#include "saved_auth.h" #include #include #include #include #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; }