1 /* ============================================================
2 * Falkon - Qt web browser
3 * Copyright (C) 2013-2018 David Rosca <nowrep@gmail.com>
4 *
5 * This program is free software: you can redistribute it and/or modify
6 * it under the terms of the GNU General Public License as published by
7 * the Free Software Foundation, either version 3 of the License, or
8 * (at your option) any later version.
9 *
10 * This program is distributed in the hope that it will be useful,
11 * but WITHOUT ANY WARRANTY; without even the implied warranty of
12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 * GNU General Public License for more details.
14 *
15 * You should have received a copy of the GNU General Public License
16 * along with this program. If not, see <http://www.gnu.org/licenses/>.
17 * ============================================================ */
18 #include "passwordmanager.h"
19 #include "passwordbackends/passwordbackend.h"
20 #include "passwordbackends/databasepasswordbackend.h"
21 #include "passwordbackends/databaseencryptedpasswordbackend.h"
22 #include "settings.h"
23
24 #include <QVector>
25 #include <QDataStream>
26
27 static const int passwordEntryVersion = 2;
28
operator <<(QDataStream & stream,const PasswordEntry & entry)29 QDataStream &operator <<(QDataStream &stream, const PasswordEntry &entry)
30 {
31 stream << passwordEntryVersion;
32 stream << entry.host;
33 stream << entry.id;
34 stream << entry.username;
35 stream << entry.password;
36 stream << entry.data;
37 stream << entry.updated;
38
39 return stream;
40 }
41
operator >>(QDataStream & stream,PasswordEntry & entry)42 QDataStream &operator >>(QDataStream &stream, PasswordEntry &entry)
43 {
44 int version;
45 stream >> version;
46
47 if (version != passwordEntryVersion) {
48 return stream;
49 }
50
51 stream >> entry.host;
52 stream >> entry.id;
53 stream >> entry.username;
54 stream >> entry.password;
55 stream >> entry.data;
56 stream >> entry.updated;
57
58 return stream;
59 }
60
PasswordManager(QObject * parent)61 PasswordManager::PasswordManager(QObject* parent)
62 : QObject(parent)
63 , m_loaded(false)
64 , m_backend(nullptr)
65 , m_databaseBackend(new DatabasePasswordBackend)
66 , m_databaseEncryptedBackend(new DatabaseEncryptedPasswordBackend)
67 {
68 m_backends[QSL("database")] = m_databaseBackend;
69 m_backends[QSL("database-encrypted")] = m_databaseEncryptedBackend;
70 }
71
loadSettings()72 void PasswordManager::loadSettings()
73 {
74 Settings settings;
75 settings.beginGroup(QSL("PasswordManager"));
76 QString backendId = settings.value(QSL("Backend"), QSL("database")).toString();
77 settings.endGroup();
78
79 if (m_backend) {
80 m_backend->setActive(false);
81 }
82 m_backend = m_backends[m_backends.contains(backendId) ? backendId : QSL("database")];
83 m_backend->setActive(true);
84 }
85
getUsernames(const QUrl & url)86 QStringList PasswordManager::getUsernames(const QUrl &url)
87 {
88 ensureLoaded();
89 return m_backend->getUsernames(url);
90 }
91
getEntries(const QUrl & url)92 QVector<PasswordEntry> PasswordManager::getEntries(const QUrl &url)
93 {
94 ensureLoaded();
95 return m_backend->getEntries(url);
96 }
97
getAllEntries()98 QVector<PasswordEntry> PasswordManager::getAllEntries()
99 {
100 ensureLoaded();
101 return m_backend->getAllEntries();
102 }
103
addEntry(const PasswordEntry & entry)104 void PasswordManager::addEntry(const PasswordEntry &entry)
105 {
106 ensureLoaded();
107 m_backend->addEntry(entry);
108 }
109
updateEntry(const PasswordEntry & entry)110 bool PasswordManager::updateEntry(const PasswordEntry &entry)
111 {
112 ensureLoaded();
113 return m_backend->updateEntry(entry);
114 }
115
updateLastUsed(PasswordEntry & entry)116 void PasswordManager::updateLastUsed(PasswordEntry &entry)
117 {
118 ensureLoaded();
119 m_backend->updateLastUsed(entry);
120 }
121
removeEntry(const PasswordEntry & entry)122 void PasswordManager::removeEntry(const PasswordEntry &entry)
123 {
124 ensureLoaded();
125 m_backend->removeEntry(entry);
126 }
127
removeAllEntries()128 void PasswordManager::removeAllEntries()
129 {
130 ensureLoaded();
131 m_backend->removeAll();
132 }
133
availableBackends()134 QHash<QString, PasswordBackend*> PasswordManager::availableBackends()
135 {
136 ensureLoaded();
137 return m_backends;
138 }
139
activeBackend()140 PasswordBackend* PasswordManager::activeBackend()
141 {
142 ensureLoaded();
143 return m_backend;
144 }
145
switchBackend(const QString & backendID)146 void PasswordManager::switchBackend(const QString &backendID)
147 {
148 PasswordBackend* backend = m_backends.value(backendID);
149
150 if (!backend) {
151 return;
152 }
153
154 if (m_backend) {
155 m_backend->setActive(false);
156 }
157
158 m_backend = backend;
159 m_backend->setActive(true);
160
161 Settings settings;
162 settings.beginGroup(QSL("PasswordManager"));
163 settings.setValue(QSL("Backend"), backendID);
164 settings.endGroup();
165
166 emit passwordBackendChanged();
167 }
168
registerBackend(const QString & id,PasswordBackend * backend)169 bool PasswordManager::registerBackend(const QString &id, PasswordBackend* backend)
170 {
171 if (m_backends.contains(id)) {
172 return false;
173 }
174
175 m_backends[id] = backend;
176 return true;
177 }
178
unregisterBackend(PasswordBackend * backend)179 void PasswordManager::unregisterBackend(PasswordBackend* backend)
180 {
181 const QString key = m_backends.key(backend);
182 m_backends.remove(key);
183
184 if (m_backend == backend) {
185 m_backend = m_databaseBackend;
186 }
187 }
188
createHost(const QUrl & url)189 QString PasswordManager::createHost(const QUrl &url)
190 {
191 QString host = url.host();
192
193 if (host.isEmpty()) {
194 host = url.toString();
195 }
196
197 if (url.port() != -1) {
198 host.append(QLatin1Char(':'));
199 host.append(QString::number(url.port()));
200 }
201
202 return host;
203 }
204
urlEncodePassword(const QString & password)205 QByteArray PasswordManager::urlEncodePassword(const QString &password)
206 {
207 // Exclude space to properly decode to +
208 QByteArray encodedPass = QUrl::toPercentEncoding(password, " ");
209 encodedPass.replace(' ', '+'); // space has to be encoded to +
210 encodedPass.replace('~', "%7E"); // ~ is unreserved char, needs to be manually encoded
211 return encodedPass;
212 }
213
ensureLoaded()214 void PasswordManager::ensureLoaded()
215 {
216 if (!m_loaded) {
217 loadSettings();
218 m_loaded = true;
219 }
220 }
221
~PasswordManager()222 PasswordManager::~PasswordManager()
223 {
224 delete m_databaseBackend;
225 delete m_databaseEncryptedBackend;
226 }
227