From bd315afe9e9a2dfdf1987abaabbf2da3521080b7 Mon Sep 17 00:00:00 2001 From: nowrep Date: Tue, 14 May 2013 17:25:55 +0200 Subject: [PATCH] [AutoFill] Rewritten password management to support multiple backends. --- src/lib/app/mainapplication.cpp | 2 +- src/lib/autofill/autofill.cpp | 194 ++++-------------- src/lib/autofill/autofill.h | 29 +-- src/lib/autofill/autofillicon.cpp | 2 +- src/lib/autofill/autofillicon.h | 6 +- src/lib/autofill/autofillnotification.cpp | 4 +- src/lib/autofill/autofillnotification.h | 5 +- src/lib/autofill/autofillwidget.cpp | 8 +- src/lib/autofill/autofillwidget.h | 6 +- .../backends/databasepasswordbackend.cpp | 125 +++++++++++ .../backends/databasepasswordbackend.h | 35 ++++ src/lib/autofill/backends/passwordbackend.h | 36 ++++ src/lib/autofill/pageformcompleter.cpp | 3 +- src/lib/autofill/pageformcompleter.h | 5 +- src/lib/autofill/passwordmanager.cpp | 95 +++++++++ src/lib/autofill/passwordmanager.h | 74 +++++++ src/lib/lib.pro | 9 +- src/lib/network/networkmanager.cpp | 9 +- src/lib/webview/webpage.cpp | 9 +- src/lib/webview/webpage.h | 6 +- 20 files changed, 458 insertions(+), 204 deletions(-) create mode 100644 src/lib/autofill/backends/databasepasswordbackend.cpp create mode 100644 src/lib/autofill/backends/databasepasswordbackend.h create mode 100644 src/lib/autofill/backends/passwordbackend.h create mode 100644 src/lib/autofill/passwordmanager.cpp create mode 100644 src/lib/autofill/passwordmanager.h diff --git a/src/lib/app/mainapplication.cpp b/src/lib/app/mainapplication.cpp index 3ea5f5e04..f58b835c7 100644 --- a/src/lib/app/mainapplication.cpp +++ b/src/lib/app/mainapplication.cpp @@ -874,7 +874,7 @@ DownloadManager* MainApplication::downManager() AutoFill* MainApplication::autoFill() { if (!m_autofill) { - m_autofill = new AutoFill(getWindow()); + m_autofill = new AutoFill(this); } return m_autofill; } diff --git a/src/lib/autofill/autofill.cpp b/src/lib/autofill/autofill.cpp index d2c1cb03a..8b5849c09 100644 --- a/src/lib/autofill/autofill.cpp +++ b/src/lib/autofill/autofill.cpp @@ -25,6 +25,7 @@ #include "pageformcompleter.h" #include "databasewriter.h" #include "settings.h" +#include "passwordmanager.h" #include #include @@ -35,9 +36,9 @@ #include #endif -AutoFill::AutoFill(QupZilla* mainClass, QObject* parent) +AutoFill::AutoFill(QObject* parent) : QObject(parent) - , p_QupZilla(mainClass) + , m_manager(new PasswordManager(this)) , m_isStoring(false) { loadSettings(); @@ -57,21 +58,7 @@ bool AutoFill::isStored(const QUrl &url) return false; } - QString server = url.host(); - if (server.isEmpty()) { - server = url.toString(); - } - - QSqlQuery query; - query.prepare("SELECT count(id) FROM autofill WHERE server=?"); - query.addBindValue(server); - query.exec(); - - query.next(); - if (query.value(0).toInt() > 0) { - return true; - } - return false; + return !m_manager->getEntries(url).isEmpty(); } bool AutoFill::isStoringEnabled(const QUrl &url) @@ -89,12 +76,9 @@ bool AutoFill::isStoringEnabled(const QUrl &url) query.prepare("SELECT count(id) FROM autofill_exceptions WHERE server=?"); query.addBindValue(server); query.exec(); - query.next(); - if (query.value(0).toInt() > 0) { - return false; - } - return true; + + return query.value(0).toInt() <= 0; } void AutoFill::blockStoringforUrl(const QUrl &url) @@ -110,155 +94,60 @@ void AutoFill::blockStoringforUrl(const QUrl &url) mApp->dbWriter()->executeQuery(query); } -AutoFillData AutoFill::getFirstFormData(const QUrl &url) +QVector AutoFill::getFormData(const QUrl &url) { - const QVector &list = getFormData(url, 1); - - if (list.isEmpty()) { - AutoFillData data; - data.id = -1; - - return data; - } - - return list.first(); + return m_manager->getEntries(url); } -QVector AutoFill::getFormData(const QUrl &url, int limit) +void AutoFill::updateLastUsed(const PasswordEntry &data) { - QVector list; - - QString server = url.host(); - if (server.isEmpty()) { - server = url.toString(); - } - - QString queryString = "SELECT id, username, password, data FROM autofill " - "WHERE server=? ORDER BY last_used DESC"; - if (limit > 0) { - queryString.append(QLatin1String(" LIMIT ?")); - } - - QSqlQuery query; - query.prepare(queryString); - query.addBindValue(server); - - if (limit > 0) { - query.addBindValue(limit); - } - - query.exec(); - - while (query.next()) { - AutoFillData data; - data.id = query.value(0).toInt(); - data.username = query.value(1).toString(); - data.password = query.value(2).toString(); - data.postData = query.value(3).toByteArray(); - - list.append(data); - } - - return list; - + m_manager->updateLastUsed(data); } -void AutoFill::updateLastUsed(int id) -{ - if (id < 0) { - return; - } - - QSqlQuery query; - query.prepare("UPDATE autofill SET last_used=strftime('%s', 'now') WHERE id=?"); - query.addBindValue(id); - query.exec(); -} - -///HTTP Authorization +// HTTP Authorization void AutoFill::addEntry(const QUrl &url, const QString &name, const QString &pass) { - QSqlQuery query; - QString server = url.host(); - if (server.isEmpty()) { - server = url.toString(); - } + PasswordEntry entry; + entry.url = url; + entry.username = name; + entry.password = pass; - // Multiple-usernames for HTTP Authorization not supported - query.prepare("SELECT username FROM autofill WHERE server=?"); - query.addBindValue(server); - query.exec(); - - if (query.next()) { - return; - } - - query.prepare("INSERT INTO autofill (server, username, password, last_used) " - "VALUES (?,?,?,strftime('%s', 'now'))"); - query.bindValue(0, server); - query.bindValue(1, name); - query.bindValue(2, pass); - mApp->dbWriter()->executeQuery(query); + m_manager->addEntry(entry); } -///WEB Form +// WEB Form void AutoFill::addEntry(const QUrl &url, const PageFormData &formData) { - QString server = url.host(); - if (server.isEmpty()) { - server = url.toString(); - } + PasswordEntry entry; + entry.url = url; + entry.username = formData.username; + entry.password = formData.password; - QSqlQuery query; - query.prepare("INSERT INTO autofill (server, data, username, password, last_used) " - "VALUES (?,?,?,?,strftime('%s', 'now'))"); - query.bindValue(0, server); - query.bindValue(1, formData.postData); - query.bindValue(2, formData.username); - query.bindValue(3, formData.password); - mApp->dbWriter()->executeQuery(query); + m_manager->addEntry(entry); } +// HTTP Authorization void AutoFill::updateEntry(const QUrl &url, const QString &name, const QString &pass) { - QSqlQuery query; - QString server = url.host(); - if (server.isEmpty()) { - server = url.toString(); - } + PasswordEntry entry; + entry.url = url; + entry.username = name; + entry.password = pass; - query.prepare("SELECT username FROM autofill WHERE server=?"); - query.addBindValue(server); - query.exec(); - - if (!query.next()) { - return; - } - - query.prepare("UPDATE autofill SET username=?, password=? WHERE server=?"); - query.bindValue(0, name); - query.bindValue(1, pass); - query.bindValue(2, server); - mApp->dbWriter()->executeQuery(query); + m_manager->updateEntry(entry); } -void AutoFill::updateEntry(const PageFormData &formData, const AutoFillData &updateData) +// WEB Form +void AutoFill::updateEntry(const PasswordEntry &entry) { - QSqlQuery query; - query.prepare("UPDATE autofill SET data=?, username=?, password=? WHERE id=?"); - query.addBindValue(formData.postData); - query.addBindValue(formData.username); - query.addBindValue(formData.password); - query.addBindValue(updateData.id); - - mApp->dbWriter()->executeQuery(query); + m_manager->updateEntry(entry); } // If password was filled in the page, returns all saved passwords on this page -QVector AutoFill::completePage(WebPage* page) +QVector AutoFill::completePage(WebPage* page) { bool completed = false; - QVector list; + QVector list; if (!page) { return list; @@ -272,10 +161,10 @@ QVector AutoFill::completePage(WebPage* page) list = getFormData(pageUrl); if (!list.isEmpty()) { - const AutoFillData data = getFirstFormData(pageUrl); + const PasswordEntry entry = list.first(); PageFormCompleter completer(page); - completed = completer.completePage(data.postData); + completed = completer.completePage(entry.data); } if (!completed) { @@ -311,24 +200,27 @@ void AutoFill::post(const QNetworkRequest &request, const QByteArray &outgoingDa PageFormCompleter completer(webPage); const PageFormData formData = completer.extractFormData(outgoingData); - if (!formData.found) { + if (!formData.isValid()) { return; } - AutoFillData updateData = { -1, QString(), QString(), QByteArray() }; + PasswordEntry updateData = { -1, QUrl(), QString(), QString(), QByteArray() }; if (isStored(siteUrl)) { - const QVector &list = getFormData(siteUrl); + const QVector &list = getFormData(siteUrl); - foreach (const AutoFillData &data, list) { + foreach (const PasswordEntry &data, list) { if (data.username == formData.username) { - updateLastUsed(data.id); + updateLastUsed(data); if (data.password == formData.password) { return; } updateData = data; + updateData.username = formData.username; + updateData.password = formData.password; + updateData.data = formData.postData; break; } } diff --git a/src/lib/autofill/autofill.h b/src/lib/autofill/autofill.h index 631d63a3c..6ac429466 100644 --- a/src/lib/autofill/autofill.h +++ b/src/lib/autofill/autofill.h @@ -29,23 +29,14 @@ class QNetworkRequest; class QupZilla; class WebPage; +class PasswordManager; struct PageFormData; - -struct AutoFillData { - int id; - QString username; - QString password; - QByteArray postData; - - bool isValid() const { - return id > -1; - } -}; +struct PasswordEntry; class QT_QUPZILLA_EXPORT AutoFill : public QObject { public: - explicit AutoFill(QupZilla* mainClass, QObject* parent = 0); + explicit AutoFill(QObject* parent = 0); void loadSettings(); @@ -53,30 +44,26 @@ public: bool isStoringEnabled(const QUrl &url); void blockStoringforUrl(const QUrl &url); - AutoFillData getFirstFormData(const QUrl &url); - QVector getFormData(const QUrl &url, int limit = 0); + QVector getFormData(const QUrl &url); - void updateLastUsed(int id); + void updateLastUsed(const PasswordEntry &data); void addEntry(const QUrl &url, const QString &name, const QString &pass); void addEntry(const QUrl &url, const PageFormData &formData); void updateEntry(const QUrl &url, const QString &name, const QString &pass); - void updateEntry(const PageFormData &formData, const AutoFillData &updateData); + void updateEntry(const PasswordEntry &entry); void post(const QNetworkRequest &request, const QByteArray &outgoingData); - QVector completePage(WebPage* page); + QVector completePage(WebPage* page); static QByteArray exportPasswords(); static bool importPasswords(const QByteArray &data); private: - QupZilla* p_QupZilla; + PasswordManager* m_manager; bool m_isStoring; }; -// Hint to QVector to use std::realloc on item moving -Q_DECLARE_TYPEINFO(AutoFillData, Q_MOVABLE_TYPE); - #endif // AUTOFILLMODEL_H diff --git a/src/lib/autofill/autofillicon.cpp b/src/lib/autofill/autofillicon.cpp index ed3e12d39..09fb600bc 100644 --- a/src/lib/autofill/autofillicon.cpp +++ b/src/lib/autofill/autofillicon.cpp @@ -37,7 +37,7 @@ void AutoFillIcon::setWebView(WebView* view) m_view = view; } -void AutoFillIcon::setFormData(const QVector &data) +void AutoFillIcon::setFormData(const QVector &data) { m_data = data; } diff --git a/src/lib/autofill/autofillicon.h b/src/lib/autofill/autofillicon.h index c677fb074..9ea11e082 100644 --- a/src/lib/autofill/autofillicon.h +++ b/src/lib/autofill/autofillicon.h @@ -20,7 +20,7 @@ #include "qz_namespace.h" #include "clickablelabel.h" -#include "autofill.h" +#include "passwordmanager.h" class WebView; @@ -32,7 +32,7 @@ public: explicit AutoFillIcon(QWidget* parent = 0); void setWebView(WebView* view); - void setFormData(const QVector &data); + void setFormData(const QVector &data); private slots: void iconClicked(); @@ -43,7 +43,7 @@ private: WebView* m_view; - QVector m_data; + QVector m_data; }; diff --git a/src/lib/autofill/autofillnotification.cpp b/src/lib/autofill/autofillnotification.cpp index 3da9da6c6..2eaad8d77 100644 --- a/src/lib/autofill/autofillnotification.cpp +++ b/src/lib/autofill/autofillnotification.cpp @@ -22,7 +22,7 @@ #include "animatedwidget.h" #include "iconprovider.h" -AutoFillNotification::AutoFillNotification(const QUrl &url, const PageFormData &formData, const AutoFillData &updateData) +AutoFillNotification::AutoFillNotification(const QUrl &url, const PageFormData &formData, const PasswordEntry &updateData) : AnimatedWidget(AnimatedWidget::Down, 300, 0) , ui(new Ui::AutoFillNotification) , m_url(url) @@ -68,7 +68,7 @@ AutoFillNotification::AutoFillNotification(const QUrl &url, const PageFormData & void AutoFillNotification::update() { - mApp->autoFill()->updateEntry(m_formData, m_updateData); + mApp->autoFill()->updateEntry(m_updateData); hide(); } diff --git a/src/lib/autofill/autofillnotification.h b/src/lib/autofill/autofillnotification.h index 32eb8b590..af572875a 100644 --- a/src/lib/autofill/autofillnotification.h +++ b/src/lib/autofill/autofillnotification.h @@ -23,6 +23,7 @@ #include "qz_namespace.h" #include "animatedwidget.h" #include "pageformcompleter.h" +#include "passwordmanager.h" #include "autofill.h" namespace Ui @@ -39,7 +40,7 @@ class QT_QUPZILLA_EXPORT AutoFillNotification : public AnimatedWidget public: explicit AutoFillNotification(const QUrl &url, const PageFormData &formData, - const AutoFillData &updateData); + const PasswordEntry &updateData); ~AutoFillNotification(); private slots: @@ -52,7 +53,7 @@ private: QUrl m_url; PageFormData m_formData; - AutoFillData m_updateData; + PasswordEntry m_updateData; }; #endif // AUTOFILLNOTIFICATION_H diff --git a/src/lib/autofill/autofillwidget.cpp b/src/lib/autofill/autofillwidget.cpp index f458a05fa..2478d3c99 100644 --- a/src/lib/autofill/autofillwidget.cpp +++ b/src/lib/autofill/autofillwidget.cpp @@ -33,12 +33,12 @@ AutoFillWidget::AutoFillWidget(WebView* view, QWidget* parent) ui->setupUi(this); } -void AutoFillWidget::setFormData(const QVector &data) +void AutoFillWidget::setFormData(const QVector &data) { m_data = data; for (int i = 0; i < data.count(); ++i) { - const AutoFillData d = data.at(i); + const PasswordEntry d = data.at(i); if (d.username.isEmpty()) { continue; } @@ -67,10 +67,10 @@ void AutoFillWidget::loginToPage() int index = button->property("data-index").toInt(&ok); if (ok && QzTools::vectorContainsIndex(m_data, index)) { - const AutoFillData data = m_data.at(index); + const PasswordEntry entry = m_data.at(index); PageFormCompleter completer(m_view->page()); - completer.completePage(data.postData); + completer.completePage(entry.data); } close(); diff --git a/src/lib/autofill/autofillwidget.h b/src/lib/autofill/autofillwidget.h index 048e0a9c8..1787de820 100644 --- a/src/lib/autofill/autofillwidget.h +++ b/src/lib/autofill/autofillwidget.h @@ -30,7 +30,7 @@ class AutoFillWidget; } class WebView; -struct AutoFillData; +struct PasswordEntry; class QT_QUPZILLA_EXPORT AutoFillWidget : public LocationBarPopup { @@ -40,7 +40,7 @@ public: explicit AutoFillWidget(WebView* view, QWidget* parent = 0); ~AutoFillWidget(); - void setFormData(const QVector &data); + void setFormData(const QVector &data); private slots: void loginToPage(); @@ -49,7 +49,7 @@ private: Ui::AutoFillWidget* ui; WebView* m_view; - QVector m_data; + QVector m_data; }; #endif // AUTOFILLWIDGET_H diff --git a/src/lib/autofill/backends/databasepasswordbackend.cpp b/src/lib/autofill/backends/databasepasswordbackend.cpp new file mode 100644 index 000000000..0e1174d56 --- /dev/null +++ b/src/lib/autofill/backends/databasepasswordbackend.cpp @@ -0,0 +1,125 @@ +/* ============================================================ +* QupZilla - WebKit based browser +* Copyright (C) 2013 David Rosca +* +* This program is free software: you can redistribute it and/or modify +* it under the terms of the GNU General Public License as published by +* the Free Software Foundation, either version 3 of the License, or +* (at your option) any later version. +* +* This program is distributed in the hope that it will be useful, +* but WITHOUT ANY WARRANTY; without even the implied warranty of +* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +* GNU General Public License for more details. +* +* You should have received a copy of the GNU General Public License +* along with this program. If not, see . +* ============================================================ */ +#include "databasepasswordbackend.h" +#include "mainapplication.h" +#include "databasewriter.h" + +#include +#include + +DatabasePasswordBackend::DatabasePasswordBackend() +{ +} + +QVector DatabasePasswordBackend::getEntries(const QUrl &url) +{ + QVector list; + + QString server = url.host(); + if (server.isEmpty()) { + server = url.toString(); + } + + QString query = "SELECT id, username, password, data FROM autofill " + "WHERE server=? ORDER BY last_used DESC"; + + QSqlQuery sqlQuery; + sqlQuery.prepare(query); + sqlQuery.addBindValue(server); + sqlQuery.exec(); + + while (sqlQuery.next()) { + PasswordEntry data; + data.id = sqlQuery.value(0); + data.url = url; + data.username = sqlQuery.value(1).toString(); + data.password = sqlQuery.value(2).toString(); + data.data = sqlQuery.value(3).toByteArray(); + + list.append(data); + } + + return list; +} + +void DatabasePasswordBackend::addEntry(const PasswordEntry &entry) +{ + QString server = entry.url.host(); + if (server.isEmpty()) { + server = entry.url.toString(); + } + + // Data is empty only for HTTP/FTP authorization + if (entry.data.isEmpty()) { + // Multiple-usernames for HTTP/FTP authorization not supported + QSqlQuery query; + query.prepare("SELECT username FROM autofill WHERE server=?"); + query.addBindValue(server); + query.exec(); + + if (query.next()) { + return; + } + } + + QSqlQuery query; + query.prepare("INSERT INTO autofill (server, data, username, password, last_used) " + "VALUES (?,?,?,?,strftime('%s', 'now'))"); + query.bindValue(0, server); + query.bindValue(1, entry.data); + query.bindValue(2, entry.username); + query.bindValue(3, entry.password); + + mApp->dbWriter()->executeQuery(query); +} + +void DatabasePasswordBackend::updateEntry(const PasswordEntry &entry) +{ + QSqlQuery query; + + // Data is empty only for HTTP/FTP authorization + if (entry.data.isEmpty()) { + QString server = entry.url.host(); + if (server.isEmpty()) { + server = entry.url.toString(); + } + + query.prepare("UPDATE autofill SET username=?, password=? WHERE server=?"); + query.bindValue(0, entry.username); + query.bindValue(1, entry.password); + query.bindValue(2, server); + } + else { + query.prepare("UPDATE autofill SET data=?, username=?, password=? WHERE id=?"); + query.addBindValue(entry.data); + query.addBindValue(entry.username); + query.addBindValue(entry.password); + query.addBindValue(entry.id); + } + + mApp->dbWriter()->executeQuery(query); +} + +void DatabasePasswordBackend::updateLastUsed(const PasswordEntry &entry) +{ + QSqlQuery query; + query.prepare("UPDATE autofill SET last_used=strftime('%s', 'now') WHERE id=?"); + query.addBindValue(entry.id); + + mApp->dbWriter()->executeQuery(query); +} diff --git a/src/lib/autofill/backends/databasepasswordbackend.h b/src/lib/autofill/backends/databasepasswordbackend.h new file mode 100644 index 000000000..930bc724f --- /dev/null +++ b/src/lib/autofill/backends/databasepasswordbackend.h @@ -0,0 +1,35 @@ +/* ============================================================ +* QupZilla - WebKit based browser +* Copyright (C) 2013 David Rosca +* +* This program is free software: you can redistribute it and/or modify +* it under the terms of the GNU General Public License as published by +* the Free Software Foundation, either version 3 of the License, or +* (at your option) any later version. +* +* This program is distributed in the hope that it will be useful, +* but WITHOUT ANY WARRANTY; without even the implied warranty of +* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +* GNU General Public License for more details. +* +* You should have received a copy of the GNU General Public License +* along with this program. If not, see . +* ============================================================ */ +#ifndef DATABASEPASSWORDBACKEND_H +#define DATABASEPASSWORDBACKEND_H + +#include "passwordbackend.h" + +class DatabasePasswordBackend : public PasswordBackend +{ +public: + explicit DatabasePasswordBackend(); + + QVector getEntries(const QUrl &url); + + void addEntry(const PasswordEntry &entry); + void updateEntry(const PasswordEntry &entry); + void updateLastUsed(const PasswordEntry &entry); +}; + +#endif // DATABASEPASSWORDBACKEND_H diff --git a/src/lib/autofill/backends/passwordbackend.h b/src/lib/autofill/backends/passwordbackend.h new file mode 100644 index 000000000..766167a58 --- /dev/null +++ b/src/lib/autofill/backends/passwordbackend.h @@ -0,0 +1,36 @@ +/* ============================================================ +* QupZilla - WebKit based browser +* Copyright (C) 2013 David Rosca +* +* This program is free software: you can redistribute it and/or modify +* it under the terms of the GNU General Public License as published by +* the Free Software Foundation, either version 3 of the License, or +* (at your option) any later version. +* +* This program is distributed in the hope that it will be useful, +* but WITHOUT ANY WARRANTY; without even the implied warranty of +* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +* GNU General Public License for more details. +* +* You should have received a copy of the GNU General Public License +* along with this program. If not, see . +* ============================================================ */ +#ifndef PASSWORDBACKEND_H +#define PASSWORDBACKEND_H + +#include "passwordmanager.h" + +class PasswordBackend +{ +public: + explicit PasswordBackend() { } + virtual ~PasswordBackend() { } + + virtual QVector getEntries(const QUrl &url) = 0; + + virtual void addEntry(const PasswordEntry &entry) = 0; + virtual void updateEntry(const PasswordEntry &entry) = 0; + virtual void updateLastUsed(const PasswordEntry &entry) = 0; +}; + +#endif // PASSWORDBACKEND_H diff --git a/src/lib/autofill/pageformcompleter.cpp b/src/lib/autofill/pageformcompleter.cpp index eb379f29f..55f071130 100644 --- a/src/lib/autofill/pageformcompleter.cpp +++ b/src/lib/autofill/pageformcompleter.cpp @@ -37,7 +37,7 @@ PageFormData PageFormCompleter::extractFormData(const QByteArray &postData) cons QString passwordValue; QByteArray data = convertWebKitFormBoundaryIfNecessary(postData); - PageFormData formData = {false, QString(), QString(), data}; + PageFormData formData = {QString(), QString(), data}; if (data.isEmpty() || !data.contains('=')) { return formData; @@ -83,7 +83,6 @@ PageFormData PageFormCompleter::extractFormData(const QByteArray &postData) cons return formData; } - formData.found = true; formData.username = usernameValue; formData.password = passwordValue; diff --git a/src/lib/autofill/pageformcompleter.h b/src/lib/autofill/pageformcompleter.h index 44393d5dd..135ebddaf 100644 --- a/src/lib/autofill/pageformcompleter.h +++ b/src/lib/autofill/pageformcompleter.h @@ -29,10 +29,13 @@ class QWebElement; class QWebElementCollection; struct PageFormData { - bool found; QString username; QString password; QByteArray postData; + + bool isValid() const { + return !password.isEmpty(); + } }; class PageFormCompleter diff --git a/src/lib/autofill/passwordmanager.cpp b/src/lib/autofill/passwordmanager.cpp new file mode 100644 index 000000000..fab351912 --- /dev/null +++ b/src/lib/autofill/passwordmanager.cpp @@ -0,0 +1,95 @@ +/* ============================================================ +* QupZilla - WebKit based browser +* Copyright (C) 2013 David Rosca +* +* This program is free software: you can redistribute it and/or modify +* it under the terms of the GNU General Public License as published by +* the Free Software Foundation, either version 3 of the License, or +* (at your option) any later version. +* +* This program is distributed in the hope that it will be useful, +* but WITHOUT ANY WARRANTY; without even the implied warranty of +* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +* GNU General Public License for more details. +* +* You should have received a copy of the GNU General Public License +* along with this program. If not, see . +* ============================================================ */ +#include "passwordmanager.h" +#include "backends/passwordbackend.h" +#include "backends/databasepasswordbackend.h" +#include "settings.h" + +#include + +PasswordManager::PasswordManager(QObject* parent) + : QObject(parent) + , m_backend(0) + , m_loaded(false) + , m_databaseBackend(new DatabasePasswordBackend) +{ + m_backends["database"] = m_databaseBackend; +} + +void PasswordManager::loadSettings() +{ + Settings settings; + settings.beginGroup("PasswordManager"); + QString backendId = settings.value("Backend", "database").toString(); + settings.endGroup(); + + m_backend = m_backends[m_backends.contains(backendId) ? backendId : "database"]; +} + +QVector PasswordManager::getEntries(const QUrl &url) +{ + ensureLoaded(); + return m_backend->getEntries(url); +} + +void PasswordManager::addEntry(const PasswordEntry &entry) +{ + ensureLoaded(); + m_backend->addEntry(entry); +} + +void PasswordManager::updateEntry(const PasswordEntry &entry) +{ + ensureLoaded(); + m_backend->updateEntry(entry); +} + +void PasswordManager::updateLastUsed(const PasswordEntry &entry) +{ + ensureLoaded(); + m_backend->updateLastUsed(entry); +} + +bool PasswordManager::registerBackend(const QString &id, PasswordBackend* backend) +{ + if (m_backends.contains(id)) { + return false; + } + + m_backends[id] = backend; + return true; +} + +void PasswordManager::unregisterBackend(PasswordBackend* backend) +{ + const QString &key = m_backends.key(backend); + m_backends.remove(key); +} + +void PasswordManager::ensureLoaded() +{ + if (!m_loaded) { + loadSettings(); + m_loaded = true; + } +} + +PasswordManager::~PasswordManager() +{ + delete m_databaseBackend; +} diff --git a/src/lib/autofill/passwordmanager.h b/src/lib/autofill/passwordmanager.h new file mode 100644 index 000000000..2e66425f3 --- /dev/null +++ b/src/lib/autofill/passwordmanager.h @@ -0,0 +1,74 @@ +/* ============================================================ +* QupZilla - WebKit based browser +* Copyright (C) 2013 David Rosca +* +* This program is free software: you can redistribute it and/or modify +* it under the terms of the GNU General Public License as published by +* the Free Software Foundation, either version 3 of the License, or +* (at your option) any later version. +* +* This program is distributed in the hope that it will be useful, +* but WITHOUT ANY WARRANTY; without even the implied warranty of +* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +* GNU General Public License for more details. +* +* You should have received a copy of the GNU General Public License +* along with this program. If not, see . +* ============================================================ */ +#ifndef PASSWORDMANAGER_H +#define PASSWORDMANAGER_H + +#include +#include +#include + +#include "qz_namespace.h" + +class PasswordBackend; +class DatabasePasswordBackend; + +struct PasswordEntry { + QVariant id; + QUrl url; + QString username; + QString password; + QByteArray data; + + bool isValid() const { + return !password.isEmpty(); + } +}; + +class QT_QUPZILLA_EXPORT PasswordManager : public QObject +{ + Q_OBJECT +public: + explicit PasswordManager(QObject* parent = 0); + ~PasswordManager(); + + void loadSettings(); + + QVector getEntries(const QUrl &url); + + void addEntry(const PasswordEntry &entry); + void updateEntry(const PasswordEntry &entry); + void updateLastUsed(const PasswordEntry &entry); + + + bool registerBackend(const QString &id, PasswordBackend* backend); + void unregisterBackend(PasswordBackend* backend); + +private: + void ensureLoaded(); + + PasswordBackend* m_backend; + bool m_loaded; + + DatabasePasswordBackend* m_databaseBackend; + QHash m_backends; +}; + +// Hint to QVector to use std::realloc on item moving +Q_DECLARE_TYPEINFO(PasswordEntry, Q_MOVABLE_TYPE); + +#endif // PASSWORDMANAGER_H diff --git a/src/lib/lib.pro b/src/lib/lib.pro index fe4d16f98..2b53a943b 100644 --- a/src/lib/lib.pro +++ b/src/lib/lib.pro @@ -215,7 +215,9 @@ SOURCES += \ tools/actioncopy.cpp \ network/pac/proxyautoconfig.cpp \ network/pac/pacmanager.cpp \ - tools/delayedfilewatcher.cpp + tools/delayedfilewatcher.cpp \ + autofill/passwordmanager.cpp \ + autofill/backends/databasepasswordbackend.cpp HEADERS += \ webview/tabpreview.h \ @@ -391,7 +393,10 @@ HEADERS += \ network/pac/proxyautoconfig.h \ network/pac/pacmanager.h \ network/pac/pacdatetime.h \ - tools/delayedfilewatcher.h + tools/delayedfilewatcher.h \ + autofill/passwordmanager.h \ + autofill/backends/passwordbackend.h \ + autofill/backends/databasepasswordbackend.h FORMS += \ preferences/autofillmanager.ui \ diff --git a/src/lib/network/networkmanager.cpp b/src/lib/network/networkmanager.cpp index 1b9e7c982..b39e51a16 100644 --- a/src/lib/network/networkmanager.cpp +++ b/src/lib/network/networkmanager.cpp @@ -30,6 +30,7 @@ #include "acceptlanguage.h" #include "cabundleupdater.h" #include "settings.h" +#include "passwordmanager.h" #include "schemehandlers/adblockschemehandler.h" #include "schemehandlers/qupzillaschemehandler.h" #include "schemehandlers/fileschemehandler.h" @@ -291,13 +292,13 @@ void NetworkManager::authentication(QNetworkReply* reply, QAuthenticator* auth) QString storedUser; QString storedPassword; if (fill->isStored(reply->url())) { - const AutoFillData &data = fill->getFirstFormData(reply->url()); + const QVector &data = fill->getFormData(reply->url()); - if (data.isValid()) { + if (!data.isEmpty()) { save->setChecked(true); shouldUpdateEntry = true; - storedUser = data.username; - storedPassword = data.password; + storedUser = data.first().username; + storedPassword = data.first().password; user->setText(storedUser); pass->setText(storedPassword); } diff --git a/src/lib/webview/webpage.cpp b/src/lib/webview/webpage.cpp index cd07d2634..687906323 100644 --- a/src/lib/webview/webpage.cpp +++ b/src/lib/webview/webpage.cpp @@ -27,6 +27,7 @@ #include "widget.h" #include "qztools.h" #include "speeddial.h" +#include "autofill.h" #include "popupwebpage.h" #include "popupwebview.h" #include "networkmanagerproxy.h" @@ -254,7 +255,7 @@ void WebPage::finished() } // Autofill - m_autoFillData = mApp->autoFill()->completePage(this); + m_passwordEntries = mApp->autoFill()->completePage(this); // AdBlock cleanBlockedObjects(); @@ -593,12 +594,12 @@ QVector WebPage::adBlockedEntries() const bool WebPage::hasMultipleUsernames() const { - return m_autoFillData.count() > 1; + return m_passwordEntries.count() > 1; } -QVector WebPage::autoFillData() const +QVector WebPage::autoFillData() const { - return m_autoFillData; + return m_passwordEntries; } void WebPage::cleanBlockedObjects() diff --git a/src/lib/webview/webpage.h b/src/lib/webview/webpage.h index ddae698fe..6e05dcba8 100644 --- a/src/lib/webview/webpage.h +++ b/src/lib/webview/webpage.h @@ -23,7 +23,7 @@ #include #include "qz_namespace.h" -#include "autofill.h" +#include "passwordmanager.h" class QWebSecurityOrigin; class QEventLoop; @@ -67,7 +67,7 @@ public: QVector adBlockedEntries() const; bool hasMultipleUsernames() const; - QVector autoFillData() const; + QVector autoFillData() const; void scheduleAdjustPage(); bool isRunningLoop(); @@ -138,7 +138,7 @@ private: QSslCertificate m_sslCert; QVector m_rejectedSslCerts; QVector m_adBlockedEntries; - QVector m_autoFillData; + QVector m_passwordEntries; QWebPage::NavigationType m_lastRequestType; QUrl m_lastRequestUrl;