mirror of
https://github.com/Nheko-Reborn/nheko.git
synced 2024-11-24 12:08:50 +03:00
parent
813790e603
commit
7b1fa60cc6
7 changed files with 5311 additions and 28 deletions
|
@ -294,6 +294,7 @@ set(SRC_FILES
|
||||||
src/RegisterPage.cpp
|
src/RegisterPage.cpp
|
||||||
src/RoomInfoListItem.cpp
|
src/RoomInfoListItem.cpp
|
||||||
src/RoomList.cpp
|
src/RoomList.cpp
|
||||||
|
src/SSOHandler.cpp
|
||||||
src/SideBarActions.cpp
|
src/SideBarActions.cpp
|
||||||
src/Splitter.cpp
|
src/Splitter.cpp
|
||||||
src/TextInputWidget.cpp
|
src/TextInputWidget.cpp
|
||||||
|
@ -493,6 +494,7 @@ qt5_wrap_cpp(MOC_HEADERS
|
||||||
src/RegisterPage.h
|
src/RegisterPage.h
|
||||||
src/RoomInfoListItem.h
|
src/RoomInfoListItem.h
|
||||||
src/RoomList.h
|
src/RoomList.h
|
||||||
|
src/SSOHandler.h
|
||||||
src/SideBarActions.h
|
src/SideBarActions.h
|
||||||
src/Splitter.h
|
src/Splitter.h
|
||||||
src/TextInputWidget.h
|
src/TextInputWidget.h
|
||||||
|
@ -556,7 +558,7 @@ elseif(WIN32)
|
||||||
else()
|
else()
|
||||||
target_link_libraries (nheko PRIVATE Qt5::DBus)
|
target_link_libraries (nheko PRIVATE Qt5::DBus)
|
||||||
endif()
|
endif()
|
||||||
target_include_directories(nheko PRIVATE src includes third_party/blurhash)
|
target_include_directories(nheko PRIVATE src includes third_party/blurhash third_party/cpp-httplib-0.5.12)
|
||||||
|
|
||||||
target_link_libraries(nheko PRIVATE
|
target_link_libraries(nheko PRIVATE
|
||||||
MatrixClient::MatrixClient
|
MatrixClient::MatrixClient
|
||||||
|
|
|
@ -988,8 +988,12 @@ ChatPage::trySync()
|
||||||
const auto err_code = mtx::errors::to_string(err->matrix_error.errcode);
|
const auto err_code = mtx::errors::to_string(err->matrix_error.errcode);
|
||||||
const int status_code = static_cast<int>(err->status_code);
|
const int status_code = static_cast<int>(err->status_code);
|
||||||
|
|
||||||
if (http::is_logged_in() && err->matrix_error.errcode ==
|
if ((http::is_logged_in() &&
|
||||||
mtx::errors::ErrorCode::M_UNKNOWN_TOKEN) {
|
(err->matrix_error.errcode ==
|
||||||
|
mtx::errors::ErrorCode::M_UNKNOWN_TOKEN ||
|
||||||
|
err->matrix_error.errcode ==
|
||||||
|
mtx::errors::ErrorCode::M_MISSING_TOKEN)) ||
|
||||||
|
!http::is_logged_in()) {
|
||||||
emit dropToLoginPageCb(msg);
|
emit dropToLoginPageCb(msg);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
|
@ -15,28 +15,35 @@
|
||||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
|
#include <QDesktopServices>
|
||||||
#include <QPainter>
|
#include <QPainter>
|
||||||
#include <QStyleOption>
|
#include <QStyleOption>
|
||||||
|
|
||||||
#include <mtx/identifiers.hpp>
|
#include <mtx/identifiers.hpp>
|
||||||
|
#include <mtx/requests.hpp>
|
||||||
#include <mtx/responses/login.hpp>
|
#include <mtx/responses/login.hpp>
|
||||||
|
|
||||||
#include "Config.h"
|
#include "Config.h"
|
||||||
#include "Logging.h"
|
#include "Logging.h"
|
||||||
#include "LoginPage.h"
|
#include "LoginPage.h"
|
||||||
#include "MatrixClient.h"
|
#include "MatrixClient.h"
|
||||||
|
#include "SSOHandler.h"
|
||||||
#include "ui/FlatButton.h"
|
#include "ui/FlatButton.h"
|
||||||
#include "ui/LoadingIndicator.h"
|
#include "ui/LoadingIndicator.h"
|
||||||
#include "ui/OverlayModal.h"
|
#include "ui/OverlayModal.h"
|
||||||
#include "ui/RaisedButton.h"
|
#include "ui/RaisedButton.h"
|
||||||
#include "ui/TextField.h"
|
#include "ui/TextField.h"
|
||||||
|
|
||||||
|
Q_DECLARE_METATYPE(LoginPage::LoginMethod)
|
||||||
|
|
||||||
using namespace mtx::identifiers;
|
using namespace mtx::identifiers;
|
||||||
|
|
||||||
LoginPage::LoginPage(QWidget *parent)
|
LoginPage::LoginPage(QWidget *parent)
|
||||||
: QWidget(parent)
|
: QWidget(parent)
|
||||||
, inferredServerAddress_()
|
, inferredServerAddress_()
|
||||||
{
|
{
|
||||||
|
qRegisterMetaType<LoginPage::LoginMethod>("LoginPage::LoginMethod");
|
||||||
|
|
||||||
top_layout_ = new QVBoxLayout();
|
top_layout_ = new QVBoxLayout();
|
||||||
|
|
||||||
top_bar_layout_ = new QHBoxLayout();
|
top_bar_layout_ = new QHBoxLayout();
|
||||||
|
@ -226,7 +233,8 @@ LoginPage::onMatrixIdEntered()
|
||||||
emit versionErrorCb(tr("Autodiscovery failed. Unknown error when "
|
emit versionErrorCb(tr("Autodiscovery failed. Unknown error when "
|
||||||
"requesting .well-known."));
|
"requesting .well-known."));
|
||||||
nhlog::net()->error("Autodiscovery failed. Unknown error when "
|
nhlog::net()->error("Autodiscovery failed. Unknown error when "
|
||||||
"requesting .well-known.");
|
"requesting .well-known. {}",
|
||||||
|
err->status_code);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -263,7 +271,16 @@ LoginPage::checkHomeserverVersion()
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
emit versionOkCb();
|
http::client()->get_login(
|
||||||
|
[this](mtx::responses::LoginFlows flows, mtx::http::RequestErr err) {
|
||||||
|
if (err || flows.flows.empty())
|
||||||
|
emit versionOkCb(LoginMethod::Password);
|
||||||
|
|
||||||
|
if (flows.flows[0].type == mtx::user_interactive::auth_types::sso)
|
||||||
|
emit versionOkCb(LoginMethod::SSO);
|
||||||
|
else
|
||||||
|
emit versionOkCb(LoginMethod::Password);
|
||||||
|
});
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -294,12 +311,22 @@ LoginPage::versionError(const QString &error)
|
||||||
}
|
}
|
||||||
|
|
||||||
void
|
void
|
||||||
LoginPage::versionOk()
|
LoginPage::versionOk(LoginMethod loginMethod)
|
||||||
{
|
{
|
||||||
|
this->loginMethod = loginMethod;
|
||||||
|
|
||||||
serverLayout_->removeWidget(spinner_);
|
serverLayout_->removeWidget(spinner_);
|
||||||
matrixidLayout_->removeWidget(spinner_);
|
matrixidLayout_->removeWidget(spinner_);
|
||||||
spinner_->stop();
|
spinner_->stop();
|
||||||
|
|
||||||
|
if (loginMethod == LoginMethod::SSO) {
|
||||||
|
password_input_->hide();
|
||||||
|
login_button_->setText(tr("SSO LOGIN"));
|
||||||
|
} else {
|
||||||
|
password_input_->show();
|
||||||
|
login_button_->setText(tr("LOGIN"));
|
||||||
|
}
|
||||||
|
|
||||||
if (serverInput_->isVisible())
|
if (serverInput_->isVisible())
|
||||||
serverInput_->hide();
|
serverInput_->hide();
|
||||||
}
|
}
|
||||||
|
@ -317,29 +344,68 @@ LoginPage::onLoginButtonClicked()
|
||||||
return loginError("You have entered an invalid Matrix ID e.g @joe:matrix.org");
|
return loginError("You have entered an invalid Matrix ID e.g @joe:matrix.org");
|
||||||
}
|
}
|
||||||
|
|
||||||
if (password_input_->text().isEmpty())
|
if (loginMethod == LoginMethod::Password) {
|
||||||
return loginError(tr("Empty password"));
|
if (password_input_->text().isEmpty())
|
||||||
|
return loginError(tr("Empty password"));
|
||||||
|
|
||||||
http::client()->login(
|
http::client()->login(
|
||||||
user.localpart(),
|
user.localpart(),
|
||||||
password_input_->text().toStdString(),
|
password_input_->text().toStdString(),
|
||||||
deviceName_->text().trimmed().isEmpty() ? initialDeviceName()
|
deviceName_->text().trimmed().isEmpty() ? initialDeviceName()
|
||||||
: deviceName_->text().toStdString(),
|
: deviceName_->text().toStdString(),
|
||||||
[this](const mtx::responses::Login &res, mtx::http::RequestErr err) {
|
[this](const mtx::responses::Login &res, mtx::http::RequestErr err) {
|
||||||
if (err) {
|
if (err) {
|
||||||
emit loginError(QString::fromStdString(err->matrix_error.error));
|
emit loginError(QString::fromStdString(err->matrix_error.error));
|
||||||
emit errorOccurred();
|
emit errorOccurred();
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (res.well_known) {
|
if (res.well_known) {
|
||||||
http::client()->set_server(res.well_known->homeserver.base_url);
|
http::client()->set_server(res.well_known->homeserver.base_url);
|
||||||
nhlog::net()->info("Login requested to user server: " +
|
nhlog::net()->info("Login requested to user server: " +
|
||||||
res.well_known->homeserver.base_url);
|
res.well_known->homeserver.base_url);
|
||||||
}
|
}
|
||||||
|
|
||||||
emit loginOk(res);
|
emit loginOk(res);
|
||||||
});
|
});
|
||||||
|
} else {
|
||||||
|
auto sso = new SSOHandler();
|
||||||
|
connect(sso, &SSOHandler::ssoSuccess, this, [this, sso](std::string token) {
|
||||||
|
mtx::requests::Login req{};
|
||||||
|
req.token = token;
|
||||||
|
req.type = mtx::user_interactive::auth_types::token;
|
||||||
|
req.device_id = deviceName_->text().trimmed().isEmpty()
|
||||||
|
? initialDeviceName()
|
||||||
|
: deviceName_->text().toStdString();
|
||||||
|
http::client()->login(
|
||||||
|
req, [this](const mtx::responses::Login &res, mtx::http::RequestErr err) {
|
||||||
|
if (err) {
|
||||||
|
emit loginError(
|
||||||
|
QString::fromStdString(err->matrix_error.error));
|
||||||
|
emit errorOccurred();
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (res.well_known) {
|
||||||
|
http::client()->set_server(
|
||||||
|
res.well_known->homeserver.base_url);
|
||||||
|
nhlog::net()->info("Login requested to user server: " +
|
||||||
|
res.well_known->homeserver.base_url);
|
||||||
|
}
|
||||||
|
|
||||||
|
emit loginOk(res);
|
||||||
|
});
|
||||||
|
sso->deleteLater();
|
||||||
|
});
|
||||||
|
connect(sso, &SSOHandler::ssoFailed, this, [this, sso]() {
|
||||||
|
emit loginError(tr("SSO login failed"));
|
||||||
|
emit errorOccurred();
|
||||||
|
sso->deleteLater();
|
||||||
|
});
|
||||||
|
|
||||||
|
QDesktopServices::openUrl(
|
||||||
|
QString::fromStdString(http::client()->login_sso_redirect(sso->url())));
|
||||||
|
}
|
||||||
|
|
||||||
emit loggingIn();
|
emit loggingIn();
|
||||||
}
|
}
|
||||||
|
@ -349,6 +415,7 @@ LoginPage::reset()
|
||||||
{
|
{
|
||||||
matrixid_input_->clear();
|
matrixid_input_->clear();
|
||||||
password_input_->clear();
|
password_input_->clear();
|
||||||
|
password_input_->show();
|
||||||
serverInput_->clear();
|
serverInput_->clear();
|
||||||
|
|
||||||
spinner_->stop();
|
spinner_->stop();
|
||||||
|
|
|
@ -38,6 +38,12 @@ class LoginPage : public QWidget
|
||||||
Q_OBJECT
|
Q_OBJECT
|
||||||
|
|
||||||
public:
|
public:
|
||||||
|
enum class LoginMethod
|
||||||
|
{
|
||||||
|
Password,
|
||||||
|
SSO,
|
||||||
|
};
|
||||||
|
|
||||||
LoginPage(QWidget *parent = nullptr);
|
LoginPage(QWidget *parent = nullptr);
|
||||||
|
|
||||||
void reset();
|
void reset();
|
||||||
|
@ -50,7 +56,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 loginErrorCb(const QString &err);
|
void loginErrorCb(const QString &err);
|
||||||
void versionOkCb();
|
void versionOkCb(LoginPage::LoginMethod method);
|
||||||
|
|
||||||
void loginOk(const mtx::responses::Login &res);
|
void loginOk(const mtx::responses::Login &res);
|
||||||
|
|
||||||
|
@ -77,7 +83,7 @@ private 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();
|
void versionOk(LoginPage::LoginMethod method);
|
||||||
|
|
||||||
private:
|
private:
|
||||||
bool isMatrixIdValid();
|
bool isMatrixIdValid();
|
||||||
|
@ -123,4 +129,5 @@ private:
|
||||||
TextField *password_input_;
|
TextField *password_input_;
|
||||||
TextField *deviceName_;
|
TextField *deviceName_;
|
||||||
TextField *serverInput_;
|
TextField *serverInput_;
|
||||||
|
LoginMethod loginMethod = LoginMethod::Password;
|
||||||
};
|
};
|
||||||
|
|
54
src/SSOHandler.cpp
Normal file
54
src/SSOHandler.cpp
Normal file
|
@ -0,0 +1,54 @@
|
||||||
|
#include "SSOHandler.h"
|
||||||
|
|
||||||
|
#include <QTimer>
|
||||||
|
|
||||||
|
#include <thread>
|
||||||
|
|
||||||
|
#include "Logging.h"
|
||||||
|
|
||||||
|
SSOHandler::SSOHandler(QObject *)
|
||||||
|
{
|
||||||
|
QTimer::singleShot(120000, this, &SSOHandler::ssoFailed);
|
||||||
|
|
||||||
|
using namespace httplib;
|
||||||
|
|
||||||
|
svr.set_logger([](const Request &req, const Response &res) {
|
||||||
|
nhlog::net()->info("req: {}, res: {}", req.path, res.status);
|
||||||
|
});
|
||||||
|
|
||||||
|
svr.Get("/sso", [this](const Request &req, Response &res) {
|
||||||
|
if (req.has_param("loginToken")) {
|
||||||
|
auto val = req.get_param_value("loginToken");
|
||||||
|
res.set_content("SSO success", "text/plain");
|
||||||
|
emit ssoSuccess(val);
|
||||||
|
} else {
|
||||||
|
res.set_content("Missing loginToken for SSO login!", "text/plain");
|
||||||
|
emit ssoFailed();
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
std::thread t([this]() {
|
||||||
|
this->port = svr.bind_to_any_port("localhost");
|
||||||
|
svr.listen_after_bind();
|
||||||
|
|
||||||
|
});
|
||||||
|
t.detach();
|
||||||
|
|
||||||
|
while (!svr.is_running()) {
|
||||||
|
std::this_thread::sleep_for(std::chrono::milliseconds(1));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
SSOHandler::~SSOHandler()
|
||||||
|
{
|
||||||
|
svr.stop();
|
||||||
|
while (svr.is_running()) {
|
||||||
|
std::this_thread::sleep_for(std::chrono::milliseconds(1));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
std::string
|
||||||
|
SSOHandler::url() const
|
||||||
|
{
|
||||||
|
return "http://localhost:" + std::to_string(port) + "/sso";
|
||||||
|
}
|
24
src/SSOHandler.h
Normal file
24
src/SSOHandler.h
Normal file
|
@ -0,0 +1,24 @@
|
||||||
|
#include "httplib.h"
|
||||||
|
|
||||||
|
#include <QObject>
|
||||||
|
#include <string>
|
||||||
|
|
||||||
|
class SSOHandler : public QObject
|
||||||
|
{
|
||||||
|
Q_OBJECT
|
||||||
|
|
||||||
|
public:
|
||||||
|
SSOHandler(QObject *parent = nullptr);
|
||||||
|
|
||||||
|
~SSOHandler();
|
||||||
|
|
||||||
|
std::string url() const;
|
||||||
|
|
||||||
|
signals:
|
||||||
|
void ssoSuccess(std::string token);
|
||||||
|
void ssoFailed();
|
||||||
|
|
||||||
|
private:
|
||||||
|
httplib::Server svr;
|
||||||
|
int port = 0;
|
||||||
|
};
|
5125
third_party/cpp-httplib-0.5.12/httplib.h
vendored
Normal file
5125
third_party/cpp-httplib-0.5.12/httplib.h
vendored
Normal file
File diff suppressed because it is too large
Load diff
Loading…
Reference in a new issue