ssu
Loading...
Searching...
No Matches
ssuurlresolver.cpp
Go to the documentation of this file.
1
7
8#include "ssuurlresolver.h"
9
10#include <QCoreApplication>
11#include <QFileInfo>
12#include <QStringList>
13#include <QUrl>
14#include <systemd/sd-journal.h>
15
16#include "libssu/sandbox_p.h"
17#include "libssu/ssulog_p.h"
18
19SsuUrlResolver::SsuUrlResolver()
20 : QObject()
21{
22 QObject::connect(this, SIGNAL(done()),
23 QCoreApplication::instance(), SLOT(quit()),
24 Qt::QueuedConnection);
25}
26
27void SsuUrlResolver::error(const QString &message)
28{
29 SsuLog *ssuLog = SsuLog::instance();
30 ssuLog->print(LOG_WARNING, message);
31
32 PluginFrame out("ERROR");
33 out.setBody(message.toStdString());
34 out.writeTo(std::cout);
35 QCoreApplication::exit(1);
36}
37
38void SsuUrlResolver::ack() const
39{
40 zypp::PluginFrame out(zypp::PluginFrame::ackCommand());
41 out.writeTo(std::cout);
42}
43
44bool SsuUrlResolver::writeZyppCredentialsIfNeeded(const QString &credentialsScope)
45{
46 QString filePath = Sandbox::map("/etc/zypp/credentials.d/" + credentialsScope);
47 QFileInfo credentialsFileInfo(filePath);
48
51 if (credentialsFileInfo.exists() &&
52 credentialsFileInfo.lastModified() > ssu.lastCredentialsUpdate() &&
53 credentialsScope != "store") {
54 // zypp credentials up to date
55 return true;
56 }
57
58 QFile credentialsFile(filePath);
59 QPair<QString, QString> credentials = ssu.credentials(credentialsScope);
60 SsuLog *ssuLog = SsuLog::instance();
61
62 if (credentials.first.isEmpty() || credentials.second.isEmpty()) {
63 ssuLog->print(LOG_WARNING, "Returned credentials are empty, skip writing");
64 return false;
65 }
66
67 if (!credentialsFile.open(QIODevice::WriteOnly | QIODevice::Text | QIODevice::Truncate)) {
68 ssuLog->print(LOG_WARNING, "Unable to open credentials file for writing");
69 return false;
70 }
71
72 QTextStream out(&credentialsFile);
73 out << "[" << ssu.credentialsUrl(credentialsScope) << "]\n";
74 out << "username=" << credentials.first << "\n";
75 out << "password=" << credentials.second << "\n";
76 out.flush();
77 credentialsFile.close();
78 return true;
79}
80
81void SsuUrlResolver::run()
82{
83 while (true) {
84 zypp::PluginFrame inputFrame(std::cin);
85 if (inputFrame.command() == "RESOLVEURL") {
86 resolve(inputFrame);
87 } else if (inputFrame.command() == "_DISCONNECT") {
88 ack();
89 break;
90 } else {
91 error(QStringLiteral("Unknown plugin command"));
92 break;
93 }
94 }
95 emit done();
96}
97
98void SsuUrlResolver::resolve(PluginFrame &in)
99{
100 QHash<QString, QString> repoParameters;
101 QString repo;
102 bool isRnd = false;
103 SsuLog *ssuLog = SsuLog::instance();
104
105 if (in.headerEmpty()) {
106 error("Received empty header list. Most likely your ssu setup is broken");
107 }
108
109 PluginFrame::HeaderListIterator it;
110 QStringList headerList;
111
112 /*
113 hasKey() for some reason makes zypper run into timeouts, so we have
114 to handle special keys here
115 */
116 for (it = in.headerBegin(); it != in.headerEnd(); it++) {
117 QString first = QString::fromStdString((*it).first);
118 QString second = QString::fromStdString((*it).second);
119
120 if (first == "repo") {
121 repo = second;
122 } else if (first == "rnd") {
123 isRnd = true;
124 } else if (first == "deviceFamily") {
125 repoParameters.insert(first, second);
126 } else if (first == "arch") {
127 repoParameters.insert(first, second);
128 } else if (first == "debug") {
129 repoParameters.insert("debugSplit", "debug");
130 } else {
131 if ((*it).second.empty())
132 headerList.append(first);
133 else
134 headerList.append(QString("%1=%2")
135 .arg(first)
136 .arg(second));
137 }
138 }
139
140 if (!ssu.useSslVerify())
141 headerList.append("ssl_verify=no");
142
143 if (ssu.isRegistered()) {
144 SignalWait w;
145 connect(&ssu, SIGNAL(done()), &w, SLOT(finished()));
146 ssu.updateCredentials();
147 w.sleep();
148
149 // error can be found in ssu.log, so just exit
150 // TODO: figure out if there's better eror handling for
151 // zypper plugins than 'blow up'
152 if (ssu.error()) {
153 error(ssu.lastError());
154 }
155 } else {
156 ssuLog->print(LOG_DEBUG, "Device not registered -- skipping credential update");
157 }
158
159 // resolve base url
160 QString resolvedUrl = ssu.repoUrl(repo, isRnd, repoParameters);
161
162 QString credentialsScope = ssu.credentialsScope(repo, isRnd);
163 // only do credentials magic on secure connections
164 if (resolvedUrl.startsWith("https://") && !credentialsScope.isEmpty() &&
165 (ssu.isRegistered() || credentialsScope == "store")) {
166 // TODO: check for credentials scope required for repository; check if the file exists;
167 // compare with configuration, and dump credentials to file if necessary
168 ssuLog->print(LOG_DEBUG, QString("Requesting credentials for '%1' with RND status %2...").arg(repo).arg(isRnd));
169
170 // personal store repositories as well as the ones listed in the
171 // store-auth-repos domain setting use store credentials. Refresh
172 // here, as we only know after checking scope if we need to have
173 // store credentials at all
174 if (credentialsScope == "store") {
175 ssu.updateStoreCredentials();
176 if (ssu.error())
177 error (ssu.lastError());
178 }
179 headerList.append(QString("credentials=%1").arg(credentialsScope));
180 writeZyppCredentialsIfNeeded(credentialsScope);
181 } else {
182 ssuLog->print(LOG_DEBUG, QString("Skipping credential for %1 with scope %2").arg(repo).arg(credentialsScope));
183 }
184
185 if (!headerList.isEmpty() && !resolvedUrl.isEmpty()) {
186 QUrl url(resolvedUrl);
187
188 if (url.hasQuery()) {
189 url.setQuery(url.query() + "&" + headerList.join("&"));
190 } else
191 url.setQuery(headerList.join("&"));
192
193 resolvedUrl = url.toString();
194 }
195
196 // TODO, we should bail out here if the configuration specifies that the repo
197 // is protected, but device is not registered and/or we don't have credentials
198 ssuLog->print(LOG_INFO, QString("%1 resolved to %2").arg(repo).arg(resolvedUrl));
199
200 if (resolvedUrl.isEmpty()) {
201 error("URL for repository is not set.");
202 } else if (resolvedUrl.indexOf(QRegExp("[a-z]*://", Qt::CaseInsensitive)) != 0) {
203 error("URL for repository is invalid.");
204 } else {
205 PluginFrame out("RESOLVEDURL");
206 out.setBody(resolvedUrl.toStdString());
207 out.writeTo(std::cout);
208 }
209}
void print(int priority, const QString &message)
Definition ssulog.cpp:27