Skip to content
This repository has been archived by the owner on Oct 17, 2019. It is now read-only.

Commit

Permalink
Implement user registration with reCAPTCHA
Browse files Browse the repository at this point in the history
fixes #264
  • Loading branch information
mujx committed Mar 12, 2018
1 parent 39a8150 commit 4659d0e
Show file tree
Hide file tree
Showing 17 changed files with 211 additions and 136 deletions.
3 changes: 2 additions & 1 deletion CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -144,6 +144,7 @@ set(SRC_FILES
src/dialogs/LeaveRoom.cc
src/dialogs/Logout.cc
src/dialogs/ReadReceipts.cc
src/dialogs/ReCaptcha.cpp

# Emoji
src/emoji/Category.cc
Expand Down Expand Up @@ -192,7 +193,6 @@ set(SRC_FILES
src/MainWindow.cc
src/MatrixClient.cc
src/QuickSwitcher.cc
src/Register.cc
src/RegisterPage.cc
src/RoomInfoListItem.cc
src/RoomList.cc
Expand Down Expand Up @@ -238,6 +238,7 @@ qt5_wrap_cpp(MOC_HEADERS
include/dialogs/LeaveRoom.h
include/dialogs/Logout.h
include/dialogs/ReadReceipts.h
include/dialogs/ReCaptcha.hpp

# Emoji
include/emoji/Category.h
Expand Down
2 changes: 2 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@ nheko
[![Latest Release](https://img.shields.io/github/release/mujx/nheko.svg)](https://github.com/mujx/nheko/releases)
[![Chat on Matrix](https://img.shields.io/badge/chat-on%20matrix-blue.svg)](https://matrix.to/#/#nheko:matrix.org)
[![AUR: nheko-git](https://img.shields.io/badge/AUR-nheko--git-blue.svg)](https://aur.archlinux.org/packages/nheko-git)
[![AUR: nheko](https://img.shields.io/badge/AUR-nheko-blue.svg)](https://aur.archlinux.org/packages/nheko)

The motivation behind the project is to provide a native desktop app for [Matrix] that
feels more like a mainstream chat app ([Riot], Telegram etc) and less like an IRC client.
Expand All @@ -14,6 +15,7 @@ feels more like a mainstream chat app ([Riot], Telegram etc) and less like an IR
Most of the features you would expect from a chat application are missing right now
but we are getting close to a more feature complete client.
Specifically there is support for:
- User registration.
- Creating, joining & leaving rooms.
- Sending & receiving invites.
- Sending & receiving files and emoji (inline widgets for images, audio and file messages).
Expand Down
2 changes: 1 addition & 1 deletion cmake/MatrixStructs.cmake
Original file line number Diff line number Diff line change
Expand Up @@ -23,7 +23,7 @@ ExternalProject_Add(
MatrixStructs

GIT_REPOSITORY https://github.com/mujx/matrix-structs
GIT_TAG a1beea3b115f037e26c15f22ed911341b3893411
GIT_TAG 850100c0ac2b5a04720b2a1f09270749bf99f7dd

BUILD_IN_SOURCE 1
SOURCE_DIR ${MATRIX_STRUCTS_ROOT}
Expand Down
2 changes: 1 addition & 1 deletion include/LoginPage.h
Original file line number Diff line number Diff line change
Expand Up @@ -41,7 +41,7 @@ class LoginPage : public QWidget
signals:
void backButtonClicked();
void loggingIn();
void errorOccured();
void errorOccurred();

protected:
void paintEvent(QPaintEvent *event) override;
Expand Down
1 change: 1 addition & 0 deletions include/MainWindow.h
Original file line number Diff line number Diff line change
Expand Up @@ -49,6 +49,7 @@ class InviteUsers;
class JoinRoom;
class LeaveRoom;
class Logout;
class ReCaptcha;
}

class MainWindow : public QMainWindow
Expand Down
7 changes: 6 additions & 1 deletion include/MatrixClient.h
Original file line number Diff line number Diff line change
Expand Up @@ -54,7 +54,8 @@ class MatrixClient : public QNetworkAccessManager
void login(const QString &username, const QString &password) noexcept;
void registerUser(const QString &username,
const QString &password,
const QString &server) noexcept;
const QString &server,
const QString &session = "") noexcept;
void versions() noexcept;
void fetchRoomAvatar(const QString &roomid, const QUrl &avatar_url);
//! Download user's avatar.
Expand Down Expand Up @@ -109,6 +110,10 @@ public slots:
signals:
void loginError(const QString &error);
void registerError(const QString &error);
void registrationFlow(const QString &user,
const QString &pass,
const QString &server,
const QString &session);
void versionError(const QString &error);

void loggedOut();
Expand Down
52 changes: 0 additions & 52 deletions include/Register.h

This file was deleted.

9 changes: 9 additions & 0 deletions include/RegisterPage.h
Original file line number Diff line number Diff line change
Expand Up @@ -20,12 +20,17 @@
#include <QLabel>
#include <QLayout>
#include <QSharedPointer>
#include <memory>

class FlatButton;
class MatrixClient;
class RaisedButton;
class TextField;

namespace dialogs {
class ReCaptcha;
}

class RegisterPage : public QWidget
{
Q_OBJECT
Expand All @@ -38,6 +43,8 @@ class RegisterPage : public QWidget

signals:
void backButtonClicked();
void errorOccurred();
void registering();

private slots:
void onBackButtonClicked();
Expand Down Expand Up @@ -70,4 +77,6 @@ private slots:

// Matrix client API provider.
QSharedPointer<MatrixClient> client_;
//! ReCaptcha dialog.
std::shared_ptr<dialogs::ReCaptcha> captchaDialog_;
};
28 changes: 28 additions & 0 deletions include/dialogs/ReCaptcha.hpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,28 @@
#pragma once

#include <QWidget>

class FlatButton;
class RaisedButton;

namespace dialogs {

class ReCaptcha : public QWidget
{
Q_OBJECT

public:
ReCaptcha(const QString &server, const QString &session, QWidget *parent = nullptr);

protected:
void paintEvent(QPaintEvent *event) override;

signals:
void closing();

private:
FlatButton *openCaptchaBtn_;
RaisedButton *confirmBtn_;
RaisedButton *cancelBtn_;
};
} // dialogs
1 change: 1 addition & 0 deletions resources/styles/nheko-dark.qss
Original file line number Diff line number Diff line change
Expand Up @@ -101,6 +101,7 @@ Avatar {
}

dialogs--Logout,
dialogs--ReCaptcha,
dialogs--LeaveRoom,
dialogs--CreateRoom,
dialogs--InviteUsers,
Expand Down
1 change: 1 addition & 0 deletions resources/styles/nheko.qss
Original file line number Diff line number Diff line change
Expand Up @@ -104,6 +104,7 @@ Avatar {
}

dialogs--Logout,
dialogs--ReCaptcha,
dialogs--LeaveRoom,
dialogs--CreateRoom,
dialogs--InviteUsers,
Expand Down
2 changes: 1 addition & 1 deletion src/LoginPage.cc
Original file line number Diff line number Diff line change
Expand Up @@ -144,7 +144,7 @@ LoginPage::LoginPage(QSharedPointer<MatrixClient> client, QWidget *parent)
connect(password_input_, SIGNAL(returnPressed()), login_button_, SLOT(click()));
connect(serverInput_, SIGNAL(returnPressed()), login_button_, SLOT(click()));
connect(client_.data(), SIGNAL(loginError(QString)), this, SLOT(loginError(QString)));
connect(client_.data(), SIGNAL(loginError(QString)), this, SIGNAL(errorOccured()));
connect(client_.data(), SIGNAL(loginError(QString)), this, SIGNAL(errorOccurred()));
connect(matrixid_input_, SIGNAL(editingFinished()), this, SLOT(onMatrixIdEntered()));
connect(client_.data(), SIGNAL(versionError(QString)), this, SLOT(versionError(QString)));
connect(client_.data(), SIGNAL(versionSuccess()), this, SLOT(versionSuccess()));
Expand Down
12 changes: 11 additions & 1 deletion src/MainWindow.cc
Original file line number Diff line number Diff line change
Expand Up @@ -85,7 +85,12 @@ MainWindow::MainWindow(QWidget *parent)
connect(login_page_, SIGNAL(backButtonClicked()), this, SLOT(showWelcomePage()));
connect(login_page_, &LoginPage::loggingIn, this, &MainWindow::showOverlayProgressBar);
connect(
login_page_, &LoginPage::errorOccured, this, [this]() { removeOverlayProgressBar(); });
register_page_, &RegisterPage::registering, this, &MainWindow::showOverlayProgressBar);
connect(
login_page_, &LoginPage::errorOccurred, this, [this]() { removeOverlayProgressBar(); });
connect(register_page_, &RegisterPage::errorOccurred, this, [this]() {
removeOverlayProgressBar();
});
connect(register_page_, SIGNAL(backButtonClicked()), this, SLOT(showWelcomePage()));

connect(chat_page_, SIGNAL(close()), this, SLOT(showWelcomePage()));
Expand Down Expand Up @@ -120,6 +125,11 @@ MainWindow::MainWindow(QWidget *parent)
this,
SLOT(showChatPage(QString, QString, QString)));

connect(client_.data(),
SIGNAL(registerSuccess(QString, QString, QString)),
this,
SLOT(showChatPage(QString, QString, QString)));

QShortcut *quitShortcut = new QShortcut(QKeySequence::Quit, this);
connect(quitShortcut, &QShortcut::activated, this, QApplication::quit);

Expand Down
67 changes: 42 additions & 25 deletions src/MatrixClient.cc
Original file line number Diff line number Diff line change
Expand Up @@ -27,9 +27,10 @@
#include <QPixmap>
#include <QSettings>
#include <QUrlQuery>
#include <mtx/errors.hpp>

#include "Deserializable.h"
#include "MatrixClient.h"
#include "Register.h"

MatrixClient::MatrixClient(QString server, QObject *parent)
: QNetworkAccessManager(parent)
Expand Down Expand Up @@ -193,50 +194,66 @@ MatrixClient::logout() noexcept
}

void
MatrixClient::registerUser(const QString &user, const QString &pass, const QString &server) noexcept
MatrixClient::registerUser(const QString &user,
const QString &pass,
const QString &server,
const QString &session) noexcept
{
setServer(server);

QUrlQuery query;
query.addQueryItem("kind", "user");

QUrl endpoint(server_);
endpoint.setPath(clientApiUrl_ + "/register");
endpoint.setQuery(query);

QNetworkRequest request(QString(endpoint.toEncoded()));
request.setHeader(QNetworkRequest::ContentTypeHeader, "application/json");

RegisterRequest body(user, pass);
auto reply = post(request, body.serialize());
QJsonObject body{{"username", user}, {"password", pass}};

connect(reply, &QNetworkReply::finished, this, [this, reply]() {
// We trying to register using the response from the recaptcha.
if (!session.isEmpty())
body = QJsonObject{
{"username", user},
{"password", pass},
{"auth", QJsonObject{{"type", "m.login.recaptcha"}, {"session", session}}}};

auto reply = post(request, QJsonDocument(body).toJson(QJsonDocument::Compact));

connect(reply, &QNetworkReply::finished, this, [this, reply, user, pass, server]() {
reply->deleteLater();

int status = reply->attribute(QNetworkRequest::HttpStatusCodeAttribute).toInt();

auto data = reply->readAll();
auto json = QJsonDocument::fromJson(data);

if (status == 0 || status >= 400) {
if (json.isObject() && json.object().contains("error"))
emit registerError(json.object().value("error").toString());
else
emit registerError(reply->errorString());
// Try to parse a regular register response.
try {
mtx::responses::Register res = nlohmann::json::parse(data);
emit registerSuccess(QString::fromStdString(res.user_id.toString()),
QString::fromStdString(res.user_id.hostname()),
QString::fromStdString(res.access_token));
} catch (const std::exception &e) {
qWarning() << "Register" << e.what();
}

// Check if the server requires a registration flow.
try {
mtx::responses::RegistrationFlows res = nlohmann::json::parse(data);
emit registrationFlow(
user, pass, server, QString::fromStdString(res.session));
return;
} catch (const std::exception &) {
}

RegisterResponse response;

try {
response.deserialize(json);
emit registerSuccess(response.getUserId(),
response.getHomeServer(),
response.getAccessToken());
} catch (DeserializationException &e) {
qWarning() << "Register" << e.what();
emit registerError("Received malformed response.");
// We encountered an unknown error.
if (status == 0 || status >= 400) {
try {
mtx::errors::Error res = nlohmann::json::parse(data);
emit registerError(QString::fromStdString(res.error));
return;
} catch (const std::exception &) {
}

emit registerError(reply->errorString());
}
});
}
Expand Down
Loading

1 comment on commit 4659d0e

@anoadragon453
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Nice!

Please sign in to comment.