Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Login with QR code/remote auth #185

Merged
merged 13 commits into from
Jul 13, 2023
2 changes: 1 addition & 1 deletion .github/workflows/ci.yml
Original file line number Diff line number Diff line change
Expand Up @@ -67,7 +67,7 @@ jobs:
with:
cond: ${{ matrix.mindeps == true }}
if_true: |
cmake -GNinja -Bbuild -DCMAKE_BUILD_TYPE=${{ matrix.buildtype }} -DUSE_LIBHANDY=OFF -DENABLE_VOICE=OFF -DENABLE_NOTIFICATION_SOUNDS=OFF
cmake -GNinja -Bbuild -DCMAKE_BUILD_TYPE=${{ matrix.buildtype }} -DUSE_LIBHANDY=OFF -DENABLE_VOICE=OFF -DENABLE_NOTIFICATION_SOUNDS=OFF -DENABLE_QRCODE_LOGIN=OFF
cmake --build build
if_false: |
cmake -GNinja -Bbuild -DCMAKE_BUILD_TYPE=${{ matrix.buildtype }} -DCMAKE_CXX_FLAGS="-Wl,--default-image-base-low"
Expand Down
3 changes: 3 additions & 0 deletions .gitmodules
Original file line number Diff line number Diff line change
Expand Up @@ -13,3 +13,6 @@
[submodule "subprojects/miniaudio"]
path = subprojects/miniaudio
url = https://github.com/mackron/miniaudio
[submodule "subprojects/qrcodegen"]
path = subprojects/qrcodegen
url = https://github.com/nayuki/QR-Code-generator
22 changes: 16 additions & 6 deletions CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,7 @@ option(USE_LIBHANDY "Enable features that require libhandy (default)" ON)
option(ENABLE_VOICE "Enable voice suppport" ON)
option(USE_KEYCHAIN "Store the token in the keychain (default)" ON)
option(ENABLE_NOTIFICATION_SOUNDS "Enable notification sounds (default)" ON)
option(ENABLE_QRCODE_LOGIN "Enable QR code login (default)" ON)

find_package(nlohmann_json REQUIRED)
find_package(CURL)
Expand Down Expand Up @@ -61,6 +62,15 @@ target_include_directories(abaddon PUBLIC ${ZLIB_INCLUDE_DIRS})
target_include_directories(abaddon PUBLIC ${SQLite3_INCLUDE_DIRS})
target_include_directories(abaddon PUBLIC ${NLOHMANN_JSON_INCLUDE_DIRS})

if (ENABLE_QRCODE_LOGIN)
add_library(qrcodegen subprojects/qrcodegen/cpp/qrcodegen.hpp subprojects/qrcodegen/cpp/qrcodegen.cpp)
target_include_directories(qrcodegen PUBLIC "${CMAKE_CURRENT_SOURCE_DIR}/subprojects/qrcodegen/cpp")
target_link_libraries(abaddon qrcodegen)

target_include_directories(abaddon PUBLIC "subprojects/qrcodegen/cpp")
target_compile_definitions(abaddon PRIVATE WITH_QRLOGIN)
endif ()

target_precompile_headers(abaddon PRIVATE <gtkmm.h> src/abaddon.hpp src/util.hpp)

if ((CMAKE_CXX_COMPILER_ID STREQUAL "GNU") OR
Expand Down Expand Up @@ -151,12 +161,12 @@ if (ENABLE_VOICE)

target_link_libraries(abaddon ${CMAKE_DL_LIBS})

if(APPLE)
target_link_libraries(abaddon "-framework CoreFoundation")
target_link_libraries(abaddon "-framework CoreAudio")
target_link_libraries(abaddon "-framework AudioToolbox")
endif()
if (APPLE)
target_link_libraries(abaddon "-framework CoreFoundation")
target_link_libraries(abaddon "-framework CoreAudio")
target_link_libraries(abaddon "-framework AudioToolbox")
endif ()

endif ()

if (${ENABLE_NOTIFICATION_SOUNDS})
Expand Down
18 changes: 18 additions & 0 deletions src/abaddon.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,7 @@
#include "windows/voicewindow.hpp"
#include "startup.hpp"
#include "notifications/notifications.hpp"
#include "remoteauth/remoteauthdialog.hpp"

#ifdef WITH_LIBHANDY
#include <handy.h>
Expand Down Expand Up @@ -267,6 +268,7 @@ int Abaddon::StartGTK() {
m_main_window->signal_action_connect().connect(sigc::mem_fun(*this, &Abaddon::ActionConnect));
m_main_window->signal_action_disconnect().connect(sigc::mem_fun(*this, &Abaddon::ActionDisconnect));
m_main_window->signal_action_set_token().connect(sigc::mem_fun(*this, &Abaddon::ActionSetToken));
m_main_window->signal_action_login_qr().connect(sigc::mem_fun(*this, &Abaddon::ActionLoginQR));
m_main_window->signal_action_reload_css().connect(sigc::mem_fun(*this, &Abaddon::ActionReloadCSS));
m_main_window->signal_action_set_status().connect(sigc::mem_fun(*this, &Abaddon::ActionSetStatus));
m_main_window->signal_action_add_recipient().connect(sigc::mem_fun(*this, &Abaddon::ActionAddRecipient));
Expand Down Expand Up @@ -834,6 +836,21 @@ void Abaddon::ActionSetToken() {
m_main_window->UpdateMenus();
}

void Abaddon::ActionLoginQR() {
#ifdef WITH_QRLOGIN
RemoteAuthDialog dlg(*m_main_window);
auto response = dlg.run();
if (response == Gtk::RESPONSE_OK) {
m_discord_token = dlg.GetToken();
m_discord.UpdateToken(m_discord_token);
m_main_window->UpdateComponents();
GetSettings().DiscordToken = m_discord_token;
ActionConnect();
}
m_main_window->UpdateMenus();
#endif
}

void Abaddon::ActionChannelOpened(Snowflake id, bool expand_to) {
if (!id.IsValid()) {
m_discord.SetReferringChannel(Snowflake::Invalid);
Expand Down Expand Up @@ -1142,6 +1159,7 @@ int main(int argc, char **argv) {
auto log_audio = spdlog::stdout_color_mt("audio");
auto log_voice = spdlog::stdout_color_mt("voice");
auto log_discord = spdlog::stdout_color_mt("discord");
auto log_ra = spdlog::stdout_color_mt("remote-auth");

Gtk::Main::init_gtkmm_internals(); // why???
return Abaddon::Get().StartGTK();
Expand Down
1 change: 1 addition & 0 deletions src/abaddon.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -41,6 +41,7 @@ class Abaddon {
void ActionConnect();
void ActionDisconnect();
void ActionSetToken();
void ActionLoginQR();
void ActionJoinGuildDialog();
void ActionChannelOpened(Snowflake id, bool expand_to = true);
void ActionChatInputSubmit(ChatSubmitParams data);
Expand Down
21 changes: 21 additions & 0 deletions src/discord/discord.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -1197,6 +1197,27 @@ void DiscordClient::AcceptVerificationGate(Snowflake guild_id, VerificationGateI
});
}

void DiscordClient::RemoteAuthLogin(const std::string &ticket, const sigc::slot<void(std::optional<std::string>, DiscordError code)> &callback) {
http::request req(http::REQUEST_POST, "https://discord.com/api/v9/users/@me/remote-auth/login");
req.set_header("Content-Type", "application/json");
req.set_user_agent(Abaddon::Get().GetSettings().UserAgent);
req.set_body("{\"ticket\":\"" + ticket + "\"}");
m_http.Execute(std::move(req), [this, callback](const http::response_type &r) {
if (CheckCode(r)) {
callback(nlohmann::json::parse(r.text).at("encrypted_token").get<std::string>(), DiscordError::NONE);
} else {
try {
const auto j = nlohmann::json::parse(r.text);
if (j.contains("captcha_service")) {
callback(std::nullopt, DiscordError::CAPTCHA_REQUIRED);
return;
}
} catch (...) {}
callback(std::nullopt, GetCodeFromResponse(r));
}
});
}

#ifdef WITH_VOICE
void DiscordClient::ConnectToVoice(Snowflake channel_id) {
auto channel = GetChannel(channel_id);
Expand Down
2 changes: 2 additions & 0 deletions src/discord/discord.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -184,6 +184,8 @@ class DiscordClient {
void GetVerificationGateInfo(Snowflake guild_id, const sigc::slot<void(std::optional<VerificationGateInfoObject>)> &callback);
void AcceptVerificationGate(Snowflake guild_id, VerificationGateInfoObject info, const sigc::slot<void(DiscordError code)> &callback);

void RemoteAuthLogin(const std::string &ticket, const sigc::slot<void(std::optional<std::string>, DiscordError code)> &callback);

#ifdef WITH_VOICE
void ConnectToVoice(Snowflake channel_id);
void DisconnectFromVoice();
Expand Down
1 change: 1 addition & 0 deletions src/discord/errors.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,7 @@ enum class DiscordError {
RELATIONSHIP_ALREADY_FRIENDS = 80007,

NONE = -1,
CAPTCHA_REQUIRED = -2,
};

constexpr const char *GetDiscordErrorDisplayString(DiscordError error) {
Expand Down
5 changes: 4 additions & 1 deletion src/discord/websocket.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -26,7 +26,7 @@ void Websocket::StartConnection(const std::string &url) {
m_websocket->disableAutomaticReconnection();
m_websocket->setUrl(url);
m_websocket->setOnMessageCallback([this](auto &&msg) { OnMessage(std::forward<decltype(msg)>(msg)); });
m_websocket->setExtraHeaders(ix::WebSocketHttpHeaders { { "User-Agent", m_agent } }); // idk if this actually works
m_websocket->setExtraHeaders(ix::WebSocketHttpHeaders { { "User-Agent", m_agent }, { "Origin", "https://discord.com" } }); // idk if this actually works
m_websocket->start();
}

Expand Down Expand Up @@ -81,6 +81,9 @@ void Websocket::OnMessage(const ix::WebSocketMessagePtr &msg) {
case ix::WebSocketMessageType::Message: {
m_signal_message.emit(msg->str);
} break;
case ix::WebSocketMessageType::Error: {
m_log->error("Websocket error: Status: {} Reason: {}", msg->errorInfo.http_status, msg->errorInfo.reason);
} break;
default:
break;
}
Expand Down
Loading
Loading