File indexing completed on 2024-05-19 04:58:38

0001 /* ============================================================
0002 * Falkon - Qt web browser
0003 * Copyright (C) 2013-2018 David Rosca <nowrep@gmail.com>
0004 *
0005 * This program is free software: you can redistribute it and/or modify
0006 * it under the terms of the GNU General Public License as published by
0007 * the Free Software Foundation, either version 3 of the License, or
0008 * (at your option) any later version.
0009 *
0010 * This program is distributed in the hope that it will be useful,
0011 * but WITHOUT ANY WARRANTY; without even the implied warranty of
0012 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
0013 * GNU General Public License for more details.
0014 *
0015 * You should have received a copy of the GNU General Public License
0016 * along with this program.  If not, see <http://www.gnu.org/licenses/>.
0017 * ============================================================ */
0018 #include "passwordmanager.h"
0019 #include "passwordbackends/passwordbackend.h"
0020 #include "passwordbackends/databasepasswordbackend.h"
0021 #include "passwordbackends/databaseencryptedpasswordbackend.h"
0022 #include "settings.h"
0023 
0024 #include <QVector>
0025 #include <QDataStream>
0026 
0027 static const int passwordEntryVersion = 2;
0028 
0029 QDataStream &operator <<(QDataStream &stream, const PasswordEntry &entry)
0030 {
0031     stream << passwordEntryVersion;
0032     stream << entry.host;
0033     stream << entry.id;
0034     stream << entry.username;
0035     stream << entry.password;
0036     stream << entry.data;
0037     stream << entry.updated;
0038 
0039     return stream;
0040 }
0041 
0042 QDataStream &operator >>(QDataStream &stream, PasswordEntry &entry)
0043 {
0044     int version;
0045     stream >> version;
0046 
0047     if (version != passwordEntryVersion) {
0048         return stream;
0049     }
0050 
0051     stream >> entry.host;
0052     stream >> entry.id;
0053     stream >> entry.username;
0054     stream >> entry.password;
0055     stream >> entry.data;
0056     stream >> entry.updated;
0057 
0058     return stream;
0059 }
0060 
0061 PasswordManager::PasswordManager(QObject* parent)
0062     : QObject(parent)
0063     , m_loaded(false)
0064     , m_backend(nullptr)
0065     , m_databaseBackend(new DatabasePasswordBackend)
0066     , m_databaseEncryptedBackend(new DatabaseEncryptedPasswordBackend)
0067 {
0068     m_backends[QSL("database")] = m_databaseBackend;
0069     m_backends[QSL("database-encrypted")] = m_databaseEncryptedBackend;
0070 }
0071 
0072 void PasswordManager::loadSettings()
0073 {
0074     Settings settings;
0075     settings.beginGroup(QSL("PasswordManager"));
0076     QString backendId = settings.value(QSL("Backend"), QSL("database")).toString();
0077     settings.endGroup();
0078 
0079     if (m_backend) {
0080         m_backend->setActive(false);
0081     }
0082     m_backend = m_backends[m_backends.contains(backendId) ? backendId : QSL("database")];
0083     m_backend->setActive(true);
0084 }
0085 
0086 QStringList PasswordManager::getUsernames(const QUrl &url)
0087 {
0088     ensureLoaded();
0089     return m_backend->getUsernames(url);
0090 }
0091 
0092 QVector<PasswordEntry> PasswordManager::getEntries(const QUrl &url)
0093 {
0094     ensureLoaded();
0095     return m_backend->getEntries(url);
0096 }
0097 
0098 QVector<PasswordEntry> PasswordManager::getAllEntries()
0099 {
0100     ensureLoaded();
0101     return m_backend->getAllEntries();
0102 }
0103 
0104 void PasswordManager::addEntry(const PasswordEntry &entry)
0105 {
0106     ensureLoaded();
0107     m_backend->addEntry(entry);
0108 }
0109 
0110 bool PasswordManager::updateEntry(const PasswordEntry &entry)
0111 {
0112     ensureLoaded();
0113     return m_backend->updateEntry(entry);
0114 }
0115 
0116 void PasswordManager::updateLastUsed(PasswordEntry &entry)
0117 {
0118     ensureLoaded();
0119     m_backend->updateLastUsed(entry);
0120 }
0121 
0122 void PasswordManager::removeEntry(const PasswordEntry &entry)
0123 {
0124     ensureLoaded();
0125     m_backend->removeEntry(entry);
0126 }
0127 
0128 void PasswordManager::removeAllEntries()
0129 {
0130     ensureLoaded();
0131     m_backend->removeAll();
0132 }
0133 
0134 QHash<QString, PasswordBackend*> PasswordManager::availableBackends()
0135 {
0136     ensureLoaded();
0137     return m_backends;
0138 }
0139 
0140 PasswordBackend* PasswordManager::activeBackend()
0141 {
0142     ensureLoaded();
0143     return m_backend;
0144 }
0145 
0146 void PasswordManager::switchBackend(const QString &backendID)
0147 {
0148     PasswordBackend* backend = m_backends.value(backendID);
0149 
0150     if (!backend) {
0151         return;
0152     }
0153 
0154     if (m_backend) {
0155         m_backend->setActive(false);
0156     }
0157 
0158     m_backend = backend;
0159     m_backend->setActive(true);
0160 
0161     Settings settings;
0162     settings.beginGroup(QSL("PasswordManager"));
0163     settings.setValue(QSL("Backend"), backendID);
0164     settings.endGroup();
0165 
0166     Q_EMIT passwordBackendChanged();
0167 }
0168 
0169 bool PasswordManager::registerBackend(const QString &id, PasswordBackend* backend)
0170 {
0171     if (m_backends.contains(id)) {
0172         return false;
0173     }
0174 
0175     m_backends[id] = backend;
0176     return true;
0177 }
0178 
0179 void PasswordManager::unregisterBackend(PasswordBackend* backend)
0180 {
0181     const QString key = m_backends.key(backend);
0182     m_backends.remove(key);
0183 
0184     if (m_backend == backend) {
0185         m_backend = m_databaseBackend;
0186     }
0187 }
0188 
0189 QString PasswordManager::createHost(const QUrl &url)
0190 {
0191     QString host = url.host();
0192 
0193     if (host.isEmpty()) {
0194         host = url.toString();
0195     }
0196 
0197     if (url.port() != -1) {
0198         host.append(QLatin1Char(':'));
0199         host.append(QString::number(url.port()));
0200     }
0201 
0202     return host;
0203 }
0204 
0205 QByteArray PasswordManager::urlEncodePassword(const QString &password)
0206 {
0207     // Exclude space to properly decode to +
0208     QByteArray encodedPass = QUrl::toPercentEncoding(password, " ");
0209     encodedPass.replace(' ', '+'); // space has to be encoded to +
0210     encodedPass.replace('~', "%7E"); // ~ is unreserved char, needs to be manually encoded
0211     return encodedPass;
0212 }
0213 
0214 void PasswordManager::ensureLoaded()
0215 {
0216     if (!m_loaded) {
0217         loadSettings();
0218         m_loaded = true;
0219     }
0220 }
0221 
0222 PasswordManager::~PasswordManager()
0223 {
0224     delete m_databaseBackend;
0225     delete m_databaseEncryptedBackend;
0226 }