File indexing completed on 2024-05-19 04:59:17
0001 /* ============================================================ 0002 * KDEFrameworksIntegration - KDE support plugin for Falkon 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 "kwalletpasswordbackend.h" 0019 #include "kdeframeworksintegrationplugin.h" 0020 #include "mainapplication.h" 0021 #include "browserwindow.h" 0022 #include "desktopnotificationsfactory.h" 0023 0024 #include <QDateTime> 0025 0026 #include <kwallet_version.h> 0027 #include <KWallet> 0028 0029 static PasswordEntry decodeEntry(const QByteArray &data) 0030 { 0031 QDataStream stream(data); 0032 PasswordEntry entry; 0033 stream >> entry; 0034 return entry; 0035 } 0036 0037 static QMap<QString, QString> encodeEntry(const PasswordEntry &entry) 0038 { 0039 QMap<QString, QString> data = { 0040 {QSL("host"), entry.host}, 0041 {QSL("username"), entry.username}, 0042 {QSL("password"), entry.password}, 0043 {QSL("updated"), QString::number(entry.updated)}, 0044 {QSL("data"), QString::fromUtf8(entry.data)} 0045 }; 0046 return data; 0047 } 0048 0049 KWalletPasswordBackend::KWalletPasswordBackend() 0050 : PasswordBackend() 0051 , m_wallet(nullptr) 0052 { 0053 } 0054 0055 QString KWalletPasswordBackend::name() const 0056 { 0057 return KDEFrameworksIntegrationPlugin::tr("KWallet"); 0058 } 0059 0060 QVector<PasswordEntry> KWalletPasswordBackend::getEntries(const QUrl &url) 0061 { 0062 initialize(); 0063 0064 const QString host = PasswordManager::createHost(url); 0065 0066 QVector<PasswordEntry> list; 0067 0068 for (const PasswordEntry &entry : std::as_const(m_allEntries)) { 0069 if (entry.host == host) { 0070 list.append(entry); 0071 } 0072 } 0073 0074 // Sort to prefer last updated entries 0075 std::sort(list.begin(), list.end()); 0076 0077 return list; 0078 } 0079 0080 QVector<PasswordEntry> KWalletPasswordBackend::getAllEntries() 0081 { 0082 initialize(); 0083 0084 return m_allEntries; 0085 } 0086 0087 // TODO QT6 - should we just start storing timestamps as 64-bit instead? 0088 static uint Q_DATETIME_TOTIME_T(const QDateTime &dateTime) 0089 { 0090 if (!dateTime.isValid()) 0091 return uint(-1); 0092 qint64 retval = dateTime.toMSecsSinceEpoch() / 1000; 0093 if (quint64(retval) >= Q_UINT64_C(0xFFFFFFFF)) 0094 return uint(-1); 0095 return uint(retval); 0096 } 0097 0098 void KWalletPasswordBackend::addEntry(const PasswordEntry &entry) 0099 { 0100 initialize(); 0101 0102 if (!m_wallet) { 0103 showErrorNotification(); 0104 return; 0105 } 0106 0107 PasswordEntry stored = entry; 0108 stored.id = QSL("%1/%2").arg(entry.host, entry.username); 0109 stored.updated = Q_DATETIME_TOTIME_T(QDateTime::currentDateTime()); 0110 0111 m_wallet->writeMap(stored.id.toString(), encodeEntry(stored)); 0112 m_allEntries.append(stored); 0113 } 0114 0115 bool KWalletPasswordBackend::updateEntry(const PasswordEntry &entry) 0116 { 0117 initialize(); 0118 0119 if (!m_wallet) { 0120 showErrorNotification(); 0121 return false; 0122 } 0123 0124 m_wallet->removeEntry(entry.id.toString()); 0125 m_wallet->writeMap(entry.id.toString(), encodeEntry(entry)); 0126 0127 int index = m_allEntries.indexOf(entry); 0128 0129 if (index > -1) { 0130 m_allEntries[index] = entry; 0131 } 0132 0133 return true; 0134 } 0135 0136 void KWalletPasswordBackend::updateLastUsed(PasswordEntry &entry) 0137 { 0138 initialize(); 0139 0140 if (!m_wallet) { 0141 showErrorNotification(); 0142 return; 0143 } 0144 0145 m_wallet->removeEntry(entry.id.toString()); 0146 0147 entry.updated = Q_DATETIME_TOTIME_T(QDateTime::currentDateTime()); 0148 0149 m_wallet->writeMap(entry.id.toString(), encodeEntry(entry)); 0150 0151 int index = m_allEntries.indexOf(entry); 0152 0153 if (index > -1) { 0154 m_allEntries[index] = entry; 0155 } 0156 } 0157 0158 void KWalletPasswordBackend::removeEntry(const PasswordEntry &entry) 0159 { 0160 initialize(); 0161 0162 if (!m_wallet) { 0163 showErrorNotification(); 0164 return; 0165 } 0166 0167 m_wallet->removeEntry(entry.id.toString()); 0168 0169 int index = m_allEntries.indexOf(entry); 0170 0171 if (index > -1) { 0172 m_allEntries.remove(index); 0173 } 0174 } 0175 0176 void KWalletPasswordBackend::removeAll() 0177 { 0178 initialize(); 0179 0180 if (!m_wallet) { 0181 showErrorNotification(); 0182 return; 0183 } 0184 0185 m_allEntries.clear(); 0186 0187 m_wallet->removeFolder(QSL("FalkonPasswords")); 0188 m_wallet->createFolder(QSL("FalkonPasswords")); 0189 } 0190 0191 void KWalletPasswordBackend::showErrorNotification() 0192 { 0193 static bool initialized; 0194 0195 if (!initialized) { 0196 initialized = true; 0197 mApp->desktopNotifications()->showNotification(KDEFrameworksIntegrationPlugin::tr("KWallet disabled"), KDEFrameworksIntegrationPlugin::tr("Please enable KWallet to save password.")); 0198 } 0199 } 0200 0201 void KWalletPasswordBackend::initialize() 0202 { 0203 if (m_wallet) { 0204 return; 0205 } 0206 0207 WId wid = 0; 0208 BrowserWindow *w = mApp->getWindow(); 0209 if (w && w->window()) { 0210 wid = w->window()->winId(); 0211 } 0212 m_wallet = KWallet::Wallet::openWallet(KWallet::Wallet::NetworkWallet(), wid); 0213 0214 if (!m_wallet) { 0215 qWarning() << "KWalletPasswordBackend::initialize Cannot open wallet!"; 0216 return; 0217 } 0218 0219 bool migrationFalkon = !m_wallet->hasFolder(QSL("FalkonPasswords")) && m_wallet->hasFolder(QSL("Falkon")); 0220 bool migrateQupzilla = !m_wallet->hasFolder(QSL("FalkonPasswords")) && !m_wallet->hasFolder(QSL("Falkon")) && m_wallet->hasFolder(QSL("QupZilla")); 0221 bool migration = false; 0222 0223 if (!m_wallet->hasFolder(QSL("FalkonPasswords")) && !m_wallet->createFolder(QSL("FalkonPasswords"))) { 0224 qWarning() << "KWalletPasswordBackend::initialize Cannot create folder \"FalkonPasswords\"!"; 0225 return; 0226 } 0227 0228 if (migrationFalkon) { 0229 if (!m_wallet->setFolder(QSL("Falkon"))) { 0230 qWarning() << "KWalletPasswordBackend::initialize Cannot set folder \"Falkon\"!"; 0231 return; 0232 } 0233 migration = true; 0234 } 0235 else if (migrateQupzilla) { 0236 if (!m_wallet->setFolder(QSL("QupZilla"))) { 0237 qWarning() << "KWalletPasswordBackend::initialize Cannot set folder \"QupZilla\"!"; 0238 return; 0239 } 0240 migration = true; 0241 } 0242 else { 0243 if (!m_wallet->setFolder(QSL("FalkonPasswords"))) { 0244 qWarning() << "KWalletPasswordBackend::initialize Cannot set folder \"FalkonPasswords\"!"; 0245 return; 0246 } 0247 } 0248 0249 if (migration) { 0250 QMap<QString, QByteArray> entries; 0251 bool ok = false; 0252 entries = m_wallet->entriesList(&ok); 0253 if (!ok) { 0254 qWarning() << "KWalletPasswordBackend::initialize Cannot read entries!"; 0255 return; 0256 } 0257 0258 QMap<QString, QByteArray>::const_iterator i = entries.constBegin(); 0259 while (i != entries.constEnd()) { 0260 PasswordEntry entry = decodeEntry(i.value()); 0261 if (entry.isValid()) { 0262 m_allEntries.append(entry); 0263 } 0264 ++i; 0265 } 0266 0267 if (!m_wallet->setFolder(QSL("FalkonPasswords"))) { 0268 qWarning() << "KWalletPasswordBackend::initialize Cannot set folder \"FalkonPasswords\"!"; 0269 return; 0270 } 0271 0272 for (const PasswordEntry &entry : std::as_const(m_allEntries)) { 0273 m_wallet->writeMap(entry.id.toString(), encodeEntry(entry)); 0274 } 0275 } 0276 else { 0277 QMap<QString, QMap<QString, QString>> entriesMap; 0278 bool ok = false; 0279 entriesMap = m_wallet->mapList(&ok); 0280 QMap<QString, QMap<QString, QString>>::const_iterator j = entriesMap.constBegin(); 0281 while (j != entriesMap.constEnd()) { 0282 PasswordEntry entry; 0283 entry.id = j.key(); 0284 entry.host = j.value()[QSL("host")]; 0285 entry.username = j.value()[QSL("username")]; 0286 entry.password = j.value()[QSL("password")]; 0287 entry.updated = j.value()[QSL("updated")].toInt(); 0288 entry.data = j.value()[QSL("data")].toUtf8(); 0289 if (entry.isValid()) { 0290 m_allEntries.append(entry); 0291 } 0292 ++j; 0293 } 0294 } 0295 } 0296 0297 KWalletPasswordBackend::~KWalletPasswordBackend() 0298 { 0299 delete m_wallet; 0300 }