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