mirror of
https://github.com/Nheko-Reborn/nheko.git
synced 2024-11-21 18:50:47 +03:00
Merge pull request #1501 from Nheko-Reborn/qmlRecaptcha
QML the reCAPTCHA dialog
This commit is contained in:
commit
8112922c5f
10 changed files with 154 additions and 134 deletions
|
@ -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
|
||||
|
@ -487,6 +485,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
|
||||
|
@ -779,6 +779,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
|
||||
|
|
|
@ -347,11 +347,6 @@ Pane {
|
|||
return UIA.submit3pidToken(t);
|
||||
}
|
||||
}
|
||||
Platform.MessageDialog {
|
||||
id: uiaErrorDialog
|
||||
|
||||
buttons: Platform.MessageDialog.Ok
|
||||
}
|
||||
Platform.MessageDialog {
|
||||
id: uiaConfirmationLinkDialog
|
||||
|
||||
|
@ -360,6 +355,7 @@ Pane {
|
|||
|
||||
onAccepted: UIA.continue3pidReceived()
|
||||
}
|
||||
|
||||
Connections {
|
||||
function onConfirm3pidToken() {
|
||||
uiaConfirmationLinkDialog.open();
|
||||
|
@ -367,10 +363,6 @@ Pane {
|
|||
function onEmail() {
|
||||
uiaEmailPrompt.show();
|
||||
}
|
||||
function onError(msg) {
|
||||
uiaErrorDialog.text = msg;
|
||||
uiaErrorDialog.open();
|
||||
}
|
||||
function onPassword() {
|
||||
console.log("UIA: password needed");
|
||||
uiaPassPrompt.show();
|
||||
|
@ -381,6 +373,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
|
||||
}
|
||||
|
|
63
resources/qml/dialogs/ReCaptchaDialog.qml
Normal file
63
resources/qml/dialogs/ReCaptchaDialog.qml
Normal file
|
@ -0,0 +1,63 @@
|
|||
// 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
|
||||
}
|
||||
}
|
||||
|
||||
}
|
|
@ -34,7 +34,6 @@ namespace dialogs {
|
|||
class CreateRoom;
|
||||
class InviteUsers;
|
||||
class MemberList;
|
||||
class ReCaptcha;
|
||||
}
|
||||
|
||||
class NhekoFixupPaletteEventFilter final : public QObject
|
||||
|
|
29
src/ReCaptcha.cpp
Normal file
29
src/ReCaptcha.cpp
Normal file
|
@ -0,0 +1,29 @@
|
|||
// 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);
|
||||
}
|
32
src/ReCaptcha.h
Normal file
32
src/ReCaptcha.h
Normal file
|
@ -0,0 +1,32 @@
|
|||
// 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;
|
||||
};
|
|
@ -1,74 +0,0 @@
|
|||
// 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();
|
||||
});
|
||||
}
|
|
@ -1,29 +0,0 @@
|
|||
// 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
|
|
@ -13,13 +13,13 @@
|
|||
|
||||
#include "Logging.h"
|
||||
#include "MatrixClient.h"
|
||||
#include "ReCaptcha.h"
|
||||
#include "dialogs/FallbackAuth.h"
|
||||
#include "dialogs/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();
|
||||
|
|
Loading…
Reference in a new issue