[gnome-maps/wip/mlundblad/osm-oauth-external: 2/4] Use external browser to authorize OAuth token




commit d4ceed0fab8cad58201c09a867ca3f614b658f00
Author: Marcus Lundblad <ml dfupdate se>
Date:   Sat Apr 23 23:05:34 2022 +0200

    Use external browser to authorize OAuth token
    
    Drop the "fully automatic" sign in method that
    we had adapted from JOSM. Instead implemtent
    OAuth setup redirecting to an external web
    browser. This is the preferred way to do
    OAuth sign up, and also lets us drop the
    dependency on WebKitGTK, as we don't need
    to render the verification web view.

 data/ui/osm-account-dialog.ui | 238 +++++++++++++++---------------------------
 src/osmAccountDialog.js       |  94 +++++------------
 src/osmConnection.js          | 172 ++++++++----------------------
 src/osmEdit.js                |  35 ++++---
 4 files changed, 171 insertions(+), 368 deletions(-)
---
diff --git a/data/ui/osm-account-dialog.ui b/data/ui/osm-account-dialog.ui
index 8cddfeca..ee30d3d9 100644
--- a/data/ui/osm-account-dialog.ui
+++ b/data/ui/osm-account-dialog.ui
@@ -12,6 +12,7 @@
         <child>
           <object class="GtkStack" id="stack">
             <property name="visible">True</property>
+            <property name="transition-type">GTK_STACK_TRANSITION_TYPE_SLIDE_RIGHT</property>
             <child>
               <object class="GtkGrid">
                 <property name="visible">True</property>
@@ -29,6 +30,7 @@
                   <packing>
                     <property name="left_attach">0</property>
                     <property name="top_attach">0</property>
+                    <property name="width">3</property>
                   </packing>
                 </child>
                 <child>
@@ -43,141 +45,80 @@ OpenStreetMap account.</property>
                   <packing>
                     <property name="left_attach">0</property>
                     <property name="top_attach">1</property>
+                    <property name="width">3</property>
                   </packing>
                 </child>
                 <child>
-                  <object class="GtkGrid">
+                  <object class="GtkLabel">
+                    <property name="label" translatable="yes">Sign in to authorize access in a web browser.
+Then fill in the obtained verification code here in the next step.</property>
                     <property name="visible">True</property>
-                    <property name="column-spacing">10</property>
-                    <property name="row-spacing">10</property>
-                    <child>
-                      <object class="GtkLabel">
-                        <property name="visible">True</property>
-                        <property name="label" translatable="yes">Email</property>
-                        <property name="halign">GTK_ALIGN_END</property>
-                        <style>
-                          <class name="dim-label"/>
-                        </style>
-                      </object>
-                      <packing>
-                        <property name="left_attach">0</property>
-                        <property name="top_attach">0</property>
-                      </packing>
-                    </child>
-                    <child>
-                      <object class="GtkEntry" id="emailEntry">
-                        <property name="visible">True</property>
-                        <property name="hexpand">True</property>
-                      </object>
-                      <packing>
-                        <property name="left_attach">1</property>
-                        <property name="top_attach">0</property>
-                        <property name="width">2</property>
-                      </packing>
-                    </child>
-                    <child>
-                      <object class="GtkLabel">
-                        <property name="visible">True</property>
-                        <property name="label" translatable="yes">Password</property>
-                        <property name="halign">GTK_ALIGN_END</property>
-                        <style>
-                          <class name="dim-label"/>
-                        </style>
-                      </object>
-                      <packing>
-                        <property name="left_attach">0</property>
-                        <property name="top_attach">1</property>
-                      </packing>
-                    </child>
-                    <child>
-                      <object class="GtkEntry" id="passwordEntry">
-                        <property name="visible">True</property>
-                        <property name="hexpand">True</property>
-                        <property name="input-purpose">GTK_INPUT_PURPOSE_PASSWORD</property>
-                        <property name="visibility">False</property>
-                        <property name="caps-lock-warning">True</property>
-                      </object>
-                      <packing>
-                        <property name="left_attach">1</property>
-                        <property name="top_attach">1</property>
-                        <property name="width">2</property>
-                      </packing>
-                    </child>
-                    <child>
-                      <object class="GtkSpinner" id="signInSpinner">
-                        <property name="visible">False</property>
-                        <property name="height_request">16</property>
-                        <property name="width_request">16</property>
-                        <property name="can_focus">False</property>
-                        <property name="active">True</property>
-                        <property name="halign">GTK_ALIGN_END</property>
-                        <property name="hexpand">True</property>
-                      </object>
-                      <packing>
-                        <property name="left_attach">1</property>
-                        <property name="top_attach">2</property>
-                      </packing>
-                    </child>
-                    <child>
-                      <object class="GtkLinkButton" id="signUpLinkButton">
-                        <property name="visible">True</property>
-                        <property name="can_focus">True</property>
-                        <property name="label" translatable="yes">Sign up</property>
-                        <property name="uri">https://www.openstreetmap.org/user/new</property>
-                        <property name="halign">GTK_ALIGN_END</property>
-                        <property name="hexpand">True</property>
-                      </object>
-                      <packing>
-                        <property name="left_attach">1</property>
-                        <property name="top_attach">2</property>
-                      </packing>
-                    </child>
-                    <child>
-                      <object class="GtkButton" id="signInButton">
-                        <property name="visible">True</property>
-                        <property name="halign">GTK_ALIGN_END</property>
-                        <property name="label" translatable="yes">Sign In</property>
-                        <property name="sensitive">False</property>
-                        <style>
-                          <class name="suggested-action"/>
-                        </style>
-                      </object>
-                      <packing>
-                        <property name="left_attach">2</property>
-                        <property name="top_attach">2</property>
-                      </packing>
-                    </child>
+                    <property name="hexpand">True</property>
+                    <property name="wrap">True</property>
+                    <property name="halign">GTK_ALIGN_CENTER</property>
+                    <property name="justify">GTK_JUSTIFY_CENTER</property>
                   </object>
                   <packing>
                     <property name="left_attach">0</property>
                     <property name="top_attach">2</property>
+                    <property name="width">3</property>
                   </packing>
                 </child>
-
                 <child>
-                  <object class="GtkLabel" id="resetPasswordLabel">
+                  <object class="GtkSpinner" id="signInSpinner">
                     <property name="visible">False</property>
-                    <property name="can_focus">True</property>
-                    <property name="label" translatable="yes"
-                      comments="The label should contain the link to the OSM reset password page with a 
translated title">Sorry, that didn’t work. Please try again, or visit
-&lt;a href="https://www.openstreetmap.org/user/forgot-password"&gt;OpenStreetMap&lt;/a&gt; to reset your 
password.</property>
-                    <property name="use-markup">True</property>
+                    <property name="height_request">16</property>
+                    <property name="width_request">16</property>
+                    <property name="can_focus">False</property>
+                    <property name="active">True</property>
+                    <property name="halign">GTK_ALIGN_END</property>
+                    <property name="hexpand">True</property>
                   </object>
                   <packing>
                     <property name="left_attach">0</property>
-                    <property name="top_attach">4</property>
+                    <property name="top_attach">3</property>
                   </packing>
                 </child>
                 <child>
-                  <object class="GtkLabel" id="verificationFailedLabel">
+                  <object class="GtkLinkButton">
+                    <property name="visible">True</property>
+                    <property name="can_focus">True</property>
+                    <property name="label" translatable="yes">Sign up</property>
+                    <property name="uri">https://www.openstreetmap.org/user/new</property>
+                    <property name="halign">GTK_ALIGN_END</property>
+                    <property name="hexpand">True</property>
+                  </object>
+                  <packing>
+                    <property name="left_attach">1</property>
+                    <property name="top_attach">3</property>
+                  </packing>
+                </child>
+                <child>
+                  <object class="GtkButton" id="signInButton">
+                    <property name="visible">True</property>
+                    <property name="halign">GTK_ALIGN_END</property>
+                    <property name="label" translatable="yes">Sign In</property>
+                    <style>
+                      <class name="suggested-action"/>
+                    </style>
+                  </object>
+                  <packing>
+                    <property name="left_attach">2</property>
+                    <property name="top_attach">3</property>
+                  </packing>
+                </child>
+                <child>
+                  <object class="GtkLabel" id="errorLabel">
                     <property name="visible">False</property>
                     <property name="can_focus">True</property>
-                    <property name="label" translatable="yes">The verification code didn’t match, please try 
again.</property>
                     <property name="use-markup">True</property>
+                    <style>
+                      <class name="warning"/>
+                    </style>
                   </object>
                   <packing>
                     <property name="left_attach">0</property>
-                    <property name="top_attach">5</property>
+                    <property name="top_attach">4</property>
                   </packing>
                 </child>
               </object>
@@ -186,59 +127,50 @@ OpenStreetMap account.</property>
               </packing>
             </child>
             <child>
-              <object class="GtkGrid" id="verifyGrid">
+              <object class="GtkGrid">
                 <property name="visible">True</property>
                 <property name="row-spacing">10</property>
+                <property name="column-spacing">10</property>
                 <property name="margin">20</property>
                 <child>
-                  <object class="GtkGrid">
+                  <object class="GtkLabel">
+                    <property name="visible">True</property>
+                    <property name="wrap">True</property>
+                    <property name="label" translatable="yes">Copy verification code shown when authorizing 
access in the browser</property>
+                  </object>
+                  <packing>
+                    <property name="left-attach">0</property>
+                    <property name="top-attach">0</property>
+                    <property name="width">2</property>
+                  </packing>
+                </child>
+                <child>
+                  <object class="GtkEntry" id="verificationEntry">
                     <property name="visible">True</property>
-                    <property name="column-spacing">10</property>
-                    <property name="row-spacing">10</property>
-                    <child>
-                      <object class="GtkLabel">
-                        <property name="visible">True</property>
-                        <property name="label" translatable="yes">Enter verification code shown 
above</property>
-                        <style>
-                          <class name="dim-label"/>
-                        </style>
-                      </object>
-                      <packing>
-                        <property name="left_attach">0</property>
-                        <property name="top_attach">0</property>
-                      </packing>
-                    </child>
-                    <child>
-                      <object class="GtkEntry" id="verificationEntry">
-                        <property name="visible">True</property>
-                      </object>
-                      <packing>
-                        <property name="left_attach">1</property>
-                        <property name="top_attach">0</property>
-                      </packing>
-                    </child>
-                    <child>
-                      <object class="GtkButton" id="verifyButton">
-                        <property name="visible">True</property>
-                        <property name="sensitive">False</property>
-                        <property name="label" translatable="yes">Verify</property>
-                        <property name="hexpand">False</property>
-                        <property name="halign">GTK_ALIGN_END</property>
-                        <style>
-                          <class name="suggested-action"/>
-                        </style>
-                      </object>
-                      <packing>
-                        <property name="left_attach">1</property>
-                        <property name="top_attach">1</property>
-                      </packing>
-                    </child>
+                    <property name="placeholder-text" translatable="yes">Verification code</property>
+                    <property name="hexpand">True</property>
                   </object>
                   <packing>
                     <property name="left_attach">0</property>
                     <property name="top_attach">1</property>
                   </packing>
                 </child>
+                <child>
+                  <object class="GtkButton" id="verifyButton">
+                    <property name="visible">True</property>
+                    <property name="sensitive">False</property>
+                    <property name="label" translatable="yes">Verify</property>
+                    <property name="hexpand">False</property>
+                    <property name="halign">GTK_ALIGN_END</property>
+                    <style>
+                      <class name="suggested-action"/>
+                    </style>
+                  </object>
+                  <packing>
+                    <property name="left_attach">1</property>
+                    <property name="top-attach">1</property>
+                  </packing>
+                </child>
               </object>
               <packing>
                 <property name="name">verify</property>
diff --git a/src/osmAccountDialog.js b/src/osmAccountDialog.js
index d522e456..21c63fe3 100644
--- a/src/osmAccountDialog.js
+++ b/src/osmAccountDialog.js
@@ -22,7 +22,6 @@
 
 const GObject = imports.gi.GObject;
 const Gtk = imports.gi.Gtk;
-const WebKit2 = imports.gi.WebKit2;
 
 const Application = imports.application;
 const Utils = imports.utils;
@@ -34,16 +33,11 @@ var Response = {
 var OSMAccountDialog = GObject.registerClass({
     Template: 'resource:///org/gnome/Maps/ui/osm-account-dialog.ui',
     InternalChildren: ['stack',
-                       'emailEntry',
-                       'passwordEntry',
                        'signInButton',
                        'signInSpinner',
-                       'signUpLinkButton',
-                       'resetPasswordLabel',
-                       'verifyGrid',
                        'verificationEntry',
                        'verifyButton',
-                       'verificationFailedLabel',
+                       'errorLabel',
                        'signedInUserLabel',
                        'signOutButton'],
 }, class OSMAccountDialog extends Gtk.Dialog {
@@ -57,12 +51,6 @@ var OSMAccountDialog = GObject.registerClass({
 
         super._init(params);
 
-        this._emailEntry.connect('changed',
-                                 this._onCredentialsChanged.bind(this));
-        this._passwordEntry.connect('changed',
-                                    this._onCredentialsChanged.bind(this));
-        this._passwordEntry.connect('activate',
-                                    this._onPasswordActivated.bind(this));
         this._signInButton.connect('clicked',
                                    this._onSignInButtonClicked.bind(this));
         this._verifyButton.connect('clicked',
@@ -76,76 +64,47 @@ var OSMAccountDialog = GObject.registerClass({
 
         /* if the user is logged in, show the logged-in view */
         if (Application.osmEdit.isSignedIn) {
-            this._signedInUserLabel.label = Application.osmEdit.username;
+            this._updateSignedInUserLabel();
             this._stack.visible_child_name = 'logged-in';
         }
-
-        /* initialize verification web view, we do it programmatically rather
-         * declare it in the .ui file to be able to enable WebKit sandboxing
-         */
-        let webContext = WebKit2.WebContext.get_default();
-
-        webContext.set_sandbox_enabled(true);
-        this._verifyView = WebKit2.WebView.new_with_context(webContext);
-        this._verifyView.visible = true;
-        this._verifyView.halign = Gtk.Align.FILL;
-        this._verifyView.height_request = 150;
-        this._verifyGrid.attach(this._verifyView, 0, 0, 1, 1);
     }
 
-    _onCredentialsChanged() {
-        let email = this._emailEntry.text;
-        let password = this._passwordEntry.text;
-
-        // make sign in button sensitive if credential have been entered
-        this._signInButton.sensitive =
-            email && email.length > 0 && password && password.length > 0;
+    _updateSignedInUserLabel() {
+        /* if we couldn't determine the logged in username (e.g. the user
+         * didn't grant permission to read user details, hide the username
+         * label
+         */
+        if (Application.osmEdit.username === '_unknown_') {
+            this._signedInUserLabel.visible = false;
+        } else {
+            this._signedInUserLabel.label = Application.osmEdit.username;
+            this._signedInUserLabel.visible = true;
+        }
     }
 
     _onSignInButtonClicked() {
         this._performSignIn();
     }
 
-    _onPasswordActivated() {
-        /* if username and password was entered, proceed with sign-in */
-        let email = this._emailEntry.text;
-        let password = this._passwordEntry.text;
-
-        if (email && email.length > 0 && password && password.length > 0)
-            this._performSignIn();
-    }
-
     _performSignIn() {
-        /* turn on signing in spinner and desensisize credential entries */
+        // turn on signing in spinner
         this._signInSpinner.visible = true;
         this._signInButton.sensitive = false;
-        this._emailEntry.sensitive = false;
-        this._passwordEntry.sensitive = false;
-        this._signUpLinkButton.visible = false;
 
-        Application.osmEdit.performOAuthSignIn(this._emailEntry.text,
-                                               this._passwordEntry.text,
-                                               this._onOAuthSignInPerformed.bind(this));
+        Application.osmEdit.performOAuthSignIn(this._onOAuthTokenAuthorized.bind(this));
     }
 
-    _onOAuthSignInPerformed(success, verificationPage) {
+    _onOAuthTokenAuthorized(success) {
         if (success) {
-            /* switch to the verification view and show the verification
-               page */
-            this._verifyView.load_html(verificationPage,
-                                       'https://www.openstreetmap.org/');
+            // switch to the verification view
             this._stack.visible_child_name = 'verify';
         } else {
-            /* clear password entry */
-            this._passwordEntry.text = '';
-            /* show the password reset link */
-            this._resetPasswordLabel.visible = true;
+            this._errorLabel.visible = true;
+            this._errorLabel.label = _("Failed to authorize access");
+            this._signInButton.label = _("Try again");
         }
 
         this._signInSpinner.visible = false;
-        /* re-sensisize credential entries */
-        this._emailEntry.sensitive = true;
-        this._passwordEntry.sensitive = true;
     }
 
     _onVerifyButtonClicked() {
@@ -185,16 +144,14 @@ var OSMAccountDialog = GObject.registerClass({
     _onOAuthAccessTokenRequested(success, errorMessage) {
         if (success) {
             /* update the username label */
-            this._signedInUserLabel.label = Application.osmEdit.username;
+            this._updateSignedInUserLabel();
 
             if (this._closeOnSignIn) {
                 this.response(Response.SIGNED_IN);
             } else {
                 /* switch to the logged in view and reset the state in case
                    the user signs out and start over again */
-                this._resetPasswordLabel.visible = false;
-                this._verificationFailedLabel = false;
-                this._signUpLinkButton.visible = true;
+                this._errorLabel.visible = false;
                 this._stack.visible_child_name = 'logged-in';
             }
         } else {
@@ -202,9 +159,9 @@ var OSMAccountDialog = GObject.registerClass({
                 Utils.showDialog(errorMessage, Gtk.MessageType.ERROR, this);
             /* switch back to the sign-in view, and show a label indicating
                that verification failed */
-            this._resetPasswordLabel.visible = false;
-            this._signUpLinkButton.visible = false;
-            this._verificationFailedLabel.visible = true;
+            this._errorLabel.visible = true;
+            this._errorLabel.label =
+                _("The verification code didn’t match, please try again.");
             this._signInButton.sensitive = true;
             this._stack.visible_child_name = 'sign-in';
         }
@@ -214,6 +171,7 @@ var OSMAccountDialog = GObject.registerClass({
 
     _onSignOutButtonClicked() {
         Application.osmEdit.signOut();
+        this._signInButton.sensitive= true;
         this._stack.visible_child_name = 'sign-in';
     }
 });
diff --git a/src/osmConnection.js b/src/osmConnection.js
index 6bb7026c..f20e8600 100644
--- a/src/osmConnection.js
+++ b/src/osmConnection.js
@@ -23,6 +23,8 @@
 const _ = imports.gettext.gettext;
 
 const Maps = imports.gi.GnomeMaps;
+
+const Gio = imports.gi.Gio;
 const Rest = imports.gi.Rest;
 const Secret = imports.gi.Secret;
 const Soup = imports.gi.Soup;
@@ -238,102 +240,19 @@ var OSMConnection = class OSMConnection {
         callback(true);
     }
 
-    authorizeOAuthToken(username, password, callback) {
-        /* get login session ID */
-        let loginUrl = LOGIN_URL + '?cookie_test=true';
-        let uri = new Soup.URI(loginUrl);
-        let msg = new Soup.Message({method: 'GET', uri: uri});
+    authorizeOAuthToken(callback) {
+        let auth = '/authorize?oauth_token=';
+        let authorizeUrl = OAUTH_ENDPOINT_URL + auth + this._oauthToken;
 
-        this._session.queue_message(msg, (obj, message) => {
-            this._onLoginFormReceived(message, username, password, callback);
-        });
-    }
+        Utils.debug('Trying to open: ' + authorizeUrl);
 
-    _onLoginFormReceived(message, username, password, callback) {
-        if (message.status_code !== Soup.Status.OK) {
+        try {
+            Gio.AppInfo.launch_default_for_uri(authorizeUrl, null);
+            callback(true);
+        } catch (e) {
+            Utils.debug('error: ' + e.message);
             callback(false);
-            return;
         }
-
-        let osmSessionID =
-            this._extractOSMSessionID(message.response_headers);
-        let osmSessionToken =
-            this._extractToken(message.response_body.data);
-
-        if (osmSessionID === null || osmSessionToken === null) {
-            callback(false, null);
-            return;
-        }
-
-        this._login(username, password, osmSessionID, osmSessionToken, callback);
-    }
-
-    _login(username, password, sessionId, token, callback) {
-        /* post login form */
-        let msg = Soup.form_request_new_from_hash('POST', LOGIN_URL,
-                                                  {username: username,
-                                                   password: password,
-                                                   referer: '/',
-                                                   commit: 'Login',
-                                                   authenticity_token: token});
-        let requestHeaders = msg.request_headers;
-
-        requestHeaders.append('Content-Type',
-                              'application/x-www-form-urlencoded');
-        requestHeaders.append('Cookie', '_osm_session=' + sessionId);
-        msg.flags |= Soup.MessageFlags.NO_REDIRECT;
-
-        this._session.queue_message(msg, (obj, message) => {
-            if (message.status_code === Soup.Status.MOVED_TEMPORARILY)
-                this._fetchAuthorizeForm(username, sessionId, callback);
-            else
-                callback(false, null);
-        });
-
-    }
-
-    _fetchAuthorizeForm(username, sessionId, callback) {
-        let auth = '/authorize?oauth_token=';
-        let authorizeUrl = OAUTH_ENDPOINT_URL + auth + this._oauthToken;
-        let uri = new Soup.URI(authorizeUrl);
-        let msg = new Soup.Message({uri: uri, method: 'GET'});
-
-        msg.request_headers.append('Cookie',
-                                   '_osm_session=' + sessionId +
-                                   '; _osm_username=' + username);
-        this._session.queue_message(msg, (obj, message) => {
-            if (message.status_code === Soup.Status.OK) {
-                let token = this._extractToken(message.response_body.data);
-                this._postAuthorizeForm(username, sessionId, token, callback);
-            } else {
-                callback(false, null);
-            }
-        });
-    }
-
-    _postAuthorizeForm(username, sessionId, token, callback) {
-        let authorizeUrl = OAUTH_ENDPOINT_URL + '/authorize';
-        let msg = Soup.form_request_new_from_hash('POST', authorizeUrl, {
-            oauth_token: this._oauthToken,
-            oauth_callback: '',
-            authenticity_token: token,
-            allow_write_api: '1',
-            commit: 'Save changes'
-        });
-        let requestHeaders = msg.request_headers;
-
-        requestHeaders.append('Content-Type',
-                              'application/x-www-form-urlencoded');
-        requestHeaders.append('Cookie',
-                              '_osm_session=' + sessionId +
-                              '; _osm_username=' + username);
-
-        this._session.queue_message(msg, (obj, message) => {
-            if (msg.status_code === Soup.Status.OK) {
-                callback(true, message.response_body.data);
-            } else
-                callback(false, null);
-        });
     }
 
     requestOAuthAccessToken(code, callback) {
@@ -342,6 +261,37 @@ var OSMConnection = class OSMConnection {
         }, this._oauthProxy);
     }
 
+    fetchLoggedInUser(callback) {
+        let call = this._callProxy.new_call();
+        call.set_method('GET');
+        call.set_function('/user/details');
+
+        call.invoke_async(null, (call, res, userdata) =>
+                                { this._onFetchedLoggedInUser(call, callback); });
+    }
+
+    _onFetchedLoggedInUser(call, callback) {
+        switch (call.get_status_code()) {
+            case Soup.Status.OK:
+                try {
+                    callback(Maps.osm_parse_user_details(call.get_payload()));
+                } catch (e) {
+                    Utils.debug('Error parsing user details: ' + e.message);
+                    callback(null);
+                }
+                break;
+            default:
+                /* Not ok, most likely 403 (forbidden), meaning the user
+                 * didn't give permission to read user details.
+                 * Just consider the user name unknown in this case
+                 */
+                Utils.debug('Got status code ' + call.get_status_code() +
+                            ' getting user details');
+                callback(null);
+                break;
+        }
+    }
+
     _onAccessOAuthToken(error, callback) {
         if (error) {
             callback(false);
@@ -389,44 +339,6 @@ var OSMConnection = class OSMConnection {
     _onPasswordCleared(source, result) {
         Secret.password_clear_finish(result);
     }
-
-    /* extract the session ID from the login form response headers */
-    _extractOSMSessionID(responseHeaders) {
-        let cookie = responseHeaders.get('Set-Cookie');
-
-        if (cookie === null)
-            return null;
-
-        let cookieParts = cookie.split(';');
-        for (let cookiePart of cookieParts) {
-            let kvPair = cookiePart.trim().split('=');
-            let kv = kvPair;
-
-            if (kv.length !== 2) {
-                continue;
-            } else if (kv[0] === '_osm_session') {
-                return kv[1];
-            }
-        }
-
-        return null;
-    }
-
-    /* extract the authenticity token from the hidden input field of the login
-       form */
-    _extractToken(messageBody) {
-        let regex = /.*authenticity_token.*value=\"([^\"]+)\".*/;
-        let lines = messageBody.split('\n');
-
-        for (let line of lines) {
-            let match = line.match(regex);
-
-            if (match && match.length === 2)
-                return match[1];
-        }
-
-        return null;
-    }
 };
 
 /*
diff --git a/src/osmEdit.js b/src/osmEdit.js
index fa1a7e5d..bd3d6256 100644
--- a/src/osmEdit.js
+++ b/src/osmEdit.js
@@ -142,21 +142,16 @@ var OSMEdit = class OSMEdit {
         this._osmConnection.closeChangeset(changesetId, callback);
     }
 
-    performOAuthSignIn(username, password, callback) {
+    performOAuthSignIn(callback) {
         this._osmConnection.requestOAuthToken((success) => {
-            if (success)
-                this._onOAuthTokenRequested(username, password, callback);
-            else
-                callback(false, null);
+            if (success) {
+                this._osmConnection.authorizeOAuthToken(callback);
+            } else {
+                callback(false);
+            }
         });
     }
 
-    _onOAuthTokenRequested(username, password, callback) {
-        /* keep track of authorizing username */
-        this._username = username;
-        this._osmConnection.authorizeOAuthToken(username, password, callback);
-    }
-
     requestOAuthAccessToken(code, callback) {
         this._osmConnection.requestOAuthAccessToken(code, (success, token) => {
             this._onOAuthAccessTokenRequested(success, callback);
@@ -165,14 +160,20 @@ var OSMEdit = class OSMEdit {
 
     _onOAuthAccessTokenRequested(success, callback) {
         if (success) {
-            this._isSignedIn = true;
-            Application.settings.set('osm-username', this._username);
+            this._osmConnection.fetchLoggedInUser((username) => {
+                this._isSignedIn = true;
+                /* if we couldn't retrieve the logged-in username,
+                 * e.g. if the user de-selected the permission when
+                 * authorizing the OAuth token, use a dummy placeholder
+                 * username to signify that we are signed in
+                 */
+                this._username = username ?? '_unknown_';
+                Application.settings.set('osm-username', this._username);
+                callback(true);
+            });
         } else {
-            /* clear out username if verification was unsuccessful */
-            this._username = null;
+            callback(false);
         }
-
-        callback(success);
     }
 
     signOut() {


[Date Prev][Date Next]   [Thread Prev][Thread Next]   [Thread Index] [Date Index] [Author Index]