-
Notifications
You must be signed in to change notification settings - Fork 0
Expand file tree
/
Copy pathuserid.cpp
More file actions
79 lines (64 loc) · 2.55 KB
/
Copy pathuserid.cpp
File metadata and controls
79 lines (64 loc) · 2.55 KB
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
#include "userid.h"
#include <QCryptographicHash>
#include <QRandomGenerator>
#include <QSettings>
#include <QSysInfo>
namespace UserId {
const char* const kSaltKey = "usage/userIdSalt";
const char* const kMachineFallbackKey = "usage/machineIdFallback";
namespace {
constexpr int kSaltBytes = 32; // 256 bits — the whole point is that it is not guessable
QByteArray randomBytes(int count)
{
QByteArray bytes(count, Qt::Uninitialized);
// The system generator, not the default one: this value's only job is to be
// unguessable, so a seedable PRNG would defeat it.
QRandomGenerator::system()->generate(bytes.begin(), bytes.end());
return bytes;
}
// Reads a base64 blob from `store`, minting and storing `count` random bytes
// the first time (or if the stored value is missing/corrupt).
QByteArray persistentRandom(QSettings& store, const char* key, int count)
{
const QByteArray stored =
QByteArray::fromBase64(store.value(QLatin1String(key)).toString().toLatin1());
if (stored.size() == count)
return stored;
const QByteArray fresh = randomBytes(count);
store.setValue(QLatin1String(key), QString::fromLatin1(fresh.toBase64()));
return fresh;
}
} // namespace
QByteArray installSalt(QSettings& store)
{
return persistentRandom(store, kSaltKey, kSaltBytes);
}
QByteArray machineId(QSettings& store)
{
// Windows: registry MachineGuid. Linux: /etc/machine-id (or
// /var/lib/dbus/machine-id). macOS: IOPlatformUUID.
const QByteArray id = QSysInfo::machineUniqueId();
if (!id.isEmpty())
return id;
// Nothing to read — a container, a hardened Linux install with no
// machine-id file, or a platform Qt has no implementation for. A stable
// per-install random value keeps the reported id from churning every launch;
// it means "same install" rather than "same machine", which is what the
// statistics actually use it for.
return persistentRandom(store, kMachineFallbackKey, kSaltBytes);
}
QString hashedUserId(const QByteArray& salt, const QByteArray& machineId)
{
QCryptographicHash hash(QCryptographicHash::Sha256);
hash.addData(salt);
// A separator so that (salt, machineId) pairs cannot collide by shifting the
// boundary between the two — belt and braces given the salt is fixed-length.
hash.addData(QByteArrayLiteral(":"));
hash.addData(machineId);
return QString::fromLatin1(hash.result().toHex());
}
QString hashedUserId(QSettings& store)
{
return hashedUserId(installSalt(store), machineId(store));
}
} // namespace UserId