mirror of
https://github.com/Nheko-Reborn/nheko.git
synced 2024-11-21 18:50:47 +03:00
parent
fee00746c8
commit
3ef0d9db3c
11 changed files with 308 additions and 90 deletions
|
@ -33,6 +33,7 @@ matrix:
|
|||
- ninja
|
||||
- openssl
|
||||
- qt5
|
||||
update: true # workaround for broken travis homebrew
|
||||
- os: linux
|
||||
compiler: gcc-7
|
||||
env:
|
||||
|
|
|
@ -228,17 +228,18 @@ configure_file(cmake/nheko.h config/nheko.h)
|
|||
set(SRC_FILES
|
||||
# Dialogs
|
||||
src/dialogs/CreateRoom.cpp
|
||||
src/dialogs/FallbackAuth.cpp
|
||||
src/dialogs/ImageOverlay.cpp
|
||||
src/dialogs/PreviewUploadOverlay.cpp
|
||||
src/dialogs/InviteUsers.cpp
|
||||
src/dialogs/JoinRoom.cpp
|
||||
src/dialogs/MemberList.cpp
|
||||
src/dialogs/LeaveRoom.cpp
|
||||
src/dialogs/Logout.cpp
|
||||
src/dialogs/UserProfile.cpp
|
||||
src/dialogs/ReadReceipts.cpp
|
||||
src/dialogs/MemberList.cpp
|
||||
src/dialogs/PreviewUploadOverlay.cpp
|
||||
src/dialogs/ReCaptcha.cpp
|
||||
src/dialogs/ReadReceipts.cpp
|
||||
src/dialogs/RoomSettings.cpp
|
||||
src/dialogs/UserProfile.cpp
|
||||
|
||||
# Emoji
|
||||
src/emoji/Category.cpp
|
||||
|
@ -333,7 +334,7 @@ if(USE_BUNDLED_MTXCLIENT)
|
|||
FetchContent_Declare(
|
||||
MatrixClient
|
||||
GIT_REPOSITORY https://github.com/Nheko-Reborn/mtxclient.git
|
||||
GIT_TAG 5fbee216e640da45c05f25b1f84f03c88bca5910
|
||||
GIT_TAG 5838f607d0e4c7595439249e8b9c213aec0667e9
|
||||
)
|
||||
FetchContent_MakeAvailable(MatrixClient)
|
||||
else()
|
||||
|
@ -424,18 +425,19 @@ feature_summary(WHAT ALL INCLUDE_QUIET_PACKAGES FATAL_ON_MISSING_REQUIRED_PACKAG
|
|||
qt5_wrap_cpp(MOC_HEADERS
|
||||
# Dialogs
|
||||
src/dialogs/CreateRoom.h
|
||||
src/dialogs/FallbackAuth.h
|
||||
src/dialogs/ImageOverlay.h
|
||||
src/dialogs/PreviewUploadOverlay.h
|
||||
src/dialogs/InviteUsers.h
|
||||
src/dialogs/JoinRoom.h
|
||||
src/dialogs/MemberList.h
|
||||
src/dialogs/LeaveRoom.h
|
||||
src/dialogs/Logout.h
|
||||
src/dialogs/UserProfile.h
|
||||
src/dialogs/MemberList.h
|
||||
src/dialogs/PreviewUploadOverlay.h
|
||||
src/dialogs/RawMessage.h
|
||||
src/dialogs/ReadReceipts.h
|
||||
src/dialogs/ReCaptcha.h
|
||||
src/dialogs/ReadReceipts.h
|
||||
src/dialogs/RoomSettings.h
|
||||
src/dialogs/UserProfile.h
|
||||
|
||||
# Emoji
|
||||
src/emoji/Category.h
|
||||
|
|
|
@ -147,9 +147,9 @@
|
|||
"name": "mtxclient",
|
||||
"sources": [
|
||||
{
|
||||
"sha256": "8cf5470570d2ed6affc0bbe0f4b6be9b0a2e2372e9f920b504126841bb73036f",
|
||||
"sha256": "df3fe7e3d59b5fc52ee3ca9a132a55fc325aa799c676e9e420073c56daeb1848",
|
||||
"type": "archive",
|
||||
"url": "https://github.com/Nheko-Reborn/mtxclient/archive/5fbee216e640da45c05f25b1f84f03c88bca5910.tar.gz"
|
||||
"url": "https://github.com/Nheko-Reborn/mtxclient/archive/5838f607d0e4c7595439249e8b9c213aec0667e9.tar.gz"
|
||||
}
|
||||
]
|
||||
},
|
||||
|
|
|
@ -507,3 +507,33 @@ MainWindow::loadJdenticonPlugin()
|
|||
nhlog::ui()->info("jdenticon plugin not found.");
|
||||
return false;
|
||||
}
|
||||
void
|
||||
MainWindow::showWelcomePage()
|
||||
{
|
||||
removeOverlayProgressBar();
|
||||
pageStack_->addWidget(welcome_page_);
|
||||
pageStack_->setCurrentWidget(welcome_page_);
|
||||
}
|
||||
|
||||
void
|
||||
MainWindow::showLoginPage()
|
||||
{
|
||||
if (modal_)
|
||||
modal_->hide();
|
||||
|
||||
pageStack_->addWidget(login_page_);
|
||||
pageStack_->setCurrentWidget(login_page_);
|
||||
}
|
||||
|
||||
void
|
||||
MainWindow::showRegisterPage()
|
||||
{
|
||||
pageStack_->addWidget(register_page_);
|
||||
pageStack_->setCurrentWidget(register_page_);
|
||||
}
|
||||
|
||||
void
|
||||
MainWindow::showUserSettingsPage()
|
||||
{
|
||||
pageStack_->setCurrentWidget(userSettingsPage_);
|
||||
}
|
||||
|
|
|
@ -24,16 +24,17 @@
|
|||
#include <QStackedWidget>
|
||||
#include <QSystemTrayIcon>
|
||||
|
||||
#include "LoginPage.h"
|
||||
#include "RegisterPage.h"
|
||||
#include "UserSettingsPage.h"
|
||||
#include "WelcomePage.h"
|
||||
#include "dialogs/UserProfile.h"
|
||||
#include "ui/OverlayModal.h"
|
||||
|
||||
#include "jdenticoninterface.h"
|
||||
|
||||
class ChatPage;
|
||||
class RegisterPage;
|
||||
class LoginPage;
|
||||
class WelcomePage;
|
||||
|
||||
class LoadingIndicator;
|
||||
class OverlayModal;
|
||||
class SnackBar;
|
||||
|
@ -97,32 +98,16 @@ private slots:
|
|||
void iconActivated(QSystemTrayIcon::ActivationReason reason);
|
||||
|
||||
//! Show the welcome page in the main window.
|
||||
void showWelcomePage()
|
||||
{
|
||||
removeOverlayProgressBar();
|
||||
pageStack_->addWidget(welcome_page_);
|
||||
pageStack_->setCurrentWidget(welcome_page_);
|
||||
}
|
||||
void showWelcomePage();
|
||||
|
||||
//! Show the login page in the main window.
|
||||
void showLoginPage()
|
||||
{
|
||||
if (modal_)
|
||||
modal_->hide();
|
||||
|
||||
pageStack_->addWidget(login_page_);
|
||||
pageStack_->setCurrentWidget(login_page_);
|
||||
}
|
||||
void showLoginPage();
|
||||
|
||||
//! Show the register page in the main window.
|
||||
void showRegisterPage()
|
||||
{
|
||||
pageStack_->addWidget(register_page_);
|
||||
pageStack_->setCurrentWidget(register_page_);
|
||||
}
|
||||
void showRegisterPage();
|
||||
|
||||
//! Show user settings page.
|
||||
void showUserSettingsPage() { pageStack_->setCurrentWidget(userSettingsPage_); }
|
||||
void showUserSettingsPage();
|
||||
|
||||
//! Show the chat page and start communicating with the given access token.
|
||||
void showChatPage();
|
||||
|
|
|
@ -15,6 +15,7 @@
|
|||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#include <QMetaType>
|
||||
#include <QPainter>
|
||||
#include <QStyleOption>
|
||||
#include <QTimer>
|
||||
|
@ -30,11 +31,17 @@
|
|||
#include "ui/RaisedButton.h"
|
||||
#include "ui/TextField.h"
|
||||
|
||||
#include "dialogs/FallbackAuth.h"
|
||||
#include "dialogs/ReCaptcha.h"
|
||||
|
||||
Q_DECLARE_METATYPE(mtx::user_interactive::Unauthorized)
|
||||
Q_DECLARE_METATYPE(mtx::user_interactive::Auth)
|
||||
|
||||
RegisterPage::RegisterPage(QWidget *parent)
|
||||
: QWidget(parent)
|
||||
{
|
||||
qRegisterMetaType<mtx::user_interactive::Unauthorized>();
|
||||
qRegisterMetaType<mtx::user_interactive::Auth>();
|
||||
top_layout_ = new QVBoxLayout();
|
||||
|
||||
back_layout_ = new QHBoxLayout();
|
||||
|
@ -133,46 +140,139 @@ RegisterPage::RegisterPage(QWidget *parent)
|
|||
this,
|
||||
&RegisterPage::registrationFlow,
|
||||
this,
|
||||
[this](const std::string &user, const std::string &pass, const std::string &session) {
|
||||
emit errorOccurred();
|
||||
[this](const std::string &user,
|
||||
const std::string &pass,
|
||||
const mtx::user_interactive::Unauthorized &unauthorized) {
|
||||
auto completed_stages = unauthorized.completed;
|
||||
auto flows = unauthorized.flows;
|
||||
auto session = unauthorized.session;
|
||||
|
||||
auto captchaDialog =
|
||||
new dialogs::ReCaptcha(QString::fromStdString(session), this);
|
||||
nhlog::ui()->info("Completed stages: {}", completed_stages.size());
|
||||
|
||||
connect(captchaDialog,
|
||||
&dialogs::ReCaptcha::confirmation,
|
||||
this,
|
||||
[this, user, pass, session, captchaDialog]() {
|
||||
captchaDialog->close();
|
||||
captchaDialog->deleteLater();
|
||||
if (!completed_stages.empty())
|
||||
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());
|
||||
|
||||
emit registering();
|
||||
if (flows.empty()) {
|
||||
nhlog::net()->error("No available registration flows!");
|
||||
emit registerErrorCb(tr("No supported registration flows!"));
|
||||
return;
|
||||
}
|
||||
|
||||
http::client()->flow_response(
|
||||
user,
|
||||
pass,
|
||||
session,
|
||||
"m.login.recaptcha",
|
||||
[this](const mtx::responses::Register &res,
|
||||
mtx::http::RequestErr err) {
|
||||
if (err) {
|
||||
nhlog::net()->warn(
|
||||
"failed to retrieve registration flows: {}",
|
||||
err->matrix_error.error);
|
||||
emit errorOccurred();
|
||||
emit registerErrorCb(QString::fromStdString(
|
||||
err->matrix_error.error));
|
||||
return;
|
||||
}
|
||||
auto current_stage = flows.front().stages.at(completed_stages.size());
|
||||
|
||||
http::client()->set_user(res.user_id);
|
||||
http::client()->set_access_token(res.access_token);
|
||||
if (current_stage == mtx::user_interactive::auth_types::recaptcha) {
|
||||
auto captchaDialog =
|
||||
new dialogs::ReCaptcha(QString::fromStdString(session), this);
|
||||
|
||||
emit registerOk();
|
||||
});
|
||||
});
|
||||
connect(captchaDialog,
|
||||
&dialogs::ReCaptcha::confirmation,
|
||||
this,
|
||||
[this, user, pass, session, captchaDialog]() {
|
||||
captchaDialog->close();
|
||||
captchaDialog->deleteLater();
|
||||
|
||||
QTimer::singleShot(1000, this, [captchaDialog]() { captchaDialog->show(); });
|
||||
emit registerAuth(
|
||||
user,
|
||||
pass,
|
||||
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) {
|
||||
emit registerAuth(user,
|
||||
pass,
|
||||
mtx::user_interactive::Auth{
|
||||
session, mtx::user_interactive::auth::Dummy{}});
|
||||
} else {
|
||||
// use fallback
|
||||
auto dialog =
|
||||
new dialogs::FallbackAuth(QString::fromStdString(current_stage),
|
||||
QString::fromStdString(session),
|
||||
this);
|
||||
|
||||
connect(dialog,
|
||||
&dialogs::FallbackAuth::confirmation,
|
||||
this,
|
||||
[this, user, pass, session, dialog]() {
|
||||
dialog->close();
|
||||
dialog->deleteLater();
|
||||
|
||||
emit registerAuth(
|
||||
user,
|
||||
pass,
|
||||
mtx::user_interactive::Auth{
|
||||
session, mtx::user_interactive::auth::Fallback{}});
|
||||
});
|
||||
connect(dialog,
|
||||
&dialogs::FallbackAuth::cancel,
|
||||
this,
|
||||
&RegisterPage::errorOccurred);
|
||||
|
||||
dialog->show();
|
||||
}
|
||||
});
|
||||
|
||||
connect(
|
||||
this,
|
||||
&RegisterPage::registerAuth,
|
||||
this,
|
||||
[this](const std::string &user,
|
||||
const std::string &pass,
|
||||
const mtx::user_interactive::Auth &auth) {
|
||||
http::client()->registration(
|
||||
user,
|
||||
pass,
|
||||
auth,
|
||||
[this, user, pass](const mtx::responses::Register &res,
|
||||
mtx::http::RequestErr err) {
|
||||
if (!err) {
|
||||
http::client()->set_user(res.user_id);
|
||||
http::client()->set_access_token(res.access_token);
|
||||
|
||||
emit registerOk();
|
||||
return;
|
||||
}
|
||||
|
||||
// The server requires registration flows.
|
||||
if (err->status_code == boost::beast::http::status::unauthorized) {
|
||||
if (err->matrix_error.unauthorized.session.empty()) {
|
||||
nhlog::net()->warn(
|
||||
"failed to retrieve registration flows: ({}) "
|
||||
"{}",
|
||||
static_cast<int>(err->status_code),
|
||||
err->matrix_error.error);
|
||||
emit registerErrorCb(
|
||||
QString::fromStdString(err->matrix_error.error));
|
||||
return;
|
||||
}
|
||||
|
||||
emit registrationFlow(
|
||||
user, pass, err->matrix_error.unauthorized);
|
||||
return;
|
||||
}
|
||||
|
||||
nhlog::net()->warn("failed to register: status_code ({})",
|
||||
static_cast<int>(err->status_code));
|
||||
|
||||
emit registerErrorCb(QString::fromStdString(err->matrix_error.error));
|
||||
});
|
||||
});
|
||||
|
||||
setLayout(top_layout_);
|
||||
|
@ -225,31 +325,27 @@ RegisterPage::onRegisterButtonClicked()
|
|||
|
||||
// The server requires registration flows.
|
||||
if (err->status_code == boost::beast::http::status::unauthorized) {
|
||||
http::client()->flow_register(
|
||||
username,
|
||||
password,
|
||||
[this, username, password](
|
||||
const mtx::responses::RegistrationFlows &res,
|
||||
mtx::http::RequestErr err) {
|
||||
if (res.session.empty() && err) {
|
||||
nhlog::net()->warn(
|
||||
"failed to retrieve registration flows: ({}) "
|
||||
"{}",
|
||||
static_cast<int>(err->status_code),
|
||||
err->matrix_error.error);
|
||||
emit errorOccurred();
|
||||
emit registerErrorCb(QString::fromStdString(
|
||||
err->matrix_error.error));
|
||||
return;
|
||||
}
|
||||
if (err->matrix_error.unauthorized.session.empty()) {
|
||||
nhlog::net()->warn(
|
||||
"failed to retrieve registration flows: ({}) "
|
||||
"{}",
|
||||
static_cast<int>(err->status_code),
|
||||
err->matrix_error.error);
|
||||
emit errorOccurred();
|
||||
emit registerErrorCb(
|
||||
QString::fromStdString(err->matrix_error.error));
|
||||
return;
|
||||
}
|
||||
|
||||
emit registrationFlow(username, password, res.session);
|
||||
});
|
||||
emit registrationFlow(
|
||||
username, password, err->matrix_error.unauthorized);
|
||||
return;
|
||||
}
|
||||
|
||||
nhlog::net()->warn("failed to register: status_code ({})",
|
||||
static_cast<int>(err->status_code));
|
||||
nhlog::net()->warn(
|
||||
"failed to register: status_code ({}), matrix_error({})",
|
||||
static_cast<int>(err->status_code),
|
||||
err->matrix_error.error);
|
||||
|
||||
emit registerErrorCb(QString::fromStdString(err->matrix_error.error));
|
||||
emit errorOccurred();
|
||||
|
|
|
@ -21,6 +21,8 @@
|
|||
#include <QLayout>
|
||||
#include <memory>
|
||||
|
||||
#include <mtx/user_interactive.hpp>
|
||||
|
||||
class FlatButton;
|
||||
class RaisedButton;
|
||||
class TextField;
|
||||
|
@ -43,7 +45,10 @@ signals:
|
|||
void registerErrorCb(const QString &msg);
|
||||
void registrationFlow(const std::string &user,
|
||||
const std::string &pass,
|
||||
const std::string &session);
|
||||
const mtx::user_interactive::Unauthorized &unauthorized);
|
||||
void registerAuth(const std::string &user,
|
||||
const std::string &pass,
|
||||
const mtx::user_interactive::Auth &auth);
|
||||
|
||||
private slots:
|
||||
void onBackButtonClicked();
|
||||
|
|
69
src/dialogs/FallbackAuth.cpp
Normal file
69
src/dialogs/FallbackAuth.cpp
Normal file
|
@ -0,0 +1,69 @@
|
|||
#include <QDesktopServices>
|
||||
#include <QLabel>
|
||||
#include <QPushButton>
|
||||
#include <QUrl>
|
||||
#include <QVBoxLayout>
|
||||
|
||||
#include "dialogs/FallbackAuth.h"
|
||||
|
||||
#include "Config.h"
|
||||
#include "MatrixClient.h"
|
||||
|
||||
using namespace dialogs;
|
||||
|
||||
FallbackAuth::FallbackAuth(const QString &authType, const QString &session, QWidget *parent)
|
||||
: QWidget(parent)
|
||||
{
|
||||
setAutoFillBackground(true);
|
||||
setWindowFlags(Qt::Tool | Qt::WindowStaysOnTopHint);
|
||||
setWindowModality(Qt::WindowModal);
|
||||
setAttribute(Qt::WA_DeleteOnClose, true);
|
||||
|
||||
auto layout = new QVBoxLayout(this);
|
||||
layout->setSpacing(conf::modals::WIDGET_SPACING);
|
||||
layout->setMargin(conf::modals::WIDGET_MARGIN);
|
||||
|
||||
auto buttonLayout = new QHBoxLayout();
|
||||
buttonLayout->setSpacing(8);
|
||||
buttonLayout->setMargin(0);
|
||||
|
||||
openBtn_ = new QPushButton(tr("Open Fallback in Browser"), this);
|
||||
cancelBtn_ = new QPushButton(tr("Cancel"), this);
|
||||
confirmBtn_ = new QPushButton(tr("Confirm"), this);
|
||||
confirmBtn_->setDefault(true);
|
||||
|
||||
buttonLayout->addStretch(1);
|
||||
buttonLayout->addWidget(openBtn_);
|
||||
buttonLayout->addWidget(cancelBtn_);
|
||||
buttonLayout->addWidget(confirmBtn_);
|
||||
|
||||
QFont font;
|
||||
font.setPointSizeF(font.pointSizeF() * conf::modals::LABEL_MEDIUM_SIZE_RATIO);
|
||||
|
||||
auto label = new QLabel(
|
||||
tr("Open the fallback, follow the steps and confirm after completing them."), this);
|
||||
label->setFont(font);
|
||||
|
||||
layout->addWidget(label);
|
||||
layout->addLayout(buttonLayout);
|
||||
|
||||
connect(openBtn_, &QPushButton::clicked, [session, authType]() {
|
||||
const auto url = QString("https://%1:%2/_matrix/client/r0/auth/%4/"
|
||||
"fallback/web?session=%3")
|
||||
.arg(QString::fromStdString(http::client()->server()))
|
||||
.arg(http::client()->port())
|
||||
.arg(session)
|
||||
.arg(authType);
|
||||
|
||||
QDesktopServices::openUrl(url);
|
||||
});
|
||||
|
||||
connect(confirmBtn_, &QPushButton::clicked, this, [this]() {
|
||||
emit confirmation();
|
||||
emit close();
|
||||
});
|
||||
connect(cancelBtn_, &QPushButton::clicked, this, [this]() {
|
||||
emit cancel();
|
||||
emit close();
|
||||
});
|
||||
}
|
26
src/dialogs/FallbackAuth.h
Normal file
26
src/dialogs/FallbackAuth.h
Normal file
|
@ -0,0 +1,26 @@
|
|||
#pragma once
|
||||
|
||||
#include <QWidget>
|
||||
|
||||
class QPushButton;
|
||||
class QLabel;
|
||||
|
||||
namespace dialogs {
|
||||
|
||||
class FallbackAuth : public QWidget
|
||||
{
|
||||
Q_OBJECT
|
||||
|
||||
public:
|
||||
FallbackAuth(const QString &authType, const QString &session, QWidget *parent = nullptr);
|
||||
|
||||
signals:
|
||||
void confirmation();
|
||||
void cancel();
|
||||
|
||||
private:
|
||||
QPushButton *openBtn_;
|
||||
QPushButton *confirmBtn_;
|
||||
QPushButton *cancelBtn_;
|
||||
};
|
||||
} // dialogs
|
|
@ -60,5 +60,8 @@ ReCaptcha::ReCaptcha(const QString &session, QWidget *parent)
|
|||
emit confirmation();
|
||||
emit close();
|
||||
});
|
||||
connect(cancelBtn_, &QPushButton::clicked, this, &dialogs::ReCaptcha::close);
|
||||
connect(cancelBtn_, &QPushButton::clicked, this, [this]() {
|
||||
emit cancel();
|
||||
emit close();
|
||||
});
|
||||
}
|
||||
|
|
|
@ -15,6 +15,7 @@ public:
|
|||
|
||||
signals:
|
||||
void confirmation();
|
||||
void cancel();
|
||||
|
||||
private:
|
||||
QPushButton *openCaptchaBtn_;
|
||||
|
|
Loading…
Reference in a new issue