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
1=== added file 'src/app/UrlUtils.js'
2--- src/app/UrlUtils.js 1970-01-01 00:00:00 +0000
3+++ src/app/UrlUtils.js 2014-12-12 09:55:56 +0000
4@@ -0,0 +1,43 @@
5+/*
6+ * Copyright 2014 Canonical Ltd.
7+ *
8+ * This file is part of webbrowser-app.
9+ *
10+ * webbrowser-app is free software; you can redistribute it and/or modify
11+ * it under the terms of the GNU General Public License as published by
12+ * the Free Software Foundation; version 3.
13+ *
14+ * webbrowser-app is distributed in the hope that it will be useful,
15+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
16+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
17+ * GNU General Public License for more details.
18+ *
19+ * You should have received a copy of the GNU General Public License
20+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
21+*/
22+
23+function extractAuthority(url) {
24+ var authority = url.toString()
25+ var indexOfScheme = authority.indexOf("://")
26+ if (indexOfScheme !== -1) {
27+ authority = authority.slice(indexOfScheme + 3)
28+ }
29+ var indexOfPath = authority.indexOf("/")
30+ if (indexOfPath !== -1) {
31+ authority = authority.slice(0, indexOfPath)
32+ }
33+ return authority
34+}
35+
36+function extractHost(url) {
37+ var host = extractAuthority(url)
38+ var indexOfAt = host.indexOf("@")
39+ if (indexOfAt !== -1) {
40+ host = host.slice(indexOfAt + 1)
41+ }
42+ var indexOfColon = host.indexOf(":")
43+ if (indexOfColon !== -1) {
44+ host = host.slice(0, indexOfColon)
45+ }
46+ return host
47+}
48
49=== modified file 'src/app/WebViewImpl.qml'
50--- src/app/WebViewImpl.qml 2014-12-03 11:45:36 +0000
51+++ src/app/WebViewImpl.qml 2014-12-12 09:55:56 +0000
52@@ -26,9 +26,6 @@
53 id: webview
54
55 property var currentWebview: webview
56- property var certificateError
57- // Invalid certificates the user has explicitly allowed for this session
58- property var allowedCertificates: []
59
60 /*experimental.certificateVerificationDialog: CertificateVerificationDialog {}
61 experimental.authenticationDialog: AuthenticationDialog {}
62@@ -41,6 +38,7 @@
63
64 QtObject {
65 id: internal
66+
67 readonly property var downloadMimeTypesBlacklist: [
68 "application/x-shockwave-flash", // http://launchpad.net/bugs/1379806
69 ]
70@@ -89,13 +87,4 @@
71 // TODO: we might want to store the answer to avoid requesting
72 // the permission everytime the user visits this site.
73 }
74-
75- onCertificateError: {
76- if(webview.allowedCertificates.indexOf(error.certificate.fingerprintSHA1) != -1) {
77- error.allow()
78- } else {
79- certificateError = error
80- error.onCancelled.connect(function() { webview.certificateError = null })
81- }
82- }
83 }
84
85=== modified file 'src/app/webbrowser/Browser.qml'
86--- src/app/webbrowser/Browser.qml 2014-12-11 17:04:20 +0000
87+++ src/app/webbrowser/Browser.qml 2014-12-12 09:55:56 +0000
88@@ -23,6 +23,7 @@
89 import webbrowsercommon.private 0.1
90 import "../actions" as Actions
91 import ".."
92+import "../UrlUtils.js" as UrlUtils
93
94 BrowserView {
95 id: browser
96@@ -106,14 +107,14 @@
97 sourceComponent: InvalidCertificateErrorSheet {
98 visible: currentWebview && currentWebview.certificateError != null
99 certificateError: currentWebview ? currentWebview.certificateError : null
100- onAllowed: {
101+ onAllowed: {
102 // Automatically allow future requests involving this
103 // certificate for the duration of the session.
104- currentWebview.allowedCertificates.push(currentWebview.certificateError.certificate.fingerprintSHA1)
105- currentWebview.certificateError = null
106+ internal.allowCertificateError(currentWebview.certificateError)
107+ currentWebview.resetCertificateError()
108 }
109 onDenied: {
110- currentWebview.certificateError = null
111+ currentWebview.resetCertificateError()
112 }
113 }
114 asynchronous: true
115@@ -422,6 +423,8 @@
116 id: webviewComponent
117
118 WebViewImpl {
119+ id: webviewimpl
120+
121 currentWebview: browser.currentWebview
122
123 anchors.fill: parent
124@@ -476,6 +479,24 @@
125
126 onGeolocationPermissionRequested: requestGeolocationPermission(request)
127
128+ property var certificateError
129+ function resetCertificateError() {
130+ certificateError = null
131+ }
132+ onCertificateError: {
133+ if (!error.isMainFrame || error.isSubresource) {
134+ // Not a main frame document error, just block the content
135+ // (it’s not overridable anyway).
136+ return
137+ }
138+ if (internal.isCertificateErrorAllowed(error)) {
139+ error.allow()
140+ } else {
141+ certificateError = error
142+ error.onCancelled.connect(webviewimpl.resetCertificateError)
143+ }
144+ }
145+
146 Loader {
147 id: newTabViewLoader
148 anchors.fill: parent
149@@ -528,6 +549,31 @@
150 chrome.forceActiveFocus()
151 Qt.inputMethod.show() // work around http://pad.lv/1316057
152 }
153+
154+ // Invalid certificates the user has explicitly allowed for this session
155+ property var allowedCertificateErrors: []
156+
157+ function allowCertificateError(error) {
158+ var host = UrlUtils.extractHost(error.url)
159+ var code = error.certError
160+ var fingerprint = error.certificate.fingerprintSHA1
161+ allowedCertificateErrors.push([host, code, fingerprint])
162+ }
163+
164+ function isCertificateErrorAllowed(error) {
165+ var host = UrlUtils.extractHost(error.url)
166+ var code = error.certError
167+ var fingerprint = error.certificate.fingerprintSHA1
168+ for (var i in allowedCertificateErrors) {
169+ var allowed = allowedCertificateErrors[i]
170+ if ((host == allowed[0]) &&
171+ (code == allowed[1]) &&
172+ (fingerprint == allowed[2])) {
173+ return true
174+ }
175+ }
176+ return false
177+ }
178 }
179
180 function openUrlInNewTab(url, setCurrent, load) {
181
182=== modified file 'src/app/webbrowser/Chrome.qml'
183--- src/app/webbrowser/Chrome.qml 2014-12-03 17:47:38 +0000
184+++ src/app/webbrowser/Chrome.qml 2014-12-12 09:55:56 +0000
185@@ -56,7 +56,7 @@
186 enabled: chrome.webview ? chrome.webview.canGoBack : false
187 onTriggered: {
188 // Workaround for https://launchpad.net/bugs/1377198
189- chrome.webview.certificateError = null
190+ chrome.webview.resetCertificateError()
191 chrome.webview.goBack()
192 }
193 }
194@@ -80,7 +80,7 @@
195 enabled: chrome.webview ? chrome.webview.canGoForward : false
196 onTriggered: {
197 // Workaround for https://launchpad.net/bugs/1377198
198- chrome.webview.certificateError = null
199+ chrome.webview.resetCertificateError()
200 chrome.webview.goForward()
201 }
202 }
203@@ -113,12 +113,12 @@
204
205 onValidated: {
206 // Workaround for https://launchpad.net/bugs/1377198
207- chrome.webview.certificateError = null
208+ chrome.webview.resetCertificateError()
209 chrome.webview.url = requestedUrl
210 }
211 onRequestReload: {
212 // Workaround for https://launchpad.net/bugs/1377198
213- chrome.webview.certificateError = null
214+ chrome.webview.resetCertificateError()
215 chrome.webview.reload()
216 }
217 onRequestStop: chrome.webview.stop()
218
219=== added file 'tests/unittests/qml/tst_UrlUtils.qml'
220--- tests/unittests/qml/tst_UrlUtils.qml 1970-01-01 00:00:00 +0000
221+++ tests/unittests/qml/tst_UrlUtils.qml 2014-12-12 09:55:56 +0000
222@@ -0,0 +1,57 @@
223+/*
224+ * Copyright 2014 Canonical Ltd.
225+ *
226+ * This file is part of webbrowser-app.
227+ *
228+ * webbrowser-app is free software; you can redistribute it and/or modify
229+ * it under the terms of the GNU General Public License as published by
230+ * the Free Software Foundation; version 3.
231+ *
232+ * webbrowser-app is distributed in the hope that it will be useful,
233+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
234+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
235+ * GNU General Public License for more details.
236+ *
237+ * You should have received a copy of the GNU General Public License
238+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
239+ */
240+
241+import QtTest 1.0
242+import "../../../src/app/UrlUtils.js" as UrlUtils
243+
244+TestCase {
245+ name: "UrlUtils"
246+
247+ function test_extractAuthority_data() {
248+ return [
249+ {url: "", authority: ""},
250+ {url: "http://example.org/", authority: "example.org"},
251+ {url: "http://www.example.org/", authority: "www.example.org"},
252+ {url: "http://www.example.org/foo/bar", authority: "www.example.org"},
253+ {url: "http://example.org:2442/foo", authority: "example.org:2442"},
254+ {url: "http://user:pwd@example.org/", authority: "user:pwd@example.org"},
255+ {url: "http://user:pwd@example.org:2442/", authority: "user:pwd@example.org:2442"},
256+ {url: "ftp://user:pwd@example.org:21/foo/bar", authority: "user:pwd@example.org:21"}
257+ ]
258+ }
259+
260+ function test_extractAuthority(data) {
261+ compare(UrlUtils.extractAuthority(data.url), data.authority)
262+ }
263+
264+ function test_extractHost_data() {
265+ return [
266+ {url: "http://example.org/", host: "example.org"},
267+ {url: "http://www.example.org/", host: "www.example.org"},
268+ {url: "http://www.example.org/foo/bar", host: "www.example.org"},
269+ {url: "http://example.org:2442/foo", host: "example.org"},
270+ {url: "http://user:pwd@example.org/", host: "example.org"},
271+ {url: "http://user:pwd@example.org:2442/", host: "example.org"},
272+ {url: "ftp://user:pwd@example.org:21/foo/bar", host: "example.org"}
273+ ]
274+ }
275+
276+ function test_extractHost(data) {
277+ compare(UrlUtils.extractHost(data.url), data.host)
278+ }
279+}

Subscribers

People subscribed via source and target branches

to status/vote changes: