Merge lp:~mardy/webbrowser-app/force-cookie-refresh into lp:webbrowser-app

Proposed by Alberto Mardegan
Status: Work in progress
Proposed branch: lp:~mardy/webbrowser-app/force-cookie-refresh
Merge into: lp:webbrowser-app
Diff against target: 449 lines (+153/-60)
7 files modified
src/app/webcontainer/AccountsLoginPage.qml (+29/-15)
src/app/webcontainer/AccountsPage.qml (+9/-6)
src/app/webcontainer/chrome-cookie-store.cpp (+25/-2)
src/app/webcontainer/chrome-cookie-store.h (+8/-0)
src/app/webcontainer/webapp-container.cpp (+6/-0)
src/app/webcontainer/webapp-container.h (+1/-0)
src/app/webcontainer/webapp-container.qml (+75/-37)
To merge this branch: bzr merge lp:~mardy/webbrowser-app/force-cookie-refresh
Reviewer Review Type Date Requested Status
Ubuntu Phablet Team Pending
Review via email: mp+248398@code.launchpad.net

Description of the change

Allow webapps to specify a maximum lifetime for cookies

After this period has expired, the container will ask OA to use an interactive login, which should get us new cookies.

To post a comment you must log in.
880. By Alberto Mardegan

No need to use a specialized method to compute time diffs

881. By Alberto Mardegan

Misc fixes

882. By Alberto Mardegan

From trunk

[ Olivier Tilloy ]
* Update translation template.
* Revert the UA override for m.youtube.com as it was causing a lot of
  stuttering (due to very high CPU usage) on krillin. In the meantime,
  the issue with videos not playing that this update was meant to
  address (bug #1415107) was resolved on youtube’s side. (LP:
  #1417258, #1415107)
[ Florian Boucault ]
* Make splashscreen white instead of the default black. (LP: #1378379)
[ Niklas Wenzel ]
* Add the ability to open a link in a new background tab (LP:
  #1339437)
[ Olivier Tilloy ]
* Use the new restoreState API in oxide 1.4 to properly save and
  restore navigation state across sessions. (LP: #1353143)
* Add a UA override for youtube.com on desktop to fix video playback.
  (LP: #1412880)
[ CI Train Bot ]
* Resync trunk
[ Alexandre Abreu ]
* Add support for intent:// schemes in the container. (LP: #1407709)
[ Ubuntu daily release ]
* New rebuild forced
[ Olivier Tilloy ]
* Update the m.youtube.com UA override to fix video playback. (LP:
  #1415107)

883. By Alberto Mardegan

Don't start browsing if are are to talk to OA

884. By Alberto Mardegan

from trunk

[ Olivier Tilloy ]
* Remove all references to private Qt headers, now that we require Qt
  5.4.
* Specify the cache path on the web context, to avoid caching data
  under ~/.local/share/. (LP: #1424726)
* Update translation template.
[ CI Train Bot ]
* New rebuild forced.
[ Olivier Tilloy ]
* Use the new Item::grabToImage() API (new in Qt 5.4) to replace the
  custom ItemCapture element. (LP: #1401581, #1425550)
[ Robert Bruce Park ]
* Launchpad automatic translations update.
[ Olivier Tilloy ]
* Fix a flaky autopilot test. (LP: #1423115)
* Use Qt::AA_ShareOpenGLContexts when building with Qt >= 5.4. (LP:
  #1387537)
[ Riccardo Padovani ]
* Fixed design of multiselection in history view (LP: #1412732)
[ CI Train Bot ]
* New rebuild forced.
[ Olivier Tilloy ]
* Honour Window.close() requests.
* Work around autopilot test failure by ensuring that the selection is
  cleared before clicking on the action button. (LP: #1417118)
* Add a config option to allow users to turn off automatic session
  restore.
* No-change rebuild against Qt 5.4.0.

885. By Alberto Mardegan

Use RequestPasswordPolicy

886. By Alberto Mardegan

From trunk

Unmerged revisions

886. By Alberto Mardegan

From trunk

885. By Alberto Mardegan

Use RequestPasswordPolicy

884. By Alberto Mardegan

from trunk

[ Olivier Tilloy ]
* Remove all references to private Qt headers, now that we require Qt
  5.4.
* Specify the cache path on the web context, to avoid caching data
  under ~/.local/share/. (LP: #1424726)
* Update translation template.
[ CI Train Bot ]
* New rebuild forced.
[ Olivier Tilloy ]
* Use the new Item::grabToImage() API (new in Qt 5.4) to replace the
  custom ItemCapture element. (LP: #1401581, #1425550)
[ Robert Bruce Park ]
* Launchpad automatic translations update.
[ Olivier Tilloy ]
* Fix a flaky autopilot test. (LP: #1423115)
* Use Qt::AA_ShareOpenGLContexts when building with Qt >= 5.4. (LP:
  #1387537)
[ Riccardo Padovani ]
* Fixed design of multiselection in history view (LP: #1412732)
[ CI Train Bot ]
* New rebuild forced.
[ Olivier Tilloy ]
* Honour Window.close() requests.
* Work around autopilot test failure by ensuring that the selection is
  cleared before clicking on the action button. (LP: #1417118)
* Add a config option to allow users to turn off automatic session
  restore.
* No-change rebuild against Qt 5.4.0.

883. By Alberto Mardegan

Don't start browsing if are are to talk to OA

882. By Alberto Mardegan

From trunk

[ Olivier Tilloy ]
* Update translation template.
* Revert the UA override for m.youtube.com as it was causing a lot of
  stuttering (due to very high CPU usage) on krillin. In the meantime,
  the issue with videos not playing that this update was meant to
  address (bug #1415107) was resolved on youtube’s side. (LP:
  #1417258, #1415107)
[ Florian Boucault ]
* Make splashscreen white instead of the default black. (LP: #1378379)
[ Niklas Wenzel ]
* Add the ability to open a link in a new background tab (LP:
  #1339437)
[ Olivier Tilloy ]
* Use the new restoreState API in oxide 1.4 to properly save and
  restore navigation state across sessions. (LP: #1353143)
* Add a UA override for youtube.com on desktop to fix video playback.
  (LP: #1412880)
[ CI Train Bot ]
* Resync trunk
[ Alexandre Abreu ]
* Add support for intent:// schemes in the container. (LP: #1407709)
[ Ubuntu daily release ]
* New rebuild forced
[ Olivier Tilloy ]
* Update the m.youtube.com UA override to fix video playback. (LP:
  #1415107)

881. By Alberto Mardegan

Misc fixes

880. By Alberto Mardegan

No need to use a specialized method to compute time diffs

879. By Alberto Mardegan

WIP

Preview Diff

[H/L] Next/Prev Comment, [J/K] Next/Prev File, [N/P] Next/Prev Hunk
1=== modified file 'src/app/webcontainer/AccountsLoginPage.qml'
2--- src/app/webcontainer/AccountsLoginPage.qml 2014-10-06 12:52:34 +0000
3+++ src/app/webcontainer/AccountsLoginPage.qml 2015-03-11 14:46:44 +0000
4@@ -28,7 +28,10 @@
5 property string accountProvider: ""
6 property string applicationName: ""
7
8- signal done(variant credentialsId)
9+ signal accountSelected(var credentialsId)
10+ signal done(bool successful)
11+
12+ property var __account: null
13
14 Timer {
15 id: checkTimer
16@@ -66,7 +69,11 @@
17 if (accountsModel.count === 0) {
18 accountsModel.createNewAccount()
19 } else {
20- doLogin(accountsModel.model.get(0, "accountServiceHandle"))
21+ var accountHandle = accountsModel.model.get(0, "accountServiceHandle")
22+ __account = accountComponent.createObject(root, {
23+ objectHandle: accountHandle
24+ })
25+ root.accountSelected(__account.authData.credentialsId)
26 }
27
28 // Note: Disable the account selection for now until we have a clearer view of
29@@ -163,6 +170,7 @@
30 }
31 }
32
33+ /*
34 Component {
35 id: accountsSelectionViewComponent
36 AccountsView {
37@@ -173,23 +181,29 @@
38 onAccountSelected: doLogin(accountServiceHandle)
39 }
40 }
41-
42- function doLogin(accountHandle) {
43- var account = accountComponent.createObject(root, {objectHandle: accountHandle});
44-
45+ */
46+
47+ function login(forceCookieRefresh) {
48 function authenticatedCallback() {
49- account.authenticated.disconnect(authenticatedCallback);
50- done(account.authData.credentialsId);
51+ console.log("Authenticated!")
52+ __account.authenticated.disconnect(authenticatedCallback)
53+ root.done(true)
54 }
55- account.authenticated.connect(authenticatedCallback);
56+ __account.authenticated.connect(authenticatedCallback)
57
58 function errorCallback() {
59- account.authenticationError.disconnect(errorCallback);
60- done(null);
61- }
62- account.authenticationError.connect(errorCallback);
63-
64- account.authenticate(null);
65+ console.log("Authentication error!")
66+ __account.authenticationError.disconnect(errorCallback)
67+ root.done(false)
68+ }
69+ __account.authenticationError.connect(errorCallback)
70+
71+ var params = {}
72+ if (forceCookieRefresh) {
73+ params["UiPolicy"] = 1 // RequestPasswordPolicy
74+ }
75+
76+ __account.authenticate(params)
77 }
78
79 Component {
80
81=== modified file 'src/app/webcontainer/AccountsPage.qml'
82--- src/app/webcontainer/AccountsPage.qml 2014-10-02 18:03:46 +0000
83+++ src/app/webcontainer/AccountsPage.qml 2015-03-11 14:46:44 +0000
84@@ -25,8 +25,10 @@
85
86 property alias accountProvider: accountsLogin.accountProvider
87 property alias applicationName: accountsLogin.applicationName
88+ property int selectedAccount: -1
89
90- signal done(bool successful, var credentialsId)
91+ signal accountSelected(var credentialsId)
92+ signal done(bool successful)
93
94 visible: true
95 anchors.fill: parent
96@@ -36,10 +38,11 @@
97
98 anchors.fill: parent
99
100- onDone: {
101- if (!accountsPage.visible)
102- return
103- accountsPage.done(credentialsId != null, credentialsId)
104- }
105+ onAccountSelected: accountsPage.selectedAccount = credentialsId
106+ onDone: accountsPage.done(successful)
107+ }
108+
109+ function login(forceCookieRefresh) {
110+ accountsLogin.login(forceCookieRefresh)
111 }
112 }
113
114=== modified file 'src/app/webcontainer/chrome-cookie-store.cpp'
115--- src/app/webcontainer/chrome-cookie-store.cpp 2014-10-08 07:08:49 +0000
116+++ src/app/webcontainer/chrome-cookie-store.cpp 2015-03-11 14:46:44 +0000
117@@ -21,11 +21,15 @@
118
119 #include <QDebug>
120 #include <QFileInfo>
121+#include <QSettings>
122 #include <QStandardPaths>
123
124+const QString keyLastMovedTimeStamp = QStringLiteral("CookiesLastMoved");
125+
126 ChromeCookieStore::ChromeCookieStore(QObject* parent):
127 CookieStore(parent),
128- m_cookieHelper(new OxideCookieHelper(this))
129+ m_cookieHelper(new OxideCookieHelper(this)),
130+ m_settings(0)
131 {
132 QObject::connect(m_cookieHelper, SIGNAL(oxideStoreBackendChanged()),
133 this, SIGNAL(oxideStoreBackendChanged()));
134@@ -73,7 +77,7 @@
135
136 QDateTime ChromeCookieStore::lastUpdateTimeStamp() const
137 {
138- QFileInfo dbFileInfo(m_dbPath);
139+ QFileInfo dbFileInfo(m_dbPath + "/cookies.sqlite");
140 return dbFileInfo.lastModified();
141 }
142
143@@ -93,6 +97,8 @@
144 return;
145 }
146 m_dbPath = normalizedPath;
147+ delete m_settings;
148+ m_settings = new QSettings(m_dbPath + "/uoa.ini", QSettings::IniFormat);
149 Q_EMIT dbPathChanged();
150 }
151 }
152@@ -101,3 +107,20 @@
153 {
154 return m_dbPath;
155 }
156+
157+void ChromeCookieStore::setLastMovedTimeStamp(const QDateTime &timeStamp)
158+{
159+ if (Q_UNLIKELY(!m_settings)) {
160+ qWarning() << "dbPath not set!";
161+ return;
162+ }
163+ m_settings->setValue(keyLastMovedTimeStamp, timeStamp.toString(Qt::ISODate));
164+ m_settings->sync();
165+ Q_EMIT lastMovedTimeStampChanged();
166+}
167+
168+QDateTime ChromeCookieStore::lastMovedTimeStamp() const
169+{
170+ return m_settings ?
171+ m_settings->value(keyLastMovedTimeStamp).toDateTime() : QDateTime();
172+}
173
174=== modified file 'src/app/webcontainer/chrome-cookie-store.h'
175--- src/app/webcontainer/chrome-cookie-store.h 2014-10-08 07:08:49 +0000
176+++ src/app/webcontainer/chrome-cookie-store.h 2015-03-11 14:46:44 +0000
177@@ -25,6 +25,7 @@
178 #include <QUrl>
179
180 class OxideCookieHelper;
181+class QSettings;
182
183 class ChromeCookieStore : public CookieStore
184 {
185@@ -32,6 +33,8 @@
186
187 Q_PROPERTY(QString dbPath READ dbPath WRITE setDbPath NOTIFY dbPathChanged)
188 Q_PROPERTY(QObject* oxideStoreBackend READ oxideStoreBackend WRITE setOxideStoreBackend NOTIFY oxideStoreBackendChanged)
189+ Q_PROPERTY(QDateTime lastMovedTimeStamp READ lastMovedTimeStamp \
190+ WRITE setLastMovedTimeStamp NOTIFY lastMovedTimeStampChanged)
191
192 public:
193 ChromeCookieStore(QObject* parent = 0);
194@@ -47,9 +50,13 @@
195 // CookieStore overrides
196 QDateTime lastUpdateTimeStamp() const Q_DECL_OVERRIDE;
197
198+ void setLastMovedTimeStamp(const QDateTime &timeStamp);
199+ QDateTime lastMovedTimeStamp() const;
200+
201 Q_SIGNALS:
202 void dbPathChanged();
203 void oxideStoreBackendChanged();
204+ void lastMovedTimeStampChanged();
205
206 private Q_SLOTS:
207 void oxideCookiesReceived(int requestId, const QVariant& cookies);
208@@ -62,6 +69,7 @@
209 private:
210 OxideCookieHelper* m_cookieHelper;
211 QString m_dbPath;
212+ QSettings *m_settings;
213 };
214
215 #endif // CHROME_COOKIE_STORE_H
216
217=== modified file 'src/app/webcontainer/webapp-container.cpp'
218--- src/app/webcontainer/webapp-container.cpp 2015-02-27 09:28:41 +0000
219+++ src/app/webcontainer/webapp-container.cpp 2015-03-11 14:46:44 +0000
220@@ -115,6 +115,7 @@
221 m_backForwardButtonsVisible(false),
222 m_addressBarVisible(false),
223 m_localWebappManifest(false),
224+ m_cookieRefreshInterval(0),
225 m_webappContainerHelper(new WebappContainerHelper())
226 {
227 }
228@@ -145,6 +146,7 @@
229 m_window->setProperty("backForwardButtonsVisible", m_backForwardButtonsVisible);
230 m_window->setProperty("chromeVisible", m_addressBarVisible);
231 m_window->setProperty("accountProvider", m_accountProvider);
232+ m_window->setProperty("cookieRefreshInterval", m_cookieRefreshInterval);
233
234 qDebug() << "Using" << (m_withOxide ? "Oxide" : "QtWebkit") << "as the web engine backend";
235 m_window->setProperty("oxide", m_withOxide);
236@@ -287,6 +289,7 @@
237 " [--enable-addressbar]"
238 " [--store-session-cookies]"
239 " [--user-agent-string=USER_AGENT]"
240+ " [--cookie-refresh-interval=DAYS]"
241 " [URL]" << endl;
242 out << "Options:" << endl;
243 out << " -h, --help display this help message and exit" << endl;
244@@ -305,6 +308,7 @@
245 out << "Chrome options (if none specified, no chrome is shown by default):" << endl;
246 out << " --enable-back-forward enable the display of the back and forward buttons (implies --enable-addressbar)" << endl;
247 out << " --enable-addressbar enable the display of a minimal chrome (favicon and title)" << endl;
248+ out << " --cookie-refresh-interval the maximum number of days between manual logins" << endl;
249 }
250
251 void WebappContainer::parseCommandLine()
252@@ -348,6 +352,8 @@
253 m_localCookieStoreDbPath = argument.split("--local-cookie-db-path=")[1];
254 } else if (argument.startsWith("--user-agent-string=")) {
255 m_userAgentOverride = argument.split("--user-agent-string=")[1];
256+ } else if (argument.startsWith("--cookie-refresh-interval=")) {
257+ m_cookieRefreshInterval = argument.split("--cookie-refresh-interval=")[1].toInt();
258 }
259 }
260 }
261
262=== modified file 'src/app/webcontainer/webapp-container.h'
263--- src/app/webcontainer/webapp-container.h 2015-01-26 14:53:18 +0000
264+++ src/app/webcontainer/webapp-container.h 2015-03-11 14:46:44 +0000
265@@ -68,6 +68,7 @@
266 QString m_popupRedirectionUrlPrefixPattern;
267 QString m_localCookieStoreDbPath;
268 QString m_userAgentOverride;
269+ int m_cookieRefreshInterval;
270 QScopedPointer<WebappContainerHelper> m_webappContainerHelper;
271 QScopedPointer<IntentFilter> m_intentFilter;
272
273
274=== modified file 'src/app/webcontainer/webapp-container.qml'
275--- src/app/webcontainer/webapp-container.qml 2015-02-02 13:55:49 +0000
276+++ src/app/webcontainer/webapp-container.qml 2015-03-11 14:46:44 +0000
277@@ -42,8 +42,10 @@
278 property string popupRedirectionUrlPrefixPattern: ""
279 property url webviewOverrideFile: ""
280 property var __webappCookieStore: null
281+ property var __sourceCookieStore: null
282 property string localUserAgentOverride: ""
283 property bool blockOpenExternalUrls: false
284+ property int cookieRefreshInterval: 0
285
286 currentWebview: webappViewLoader.item ? webappViewLoader.item.currentWebview : null
287
288@@ -164,9 +166,10 @@
289 if (status == Loader.Error) {
290 // Happens on the desktop, if Ubuntu.OnlineAccounts.Client
291 // can't be imported
292- loadWebAppView()
293+ loadWebAppView(true)
294 } else if (status == Loader.Ready) {
295 item.visible = true
296+ initializeForAccount(item.selectedAccount)
297 }
298 }
299 }
300@@ -177,48 +180,81 @@
301 }
302 if (!result) {
303 console.log("Cookies were not moved")
304+ } else {
305+ console.log("cookies moved, timestamp = " + __sourceCookieStore.lastUpdateTimeStamp)
306+ __webappCookieStore.lastMovedTimeStamp = __sourceCookieStore.lastUpdateTimeStamp
307 }
308 webappViewLoader.item.url = root.url
309 }
310
311 function moveCookies(credentialsId) {
312+ console.log("moving cookies for id " + credentialsId)
313+ var storeComponent = localCookieStoreDbPath.length !== 0 ?
314+ localCookieStoreComponent : onlineAccountStoreComponent
315+
316+ __sourceCookieStore = storeComponent.createObject(root, { "accountId": credentialsId })
317+ __webappCookieStore.moved.connect(onCookiesMoved)
318+ __webappCookieStore.moveFrom(__sourceCookieStore)
319+ }
320+
321+ function doLogin() {
322 if (!__webappCookieStore) {
323 var context = webappViewLoader.item.currentWebview.context
324 __webappCookieStore = oxideCookieStoreComponent.createObject(this, {
325 "oxideStoreBackend": context.cookieManager,
326- "dbPath": context.dataPath + "/cookies.sqlite"
327+ "dbPath": context.dataPath
328 })
329 }
330
331- var storeComponent = localCookieStoreDbPath.length !== 0 ?
332- localCookieStoreComponent : onlineAccountStoreComponent
333-
334- var instance = storeComponent.createObject(root, { "accountId": credentialsId })
335- __webappCookieStore.moved.connect(onCookiesMoved)
336- __webappCookieStore.moveFrom(instance)
337+ /* Check the date of the cookies; if it's older than
338+ * "cookieRefreshInterval" days, set the "forceCookieRefresh" flag so
339+ * that Online Accounts will use an interactive login (and hopefully
340+ * get new cookies). */
341+ var forceCookieRefresh = false
342+ if (cookieRefreshInterval > 0) {
343+ var elapsedMs = Date.now() - __webappCookieStore.lastMovedTimeStamp
344+ // convert days to milliseconds
345+ if (elapsedMs > cookieRefreshInterval * 86400000) {
346+ forceCookieRefresh = true
347+ }
348+ }
349+ console.log("Preparing for login, forced = " + forceCookieRefresh)
350+ accountsPageComponentLoader.item.login(forceCookieRefresh)
351+ }
352+
353+ function initializeForAccount(credentialsId) {
354+ console.log("Account selected, creds: " + credentialsId)
355+ if (credentialsId < 0) return
356+
357+ if (credentialsId > 0) {
358+ webappViewLoader.loaded.connect(function () {
359+ if (webappViewLoader.status == Loader.Ready) {
360+ doLogin()
361+ }
362+ });
363+ webappViewLoader.credentialsId = credentialsId
364+ // If we need to preserve session cookies, make sure that the
365+ // mode is "restored" and not "persistent", or the cookies
366+ // transferred from OA would be lost.
367+ // We check if the webContextSessionCookieMode is defined and, if so,
368+ // we override it in the webapp loader.
369+ if (typeof webContextSessionCookieMode === "string") {
370+ webappViewLoader.webContextSessionCookieMode = "restored"
371+ }
372+ }
373+
374+ loadWebAppView(credentialsId == 0)
375 }
376
377 Connections {
378 target: accountsPageComponentLoader.item
379+ onSelectedAccountChanged: initializeForAccount(accountsPageComponentLoader.item.selectedAccount)
380 onDone: {
381+ console.log("Authentication done, successful = " + successful)
382 if (successful) {
383- webappViewLoader.loaded.connect(function () {
384- if (webappViewLoader.status == Loader.Ready) {
385- moveCookies(webappViewLoader.credentialsId)
386- }
387- });
388- webappViewLoader.credentialsId = credentialsId
389- // If we need to preserve session cookies, make sure that the
390- // mode is "restored" and not "persistent", or the cookies
391- // transferred from OA would be lost.
392- // We check if the webContextSessionCookieMode is defined and, if so,
393- // we override it in the webapp loader.
394- if (typeof webContextSessionCookieMode === "string") {
395- webappViewLoader.webContextSessionCookieMode = "restored"
396- }
397+ moveCookies(webappViewLoader.credentialsId)
398 }
399-
400- loadWebAppView()
401+ // FIXME else?
402 }
403 }
404
405@@ -243,7 +279,7 @@
406 if (accountProvider.length !== 0 && oxide) {
407 loadLoginView();
408 } else {
409- loadWebAppView();
410+ loadWebAppView(true);
411 }
412 }
413
414@@ -259,22 +295,24 @@
415 })
416 }
417
418- function loadWebAppView() {
419+ function loadWebAppView(startBrowsing) {
420 if (accountsPageComponentLoader.item)
421 accountsPageComponentLoader.item.visible = false
422
423- webappViewLoader.loaded.connect(function () {
424- if (webappViewLoader.status === Loader.Ready) {
425- // As we use StateSaver to restore the URL, we need to check first if
426- // it has not been set previously before setting the URL to the default property
427- // homepage.
428- var webView = webappViewLoader.item.currentWebview
429- var current_url = webView.url.toString();
430- if (!current_url || current_url.length === 0) {
431- webView.url = root.url
432+ if (startBrowsing) {
433+ webappViewLoader.loaded.connect(function () {
434+ if (webappViewLoader.status === Loader.Ready) {
435+ // As we use StateSaver to restore the URL, we need to check first if
436+ // it has not been set previously before setting the URL to the default property
437+ // homepage.
438+ var webView = webappViewLoader.item.currentWebview
439+ var current_url = webView.url.toString();
440+ if (!current_url || current_url.length === 0) {
441+ webView.url = root.url
442+ }
443 }
444- }
445- });
446+ });
447+ }
448 webappViewLoader.sourceComponent = webappViewComponent
449 }
450

Subscribers

People subscribed via source and target branches

to status/vote changes: