summary refs log tree commit diff
path: root/src
diff options
context:
space:
mode:
authorNicolas Werner <nicolas.werner@hotmail.de>2021-11-03 18:36:12 +0100
committerNicolas Werner <nicolas.werner@hotmail.de>2021-11-03 18:39:51 +0100
commit211fd9d76cfd691eceb8c77297ee20fd0fde4bbb (patch)
tree287451ffac2b9eb556dd6d57578a6fbdee591913 /src
parentMerge branch 'macos_api_updates' into 'master' (diff)
downloadnheko-211fd9d76cfd691eceb8c77297ee20fd0fde4bbb.tar.xz
Fix registration on matrix.org
This was a bit of a journey:
https://github.com/matrix-org/matrix-doc/pull/3471
But it should work now and we now use the UIAHandler everywhere.

fixes #670
Diffstat (limited to '')
-rw-r--r--src/RegisterPage.cpp123
-rw-r--r--src/RegisterPage.h4
-rw-r--r--src/ui/UIA.cpp146
-rw-r--r--src/ui/UIA.h17
4 files changed, 168 insertions, 122 deletions
diff --git a/src/RegisterPage.cpp b/src/RegisterPage.cpp
index 0204a307..271a7fc2 100644
--- a/src/RegisterPage.cpp
+++ b/src/RegisterPage.cpp
@@ -23,6 +23,7 @@
 #include "ui/FlatButton.h"
 #include "ui/RaisedButton.h"
 #include "ui/TextField.h"
+#include "ui/UIA.h"
 
 #include "dialogs/FallbackAuth.h"
 #include "dialogs/ReCaptcha.h"
@@ -178,8 +179,6 @@ RegisterPage::RegisterPage(QWidget *parent)
     connect(this, &RegisterPage::wellKnownLookup, this, &RegisterPage::doWellKnownLookup);
     connect(this, &RegisterPage::versionsCheck, this, &RegisterPage::doVersionsCheck);
     connect(this, &RegisterPage::registration, this, &RegisterPage::doRegistration);
-    connect(this, &RegisterPage::UIA, this, &RegisterPage::doUIA);
-    connect(this, &RegisterPage::registrationWithAuth, this, &RegisterPage::doRegistrationWithAuth);
 }
 
 void
@@ -277,18 +276,11 @@ RegisterPage::onRegisterButtonClicked()
         //
         // The sequence of events looks something like this:
         //
-        // dowellKnownLookup
+        // doKnownLookup
         //   v
         // doVersionsCheck
         //   v
-        // doRegistration
-        //   v
-        // doUIA <-----------------+
-        //   v					   | More auth required
-        // doRegistrationWithAuth -+
-        //                         | Success
-        // 						   v
-        //                     registering
+        // doRegistration -> loops the UIAHandler until complete
 
         emit wellKnownLookup();
 
@@ -367,18 +359,12 @@ RegisterPage::doRegistration()
     if (checkUsername() && checkPassword() && checkPasswordConfirmation()) {
         auto username = username_input_->text().toStdString();
         auto password = password_input_->text().toStdString();
-        http::client()->registration(username, password, registrationCb());
-    }
-}
-
-void
-RegisterPage::doRegistrationWithAuth(const mtx::user_interactive::Auth &auth)
-{
-    // These inputs should still be alright, but check just in case
-    if (checkUsername() && checkPassword() && checkPasswordConfirmation()) {
-        auto username = username_input_->text().toStdString();
-        auto password = password_input_->text().toStdString();
-        http::client()->registration(username, password, auth, registrationCb());
+        connect(UIA::instance(), &UIA::error, this, [this](QString msg) {
+            showError(msg);
+            disconnect(UIA::instance(), &UIA::error, this, nullptr);
+        });
+        http::client()->registration(
+          username, password, ::UIA::instance()->genericHandler("Registration"), registrationCb());
     }
 }
 
@@ -392,6 +378,7 @@ RegisterPage::registrationCb()
             http::client()->set_user(res.user_id);
             http::client()->set_access_token(res.access_token);
             emit registerOk();
+            disconnect(UIA::instance(), &UIA::error, this, nullptr);
             return;
         }
 
@@ -403,11 +390,7 @@ RegisterPage::registrationCb()
                                    static_cast<int>(err->status_code),
                                    err->matrix_error.error);
                 showError(QString::fromStdString(err->matrix_error.error));
-                return;
             }
-
-            // Attempt to complete a UIA stage
-            emit UIA(err->matrix_error.unauthorized);
             return;
         }
 
@@ -420,92 +403,6 @@ RegisterPage::registrationCb()
 }
 
 void
-RegisterPage::doUIA(const mtx::user_interactive::Unauthorized &unauthorized)
-{
-    auto completed_stages = unauthorized.completed;
-    auto flows            = unauthorized.flows;
-    auto session =
-      unauthorized.session.empty() ? http::client()->generate_txn_id() : unauthorized.session;
-
-    nhlog::ui()->info("Completed stages: {}", completed_stages.size());
-
-    if (!completed_stages.empty()) {
-        // Get rid of all flows which don't start with the sequence of
-        // stages that have already been completed.
-        flows.erase(std::remove_if(flows.begin(),
-                                   flows.end(),
-                                   [completed_stages](auto flow) {
-                                       if (completed_stages.size() > flow.stages.size())
-                                           return true;
-                                       for (size_t f = 0; f < completed_stages.size(); f++)
-                                           if (completed_stages[f] != flow.stages[f])
-                                               return true;
-                                       return false;
-                                   }),
-                    flows.end());
-    }
-
-    if (flows.empty()) {
-        nhlog::ui()->error("No available registration flows!");
-        showError(tr("No supported registration flows!"));
-        return;
-    }
-
-    auto current_stage = flows.front().stages.at(completed_stages.size());
-
-    if (current_stage == mtx::user_interactive::auth_types::recaptcha) {
-        auto captchaDialog = new dialogs::ReCaptcha(QString::fromStdString(session), this);
-
-        connect(
-          captchaDialog, &dialogs::ReCaptcha::confirmation, this, [this, session, captchaDialog]() {
-              captchaDialog->close();
-              captchaDialog->deleteLater();
-              doRegistrationWithAuth(
-                mtx::user_interactive::Auth{session, mtx::user_interactive::auth::Fallback{}});
-          });
-
-        connect(captchaDialog, &dialogs::ReCaptcha::cancel, this, &RegisterPage::errorOccurred);
-
-        QTimer::singleShot(1000, this, [captchaDialog]() { captchaDialog->show(); });
-
-    } else if (current_stage == mtx::user_interactive::auth_types::dummy) {
-        doRegistrationWithAuth(
-          mtx::user_interactive::Auth{session, mtx::user_interactive::auth::Dummy{}});
-
-    } else if (current_stage == mtx::user_interactive::auth_types::registration_token) {
-        bool ok;
-        QString token = QInputDialog::getText(this,
-                                              tr("Registration token"),
-                                              tr("Please enter a valid registration token."),
-                                              QLineEdit::Normal,
-                                              QString(),
-                                              &ok);
-
-        if (ok) {
-            emit registrationWithAuth(mtx::user_interactive::Auth{
-              session, mtx::user_interactive::auth::RegistrationToken{token.toStdString()}});
-        } else {
-            emit errorOccurred();
-        }
-    } else {
-        // use fallback
-        auto dialog = new dialogs::FallbackAuth(
-          QString::fromStdString(current_stage), QString::fromStdString(session), this);
-
-        connect(dialog, &dialogs::FallbackAuth::confirmation, this, [this, session, dialog]() {
-            dialog->close();
-            dialog->deleteLater();
-            emit registrationWithAuth(
-              mtx::user_interactive::Auth{session, mtx::user_interactive::auth::Fallback{}});
-        });
-
-        connect(dialog, &dialogs::FallbackAuth::cancel, this, &RegisterPage::errorOccurred);
-
-        dialog->show();
-    }
-}
-
-void
 RegisterPage::paintEvent(QPaintEvent *)
 {
     QStyleOption opt;
diff --git a/src/RegisterPage.h b/src/RegisterPage.h
index b88808f9..0d7da9ad 100644
--- a/src/RegisterPage.h
+++ b/src/RegisterPage.h
@@ -39,8 +39,6 @@ signals:
     void wellKnownLookup();
     void versionsCheck();
     void registration();
-    void UIA(const mtx::user_interactive::Unauthorized &unauthorized);
-    void registrationWithAuth(const mtx::user_interactive::Auth &auth);
 
     void registering();
     void registerOk();
@@ -62,8 +60,6 @@ private slots:
     void doWellKnownLookup();
     void doVersionsCheck();
     void doRegistration();
-    void doUIA(const mtx::user_interactive::Unauthorized &unauthorized);
-    void doRegistrationWithAuth(const mtx::user_interactive::Auth &auth);
     mtx::http::Callback<mtx::responses::Register> registrationCb();
 
 private:
diff --git a/src/ui/UIA.cpp b/src/ui/UIA.cpp
index 29161382..c157ea0f 100644
--- a/src/ui/UIA.cpp
+++ b/src/ui/UIA.cpp
@@ -9,6 +9,8 @@
 #include <QInputDialog>
 #include <QTimer>
 
+#include <mtx/responses/common.hpp>
+
 #include "Logging.h"
 #include "MainWindow.h"
 #include "dialogs/FallbackAuth.h"
@@ -54,6 +56,7 @@ UIA::genericHandler(QString context)
 
             if (flows.empty()) {
                 nhlog::ui()->error("No available registration flows!");
+                emit error(tr("No available registration flows!"));
                 return;
             }
 
@@ -61,6 +64,10 @@ UIA::genericHandler(QString context)
 
             if (current_stage == mtx::user_interactive::auth_types::password) {
                 emit password();
+            } else if (current_stage == mtx::user_interactive::auth_types::email_identity) {
+                emit email();
+            } else if (current_stage == mtx::user_interactive::auth_types::msisdn) {
+                emit phoneNumber();
             } else if (current_stage == mtx::user_interactive::auth_types::recaptcha) {
                 auto captchaDialog =
                   new dialogs::ReCaptcha(QString::fromStdString(u.session), MainWindow::instance());
@@ -74,8 +81,9 @@ UIA::genericHandler(QString context)
                                                          mtx::user_interactive::auth::Fallback{}});
                   });
 
-                // connect(
-                //  captchaDialog, &dialogs::ReCaptcha::cancel, this, &RegisterPage::errorOccurred);
+                connect(captchaDialog, &dialogs::ReCaptcha::cancel, this, [this]() {
+                    emit error(tr("Registration aborted"));
+                });
 
                 QTimer::singleShot(0, this, [captchaDialog]() { captchaDialog->show(); });
 
@@ -98,7 +106,7 @@ UIA::genericHandler(QString context)
                       u.session,
                       mtx::user_interactive::auth::RegistrationToken{token.toStdString()}});
                 } else {
-                    // emit errorOccurred();
+                    emit error(tr("Registration aborted"));
                 }
             } else {
                 // use fallback
@@ -114,8 +122,9 @@ UIA::genericHandler(QString context)
                                                        mtx::user_interactive::auth::Fallback{}});
                 });
 
-                // connect(dialog, &dialogs::FallbackAuth::cancel, this,
-                // &RegisterPage::errorOccurred);
+                connect(dialog, &dialogs::FallbackAuth::cancel, this, [this]() {
+                    emit error(tr("Registration aborted"));
+                });
 
                 dialog->show();
             }
@@ -134,3 +143,130 @@ UIA::continuePassword(QString password)
     if (currentHandler)
         currentHandler->next(mtx::user_interactive::Auth{currentStatus.session, p});
 }
+
+void
+UIA::continueEmail(QString email)
+{
+    mtx::requests::RequestEmailToken r{};
+    r.client_secret = this->client_secret = mtx::client::utils::random_token(128, false);
+    r.email                               = email.toStdString();
+    r.send_attempt                        = 0;
+    http::client()->register_email_request_token(
+      r, [this](const mtx::responses::RequestToken &token, mtx::http::RequestErr e) {
+          if (!e) {
+              this->sid        = token.sid;
+              this->submit_url = token.submit_url;
+              this->email_     = true;
+
+              if (submit_url.empty()) {
+                  nhlog::ui()->debug("Got no submit url.");
+                  emit confirm3pidToken();
+              } else {
+                  nhlog::ui()->debug("Got submit url: {}", token.submit_url);
+                  emit prompt3pidToken();
+              }
+          } else {
+              nhlog::ui()->debug("Registering email failed! ({},{},{},{})",
+                                 e->status_code,
+                                 e->status_code,
+                                 e->parse_error,
+                                 e->matrix_error.error);
+              emit error(QString::fromStdString(e->matrix_error.error));
+          }
+      });
+}
+void
+UIA::continuePhoneNumber(QString countryCode, QString phoneNumber)
+{
+    mtx::requests::RequestMSISDNToken r{};
+    r.client_secret = this->client_secret = mtx::client::utils::random_token(128, false);
+    r.country                             = countryCode.toStdString();
+    r.phone_number                        = phoneNumber.toStdString();
+    r.send_attempt                        = 0;
+    http::client()->register_phone_request_token(
+      r, [this](const mtx::responses::RequestToken &token, mtx::http::RequestErr e) {
+          if (!e) {
+              this->sid        = token.sid;
+              this->submit_url = token.submit_url;
+              this->email_     = false;
+              if (submit_url.empty()) {
+                  nhlog::ui()->debug("Got no submit url.");
+                  emit confirm3pidToken();
+              } else {
+                  nhlog::ui()->debug("Got submit url: {}", token.submit_url);
+                  emit prompt3pidToken();
+              }
+          } else {
+              nhlog::ui()->debug("Registering phone number failed! ({},{},{},{})",
+                                 e->status_code,
+                                 e->status_code,
+                                 e->parse_error,
+                                 e->matrix_error.error);
+              emit error(QString::fromStdString(e->matrix_error.error));
+          }
+      });
+}
+
+void
+UIA::continue3pidReceived()
+{
+    mtx::user_interactive::auth::ThreePIDCred c{};
+    c.client_secret = this->client_secret;
+    c.sid           = this->sid;
+
+    if (this->email_) {
+        mtx::user_interactive::auth::EmailIdentity i{};
+        i.threepidCred = c;
+        this->currentHandler->next(mtx::user_interactive::Auth{currentStatus.session, i});
+    } else {
+        mtx::user_interactive::auth::MSISDN i{};
+        i.threepidCred = c;
+        this->currentHandler->next(mtx::user_interactive::Auth{currentStatus.session, i});
+    }
+}
+
+void
+UIA::submit3pidToken(QString token)
+{
+    mtx::requests::IdentitySubmitToken t{};
+    t.client_secret = this->client_secret;
+    t.sid           = this->sid;
+    t.token         = token.toStdString();
+
+    http::client()->validate_submit_token(
+      submit_url, t, [this](const mtx::responses::Success &success, mtx::http::RequestErr e) {
+          if (!e && success.success) {
+              mtx::user_interactive::auth::ThreePIDCred c{};
+              c.client_secret = this->client_secret;
+              c.sid           = this->sid;
+
+              nhlog::ui()->debug("Submit token success");
+
+              if (this->email_) {
+                  mtx::user_interactive::auth::EmailIdentity i{};
+                  i.threepidCred = c;
+                  this->currentHandler->next(mtx::user_interactive::Auth{currentStatus.session, i});
+              } else {
+                  mtx::user_interactive::auth::MSISDN i{};
+                  i.threepidCred = c;
+                  this->currentHandler->next(mtx::user_interactive::Auth{currentStatus.session, i});
+              }
+          } else {
+              if (e) {
+                  nhlog::ui()->debug("Submit token invalid! ({},{},{},{})",
+                                     e->status_code,
+                                     e->status_code,
+                                     e->parse_error,
+                                     e->matrix_error.error);
+                  emit error(QString::fromStdString(e->matrix_error.error));
+              } else {
+                  nhlog::ui()->debug("Submit token invalid!");
+                  emit error(tr("Invalid token"));
+              }
+          }
+
+          this->client_secret.clear();
+          this->sid.clear();
+          this->submit_url.clear();
+      });
+}
diff --git a/src/ui/UIA.h b/src/ui/UIA.h
index fb047451..0db23897 100644
--- a/src/ui/UIA.h
+++ b/src/ui/UIA.h
@@ -27,14 +27,31 @@ public:
 
 public slots:
     void continuePassword(QString password);
+    void continueEmail(QString email);
+    void continuePhoneNumber(QString countryCode, QString phoneNumber);
+    void submit3pidToken(QString token);
+    void continue3pidReceived();
 
 signals:
     void password();
+    void email();
+    void phoneNumber();
+
+    void confirm3pidToken();
+    void prompt3pidToken();
+    void tokenAccepted();
 
     void titleChanged();
+    void error(QString msg);
 
 private:
     std::optional<mtx::http::UIAHandler> currentHandler;
     mtx::user_interactive::Unauthorized currentStatus;
     QString title_;
+
+    // for 3pids like email and phone number
+    std::string client_secret;
+    std::string sid;
+    std::string submit_url;
+    bool email_ = true;
 };