[Merge] lp:~mardy/webbrowser-app/add-onlineaccount-support-for-container2 into lp:webbrowser-app

Olivier Tilloy olivier.tilloy at canonical.com
Mon Jun 2 09:53:39 UTC 2014



Diff comments:

> === modified file 'debian/control'
> --- debian/control	2014-05-02 05:45:21 +0000
> +++ debian/control	2014-05-30 12:37:47 +0000
> @@ -51,9 +51,12 @@
>  Multi-Arch: foreign
>  Depends: ${misc:Depends},
>           ${shlibs:Depends},
> +         libqt5webkit5-qmlwebkitplugin, 
> +         qtdeclarative5-accounts-plugin,
> +         qtdeclarative5-qtquick2-plugin (>= 5.2),
>           unity-webapps-qml,
> -         libqt5webkit5-qmlwebkitplugin, 
>           webbrowser-app (= ${binary:Version}),
> +Suggests: qtdeclarative5-online-accounts-client0.1 (>= 0.3),
>  Description: Ubuntu web applications container
>   A lightweight webapps container tailored for Ubuntu, based on the Webkit
>   rendering engine and using the Ubuntu UI components.
> 
> === modified file 'src/app/browserapplication.cpp'
> --- src/app/browserapplication.cpp	2014-05-21 08:01:42 +0000
> +++ src/app/browserapplication.cpp	2014-05-30 12:37:47 +0000
> @@ -122,6 +122,9 @@
>      if (!isRunningInstalled()) {
>          m_engine->addImportPath(UbuntuBrowserImportsDirectory());
>      }
> +
> +    qmlEngineCreated(m_engine);
> +
>      QQmlContext* context = m_engine->rootContext();
>      m_component = new QQmlComponent(m_engine);
>      m_component->loadUrl(QUrl::fromLocalFile(UbuntuBrowserDirectory() + "/" + qmlFileSubPath));
> @@ -141,6 +144,9 @@
>      return true;
>  }
>  
> +void BrowserApplication::qmlEngineCreated(QQmlEngine*)
> +{}
> +
>  int BrowserApplication::run()
>  {
>      Q_ASSERT(m_window != 0);
> 
> === modified file 'src/app/browserapplication.h'
> --- src/app/browserapplication.h	2014-04-10 14:47:53 +0000
> +++ src/app/browserapplication.h	2014-05-30 12:37:47 +0000
> @@ -49,6 +49,8 @@
>      virtual void printUsage() const = 0;
>      QList<QUrl> urls() const;
>  
> +    virtual void qmlEngineCreated(QQmlEngine*);
> +
>      QStringList m_arguments;
>      QQmlEngine* m_engine;
>      QQuickWindow* m_window;
> 
> === added file 'src/app/webcontainer/AccountsPage.qml'
> --- src/app/webcontainer/AccountsPage.qml	1970-01-01 00:00:00 +0000
> +++ src/app/webcontainer/AccountsPage.qml	2014-05-30 12:37:47 +0000
> @@ -0,0 +1,73 @@
> +/*
> + * Copyright 2013-2014 Canonical Ltd.
> + *
> + * This file is part of webbrowser-app.
> + *
> + * webbrowser-app 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; version 3.
> + *
> + * webbrowser-app 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 <http://www.gnu.org/licenses/>.
> + */
> +
> +import QtQuick 2.0
> +import Ubuntu.Components 0.1
> +import webcontainer.private 0.1
> +
> +Page {
> +    id: accountsPage
> +
> +    property alias accountProvider: accountsLogin.accountProvider
> +    property alias applicationName: accountsLogin.applicationName
> +    property var webappCookieStore: null
> +
> +    signal done()
> +
> +    visible: false
> +    anchors.fill: parent
> +
> +    AccountsLoginPage {
> +        id: accountsLogin
> +
> +        anchors.fill: parent
> +
> +        QtObject {
> +            id: internal
> +            function onMoved(result) {
> +                webappCookieStore.moved.disconnect(internal.onMoved)
> +                if (!result) {
> +                    console.error("Unable to move cookies")
> +                }
> +                accountsPage.done()
> +            }
> +        }
> +
> +        onDone: {
> +            if (!accountsPage.visible)
> +                return
> +            if (!credentialsId) {
> +                accountsPage.done()
> +                return
> +            }
> +
> +            if (webappCookieStore) {
> +                var instance = onlineAccountStoreComponent.createObject(accountsLogin, {accountId: credentialsId})
> +                webappCookieStore.moved.connect(internal.onMoved)
> +                webappCookieStore.moveFrom(instance)
> +            } else {
> +                accountsPage.done()
> +            }
> +        }
> +    }
> +
> +    Component {
> +        id: onlineAccountStoreComponent
> +        OnlineAccountsCookieStore { }
> +    }
> +}
> 
> === modified file 'src/app/webcontainer/CMakeLists.txt'
> --- src/app/webcontainer/CMakeLists.txt	2014-04-03 12:01:59 +0000
> +++ src/app/webcontainer/CMakeLists.txt	2014-05-30 12:37:47 +0000
> @@ -9,7 +9,11 @@
>  set(WEBAPP_CONTAINER webapp-container)
>  
>  set(WEBAPP_CONTAINER_SRC
> +    chrome-cookie-store.cpp
> +    cookie-store.cpp
> +    online-accounts-cookie-store.cpp
>      webapp-container.cpp
> +    webkit-cookie-store.cpp
>      session-utils.cpp
>      url-pattern-utils.cpp
>  )
> @@ -18,7 +22,7 @@
>  
>  target_link_libraries(${WEBAPP_CONTAINER} ${COMMONLIB})
>  
> -qt5_use_modules(${WEBAPP_CONTAINER} Core Widgets Quick)
> +qt5_use_modules(${WEBAPP_CONTAINER} Core Widgets Quick Sql DBus)
>  
>  install(TARGETS ${WEBAPP_CONTAINER}
>          RUNTIME DESTINATION ${CMAKE_INSTALL_BINDIR})
> 
> === added file 'src/app/webcontainer/chrome-cookie-store.cpp'
> --- src/app/webcontainer/chrome-cookie-store.cpp	1970-01-01 00:00:00 +0000
> +++ src/app/webcontainer/chrome-cookie-store.cpp	2014-05-30 12:37:47 +0000
> @@ -0,0 +1,220 @@
> +/*
> + * Copyright 2014 Canonical Ltd.
> + *
> + * This file is part of webbrowser-app.
> + *
> + * webbrowser-app 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; version 3.
> + *
> + * webbrowser-app 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 <http://www.gnu.org/licenses/>.
> + */
> +
> +#include "chrome-cookie-store.h"
> +
> +#include <QDebug>
> +#include <QFileInfo>
> +#include <QNetworkCookie>
> +#include <QSqlError>
> +#include <QSqlQuery>
> +#include <QStandardPaths>
> +
> +static int connectionCounter = 0;
> +
> +static qint64 dateTimeToChrome(const QDateTime &time)
> +{
> +    /* Chrome uses Mon Jan 01 00:00:00 UTC 1601 as the epoch, hence the
> +     * magic number */
> +    return (time.toMSecsSinceEpoch() + 11644473600000) * 1000;
> +}
> +
> +static QDateTime dateTimeFromChrome(qint64 chromeTimeStamp)
> +{
> +    qint64 msecsSinceEpoch = chromeTimeStamp / 1000 - 11644473600000;
> +    return QDateTime::fromMSecsSinceEpoch(msecsSinceEpoch);
> +}
> +
> +ChromeCookieStore::ChromeCookieStore(QObject* parent):
> +    CookieStore(parent)
> +{
> +    QString connectionName =
> +        QString("chromeCookieStore-%1").arg(connectionCounter++);

What’s the use case for a unique connection name inside the webapp-container executable address space? Do we expect that one instance of the container will instantiate several cookie stores?

And isn’t there a risk that two separate instances of the container might each instantiate a cookie store at the same time with the same connection name, thus invalidating one of the two connections? If so, we should probably use the PID and and random hash to generate a connection name that is safe enough.

> +    m_db = QSqlDatabase::addDatabase("QSQLITE", connectionName);
> +}
> +
> +Cookies ChromeCookieStore::doGetCookies()
> +{
> +    Cookies cookies;
> +    m_db.setDatabaseName(getFullDbPathName());
> +
> +    if (Q_UNLIKELY(!m_db.open())) {
> +        qCritical() << "Could not open cookie database:" << getFullDbPathName()
> +            << m_db.lastError();
> +        return cookies;
> +    }
> +
> +    QSqlQuery q(m_db);
> +    q.exec("SELECT host_key, name, value, path, expires_utc, secure, httponly, has_expires FROM cookies;");
> +
> +    while (q.next()) {
> +        /* Build the cookie string from its parts */
> +        QNetworkCookie cookie(q.value(1).toString().toUtf8(),
> +                              q.value(2).toString().toUtf8());
> +        cookie.setSecure(q.value(5).toBool());
> +        cookie.setHttpOnly(q.value(6).toBool());
> +        if (q.value(7).toBool()) {
> +            QDateTime expires = dateTimeFromChrome(q.value(4).toULongLong());
> +            cookie.setExpirationDate(expires);
> +        }
> +        cookie.setDomain(q.value(0).toString());
> +        cookie.setPath(q.value(3).toString());
> +        cookies.append(cookie.toRawForm());
> +    }
> +
> +    m_db.close();
> +    return cookies;
> +}
> +
> +QDateTime ChromeCookieStore::lastUpdateTimeStamp() const
> +{
> +    QFileInfo dbFileInfo(getFullDbPathName());
> +    return dbFileInfo.lastModified();
> +}
> +
> +bool ChromeCookieStore::createDb()
> +{
> +    if (Q_UNLIKELY(!m_db.transaction())) return false;
> +
> +    QSqlQuery q(m_db);
> +    bool ok;
> +    ok = q.exec("CREATE TABLE meta(key LONGVARCHAR NOT NULL UNIQUE PRIMARY KEY,"
> +                "value LONGVARCHAR)");
> +    if (Q_UNLIKELY(!ok)) {
> +        m_db.rollback();
> +        return false;
> +    }
> +
> +    ok = q.exec("CREATE TABLE cookies (creation_utc INTEGER NOT NULL UNIQUE PRIMARY KEY,"
> +                "host_key TEXT NOT NULL,"
> +                "name TEXT NOT NULL,"
> +                "value TEXT NOT NULL,"
> +                "path TEXT NOT NULL,"
> +                "expires_utc INTEGER NOT NULL,"
> +                "secure INTEGER NOT NULL,"
> +                "httponly INTEGER NOT NULL,"
> +                "last_access_utc INTEGER NOT NULL,"
> +                "has_expires INTEGER NOT NULL DEFAULT 1,"
> +                "persistent INTEGER NOT NULL DEFAULT 1,"
> +                "priority INTEGER NOT NULL DEFAULT 1,"
> +                "encrypted_value BLOB DEFAULT '')");
> +    if (Q_UNLIKELY(!ok)) {
> +        m_db.rollback();
> +        return false;
> +    }
> +
> +    ok = q.exec("CREATE INDEX domain ON cookies(host_key)");
> +    if (Q_UNLIKELY(!ok)) {
> +        m_db.rollback();
> +        return false;
> +    }
> +
> +    ok = q.exec("INSERT INTO meta (key, value) VALUES ('version', '7')");
> +    if (Q_UNLIKELY(!ok)) {
> +        m_db.rollback();
> +        return false;
> +    }
> +
> +    ok = q.exec("INSERT INTO meta (key, value) VALUES ('last_compatible_version', '5')");
> +    if (Q_UNLIKELY(!ok)) {
> +        m_db.rollback();
> +        return false;
> +    }
> +
> +    return m_db.commit();
> +}
> +
> +bool ChromeCookieStore::doSetCookies(const Cookies& cookies)
> +{
> +    m_db.setDatabaseName(getFullDbPathName());
> +
> +    if (!m_db.open()) {
> +        qCritical() << "Could not open cookie database:" <<
> +            getFullDbPathName() << m_db.lastError().text();
> +        return false;
> +    }
> +
> +    QSqlQuery q(m_db);
> +    // Check whether the table already exists
> +    q.exec("SELECT name FROM sqlite_master WHERE type='table' AND name='cookies'");
> +    if (!q.next() && !createDb()) {
> +        qCritical() << "Could not create cookie database:" <<
> +            getFullDbPathName() << m_db.lastError().text();
> +        return false;
> +    }
> +
> +    QList<QNetworkCookie> parsedCookies;
> +
> +    Q_FOREACH(const QByteArray &cookie, cookies) {
> +        parsedCookies.append(QNetworkCookie::parseCookies(cookie));
> +    }
> +
> +    q.prepare("INSERT INTO cookies (creation_utc,"
> +              "host_key, name, value, path,"
> +              "expires_utc, secure, httponly, last_access_utc,"
> +              "has_expires, persistent, priority, encrypted_value) "
> +              "VALUES (:creation_utc,"
> +              ":host_key, :name, :value, :path,"
> +              ":expires_utc, :secure, :httponly, :last_access_utc,"
> +              ":has_expires, :persistent, :priority, :encrypted_value)");
> +    Q_FOREACH(const QNetworkCookie &cookie, parsedCookies) {
> +        q.bindValue(":creation_utc",
> +                    dateTimeToChrome(QDateTime::currentDateTimeUtc()));
> +        q.bindValue(":host_key", cookie.domain());
> +        q.bindValue(":name", cookie.name());
> +        q.bindValue(":value", cookie.value());
> +        q.bindValue(":path", cookie.path());
> +        q.bindValue(":expires_utc",
> +                    dateTimeToChrome(cookie.expirationDate().toUTC()));
> +        q.bindValue(":secure", cookie.isSecure());
> +        q.bindValue(":httponly", cookie.isHttpOnly());
> +        q.bindValue(":last_access_utc",
> +                    dateTimeToChrome(QDateTime::currentDateTimeUtc()));
> +        q.bindValue(":has_expires", cookie.expirationDate().isValid());
> +        q.bindValue(":persistent", true);
> +        q.bindValue(":priority", 1);
> +        q.bindValue(":encrypted_value", 1);
> +        q.exec();
> +    }
> +
> +    m_db.close();
> +
> +    return true;
> +}
> +
> +QString ChromeCookieStore::getFullDbPathName() const
> +{
> +    return dbPath().startsWith('/') ? dbPath() :
> +        QStandardPaths::standardLocations(QStandardPaths::HomeLocation)[0] + "/" + dbPath();

What’s the use case for this? Do we really expect clients to provide a path that is relative to $HOME ?
If the path is relative, shouldn’t it be understood as relative to $PWD ?

> +}
> +
> +void ChromeCookieStore::setDbPath(const QString &path)
> +{
> +    // If path is a URL, strip the initial "file://"
> +    QString normalizedPath = path.startsWith("file://") ? path.mid(7) : path;
> +
> +    if (normalizedPath != m_dbPath) {
> +        m_dbPath = normalizedPath;
> +        Q_EMIT dbPathChanged();
> +    }
> +}
> +
> +QString ChromeCookieStore::dbPath () const
> +{
> +    return m_dbPath;
> +}
> 
> === added file 'src/app/webcontainer/chrome-cookie-store.h'
> --- src/app/webcontainer/chrome-cookie-store.h	1970-01-01 00:00:00 +0000
> +++ src/app/webcontainer/chrome-cookie-store.h	2014-05-30 12:37:47 +0000
> @@ -0,0 +1,54 @@
> +/*
> + * Copyright 2014 Canonical Ltd.
> + *
> + * This file is part of webbrowser-app.
> + *
> + * webbrowser-app 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; version 3.
> + *
> + * webbrowser-app 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 <http://www.gnu.org/licenses/>.
> + */
> +
> +#ifndef CHROME_COOKIE_STORE_H
> +#define CHROME_COOKIE_STORE_H
> +
> +#include "cookie-store.h"
> +
> +#include <QSqlDatabase>
> +
> +class ChromeCookieStore : public CookieStore
> +{
> +    Q_OBJECT
> +    Q_PROPERTY(QString dbPath READ dbPath WRITE setDbPath NOTIFY dbPathChanged)
> +
> +public:
> +    ChromeCookieStore(QObject* parent = 0);
> +
> +    void setDbPath(const QString& path);
> +    QString dbPath() const;
> +
> +    QDateTime lastUpdateTimeStamp() const Q_DECL_OVERRIDE;
> +
> +Q_SIGNALS:
> +    void dbPathChanged();
> +
> +private:
> +    virtual Cookies doGetCookies() Q_DECL_OVERRIDE;
> +    virtual bool doSetCookies(const Cookies& cookies) Q_DECL_OVERRIDE;
> +
> +    QString getFullDbPathName() const;
> +    bool createDb();
> +
> +private:
> +    QString m_dbPath;
> +    QSqlDatabase m_db;
> +};
> +
> +#endif // CHROME_COOKIE_STORE_H
> 
> === renamed file 'src/app/webcontainer/cookiestore.cpp' => 'src/app/webcontainer/cookie-store.cpp'
> --- src/app/webcontainer/cookiestore.cpp	2014-01-27 22:58:55 +0000
> +++ src/app/webcontainer/cookie-store.cpp	2014-05-30 12:37:47 +0000
> @@ -1,5 +1,5 @@
>  /*
> - * Copyright 2013 Canonical Ltd.
> + * Copyright 2014 Canonical Ltd.
>   *
>   * This file is part of webbrowser-app.
>   *
> @@ -18,10 +18,10 @@
>  
>  #include <QDebug>
>  
> -#include "cookiestore.h"
> +#include "cookie-store.h"
>  
> -CookieStore::CookieStore(QObject *parent)
> -    : QObject(parent)
> +CookieStore::CookieStore(QObject* parent):
> +    QObject(parent)
>  {
>      qRegisterMetaType<Cookies>("Cookies");
>  }
> @@ -31,19 +31,26 @@
>      return doGetCookies();
>  }
>  
> -void CookieStore::setCookies(Cookies cookies)
> +bool CookieStore::setCookies(const Cookies& cookies)
>  {
> -    doSetCookies(cookies);
> +    if (doSetCookies(cookies)) {
> +        Q_EMIT cookiesChanged();
> +        return true;
> +    } else {
> +        return false;
> +    }
>  }
>  
>  Cookies CookieStore::doGetCookies()
>  {
> +    Q_UNIMPLEMENTED();
>      return Cookies();
>  }
>  
> -void CookieStore::doSetCookies(Cookies cookies)
> +bool CookieStore::doSetCookies(const Cookies& cookies)
>  {
>      Q_UNUSED(cookies);
> +    Q_UNIMPLEMENTED();
>  }
>  
>  QDateTime CookieStore::lastUpdateTimeStamp() const
> @@ -51,33 +58,32 @@
>      return _lastUpdateTimeStamp;
>  }
>  
> -void CookieStore::updateLastUpdateTimestamp(const QDateTime & timestamp)
> +void CookieStore::updateLastUpdateTimestamp(const QDateTime& timestamp)
>  {
>      _lastUpdateTimeStamp = timestamp;
>  }
>  
> -void CookieStore::moveFrom(CookieStore *store)
> +void CookieStore::moveFrom(CookieStore* store)
>  {
> -    if (! store)
> +    if (Q_UNLIKELY(!store))
>          return;
>  
> -    Cookies cookies =
> -            store->cookies();
> -
> -    QDateTime lastRemoteCookieUpdate =
> -            store->lastUpdateTimeStamp();
> -
> -    QDateTime lastLocalCookieUpdate =
> -            lastUpdateTimeStamp();
> -
> -    if (lastRemoteCookieUpdate.isValid()
> -            && lastLocalCookieUpdate.isValid()
> -            && (lastRemoteCookieUpdate < lastLocalCookieUpdate))
> +    Cookies cookies = store->cookies();
> +
> +    QDateTime lastRemoteCookieUpdate = store->lastUpdateTimeStamp();
> +    QDateTime lastLocalCookieUpdate = lastUpdateTimeStamp();
> +
> +    if (lastRemoteCookieUpdate.isValid() &&
> +        lastLocalCookieUpdate.isValid() &&
> +        (lastRemoteCookieUpdate < lastLocalCookieUpdate))
>      {
>          Q_EMIT moved(false);
>          return;
>      }
>  
> -    setCookies(cookies);
> +    if (setCookies(cookies)) {
> +        Q_EMIT moved(true);
> +    } else {
> +        Q_EMIT moved(false);
> +    }
>  }
> -
> 
> === renamed file 'src/app/webcontainer/cookiestore.h' => 'src/app/webcontainer/cookie-store.h'
> --- src/app/webcontainer/cookiestore.h	2014-01-27 22:58:55 +0000
> +++ src/app/webcontainer/cookie-store.h	2014-05-30 12:37:47 +0000
> @@ -1,5 +1,5 @@
>  /*
> - * Copyright 2013 Canonical Ltd.
> + * Copyright 2014 Canonical Ltd.
>   *
>   * This file is part of webbrowser-app.
>   *
> @@ -16,62 +16,50 @@
>   * along with this program.  If not, see <http://www.gnu.org/licenses/>.
>   */
>  
> -#ifndef __COOKIESTORE_H__
> -#define __COOKIESTORE_H__
> +#ifndef __COOKIE_STORE_H__
> +#define __COOKIE_STORE_H__
>  
> +#include <QByteArray>
> +#include <QDateTime>
> +#include <QList>
>  #include <QObject>
> -#include <QtCore/QList>
> -#include <QtCore/QString>
> -#include <QDateTime>
> -#include <QString>
> -#include <QMap>
>  
> -typedef QMap<QString, QString> Cookies;
> +typedef QList<QByteArray> Cookies;
>  Q_DECLARE_METATYPE(Cookies);
>  
>  
>  class CookieStore : public QObject
>  {
>      Q_OBJECT
> -    Q_PROPERTY(Cookies cookies READ \
> -               cookies WRITE setCookies \
> +    Q_PROPERTY(Cookies cookies READ cookies WRITE setCookies \
>                 NOTIFY cookiesChanged)
> -    Q_PROPERTY(QDateTime lastUpdateTimeStamp \
> -               READ lastUpdateTimeStamp \
> +    Q_PROPERTY(QDateTime lastUpdateTimeStamp READ lastUpdateTimeStamp \
>                 NOTIFY lastUpdateTimeStampChanged)
>  
>  public:
> -
> -    CookieStore(QObject *parent = 0);
> -
> +    CookieStore(QObject* parent = 0);
> +
> +    bool setCookies(const Cookies& cookies);
>      Cookies cookies();
> -    void setCookies(Cookies);
>  
>      virtual QDateTime lastUpdateTimeStamp() const;
>  
> -    Q_INVOKABLE void moveFrom (CookieStore * store);
> +    Q_INVOKABLE void moveFrom(CookieStore* store);
>  
>  Q_SIGNALS:
> -
>      void moved(bool);
>      void cookiesChanged();
>      void lastUpdateTimeStampChanged();
>  
>  protected:
> -
> -    void updateLastUpdateTimestamp(const QDateTime & timestamp);
> -
> +    void updateLastUpdateTimestamp(const QDateTime& timestamp);
>  
>  private:
> -
>      virtual Cookies doGetCookies();
> -    virtual void doSetCookies(Cookies);
> +    virtual bool doSetCookies(const Cookies& Cookies);
>  
>  private:
> -
>      QDateTime _lastUpdateTimeStamp;
>  };
>  
> -
> -#endif // __COOKIESTORE_H__
> -
> +#endif // __COOKIE_STORE_H__
> 
> === renamed file 'src/app/webcontainer/onlineaccountscookiestore.cpp' => 'src/app/webcontainer/online-accounts-cookie-store.cpp'
> --- src/app/webcontainer/onlineaccountscookiestore.cpp	2014-01-27 22:58:55 +0000
> +++ src/app/webcontainer/online-accounts-cookie-store.cpp	2014-05-30 12:37:47 +0000
> @@ -1,5 +1,5 @@
>  /*
> - * Copyright 2013 Canonical Ltd.
> + * Copyright 2013-2014 Canonical Ltd.
>   *
>   * This file is part of webbrowser-app.
>   *
> @@ -16,7 +16,7 @@
>   * along with this program.  If not, see <http://www.gnu.org/licenses/>.
>   */
>  
> -#include "onlineaccountscookiestore.h"
> +#include "online-accounts-cookie-store.h"
>  
>  #include <QList>
>  #include <QVariant>
> @@ -44,15 +44,12 @@
>  #   define ONLINE_ACCOUNTS_COOKIE_STORE_METHOD "cookiesForIdentity"
>  #endif
>  
> -class OnlineAccountsCookieStorePrivate : public QObject
> +class OnlineAccountsCookieStorePrivate
>  {
> -    Q_OBJECT
> -
>  public:
> -    OnlineAccountsCookieStorePrivate (QObject * parent = 0)
> -        : QObject(parent),
> -          _id (0),
> -          m_connection (QDBusConnection::sessionBus())
> +    OnlineAccountsCookieStorePrivate():
> +        _id(0),
> +        m_connection(QDBusConnection::sessionBus())
>      {}
>  
>      quint32 _id;
> @@ -135,9 +132,8 @@
>      return qdbus_cast<Cookies>(arguments.front());
>  }
>  
> -void OnlineAccountsCookieStore::doSetCookies(Cookies cookies)
> +bool OnlineAccountsCookieStore::doSetCookies(const Cookies& cookies)
>  {
>      Q_UNUSED(cookies);
> +    return false;
>  }
> -
> -#include "onlineaccountscookiestore.moc"
> 
> === renamed file 'src/app/webcontainer/onlineaccountscookiestore.h' => 'src/app/webcontainer/online-accounts-cookie-store.h'
> --- src/app/webcontainer/onlineaccountscookiestore.h	2014-01-27 22:58:55 +0000
> +++ src/app/webcontainer/online-accounts-cookie-store.h	2014-05-30 12:37:47 +0000
> @@ -1,5 +1,5 @@
>  /*
> - * Copyright 2013 Canonical Ltd.
> + * Copyright 2013-2014 Canonical Ltd.
>   *
>   * This file is part of webbrowser-app.
>   *
> @@ -16,10 +16,10 @@
>   * along with this program.  If not, see <http://www.gnu.org/licenses/>.
>   */
>  
> -#ifndef ONLINEACCOUNTSCOOKIESTORE_H
> -#define ONLINEACCOUNTSCOOKIESTORE_H
> +#ifndef ONLINE_ACCOUNTS_COOKIE_STORE_H
> +#define ONLINE_ACCOUNTS_COOKIE_STORE_H
>  
> -#include "cookiestore.h"
> +#include "cookie-store.h"
>  
>  class OnlineAccountsCookieStorePrivate;
>  
> @@ -45,7 +45,7 @@
>  private:
>  
>      virtual Cookies doGetCookies() Q_DECL_OVERRIDE;
> -    virtual void doSetCookies(Cookies) Q_DECL_OVERRIDE;
> +    virtual bool doSetCookies(const Cookies& cookies) Q_DECL_OVERRIDE;
>  
>  
>  private:
> @@ -54,4 +54,4 @@
>      Q_DECLARE_PRIVATE(OnlineAccountsCookieStore)
>  };
>  
> -#endif // ONLINEACCOUNTSCOOKIESTORE_H
> +#endif // ONLINE_ACCOUNTS_COOKIE_STORE_H
> 
> === removed file 'src/app/webcontainer/sqlitecookiestore.cpp'
> --- src/app/webcontainer/sqlitecookiestore.cpp	2014-02-07 16:44:50 +0000
> +++ src/app/webcontainer/sqlitecookiestore.cpp	1970-01-01 00:00:00 +0000
> @@ -1,99 +0,0 @@
> -/*
> - * Copyright 2013 Canonical Ltd.
> - *
> - * This file is part of webbrowser-app.
> - *
> - * webbrowser-app 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; version 3.
> - *
> - * webbrowser-app 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 <http://www.gnu.org/licenses/>.
> - */
> -
> -#include "sqlitecookiestore.h"
> -
> -#include <QSqlDatabase>
> -#include <QSqlError>
> -#include <QSqlQuery>
> -#include <QFileInfo>
> -#include <QStandardPaths>
> -#include <QDebug>
> -
> -
> -SqliteCookieStore::SqliteCookieStore(QObject *parent)
> -    : CookieStore(parent)
> -{}
> -
> -Cookies SqliteCookieStore::doGetCookies()
> -{
> -    return Cookies();
> -}
> -
> -QDateTime SqliteCookieStore::lastUpdateTimeStamp() const
> -{
> -    QFileInfo dbFileInfo(getFullDbPathName ());
> -    return dbFileInfo.lastModified();
> -}
> -
> -void SqliteCookieStore::doSetCookies(Cookies cookies)
> -{
> -    QSqlDatabase db = QSqlDatabase::addDatabase("QSQLITE");
> -    db.setDatabaseName (getFullDbPathName ());
> -
> -    if ( ! db.open())
> -    {
> -        qCritical() << "Could not open cookie database: " << getFullDbPathName() << db.lastError();
> -        Q_EMIT moved(false);
> -        return;
> -    }
> -
> -    QSqlQuery q(db);
> -    q.exec("CREATE TABLE IF NOT EXISTS cookies "
> -           "(cookieId VARCHAR PRIMARY KEY, cookie BLOB)");
> -    q.exec ("DELETE FROM cookies;");
> -
> -    q.prepare("INSERT INTO cookies (cookieId, cookie) "
> -              "VALUES (:cookieId, :cookie)");
> -
> -    for (Cookies::const_iterator it = cookies.constBegin();
> -         it != cookies.constEnd();
> -         ++it)
> -    {
> -        q.bindValue(":cookieId", it.key());
> -        q.bindValue(":cookie", it.value());
> -
> -        if ( ! q.exec())
> -        {
> -            qWarning() << "Couldn't insert cookie into DB"
> -                       << it.key();
> -       }
> -    }
> -
> -    Q_EMIT moved(true);
> -}
> -
> -QString SqliteCookieStore::getFullDbPathName() const
> -{
> -    return QStandardPaths::standardLocations(QStandardPaths::HomeLocation)[0] + "/" + dbPath();
> -}
> -
> -void SqliteCookieStore::setDbPath(const QString &path)
> -{
> -    if (path != m_dbPath)
> -    {
> -        m_dbPath = path;
> -        Q_EMIT dbPathChanged();
> -    }
> -}
> -
> -QString SqliteCookieStore::dbPath () const
> -{
> -    return m_dbPath;
> -}
> -
> 
> === removed file 'src/app/webcontainer/sqlitecookiestore.h'
> --- src/app/webcontainer/sqlitecookiestore.h	2014-01-27 22:58:55 +0000
> +++ src/app/webcontainer/sqlitecookiestore.h	1970-01-01 00:00:00 +0000
> @@ -1,58 +0,0 @@
> -/*
> - * Copyright 2013 Canonical Ltd.
> - *
> - * This file is part of webbrowser-app.
> - *
> - * webbrowser-app 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; version 3.
> - *
> - * webbrowser-app 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 <http://www.gnu.org/licenses/>.
> - */
> -
> -#ifndef SQLITECOOKIESTORE_H
> -#define SQLITECOOKIESTORE_H
> -
> -#include "cookiestore.h"
> -#include <QString>
> -
> -
> -class SqliteCookieStore : public CookieStore
> -{
> -    Q_OBJECT
> -    Q_PROPERTY(QString dbPath READ dbPath WRITE setDbPath NOTIFY dbPathChanged)
> -
> -
> -public:
> -    SqliteCookieStore(QObject *parent = 0);
> -
> -    void setDbPath (const QString & path);
> -    QString dbPath () const;
> -
> -    QDateTime lastUpdateTimeStamp() const Q_DECL_OVERRIDE;
> -
> -
> -Q_SIGNALS:
> -
> -    void dbPathChanged();
> -
> -
> -private:
> -
> -    virtual Cookies doGetCookies() Q_DECL_OVERRIDE;
> -    virtual void doSetCookies(Cookies) Q_DECL_OVERRIDE;
> -
> -    QString getFullDbPathName() const;
> -
> -
> -private:
> -    QString m_dbPath;
> -};
> -
> -#endif // SQLITECOOKIESTORE_H
> 
> === modified file 'src/app/webcontainer/webapp-container.cpp'
> --- src/app/webcontainer/webapp-container.cpp	2014-05-08 16:51:08 +0000
> +++ src/app/webcontainer/webapp-container.cpp	2014-05-30 12:37:47 +0000
> @@ -19,8 +19,11 @@
>  #include "config.h"
>  #include "webapp-container.h"
>  
> +#include "chrome-cookie-store.h"
> +#include "online-accounts-cookie-store.h"
>  #include "session-utils.h"
>  #include "url-pattern-utils.h"
> +#include "webkit-cookie-store.h"
>  
>  // Qt
>  #include <QtCore/QCoreApplication>
> @@ -30,14 +33,17 @@
>  #include <QtCore/QtGlobal>
>  #include <QtCore/QRegularExpression>
>  #include <QtCore/QTextStream>
> -#include <QtQuick/QQuickWindow>
>  #include <QtQml/QQmlComponent>
>  #include <QtQml/QQmlContext>
>  #include <QtQml/QQmlEngine>
> +#include <QtQml>
> +#include <QtQuick/QQuickWindow>
>  
>  #include <QStandardPaths>
>  #include <QSettings>
>  
> +static const char privateModuleUri[] = "webcontainer.private";
> +
>  namespace
>  {
>  
> @@ -103,6 +109,7 @@
>          m_window->setProperty("webappName", m_webappName);
>          m_window->setProperty("backForwardButtonsVisible", m_backForwardButtonsVisible);
>          m_window->setProperty("addressBarVisible", m_addressBarVisible);
> +        m_window->setProperty("accountProvider", m_accountProvider);
>  
>          qDebug() << "Using" << (m_withOxide ? "Oxide" : "QtWebkit") << "as the web engine backend";
>          m_window->setProperty("oxide", m_withOxide);
> @@ -134,6 +141,18 @@
>      }
>  }
>  
> +void WebappContainer::qmlEngineCreated(QQmlEngine* engine)
> +{
> +    if (engine) {
> +        qmlRegisterType<ChromeCookieStore>(privateModuleUri, 0, 1,
> +                                           "ChromeCookieStore");
> +        qmlRegisterType<WebkitCookieStore>(privateModuleUri, 0, 1,
> +                                           "WebkitCookieStore");
> +        qmlRegisterType<OnlineAccountsCookieStore>(privateModuleUri, 0, 1,
> +                                                   "OnlineAccountsCookieStore");
> +    }
> +}
> +
>  void WebappContainer::printUsage() const
>  {
>      QTextStream out(stdout);
> @@ -147,6 +166,7 @@
>         " [--webapp=name]"
>         " [--webappModelSearchPath=PATH]"
>         " [--webappUrlPatterns=URL_PATTERNS]"
> +       " [--accountProvider=PROVIDER_NAME]"
>         " [--enable-back-forward]"
>         " [--enable-addressbar]"
>         " [--store-session-cookies]"
> @@ -162,6 +182,7 @@
>      out << "  --webapp=name                       try to match the webapp by name with an installed integration script" << endl;
>      out << "  --webappModelSearchPath=PATH        alter the search path for installed webapps and set it to PATH. PATH can be an absolute or path relative to CWD" << endl;
>      out << "  --webappUrlPatterns=URL_PATTERNS    list of comma-separated url patterns (wildcard based) that the webapp is allowed to navigate to" << endl;
> +    out << "  --accountProvider=PROVIDER_NAME     Online account provider for the application if the application is to reuse a local account." << endl;
>      out << "  --store-session-cookies             store session cookies on disk" << endl;
>      out << "Chrome options (if none specified, no chrome is shown by default):" << endl;
>      out << "  --enable-back-forward               enable the display of the back and forward buttons" << endl;
> @@ -190,6 +211,8 @@
>                  QStringList includePatterns = tail.split(URL_PATTERN_SEPARATOR);
>                  m_webappUrlPatterns = UrlPatternUtils::filterAndTransformUrlPatterns(includePatterns);
>              }
> +        } else if (argument.startsWith("--accountProvider=")) {
> +            m_accountProvider = argument.split("--accountProvider=")[1];
>          } else if (argument == "--store-session-cookies") {
>              m_storeSessionCookies = true;
>          } else if (argument == "--enable-back-forward") {
> 
> === modified file 'src/app/webcontainer/webapp-container.h'
> --- src/app/webcontainer/webapp-container.h	2014-05-08 16:51:08 +0000
> +++ src/app/webcontainer/webapp-container.h	2014-05-30 12:37:47 +0000
> @@ -34,6 +34,9 @@
>  
>      bool initialize();
>  
> +protected:
> +    void qmlEngineCreated(QQmlEngine *);
> +
>  private:
>      virtual void printUsage() const;
>      void parseCommandLine();
> @@ -44,6 +47,7 @@
>      QString m_webappName;
>      QString m_webappModelSearchPath;
>      QStringList m_webappUrlPatterns;
> +    QString m_accountProvider;
>      bool m_withOxide;
>      bool m_storeSessionCookies;
>      bool m_backForwardButtonsVisible;
> 
> === modified file 'src/app/webcontainer/webapp-container.qml'
> --- src/app/webcontainer/webapp-container.qml	2014-04-22 15:35:16 +0000
> +++ src/app/webcontainer/webapp-container.qml	2014-05-30 12:37:47 +0000
> @@ -1,5 +1,5 @@
>  /*
> - * Copyright 2013 Canonical Ltd.
> + * Copyright 2013-2014 Canonical Ltd.
>   *
>   * This file is part of webbrowser-app.
>   *
> @@ -19,22 +19,27 @@
>  import QtQuick 2.0
>  import QtQuick.Window 2.0
>  import Ubuntu.Components 0.1
> +import Ubuntu.Components.Extras.Browser 0.2
> +import webcontainer.private 0.1
>  
>  Window {
> +    id: root
>      objectName: "webappContainer"
>  
> -    property alias developerExtrasEnabled: browser.developerExtrasEnabled
> -
> -    property alias backForwardButtonsVisible: browser.backForwardButtonsVisible
> -    property alias addressBarVisible: browser.addressBarVisible
> -
> -    property alias url: browser.url
> -    property alias webappName: browser.webappName
> -    property alias webappModelSearchPath: browser.webappModelSearchPath
> -    property alias webappUrlPatterns: browser.webappUrlPatterns
> -    property alias oxide: browser.oxide
> -
> -    contentOrientation: browser.screenOrientation
> +    property bool developerExtrasEnabled: false
> +
> +    property bool backForwardButtonsVisible: true
> +    property bool addressBarVisible: true
> +
> +    property string url: ""
> +    property string webappName: ""
> +    property string webappModelSearchPath: ""
> +    property var webappUrlPatterns
> +    property bool oxide: false
> +    property string accountProvider: ""
> +    property var __webappCookieStore: null
> +
> +    contentOrientation: Screen.orientation
>  
>      width: 800
>      height: 600
> @@ -42,24 +47,107 @@
>      title: {
>          if (typeof(webappName) === 'string' && webappName.length !== 0) {
>              return webappName
> -        } else if (browser.title) {
> +        } else if (webappPageComponentLoader.item &&
> +                   webappPageComponentLoader.item.title) {
>              // TRANSLATORS: %1 refers to the current page’s title
> -            return i18n.tr("%1 - Ubuntu Web Browser").arg(browser.title)
> +            return i18n.tr("%1 - Ubuntu Web Browser").arg(webappPageComponentLoader.item.title)
>          } else {
>              return i18n.tr("Ubuntu Web Browser")
>          }
>      }
>  
> -    WebApp {
> -        id: browser
> -
> -        property int screenOrientation: Screen.orientation
> -
> -        chromeless: !backForwardButtonsVisible && !addressBarVisible
> -        webbrowserWindow: webbrowserWindowProxy
> -
> -        anchors.fill: parent
> -
> -        Component.onCompleted: i18n.domain = "webbrowser-app"
> +    Loader {
> +        id: webappPageComponentLoader
> +        anchors.fill: parent
> +    }
> +
> +    Component {
> +        id: webappPageComponent
> +
> +        WebApp {
> +            id: browser
> +            addressBarVisible: root.addressBarVisible
> +            backForwardButtonsVisible: root.backForwardButtonsVisible
> +            developerExtrasEnabled: root.developerExtrasEnabled
> +            oxide: root.oxide
> +            url: root.url
> +            webappModelSearchPath: root.webappModelSearchPath
> +            webappName: root.webappName
> +            webappUrlPatterns: root.webappUrlPatterns
> +
> +            anchors.fill: parent
> +
> +            chromeless: !backForwardButtonsVisible && !addressBarVisible
> +            webbrowserWindow: webbrowserWindowProxy
> +
> +            Component.onCompleted: i18n.domain = "webbrowser-app"
> +        }
> +    }
> +
> +    Loader {
> +        id: accountsPageComponentLoader
> +        anchors.fill: parent
> +        onStatusChanged: {
> +            if (status == Loader.Error) {
> +                // Happens on the desktop, if Ubuntu.OnlineAccounts.Client
> +                // can't be imported
> +                loadWebAppView()
> +            } else if (status == Loader.Ready) {
> +                item.visible = true
> +            }
> +        }
> +    }
> +
> +    Connections {
> +        target: accountsPageComponentLoader.item
> +        onDone: loadWebAppView()
> +    }
> +
> +    Component {
> +        id: webkitCookieStoreComponent
> +        WebkitCookieStore {
> +            dbPath: dataLocation + "/.QtWebKit/cookies.db"
> +        }
> +    }
> +
> +    Component {
> +        id: chromeCookieStoreComponent
> +        ChromeCookieStore {
> +            dbPath: dataLocation + "/cookies.sqlite"
> +        }
> +    }
> +
> +    Component.onCompleted: updateCurrentView()
> +
> +    onAccountProviderChanged: updateCurrentView();
> +
> +    function updateCurrentView() {
> +        // check if we are to display the login view
> +        // or directly switch to the webapp view
> +        if (accountProvider.length !== 0) {
> +            loadLoginView();
> +        } else {
> +            loadWebAppView();
> +        }
> +    }
> +
> +    function loadLoginView() {
> +        if (!__webappCookieStore) {
> +            var cookieStoreComponent =
> +                oxide ? chromeCookieStoreComponent : webkitCookieStoreComponent
> +            __webappCookieStore = cookieStoreComponent.createObject(this)
> +        }
> +        accountsPageComponentLoader.setSource("AccountsPage.qml", {
> +            "accountProvider": accountProvider,
> +            "applicationName": Qt.application.name,
> +            "webappCookieStore": __webappCookieStore
> +        })
> +    }
> +
> +    function loadWebAppView() {
> +        webappPageComponentLoader.sourceComponent = webappPageComponent;
> +        if (accountsPageComponentLoader.item)
> +            accountsPageComponentLoader.item.visible = false;
> +        webappPageComponentLoader.item.visible = true;
>      }
>  }
> 
> === added file 'src/app/webcontainer/webkit-cookie-store.cpp'
> --- src/app/webcontainer/webkit-cookie-store.cpp	1970-01-01 00:00:00 +0000
> +++ src/app/webcontainer/webkit-cookie-store.cpp	2014-05-30 12:37:47 +0000
> @@ -0,0 +1,119 @@
> +/*
> + * Copyright 2014 Canonical Ltd.
> + *
> + * This file is part of webbrowser-app.
> + *
> + * webbrowser-app 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; version 3.
> + *
> + * webbrowser-app 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 <http://www.gnu.org/licenses/>.
> + */
> +
> +#include "webkit-cookie-store.h"
> +
> +#include <QDebug>
> +#include <QFileInfo>
> +#include <QNetworkCookie>
> +#include <QSqlError>
> +#include <QSqlQuery>
> +#include <QStandardPaths>
> +
> +static int connectionCounter = 0;
> +
> +WebkitCookieStore::WebkitCookieStore(QObject* parent):
> +    CookieStore(parent)
> +{
> +    QString connectionName =
> +        QString("webkitCookieStore-%1").arg(connectionCounter++);
> +    m_db = QSqlDatabase::addDatabase("QSQLITE", connectionName);
> +}
> +
> +Cookies WebkitCookieStore::doGetCookies()
> +{
> +    Cookies cookies;
> +    m_db.setDatabaseName(getFullDbPathName());
> +
> +    if (!m_db.open()) {
> +        qCritical() << "Could not open cookie database:" << getFullDbPathName() << m_db.lastError();
> +        return cookies;
> +    }
> +
> +    QSqlQuery q(m_db);
> +    q.exec("SELECT cookie FROM cookies;");
> +
> +    while (q.next()) {
> +        cookies.append(q.value(0).toString().toUtf8());
> +    }
> +
> +    m_db.close();
> +    return cookies;
> +}
> +
> +QDateTime WebkitCookieStore::lastUpdateTimeStamp() const
> +{
> +    QFileInfo dbFileInfo(getFullDbPathName());
> +    return dbFileInfo.lastModified();
> +}
> +
> +bool WebkitCookieStore::doSetCookies(const Cookies& cookies)
> +{
> +    m_db.setDatabaseName(getFullDbPathName());
> +
> +    if (!m_db.open()) {
> +        qCritical() << "Could not open cookie database:" << getFullDbPathName() << m_db.lastError();
> +        return false;
> +    }
> +
> +    QSqlQuery q(m_db);
> +    q.exec("CREATE TABLE IF NOT EXISTS cookies "
> +           "(cookieId VARCHAR PRIMARY KEY, cookie BLOB)");
> +    q.exec ("DELETE FROM cookies;");
> +
> +    q.prepare("INSERT INTO cookies (cookieId, cookie) "
> +              "VALUES (:cookieId, :cookie)");
> +
> +    Q_FOREACH(const QByteArray& cookie, cookies) {
> +        /* The unique key is the hostname + the cookie name */
> +        QList<QNetworkCookie> parsed = QNetworkCookie::parseCookies(cookie);
> +        if (parsed.isEmpty()) continue;
> +
> +        const QNetworkCookie& c = parsed.first();
> +        q.bindValue(":cookieId", c.domain() + c.name());
> +        q.bindValue(":cookie", cookie);
> +
> +        if (!q.exec()) {
> +            qWarning() << "Couldn't insert cookie into DB" << cookie;
> +        }
> +    }
> +
> +    m_db.close();
> +
> +    return true;
> +}
> +
> +QString WebkitCookieStore::getFullDbPathName() const
> +{
> +    return dbPath().startsWith('/') ? dbPath() :
> +        QStandardPaths::standardLocations(QStandardPaths::HomeLocation)[0] + "/" + dbPath();
> +}
> +
> +void WebkitCookieStore::setDbPath(const QString& path)
> +{
> +    if (path != m_dbPath) {
> +        m_dbPath = path;
> +        Q_EMIT dbPathChanged();
> +    }
> +}
> +
> +QString WebkitCookieStore::dbPath() const
> +{
> +    return m_dbPath;
> +}
> +
> 
> === added file 'src/app/webcontainer/webkit-cookie-store.h'
> --- src/app/webcontainer/webkit-cookie-store.h	1970-01-01 00:00:00 +0000
> +++ src/app/webcontainer/webkit-cookie-store.h	2014-05-30 12:37:47 +0000
> @@ -0,0 +1,53 @@
> +/*
> + * Copyright 2014 Canonical Ltd.
> + *
> + * This file is part of webbrowser-app.
> + *
> + * webbrowser-app 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; version 3.
> + *
> + * webbrowser-app 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 <http://www.gnu.org/licenses/>.
> + */
> +
> +#ifndef WEBKIT_COOKIE_STORE_H
> +#define WEBKIT_COOKIE_STORE_H
> +
> +#include "cookie-store.h"
> +
> +#include <QSqlDatabase>
> +
> +class WebkitCookieStore : public CookieStore
> +{
> +    Q_OBJECT
> +    Q_PROPERTY(QString dbPath READ dbPath WRITE setDbPath NOTIFY dbPathChanged)
> +
> +public:
> +    WebkitCookieStore(QObject* parent = 0);
> +
> +    void setDbPath(const QString& path);
> +    QString dbPath() const;
> +
> +    QDateTime lastUpdateTimeStamp() const Q_DECL_OVERRIDE;
> +
> +Q_SIGNALS:
> +    void dbPathChanged();
> +
> +private:
> +    virtual Cookies doGetCookies() Q_DECL_OVERRIDE;
> +    virtual bool doSetCookies(const Cookies& cookies) Q_DECL_OVERRIDE;
> +
> +    QString getFullDbPathName() const;
> +
> +private:
> +    QString m_dbPath;
> +    QSqlDatabase m_db;
> +};
> +
> +#endif // WEBKIT_COOKIE_STORE_H
> 
> === modified file 'tests/unittests/CMakeLists.txt'
> --- tests/unittests/CMakeLists.txt	2014-04-03 12:54:12 +0000
> +++ tests/unittests/CMakeLists.txt	2014-05-30 12:37:47 +0000
> @@ -10,3 +10,4 @@
>  add_subdirectory(tabs-model)
>  add_subdirectory(bookmarks-model)
>  add_subdirectory(container-url-patterns)
> +add_subdirectory(cookie-store)
> 
> === added directory 'tests/unittests/cookie-store'
> === added file 'tests/unittests/cookie-store/CMakeLists.txt'
> --- tests/unittests/cookie-store/CMakeLists.txt	1970-01-01 00:00:00 +0000
> +++ tests/unittests/cookie-store/CMakeLists.txt	2014-05-30 12:37:47 +0000
> @@ -0,0 +1,11 @@
> +set(TEST tst_CookieStoreTest)
> +set(SOURCES
> +    ${webapp-container_SOURCE_DIR}/chrome-cookie-store.cpp
> +    ${webapp-container_SOURCE_DIR}/cookie-store.cpp
> +    ${webapp-container_SOURCE_DIR}/webkit-cookie-store.cpp
> +    tst_CookieStore.cpp
> +)
> +add_executable(${TEST} ${SOURCES})
> +include_directories(${webapp-container_SOURCE_DIR})
> +qt5_use_modules(${TEST} Core Network Sql Test)
> +add_test(${TEST} ${CMAKE_CURRENT_BINARY_DIR}/${TEST} -xunitxml -o ${TEST}.xml)
> 
> === added file 'tests/unittests/cookie-store/tst_CookieStore.cpp'
> --- tests/unittests/cookie-store/tst_CookieStore.cpp	1970-01-01 00:00:00 +0000
> +++ tests/unittests/cookie-store/tst_CookieStore.cpp	2014-05-30 12:37:47 +0000
> @@ -0,0 +1,189 @@
> +/*
> + * Copyright 2014 Canonical Ltd.
> + *
> + * This file is part of webbrowser-app.
> + *
> + * webbrowser-app 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; version 3.
> + *
> + * webbrowser-app 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 <http://www.gnu.org/licenses/>.
> + */
> +
> +// Qt
> +#include <QtCore/QDir>
> +#include <QtCore/QSet>
> +#include <QtCore/QTemporaryDir>
> +#include <QtNetwork/QNetworkCookie>
> +#include <QtTest/QSignalSpy>
> +#include <QtTest/QtTest>
> +
> +// local
> +#include "chrome-cookie-store.h"
> +#include "webkit-cookie-store.h"
> +
> +uint qHash(const QNetworkCookie &cookie, uint seed)
> +{
> +    return qHash(cookie.toRawForm(), seed);
> +}
> +
> +class CookieStoreTest : public QObject
> +{
> +    Q_OBJECT
> +
> +private Q_SLOTS:
> +    void testChromeProperties();
> +    void testWebkitProperties();
> +
> +    void testChromeReadWrite_data() { setupCookieData(); }
> +    void testWebkitReadWrite_data() { setupCookieData(); }
> +    void testChromeReadWrite();
> +    void testWebkitReadWrite();
> +
> +    void testMoving_data() { setupCookieData(); }
> +    void testMoving();
> +
> +private:
> +    void setupCookieData();
> +    QSet<QNetworkCookie> parseCookies(const Cookies &rawCookies);
> +};
> +
> +QSet<QNetworkCookie>
> +CookieStoreTest::parseCookies(const Cookies &rawCookies)
> +{
> +    QList<QNetworkCookie> cookies;
> +    Q_FOREACH(const QByteArray &rawCookie, rawCookies) {
> +        cookies.append(QNetworkCookie::parseCookies(rawCookie));
> +    }
> +    return cookies.toSet();
> +}
> +
> +void CookieStoreTest::testChromeProperties()
> +{
> +    QTemporaryDir tmpDir;
> +    QVERIFY(tmpDir.isValid());
> +    QTemporaryDir tmpDir2;
> +    QVERIFY(tmpDir2.isValid());
> +
> +    ChromeCookieStore store;
> +    QSignalSpy dbPathChanged(&store, SIGNAL(dbPathChanged()));
> +
> +    store.setProperty("dbPath", tmpDir.path());
> +    QCOMPARE(dbPathChanged.count(), 1);
> +    QCOMPARE(store.property("dbPath").toString(), tmpDir.path());
> +    dbPathChanged.clear();
> +
> +    store.setProperty("dbPath", "file://" + tmpDir2.path());
> +    QCOMPARE(dbPathChanged.count(), 1);
> +    QCOMPARE(store.property("dbPath").toString(), tmpDir2.path());
> +
> +    QVERIFY(store.property("cookies").value<Cookies>().isEmpty());
> +}
> +
> +void CookieStoreTest::testWebkitProperties()
> +{
> +    QTemporaryDir tmpDir;
> +    QVERIFY(tmpDir.isValid());
> +
> +    WebkitCookieStore store;
> +    QSignalSpy dbPathChanged(&store, SIGNAL(dbPathChanged()));
> +
> +    store.setProperty("dbPath", tmpDir.path());
> +    QCOMPARE(dbPathChanged.count(), 1);
> +    QCOMPARE(store.property("dbPath").toString(), tmpDir.path());
> +
> +    QVERIFY(store.property("cookies").value<Cookies>().isEmpty());
> +}
> +
> +void CookieStoreTest::setupCookieData()
> +{
> +    QTest::addColumn<Cookies>("cookies");
> +
> +    Cookies cookies;
> +
> +    cookies << "LSID=DQAAAKEaem_vYg; Domain=docs.foo.com; Path=/accounts; "
> +        "Expires=Wed, 13 Jan 2021 22:23:01 GMT; Secure; HttpOnly";
> +    QTest::newRow("Single cookie") << cookies;
> +
> +    cookies.clear();
> +    cookies << "LSID=DQAAAKEaem_vYg; Domain=docs.foo.com; Path=/accounts; "
> +        "Expires=Wed, 13 Jan 2021 22:23:01 GMT; Secure; HttpOnly";
> +    cookies << "HSID=AYQEVnDKrdst; Domain=.foo.com; Path=/; "
> +        "Expires=Wed, 13 Jan 2021 22:23:01 GMT; HttpOnly";
> +    cookies << "SSID=Ap4PGTEq; Domain=foo.com; Path=/; "
> +        "Expires=Wed, 13 Jan 2021 22:23:01 GMT; Secure";
> +    cookies << "made_write_conn=1295214458; Path=/; Domain=.example.com";
> +    QTest::newRow("Few cookies") << cookies;
> +}
> +
> +void CookieStoreTest::testChromeReadWrite()
> +{
> +    QFETCH(Cookies, cookies);
> +
> +    QTemporaryDir tmpDir;
> +    QVERIFY(tmpDir.isValid());
> +    QDir testDir(tmpDir.path());
> +
> +    ChromeCookieStore store;
> +    QSignalSpy cookiesChanged(&store, SIGNAL(cookiesChanged()));
> +    store.setDbPath(testDir.filePath("cookies.db"));
> +
> +    QCOMPARE(cookiesChanged.count(), 0);
> +    store.setProperty("cookies", QVariant::fromValue(cookies));
> +    QCOMPARE(cookiesChanged.count(), 1);
> +    Cookies readCookies = store.property("cookies").value<Cookies>();
> +    QCOMPARE(parseCookies(readCookies), parseCookies(cookies));
> +}
> +
> +void CookieStoreTest::testWebkitReadWrite()
> +{
> +    QFETCH(Cookies, cookies);
> +
> +    QTemporaryDir tmpDir;
> +    QVERIFY(tmpDir.isValid());
> +    QDir testDir(tmpDir.path());
> +
> +    WebkitCookieStore store;
> +    QSignalSpy cookiesChanged(&store, SIGNAL(cookiesChanged()));
> +    store.setDbPath(testDir.filePath("cookies.db"));
> +
> +    QCOMPARE(cookiesChanged.count(), 0);
> +    store.setProperty("cookies", QVariant::fromValue(cookies));
> +    QCOMPARE(cookiesChanged.count(), 1);
> +    Cookies readCookies = store.property("cookies").value<Cookies>();
> +    QCOMPARE(parseCookies(readCookies), parseCookies(cookies));
> +}
> +
> +void CookieStoreTest::testMoving()
> +{
> +    QFETCH(Cookies, cookies);
> +
> +    QTemporaryDir tmpDir;
> +    QVERIFY(tmpDir.isValid());
> +    QDir testDir(tmpDir.path());
> +
> +    WebkitCookieStore webkitStore;
> +    webkitStore.setDbPath(testDir.filePath("webkit.db"));
> +    webkitStore.setProperty("cookies", QVariant::fromValue(cookies));
> +
> +    ChromeCookieStore chromeStore;
> +    chromeStore.setDbPath(testDir.filePath("chrome.db"));
> +
> +    QSignalSpy moved(&chromeStore, SIGNAL(moved(bool)));
> +    chromeStore.moveFrom(&webkitStore);
> +
> +    QCOMPARE(moved.count(), 1);
> +    QCOMPARE(moved.at(0).at(0).toBool(), true);
> +
> +    Cookies movedCookies = chromeStore.property("cookies").value<Cookies>();
> +    QCOMPARE(parseCookies(movedCookies), parseCookies(cookies));
> +}
> +
> +QTEST_MAIN(CookieStoreTest)
> +#include "tst_CookieStore.moc"
> 


-- 
https://code.launchpad.net/~mardy/webbrowser-app/add-onlineaccount-support-for-container2/+merge/211701
Your team Ubuntu Phablet Team is subscribed to branch lp:webbrowser-app.



More information about the Ubuntu-reviews mailing list