Merge lp:~osomon/webbrowser-app/broken-lock into lp:webbrowser-app

Proposed by Olivier Tilloy
Status: Merged
Approved by: Olivier Tilloy
Approved revision: 873
Merged at revision: 868
Proposed branch: lp:~osomon/webbrowser-app/broken-lock
Merge into: lp:webbrowser-app
Diff against target: 516 lines (+225/-169)
3 files modified
src/app/webbrowser/AddressBar.qml (+95/-93)
src/app/webbrowser/Chrome.qml (+2/-2)
src/app/webbrowser/SecurityCertificatePopover.qml (+128/-74)
To merge this branch: bzr merge lp:~osomon/webbrowser-app/broken-lock
Reviewer Review Type Date Requested Status
PS Jenkins bot continuous-integration Needs Fixing
Michael Sheldon (community) Approve
Review via email: mp+247061@code.launchpad.net

Commit message

Display a broken padlock icon when browsing a page loaded over an insecure connection.

To post a comment you must log in.
Revision history for this message
PS Jenkins bot (ps-jenkins) wrote :
review: Needs Fixing (continuous-integration)
Revision history for this message
PS Jenkins bot (ps-jenkins) wrote :
review: Needs Fixing (continuous-integration)
Revision history for this message
PS Jenkins bot (ps-jenkins) wrote :
review: Needs Fixing (continuous-integration)
Revision history for this message
Michael Sheldon (michael-sheldon) wrote :

Looks good to me, the only possible addition that might be worth considering is adding a brief description to the certificate pop-up for the broken padlock like we currently have for the insecure content warning.

review: Approve
Revision history for this message
PS Jenkins bot (ps-jenkins) wrote :
review: Needs Fixing (continuous-integration)
Revision history for this message
PS Jenkins bot (ps-jenkins) wrote :
review: Needs Fixing (continuous-integration)
Revision history for this message
PS Jenkins bot (ps-jenkins) wrote :
review: Needs Fixing (continuous-integration)
Revision history for this message
PS Jenkins bot (ps-jenkins) wrote :
review: Needs Fixing (continuous-integration)

Preview Diff

[H/L] Next/Prev Comment, [J/K] Next/Prev File, [N/P] Next/Prev Hunk
1=== modified file 'src/app/webbrowser/AddressBar.qml'
2--- src/app/webbrowser/AddressBar.qml 2014-12-12 23:51:36 +0000
3+++ src/app/webbrowser/AddressBar.qml 2015-01-21 15:39:32 +0000
4@@ -1,5 +1,5 @@
5 /*
6- * Copyright 2013-2014 Canonical Ltd.
7+ * Copyright 2013-2015 Canonical Ltd.
8 *
9 * This file is part of webbrowser-app.
10 *
11@@ -41,7 +41,7 @@
12 // XXX: for testing purposes only, do not use to modify the
13 // contents/behaviour of the internals of the component.
14 readonly property Item __textField: textField
15- readonly property Item __actionButton: actionButton
16+ readonly property Item __actionButton: action
17 readonly property Item __bookmarkToggle: bookmarkToggle
18
19 height: textField.height
20@@ -64,117 +64,118 @@
21 anchors.fill: parent
22
23 primaryItem: Item {
24- width: iconsRow.width
25- height: iconsRow.height
26+ id: icons
27+
28+ width: iconsRow.width + units.gu(1)
29+ height: units.gu(2)
30+
31 Row {
32 id: iconsRow
33- Item {
34- height: textField.height
35+
36+ spacing: units.gu(1)
37+ anchors {
38+ top: parent.top
39+ bottom: parent.bottom
40+ horizontalCenter: parent.horizontalCenter
41+ }
42+
43+ Favicon {
44+ id: favicon
45+ anchors.verticalCenter: parent.verticalCenter
46+ visible: (addressbar.state == "") && addressbar.actualUrl.toString() &&
47+ !internal.securityWarning && !internal.securityError
48+ }
49+
50+ Icon {
51+ id: action
52+
53+ height: parent.height
54 width: height
55- visible: (addressbar.state != "") || !internal.secureConnection || !internal.securityWarning
56-
57- Favicon {
58- id: favicon
59- anchors.centerIn: parent
60- visible: (addressbar.state == "") && addressbar.actualUrl.toString() && !internal.securityWarning
61- }
62-
63- Item {
64- id: certificatePopoverPositioner
65- anchors.bottom: favicon.bottom
66- anchors.horizontalCenter: favicon.horizontalCenter
67- }
68+
69+ visible: (addressbar.state == "editing") ||
70+ (addressbar.state == "loading") ||
71+ !addressbar.text
72+
73+ enabled: addressbar.text
74+ opacity: enabled ? 1.0 : 0.3
75+
76+ readonly property bool loading: addressbar.state == "loading"
77+ readonly property bool editing: addressbar.state == "editing"
78+ readonly property bool reload: editing && addressbar.text &&
79+ (addressbar.text == addressbar.actualUrl)
80+ readonly property bool looksLikeAUrl: internal.looksLikeAUrl(addressbar.text.trim())
81+
82+ name: loading ? "stop" :
83+ reload ? "reload" :
84+ looksLikeAUrl ? "stock_website" : "search"
85
86 MouseArea {
87- id: actionButton
88 objectName: "actionButton"
89- anchors.fill: parent
90- enabled: addressbar.text
91- opacity: enabled ? 1.0 : 0.3
92
93- Icon {
94- id: actionIcon
95- height: parent.height - units.gu(2)
96- width: height
97- anchors.centerIn: parent
98- name: {
99- switch (addressbar.state) {
100- case "loading":
101- return "stop"
102- case "editing":
103- if (addressbar.text && (addressbar.text == addressbar.actualUrl)) {
104- return "reload"
105- } else if (internal.looksLikeAUrl(addressbar.text.trim())) {
106- return "stock_website"
107- } else {
108- return "search"
109- }
110- default:
111- if (!favicon.visible) {
112- if (internal.looksLikeAUrl(addressbar.text.trim())) {
113- return "stock_website"
114- } else {
115- return "search"
116- }
117- } else {
118- return ""
119- }
120- }
121- }
122+ anchors {
123+ fill: parent
124+ margins: -units.gu(1)
125 }
126
127 onClicked: {
128- switch (actionIcon.name) {
129- case "":
130- break
131- case "stop":
132+ if (action.loading) {
133 addressbar.requestStop()
134- break
135- case "reload":
136+ } else if (action.reload) {
137 addressbar.requestReload()
138- break
139- default:
140+ } else {
141 textField.accepted()
142 }
143 }
144 }
145 }
146
147- Item {
148- id: securityDisplay
149- height: textField.height
150- width: securityIcon.width
151- visible: internal.secureConnection && (addressbar.state == "")
152-
153- Icon {
154- id: securityIcon
155- anchors.centerIn: parent
156- height: parent.height - units.gu(2)
157- width: height
158- name: "network-secure"
159- }
160- }
161-
162- Item {
163- height: textField.height
164- width: warningIcon.width
165- visible: internal.securityWarning && (addressbar.state == "")
166-
167- Icon {
168- id: warningIcon
169- anchors.centerIn: parent
170- height: parent.height - units.gu(2)
171- width: height
172- name: "security-alert"
173- }
174- }
175+ Icon {
176+ name: "network-secure"
177+ height: parent.height
178+ width: height
179+ visible: (addressbar.state == "") && internal.secureConnection
180+ }
181+
182+ Image {
183+ source: "assets/broken_lock.png"
184+ height: parent.height
185+ fillMode: Image.PreserveAspectFit
186+ visible: (addressbar.state == "") && internal.securityError
187+ }
188+
189+ Icon {
190+ name: "security-alert"
191+ height: parent.height
192+ width: height
193+ visible: (addressbar.state == "") && internal.securityWarning
194+ }
195+ }
196+
197+ Item {
198+ id: certificatePopoverPositioner
199+ anchors {
200+ top: iconsRow.top
201+ bottom: iconsRow.bottom
202+ left: iconsRow.left
203+ }
204+ width: units.gu(2)
205 }
206
207 MouseArea {
208- enabled: securityDisplay.visible && addressbar.state != "editing" && addressbar.state != "loading"
209- anchors.fill: parent
210+ enabled: addressbar.state == ""
211+ anchors {
212+ left: iconsRow.left
213+ leftMargin: -units.gu(1)
214+ right: iconsRow.right
215+ verticalCenter: parent.verticalCenter
216+ }
217+ height: textField.height
218
219- onClicked: addressbar.showSecurityCertificateDetails()
220+ onClicked: {
221+ if (internal.secureConnection || internal.securityError) {
222+ addressbar.showSecurityCertificateDetails()
223+ }
224+ }
225 }
226 }
227
228@@ -226,8 +227,8 @@
229 MouseArea {
230 anchors {
231 fill: parent
232- leftMargin: iconsRow.width
233- rightMargin: bookmarkButton.width
234+ leftMargin: icons.width
235+ rightMargin: bookmarkToggle.width
236 }
237 visible: !textField.activeFocus
238 onClicked: {
239@@ -243,6 +244,7 @@
240 readonly property int securityLevel: addressbar.securityStatus ? addressbar.securityStatus.securityLevel : Oxide.SecurityStatus.SecurityLevelNone
241 readonly property bool secureConnection: addressbar.securityStatus ? (securityLevel == Oxide.SecurityStatus.SecurityLevelSecure || securityLevel == Oxide.SecurityStatus.SecurityLevelSecureEV || securityLevel == Oxide.SecurityStatus.SecurityLevelWarning) : false
242 readonly property bool securityWarning: addressbar.securityStatus ? (securityLevel == Oxide.SecurityStatus.SecurityLevelWarning) : false
243+ readonly property bool securityError: addressbar.securityStatus ? (securityLevel == Oxide.SecurityStatus.SecurityLevelError) : false
244
245 property var securityCertificateDetails: null
246
247
248=== modified file 'src/app/webbrowser/Chrome.qml'
249--- src/app/webbrowser/Chrome.qml 2014-12-12 09:48:34 +0000
250+++ src/app/webbrowser/Chrome.qml 2015-01-21 15:39:32 +0000
251@@ -1,5 +1,5 @@
252 /*
253- * Copyright 2013-2014 Canonical Ltd.
254+ * Copyright 2013-2015 Canonical Ltd.
255 *
256 * This file is part of webbrowser-app.
257 *
258@@ -98,7 +98,7 @@
259 verticalCenter: parent.verticalCenter
260 }
261
262- icon: chrome.webview ? chrome.webview.icon : ""
263+ icon: (chrome.webview && !chrome.webview.certificateError) ? chrome.webview.icon : ""
264
265 loading: chrome.webview ?
266 chrome.webview.loading
267
268=== modified file 'src/app/webbrowser/SecurityCertificatePopover.qml'
269--- src/app/webbrowser/SecurityCertificatePopover.qml 2014-11-11 11:48:10 +0000
270+++ src/app/webbrowser/SecurityCertificatePopover.qml 2015-01-21 15:39:32 +0000
271@@ -1,5 +1,5 @@
272 /*
273- * Copyright 2014 Canonical Ltd.
274+ * Copyright 2014-2015 Canonical Ltd.
275 *
276 * This file is part of webbrowser-app.
277 *
278@@ -27,6 +27,9 @@
279
280 property var securityStatus
281
282+ readonly property bool isWarning: securityStatus.securityLevel == Oxide.SecurityStatus.SecurityLevelWarning
283+ readonly property bool isError: securityStatus.securityLevel == Oxide.SecurityStatus.SecurityLevelError
284+
285 Column {
286 width: parent.width - units.gu(4)
287 anchors.horizontalCenter: parent.horizontalCenter
288@@ -39,7 +42,7 @@
289
290 Column {
291 width: parent.width
292- visible: securityStatus.securityLevel == Oxide.SecurityStatus.SecurityLevelWarning
293+ visible: certificatePopover.isWarning || certificatePopover.isError
294 spacing: units.gu(0.5)
295
296 Row {
297@@ -47,16 +50,60 @@
298 spacing: units.gu(0.5)
299
300 Icon {
301+ id: alertIcon
302 name: "security-alert"
303 height: units.gu(2)
304 width: height
305 }
306
307- Label {
308- width: parent.width
309- wrapMode: Text.WordWrap
310- text: i18n.tr("This site has insecure content")
311- fontSize: "x-small"
312+ Column {
313+ width: parent.width - alertIcon.width - parent.spacing
314+ height: childrenRect.height
315+ spacing: units.gu(0.5)
316+
317+ Label {
318+ width: parent.width
319+ wrapMode: Text.WordWrap
320+ fontSize: "x-small"
321+ text: certificatePopover.isWarning ?
322+ i18n.tr("This site has insecure content") :
323+ i18n.tr("Identity Not Verified")
324+ }
325+
326+ Label {
327+ width: parent.width
328+ wrapMode: Text.WordWrap
329+ visible: certificatePopover.isError
330+ fontSize: "x-small"
331+ text: i18n.tr("The identity of this website has not been verified.")
332+ }
333+
334+ Label {
335+ width: parent.width
336+ wrapMode: Text.WordWrap
337+ visible: certificatePopover.isError
338+ fontSize: "x-small"
339+ text: {
340+ switch (securityStatus.certStatus) {
341+ case Oxide.SecurityStatus.CertStatusBadIdentity:
342+ return i18n.tr("Server certificate does not match the identity of the site.")
343+ case Oxide.SecurityStatus.CertStatusExpired:
344+ return i18n.tr("Server certificate has expired.")
345+ case Oxide.SecurityStatus.CertStatusDateInvalid:
346+ return i18n.tr("Server certificate contains invalid dates.")
347+ case Oxide.SecurityStatus.CertStatusAuthorityInvalid:
348+ return i18n.tr("Server certificate is issued by an entity that is not trusted.")
349+ case Oxide.SecurityStatus.CertStatusRevoked:
350+ return i18n.tr("Server certificate has been revoked.")
351+ case Oxide.SecurityStatus.CertStatusInvalid:
352+ return i18n.tr("Server certificate is invalid.")
353+ case Oxide.SecurityStatus.CertStatusInsecure:
354+ return i18n.tr("Server certificate is insecure.")
355+ default:
356+ return i18n.tr("Server certificate failed our security checks for an unknown reason.")
357+ }
358+ }
359+ }
360 }
361 }
362
363@@ -64,76 +111,83 @@
364 width: parent.width
365 anchors.leftMargin: 0
366 anchors.rightMargin: 0
367- }
368- }
369-
370- Label {
371- width: parent.width
372- wrapMode: Text.WordWrap
373- text: i18n.tr("You are connected to")
374- fontSize: "x-small"
375- }
376-
377- Label {
378- width: parent.width
379- wrapMode: Text.WordWrap
380- text: securityStatus.certificate.subjectDisplayName
381- fontSize: "x-small"
382- }
383-
384- ThinDivider {
385- width: parent.width
386- anchors.leftMargin: 0
387- anchors.rightMargin: 0
388- visible: orgName.visible || localityName.visible || stateName.visible || countryName.visible
389- }
390-
391- Label {
392- width: parent.width
393- wrapMode: Text.WordWrap
394- visible: orgName.visible
395- text: i18n.tr("Which is run by")
396- fontSize: "x-small"
397- }
398-
399- Label {
400- id: orgName
401- width: parent.width
402- wrapMode: Text.WordWrap
403- visible: text.length > 0
404- text: securityStatus.certificate.getSubjectInfo(Oxide.SslCertificate.PrincipalAttrOrganizationName).join(", ")
405- fontSize: "x-small"
406- }
407-
408- Label {
409- id: localityName
410- width: parent.width
411- wrapMode: Text.WordWrap
412- visible: text.length > 0
413- text: securityStatus.certificate.getSubjectInfo(Oxide.SslCertificate.PrincipalAttrLocalityName).join(", ")
414- fontSize: "x-small"
415- }
416-
417- Label {
418- id: stateName
419- width: parent.width
420- wrapMode: Text.WordWrap
421- visible: text.length > 0
422- text: securityStatus.certificate.getSubjectInfo(Oxide.SslCertificate.PrincipalAttrStateOrProvinceName).join(", ")
423- fontSize: "x-small"
424- }
425-
426- Label {
427- id: countryName
428- width: parent.width
429- wrapMode: Text.WordWrap
430- visible: text.length > 0
431- text: securityStatus.certificate.getSubjectInfo(Oxide.SslCertificate.PrincipalAttrCountryName).join(", ")
432- fontSize: "x-small"
433+ visible: !certificatePopover.isError
434+ }
435+ }
436+
437+ Column {
438+ width: parent.width
439+ spacing: units.gu(0.5)
440+ visible: !certificatePopover.isError
441+
442+ Label {
443+ width: parent.width
444+ wrapMode: Text.WordWrap
445+ text: i18n.tr("You are connected to")
446+ fontSize: "x-small"
447+ }
448+
449+ Label {
450+ width: parent.width
451+ wrapMode: Text.WordWrap
452+ text: securityStatus.certificate.subjectDisplayName
453+ fontSize: "x-small"
454+ }
455+
456+ ThinDivider {
457+ width: parent.width
458+ anchors.leftMargin: 0
459+ anchors.rightMargin: 0
460+ visible: orgName.visible || localityName.visible || stateName.visible || countryName.visible
461+ }
462+
463+ Label {
464+ width: parent.width
465+ wrapMode: Text.WordWrap
466+ visible: orgName.visible
467+ text: i18n.tr("Which is run by")
468+ fontSize: "x-small"
469+ }
470+
471+ Label {
472+ id: orgName
473+ width: parent.width
474+ wrapMode: Text.WordWrap
475+ visible: text.length > 0
476+ text: securityStatus.certificate.getSubjectInfo(Oxide.SslCertificate.PrincipalAttrOrganizationName).join(", ")
477+ fontSize: "x-small"
478+ }
479+
480+ Label {
481+ id: localityName
482+ width: parent.width
483+ wrapMode: Text.WordWrap
484+ visible: text.length > 0
485+ text: securityStatus.certificate.getSubjectInfo(Oxide.SslCertificate.PrincipalAttrLocalityName).join(", ")
486+ fontSize: "x-small"
487+ }
488+
489+ Label {
490+ id: stateName
491+ width: parent.width
492+ wrapMode: Text.WordWrap
493+ visible: text.length > 0
494+ text: securityStatus.certificate.getSubjectInfo(Oxide.SslCertificate.PrincipalAttrStateOrProvinceName).join(", ")
495+ fontSize: "x-small"
496+ }
497+
498+ Label {
499+ id: countryName
500+ width: parent.width
501+ wrapMode: Text.WordWrap
502+ visible: text.length > 0
503+ text: securityStatus.certificate.getSubjectInfo(Oxide.SslCertificate.PrincipalAttrCountryName).join(", ")
504+ fontSize: "x-small"
505+ }
506 }
507
508 Item {
509- height: units.gu(1.5)
510+ height: units.gu(1)
511 width: parent.width
512 }
513 }
514
515=== added file 'src/app/webbrowser/assets/broken_lock@27.png'
516Binary files src/app/webbrowser/assets/broken_lock@27.png 1970-01-01 00:00:00 +0000 and src/app/webbrowser/assets/broken_lock@27.png 2015-01-21 15:39:32 +0000 differ

Subscribers

People subscribed via source and target branches

to status/vote changes: