1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
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
117
118
119
120
121
122
123
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;
}
|