mirror of
https://github.com/Nheko-Reborn/nheko.git
synced 2024-11-26 04:58:49 +03:00
parent
ab05e2d8dc
commit
9482ac4e7a
6 changed files with 129 additions and 53 deletions
|
@ -405,7 +405,7 @@ if(USE_BUNDLED_MTXCLIENT)
|
||||||
FetchContent_Declare(
|
FetchContent_Declare(
|
||||||
MatrixClient
|
MatrixClient
|
||||||
GIT_REPOSITORY https://github.com/Nheko-Reborn/mtxclient.git
|
GIT_REPOSITORY https://github.com/Nheko-Reborn/mtxclient.git
|
||||||
GIT_TAG 25857f17272809ce2359f214d76fa11d46b1fa7e
|
GIT_TAG e1b75074b501d2d3e0100d1170b3edef8a00799c
|
||||||
)
|
)
|
||||||
set(BUILD_LIB_EXAMPLES OFF CACHE INTERNAL "")
|
set(BUILD_LIB_EXAMPLES OFF CACHE INTERNAL "")
|
||||||
set(BUILD_LIB_TESTS OFF CACHE INTERNAL "")
|
set(BUILD_LIB_TESTS OFF CACHE INTERNAL "")
|
||||||
|
@ -692,7 +692,7 @@ if(USE_BUNDLED_COEURL)
|
||||||
FetchContent_Declare(
|
FetchContent_Declare(
|
||||||
coeurl
|
coeurl
|
||||||
GIT_REPOSITORY https://nheko.im/Nheko-Reborn/coeurl.git
|
GIT_REPOSITORY https://nheko.im/Nheko-Reborn/coeurl.git
|
||||||
GIT_TAG v0.1.1
|
GIT_TAG v0.1.2
|
||||||
)
|
)
|
||||||
FetchContent_MakeAvailable(coeurl)
|
FetchContent_MakeAvailable(coeurl)
|
||||||
target_link_libraries(nheko PUBLIC coeurl::coeurl)
|
target_link_libraries(nheko PUBLIC coeurl::coeurl)
|
||||||
|
|
|
@ -177,8 +177,8 @@ modules:
|
||||||
- -Ddefault_library=static
|
- -Ddefault_library=static
|
||||||
name: coeurl
|
name: coeurl
|
||||||
sources:
|
sources:
|
||||||
- commit: fa108b25a92b0e037723debc4388a300e737dc2d
|
- commit: 1c530c153687c9072619f00ad77fff9960bdb048
|
||||||
tag: v0.1.1
|
tag: v0.1.2
|
||||||
type: git
|
type: git
|
||||||
url: https://nheko.im/nheko-reborn/coeurl.git
|
url: https://nheko.im/nheko-reborn/coeurl.git
|
||||||
- config-opts:
|
- config-opts:
|
||||||
|
@ -189,7 +189,7 @@ modules:
|
||||||
buildsystem: cmake-ninja
|
buildsystem: cmake-ninja
|
||||||
name: mtxclient
|
name: mtxclient
|
||||||
sources:
|
sources:
|
||||||
- commit: 25857f17272809ce2359f214d76fa11d46b1fa7e
|
- commit: e1b75074b501d2d3e0100d1170b3edef8a00799c
|
||||||
#tag: v0.6.2
|
#tag: v0.6.2
|
||||||
type: git
|
type: git
|
||||||
url: https://github.com/Nheko-Reborn/mtxclient.git
|
url: https://github.com/Nheko-Reborn/mtxclient.git
|
||||||
|
|
|
@ -6,6 +6,7 @@
|
||||||
import QtGraphicalEffects 1.12
|
import QtGraphicalEffects 1.12
|
||||||
import QtQuick 2.9
|
import QtQuick 2.9
|
||||||
import QtQuick.Controls 2.5
|
import QtQuick.Controls 2.5
|
||||||
|
import QtQuick.Layouts 1.2
|
||||||
import im.nheko 1.0
|
import im.nheko 1.0
|
||||||
|
|
||||||
// FIXME(Nico): Don't use hardcoded colors.
|
// FIXME(Nico): Don't use hardcoded colors.
|
||||||
|
@ -16,6 +17,8 @@ Button {
|
||||||
implicitWidth: Math.ceil(control.contentItem.implicitWidth + control.contentItem.implicitHeight)
|
implicitWidth: Math.ceil(control.contentItem.implicitWidth + control.contentItem.implicitHeight)
|
||||||
hoverEnabled: true
|
hoverEnabled: true
|
||||||
|
|
||||||
|
property string iconImage: ""
|
||||||
|
|
||||||
DropShadow {
|
DropShadow {
|
||||||
anchors.fill: control.background
|
anchors.fill: control.background
|
||||||
horizontalOffset: 3
|
horizontalOffset: 3
|
||||||
|
@ -27,7 +30,20 @@ Button {
|
||||||
source: control.background
|
source: control.background
|
||||||
}
|
}
|
||||||
|
|
||||||
contentItem: Text {
|
contentItem: RowLayout {
|
||||||
|
spacing: 0
|
||||||
|
anchors.centerIn: parent
|
||||||
|
Image {
|
||||||
|
Layout.leftMargin: Nheko.paddingMedium
|
||||||
|
Layout.alignment: Qt.AlignVCenter | Qt.AlignHCenter
|
||||||
|
Layout.preferredHeight: fontMetrics.font.pixelSize * 1.5
|
||||||
|
Layout.preferredWidth: fontMetrics.font.pixelSize * 1.5
|
||||||
|
visible: !!iconImage
|
||||||
|
source: iconImage
|
||||||
|
}
|
||||||
|
|
||||||
|
Text {
|
||||||
|
Layout.alignment: Qt.AlignHCenter
|
||||||
text: control.text
|
text: control.text
|
||||||
//font: control.font
|
//font: control.font
|
||||||
font.capitalization: Font.AllUppercase
|
font.capitalization: Font.AllUppercase
|
||||||
|
@ -38,6 +54,7 @@ Button {
|
||||||
verticalAlignment: Text.AlignVCenter
|
verticalAlignment: Text.AlignVCenter
|
||||||
elide: Text.ElideRight
|
elide: Text.ElideRight
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
background: Rectangle {
|
background: Rectangle {
|
||||||
//height: control.contentItem.implicitHeight * 2
|
//height: control.contentItem.implicitHeight * 2
|
||||||
|
|
|
@ -61,7 +61,7 @@ Item {
|
||||||
onEditingFinished: login.mxid = text
|
onEditingFinished: login.mxid = text
|
||||||
|
|
||||||
ToolTip.text: qsTr("Your login name. A mxid should start with @ followed by the user id. After the user id you need to include your server name after a :.\nYou can also put your homeserver address there, if your server doesn't support .well-known lookup.\nExample: @user:server.my\nIf Nheko fails to discover your homeserver, it will show you a field to enter the server manually.")
|
ToolTip.text: qsTr("Your login name. A mxid should start with @ followed by the user id. After the user id you need to include your server name after a :.\nYou can also put your homeserver address there, if your server doesn't support .well-known lookup.\nExample: @user:server.my\nIf Nheko fails to discover your homeserver, it will show you a field to enter the server manually.")
|
||||||
Keys.forwardTo: [pwBtn, ssoBtn]
|
Keys.forwardTo: [pwBtn, ssoRepeater]
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
@ -89,7 +89,7 @@ Item {
|
||||||
echoMode: TextInput.Password
|
echoMode: TextInput.Password
|
||||||
ToolTip.text: qsTr("Your password.")
|
ToolTip.text: qsTr("Your password.")
|
||||||
visible: login.passwordSupported
|
visible: login.passwordSupported
|
||||||
Keys.forwardTo: [pwBtn, ssoBtn]
|
Keys.forwardTo: [pwBtn, ssoRepeater]
|
||||||
}
|
}
|
||||||
|
|
||||||
MatrixTextField {
|
MatrixTextField {
|
||||||
|
@ -98,7 +98,7 @@ Item {
|
||||||
label: qsTr("Device name")
|
label: qsTr("Device name")
|
||||||
placeholderText: login.initialDeviceName()
|
placeholderText: login.initialDeviceName()
|
||||||
ToolTip.text: qsTr("A name for this device, which will be shown to others, when verifying your devices. If none is provided a default is used.")
|
ToolTip.text: qsTr("A name for this device, which will be shown to others, when verifying your devices. If none is provided a default is used.")
|
||||||
Keys.forwardTo: [pwBtn, ssoBtn]
|
Keys.forwardTo: [pwBtn, ssoRepeater]
|
||||||
}
|
}
|
||||||
|
|
||||||
MatrixTextField {
|
MatrixTextField {
|
||||||
|
@ -112,7 +112,7 @@ Item {
|
||||||
text: login.homeserver
|
text: login.homeserver
|
||||||
onEditingFinished: login.homeserver = text
|
onEditingFinished: login.homeserver = text
|
||||||
ToolTip.text: qsTr("The address that can be used to contact you homeservers client API.\nExample: https://server.my:8787")
|
ToolTip.text: qsTr("The address that can be used to contact you homeservers client API.\nExample: https://server.my:8787")
|
||||||
Keys.forwardTo: [pwBtn, ssoBtn]
|
Keys.forwardTo: [pwBtn, ssoRepeater]
|
||||||
}
|
}
|
||||||
|
|
||||||
Item {
|
Item {
|
||||||
|
@ -150,21 +150,28 @@ Item {
|
||||||
Keys.onReturnPressed: pwBtn.pwLogin()
|
Keys.onReturnPressed: pwBtn.pwLogin()
|
||||||
Keys.enabled: pwBtn.enabled && login.passwordSupported
|
Keys.enabled: pwBtn.enabled && login.passwordSupported
|
||||||
}
|
}
|
||||||
FlatButton {
|
|
||||||
|
Repeater {
|
||||||
|
id: ssoRepeater
|
||||||
|
|
||||||
|
model: login.identityProviders
|
||||||
|
|
||||||
|
delegate: FlatButton {
|
||||||
id: ssoBtn
|
id: ssoBtn
|
||||||
visible: login.ssoSupported
|
visible: login.ssoSupported
|
||||||
enabled: login.homeserverValid && matrixIdLabel.text == login.mxid && login.homeserver == hsLabel.text
|
enabled: login.homeserverValid && matrixIdLabel.text == login.mxid && login.homeserver == hsLabel.text
|
||||||
Layout.alignment: Qt.AlignHCenter
|
Layout.alignment: Qt.AlignHCenter
|
||||||
text: qsTr("SSO LOGIN")
|
text: modelData.name
|
||||||
|
iconImage: modelData.avatarUrl.replace("mxc://", "image://MxcImage/")
|
||||||
function ssoLogin() {
|
function ssoLogin() {
|
||||||
login.onLoginButtonClicked(Login.SSO, matrixIdLabel.text, passwordLabel.text, deviceNameLabel.text)
|
login.onLoginButtonClicked(Login.SSO, matrixIdLabel.text, modelData.id, deviceNameLabel.text)
|
||||||
}
|
}
|
||||||
onClicked: ssoBtn.ssoLogin()
|
onClicked: ssoBtn.ssoLogin()
|
||||||
Keys.onEnterPressed: ssoBtn.ssoLogin()
|
Keys.onEnterPressed: ssoBtn.ssoLogin()
|
||||||
Keys.onReturnPressed: ssoBtn.ssoLogin()
|
Keys.onReturnPressed: ssoBtn.ssoLogin()
|
||||||
Keys.enabled: ssoBtn.enabled && !login.passwordSupported
|
Keys.enabled: ssoBtn.enabled && !login.passwordSupported
|
||||||
}
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -19,6 +19,7 @@
|
||||||
#include "UserSettingsPage.h"
|
#include "UserSettingsPage.h"
|
||||||
|
|
||||||
Q_DECLARE_METATYPE(LoginPage::LoginMethod)
|
Q_DECLARE_METATYPE(LoginPage::LoginMethod)
|
||||||
|
Q_DECLARE_METATYPE(SSOProvider)
|
||||||
|
|
||||||
using namespace mtx::identifiers;
|
using namespace mtx::identifiers;
|
||||||
|
|
||||||
|
@ -28,6 +29,7 @@ LoginPage::LoginPage(QObject *parent)
|
||||||
{
|
{
|
||||||
[[maybe_unused]] static auto ignored =
|
[[maybe_unused]] static auto ignored =
|
||||||
qRegisterMetaType<LoginPage::LoginMethod>("LoginPage::LoginMethod");
|
qRegisterMetaType<LoginPage::LoginMethod>("LoginPage::LoginMethod");
|
||||||
|
[[maybe_unused]] static auto ignored2 = qRegisterMetaType<SSOProvider>();
|
||||||
|
|
||||||
connect(this, &LoginPage::versionOkCb, this, &LoginPage::versionOk, Qt::QueuedConnection);
|
connect(this, &LoginPage::versionOkCb, this, &LoginPage::versionOk, Qt::QueuedConnection);
|
||||||
connect(this, &LoginPage::versionErrorCb, this, &LoginPage::versionError, Qt::QueuedConnection);
|
connect(this, &LoginPage::versionErrorCb, this, &LoginPage::versionError, Qt::QueuedConnection);
|
||||||
|
@ -166,21 +168,46 @@ LoginPage::checkHomeserverVersion()
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
http::client()->get_login(
|
http::client()->get_login([this](mtx::responses::LoginFlows flows,
|
||||||
[this](mtx::responses::LoginFlows flows, mtx::http::RequestErr err) {
|
mtx::http::RequestErr err) {
|
||||||
if (err || flows.flows.empty())
|
if (err || flows.flows.empty())
|
||||||
emit versionOkCb(true, false);
|
emit versionOkCb(true, false, {});
|
||||||
|
|
||||||
|
QVariantList idps;
|
||||||
bool ssoSupported = false;
|
bool ssoSupported = false;
|
||||||
bool passwordSupported = false;
|
bool passwordSupported = false;
|
||||||
for (const auto &flow : flows.flows) {
|
for (const auto &flow : flows.flows) {
|
||||||
if (flow.type == mtx::user_interactive::auth_types::sso) {
|
if (flow.type == mtx::user_interactive::auth_types::sso) {
|
||||||
ssoSupported = true;
|
ssoSupported = true;
|
||||||
|
|
||||||
|
for (const auto &idp : flow.identity_providers) {
|
||||||
|
SSOProvider prov;
|
||||||
|
if (idp.brand == "apple")
|
||||||
|
prov.name_ = tr("Sign in with Apple");
|
||||||
|
else if (idp.brand == "facebook")
|
||||||
|
prov.name_ = tr("Continue with Facebook");
|
||||||
|
else if (idp.brand == "google")
|
||||||
|
prov.name_ = tr("Sign in with Google");
|
||||||
|
else if (idp.brand == "twitter")
|
||||||
|
prov.name_ = tr("Sign in with Twitter");
|
||||||
|
else
|
||||||
|
prov.name_ = tr("Login using %1").arg(QString::fromStdString(idp.name));
|
||||||
|
|
||||||
|
prov.avatarUrl_ = QString::fromStdString(idp.icon);
|
||||||
|
prov.id_ = QString::fromStdString(idp.id);
|
||||||
|
idps.push_back(QVariant::fromValue(prov));
|
||||||
|
}
|
||||||
|
|
||||||
|
if (flow.identity_providers.empty()) {
|
||||||
|
SSOProvider prov;
|
||||||
|
prov.name_ = tr("SSO LOGIN");
|
||||||
|
idps.push_back(QVariant::fromValue(prov));
|
||||||
|
}
|
||||||
} else if (flow.type == mtx::user_interactive::auth_types::password) {
|
} else if (flow.type == mtx::user_interactive::auth_types::password) {
|
||||||
passwordSupported = true;
|
passwordSupported = true;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
emit versionOkCb(passwordSupported, ssoSupported);
|
emit versionOkCb(passwordSupported, ssoSupported, idps);
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
@ -198,10 +225,11 @@ LoginPage::versionError(const QString &error)
|
||||||
}
|
}
|
||||||
|
|
||||||
void
|
void
|
||||||
LoginPage::versionOk(bool passwordSupported, bool ssoSupported)
|
LoginPage::versionOk(bool passwordSupported, bool ssoSupported, QVariantList idps)
|
||||||
{
|
{
|
||||||
passwordSupported_ = passwordSupported;
|
passwordSupported_ = passwordSupported;
|
||||||
ssoSupported_ = ssoSupported;
|
ssoSupported_ = ssoSupported;
|
||||||
|
identityProviders_ = idps;
|
||||||
|
|
||||||
lookingUpHs_ = false;
|
lookingUpHs_ = false;
|
||||||
homeserverValid_ = true;
|
homeserverValid_ = true;
|
||||||
|
@ -287,8 +315,9 @@ LoginPage::onLoginButtonClicked(LoginMethod loginMethod,
|
||||||
sso->deleteLater();
|
sso->deleteLater();
|
||||||
});
|
});
|
||||||
|
|
||||||
QDesktopServices::openUrl(
|
// password doubles as the idp id for SSO login
|
||||||
QString::fromStdString(http::client()->login_sso_redirect(sso->url())));
|
QDesktopServices::openUrl(QString::fromStdString(
|
||||||
|
http::client()->login_sso_redirect(sso->url(), password.toStdString())));
|
||||||
}
|
}
|
||||||
|
|
||||||
loggingIn_ = true;
|
loggingIn_ = true;
|
||||||
|
|
|
@ -7,6 +7,7 @@
|
||||||
#pragma once
|
#pragma once
|
||||||
|
|
||||||
#include <QObject>
|
#include <QObject>
|
||||||
|
#include <QVariantList>
|
||||||
|
|
||||||
namespace mtx {
|
namespace mtx {
|
||||||
namespace responses {
|
namespace responses {
|
||||||
|
@ -14,6 +15,23 @@ struct Login;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
struct SSOProvider
|
||||||
|
{
|
||||||
|
Q_GADGET
|
||||||
|
Q_PROPERTY(QString avatarUrl READ avatarUrl CONSTANT)
|
||||||
|
Q_PROPERTY(QString name READ name CONSTANT)
|
||||||
|
Q_PROPERTY(QString id READ id CONSTANT)
|
||||||
|
|
||||||
|
public:
|
||||||
|
[[nodiscard]] QString avatarUrl() const { return avatarUrl_; }
|
||||||
|
[[nodiscard]] QString name() const { return name_.toHtmlEscaped(); }
|
||||||
|
[[nodiscard]] QString id() const { return id_; }
|
||||||
|
|
||||||
|
QString avatarUrl_;
|
||||||
|
QString name_;
|
||||||
|
QString id_;
|
||||||
|
};
|
||||||
|
|
||||||
class LoginPage : public QObject
|
class LoginPage : public QObject
|
||||||
{
|
{
|
||||||
Q_OBJECT
|
Q_OBJECT
|
||||||
|
@ -30,6 +48,8 @@ class LoginPage : public QObject
|
||||||
Q_PROPERTY(bool ssoSupported READ ssoSupported NOTIFY versionLookedUp)
|
Q_PROPERTY(bool ssoSupported READ ssoSupported NOTIFY versionLookedUp)
|
||||||
Q_PROPERTY(bool homeserverNeeded READ homeserverNeeded NOTIFY versionLookedUp)
|
Q_PROPERTY(bool homeserverNeeded READ homeserverNeeded NOTIFY versionLookedUp)
|
||||||
|
|
||||||
|
Q_PROPERTY(QVariantList identityProviders READ identityProviders NOTIFY versionLookedUp)
|
||||||
|
|
||||||
public:
|
public:
|
||||||
enum class LoginMethod
|
enum class LoginMethod
|
||||||
{
|
{
|
||||||
|
@ -51,6 +71,7 @@ public:
|
||||||
bool ssoSupported() const { return ssoSupported_; }
|
bool ssoSupported() const { return ssoSupported_; }
|
||||||
bool homeserverNeeded() const { return homeserverNeeded_; }
|
bool homeserverNeeded() const { return homeserverNeeded_; }
|
||||||
bool homeserverValid() const { return homeserverValid_; }
|
bool homeserverValid() const { return homeserverValid_; }
|
||||||
|
QVariantList identityProviders() const { return identityProviders_; }
|
||||||
|
|
||||||
QString homeserver() { return homeserver_; }
|
QString homeserver() { return homeserver_; }
|
||||||
QString mxid() { return mxid_; }
|
QString mxid() { return mxid_; }
|
||||||
|
@ -89,7 +110,7 @@ signals:
|
||||||
|
|
||||||
//! Used to trigger the corresponding slot outside of the main thread.
|
//! Used to trigger the corresponding slot outside of the main thread.
|
||||||
void versionErrorCb(const QString &err);
|
void versionErrorCb(const QString &err);
|
||||||
void versionOkCb(bool passwordSupported, bool ssoSupported);
|
void versionOkCb(bool passwordSupported, bool ssoSupported, QVariantList identityProviders);
|
||||||
|
|
||||||
void loginOk(const mtx::responses::Login &res);
|
void loginOk(const mtx::responses::Login &res);
|
||||||
|
|
||||||
|
@ -116,7 +137,7 @@ public slots:
|
||||||
// Callback for errors produced during server probing
|
// Callback for errors produced during server probing
|
||||||
void versionError(const QString &error_message);
|
void versionError(const QString &error_message);
|
||||||
// Callback for successful server probing
|
// Callback for successful server probing
|
||||||
void versionOk(bool passwordSupported, bool ssoSupported);
|
void versionOk(bool passwordSupported, bool ssoSupported, QVariantList identityProviders);
|
||||||
|
|
||||||
private:
|
private:
|
||||||
void checkHomeserverVersion();
|
void checkHomeserverVersion();
|
||||||
|
@ -137,6 +158,8 @@ private:
|
||||||
QString mxidError_;
|
QString mxidError_;
|
||||||
QString error_;
|
QString error_;
|
||||||
|
|
||||||
|
QVariantList identityProviders_;
|
||||||
|
|
||||||
bool passwordSupported_ = true;
|
bool passwordSupported_ = true;
|
||||||
bool ssoSupported_ = false;
|
bool ssoSupported_ = false;
|
||||||
|
|
||||||
|
|
Loading…
Reference in a new issue