diff options
| author | Osmium Sorcerer <os@sof.beauty> | 2026-03-22 18:55:26 +0000 |
|---|---|---|
| committer | Osmium Sorcerer <os@sof.beauty> | 2026-03-29 22:22:25 +0000 |
| commit | a124f46861d549ddc13485536962e34d80de939a (patch) | |
| tree | 3553849323aa70fef1e198f3476a2abcc7adfe39 /src/saved_auth.cpp | |
| parent | b1ad938c37f4e175e5509f727d1033b074b134d4 (diff) | |
Add authentication dialog
Introduce start_auth_flow, a function invoked by typing `/auth username`
in OOC. It sends an public-key authentication request to the server,
starting the entire flow.
The flow invoves two dialogs: to select the key, and to enter the
passphrase to unlock the key. For convenience, each successful unlock
also remembers the key for that username on the server, storing this
in `saved_auth.json` (I chose JSON because I wanted it to stay
human-editable; INI would be better, but it suffers from bad platform
quirks in Qt).
Diffstat (limited to 'src/saved_auth.cpp')
| -rw-r--r-- | src/saved_auth.cpp | 124 |
1 files changed, 124 insertions, 0 deletions
diff --git a/src/saved_auth.cpp b/src/saved_auth.cpp new file mode 100644 index 0000000..aa1c696 --- /dev/null +++ b/src/saved_auth.cpp @@ -0,0 +1,124 @@ +#include "saved_auth.h" + +#include <QDir> +#include <QFile> +#include <QJsonDocument> +#include <QJsonObject> + +#include "file_functions.h" + +// I wish I could use INI for settings to let users edit it manually if they +// wanted to, like ~/.ssh/config. Unfortunately, due to adherence to idiotic +// conventions, INI keys are case-insensitive on Windows, while the usernames +// aren't. Rather than defining my own stupid encoding to work around this +// issue (thus ruining convenience I originally strived for), I'll ditch INI +// altogether. I could use CBOR for consistency, but I'm using JSON because +// it's supposed to be manually editable, and I don't want to complicate +// things by creating a new settings format. +bool SavedAuth::load() +{ + QFile saved_auth_file(QDir(get_app_path()).filePath("saved_auth.json")); + if (!saved_auth_file.open(QIODevice::ReadOnly)) + { + return false; + } + QByteArray raw_data = saved_auth_file.readAll(); + saved_auth_file.close(); + + QJsonParseError err; + QJsonDocument doc = QJsonDocument::fromJson(raw_data, &err); + if (err.error != QJsonParseError::NoError || !doc.isObject()) + { + return false; + } + + m_table.clear(); + QJsonObject root = doc.object(); + for (auto host_it = root.begin(); host_it != root.end(); ++host_it) + { + if (!host_it.value().isObject()) + { + continue; + } + + QByteArray host = host_it.key().toUtf8(); + QJsonObject users = host_it.value().toObject(); + + for (auto user_it = users.begin(); user_it != users.end(); ++user_it) + { + if (!user_it.value().isString()) + { + continue; + } + + QByteArray user = user_it.key().toUtf8(); + QByteArray saved_key = QByteArray::fromBase64(user_it.value().toString().toUtf8()); + + m_table[host + '\0' + user] = saved_key; + } + } + + return true; +} + +QByteArray SavedAuth::lookup(QByteArrayView host, QByteArrayView user) const +{ + return m_table.value(flatten_key(host, user)); +} + +void SavedAuth::insert(QByteArrayView host, QByteArrayView user, QByteArrayView saved_key) +{ + m_table[flatten_key(host, user)] = QByteArray(saved_key); + save(); +} + +void SavedAuth::remove(QByteArrayView host, QByteArrayView user) +{ + m_table.remove(flatten_key(host, user)); + save(); +} + +bool SavedAuth::save() const +{ + QJsonObject root; + + for (auto it = m_table.begin(); it != m_table.end(); ++it) + { + const QByteArray &flat = it.key(); + const QByteArray &key_id = it.value(); + + int sep = flat.indexOf('\0'); + if (sep < 0) + { + continue; + } + + QString host = QString::fromUtf8(flat.left(sep)); + QString user = QString::fromUtf8(flat.mid(sep + 1)); + + QJsonObject host_obj = root.value(host).toObject(); + + host_obj[user] = QString::fromUtf8(key_id.toBase64(QByteArray::OmitTrailingEquals)); + + root[host] = host_obj; + } + + QJsonDocument doc(root); + + QFile f(QDir(get_app_path()).filePath("saved_auth.json")); + if (!f.open(QIODevice::WriteOnly)) + return false; + + f.write(doc.toJson(QJsonDocument::Indented)); + return true; +} + +QByteArray SavedAuth::flatten_key(QByteArrayView host, QByteArrayView user) const +{ + QByteArray key; + key.reserve(host.size() + 1 + user.size()); + key.append(host); + key.append('\0'); + key.append(user); + return key; +} |
