Skip to content
Snippets Groups Projects
Commit fedc1788 authored by Loren Burkholder's avatar Loren Burkholder
Browse files

Port the reCAPTCHA dialog to QML

parent ff4c16c3
No related branches found
No related tags found
No related merge requests found
......@@ -353,8 +353,6 @@ set(SRC_FILES
# Dialogs
src/dialogs/FallbackAuth.cpp
src/dialogs/FallbackAuth.h
src/dialogs/ReCaptcha.cpp
src/dialogs/ReCaptcha.h
# Emoji
src/emoji/Provider.cpp
......@@ -485,6 +483,8 @@ set(SRC_FILES
src/PowerlevelsEditModels.h
src/ReadReceiptsModel.cpp
src/ReadReceiptsModel.h
src/ReCaptcha.cpp
src/ReCaptcha.h
src/RegisterPage.cpp
src/RegisterPage.h
src/RoomDirectoryModel.cpp
......@@ -776,6 +776,7 @@ set(QML_SOURCES
resources/qml/dialogs/PowerLevelSpacesApplyDialog.qml
resources/qml/dialogs/RawMessageDialog.qml
resources/qml/dialogs/ReadReceipts.qml
resources/qml/dialogs/ReCaptchaDialog.qml
resources/qml/dialogs/RoomDirectory.qml
resources/qml/dialogs/RoomMembers.qml
resources/qml/dialogs/AllowedRoomsSettingsDialog.qml
......
......@@ -360,6 +360,7 @@ Pane {
onAccepted: UIA.continue3pidReceived()
}
Connections {
function onConfirm3pidToken() {
uiaConfirmationLinkDialog.open();
......@@ -381,6 +382,18 @@ Pane {
function onPrompt3pidToken() {
uiaTokenPrompt.show();
}
function onReCaptcha(recaptcha) {
var component = Qt.createComponent("qrc:/resources/qml/dialogs/ReCaptchaDialog.qml");
if (component.status == Component.Ready) {
var dialog = component.createObject(timelineRoot, {
"recaptcha": recaptcha
});
dialog.show();
destroyOnClose(dialog);
} else {
console.error("Failed to create component: " + component.errorString());
}
}
target: UIA
}
......
// SPDX-FileCopyrightText: Nheko Contributors
//
// SPDX-License-Identifier: GPL-3.0-or-later
import QtQuick
import QtQuick.Controls
import im.nheko
ApplicationWindow {
id: recaptchaRoot
required property ReCaptcha recaptcha
function accept() {
recaptcha.confirm();
recaptchaRoot.close();
}
function reject() {
recaptcha.cancel();
recaptchaRoot.close();
}
color: palette.window
title: recaptcha.context
flags: Qt.Tool | Qt.WindowStaysOnTopHint | Qt.WindowCloseButtonHint | Qt.WindowTitleHint
height: msg.implicitHeight + footer.implicitHeight
width: Math.max(msg.implicitWidth, footer.implicitWidth)
Shortcut {
sequence: StandardKey.Cancel
onActivated: recaptchaRoot.reject()
}
Label {
id: msg
anchors.fill: parent
padding: 8
text: qsTr("Solve the reCAPTCHA and press the confirm button")
}
footer: DialogButtonBox {
onAccepted: recaptchaRoot.accept()
onRejected: recaptchaRoot.reject()
Button {
text: qsTr("Open reCAPTCHA")
onClicked: recaptcha.openReCaptcha()
}
Button {
text: qsTr("Cancel")
DialogButtonBox.buttonRole: DialogButtonBox.RejectRole
}
Button {
text: qsTr("Confirm")
DialogButtonBox.buttonRole: DialogButtonBox.AcceptRole
}
}
}
// SPDX-FileCopyrightText: Nheko Contributors
//
// SPDX-License-Identifier: GPL-3.0-or-later
#include "ReCaptcha.h"
#include <QDesktopServices>
#include <QUrl>
#include "MatrixClient.h"
ReCaptcha::ReCaptcha(const QString &session, const QString &context, QObject *parent)
: QObject{parent},
m_session{session},
m_context{context}
{
}
void ReCaptcha::openReCaptcha()
{
const auto url = QString("https://%1:%2/_matrix/client/r0/auth/m.login.recaptcha/"
"fallback/web?session=%3")
.arg(QString::fromStdString(http::client()->server()))
.arg(http::client()->port())
.arg(m_session);
QDesktopServices::openUrl(url);
}
// SPDX-FileCopyrightText: Nheko Contributors
//
// SPDX-License-Identifier: GPL-3.0-or-later
#pragma once
#include <QQmlEngine>
class ReCaptcha : public QObject
{
Q_OBJECT
QML_ELEMENT
QML_UNCREATABLE("")
Q_PROPERTY(QString context MEMBER m_context CONSTANT)
Q_PROPERTY(QString session MEMBER m_session CONSTANT)
public:
ReCaptcha(const QString &session, const QString &context, QObject *parent = nullptr);
Q_INVOKABLE void openReCaptcha();
Q_INVOKABLE void confirm() { emit confirmation(); }
Q_INVOKABLE void cancel() { emit cancelled(); }
signals:
void confirmation();
void cancelled();
private:
QString m_session;
QString m_context;
};
// SPDX-FileCopyrightText: Nheko Contributors
//
// SPDX-License-Identifier: GPL-3.0-or-later
#include <QDesktopServices>
#include <QLabel>
#include <QPushButton>
#include <QUrl>
#include <QVBoxLayout>
#include "dialogs/ReCaptcha.h"
#include "Config.h"
#include "MatrixClient.h"
using namespace dialogs;
ReCaptcha::ReCaptcha(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->setContentsMargins(conf::modals::WIDGET_MARGIN,
conf::modals::WIDGET_MARGIN,
conf::modals::WIDGET_MARGIN,
conf::modals::WIDGET_MARGIN);
auto buttonLayout = new QHBoxLayout();
buttonLayout->setContentsMargins(0, 0, 0, 0);
buttonLayout->setSpacing(8);
openCaptchaBtn_ = new QPushButton(tr("Open reCAPTCHA"), this);
cancelBtn_ = new QPushButton(tr("Cancel"), this);
confirmBtn_ = new QPushButton(tr("Confirm"), this);
confirmBtn_->setDefault(true);
buttonLayout->addStretch(1);
buttonLayout->addWidget(openCaptchaBtn_);
buttonLayout->addWidget(cancelBtn_);
buttonLayout->addWidget(confirmBtn_);
QFont font;
font.setPointSizeF(font.pointSizeF() * conf::modals::LABEL_MEDIUM_SIZE_RATIO);
auto label = new QLabel(tr("Solve the reCAPTCHA and press the confirm button"), this);
label->setFont(font);
layout->addWidget(label);
layout->addLayout(buttonLayout);
connect(openCaptchaBtn_, &QPushButton::clicked, [session]() {
const auto url = QString("https://%1:%2/_matrix/client/r0/auth/m.login.recaptcha/"
"fallback/web?session=%3")
.arg(QString::fromStdString(http::client()->server()))
.arg(http::client()->port())
.arg(session);
QDesktopServices::openUrl(url);
});
connect(confirmBtn_, &QPushButton::clicked, this, [this]() {
emit confirmation();
close();
});
connect(cancelBtn_, &QPushButton::clicked, this, [this]() {
emit cancel();
close();
});
}
// SPDX-FileCopyrightText: Nheko Contributors
//
// SPDX-License-Identifier: GPL-3.0-or-later
#pragma once
#include <QWidget>
class QPushButton;
namespace dialogs {
class ReCaptcha final : public QWidget
{
Q_OBJECT
public:
ReCaptcha(const QString &session, QWidget *parent = nullptr);
signals:
void confirmation();
void cancel();
private:
QPushButton *openCaptchaBtn_;
QPushButton *confirmBtn_;
QPushButton *cancelBtn_;
};
} // dialogs
......@@ -14,12 +14,12 @@
#include "Logging.h"
#include "MatrixClient.h"
#include "dialogs/FallbackAuth.h"
#include "dialogs/ReCaptcha.h"
#include "ReCaptcha.h"
UIA *
UIA::instance()
{
static UIA uia;
static UIA uia{nullptr};
return &uia;
}
......@@ -99,24 +99,16 @@ UIA::genericHandler(QString context)
} 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), nullptr);
captchaDialog->setWindowTitle(context);
connect(
captchaDialog, &dialogs::ReCaptcha::confirmation, this, [captchaDialog, h, u]() {
captchaDialog->close();
captchaDialog->deleteLater();
h.next(mtx::user_interactive::Auth{u.session,
mtx::user_interactive::auth::Fallback{}});
});
connect(captchaDialog, &dialogs::ReCaptcha::cancel, this, [this]() {
auto captcha = new ReCaptcha(QString::fromStdString(u.session), context, nullptr);
QQmlEngine::setObjectOwnership(captcha, QQmlEngine::JavaScriptOwnership);
connect(captcha, &ReCaptcha::confirmation, this, [h, u]() {
h.next(mtx::user_interactive::Auth{u.session,
mtx::user_interactive::auth::Fallback{}});
});
connect(captcha, &ReCaptcha::cancelled, this, [this]() {
emit error(tr("Registration aborted"));
});
QTimer::singleShot(0, this, [captchaDialog]() { captchaDialog->show(); });
emit reCaptcha(captcha);
} else if (current_stage == mtx::user_interactive::auth_types::dummy) {
h.next(
mtx::user_interactive::Auth{u.session, mtx::user_interactive::auth::Dummy{}});
......
......@@ -9,6 +9,8 @@
#include <mtxclient/http/client.hpp>
#include "ReCaptcha.h"
class UIA final : public QObject
{
Q_OBJECT
......@@ -39,7 +41,7 @@ public:
return instance();
}
UIA(QObject *parent = nullptr)
UIA(QObject *parent)
: QObject(parent)
{
}
......@@ -59,6 +61,7 @@ signals:
void password();
void email();
void phoneNumber();
void reCaptcha(ReCaptcha *recaptcha);
void confirm3pidToken();
void prompt3pidToken();
......
0% Loading or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment