From f270350ae6faa7c56bb8836673260ffef8135166 Mon Sep 17 00:00:00 2001 From: ZGaetano Date: Thu, 7 May 2026 00:15:56 -0400 Subject: [PATCH] RelayClient: fix syntax error in savedServers(); strip trailing slash on relay URLs --- app/vpn/relayclient.cpp | 67 ++++++++++++++++------------------------- 1 file changed, 26 insertions(+), 41 deletions(-) diff --git a/app/vpn/relayclient.cpp b/app/vpn/relayclient.cpp index bd1e450..aa12f4c 100644 --- a/app/vpn/relayclient.cpp +++ b/app/vpn/relayclient.cpp @@ -14,23 +14,22 @@ RelayClient::RelayClient(QObject *parent) : QObject(parent) , m_nam(new QNetworkAccessManager(this)) - , m_settings(new QSettings(QStringLiteral("WildDragon"), QStringLiteral("DragonMoonlight"), this)) + , m_settings(new QSettings(QStringLiteral("WildDragon"), + QStringLiteral("DragonMoonlight"), this)) { } RelayClient::~RelayClient() = default; -// ─── URL helpers ────────────────────────────────────────────────────────────── - QUrl RelayClient::apiUrl(const QString &path) const { QUrl u = m_relayUrl; - u.setPath(u.path() + path); + QString base = u.path(); + while (base.endsWith(QLatin1Char('/'))) base.chop(1); + u.setPath(base + path); return u; } -// ─── Auth-header injection ──────────────────────────────────────────────── - QNetworkReply *RelayClient::authedGet(const QString &path) { QNetworkRequest req(apiUrl(path)); @@ -53,8 +52,6 @@ QNetworkReply *RelayClient::authedDelete(const QString &path) return m_nam->deleteResource(req); } -// ─── login() ───────────────────────────────────────────────────────────────── - void RelayClient::login(const QUrl &relayUrl, const QString &username, const QString &password) { m_relayUrl = relayUrl; @@ -62,7 +59,8 @@ void RelayClient::login(const QUrl &relayUrl, const QString &username, const QSt m_jwt.clear(); QNetworkRequest req(apiUrl(QStringLiteral("/api/auth/login"))); - req.setHeader(QNetworkRequest::ContentTypeHeader, QByteArrayLiteral("application/json")); + req.setHeader(QNetworkRequest::ContentTypeHeader, + QByteArrayLiteral("application/json")); QJsonObject body; body[QStringLiteral("username")] = username; @@ -87,7 +85,8 @@ void RelayClient::onLoginReply(QNetworkReply *reply, const QString &username, const QJsonObject json = QJsonDocument::fromJson(reply->readAll()).object(); const QString token = json[QStringLiteral("token")].toString(); if (token.isEmpty()) { - const QString err = json[QStringLiteral("error")].toString(QStringLiteral("Unknown error")); + const QString err = json[QStringLiteral("error")] + .toString(QStringLiteral("Unknown error")); emit loginFailed(err); return; } @@ -98,11 +97,8 @@ void RelayClient::onLoginReply(QNetworkReply *reply, const QString &username, emit loginSucceeded(); } -// ─── provisionVPN() ─────────────────────────────────────────────────────────── - void RelayClient::provisionVPN(const QString &deviceName) { - // Use the machine's host name if the caller didn't provide one. const QString device = deviceName.isEmpty() ? QSysInfo::machineHostName() : deviceName; @@ -128,36 +124,34 @@ void RelayClient::onProvisionReply(QNetworkReply *reply) const QJsonObject json = QJsonDocument::fromJson(reply->readAll()).object(); const QString conf = json[QStringLiteral("conf")].toString(); if (conf.isEmpty()) { - const QString err = json[QStringLiteral("error")].toString(QStringLiteral("No conf in response")); + const QString err = json[QStringLiteral("error")] + .toString(QStringLiteral("No conf in response")); emit vpnProvisionFailed(err); return; } m_vpnPeerId = json[QStringLiteral("id")].toInt(-1); - // Persist peer ID so we can revoke it even after a restart. - m_settings->setValue(QStringLiteral("vpn/peer_id"), m_vpnPeerId); - m_settings->setValue(QStringLiteral("vpn/relay_url"), m_relayUrl.toString()); + m_settings->setValue(QStringLiteral("vpn/peer_id"), m_vpnPeerId); + m_settings->setValue(QStringLiteral("vpn/relay_url"), m_relayUrl.toString()); RelayVPNConf vpnConf; vpnConf.conf = conf; emit vpnProvisioned(vpnConf); } -// ─── revokeVPN() ───────────────────────────────────────────────────────────── - void RelayClient::revokeVPN() { if (m_vpnPeerId < 0) { - // Try to load from settings (post-restart cleanup). m_vpnPeerId = m_settings->value(QStringLiteral("vpn/peer_id"), -1).toInt(); } if (m_vpnPeerId < 0) { - emit vpnRevoked(); // nothing to do + emit vpnRevoked(); return; } - const QString path = QStringLiteral("/api/vpn/peer/") + QString::number(m_vpnPeerId); + const QString path = QStringLiteral("/api/vpn/peer/") + + QString::number(m_vpnPeerId); QNetworkReply *reply = authedDelete(path); connect(reply, &QNetworkReply::finished, this, [this, reply]() { reply->deleteLater(); @@ -175,8 +169,6 @@ void RelayClient::onRevokeReply(QNetworkReply *reply) emit vpnRevoked(); } -// ─── fetchHosts() ───────────────────────────────────────────────────────────── - void RelayClient::fetchHosts() { QNetworkReply *reply = authedGet(QStringLiteral("/api/hosts")); @@ -202,21 +194,21 @@ void RelayClient::onHostsReply(QNetworkReply *reply) h.ip = obj[QStringLiteral("ip")].toString(); h.port = obj[QStringLiteral("port")].toInt(47984); - // Parse displays array if present const QJsonArray displaysArr = obj[QStringLiteral("displays")].toArray(); for (const QJsonValue &dv : displaysArr) { const QJsonObject displayObj = dv.toObject(); QVariantMap displayMap; - displayMap[QStringLiteral("name")] = displayObj[QStringLiteral("name")].toString(); + displayMap[QStringLiteral("name")] = displayObj[QStringLiteral("name")].toString(); displayMap[QStringLiteral("friendlyName")] = displayObj[QStringLiteral("friendlyName")].toString(); - displayMap[QStringLiteral("width")] = displayObj[QStringLiteral("width")].toInt(); - displayMap[QStringLiteral("height")] = displayObj[QStringLiteral("height")].toInt(); - displayMap[QStringLiteral("isPrimary")] = displayObj[QStringLiteral("isPrimary")].toBool(); + displayMap[QStringLiteral("width")] = displayObj[QStringLiteral("width")].toInt(); + displayMap[QStringLiteral("height")] = displayObj[QStringLiteral("height")].toInt(); + displayMap[QStringLiteral("isPrimary")] = displayObj[QStringLiteral("isPrimary")].toBool(); h.displays.append(displayMap); } if (h.displays.isEmpty()) { - qWarning() << "Host" << h.name << "has no display data in relay response"; + qDebug() << "Host" << h.name + << "has no display data in relay response (older Artemis?)"; } if (!h.ip.isEmpty()) @@ -225,21 +217,15 @@ void RelayClient::onHostsReply(QNetworkReply *reply) emit hostsReady(hosts); } -// ─── Persistence ────────────────────────────────────────────────────────────── - void RelayClient::persistJwt() { - // NOTE: QSettings on macOS stores in ~/Library/Preferences. - // The JWT has a limited lifetime — don't rely on it across sessions; - // the app will re-authenticate on next launch using saved credentials. m_settings->setValue(QStringLiteral("auth/relay_url"), m_relayUrl.toString()); m_settings->setValue(QStringLiteral("auth/username"), m_username); - // We do NOT persist the JWT itself or the password. } void RelayClient::loadJwt() { - // Intentionally empty — re-auth on each launch for security. + // Intentionally empty - we re-auth on each launch for security. } void RelayClient::saveServer(const QString &label, const QUrl &url, @@ -248,8 +234,7 @@ void RelayClient::saveServer(const QString &label, const QUrl &url, m_settings->beginGroup(QStringLiteral("servers/") + label); m_settings->setValue(QStringLiteral("url"), url.toString()); m_settings->setValue(QStringLiteral("username"), username); - // password stored in the system keychain would be better; plain QSettings - // as a baseline — replace with QKeychain in production. + // TODO: replace with QKeychain so the password isn't stored in plaintext. m_settings->setValue(QStringLiteral("password"), password); m_settings->endGroup(); } @@ -260,13 +245,13 @@ QList RelayClient::savedServers() const const QStringList groups = m_settings->childGroups(); for (const QString &g : groups) { if (!g.startsWith(QStringLiteral("servers/"))) continue; - const QString label = g.mid(8); + const QString label = g.mid(8); // length of "servers/" m_settings->beginGroup(g); SavedServer s; s.label = label; s.url = QUrl(m_settings->value(QStringLiteral("url")).toString()); s.username = m_settings->value(QStringLiteral("username")).toString(); - s.password = m_settings->value(QStringLiteral("password")).toString()); + s.password = m_settings->value(QStringLiteral("password")).toString(); m_settings->endGroup(); list << s; }