Merge lp:~osomon/webbrowser-app/certificate-error-fixes into lp:webbrowser-app

Proposed by Olivier Tilloy
Status: Merged
Approved by: Olivier Tilloy
Approved revision: 811
Merged at revision: 847
Proposed branch: lp:~osomon/webbrowser-app/certificate-error-fixes
Merge into: lp:webbrowser-app
Diff against target: 279 lines (+155/-20)
5 files modified
src/app/UrlUtils.js (+43/-0)
src/app/WebViewImpl.qml (+1/-12)
src/app/webbrowser/Browser.qml (+50/-4)
src/app/webbrowser/Chrome.qml (+4/-4)
tests/unittests/qml/tst_UrlUtils.qml (+57/-0)
To merge this branch: bzr merge lp:~osomon/webbrowser-app/certificate-error-fixes
Reviewer Review Type Date Requested Status
PS Jenkins bot continuous-integration Needs Fixing
Chris Coulson Approve
Michael Sheldon Pending
Ubuntu Phablet Team Pending
Review via email: mp+243795@code.launchpad.net

Commit message

Record host and error code along with certificate fingerprint when whitelisting a certificate error.

Description of the change

Note to the reviewer: this fixes only points 1 and 2 of bug #1377194. Points 3 and 5 require further design input (I’m in discussions with design, they will be addressed separately), and point 4 is being fixed separately (see https://code.launchpad.net/~osomon/webbrowser-app/reset-cancelled-certificateError/+merge/243522).

To post a comment you must log in.
Revision history for this message
Chris Coulson (chrisccoulson) :
review: Approve
Revision history for this message
PS Jenkins bot (ps-jenkins) wrote :
review: Needs Fixing (continuous-integration)
810. By Olivier Tilloy

Merge the latest changes from trunk,
and resolve a conflict.

811. By Olivier Tilloy

Revert meaningless changes to the translation template,
previously committed by accident.

Preview Diff

[H/L] Next/Prev Comment, [J/K] Next/Prev File, [N/P] Next/Prev Hunk
=== added file 'src/app/UrlUtils.js'
--- src/app/UrlUtils.js 1970-01-01 00:00:00 +0000
+++ src/app/UrlUtils.js 2014-12-12 09:55:56 +0000
@@ -0,0 +1,43 @@
1/*
2 * Copyright 2014 Canonical Ltd.
3 *
4 * This file is part of webbrowser-app.
5 *
6 * webbrowser-app is free software; you can redistribute it and/or modify
7 * it under the terms of the GNU General Public License as published by
8 * the Free Software Foundation; version 3.
9 *
10 * webbrowser-app is distributed in the hope that it will be useful,
11 * but WITHOUT ANY WARRANTY; without even the implied warranty of
12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 * GNU General Public License for more details.
14 *
15 * You should have received a copy of the GNU General Public License
16 * along with this program. If not, see <http://www.gnu.org/licenses/>.
17*/
18
19function extractAuthority(url) {
20 var authority = url.toString()
21 var indexOfScheme = authority.indexOf("://")
22 if (indexOfScheme !== -1) {
23 authority = authority.slice(indexOfScheme + 3)
24 }
25 var indexOfPath = authority.indexOf("/")
26 if (indexOfPath !== -1) {
27 authority = authority.slice(0, indexOfPath)
28 }
29 return authority
30}
31
32function extractHost(url) {
33 var host = extractAuthority(url)
34 var indexOfAt = host.indexOf("@")
35 if (indexOfAt !== -1) {
36 host = host.slice(indexOfAt + 1)
37 }
38 var indexOfColon = host.indexOf(":")
39 if (indexOfColon !== -1) {
40 host = host.slice(0, indexOfColon)
41 }
42 return host
43}
044
=== modified file 'src/app/WebViewImpl.qml'
--- src/app/WebViewImpl.qml 2014-12-03 11:45:36 +0000
+++ src/app/WebViewImpl.qml 2014-12-12 09:55:56 +0000
@@ -26,9 +26,6 @@
26 id: webview26 id: webview
2727
28 property var currentWebview: webview28 property var currentWebview: webview
29 property var certificateError
30 // Invalid certificates the user has explicitly allowed for this session
31 property var allowedCertificates: []
3229
33 /*experimental.certificateVerificationDialog: CertificateVerificationDialog {}30 /*experimental.certificateVerificationDialog: CertificateVerificationDialog {}
34 experimental.authenticationDialog: AuthenticationDialog {}31 experimental.authenticationDialog: AuthenticationDialog {}
@@ -41,6 +38,7 @@
4138
42 QtObject {39 QtObject {
43 id: internal40 id: internal
41
44 readonly property var downloadMimeTypesBlacklist: [42 readonly property var downloadMimeTypesBlacklist: [
45 "application/x-shockwave-flash", // http://launchpad.net/bugs/137980643 "application/x-shockwave-flash", // http://launchpad.net/bugs/1379806
46 ]44 ]
@@ -89,13 +87,4 @@
89 // TODO: we might want to store the answer to avoid requesting87 // TODO: we might want to store the answer to avoid requesting
90 // the permission everytime the user visits this site.88 // the permission everytime the user visits this site.
91 }89 }
92
93 onCertificateError: {
94 if(webview.allowedCertificates.indexOf(error.certificate.fingerprintSHA1) != -1) {
95 error.allow()
96 } else {
97 certificateError = error
98 error.onCancelled.connect(function() { webview.certificateError = null })
99 }
100 }
101}90}
10291
=== modified file 'src/app/webbrowser/Browser.qml'
--- src/app/webbrowser/Browser.qml 2014-12-11 17:04:20 +0000
+++ src/app/webbrowser/Browser.qml 2014-12-12 09:55:56 +0000
@@ -23,6 +23,7 @@
23import webbrowsercommon.private 0.123import webbrowsercommon.private 0.1
24import "../actions" as Actions24import "../actions" as Actions
25import ".."25import ".."
26import "../UrlUtils.js" as UrlUtils
2627
27BrowserView {28BrowserView {
28 id: browser29 id: browser
@@ -106,14 +107,14 @@
106 sourceComponent: InvalidCertificateErrorSheet {107 sourceComponent: InvalidCertificateErrorSheet {
107 visible: currentWebview && currentWebview.certificateError != null108 visible: currentWebview && currentWebview.certificateError != null
108 certificateError: currentWebview ? currentWebview.certificateError : null109 certificateError: currentWebview ? currentWebview.certificateError : null
109 onAllowed: { 110 onAllowed: {
110 // Automatically allow future requests involving this111 // Automatically allow future requests involving this
111 // certificate for the duration of the session.112 // certificate for the duration of the session.
112 currentWebview.allowedCertificates.push(currentWebview.certificateError.certificate.fingerprintSHA1)113 internal.allowCertificateError(currentWebview.certificateError)
113 currentWebview.certificateError = null114 currentWebview.resetCertificateError()
114 }115 }
115 onDenied: {116 onDenied: {
116 currentWebview.certificateError = null117 currentWebview.resetCertificateError()
117 }118 }
118 }119 }
119 asynchronous: true120 asynchronous: true
@@ -422,6 +423,8 @@
422 id: webviewComponent423 id: webviewComponent
423424
424 WebViewImpl {425 WebViewImpl {
426 id: webviewimpl
427
425 currentWebview: browser.currentWebview428 currentWebview: browser.currentWebview
426429
427 anchors.fill: parent430 anchors.fill: parent
@@ -476,6 +479,24 @@
476479
477 onGeolocationPermissionRequested: requestGeolocationPermission(request)480 onGeolocationPermissionRequested: requestGeolocationPermission(request)
478481
482 property var certificateError
483 function resetCertificateError() {
484 certificateError = null
485 }
486 onCertificateError: {
487 if (!error.isMainFrame || error.isSubresource) {
488 // Not a main frame document error, just block the content
489 // (it’s not overridable anyway).
490 return
491 }
492 if (internal.isCertificateErrorAllowed(error)) {
493 error.allow()
494 } else {
495 certificateError = error
496 error.onCancelled.connect(webviewimpl.resetCertificateError)
497 }
498 }
499
479 Loader {500 Loader {
480 id: newTabViewLoader501 id: newTabViewLoader
481 anchors.fill: parent502 anchors.fill: parent
@@ -528,6 +549,31 @@
528 chrome.forceActiveFocus()549 chrome.forceActiveFocus()
529 Qt.inputMethod.show() // work around http://pad.lv/1316057550 Qt.inputMethod.show() // work around http://pad.lv/1316057
530 }551 }
552
553 // Invalid certificates the user has explicitly allowed for this session
554 property var allowedCertificateErrors: []
555
556 function allowCertificateError(error) {
557 var host = UrlUtils.extractHost(error.url)
558 var code = error.certError
559 var fingerprint = error.certificate.fingerprintSHA1
560 allowedCertificateErrors.push([host, code, fingerprint])
561 }
562
563 function isCertificateErrorAllowed(error) {
564 var host = UrlUtils.extractHost(error.url)
565 var code = error.certError
566 var fingerprint = error.certificate.fingerprintSHA1
567 for (var i in allowedCertificateErrors) {
568 var allowed = allowedCertificateErrors[i]
569 if ((host == allowed[0]) &&
570 (code == allowed[1]) &&
571 (fingerprint == allowed[2])) {
572 return true
573 }
574 }
575 return false
576 }
531 }577 }
532578
533 function openUrlInNewTab(url, setCurrent, load) {579 function openUrlInNewTab(url, setCurrent, load) {
534580
=== modified file 'src/app/webbrowser/Chrome.qml'
--- src/app/webbrowser/Chrome.qml 2014-12-03 17:47:38 +0000
+++ src/app/webbrowser/Chrome.qml 2014-12-12 09:55:56 +0000
@@ -56,7 +56,7 @@
56 enabled: chrome.webview ? chrome.webview.canGoBack : false56 enabled: chrome.webview ? chrome.webview.canGoBack : false
57 onTriggered: {57 onTriggered: {
58 // Workaround for https://launchpad.net/bugs/137719858 // Workaround for https://launchpad.net/bugs/1377198
59 chrome.webview.certificateError = null59 chrome.webview.resetCertificateError()
60 chrome.webview.goBack()60 chrome.webview.goBack()
61 }61 }
62 }62 }
@@ -80,7 +80,7 @@
80 enabled: chrome.webview ? chrome.webview.canGoForward : false80 enabled: chrome.webview ? chrome.webview.canGoForward : false
81 onTriggered: {81 onTriggered: {
82 // Workaround for https://launchpad.net/bugs/137719882 // Workaround for https://launchpad.net/bugs/1377198
83 chrome.webview.certificateError = null83 chrome.webview.resetCertificateError()
84 chrome.webview.goForward()84 chrome.webview.goForward()
85 }85 }
86 }86 }
@@ -113,12 +113,12 @@
113113
114 onValidated: {114 onValidated: {
115 // Workaround for https://launchpad.net/bugs/1377198115 // Workaround for https://launchpad.net/bugs/1377198
116 chrome.webview.certificateError = null116 chrome.webview.resetCertificateError()
117 chrome.webview.url = requestedUrl117 chrome.webview.url = requestedUrl
118 }118 }
119 onRequestReload: {119 onRequestReload: {
120 // Workaround for https://launchpad.net/bugs/1377198120 // Workaround for https://launchpad.net/bugs/1377198
121 chrome.webview.certificateError = null121 chrome.webview.resetCertificateError()
122 chrome.webview.reload()122 chrome.webview.reload()
123 }123 }
124 onRequestStop: chrome.webview.stop()124 onRequestStop: chrome.webview.stop()
125125
=== added file 'tests/unittests/qml/tst_UrlUtils.qml'
--- tests/unittests/qml/tst_UrlUtils.qml 1970-01-01 00:00:00 +0000
+++ tests/unittests/qml/tst_UrlUtils.qml 2014-12-12 09:55:56 +0000
@@ -0,0 +1,57 @@
1/*
2 * Copyright 2014 Canonical Ltd.
3 *
4 * This file is part of webbrowser-app.
5 *
6 * webbrowser-app is free software; you can redistribute it and/or modify
7 * it under the terms of the GNU General Public License as published by
8 * the Free Software Foundation; version 3.
9 *
10 * webbrowser-app is distributed in the hope that it will be useful,
11 * but WITHOUT ANY WARRANTY; without even the implied warranty of
12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 * GNU General Public License for more details.
14 *
15 * You should have received a copy of the GNU General Public License
16 * along with this program. If not, see <http://www.gnu.org/licenses/>.
17 */
18
19import QtTest 1.0
20import "../../../src/app/UrlUtils.js" as UrlUtils
21
22TestCase {
23 name: "UrlUtils"
24
25 function test_extractAuthority_data() {
26 return [
27 {url: "", authority: ""},
28 {url: "http://example.org/", authority: "example.org"},
29 {url: "http://www.example.org/", authority: "www.example.org"},
30 {url: "http://www.example.org/foo/bar", authority: "www.example.org"},
31 {url: "http://example.org:2442/foo", authority: "example.org:2442"},
32 {url: "http://user:pwd@example.org/", authority: "user:pwd@example.org"},
33 {url: "http://user:pwd@example.org:2442/", authority: "user:pwd@example.org:2442"},
34 {url: "ftp://user:pwd@example.org:21/foo/bar", authority: "user:pwd@example.org:21"}
35 ]
36 }
37
38 function test_extractAuthority(data) {
39 compare(UrlUtils.extractAuthority(data.url), data.authority)
40 }
41
42 function test_extractHost_data() {
43 return [
44 {url: "http://example.org/", host: "example.org"},
45 {url: "http://www.example.org/", host: "www.example.org"},
46 {url: "http://www.example.org/foo/bar", host: "www.example.org"},
47 {url: "http://example.org:2442/foo", host: "example.org"},
48 {url: "http://user:pwd@example.org/", host: "example.org"},
49 {url: "http://user:pwd@example.org:2442/", host: "example.org"},
50 {url: "ftp://user:pwd@example.org:21/foo/bar", host: "example.org"}
51 ]
52 }
53
54 function test_extractHost(data) {
55 compare(UrlUtils.extractHost(data.url), data.host)
56 }
57}

Subscribers

People subscribed via source and target branches

to status/vote changes: