File indexing completed on 2024-05-12 04:57:55
0001 /* ============================================================ 0002 * Falkon - Qt web browser 0003 * Copyright (C) 2010-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 "autofill.h" 0019 #include "browserwindow.h" 0020 #include "webpage.h" 0021 #include "sqldatabase.h" 0022 #include "popupwebview.h" 0023 #include "mainapplication.h" 0024 #include "autofillnotification.h" 0025 #include "settings.h" 0026 #include "passwordmanager.h" 0027 #include "qztools.h" 0028 #include "scripts.h" 0029 #include "webpage.h" 0030 0031 #include <QXmlStreamWriter> 0032 #include <QXmlStreamReader> 0033 #include <QWebEngineProfile> 0034 #include <QWebEngineScriptCollection> 0035 #include <QUrlQuery> 0036 0037 AutoFill::AutoFill(QObject* parent) 0038 : QObject(parent) 0039 , m_manager(new PasswordManager(this)) 0040 { 0041 loadSettings(); 0042 0043 // Setup AutoFill userscript 0044 QWebEngineScript script; 0045 script.setName(QSL("_falkon_autofill")); 0046 script.setInjectionPoint(QWebEngineScript::DocumentReady); 0047 script.setWorldId(WebPage::SafeJsWorld); 0048 script.setRunsOnSubFrames(true); 0049 script.setSourceCode(Scripts::setupFormObserver()); 0050 mApp->webProfile()->scripts()->insert(script); 0051 } 0052 0053 PasswordManager* AutoFill::passwordManager() const 0054 { 0055 return m_manager; 0056 } 0057 0058 void AutoFill::loadSettings() 0059 { 0060 Settings settings; 0061 settings.beginGroup(QStringLiteral("Web-Browser-Settings")); 0062 m_isStoring = settings.value(QStringLiteral("SavePasswordsOnSites"), true).toBool(); 0063 m_isAutoComplete = settings.value(QStringLiteral("AutoCompletePasswords"), true).toBool(); 0064 settings.endGroup(); 0065 } 0066 0067 bool AutoFill::isStored(const QUrl &url) 0068 { 0069 if (!isStoringEnabled(url)) { 0070 return false; 0071 } 0072 0073 return !m_manager->getUsernames(url).isEmpty(); 0074 } 0075 0076 bool AutoFill::isStoringEnabled(const QUrl &url) 0077 { 0078 if (!m_isStoring) { 0079 return false; 0080 } 0081 0082 QString server = url.host(); 0083 if (server.isEmpty()) { 0084 server = url.toString(); 0085 } 0086 0087 QSqlQuery query(SqlDatabase::instance()->database()); 0088 query.prepare(QStringLiteral("SELECT count(id) FROM autofill_exceptions WHERE server=?")); 0089 query.addBindValue(server); 0090 query.exec(); 0091 0092 if (!query.next()) { 0093 return false; 0094 } 0095 0096 return query.value(0).toInt() <= 0; 0097 } 0098 0099 void AutoFill::blockStoringforUrl(const QUrl &url) 0100 { 0101 QString server = url.host(); 0102 if (server.isEmpty()) { 0103 server = url.toString(); 0104 } 0105 0106 QSqlQuery query(SqlDatabase::instance()->database()); 0107 query.prepare(QStringLiteral("INSERT INTO autofill_exceptions (server) VALUES (?)")); 0108 query.addBindValue(server); 0109 query.exec(); 0110 } 0111 0112 QVector<PasswordEntry> AutoFill::getFormData(const QUrl &url) 0113 { 0114 return m_manager->getEntries(url); 0115 } 0116 0117 QVector<PasswordEntry> AutoFill::getAllFormData() 0118 { 0119 return m_manager->getAllEntries(); 0120 } 0121 0122 void AutoFill::updateLastUsed(PasswordEntry &data) 0123 { 0124 m_manager->updateLastUsed(data); 0125 } 0126 0127 // HTTP Authorization 0128 void AutoFill::addEntry(const QUrl &url, const QString &name, const QString &pass) 0129 { 0130 PasswordEntry entry; 0131 entry.host = PasswordManager::createHost(url); 0132 entry.username = name; 0133 entry.password = pass; 0134 0135 m_manager->addEntry(entry); 0136 } 0137 0138 // WEB Form 0139 void AutoFill::addEntry(const QUrl &url, const PageFormData &formData) 0140 { 0141 PasswordEntry entry; 0142 entry.host = PasswordManager::createHost(url); 0143 entry.username = formData.username; 0144 entry.password = formData.password; 0145 entry.data = formData.postData; 0146 0147 m_manager->addEntry(entry); 0148 } 0149 0150 // HTTP Authorization 0151 void AutoFill::updateEntry(const QUrl &url, const QString &name, const QString &pass) 0152 { 0153 PasswordEntry entry; 0154 entry.host = PasswordManager::createHost(url); 0155 entry.username = name; 0156 entry.password = pass; 0157 0158 m_manager->updateEntry(entry); 0159 } 0160 0161 // WEB Form 0162 bool AutoFill::updateEntry(const PasswordEntry &entry) 0163 { 0164 return m_manager->updateEntry(entry); 0165 } 0166 0167 void AutoFill::removeEntry(const PasswordEntry &entry) 0168 { 0169 m_manager->removeEntry(entry); 0170 } 0171 0172 void AutoFill::removeAllEntries() 0173 { 0174 m_manager->removeAllEntries(); 0175 } 0176 0177 void AutoFill::saveForm(WebPage *page, const QUrl &frameUrl, const PageFormData &formData) 0178 { 0179 // Don't save in private browsing 0180 if (mApp->isPrivate() || !page) 0181 return; 0182 0183 if (!isStoringEnabled(frameUrl)) 0184 return; 0185 0186 PasswordEntry updateData; 0187 0188 if (isStored(frameUrl)) { 0189 const QVector<PasswordEntry> &list = getFormData(frameUrl); 0190 0191 for (const PasswordEntry &data : list) { 0192 if (data.username == formData.username) { 0193 updateData = data; 0194 updateLastUsed(updateData); 0195 0196 if (data.password == formData.password) { 0197 updateData.password.clear(); 0198 return; 0199 } 0200 0201 updateData.username = formData.username; 0202 updateData.password = formData.password; 0203 updateData.data = formData.postData; 0204 break; 0205 } 0206 } 0207 } 0208 0209 if (m_lastNotification && m_lastNotificationPage == page) { 0210 m_lastNotification->close(); 0211 } 0212 0213 auto* aWidget = new AutoFillNotification(frameUrl, formData, updateData); 0214 page->view()->addNotification(aWidget); 0215 0216 m_lastNotification = aWidget; 0217 m_lastNotificationPage = page; 0218 } 0219 0220 // Returns all saved passwords on this page 0221 QStringList AutoFill::completePage(WebPage *page, const QUrl &frameUrl) 0222 { 0223 QStringList usernames; 0224 0225 if (!page || !isStored(frameUrl)) 0226 return usernames; 0227 0228 if (!m_isAutoComplete) { 0229 return m_manager->getUsernames(frameUrl); 0230 } 0231 0232 const auto entries = getFormData(frameUrl); 0233 0234 if (!entries.isEmpty()) { 0235 PasswordEntry entry = entries.at(0); 0236 updateLastUsed(entry); 0237 page->runJavaScript(Scripts::completeFormData(entry.data), WebPage::SafeJsWorld); 0238 } 0239 0240 usernames.reserve(entries.size()); 0241 for (const PasswordEntry &entry : entries) { 0242 usernames.append(entry.username); 0243 } 0244 return usernames; 0245 } 0246 0247 QByteArray AutoFill::exportPasswords() 0248 { 0249 QByteArray output; 0250 0251 QXmlStreamWriter stream(&output); 0252 stream.setAutoFormatting(true); 0253 0254 stream.writeStartDocument(); 0255 stream.writeStartElement(QStringLiteral("passwords")); 0256 stream.writeAttribute(QStringLiteral("version"), QStringLiteral("1.0")); 0257 0258 const QVector<PasswordEntry> entries = m_manager->getAllEntries(); 0259 0260 for (const PasswordEntry &entry : entries) { 0261 stream.writeStartElement(QStringLiteral("entry")); 0262 stream.writeTextElement(QStringLiteral("server"), entry.host); 0263 stream.writeTextElement(QStringLiteral("username"), entry.username); 0264 stream.writeTextElement(QStringLiteral("password"), entry.password); 0265 stream.writeTextElement(QStringLiteral("data"), entry.data); 0266 stream.writeEndElement(); 0267 } 0268 0269 QSqlQuery query(SqlDatabase::instance()->database()); 0270 query.prepare(QStringLiteral("SELECT server FROM autofill_exceptions")); 0271 query.exec(); 0272 while (query.next()) { 0273 stream.writeStartElement(QStringLiteral("exception")); 0274 stream.writeTextElement(QStringLiteral("server"), query.value(0).toString()); 0275 stream.writeEndElement(); 0276 } 0277 0278 stream.writeEndElement(); 0279 stream.writeEndDocument(); 0280 0281 return output; 0282 } 0283 0284 bool AutoFill::importPasswords(const QByteArray &data) 0285 { 0286 QSqlDatabase db = QSqlDatabase::database(); 0287 db.transaction(); 0288 0289 QXmlStreamReader xml(data); 0290 0291 while (!xml.atEnd()) { 0292 xml.readNext(); 0293 0294 if (xml.isStartElement()) { 0295 if (xml.name() == QLatin1String("entry")) { 0296 PasswordEntry entry; 0297 0298 while (xml.readNext()) { 0299 if (xml.name() == QLatin1String("server")) { 0300 entry.host = xml.readElementText(); 0301 } 0302 else if (xml.name() == QLatin1String("username")) { 0303 entry.username = xml.readElementText(); 0304 } 0305 else if (xml.name() == QLatin1String("password")) { 0306 entry.password = xml.readElementText(); 0307 } 0308 else if (xml.name() == QLatin1String("data")) { 0309 entry.data = xml.readElementText().toUtf8(); 0310 } 0311 0312 if (xml.isEndElement() && xml.name() == QLatin1String("entry")) { 0313 break; 0314 } 0315 } 0316 0317 if (entry.isValid()) { 0318 bool containsEntry = false; 0319 0320 const auto entries = m_manager->getEntries(QUrl(entry.host)); 0321 for (const PasswordEntry &e : entries) { 0322 if (e.username == entry.username) { 0323 containsEntry = true; 0324 break; 0325 } 0326 } 0327 0328 if (!containsEntry) { 0329 m_manager->addEntry(entry); 0330 } 0331 } 0332 } 0333 else if (xml.name() == QLatin1String("exception")) { 0334 QString server; 0335 0336 while (xml.readNext()) { 0337 if (xml.name() == QLatin1String("server")) { 0338 server = xml.readElementText(); 0339 } 0340 0341 if (xml.isEndElement() && xml.name() == QLatin1String("exception")) { 0342 break; 0343 } 0344 } 0345 0346 if (!server.isEmpty()) { 0347 QSqlQuery query(SqlDatabase::instance()->database()); 0348 query.prepare(QStringLiteral("SELECT id FROM autofill_exceptions WHERE server=?")); 0349 query.addBindValue(server); 0350 query.exec(); 0351 0352 if (!query.next()) { 0353 query.prepare(QStringLiteral("INSERT INTO autofill_exceptions (server) VALUES (?)")); 0354 query.addBindValue(server); 0355 query.exec(); 0356 } 0357 } 0358 } 0359 } 0360 } 0361 0362 db.commit(); 0363 0364 return !xml.hasError(); 0365 }