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