diff --git a/src/lib/adblock/adblockmanager.cpp b/src/lib/adblock/adblockmanager.cpp index 652127d08..ced7f6146 100644 --- a/src/lib/adblock/adblockmanager.cpp +++ b/src/lib/adblock/adblockmanager.cpp @@ -24,7 +24,6 @@ #include "mainapplication.h" #include "webpage.h" #include "qztools.h" -#include "networkmanager.h" #include "browserwindow.h" #include "settings.h" diff --git a/src/lib/app/browserwindow.cpp b/src/lib/app/browserwindow.cpp index 79bfbfb74..4f4dd93e6 100644 --- a/src/lib/app/browserwindow.cpp +++ b/src/lib/app/browserwindow.cpp @@ -33,7 +33,6 @@ #include "bookmarkstoolbar.h" #include "clearprivatedata.h" #include "sourceviewer.h" -#include "networkmanager.h" #include "autofill.h" #include "networkmanagerproxy.h" #include "mainapplication.h" diff --git a/src/lib/app/mainapplication.cpp b/src/lib/app/mainapplication.cpp index 7f3602a3e..8a7ceb775 100644 --- a/src/lib/app/mainapplication.cpp +++ b/src/lib/app/mainapplication.cpp @@ -33,7 +33,6 @@ #include "pluginproxy.h" #include "iconprovider.h" #include "browserwindow.h" -#include "networkmanager.h" #include "checkboxdialog.h" #include "profilemanager.h" #include "adblockmanager.h" @@ -268,6 +267,7 @@ MainApplication::MainApplication(int &argc, char** argv) loadSettings(); m_plugins = new PluginProxy; + m_autoFill = new AutoFill(this); if (!noAddons) m_plugins->loadPlugins(); @@ -503,9 +503,6 @@ Bookmarks* MainApplication::bookmarks() AutoFill* MainApplication::autoFill() { - if (!m_autoFill) { - m_autoFill = new AutoFill(this); - } return m_autoFill; } diff --git a/src/lib/autofill/autofill.cpp b/src/lib/autofill/autofill.cpp index 9fdc8d2fe..ce8319adb 100644 --- a/src/lib/autofill/autofill.cpp +++ b/src/lib/autofill/autofill.cpp @@ -23,14 +23,16 @@ #include "popupwebview.h" #include "mainapplication.h" #include "autofillnotification.h" -#include "pageformcompleter.h" #include "settings.h" #include "passwordmanager.h" #include "qztools.h" +#include "scripts.h" #include #include #include +#include +#include #include @@ -40,6 +42,15 @@ AutoFill::AutoFill(QObject* parent) , m_isStoring(false) { loadSettings(); + + // Setup AutoFill userscript + QWebEngineScript script; + script.setName(QSL("_qupzilla_autofill")); + script.setInjectionPoint(QWebEngineScript::DocumentReady); + script.setWorldId(QWebEngineScript::MainWorld); + script.setRunsOnSubFrames(true); + script.setSourceCode(Scripts::setupFormObserver()); + mApp->webProfile()->scripts()->insert(script); } PasswordManager* AutoFill::passwordManager() const @@ -166,75 +177,18 @@ void AutoFill::removeAllEntries() m_manager->removeAllEntries(); } -// If password was filled in the page, returns all saved passwords on this page -QVector AutoFill::completeFrame(QWebEngineFrame* frame) +void AutoFill::saveForm(QWebEnginePage *page, const QUrl &frameUrl, const PageFormData &formData) { - bool completed = false; - QVector list; - - if (!frame) { - return list; - } - -#if QTWEBENGINE_DISABLED - const QUrl frameUrl = QzTools::frameUrl(frame); - if (!isStored(frameUrl)) { - return list; - } - - list = getFormData(frameUrl); -#endif - - if (!list.isEmpty()) { - const PasswordEntry entry = list.first(); - - PageFormCompleter completer; - completed = completer.completeFormData(frame, entry.data); - } - - if (!completed) { - list.clear(); - } - - return list; -} - -void AutoFill::post(const QNetworkRequest &request, const QByteArray &outgoingData) -{ - Q_UNUSED(request) - Q_UNUSED(outgoingData) -#if QTWEBENGINE_DISABLED // Don't save in private browsing - if (mApp->isPrivate()) { + if (mApp->isPrivate() || !page) return; - } - QWebEngineFrame* frame = qobject_cast(request.originatingObject()); - if (!frame) { + WebView* webView = qobject_cast(page->view()); + if (!webView) return; - } - WebPage* webPage = qobject_cast(frame->page()); - if (!webPage) { + if (!isStoringEnabled(frameUrl)) return; - } - - WebView* webView = qobject_cast(webPage->view()); - if (!webView) { - return; - } - - const QUrl frameUrl = QzTools::frameUrl(frame); - if (!isStoringEnabled(frameUrl)) { - return; - } - - PageFormCompleter completer; - const PageFormData formData = completer.extractFormData(frame, outgoingData); - - if (!formData.isValid()) { - return; - } PasswordEntry updateData; @@ -261,7 +215,24 @@ void AutoFill::post(const QNetworkRequest &request, const QByteArray &outgoingDa AutoFillNotification* aWidget = new AutoFillNotification(frameUrl, formData, updateData); webView->addNotification(aWidget); -#endif +} + +// Returns all saved passwords on this page +QVector AutoFill::completePage(QWebEnginePage *page, const QUrl &frameUrl) +{ + QVector list; + + if (!page || !isStored(frameUrl)) + return list; + + list = getFormData(frameUrl); + + if (!list.isEmpty()) { + const PasswordEntry entry = list.first(); + page->runJavaScript(Scripts::completeFormData(entry.data)); + } + + return list; } QByteArray AutoFill::exportPasswords() diff --git a/src/lib/autofill/autofill.h b/src/lib/autofill/autofill.h index e45991da8..6182e7290 100644 --- a/src/lib/autofill/autofill.h +++ b/src/lib/autofill/autofill.h @@ -23,8 +23,7 @@ #include "qzcommon.h" class QUrl; -class QWebEngineFrame; -class QWebElement; +class QWebEnginePage; class QNetworkRequest; class BrowserWindow; @@ -32,6 +31,16 @@ class PasswordManager; struct PageFormData; struct PasswordEntry; +struct PageFormData { + QString username; + QString password; + QByteArray postData; + + bool isValid() const { + return !password.isEmpty(); + } +}; + class QUPZILLA_EXPORT AutoFill : public QObject { Q_OBJECT @@ -60,8 +69,8 @@ public: void removeEntry(const PasswordEntry &entry); void removeAllEntries(); - void post(const QNetworkRequest &request, const QByteArray &outgoingData); - QVector completeFrame(QWebEngineFrame *frame); + void saveForm(QWebEnginePage *page, const QUrl &frameUrl, const PageFormData &formData); + QVector completePage(QWebEnginePage *page, const QUrl &frameUrl); QByteArray exportPasswords(); bool importPasswords(const QByteArray &data); diff --git a/src/lib/autofill/autofillnotification.h b/src/lib/autofill/autofillnotification.h index 7a3a1b859..2b5de56b2 100644 --- a/src/lib/autofill/autofillnotification.h +++ b/src/lib/autofill/autofillnotification.h @@ -22,7 +22,6 @@ #include "qzcommon.h" #include "animatedwidget.h" -#include "pageformcompleter.h" #include "passwordmanager.h" #include "autofill.h" diff --git a/src/lib/autofill/autofillwidget.cpp b/src/lib/autofill/autofillwidget.cpp index 27a69cf19..23a9be0e6 100644 --- a/src/lib/autofill/autofillwidget.cpp +++ b/src/lib/autofill/autofillwidget.cpp @@ -17,11 +17,11 @@ * ============================================================ */ #include "autofillwidget.h" #include "ui_autofillwidget.h" -#include "pageformcompleter.h" #include "autofill.h" #include "qztools.h" #include "webview.h" #include "webpage.h" +#include "scripts.h" #include @@ -67,9 +67,7 @@ void AutoFillWidget::loginToPage() if (ok && QzTools::containsIndex(m_data, index)) { const PasswordEntry entry = m_data.at(index); - - PageFormCompleter completer; - completer.completeFormData(m_view->page(), entry.data); + m_view->page()->runJavaScript(Scripts::completeFormData(entry.data)); } close(); diff --git a/src/lib/autofill/pageformcompleter.cpp b/src/lib/autofill/pageformcompleter.cpp deleted file mode 100644 index 424789c2e..000000000 --- a/src/lib/autofill/pageformcompleter.cpp +++ /dev/null @@ -1,284 +0,0 @@ -/* ============================================================ -* QupZilla - WebKit based browser -* Copyright (C) 2013-2014 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 "pageformcompleter.h" -#include "qzregexp.h" - -#include -#include - -PageFormCompleter::PageFormCompleter() - : m_page(0) - , m_frame(0) -{ -} - -PageFormData PageFormCompleter::extractFormData(QWebEnginePage* page, const QByteArray &postData) -{ - m_page = page; - return extractFormData(postData); -} - -PageFormData PageFormCompleter::extractFormData(QWebEngineFrame* frame, const QByteArray &postData) -{ - m_frame = frame; - return extractFormData(postData); -} - -bool PageFormCompleter::completeFormData(QWebEnginePage* page, const QByteArray &data) -{ - m_page = page; - return completeFormData(data); -} - -bool PageFormCompleter::completeFormData(QWebEngineFrame* frame, const QByteArray &data) -{ - m_frame = frame; - return completeFormData(data); -} - -PageFormData PageFormCompleter::extractFormData(const QByteArray &postData) const -{ - QString usernameValue; - QString passwordValue; - - QByteArray data = convertWebKitFormBoundaryIfNecessary(postData); - PageFormData formData = {QString(), QString(), data}; - - if (data.isEmpty() || !data.contains('=')) { - return formData; - } - - const QueryItems queryItems = createQueryItems(data); - - if (queryItems.isEmpty()) { - return formData; - } - -#if QTWEBENGINE_DISABLED - const QWebElementCollection allForms = getAllElementsFromPage("form"); - - // Find form that contains password value sent in data - foreach (const QWebElement &formElement, allForms) { - bool found = false; - const QWebElementCollection inputs = formElement.findAll("input[type=\"password\"]"); - - foreach (QWebElement inputElement, inputs) { - const QString passName = inputElement.attribute("name"); - const QString passValue = inputElement.evaluateJavaScript("this.value").toString(); - - if (queryItemsContains(queryItems, passName, passValue)) { - // Set passwordValue if not empty (to make it possible extract forms without username field) - passwordValue = passValue; - - const QueryItem item = findUsername(formElement); - if (queryItemsContains(queryItems, item.first, item.second)) { - usernameValue = item.second; - found = true; - break; - } - } - } - - if (found) { - break; - } - } - - // It is necessary only to find password, as there may be form without username field - if (passwordValue.isEmpty()) { - return formData; - } - - formData.username = usernameValue; - formData.password = passwordValue; -#endif - - return formData; -} - -// Returns if any data was actually filled in page -bool PageFormCompleter::completeFormData(const QByteArray &data) const -{ - bool completed = false; - const QueryItems queryItems = createQueryItems(data); - - // Input types that are being completed - QStringList inputTypes; - inputTypes << "text" << "password" << "email"; - -#if QTWEBENGINE_DISABLED - // Find all input elements in the page - const QWebElementCollection inputs = getAllElementsFromPage("input"); - - for (int i = 0; i < queryItems.count(); i++) { - const QString key = queryItems.at(i).first; - const QString value = queryItems.at(i).second; - - for (int i = 0; i < inputs.count(); i++) { - QWebElement element = inputs.at(i); - const QString typeAttr = element.attribute("type"); - - if (!inputTypes.contains(typeAttr) && !typeAttr.isEmpty()) { - continue; - } - - if (key == element.attribute("name")) { - completed = true; - element.setAttribute("value", value); - } - } - } -#endif - - return completed; -} - -bool PageFormCompleter::queryItemsContains(const QueryItems &queryItems, const QString &attributeName, - const QString &attributeValue) const -{ - if (attributeName.isEmpty() || attributeValue.isEmpty()) { - return false; - } - - for (int i = 0; i < queryItems.count(); i++) { - const QueryItem item = queryItems.at(i); - - if (item.first == attributeName) { - return item.second == attributeValue; - } - } - - return false; -} - -QByteArray PageFormCompleter::convertWebKitFormBoundaryIfNecessary(const QByteArray &data) const -{ - /* Sometimes, data are passed in this format: - * - * ------WebKitFormBoundary0bBp3bFMdGwqanMp - * Content-Disposition: form-data; name="name-of-attribute" - * - * value-of-attribute - * ------WebKitFormBoundary0bBp3bFMdGwqanMp-- - * - * So this function converts this format into name=value& format - */ - - if (!data.contains(QByteArray("------WebKitFormBoundary"))) { - return data; - } - - QByteArray formatedData; - QzRegExp rx("name=\"(.*)------WebKitFormBoundary"); - rx.setMinimal(true); - - int pos = 0; - while ((pos = rx.indexIn(data, pos)) != -1) { - QString string = rx.cap(1); - pos += rx.matchedLength(); - - int endOfAttributeName = string.indexOf(QLatin1Char('"')); - if (endOfAttributeName == -1) { - continue; - } - - QString attrName = string.left(endOfAttributeName); - QString attrValue = string.mid(endOfAttributeName + 1).trimmed().remove(QLatin1Char('\n')); - - if (attrName.isEmpty() || attrValue.isEmpty()) { - continue; - } - - formatedData.append(attrName + "=" + attrValue + "&"); - } - - return formatedData; -} - -PageFormCompleter::QueryItem PageFormCompleter::findUsername(const QWebElement &form) const -{ - Q_UNUSED(form) -#if QTWEBENGINE_DISABLED - // Try to find username (or email) field in the form. - QStringList selectors; - selectors << "input[type=\"text\"][name*=\"user\"]" - << "input[type=\"text\"][name*=\"name\"]" - << "input[type=\"text\"]" - << "input[type=\"email\"]" - << "input:not([type=\"hidden\"][type=\"password\"])"; - - foreach (const QString &selector, selectors) { - const QWebElementCollection inputs = form.findAll(selector); - foreach (QWebElement element, inputs) { - const QString name = element.attribute("name"); - const QString value = element.evaluateJavaScript("this.value").toString(); - - if (!name.isEmpty() && !value.isEmpty()) { - QueryItem item; - item.first = name; - item.second = value; - return item; - } - } - } -#endif - - return QueryItem(); -} - -PageFormCompleter::QueryItems PageFormCompleter::createQueryItems(QByteArray data) const -{ - // QUrlQuery/QUrl never encodes/decodes + and spaces - data.replace('+', ' '); - - QUrlQuery query; - query.setQuery(data); - QueryItems arguments = query.queryItems(QUrl::FullyDecoded); - - return arguments; -} - -#if QTWEBENGINE_DISABLED -QWebElementCollection PageFormCompleter::getAllElementsFromPage(const QString &selector) const -{ - QWebElementCollection list; - - if (!m_page && !m_frame) - return list; - - if (m_frame) - return m_frame->findAllElements(selector); - - if (!m_page->mainFrame()) - return list; - - QList frames; - frames.append(m_page->mainFrame()); - - while (!frames.isEmpty()) { - QWebFrame* frame = frames.takeFirst(); - if (frame && !frame->documentElement().isNull()) { - list.append(frame->findAllElements(selector)); - frames += frame->childFrames(); - } - } - - return list; -} - -#endif diff --git a/src/lib/autofill/pageformcompleter.h b/src/lib/autofill/pageformcompleter.h deleted file mode 100644 index da28fa3ba..000000000 --- a/src/lib/autofill/pageformcompleter.h +++ /dev/null @@ -1,73 +0,0 @@ -/* ============================================================ -* QupZilla - WebKit based browser -* Copyright (C) 2013-2014 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 PAGEFORMCOMPLETER_H -#define PAGEFORMCOMPLETER_H - -#include -#include -#include - -#include "qzcommon.h" - -class QWebEnginePage; -class QWebEngineFrame; -class QWebElement; -class QWebElementCollection; - -struct PageFormData { - QString username; - QString password; - QByteArray postData; - - bool isValid() const { - return !password.isEmpty(); - } -}; - -class QUPZILLA_EXPORT PageFormCompleter -{ -public: - explicit PageFormCompleter(); - - PageFormData extractFormData(QWebEnginePage* page, const QByteArray &postData); - PageFormData extractFormData(QWebEngineFrame* frame, const QByteArray &postData); - - bool completeFormData(QWebEnginePage* page, const QByteArray &data); - bool completeFormData(QWebEngineFrame* frame, const QByteArray &data); - -private: - typedef QPair QueryItem; - typedef QList > QueryItems; - - PageFormData extractFormData(const QByteArray &postData) const; - bool completeFormData(const QByteArray &data) const; - - bool queryItemsContains(const QueryItems &queryItems, const QString &attributeName, - const QString &attributeValue) const; - QByteArray convertWebKitFormBoundaryIfNecessary(const QByteArray &data) const; - QueryItem findUsername(const QWebElement &form) const; - QueryItems createQueryItems(QByteArray data) const; -#if QTWEBENGINE_DISABLED - QWebElementCollection getAllElementsFromPage(const QString &selector) const; -#endif - - QWebEnginePage* m_page; - QWebEngineFrame* m_frame; -}; - -#endif // PAGEFORMCOMPLETER_H diff --git a/src/lib/lib.pro b/src/lib/lib.pro index 3fdbb5881..d6d924671 100644 --- a/src/lib/lib.pro +++ b/src/lib/lib.pro @@ -76,7 +76,6 @@ SOURCES += \ autofill/autofillicon.cpp \ autofill/autofillnotification.cpp \ autofill/autofillwidget.cpp \ - autofill/pageformcompleter.cpp \ autofill/passwordbackends/databaseencryptedpasswordbackend.cpp \ autofill/passwordbackends/databasepasswordbackend.cpp \ autofill/passwordbackends/passwordbackend.cpp \ @@ -237,7 +236,8 @@ SOURCES += \ webtab/tabbedwebview.cpp \ webtab/webtab.cpp \ adblock/adblockmatcher.cpp \ - tools/scripts.cpp + tools/scripts.cpp \ + webengine/javascript/autofilljsobject.cpp HEADERS += \ 3rdparty/ecwin7.h \ @@ -272,7 +272,6 @@ HEADERS += \ autofill/autofillicon.h \ autofill/autofillnotification.h \ autofill/autofillwidget.h \ - autofill/pageformcompleter.h \ autofill/passwordbackends/databaseencryptedpasswordbackend.h \ autofill/passwordbackends/databasepasswordbackend.h \ autofill/passwordbackends/passwordbackend.h \ @@ -326,7 +325,7 @@ HEADERS += \ navigation/siteicon.h \ navigation/websearchbar.h \ #network/cabundleupdater.h \ - network/networkmanager.h \ + #network/networkmanager.h \ network/networkmanagerproxy.h \ network/networkproxyfactory.h \ network/pac/pacdatetime.h \ @@ -437,7 +436,8 @@ HEADERS += \ webtab/tabbedwebview.h \ webtab/webtab.h \ adblock/adblockmatcher.h \ - tools/scripts.h + tools/scripts.h \ + webengine/javascript/autofilljsobject.h FORMS += \ adblock/adblockaddsubscriptiondialog.ui \ diff --git a/src/lib/network/networkmanager.cpp b/src/lib/network/networkmanager.cpp index 1eba48ad3..692b80358 100644 --- a/src/lib/network/networkmanager.cpp +++ b/src/lib/network/networkmanager.cpp @@ -15,7 +15,6 @@ * You should have received a copy of the GNU General Public License * along with this program. If not, see . * ============================================================ */ -#include "networkmanager.h" #include "browserwindow.h" #include "autofill.h" #include "networkmanagerproxy.h" diff --git a/src/lib/opensearch/searchenginesmanager.cpp b/src/lib/opensearch/searchenginesmanager.cpp index 07e444b03..5ad937c3a 100644 --- a/src/lib/opensearch/searchenginesmanager.cpp +++ b/src/lib/opensearch/searchenginesmanager.cpp @@ -20,7 +20,6 @@ #include "editsearchengine.h" #include "iconprovider.h" #include "mainapplication.h" -#include "networkmanager.h" #include "opensearchreader.h" #include "opensearchengine.h" #include "settings.h" diff --git a/src/lib/tools/scripts.cpp b/src/lib/tools/scripts.cpp index 024d0ad7a..092b292b6 100644 --- a/src/lib/tools/scripts.cpp +++ b/src/lib/tools/scripts.cpp @@ -49,6 +49,57 @@ QString Scripts::setupWebChannel() return source.arg(QzTools::readAllFileContents(QSL(":/html/qwebchannel.js"))); } +QString Scripts::setupFormObserver() +{ + QString source = QL1S("(function() {" + "function findUsername(inputs) {" + " for (var i = 0; i < inputs.length; ++i)" + " if (inputs[i].type == 'text' && inputs[i].value.length && inputs[i].name.indexOf('user') != -1)" + " return inputs[i].value;" + " for (var i = 0; i < inputs.length; ++i)" + " if (inputs[i].type == 'text' && inputs[i].value.length && inputs[i].name.indexOf('name') != -1)" + " return inputs[i].value;" + " for (var i = 0; i < inputs.length; ++i)" + " if (inputs[i].type == 'text' && inputs[i].value.length)" + " return inputs[i].value;" + " for (var i = 0; i < inputs.length; ++i)" + " if (inputs[i].type == 'email' && inputs[i].value.length)" + " return inputs[i].value;" + " return '';" + "}" + "function registerForm(form) {" + " form.addEventListener('submit', function() {" + " var form = this;" + " var data = '';" + " var password = '';" + " var inputs = form.getElementsByTagName('input');" + " for (var i = 0; i < inputs.length; ++i) {" + " var input = inputs[i];" + " var type = input.type.toLowerCase();" + " if (type != 'text' && type != 'password' && type != 'email')" + " continue;" + " if (!password && type == 'password')" + " password = input.value;" + " data += encodeURIComponent(input.name);" + " data += '=';" + " data += encodeURIComponent(input.value);" + " data += '&';" + " }" + " if (!password)" + " return;" + " data = data.substring(0, data.length - 1);" + " var url = window.location.href;" + " var username = findUsername(inputs);" + " external.autoFill.formSubmitted(url, username, password, data);" + " }, true);" + "}" + "for (var i = 0; i < document.forms.length; ++i)" + " registerForm(document.forms[i]);" + "})()"); + + return source; +} + QString Scripts::setCss(const QString &css) { QString source = QL1S("(function() {" @@ -94,3 +145,36 @@ QString Scripts::sendPostData(const QUrl &url, const QByteArray &data) return source.arg(url.toString(), values); } + +QString Scripts::completeFormData(const QByteArray &data) +{ + QString source = QL1S("(function() {" + "var data = '%1'.split('&');" + "var inputs = [];" + "var frames = [window, window.frames];" + "for (var i = 0; i < frames.length; ++i) {" + " var finputs = frames[i].document.getElementsByTagName('input');" + " for (var j = 0; j < finputs.length; ++j) {" + " var type = finputs[j].type.toLowerCase();" + " if (type == 'text' || type == 'password' || type == 'email')" + " inputs.push(finputs[j]);" + " }" + "}" + "for (var i = 0; i < data.length; ++i) {" + " var pair = data[i].split('=');" + " if (pair.length != 2)" + " continue;" + " var key = decodeURIComponent(pair[0]);" + " var val = decodeURIComponent(pair[1]);" + " for (var j = 0; j < inputs.length; ++j) {" + " var input = inputs[j];" + " if (input.name == key)" + " input.value = val;" + " }" + "}" + "})()"); + + QString d = data; + d.replace(QL1S("'"), QL1S("\\'")); + return source.arg(d); +} diff --git a/src/lib/tools/scripts.h b/src/lib/tools/scripts.h index c83c41f33..28df339af 100644 --- a/src/lib/tools/scripts.h +++ b/src/lib/tools/scripts.h @@ -29,8 +29,11 @@ class QUPZILLA_EXPORT Scripts { public: static QString setupWebChannel(); + static QString setupFormObserver(); + static QString setCss(const QString &css); static QString sendPostData(const QUrl &url, const QByteArray &data); + static QString completeFormData(const QByteArray &data); }; #endif // SCRIPTS_H diff --git a/src/lib/webengine/javascript/autofilljsobject.cpp b/src/lib/webengine/javascript/autofilljsobject.cpp new file mode 100644 index 000000000..3f605568f --- /dev/null +++ b/src/lib/webengine/javascript/autofilljsobject.cpp @@ -0,0 +1,40 @@ +/* ============================================================ +* QupZilla - QtWebEngine based browser +* Copyright (C) 2015 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 "autofilljsobject.h" +#include "externaljsobject.h" +#include "mainapplication.h" +#include "autofill.h" +#include "webpage.h" + +AutoFillJsObject::AutoFillJsObject(ExternalJsObject *parent) + : QObject(parent) + , m_jsObject(parent) +{ +} + +void AutoFillJsObject::formSubmitted(const QString &frameUrl, const QString &username, const QString &password, const QByteArray &data) +{ + PageFormData formData; + formData.username = username; + formData.password = password; + formData.postData = data; + + mApp->autoFill()->saveForm(m_jsObject->page(), QUrl(frameUrl), formData); +} + diff --git a/src/lib/webengine/javascript/autofilljsobject.h b/src/lib/webengine/javascript/autofilljsobject.h new file mode 100644 index 000000000..924706abb --- /dev/null +++ b/src/lib/webengine/javascript/autofilljsobject.h @@ -0,0 +1,39 @@ +/* ============================================================ +* QupZilla - QtWebEngine based browser +* Copyright (C) 2015 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 AUTOFILLJSOBJECT_H +#define AUTOFILLJSOBJECT_H + +#include + +class ExternalJsObject; + +class AutoFillJsObject : public QObject +{ + Q_OBJECT +public: + explicit AutoFillJsObject(ExternalJsObject *parent); + +public slots: + void formSubmitted(const QString &frameUrl, const QString &username, const QString &password, const QByteArray &data); + +private: + ExternalJsObject *m_jsObject; +}; + +#endif // AUTOFILLJSOBJECT_H diff --git a/src/lib/webengine/javascript/externaljsobject.cpp b/src/lib/webengine/javascript/externaljsobject.cpp index c8e160acb..7faaa0e30 100644 --- a/src/lib/webengine/javascript/externaljsobject.cpp +++ b/src/lib/webengine/javascript/externaljsobject.cpp @@ -21,13 +21,20 @@ #include "speeddial.h" #include "webpage.h" #include "searchenginesmanager.h" +#include "autofilljsobject.h" ExternalJsObject::ExternalJsObject(WebPage *page) : QObject(page) , m_page(page) + , m_autoFill(new AutoFillJsObject(this)) { } +WebPage *ExternalJsObject::page() const +{ + return m_page; +} + void ExternalJsObject::AddSearchProvider(const QString &engineUrl) { mApp->searchEnginesManager()->addEngine(QUrl(engineUrl)); @@ -46,3 +53,8 @@ QObject *ExternalJsObject::speedDial() const return mApp->plugins()->speedDial(); } + +QObject *ExternalJsObject::autoFill() const +{ + return m_autoFill; +} diff --git a/src/lib/webengine/javascript/externaljsobject.h b/src/lib/webengine/javascript/externaljsobject.h index 1d1bad29b..6858ae0d5 100644 --- a/src/lib/webengine/javascript/externaljsobject.h +++ b/src/lib/webengine/javascript/externaljsobject.h @@ -21,24 +21,29 @@ #include class WebPage; +class AutoFillJsObject; class ExternalJsObject : public QObject { Q_OBJECT Q_PROPERTY(QObject* speedDial READ speedDial CONSTANT) + Q_PROPERTY(QObject* autoFill READ autoFill CONSTANT) public: explicit ExternalJsObject(WebPage *page); + WebPage *page() const; + public slots: void AddSearchProvider(const QString &engineUrl); int IsSearchProviderInstalled(const QString &engineURL); private: QObject *speedDial() const; + QObject *autoFill() const; WebPage *m_page; - + AutoFillJsObject *m_autoFill; }; #endif // EXTERNALJSOBJECT_H diff --git a/src/lib/webengine/webpage.cpp b/src/lib/webengine/webpage.cpp index 4f394a108..62477b8e7 100644 --- a/src/lib/webengine/webpage.cpp +++ b/src/lib/webengine/webpage.cpp @@ -211,6 +211,9 @@ void WebPage::finished() // AdBlock cleanBlockedObjects(); + + // AutoFill + m_passwordEntries = mApp->autoFill()->completePage(this, url()); } void WebPage::watchedFileChanged(const QString &file) @@ -293,9 +296,17 @@ void WebPage::desktopServicesOpen(const QUrl &url) void WebPage::setupWebChannel() { + QWebChannel *old = webChannel(); + const QString objectName = QSL("qz_object"); + QWebChannel *channel = new QWebChannel(this); channel->registerObject(QSL("qz_object"), new ExternalJsObject(this)); setWebChannel(channel); + + if (old) { + delete old->registeredObjects().value(objectName); + delete old; + } } void WebPage::windowCloseRequested() diff --git a/src/lib/webtab/tabbedwebview.cpp b/src/lib/webtab/tabbedwebview.cpp index 4bc191afa..9ea416cc1 100644 --- a/src/lib/webtab/tabbedwebview.cpp +++ b/src/lib/webtab/tabbedwebview.cpp @@ -19,7 +19,6 @@ #include "browserwindow.h" #include "webpage.h" #include "tabwidget.h" -#include "networkmanager.h" #include "mainapplication.h" #include "tabbar.h" #include "webtab.h" diff --git a/tests/form-iframe.html b/tests/form-iframe.html new file mode 100644 index 000000000..16ce118e3 --- /dev/null +++ b/tests/form-iframe.html @@ -0,0 +1,11 @@ + + + + Form completion test in iframe + + +

Form completion test in iframe

+ + + +