1 #include "settings.h"
2
3 #include "logging.h"
4
5 #include <QtCore/QUrl>
6
7 using namespace Quotient;
8
9 QString Settings::legacyOrganizationName {};
10 QString Settings::legacyApplicationName {};
11
setLegacyNames(const QString & organizationName,const QString & applicationName)12 void Settings::setLegacyNames(const QString& organizationName,
13 const QString& applicationName)
14 {
15 legacyOrganizationName = organizationName;
16 legacyApplicationName = applicationName;
17 }
18
Settings(QObject * parent)19 Settings::Settings(QObject* parent) : QSettings(parent)
20 {
21 setIniCodec("UTF-8");
22 }
23
setValue(const QString & key,const QVariant & value)24 void Settings::setValue(const QString& key, const QVariant& value)
25 {
26 QSettings::setValue(key, value);
27 if (legacySettings.contains(key))
28 legacySettings.remove(key);
29 }
30
remove(const QString & key)31 void Settings::remove(const QString& key)
32 {
33 QSettings::remove(key);
34 if (legacySettings.contains(key))
35 legacySettings.remove(key);
36 }
37
value(const QString & key,const QVariant & defaultValue) const38 QVariant Settings::value(const QString& key, const QVariant& defaultValue) const
39 {
40 auto value = QSettings::value(key, legacySettings.value(key, defaultValue));
41 // QML's Qt.labs.Settings stores boolean values as strings, which, if loaded
42 // through the usual QSettings interface, confuses QML
43 // (QVariant("false") == true in JavaScript). Since we have a mixed
44 // environment where both QSettings and Qt.labs.Settings may potentially
45 // work with same settings, better ensure compatibility.
46 return value.toString() == QStringLiteral("false") ? QVariant(false) : value;
47 }
48
contains(const QString & key) const49 bool Settings::contains(const QString& key) const
50 {
51 return QSettings::contains(key) || legacySettings.contains(key);
52 }
53
childGroups() const54 QStringList Settings::childGroups() const
55 {
56 auto groups = QSettings::childGroups();
57 const auto& legacyGroups = legacySettings.childGroups();
58 for (const auto& g: legacyGroups)
59 if (!groups.contains(g))
60 groups.push_back(g);
61 return groups;
62 }
63
setValue(const QString & key,const QVariant & value)64 void SettingsGroup::setValue(const QString& key, const QVariant& value)
65 {
66 Settings::setValue(groupPath + '/' + key, value);
67 }
68
contains(const QString & key) const69 bool SettingsGroup::contains(const QString& key) const
70 {
71 return Settings::contains(groupPath + '/' + key);
72 }
73
value(const QString & key,const QVariant & defaultValue) const74 QVariant SettingsGroup::value(const QString& key,
75 const QVariant& defaultValue) const
76 {
77 return Settings::value(groupPath + '/' + key, defaultValue);
78 }
79
group() const80 QString SettingsGroup::group() const { return groupPath; }
81
childGroups() const82 QStringList SettingsGroup::childGroups() const
83 {
84 const_cast<SettingsGroup*>(this)->beginGroup(groupPath);
85 const_cast<QSettings&>(legacySettings).beginGroup(groupPath);
86 QStringList l = Settings::childGroups();
87 const_cast<SettingsGroup*>(this)->endGroup();
88 const_cast<QSettings&>(legacySettings).endGroup();
89 return l;
90 }
91
remove(const QString & key)92 void SettingsGroup::remove(const QString& key)
93 {
94 QString fullKey { groupPath };
95 if (!key.isEmpty())
96 fullKey += "/" + key;
97 Settings::remove(fullKey);
98 }
99
100 QTNT_DEFINE_SETTING(AccountSettings, QString, deviceId, "device_id", {},
101 setDeviceId)
102 QTNT_DEFINE_SETTING(AccountSettings, QString, deviceName, "device_name", {},
103 setDeviceName)
104 QTNT_DEFINE_SETTING(AccountSettings, bool, keepLoggedIn, "keep_logged_in", false,
105 setKeepLoggedIn)
106
107 static const auto HomeserverKey = QStringLiteral("homeserver");
108 static const auto AccessTokenKey = QStringLiteral("access_token");
109 static const auto EncryptionAccountPickleKey =
110 QStringLiteral("encryption_account_pickle");
111
homeserver() const112 QUrl AccountSettings::homeserver() const
113 {
114 return QUrl::fromUserInput(value(HomeserverKey).toString());
115 }
116
setHomeserver(const QUrl & url)117 void AccountSettings::setHomeserver(const QUrl& url)
118 {
119 setValue(HomeserverKey, url.toString());
120 }
121
userId() const122 QString AccountSettings::userId() const { return group().section('/', -1); }
123
accessToken() const124 QString AccountSettings::accessToken() const
125 {
126 return value(AccessTokenKey).toString();
127 }
128
setAccessToken(const QString & accessToken)129 void AccountSettings::setAccessToken(const QString& accessToken)
130 {
131 qCWarning(MAIN) << "Saving access_token to QSettings is insecure."
132 " Developers, do it manually or contribute to share "
133 "QtKeychain logic to libQuotient.";
134 setValue(AccessTokenKey, accessToken);
135 }
136
clearAccessToken()137 void AccountSettings::clearAccessToken()
138 {
139 legacySettings.remove(AccessTokenKey);
140 legacySettings.remove(QStringLiteral("device_id")); // Force the server to
141 // re-issue it
142 remove(AccessTokenKey);
143 }
144
encryptionAccountPickle()145 QByteArray AccountSettings::encryptionAccountPickle()
146 {
147 QString passphrase = ""; // FIXME: add QtKeychain
148 return value("encryption_account_pickle", "").toByteArray();
149 }
150
setEncryptionAccountPickle(const QByteArray & encryptionAccountPickle)151 void AccountSettings::setEncryptionAccountPickle(
152 const QByteArray& encryptionAccountPickle)
153 {
154 qCWarning(MAIN)
155 << "Saving encryption_account_pickle to QSettings is insecure."
156 " Developers, do it manually or contribute to share QtKeychain "
157 "logic to libQuotient.";
158 QString passphrase = ""; // FIXME: add QtKeychain
159 setValue("encryption_account_pickle", encryptionAccountPickle);
160 }
161
clearEncryptionAccountPickle()162 void AccountSettings::clearEncryptionAccountPickle()
163 {
164 remove(EncryptionAccountPickleKey); // TODO: Force to re-issue it?
165 }
166