summaryrefslogtreecommitdiff
blob: 61d3b306bed4773decc77f2b1d7b13f1dbd5643e (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
From 7b0934611ef72fb7e7c405813a1d2bb8b944dadc Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Daniel=20Vr=C3=A1til?= <dvratil@kde.org>
Date: Thu, 27 Apr 2017 18:41:45 +0200
Subject: [PATCH 3/3] Auth: add URL bar and SSL indicator to the authentication
 page

To increase trust-worthiness of the authentication dialog we now display
the URL and an SSL indicator above the webview.
---
 src/core/ui/authwidget.cpp   |   2 +
 src/core/ui/authwidget_p.cpp | 137 +++++++++++++++++++++++++++++++++++++++----
 src/core/ui/authwidget_p.h   |  25 ++++----
 3 files changed, 136 insertions(+), 28 deletions(-)

diff --git a/src/core/ui/authwidget.cpp b/src/core/ui/authwidget.cpp
index 18d2106..ac09b63 100644
--- a/src/core/ui/authwidget.cpp
+++ b/src/core/ui/authwidget.cpp
@@ -107,6 +107,8 @@ void AuthWidget::authenticate()
 
     qCDebug(KGAPIRaw) << "Requesting new token:" << url;
 
+    d->sslIndicator->setVisible(true);
+    d->urlEdit->setVisible(true);
     d->webview->setVisible(true);
     if (d->showProgressBar) {
         d->progressbar->setVisible(true);
diff --git a/src/core/ui/authwidget_p.cpp b/src/core/ui/authwidget_p.cpp
index a51f4a9..f732935 100644
--- a/src/core/ui/authwidget_p.cpp
+++ b/src/core/ui/authwidget_p.cpp
@@ -25,35 +25,79 @@
 #include "private/newtokensfetchjob_p.h"
 #include "../../debug.h"
 
-#include <QWebEngineView>
 #include <QWebEngineProfile>
 #include <QNetworkReply>
 #include <QContextMenuEvent>
 
+#include <QVBoxLayout>
+#include <QLabel>
+#include <QTimer>
+#include <QMessageBox>
+
 #include <QDateTime>
 
 using namespace KGAPI2;
 
-WebView::WebView(QWidget *parent)
-    : QWebEngineView(parent)
+namespace
 {
-    // Don't store cookies, so that subsequent invocations of AuthJob won't remember
-    // the previous accounts.
-    QWebEngineProfile::defaultProfile()->setPersistentCookiesPolicy(QWebEngineProfile::NoPersistentCookies);
-}
 
-
-WebView::~WebView()
+class WebView : public QWebEngineView
 {
+    Q_OBJECT
+public:
+    explicit WebView(QWidget *parent = nullptr)
+        : QWebEngineView(parent)
+    {
+        // Don't store cookies, so that subsequent invocations of AuthJob won't remember
+        // the previous accounts.
+        QWebEngineProfile::defaultProfile()->setPersistentCookiesPolicy(QWebEngineProfile::NoPersistentCookies);
+    }
 
-}
+    void contextMenuEvent(QContextMenuEvent *e) Q_DECL_OVERRIDE
+    {
+        // No menu
+        e->accept();
+    }
+};
 
-void WebView::contextMenuEvent(QContextMenuEvent *e)
+class WebPage : public QWebEnginePage
 {
-    // No menu
-    e->accept();
+    Q_OBJECT
+public:
+    explicit WebPage(QObject *parent = nullptr)
+        : QWebEnginePage(parent)
+        , mLastError(nullptr)
+    {
+    }
+
+    QWebEngineCertificateError *lastCertificateError() const
+    {
+        return mLastError;
+    }
+
+    bool certificateError(const QWebEngineCertificateError &err) Q_DECL_OVERRIDE
+    {
+        if (mLastError) {
+            delete mLastError;
+        }
+        mLastError = new QWebEngineCertificateError(err.error(), err.url(), err.isOverridable(), err.errorDescription());
+        Q_EMIT sslError();
+
+        return false; // don't let it through
+    }
+
+Q_SIGNALS:
+    void sslError();
+
+private:
+    QWebEngineCertificateError *mLastError;
+};
+
 }
 
+
+
+
 AuthWidgetPrivate::AuthWidgetPrivate(AuthWidget *parent):
     QObject(),
     showProgressBar(true),
@@ -67,6 +111,15 @@ AuthWidgetPrivate::~AuthWidgetPrivate()
 {
 }
 
+void AuthWidgetPrivate::setSslIcon(const QString &iconName)
+{
+    // FIXME: workaround for silly Breeze icons: the small 22x22 icons are
+    // monochromatic, which is absolutely useless since we are trying to security
+    // information here, so instead we force use the bigger 48x48 icons which
+    // have colors and downscale them
+    sslIndicator->setIcon(QIcon::fromTheme(iconName).pixmap(48));
+}
+
 void AuthWidgetPrivate::setupUi()
 {
     vbox = new QVBoxLayout(q);
@@ -79,6 +132,26 @@ void AuthWidgetPrivate::setupUi()
     label->setVisible(false);
     vbox->addWidget(label);
 
+    auto hbox = new QHBoxLayout;
+    hbox->setSpacing(0);
+    sslIndicator = new QToolButton(q);
+    connect(sslIndicator, &QToolButton::clicked,
+            this, [this]() {
+                auto page = qobject_cast<WebPage*>(webview->page());
+                if (auto err = page->lastCertificateError()) {
+                    QMessageBox msg;
+                    msg.setIconPixmap(QIcon::fromTheme(QStringLiteral("security-low")).pixmap(64));
+                    msg.setText(err->errorDescription());
+                    msg.addButton(QMessageBox::Ok);
+                    msg.exec();
+                }
+            });
+    hbox->addWidget(sslIndicator);
+    urlEdit = new QLineEdit(q);
+    urlEdit->setReadOnly(true);
+    hbox->addWidget(urlEdit);
+    vbox->addLayout(hbox);
+
     progressbar = new QProgressBar(q);
     progressbar->setMinimum(0);
     progressbar->setMaximum(100);
@@ -87,6 +160,13 @@ void AuthWidgetPrivate::setupUi()
 
     webview = new WebView(q);
 
+    auto webpage = new WebPage(webview);
+    connect(webpage, &WebPage::sslError,
+            this, [this]() {
+                setSslIcon(QStringLiteral("security-low"));
+            });
+    webview->setPage(webpage);
+
     vbox->addWidget(webview);
     connect(webview, &QWebEngineView::loadProgress, progressbar, &QProgressBar::setValue);
     connect(webview, &QWebEngineView::urlChanged, this, &AuthWidgetPrivate::webviewUrlChanged);
@@ -104,6 +184,8 @@ void AuthWidgetPrivate::setProgress(AuthWidget::Progress progress)
 void AuthWidgetPrivate::emitError(const enum Error errCode, const QString& msg)
 {
     label->setVisible(true);
+    sslIndicator->setVisible(false);
+    urlEdit->setVisible(false);
     webview->setVisible(false);
     progressbar->setVisible(false);
 
@@ -118,10 +200,33 @@ void AuthWidgetPrivate::webviewUrlChanged(const QUrl &url)
 {
     qCDebug(KGAPIDebug) << "URLChange:" << url;
 
+    // Whoa! That should not happen!
+    if (url.scheme() != QLatin1String("https")) {
+        QTimer::singleShot(0, this, [this, url]() {
+            QUrl sslUrl = url;
+            sslUrl.setScheme(QStringLiteral("https"));
+            webview->setUrl(sslUrl);
+        });
+        return;
+    }
+
     if (!isGoogleHost(url)) {
+        // We handled SSL above, so we are secure. We are however outside of
+        // accounts.google.com, which is a little suspicious in context of this class
+        setSslIcon(QStringLiteral("security-medium"));
         return;
     }
 
+    if (qobject_cast<WebPage*>(webview->page())->lastCertificateError()) {
+        setSslIcon(QStringLiteral("security-low"));
+    } else {
+        // We have no way of obtaining current SSL certifiace from QWebEngine, but we
+        // handled SSL and accounts.google.com cases above and QWebEngine did not report
+        // any SSL error to us, so we can assume we are safe.
+        setSslIcon(QStringLiteral("security-high"));
+    }
+
+
     // Username and password inputs are loaded dynamically, so we only get
     // urlChanged, but not urlFinished.
     if (isUsernameFrame(url)) {
@@ -145,6 +250,8 @@ void AuthWidgetPrivate::webviewUrlChanged(const QUrl &url)
     } else if (isTokenPage(url)) {
         /* Access token here - hide browser and tell user to wait until we
          * finish the authentication process ourselves */
+        sslIndicator->setVisible(false);
+        urlEdit->setVisible(false);
         webview->setVisible(false);
         progressbar->setVisible(false);
         label->setVisible(true);
@@ -160,6 +267,8 @@ void AuthWidgetPrivate::webviewFinished(bool ok)
     }
 
     const QUrl url = webview->url();
+    urlEdit->setText(url.toDisplayString(QUrl::PrettyDecoded));
+    urlEdit->setCursorPosition(0);
     qCDebug(KGAPIDebug) << "URLFinished:" << url;
 
     if (!isGoogleHost(url)) {
@@ -238,3 +347,5 @@ void AuthWidgetPrivate::accountInfoReceived(KGAPI2::Job* job)
     setProgress(AuthWidget::Finished);
 }
 
+
+#include "authwidget_p.moc"
diff --git a/src/core/ui/authwidget_p.h b/src/core/ui/authwidget_p.h
index 9c488be..78b0e7f 100644
--- a/src/core/ui/authwidget_p.h
+++ b/src/core/ui/authwidget_p.h
@@ -26,27 +26,18 @@
 #include "ui/authwidget.h"
 #include "types.h"
 
+#include <QLineEdit>
+#include <QToolButton>
 #include <QProgressBar>
-#include <QVBoxLayout>
 #include <QWebEngineView>
-#include <QLabel>
+
+class QVBoxLayout;
+class QLabel;
 
 namespace KGAPI2 {
 
 class Job;
 
-class WebView : public QWebEngineView
-{
-    Q_OBJECT
-public:
-    explicit WebView(QWidget *parent=0);
-    ~WebView();
-
-protected:
-    void contextMenuEvent(QContextMenuEvent *) Q_DECL_OVERRIDE;
-};
-
-
 class Q_DECL_HIDDEN AuthWidgetPrivate: public QObject {
 
     Q_OBJECT
@@ -65,9 +56,11 @@ class Q_DECL_HIDDEN AuthWidgetPrivate: public QObject {
     QString apiKey;
     QString secretKey;
 
+    QToolButton *sslIndicator;
+    QLineEdit *urlEdit;
     QProgressBar *progressbar;
     QVBoxLayout *vbox;
-    WebView *webview;
+    QWebEngineView *webview;
     QLabel *label;
 
   private Q_SLOTS:
@@ -88,6 +81,8 @@ class Q_DECL_HIDDEN AuthWidgetPrivate: public QObject {
     bool isPasswordFrame(const QUrl &url) { return url.path() == QLatin1String("/signin/v2/challenge/pwd"); }
     bool isTokenPage(const QUrl &url) { return url.path() == QLatin1String("/o/oauth2/approval/v2"); }
 
+    void setSslIcon(const QString &icon);
+
     AuthWidget *q;
 
     friend class AuthWidget;
-- 
2.12.2