Page MenuHomePhorge

No OneTemporary

diff --git a/kdewebkit/kwebwallet.cpp b/kdewebkit/kwebwallet.cpp
index bb2b551ca6..51d0686810 100644
--- a/kdewebkit/kwebwallet.cpp
+++ b/kdewebkit/kwebwallet.cpp
@@ -1,580 +1,585 @@
/*
* This file is part of the KDE project.
*
* Copyright (C) 2009 Dawit Alemayehu <adawit@kde.org>
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Library General Public
* License as published by the Free Software Foundation; either
* version 2 of the License, or (at your option) any later version.
*
* This library 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
* Library General Public License for more details.
*
* You should have received a copy of the GNU Library General Public License
* along with this library; see the file COPYING.LIB. If not, write to
* the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
* Boston, MA 02110-1301, USA.
*
*/
#include "kwebwallet.h"
#include <kwallet.h>
#include <kdebug.h>
#include <QtCore/QSet>
#include <QtCore/QHash>
#include <QtCore/QFile>
#include <QtCore/QWeakPointer>
#include <QtCore/QScopedPointer>
#include <QtWebKit/QWebPage>
#include <QtWebKit/QWebFrame>
#include <QtWebKit/QWebElement>
#include <QtWebKit/QWebElementCollection>
#include <qwindowdefs.h>
#define QL1S(x) QLatin1String(x)
#define QL1C(x) QLatin1Char(x)
// Form parsing JS code adapted from Arora.
// See https://github.com/Arora/arora/blob/master/src/data/parseForms.js
#define FORM_PARSING_JS "(function (){ \
var forms; \
var numForms = document.forms.length; \
if (numForms > 0 ) { \
var forms = new Array; \
for (var i = 0; i < numForms; ++i) { \
var form = document.forms[i]; \
if (form.method.toLowerCase() != 'post') \
continue; \
var formObject = new Object; \
formObject.name = form.name; \
formObject.index = i; \
var elements = new Array; \
var numElements = form.elements.length; \
for (var j = 0; j < numElements; ++j) { \
var e = form.elements[j]; \
var element = new Object; \
element.name = e.name; \
element.value = e.value; \
element.type = e.type; \
element.readonly = e.hasAttribute('readonly'); \
element.disabled = e.hasAttribute('disabled'); \
if (element.autocomplete != null) \
element.autocomplete = element.autocomplete.value; \
elements.push(element); \
} \
formObject.elements = elements; \
forms.push(formObject); \
} \
} \
return forms; \
}())"
/**
* Creates key used to store and retrieve form data.
*
*/
static QString walletKey(KWebWallet::WebForm form)
{
QString key = form.url.toString(QUrl::RemoveQuery|QUrl::RemoveFragment);
key += QL1C('#');
key += form.name;
return key;
}
static void collectAllChildFrames(QWebFrame* frame, QList<QWebFrame*>& list)
{
list << frame->childFrames();
QListIterator<QWebFrame*> it(frame->childFrames());
while (it.hasNext()) {
collectAllChildFrames(it.next(), list);
}
}
+static QUrl urlForFrame(QWebFrame* frame)
+{
+ return (frame->url().isEmpty() ? frame->baseUrl().resolved(frame->url()) : frame->url());
+}
+
class KWebWallet::KWebWalletPrivate
{
public:
struct FormsData
{
QWeakPointer<QWebFrame> frame;
KWebWallet::WebFormList forms;
};
KWebWalletPrivate(KWebWallet* parent);
KWebWallet::WebFormList parseFormData(QWebFrame* frame, bool fillform = true, bool ignorepasswd = false);
void fillDataFromCache(KWebWallet::WebFormList &formList);
void saveDataToCache(const QString &key);
void removeDataFromCache(const WebFormList &formList);
void openWallet();
// Private slots...
void _k_openWalletDone(bool);
void _k_walletClosed();
WId wid;
KWebWallet *q;
QScopedPointer<KWallet::Wallet> wallet;
KWebWallet::WebFormList pendingRemoveRequests;
QHash<KUrl, FormsData> pendingFillRequests;
QHash<QString, KWebWallet::WebFormList> pendingSaveRequests;
QSet<KUrl> confirmSaveRequestOverwrites;
};
KWebWallet::KWebWalletPrivate::KWebWalletPrivate(KWebWallet *parent)
:wid (0), q(parent)
{
}
KWebWallet::WebFormList KWebWallet::KWebWalletPrivate::parseFormData(QWebFrame *frame, bool fillform, bool ignorepasswd)
{
Q_ASSERT(frame);
KWebWallet::WebFormList list;
// Execute the javscript to obtain the necessary fields...
QVariantList results = frame->evaluateJavaScript(QL1S(FORM_PARSING_JS)).toList();
Q_FOREACH (const QVariant &formVariant, results) {
QVariantMap map = formVariant.toMap();
KWebWallet::WebForm form;
- form.url = frame->url();
+ form.url = urlForFrame(frame);
form.name = map[QL1S("name")].toString();
form.index = map[QL1S("index")].toString();
bool formHasPasswords = false;
const QVariantList elements = map[QL1S("elements")].toList();
QList<KWebWallet::WebForm::WebField> inputFields;
Q_FOREACH (const QVariant &element, elements) {
QVariantMap elementMap = element.toMap();
const QString name = elementMap[QL1S("name")].toString();
const QString value = (ignorepasswd ? QString() : elementMap[QL1S("value")].toString());
const QString type = elementMap[QL1S("type")].toString();
const bool isPasswdInput = (type.compare(QL1S("password"), Qt::CaseInsensitive) == 0);
const bool isTextInput = (type.compare(QL1S("text"), Qt::CaseInsensitive) == 0);
const bool autoCompleteOff = (elementMap[QL1S("autocomplete")].toString().compare(QL1S("off"), Qt::CaseInsensitive) == 0);
if (name.isEmpty())
continue;
if (!isPasswdInput && !isTextInput)
continue;
if (autoCompleteOff)
continue;
if (elementMap[QL1S("disabled")].toBool())
continue;
if (fillform && elementMap[QL1S("readonly")].toBool())
continue;
if (isPasswdInput && !fillform && value.isEmpty())
continue;
if (isPasswdInput)
formHasPasswords = true;
inputFields.append(qMakePair(name, value));
}
// Only add the input fields on form save requests...
if (formHasPasswords && !fillform)
form.fields = inputFields;
// Add the form to the list if we are saving it or it has cached data.
if ((fillform && q->hasCachedFormData(form)) || (!fillform && !form.fields.isEmpty()))
list << form;
}
return list;
}
void KWebWallet::KWebWalletPrivate::fillDataFromCache(KWebWallet::WebFormList &formList)
{
if (!wallet) {
kWarning(800) << "Unable to retrieve form data from wallet";
return;
}
QMap<QString, QString> cachedValues;
QMutableListIterator <WebForm> formIt (formList);
while (formIt.hasNext()) {
KWebWallet::WebForm &form = formIt.next();
const QString key (walletKey(form));
if (wallet->readMap(key, cachedValues) != 0) {
kWarning(800) << "Unable to read form data for key:" << key;
continue;
}
QMapIterator<QString, QString> valuesIt (cachedValues);
while (valuesIt.hasNext()) {
valuesIt.next();
//kDebug(800) << "wallet key:" << key << valuesIt.key() << valuesIt.value();
form.fields << qMakePair(valuesIt.key(), valuesIt.value());
}
}
}
void KWebWallet::KWebWalletPrivate::saveDataToCache(const QString &key)
{
// Make sure the specified keys exists before acting on it. See BR# 270209.
if (!pendingSaveRequests.contains(key)) {
return;
}
bool success = false;
const QUrl url = pendingSaveRequests.value(key).first().url;
if (wallet) {
int count = 0;
const KWebWallet::WebFormList list = pendingSaveRequests.value(key);
QListIterator<KWebWallet::WebForm> formIt (list);
while (formIt.hasNext()) {
QMap<QString, QString> values, storedValues;
const KWebWallet::WebForm form = formIt.next();
const QString accessKey = walletKey(form);
if (confirmSaveRequestOverwrites.contains(url)) {
confirmSaveRequestOverwrites.remove(url);
const int status = wallet->readMap(accessKey, storedValues);
if (status == 0 && storedValues.count()) {
QListIterator<KWebWallet::WebForm::WebField> fieldIt (form.fields);
while (fieldIt.hasNext()) {
const KWebWallet::WebForm::WebField field = fieldIt.next();
if (storedValues.contains(field.first) &&
storedValues.value(field.first) != field.second) {
emit q->saveFormDataRequested(key, url);
return;
}
}
// If we got here it means the new credential is exactly
// the same as the one already cached ; so skip the
// re-saving part...
success = true;
continue;
}
}
QListIterator<KWebWallet::WebForm::WebField> fieldIt (form.fields);
while (fieldIt.hasNext()) {
const KWebWallet::WebForm::WebField field = fieldIt.next();
values.insert(field.first, field.second);
}
if (wallet->writeMap(accessKey, values) == 0)
count++;
else
kWarning(800) << "Unable to write form data to wallet";
}
if (list.isEmpty() || count > 0)
success = true;
pendingSaveRequests.remove(key);
} else {
kWarning(800) << "NULL KWallet instance!";
}
emit q->saveFormDataCompleted(url, success);
}
void KWebWallet::KWebWalletPrivate::openWallet()
{
if (!wallet.isNull()) {
return;
}
wallet.reset(KWallet::Wallet::openWallet(KWallet::Wallet::NetworkWallet(),
wid, KWallet::Wallet::Asynchronous));
if (wallet.isNull()) {
return;
}
connect(wallet.data(), SIGNAL(walletOpened(bool)), q, SLOT(_k_openWalletDone(bool)));
connect(wallet.data(), SIGNAL(walletClosed()), q, SLOT(_k_walletClosed()));
}
void KWebWallet::KWebWalletPrivate::removeDataFromCache(const WebFormList &formList)
{
if (!wallet) {
kWarning(800) << "NULL KWallet instance!";
return;
}
QListIterator<WebForm> formIt (formList);
while (formIt.hasNext())
wallet->removeEntry(walletKey(formIt.next()));
}
void KWebWallet::KWebWalletPrivate::_k_openWalletDone(bool ok)
{
Q_ASSERT (wallet);
if (ok &&
(wallet->hasFolder(KWallet::Wallet::FormDataFolder()) ||
wallet->createFolder(KWallet::Wallet::FormDataFolder())) &&
wallet->setFolder(KWallet::Wallet::FormDataFolder())) {
// Do pending fill requests...
if (!pendingFillRequests.isEmpty()) {
KUrl::List urlList;
QMutableHashIterator<KUrl, FormsData> requestIt (pendingFillRequests);
while (requestIt.hasNext()) {
requestIt.next();
KWebWallet::WebFormList list = requestIt.value().forms;
fillDataFromCache(list);
q->fillWebForm(requestIt.key(), list);
}
pendingFillRequests.clear();
}
// Do pending save requests...
if (!pendingSaveRequests.isEmpty()) {
QListIterator<QString> keysIt (pendingSaveRequests.keys());
while (keysIt.hasNext())
saveDataToCache(keysIt.next());
}
// Do pending remove requests...
if (!pendingRemoveRequests.isEmpty()) {
removeDataFromCache(pendingRemoveRequests);
pendingRemoveRequests.clear();
}
} else {
// Delete the wallet if opening the wallet failed or we were unable
// to change to the folder we wanted to change to.
delete wallet.take();
}
}
void KWebWallet::KWebWalletPrivate::_k_walletClosed()
{
if (wallet)
wallet.take()->deleteLater();
emit q->walletClosed();
}
KWebWallet::KWebWallet(QObject *parent, WId wid)
:QObject(parent), d(new KWebWalletPrivate(this))
{
if (!wid) {
// If wid is 0, make the best effort the discern it from our parent.
QWebPage *page = qobject_cast<QWebPage*>(parent);
if (page) {
QWidget *widget = page->view();
if (widget && widget->window())
wid = widget->window()->winId();
}
}
d->wid = wid;
}
KWebWallet::~KWebWallet()
{
delete d;
}
KWebWallet::WebFormList KWebWallet::formsWithCachedData(QWebFrame* frame, bool recursive) const
{
WebFormList list;
if (frame) {
list << d->parseFormData(frame);
if (recursive) {
QList<QWebFrame*> childFrameList;
collectAllChildFrames(frame, childFrameList);
QListIterator <QWebFrame *> framesIt (childFrameList);
while (framesIt.hasNext()) {
list << d->parseFormData(framesIt.next());
}
}
}
return list;
}
void KWebWallet::fillFormData(QWebFrame *frame, bool recursive)
{
if (!frame)
return;
KUrl::List urlList;
WebFormList formsList = d->parseFormData(frame);
if (!formsList.isEmpty()) {
- const QUrl url (frame->url());
+ const QUrl url (urlForFrame(frame));
if (d->pendingFillRequests.contains(url)) {
kWarning(800) << "Duplicate request rejected!";
} else {
KWebWalletPrivate::FormsData data;
data.frame = QWeakPointer<QWebFrame>(frame);
data.forms << formsList;
d->pendingFillRequests.insert(url, data);
urlList << url;
}
}
if (recursive) {
QList<QWebFrame*> childFrameList;
collectAllChildFrames(frame, childFrameList);
QListIterator<QWebFrame*> frameIt (childFrameList);
while (frameIt.hasNext()) {
QWebFrame *childFrame = frameIt.next();
formsList = d->parseFormData(childFrame);
if (formsList.isEmpty())
continue;
const QUrl url (childFrame->url());
if (d->pendingFillRequests.contains(url)) {
kWarning(800) << "Duplicate request rejected!!!";
} else {
KWebWalletPrivate::FormsData data;
data.frame = QWeakPointer<QWebFrame>(childFrame);
data.forms << formsList;
d->pendingFillRequests.insert(url, data);
urlList << url;
}
}
}
if (!urlList.isEmpty())
fillFormDataFromCache(urlList);
}
void KWebWallet::saveFormData(QWebFrame *frame, bool recursive, bool ignorePasswordFields)
{
if (!frame)
return;
WebFormList list = d->parseFormData(frame, false, ignorePasswordFields);
if (recursive) {
QList<QWebFrame*> childFrameList;
collectAllChildFrames(frame, childFrameList);
QListIterator<QWebFrame*> frameIt (childFrameList);
while (frameIt.hasNext())
list << d->parseFormData(frameIt.next(), false, ignorePasswordFields);
}
if (list.isEmpty())
return;
- const QString key = QString::number(qHash(frame->url().toString() + frame->frameName()), 16);
+ const QString key = QString::number(qHash(urlForFrame(frame).toString() + frame->frameName()), 16);
const bool isAlreadyPending = d->pendingSaveRequests.contains(key);
d->pendingSaveRequests.insert(key, list);
if (isAlreadyPending)
return;
for (int i = 0 ; i < list.count(); ++i) {
if (hasCachedFormData(list.at(i)))
list.takeAt(i);
}
if (list.isEmpty()) {
- d->confirmSaveRequestOverwrites.insert(frame->url());
+ d->confirmSaveRequestOverwrites.insert(urlForFrame(frame));
saveFormDataToCache(key);
return;
}
- emit saveFormDataRequested(key, frame->url());
+ emit saveFormDataRequested(key, urlForFrame(frame));
}
void KWebWallet::removeFormData(QWebFrame *frame, bool recursive)
{
if (frame)
removeFormDataFromCache(formsWithCachedData(frame, recursive));
}
void KWebWallet::removeFormData(const WebFormList &forms)
{
d->pendingRemoveRequests << forms;
removeFormDataFromCache(forms);
}
void KWebWallet::acceptSaveFormDataRequest(const QString &key)
{
saveFormDataToCache(key);
}
void KWebWallet::rejectSaveFormDataRequest(const QString & key)
{
d->pendingSaveRequests.remove(key);
}
void KWebWallet::fillWebForm(const KUrl &url, const KWebWallet::WebFormList &forms)
{
QWeakPointer<QWebFrame> frame = d->pendingFillRequests.value(url).frame;
if (!frame)
return;
QString script;
bool wasFilled = false;
Q_FOREACH (const KWebWallet::WebForm& form, forms) {
Q_FOREACH(const KWebWallet::WebForm::WebField& field, form.fields) {
QString value = field.second;
value.replace(QLatin1Char('\\'), QLatin1String("\\\\"));
script += QString::fromLatin1("document.forms[\"%1\"].elements[\"%2\"].value=\"%3\";\n")
.arg((form.name.isEmpty() ? form.index : form.name))
.arg(field.first).arg(value);
}
}
if (!script.isEmpty()) {
wasFilled = true;
frame.data()->evaluateJavaScript(script);
}
emit fillFormRequestCompleted(wasFilled);
}
KWebWallet::WebFormList KWebWallet::formsToFill(const KUrl &url) const
{
return d->pendingFillRequests.value(url).forms;
}
KWebWallet::WebFormList KWebWallet::formsToSave(const QString &key) const
{
return d->pendingSaveRequests.value(key);
}
bool KWebWallet::hasCachedFormData(const WebForm &form) const
{
return !KWallet::Wallet::keyDoesNotExist(KWallet::Wallet::NetworkWallet(),
KWallet::Wallet::FormDataFolder(),
walletKey(form));
}
void KWebWallet::fillFormDataFromCache(const KUrl::List &urlList)
{
if (d->wallet) {
QListIterator<KUrl> urlIt (urlList);
while (urlIt.hasNext()) {
const KUrl url = urlIt.next();
WebFormList list = formsToFill(url);
d->fillDataFromCache(list);
fillWebForm(url, list);
}
d->pendingFillRequests.clear();
}
d->openWallet();
}
void KWebWallet::saveFormDataToCache(const QString &key)
{
if (d->wallet) {
d->saveDataToCache(key);
return;
}
d->openWallet();
}
void KWebWallet::removeFormDataFromCache(const WebFormList &forms)
{
if (d->wallet) {
d->removeDataFromCache(forms);
d->pendingRemoveRequests.clear();
return;
}
d->openWallet();
}
#include "kwebwallet.moc"

File Metadata

Mime Type
text/x-diff
Expires
Fri, Nov 1, 8:26 AM (1 d, 8 h)
Storage Engine
blob
Storage Format
Raw Data
Storage Handle
10074999
Default Alt Text
(19 KB)

Event Timeline