Merge lp:~michael-sheldon/webbrowser-app/ssl-status into lp:webbrowser-app

Proposed by Michael Sheldon
Status: Merged
Approved by: Olivier Tilloy
Approved revision: 731
Merged at revision: 718
Proposed branch: lp:~michael-sheldon/webbrowser-app/ssl-status
Merge into: lp:webbrowser-app
Diff against target: 874 lines (+658/-70)
6 files modified
po/webbrowser-app.pot (+168/-11)
src/app/InvalidCertificateErrorSheet.qml (+215/-0)
src/app/WebViewImpl.qml (+11/-0)
src/app/webbrowser/AddressBar.qml (+245/-59)
src/app/webbrowser/Browser.qml (+18/-0)
src/app/webbrowser/Chrome.qml (+1/-0)
To merge this branch: bzr merge lp:~michael-sheldon/webbrowser-app/ssl-status
Reviewer Review Type Date Requested Status
PS Jenkins bot continuous-integration Needs Fixing
Olivier Tilloy Approve
Review via email: mp+235309@code.launchpad.net

Commit message

* Display padlock when viewing pages over HTTPS.
* Provide certificate details when padlock is clicked.
* Display error pages when invalid SSL certificates are presented and allow users to override these warnings.
* Display warning symbol when insecure content is loaded over HTTPS (currently incorrect icon, should be updated when dialog-warning-symbol lands in ubuntu-theme).

Description of the change

* Display padlock when viewing pages over HTTPS.
* Provide certificate details when padlock is clicked.
* Display error pages when invalid SSL certificates are presented and allow users to override these warnings.
* Display warning symbol when insecure content is loaded over HTTPS (currently incorrect icon, should be updated when dialog-warning-symbol lands in ubuntu-theme).

To post a comment you must log in.
Revision history for this message
PS Jenkins bot (ps-jenkins) wrote :
review: Approve (continuous-integration)
Revision history for this message
Olivier Tilloy (osomon) wrote :

I don’t see changes to the translation template, despite the new strings. Is that on purpose (i.e. planning to update the file and push to trunk directly after landing)?
So far we’ve been merging translation template updates along with the corresponding code changes, and dealing with conflicts on a case-by-case basis, but I’m open to revising this approach.

Revision history for this message
Olivier Tilloy (osomon) wrote :

6 + * Copyright 2013-2014 Canonical Ltd.

This should probably be only copyright 2014.

722. By Michael Sheldon

Fix copyright statement

723. By Michael Sheldon

Update translation template

Revision history for this message
Michael Sheldon (michael-sheldon) wrote :

Here are a few sites that can be used to test some different SSL failure conditions:

Expired certificate: https://testssl-expire.disig.sk/
Bad Identity (only valid for https://www.halifax.co.uk): https://halifax.co.uk
Mix of secure/insecure content: https://www.bennish.net/mixed-content.html
Dynamic mix of secure/insecure content (secure until play is pressed on a track): https://m.7digital.com/GB/releases/1530991
Revoked EV certificate (will cause a crash due to bug 1371569 until the next oxide release): https://test-sspev.verisign.com:2443/test-SSPEV-revoked-verisign.html

Revision history for this message
Olivier Tilloy (osomon) wrote :

I don’t think this is explicitly mentioned in the spec, but I think it would be nice to enable tap on the certificate details popover to dismiss it.

Revision history for this message
Olivier Tilloy (osomon) wrote :

There seems to be a regression in what the address bar displays, probably not introduced by this MR (maybe by http://bazaar.launchpad.net/~phablet-team/webbrowser-app/trunk/revision/710), which becomes very visible when trying to browse a site with an invalid security certificate: browse to any site, wait for it to fully load, then tap on the address bar and try to browse to e.g. https://www.pcwebshop.co.uk/ : you’re presented with the security warning page, but the shortened address in the address bar is that of the previously browsed site.

We might want to address this issue as part of this MR, considering that it makes it much more visible to the user.

Revision history for this message
Olivier Tilloy (osomon) wrote :

If I browse to a site with an invalid security certificate (e.g. https://www.pcwebshop.co.uk/) and choose to proceed anyway, despite the security warning, the site is loaded but there is no visual feedback in the address bar, there should probably be a broken padlock icon or something similar. Anyway, this is something we need to discuss with design.

Revision history for this message
PS Jenkins bot (ps-jenkins) wrote :
review: Approve (continuous-integration)
Revision history for this message
Olivier Tilloy (osomon) wrote :

On the invalid security certificate warning page, the "proceed anyway" and "back to safety" button are pretty narrow, translations in many languages that are more verbose than English won’t fit, and they will end up ellipsized. E.g. in French:

    "Poursuivre quand même" → "Poursuivre qu…"
    "Retour à la sécurité" → "Retour à la séc…"

And the buttons are not resized when changing the orientation of the device to landscape, even though there is more space available. Let’s request design to comment, and in the meantime I would put the two buttons in a column and not constrain their width to ensure the text fits.

Revision history for this message
Olivier Tilloy (osomon) wrote :

It looks like the dates in the details of the security certificate warning page are incorrectly formatted (or maybe incorrectly exposed by oxide?). For https://testssl-expire.disig.sk/ I’m seeing an expiry date of "jeu. juil. 23 15:17:38 2381 GMT+0100". The year looks incorrect (and the formatting too, for a date localized in French, but I guess that’s a separate issue).

Revision history for this message
Olivier Tilloy (osomon) wrote :

> On the invalid security certificate warning page, the "proceed anyway" and
> "back to safety" button are pretty narrow, translations in many languages that
> are more verbose than English won’t fit, and they will end up ellipsized. E.g.
> in French:

A screenshot taken on my krillin to illustrate the issue: http://people.canonical.com/~osomon/security-certificate-warning.png

Revision history for this message
Olivier Tilloy (osomon) wrote :

408 + // TRANSLATORS: %1 refers to the SSL certificate's start date

Copy/paste error, this should read "expiry date".

review: Needs Fixing
Revision history for this message
Olivier Tilloy (osomon) wrote :

Some sentences in the invalid certificate warning page are missing a full stop at the end:

    "This site security certificate is not trusted"

    "You should not proceed, especially if you have never seen this warning before for this site"

Revision history for this message
Olivier Tilloy (osomon) wrote :

    "This site security certificate is not trusted\n…"

The above is repeated in a number of situations, would it be worth making it a separate string in its own label, to save translators some work?

Revision history for this message
Olivier Tilloy (osomon) wrote :

486 + console.log("Switch failed")

is this really needed?

Revision history for this message
Olivier Tilloy (osomon) wrote :

285 + target: certificateError ? certificateError : null

isn’t this equivalent to:

    target: certificateError

724. By Michael Sheldon

Place buttons in column and don't restrict their width

725. By Michael Sheldon

Add missing full stops from certificate error

726. By Michael Sheldon

Remove stray debug statement

727. By Michael Sheldon

Fix incorrect translator hint

Revision history for this message
Olivier Tilloy (osomon) wrote :

365 + onTextChanged: {
366 + // Remove any blank lines caused by missing entries
367 + while(subjectAddress.text.indexOf("\n\n") != -1) {
368 + subjectAddress.text = subjectAddress.text.replace("\n\n", "\n")
369 + }
370 + }

Wouldn’t it be much easier to just do that where 'text' is assigned:

    text: i18n.tr("[…]").arg([…]).replace(/\n\n/g, "\n")

728. By Michael Sheldon

Use locale based date display in certificate errors

729. By Michael Sheldon

Dismiss certificate popover when clicked

Revision history for this message
Michael Sheldon (michael-sheldon) wrote :

> 285 + target: certificateError ? certificateError : null
>
> isn’t this equivalent to:
>
> target: certificateError

 This would cause a warning due to the certificateError being undefined on start up (whereas explicitly setting a null target won't).

Revision history for this message
Olivier Tilloy (osomon) wrote :

> > 285 + target: certificateError ? certificateError : null
> >
> > isn’t this equivalent to:
> >
> > target: certificateError
>
> This would cause a warning due to the certificateError being undefined on
> start up (whereas explicitly setting a null target won't).

Ah, ok. I would have expected it to be 'null' rather than 'undefined'. The conditional makes sense then.

Revision history for this message
Michael Sheldon (michael-sheldon) wrote :

I've switched the dates to using the locale date, the incorrect year is a bug in oxide which is being tracked here: https://bugs.launchpad.net/oxide/+bug/1372414

730. By Michael Sheldon

Simplify removal of extra whitespace in certificate addresses

Revision history for this message
Michael Sheldon (michael-sheldon) wrote :

> 365 + onTextChanged: {
> 366 + // Remove any blank lines caused by missing
> entries
> 367 + while(subjectAddress.text.indexOf("\n\n") !=
> -1) {
> 368 + subjectAddress.text =
> subjectAddress.text.replace("\n\n", "\n")
> 369 + }
> 370 + }
>
> Wouldn’t it be much easier to just do that where 'text' is assigned:
>
> text: i18n.tr("[…]").arg([…]).replace(/\n\n/g, "\n")

Yeah, the problem with that was that since it was only a single pass it could leave extra white space when there'd been three blank lines. But I just realised I could match against /\n+/g to fix that, so I've committed a tidier implementation now.

Revision history for this message
PS Jenkins bot (ps-jenkins) wrote :
review: Approve (continuous-integration)
731. By Michael Sheldon

Avoid duplication of string on SSL certificate error page

Revision history for this message
Olivier Tilloy (osomon) wrote :

It all looks good to me now. Thanks!

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

FAILED: Continuous integration, rev:731
http://jenkins.qa.ubuntu.com/job/webbrowser-app-ci/1096/
Executed test runs:
    FAILURE: http://jenkins.qa.ubuntu.com/job/generic-deb-autopilot-utopic-touch/5055/console
    SUCCESS: http://jenkins.qa.ubuntu.com/job/generic-mediumtests-utopic/3691
    SUCCESS: http://jenkins.qa.ubuntu.com/job/webbrowser-app-utopic-amd64-ci/295
    SUCCESS: http://jenkins.qa.ubuntu.com/job/webbrowser-app-utopic-armhf-ci/295
        deb: http://jenkins.qa.ubuntu.com/job/webbrowser-app-utopic-armhf-ci/295/artifact/work/output/*zip*/output.zip
    SUCCESS: http://jenkins.qa.ubuntu.com/job/webbrowser-app-utopic-i386-ci/295
    FAILURE: http://jenkins.qa.ubuntu.com/job/generic-deb-autopilot-runner-mako/4805/console
    SUCCESS: http://jenkins.qa.ubuntu.com/job/generic-mediumtests-builder-utopic-armhf/6307
        deb: http://jenkins.qa.ubuntu.com/job/generic-mediumtests-builder-utopic-armhf/6307/artifact/work/output/*zip*/output.zip
    SUCCESS: http://s-jenkins.ubuntu-ci:8080/job/touch-flash-device/13545
    SUCCESS: http://jenkins.qa.ubuntu.com/job/autopilot-testrunner-otto-utopic/3084
    SUCCESS: http://jenkins.qa.ubuntu.com/job/generic-mediumtests-builder-utopic-amd64/4000
        deb: http://jenkins.qa.ubuntu.com/job/generic-mediumtests-builder-utopic-amd64/4000/artifact/work/output/*zip*/output.zip

Click here to trigger a rebuild:
http://s-jenkins.ubuntu-ci:8080/job/webbrowser-app-ci/1096/rebuild

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

FAILED: Continuous integration, rev:731
http://jenkins.qa.ubuntu.com/job/webbrowser-app-ci/1097/
Executed test runs:
    FAILURE: http://jenkins.qa.ubuntu.com/job/generic-deb-autopilot-utopic-touch/5060/console
    SUCCESS: http://jenkins.qa.ubuntu.com/job/generic-mediumtests-utopic/3694
    SUCCESS: http://jenkins.qa.ubuntu.com/job/webbrowser-app-utopic-amd64-ci/296
    SUCCESS: http://jenkins.qa.ubuntu.com/job/webbrowser-app-utopic-armhf-ci/296
        deb: http://jenkins.qa.ubuntu.com/job/webbrowser-app-utopic-armhf-ci/296/artifact/work/output/*zip*/output.zip
    SUCCESS: http://jenkins.qa.ubuntu.com/job/webbrowser-app-utopic-i386-ci/296
    FAILURE: http://jenkins.qa.ubuntu.com/job/generic-deb-autopilot-runner-mako/4808/console
    SUCCESS: http://jenkins.qa.ubuntu.com/job/generic-mediumtests-builder-utopic-armhf/6312
        deb: http://jenkins.qa.ubuntu.com/job/generic-mediumtests-builder-utopic-armhf/6312/artifact/work/output/*zip*/output.zip
    SUCCESS: http://s-jenkins.ubuntu-ci:8080/job/touch-flash-device/13549
    SUCCESS: http://jenkins.qa.ubuntu.com/job/autopilot-testrunner-otto-utopic/3086
    SUCCESS: http://jenkins.qa.ubuntu.com/job/generic-mediumtests-builder-utopic-amd64/4003
        deb: http://jenkins.qa.ubuntu.com/job/generic-mediumtests-builder-utopic-amd64/4003/artifact/work/output/*zip*/output.zip

Click here to trigger a rebuild:
http://s-jenkins.ubuntu-ci:8080/job/webbrowser-app-ci/1097/rebuild

review: Needs Fixing (continuous-integration)

Preview Diff

[H/L] Next/Prev Comment, [J/K] Next/Prev File, [N/P] Next/Prev Hunk
=== modified file 'po/webbrowser-app.pot'
--- po/webbrowser-app.pot 2014-08-21 11:28:58 +0000
+++ po/webbrowser-app.pot 2014-09-22 14:01:07 +0000
@@ -8,7 +8,7 @@
8msgstr ""8msgstr ""
9"Project-Id-Version: webbrowser-app\n"9"Project-Id-Version: webbrowser-app\n"
10"Report-Msgid-Bugs-To: \n"10"Report-Msgid-Bugs-To: \n"
11"POT-Creation-Date: 2014-08-21 13:27+0200\n"11"POT-Creation-Date: 2014-09-22 14:59+0100\n"
12"PO-Revision-Date: YEAR-MO-DA HO:MI+ZONE\n"12"PO-Revision-Date: YEAR-MO-DA HO:MI+ZONE\n"
13"Last-Translator: FULL NAME <EMAIL@ADDRESS>\n"13"Last-Translator: FULL NAME <EMAIL@ADDRESS>\n"
14"Language-Team: LANGUAGE <LL@li.org>\n"14"Language-Team: LANGUAGE <LL@li.org>\n"
@@ -75,10 +75,12 @@
75msgstr ""75msgstr ""
7676
77#: src/app/CertificateVerificationDialog.qml:2977#: src/app/CertificateVerificationDialog.qml:29
78#: src/app/InvalidCertificateErrorSheet.qml:162
78msgid "Proceed anyway"79msgid "Proceed anyway"
79msgstr ""80msgstr ""
8081
81#: src/app/CertificateVerificationDialog.qml:3582#: src/app/CertificateVerificationDialog.qml:35
83#: src/app/InvalidCertificateErrorSheet.qml:175
82msgid "Back to safety"84msgid "Back to safety"
83msgstr ""85msgstr ""
8486
@@ -129,6 +131,149 @@
129msgid "Allow"131msgid "Allow"
130msgstr ""132msgstr ""
131133
134#: src/app/InvalidCertificateErrorSheet.qml:58
135msgid "This site security certificate is not trusted.\n"
136msgstr ""
137
138#: src/app/InvalidCertificateErrorSheet.qml:66
139msgid "Learn more"
140msgstr ""
141
142#. TRANSLATORS: %1 refers to the SSL certificate's serial number
143#: src/app/InvalidCertificateErrorSheet.qml:90
144#, qt-format
145msgid ""
146"Serial number:\n"
147"%1"
148msgstr ""
149
150#. TRANSLATORS: %1 refers to the SSL certificate's subject display name
151#: src/app/InvalidCertificateErrorSheet.qml:97
152#, qt-format
153msgid ""
154"Subject:\n"
155"%1"
156msgstr ""
157
158#. TRANSLATORS: %1 refers to the SSL certificate's subject's address
159#: src/app/InvalidCertificateErrorSheet.qml:105
160#, qt-format
161msgid ""
162"Subject address:\n"
163"%1"
164msgstr ""
165
166#. TRANSLATORS: %1 refers to the SSL certificate's issuer display name
167#: src/app/InvalidCertificateErrorSheet.qml:116
168#, qt-format
169msgid ""
170"Issuer:\n"
171"%1"
172msgstr ""
173
174#. TRANSLATORS: %1 refers to the SSL certificate's issuer's address
175#: src/app/InvalidCertificateErrorSheet.qml:124
176#, qt-format
177msgid ""
178"Issuer address:\n"
179"%1"
180msgstr ""
181
182#. TRANSLATORS: %1 refers to the SSL certificate's start date
183#: src/app/InvalidCertificateErrorSheet.qml:135
184#, qt-format
185msgid ""
186"Valid from:\n"
187"%1"
188msgstr ""
189
190#. TRANSLATORS: %1 refers to the SSL certificate's expiry date
191#: src/app/InvalidCertificateErrorSheet.qml:142
192#, qt-format
193msgid ""
194"Valid until:\n"
195"%1"
196msgstr ""
197
198#. TRANSLATORS: %1 refers to the SSL certificate's SHA1 fingerprint
199#: src/app/InvalidCertificateErrorSheet.qml:149
200#, qt-format
201msgid ""
202"Fingerprint (SHA1):\n"
203"%1"
204msgstr ""
205
206#: src/app/InvalidCertificateErrorSheet.qml:155
207msgid ""
208"You should not proceed, especially if you have never seen this warning "
209"before for this site."
210msgstr ""
211
212#. TRANSLATORS: %1 refers to the domain name of the SSL certificate
213#: src/app/InvalidCertificateErrorSheet.qml:190
214#, qt-format
215msgid ""
216"You attempted to reach %1 but the server presented a security certificate "
217"which does not match the identity of the site."
218msgstr ""
219
220#. TRANSLATORS: %1 refers to the domain name of the SSL certificate
221#: src/app/InvalidCertificateErrorSheet.qml:193
222#, qt-format
223msgid ""
224"You attempted to reach %1 but the server presented a security certificate "
225"which has expired."
226msgstr ""
227
228#. TRANSLATORS: %1 refers to the domain name of the SSL certificate
229#: src/app/InvalidCertificateErrorSheet.qml:196
230#, qt-format
231msgid ""
232"You attempted to reach %1 but the server presented a security certificate "
233"which contains invalid dates."
234msgstr ""
235
236#. TRANSLATORS: %1 refers to the domain name of the SSL certificate
237#: src/app/InvalidCertificateErrorSheet.qml:199
238#, qt-format
239msgid ""
240"You attempted to reach %1 but the server presented a security certificate "
241"issued by an entity that is not trusted."
242msgstr ""
243
244#. TRANSLATORS: %1 refers to the domain name of the SSL certificate
245#: src/app/InvalidCertificateErrorSheet.qml:202
246#, qt-format
247msgid ""
248"You attempted to reach %1 but the server presented a security certificate "
249"that has been revoked."
250msgstr ""
251
252#. TRANSLATORS: %1 refers to the domain name of the SSL certificate
253#: src/app/InvalidCertificateErrorSheet.qml:205
254#, qt-format
255msgid ""
256"You attempted to reach %1 but the server presented an invalid security "
257"certificate."
258msgstr ""
259
260#. TRANSLATORS: %1 refers to the domain name of the SSL certificate
261#: src/app/InvalidCertificateErrorSheet.qml:208
262#, qt-format
263msgid ""
264"You attempted to reach %1 but the server presented an insecure security "
265"certificate."
266msgstr ""
267
268#. TRANSLATORS: %1 refers to the domain name of the SSL certificate
269#: src/app/InvalidCertificateErrorSheet.qml:211
270#, qt-format
271msgid ""
272"This site security certificate is not trusted\n"
273"You attempted to reach %1 but the server presented a security certificate "
274"which failed our security checks for an unknown reason."
275msgstr ""
276
132#: src/app/PromptDialog.qml:23277#: src/app/PromptDialog.qml:23
133msgid "JavaScript Prompt"278msgid "JavaScript Prompt"
134msgstr ""279msgstr ""
@@ -245,23 +390,35 @@
245msgid "Share…"390msgid "Share…"
246msgstr ""391msgstr ""
247392
248#: src/app/webbrowser/AddressBar.qml:148393#: src/app/webbrowser/AddressBar.qml:214
394msgid "This site has insecure content"
395msgstr ""
396
397#: src/app/webbrowser/AddressBar.qml:229
398msgid "You are connected to"
399msgstr ""
400
401#: src/app/webbrowser/AddressBar.qml:251
402msgid "Which is run by"
403msgstr ""
404
405#: src/app/webbrowser/AddressBar.qml:335
249msgid "search or enter an address"406msgid "search or enter an address"
250msgstr ""407msgstr ""
251408
252#: src/app/webbrowser/Browser.qml:154409#: src/app/webbrowser/Browser.qml:179
253msgid "Share"410msgid "Share"
254msgstr ""411msgstr ""
255412
256#: src/app/webbrowser/Browser.qml:168413#: src/app/webbrowser/Browser.qml:193
257msgid "History"414msgid "History"
258msgstr ""415msgstr ""
259416
260#: src/app/webbrowser/Browser.qml:174417#: src/app/webbrowser/Browser.qml:200
261msgid "Open tabs"418msgid "Open tabs"
262msgstr ""419msgstr ""
263420
264#: src/app/webbrowser/Browser.qml:180 src/app/webbrowser/TabsView.qml:57421#: src/app/webbrowser/Browser.qml:206 src/app/webbrowser/TabsView.qml:57
265msgid "New tab"422msgid "New tab"
266msgstr ""423msgstr ""
267424
@@ -330,25 +487,25 @@
330487
331#. TRANSLATORS: %1 refers to the current page’s title488#. TRANSLATORS: %1 refers to the current page’s title
332#: src/app/webbrowser/webbrowser-app.qml:39489#: src/app/webbrowser/webbrowser-app.qml:39
333#: src/app/webcontainer/webapp-container.qml:57490#: src/app/webcontainer/webapp-container.qml:60
334#, qt-format491#, qt-format
335msgid "%1 - Ubuntu Web Browser"492msgid "%1 - Ubuntu Web Browser"
336msgstr ""493msgstr ""
337494
338#: src/app/webbrowser/webbrowser-app.qml:41495#: src/app/webbrowser/webbrowser-app.qml:41
339#: src/app/webcontainer/webapp-container.qml:59496#: src/app/webcontainer/webapp-container.qml:62
340msgid "Ubuntu Web Browser"497msgid "Ubuntu Web Browser"
341msgstr ""498msgstr ""
342499
343#: src/app/webcontainer/AccountsLoginPage.qml:70500#: src/app/webcontainer/AccountsLoginPage.qml:87
344msgid "No local account found for "501msgid "No local account found for "
345msgstr ""502msgstr ""
346503
347#: src/app/webcontainer/AccountsLoginPage.qml:75504#: src/app/webcontainer/AccountsLoginPage.qml:92
348msgid "Skip account creation step"505msgid "Skip account creation step"
349msgstr ""506msgstr ""
350507
351#: src/app/webcontainer/AccountsLoginPage.qml:124508#: src/app/webcontainer/AccountsLoginPage.qml:141
352msgid "Add account"509msgid "Add account"
353msgstr ""510msgstr ""
354511
355512
=== added file 'src/app/InvalidCertificateErrorSheet.qml'
--- src/app/InvalidCertificateErrorSheet.qml 1970-01-01 00:00:00 +0000
+++ src/app/InvalidCertificateErrorSheet.qml 2014-09-22 14:01:07 +0000
@@ -0,0 +1,215 @@
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 QtQuick 2.0
20import Ubuntu.Components 1.1
21import com.canonical.Oxide 1.0 as Oxide
22
23Rectangle {
24 property var certificateError
25
26 signal allowed()
27 signal denied()
28
29 Connections {
30 target: certificateError ? certificateError : null
31 onCancelled: {
32 moreInfo.visible = false
33 denied()
34 }
35 }
36
37 Flickable {
38 anchors.fill: parent
39 anchors.margins: units.gu(4)
40 contentHeight: errorCol.height
41
42 Column {
43 id: errorCol
44 anchors.centerIn: parent
45 width: parent.width
46
47 spacing: units.gu(3)
48
49 Icon {
50 anchors.horizontalCenter: parent.horizontalCenter
51 name: "security-alert"
52 width: units.gu(4)
53 height: width
54 }
55
56 Label {
57 width: parent.width
58 text: certificateError ? i18n.tr("This site security certificate is not trusted.\n") + textForError(certificateError.certError) : ""
59 wrapMode: Text.Wrap
60 horizontalAlignment: Text.AlignHCenter
61 fontSize: "x-small"
62 }
63
64 Label {
65 width: parent.width
66 text: i18n.tr("Learn more")
67 font.underline: true
68 fontSize: "x-small"
69 horizontalAlignment: Text.AlignHCenter
70 visible: !moreInfo.visible
71 MouseArea {
72 anchors.fill: parent
73 onClicked: {
74 moreInfo.visible = true
75 }
76 }
77 }
78
79 Column {
80 id: moreInfo
81 width: parent.width
82 visible: false
83 spacing: units.gu(1)
84
85 Label {
86 fontSize: "x-small"
87 width: parent.width
88 wrapMode: Text.Wrap
89 // TRANSLATORS: %1 refers to the SSL certificate's serial number
90 text: i18n.tr("Serial number:\n%1").arg(certificateError ? certificateError.certificate.serialNumber : "")
91 }
92 Label {
93 fontSize: "x-small"
94 width: parent.width
95 wrapMode: Text.Wrap
96 // TRANSLATORS: %1 refers to the SSL certificate's subject display name
97 text: i18n.tr("Subject:\n%1").arg(certificateError ? certificateError.certificate.subjectDisplayName : "")
98 }
99 Label {
100 id: subjectAddress
101 fontSize: "x-small"
102 width: parent.width
103 wrapMode: Text.Wrap
104 // TRANSLATORS: %1 refers to the SSL certificate's subject's address
105 text: i18n.tr("Subject address:\n%1").arg(certificateError ?
106 (certificateError.certificate.getSubjectInfo(Oxide.SslCertificate.PrincipalAttrOrganizationName).join(", ") + "\n" +
107 certificateError.certificate.getSubjectInfo(Oxide.SslCertificate.PrincipalAttrLocalityName).join(", ") + "\n" +
108 certificateError.certificate.getSubjectInfo(Oxide.SslCertificate.PrincipalAttrStateOrProvinceName).join(", ") + "\n" +
109 certificateError.certificate.getSubjectInfo(Oxide.SslCertificate.PrincipalAttrCountryName).join(", ")).replace(/\n+/g, "\n") : "")
110 }
111 Label {
112 fontSize: "x-small"
113 width: parent.width
114 wrapMode: Text.Wrap
115 // TRANSLATORS: %1 refers to the SSL certificate's issuer display name
116 text: i18n.tr("Issuer:\n%1").arg(certificateError ? certificateError.certificate.issuerDisplayName : "")
117 }
118 Label {
119 id: issuerAddress
120 fontSize: "x-small"
121 width: parent.width
122 wrapMode: Text.Wrap
123 // TRANSLATORS: %1 refers to the SSL certificate's issuer's address
124 text: i18n.tr("Issuer address:\n%1").arg(certificateError ?
125 (certificateError.certificate.getIssuerInfo(Oxide.SslCertificate.PrincipalAttrOrganizationName).join(", ") + "\n" +
126 certificateError.certificate.getIssuerInfo(Oxide.SslCertificate.PrincipalAttrLocalityName).join(", ") + "\n" +
127 certificateError.certificate.getIssuerInfo(Oxide.SslCertificate.PrincipalAttrStateOrProvinceName).join(", ") + "\n" +
128 certificateError.certificate.getIssuerInfo(Oxide.SslCertificate.PrincipalAttrCountryName).join(", ")).replace(/\n+/g, "\n") : "")
129 }
130 Label {
131 fontSize: "x-small"
132 width: parent.width
133 wrapMode: Text.Wrap
134 // TRANSLATORS: %1 refers to the SSL certificate's start date
135 text: i18n.tr("Valid from:\n%1").arg(certificateError ? certificateError.certificate.effectiveDate.toLocaleString() : "")
136 }
137 Label {
138 fontSize: "x-small"
139 width: parent.width
140 wrapMode: Text.Wrap
141 // TRANSLATORS: %1 refers to the SSL certificate's expiry date
142 text: i18n.tr("Valid until:\n%1").arg(certificateError ? certificateError.certificate.expiryDate.toLocaleString() : "")
143 }
144 Label {
145 fontSize: "x-small"
146 width: parent.width
147 wrapMode: Text.Wrap
148 // TRANSLATORS: %1 refers to the SSL certificate's SHA1 fingerprint
149 text: i18n.tr("Fingerprint (SHA1):\n%1").arg(certificateError ? certificateError.certificate.fingerprintSHA1 : "")
150 }
151 }
152
153 Label {
154 width: parent.width
155 text: i18n.tr("You should not proceed, especially if you have never seen this warning before for this site.")
156 wrapMode: Text.Wrap
157 fontSize: "x-small"
158 horizontalAlignment: Text.AlignHCenter
159 }
160
161 Button {
162 text: i18n.tr("Proceed anyway")
163 anchors.horizontalCenter: parent.horizontalCenter
164 visible: certificateError ? certificateError.overridable : false
165 onClicked: {
166 moreInfo.visible = false
167 certificateError.allow()
168 allowed()
169 }
170 }
171
172 Button {
173 id: backButton
174 anchors.horizontalCenter: parent.horizontalCenter
175 text: i18n.tr("Back to safety")
176 onClicked: {
177 moreInfo.visible = false
178 certificateError.deny()
179 denied()
180 }
181 color: UbuntuColors.orange
182 }
183 }
184 }
185
186 function textForError(error) {
187 switch(error) {
188 case Oxide.CertificateError.ErrorBadIdentity:
189 // TRANSLATORS: %1 refers to the domain name of the SSL certificate
190 return i18n.tr("You attempted to reach %1 but the server presented a security certificate which does not match the identity of the site.").arg(certificateError ? certificateError.url : "")
191 case Oxide.CertificateError.ErrorExpired:
192 // TRANSLATORS: %1 refers to the domain name of the SSL certificate
193 return i18n.tr("You attempted to reach %1 but the server presented a security certificate which has expired.").arg(certificateError ? certificateError.url : "")
194 case Oxide.CertificateError.ErrorDateInvalid:
195 // TRANSLATORS: %1 refers to the domain name of the SSL certificate
196 return i18n.tr("You attempted to reach %1 but the server presented a security certificate which contains invalid dates.").arg(certificateError ? certificateError.url : "")
197 case Oxide.CertificateError.ErrorAuthorityInvalid:
198 // TRANSLATORS: %1 refers to the domain name of the SSL certificate
199 return i18n.tr("You attempted to reach %1 but the server presented a security certificate issued by an entity that is not trusted.").arg(certificateError ? certificateError.url : "")
200 case Oxide.CertificateError.ErrorRevoked:
201 // TRANSLATORS: %1 refers to the domain name of the SSL certificate
202 return i18n.tr("You attempted to reach %1 but the server presented a security certificate that has been revoked.").arg(certificateError ? certificateError.url : "")
203 case Oxide.CertificateError.ErrorInvalid:
204 // TRANSLATORS: %1 refers to the domain name of the SSL certificate
205 return i18n.tr("You attempted to reach %1 but the server presented an invalid security certificate.").arg(certificateError ? certificateError.url : "")
206 case Oxide.CertificateError.ErrorInsecure:
207 // TRANSLATORS: %1 refers to the domain name of the SSL certificate
208 return i18n.tr("You attempted to reach %1 but the server presented an insecure security certificate.").arg(certificateError ? certificateError.url : "")
209 default:
210 // TRANSLATORS: %1 refers to the domain name of the SSL certificate
211 return i18n.tr("This site security certificate is not trusted\nYou attempted to reach %1 but the server presented a security certificate which failed our security checks for an unknown reason.").arg(certificateError ? certificateError.url : "")
212 }
213 }
214
215}
0216
=== modified file 'src/app/WebViewImpl.qml'
--- src/app/WebViewImpl.qml 2014-08-21 16:45:23 +0000
+++ src/app/WebViewImpl.qml 2014-09-22 14:01:07 +0000
@@ -26,6 +26,9 @@
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: []
2932
30 /*experimental.certificateVerificationDialog: CertificateVerificationDialog {}33 /*experimental.certificateVerificationDialog: CertificateVerificationDialog {}
31 experimental.authenticationDialog: AuthenticationDialog {}34 experimental.authenticationDialog: AuthenticationDialog {}
@@ -74,4 +77,12 @@
74 // TODO: we might want to store the answer to avoid requesting77 // TODO: we might want to store the answer to avoid requesting
75 // the permission everytime the user visits this site.78 // the permission everytime the user visits this site.
76 }79 }
80
81 onCertificateError: {
82 if(webview.allowedCertificates.indexOf(error.certificate.fingerprintSHA1) != -1) {
83 error.allow()
84 } else {
85 certificateError = error
86 }
87 }
77}88}
7889
=== modified file 'src/app/webbrowser/AddressBar.qml'
--- src/app/webbrowser/AddressBar.qml 2014-09-08 10:10:48 +0000
+++ src/app/webbrowser/AddressBar.qml 2014-09-22 14:01:07 +0000
@@ -18,6 +18,9 @@
1818
19import QtQuick 2.019import QtQuick 2.0
20import Ubuntu.Components 1.120import Ubuntu.Components 1.1
21import Ubuntu.Components.Popups 1.0
22import Ubuntu.Components.ListItems 1.0
23import com.canonical.Oxide 1.0 as Oxide
21import ".."24import ".."
2225
23FocusScope {26FocusScope {
@@ -28,6 +31,7 @@
28 property bool bookmarked: false31 property bool bookmarked: false
29 property url requestedUrl32 property url requestedUrl
30 property url actualUrl33 property url actualUrl
34 property var securityStatus
31 signal validated()35 signal validated()
32 property bool loading36 property bool loading
33 signal requestReload()37 signal requestReload()
@@ -55,68 +59,250 @@
55 anchors.fill: parent59 anchors.fill: parent
5660
57 primaryItem: Item {61 primaryItem: Item {
58 height: textField.height62 width: iconsRow.width
59 width: height63 height: iconsRow.height
6064 Row {
61 Favicon {65 id: iconsRow
62 id: favicon66 Item {
63 anchors.centerIn: parent67 height: textField.height
64 visible: (addressbar.state == "") && addressbar.actualUrl.toString()
65 }
66
67 MouseArea {
68 id: actionButton
69 objectName: "actionButton"
70 anchors.fill: parent
71 enabled: addressbar.text
72 opacity: enabled ? 1.0 : 0.3
73
74 Icon {
75 id: actionIcon
76 height: parent.height - units.gu(2)
77 width: height68 width: height
78 anchors.centerIn: parent69 visible: securityStatus ? securityStatus.securityLevel != Oxide.SecurityStatus.SecurityLevelWarning || addressbar.state != "" : true
79 name: {70
80 switch (addressbar.state) {71 Favicon {
81 case "loading":72 id: favicon
82 return "stop"73 anchors.centerIn: parent
83 case "editing":74 visible: securityStatus ? (securityStatus.securityLevel != Oxide.SecurityStatus.SecurityLevelWarning) && (addressbar.state == "") && addressbar.actualUrl.toString() : (addressbar.state == "") && addressbar.actualUrl.toString()
84 if (addressbar.text && (addressbar.text == addressbar.actualUrl)) {75 }
85 return "reload"76
86 } else if (looksLikeAUrl(addressbar.text.trim())) {77 Item {
87 return "stock_website"78 id: certificatePopoverPositioner
88 } else {79 anchors.bottom: favicon.bottom
89 return "search"80 anchors.horizontalCenter: favicon.horizontalCenter
90 }81 }
91 default:82
92 if (!favicon.visible) {83 MouseArea {
93 if (looksLikeAUrl(addressbar.text.trim())) {84 id: actionButton
94 return "stock_website"85 objectName: "actionButton"
95 } else {86 anchors.fill: parent
96 return "search"87 enabled: addressbar.text
88 opacity: enabled ? 1.0 : 0.3
89
90 Icon {
91 id: actionIcon
92 height: parent.height - units.gu(2)
93 width: height
94 anchors.centerIn: parent
95 name: {
96 switch (addressbar.state) {
97 case "loading":
98 return "stop"
99 case "editing":
100 if (addressbar.text && (addressbar.text == addressbar.actualUrl)) {
101 return "reload"
102 } else if (looksLikeAUrl(addressbar.text.trim())) {
103 return "stock_website"
104 } else {
105 return "search"
106 }
107 default:
108 if (!favicon.visible) {
109 if (looksLikeAUrl(addressbar.text.trim())) {
110 return "stock_website"
111 } else {
112 return "search"
113 }
114 } else {
115 return ""
116 }
97 }117 }
98 } else {118 }
99 return ""119 }
100 }120
101 }121 onClicked: {
102 }122 switch (actionIcon.name) {
103 }123 case "":
124 break;
125 case "stop":
126 addressbar.requestStop()
127 break
128 case "reload":
129 addressbar.requestReload()
130 break
131 default:
132 textField.accepted()
133 }
134 }
135 }
136
137 }
138
139 Item {
140 id: securityDisplay
141 height: textField.height
142 width: securityIcon.width
143 visible: securityStatus ? (securityStatus.securityLevel == Oxide.SecurityStatus.SecurityLevelSecure || securityStatus.securityLevel == Oxide.SecurityStatus.SecurityLevelSecureEV || securityStatus.securityLevel == Oxide.SecurityStatus.SecurityLevelWarning) && addressbar.state == "" : false
144
145 Icon {
146 id: securityIcon
147 anchors.centerIn: parent
148 height: parent.height - units.gu(2)
149 width: height
150 name: "network-secure"
151 }
152 }
153
154 Item {
155 id: securityWarning
156 height: textField.height
157 width: warningIcon.width
158 visible: securityStatus ? securityStatus.securityLevel == Oxide.SecurityStatus.SecurityLevelWarning && addressbar.state == "" : false
159
160 Icon {
161 id: warningIcon
162 anchors.centerIn: parent
163 height: parent.height - units.gu(2)
164 width: height
165 name: "security-alert"
166 }
167 }
168
169 }
170
171 MouseArea {
172 enabled: securityDisplay.visible && addressbar.state != "editing" && addressbar.state != "loading"
173 anchors.fill: parent
104174
105 onClicked: {175 onClicked: {
106 switch (actionIcon.name) {176 PopupUtils.open(certificatePopoverComponent, certificatePopoverPositioner)
107 case "":177 }
108 break;178 }
109 case "stop":179
110 addressbar.requestStop()180
111 break181 Component {
112 case "reload":182 id: certificatePopoverComponent
113 addressbar.requestReload()183 Popover {
114 break184 id: certificatePopover
115 default:185 Column {
116 textField.accepted()186 id: certificateDetails
117 }187 width: parent.width - units.gu(4)
118 }188 anchors.horizontalCenter: parent.horizontalCenter
119 }189 spacing: units.gu(0.5)
190
191 Item {
192 height: units.gu(1.5)
193 width: parent.width
194 }
195
196 Column {
197 width: parent.width
198 visible: securityStatus.securityLevel == Oxide.SecurityStatus.SecurityLevelWarning
199 spacing: units.gu(0.5)
200
201 Row {
202 width: parent.width
203 spacing: units.gu(0.5)
204
205 Icon {
206 name: "security-alert"
207 height: units.gu(2)
208 width: height
209 }
210
211 Label {
212 width: parent.width
213 wrapMode: Text.WordWrap
214 text: i18n.tr("This site has insecure content")
215 fontSize: "x-small"
216 }
217 }
218
219 ThinDivider {
220 width: parent.width
221 anchors.leftMargin: 0
222 anchors.rightMargin: 0
223 }
224 }
225
226 Label {
227 width: parent.width
228 wrapMode: Text.WordWrap
229 text: i18n.tr("You are connected to")
230 fontSize: "x-small"
231 }
232
233 Label {
234 width: parent.width
235 wrapMode: Text.WordWrap
236 text: securityStatus.certificate.subjectDisplayName
237 fontSize: "x-small"
238 }
239
240 ThinDivider {
241 width: parent.width
242 anchors.leftMargin: 0
243 anchors.rightMargin: 0
244 visible: orgName.visible || localityName.visible || stateName.visible || countryName.visible
245 }
246
247 Label {
248 width: parent.width
249 wrapMode: Text.WordWrap
250 visible: orgName.visible
251 text: i18n.tr("Which is run by")
252 fontSize: "x-small"
253 }
254
255 Label {
256 id: orgName
257 width: parent.width
258 wrapMode: Text.WordWrap
259 visible: text.length > 0
260 text: securityStatus.certificate.getSubjectInfo(Oxide.SslCertificate.PrincipalAttrOrganizationName).join(", ")
261 fontSize: "x-small"
262 }
263
264 Label {
265 id: localityName
266 width: parent.width
267 wrapMode: Text.WordWrap
268 visible: text.length > 0
269 text: securityStatus.certificate.getSubjectInfo(Oxide.SslCertificate.PrincipalAttrLocalityName).join(", ")
270 fontSize: "x-small"
271 }
272
273 Label {
274 id: stateName
275 width: parent.width
276 wrapMode: Text.WordWrap
277 visible: text.length > 0
278 text: securityStatus.certificate.getSubjectInfo(Oxide.SslCertificate.PrincipalAttrStateOrProvinceName).join(", ")
279 fontSize: "x-small"
280 }
281
282 Label {
283 id: countryName
284 width: parent.width
285 wrapMode: Text.WordWrap
286 visible: text.length > 0
287 text: securityStatus.certificate.getSubjectInfo(Oxide.SslCertificate.PrincipalAttrCountryName).join(", ")
288 fontSize: "x-small"
289 }
290
291 Item {
292 height: units.gu(1.5)
293 width: parent.width
294 }
295
296 }
297
298 MouseArea {
299 anchors.fill: parent
300 onClicked: PopupUtils.close(certificatePopover)
301 }
302
303 }
304 }
305
120 }306 }
121307
122 secondaryItem: Item {308 secondaryItem: Item {
@@ -174,7 +360,7 @@
174 MouseArea {360 MouseArea {
175 anchors {361 anchors {
176 fill: parent362 fill: parent
177 leftMargin: actionButton.width363 leftMargin: iconsRow.width
178 rightMargin: bookmarkButton.width364 rightMargin: bookmarkButton.width
179 }365 }
180 visible: !textField.activeFocus366 visible: !textField.activeFocus
181367
=== modified file 'src/app/webbrowser/Browser.qml'
--- src/app/webbrowser/Browser.qml 2014-08-25 16:56:58 +0000
+++ src/app/webbrowser/Browser.qml 2014-09-22 14:01:07 +0000
@@ -121,6 +121,24 @@
121 asynchronous: true121 asynchronous: true
122 }122 }
123123
124 Loader {
125 anchors.fill: tabContainer
126 sourceComponent: InvalidCertificateErrorSheet {
127 visible: currentWebview && currentWebview.certificateError != null
128 certificateError: currentWebview ? currentWebview.certificateError : null
129 onAllowed: {
130 // Automatically allow future requests involving this
131 // certificate for the duration of the session.
132 currentWebview.allowedCertificates.push(currentWebview.certificateError.certificate.fingerprintSHA1)
133 currentWebview.certificateError = null
134 }
135 onDenied: {
136 currentWebview.certificateError = null
137 }
138 }
139 asynchronous: true
140 }
141
124 Chrome {142 Chrome {
125 id: chrome143 id: chrome
126144
127145
=== modified file 'src/app/webbrowser/Chrome.qml'
--- src/app/webbrowser/Chrome.qml 2014-08-22 12:22:37 +0000
+++ src/app/webbrowser/Chrome.qml 2014-09-22 14:01:07 +0000
@@ -152,6 +152,7 @@
152 onWebviewChanged: {152 onWebviewChanged: {
153 if (webview) {153 if (webview) {
154 addressbar.actualUrl = webview.url154 addressbar.actualUrl = webview.url
155 addressbar.securityStatus = webview.securityStatus
155 }156 }
156 }157 }
157158

Subscribers

People subscribed via source and target branches

to status/vote changes: