summaryrefslogtreecommitdiff
blob: eb426465947babf9cbd19442356e6e588db5929e (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
From 68b89bce22d0da234345ccffb869ae6863592624 Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Daniel=20Vr=C3=A1til?= <dvratil@kde.org>
Date: Thu, 27 Apr 2017 17:22:27 +0200
Subject: [PATCH 1/3] Auth: Adapt to changes in Google OAuth token retrieval
 process

URLs and HTML code have changed a bit, which breaks authentication. Hopefully
they won't change it too often in the future.
---
 src/core/ui/authwidget_p.cpp | 109 ++++++++++++++++++++++++-------------------
 src/core/ui/authwidget_p.h   |   6 +++
 2 files changed, 67 insertions(+), 48 deletions(-)

diff --git a/src/core/ui/authwidget_p.cpp b/src/core/ui/authwidget_p.cpp
index 6de33f5..75d38cd 100644
--- a/src/core/ui/authwidget_p.cpp
+++ b/src/core/ui/authwidget_p.cpp
@@ -112,11 +112,35 @@ void AuthWidgetPrivate::emitError(const enum Error errCode, const QString& msg)
 
 void AuthWidgetPrivate::webviewUrlChanged(const QUrl &url)
 {
-    qCDebug(KGAPIDebug) << url;
+    qCDebug(KGAPIDebug) << "URLChange:" << url;
 
-    /* Access token here - hide browser and tell user to wait until we
-     * finish the authentication process ourselves */
-    if (url.host() == QLatin1String("accounts.google.com") && url.path() == QLatin1String("/o/oauth2/approval")) {
+    if (!isGoogleHost(url)) {
+        return;
+    }
+
+    // Username and password inputs are loaded dynamically, so we only get
+    // urlChanged, but not urlFinished.
+    if (isUsernameFrame(url)) {
+#if QT_VERSION >= QT_VERSION_CHECK(5, 7, 0)
+        if (!username.isEmpty()) {
+            webview->page()->runJavaScript(QStringLiteral("document.getElementById(\"identifierId\").value = \"%1\";").arg(username));
+        }
+#endif
+    } else if (isPasswordFrame(url)) {
+#if QT_VERSION >= QT_VERSION_CHECK(5, 7, 0)
+        if (!password.isEmpty()) {
+            webview->page()->runJavaScript(QStringLiteral("var elems = document.getElementsByTagName(\"input\");"
+                                                          "for (var i = 0; i < elems.length; i++) {"
+                                                          "  if (elems[i].type == \"password\" && elems[i].name == \"password\") {"
+                                                          "      elems[i].value = \"%1\";"
+                                                          "      break;"
+                                                          "  }"
+                                                          "}").arg(password));
+        }
+#endif
+    } else if (isTokenPage(url)) {
+        /* Access token here - hide browser and tell user to wait until we
+         * finish the authentication process ourselves */
         webview->setVisible(false);
         progressbar->setVisible(false);
         label->setVisible(true);
@@ -131,57 +155,46 @@ void AuthWidgetPrivate::webviewFinished(bool ok)
         qCWarning(KGAPIDebug) << "Failed to load" << webview->url();
     }
 
-    QUrl url = webview->url();
-    qCDebug(KGAPIDebug) << url;
-
-    if (url.host() == QLatin1String("accounts.google.com") && url.path() == QLatin1String("/ServiceLogin")) {
-        if (username.isEmpty() && password.isEmpty()) {
-            return;
-        }
-
-#if QT_VERSION >= QT_VERSION_CHECK(5, 7, 0)
-        const auto js = QStringLiteral("document.getElementById(\"%1\").value = \"%2\";");
-        if (!username.isEmpty()) {
-            webview->page()->runJavaScript(js.arg(QStringLiteral("Email"), username));
-        }
-
-        if (!password.isEmpty()) {
-            webview->page()->runJavaScript(js.arg(QStringLiteral("Passwd"), password));
-        }
-#endif
+    const QUrl url = webview->url();
+    qCDebug(KGAPIDebug) << "URLFinished:" << url;
 
+    if (!isGoogleHost(url)) {
         return;
     }
 
-    if (url.host() == QLatin1String("accounts.google.com") && url.path() == QLatin1String("/o/oauth2/approval")) {
-        QString title = webview->title();
-        QString token;
-
-        if (title.startsWith(QLatin1String("success"), Qt::CaseInsensitive)) {
-            int pos = title.indexOf(QLatin1String("code="));
-            /* Skip the 'code=' string as well */
-            token = title.mid (pos + 5);
+    if (isTokenPage(url)) {
+        const auto token = url.queryItemValue(QStringLiteral("approvalCode"));
+        if (!token.isEmpty()) {
+            qCDebug(KGAPIDebug) << "Got token: " << token;
+            auto fetch = new KGAPI2::NewTokensFetchJob(token, apiKey, secretKey);
+            connect(fetch, &Job::finished, this, &AuthWidgetPrivate::tokensReceived);
         } else {
-            webview->page()->toHtml([title](const QString &html) {
-                qCDebug(KGAPIDebug) << "Parsing token page failed. Title:" << title;
-                qCDebug(KGAPIDebug) << html;
-            });
+#if QT_VERSION >= QT_VERSION_CHECK(5, 7, 0)
+            qCWarning(KGAPIDebug) << "Failed to parse token from URL, peaking into HTML...";
+            webview->page()->runJavaScript(
+                QStringLiteral("document.getElementById(\"code\").value;"),
+                [this](const QVariant &result) {
+                    const auto token = result.toString();
+                    if (token.isEmpty()) {
+                        qCWarning(KGAPIDebug) << "Peaked into HTML, but cound not find token :(";
+                        webview->page()->toHtml([](const QString &html) {
+                            qCDebug(KGAPIDebug) << "Parsing token page failed";
+                            qCDebug(KGAPIDebug) << html;
+                        });
+                        emitError(AuthError, tr("Parsing token page failed."));
+                        return;
+                    }
+                    qCDebug(KGAPIDebug) << "Peaked into HTML and found token: " << token;
+                    auto fetch = new KGAPI2::NewTokensFetchJob(token, apiKey, secretKey);
+                    connect(fetch, &Job::finished, this, &AuthWidgetPrivate::tokensReceived);
+                });
+#else
+            qCWarning(KGAPIDebug) << "Failed to parse token from URL!";
             emitError(AuthError, tr("Parsing token page failed."));
-            return;
-        }
-
-        if (token.isEmpty()) {
-            webview->page()->toHtml([](const QString &html) {
-                qCDebug(KGAPIDebug) << "Failed to obtain token.";
-                qCDebug(KGAPIRaw) << html;
-            });
-            emitError(AuthError, tr("Failed to obtain token."));
-            return;
+#endif
         }
-
-        KGAPI2::NewTokensFetchJob *fetchJob = new KGAPI2::NewTokensFetchJob(token, apiKey, secretKey);
-        connect(fetchJob, &Job::finished,
-                this, &AuthWidgetPrivate::tokensReceived);
+    } else {
+        //qCDebug(KGAPIDebug) << "Unhandled page:" << url.host() << ", " << url.path();
     }
 }
 
diff --git a/src/core/ui/authwidget_p.h b/src/core/ui/authwidget_p.h
index 673b0cb..9c488be 100644
--- a/src/core/ui/authwidget_p.h
+++ b/src/core/ui/authwidget_p.h
@@ -82,6 +82,12 @@ class Q_DECL_HIDDEN AuthWidgetPrivate: public QObject {
     void setupUi();
     void setProgress(AuthWidget::Progress progress);
 
+    bool isGoogleHost(const QUrl &url) const { return url.host() == QLatin1String("accounts.google.com"); }
+    bool isSigninPage(const QUrl &url) const { return url.path() == QLatin1String("/signin/oauth"); }
+    bool isUsernameFrame(const QUrl &url) { return url.path() == QLatin1String("/signin/oauth/identifier"); }
+    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"); }
+
     AuthWidget *q;
 
     friend class AuthWidget;
-- 
2.12.2