fetch cookies and build number on startup

This commit is contained in:
ouwou 2022-08-17 01:42:30 -04:00
parent 14602a7384
commit 32fc7def7c
11 changed files with 226 additions and 26 deletions

View File

@ -17,6 +17,7 @@
#include "windows/profilewindow.hpp"
#include "windows/pinnedwindow.hpp"
#include "windows/threadswindow.hpp"
#include "startup.hpp"
#ifdef WITH_LIBHANDY
#include <handy.h>
@ -253,6 +254,9 @@ int Abaddon::StartGTK() {
m_main_window->UpdateMenus();
m_main_window->show();
RunFirstTimeDiscordStartup();
return m_gtk_app->run(*m_main_window);
}
@ -435,6 +439,43 @@ void Abaddon::ShowUserMenu(const GdkEvent *event, Snowflake id, Snowflake guild_
m_user_menu->popup_at_pointer(event);
}
void Abaddon::RunFirstTimeDiscordStartup() {
DiscordStartupDialog dlg(*m_main_window);
dlg.set_position(Gtk::WIN_POS_CENTER);
std::optional<std::string> cookie;
std::optional<uint32_t> build_number;
dlg.signal_response().connect([&](int response) {
if (response == Gtk::RESPONSE_OK) {
cookie = dlg.GetCookie();
build_number = dlg.GetBuildNumber();
}
});
dlg.run();
Glib::signal_idle().connect_once([this, cookie, build_number]() {
if (cookie.has_value()) {
m_discord.SetCookie(*cookie);
} else {
ConfirmDialog confirm(*m_main_window);
confirm.SetConfirmText("Cookies could not be fetched. This may increase your chances of being flagged by Discord's anti-spam");
confirm.SetAcceptOnly(true);
confirm.run();
}
if (build_number.has_value()) {
m_discord.SetBuildNumber(*build_number);
} else {
ConfirmDialog confirm(*m_main_window);
confirm.SetConfirmText("Build number could not be fetched. This may increase your chances of being flagged by Discord's anti-spam");
confirm.SetAcceptOnly(true);
confirm.run();
}
});
}
void Abaddon::ShowGuildVerificationGateDialog(Snowflake guild_id) {
VerificationGateDialog dlg(*m_main_window, guild_id);
if (dlg.run() == Gtk::RESPONSE_OK) {

View File

@ -94,6 +94,8 @@ public:
static std::string GetStateCachePath(const std::string &path);
protected:
void RunFirstTimeDiscordStartup();
void ShowGuildVerificationGateDialog(Snowflake guild_id);
void CheckMessagesForMembers(const ChannelData &chan, const std::vector<Message> &msgs);

View File

@ -34,3 +34,7 @@ ConfirmDialog::ConfirmDialog(Gtk::Window &parent)
void ConfirmDialog::SetConfirmText(const Glib::ustring &text) {
m_label.set_text(text);
}
void ConfirmDialog::SetAcceptOnly(bool accept_only) {
m_cancel.set_visible(!accept_only);
}

View File

@ -5,6 +5,7 @@ class ConfirmDialog : public Gtk::Dialog {
public:
ConfirmDialog(Gtk::Window &parent);
void SetConfirmText(const Glib::ustring &text);
void SetAcceptOnly(bool accept_only);
protected:
Gtk::Label m_label;

View File

@ -1188,6 +1188,14 @@ void DiscordClient::SetReferringChannel(Snowflake id) {
}
}
void DiscordClient::SetBuildNumber(uint32_t build_number) {
m_build_number = build_number;
}
void DiscordClient::SetCookie(std::string_view cookie) {
m_http.SetCookie(cookie);
}
void DiscordClient::UpdateToken(const std::string &token) {
if (!IsStarted()) {
m_token = token;
@ -2314,7 +2322,7 @@ void DiscordClient::SendIdentify() {
msg.Properties.ReferrerCurrent = "";
msg.Properties.ReferringDomainCurrent = "";
msg.Properties.ReleaseChannel = "stable";
msg.Properties.ClientBuildNumber = 141021;
msg.Properties.ClientBuildNumber = m_build_number;
msg.Properties.ClientEventSource = "";
msg.Presence.Status = "online";
msg.Presence.Since = 0;

View File

@ -206,6 +206,9 @@ public:
void SetReferringChannel(Snowflake id);
void SetBuildNumber(uint32_t build_number);
void SetCookie(std::string_view cookie);
void UpdateToken(const std::string &token);
void SetUserAgent(const std::string &agent);
@ -303,6 +306,8 @@ private:
std::string m_token;
uint32_t m_build_number = 142000;
void AddUserToGuild(Snowflake user_id, Snowflake guild_id);
std::map<Snowflake, std::set<Snowflake>> m_guild_to_users;
std::map<Snowflake, std::set<Snowflake>> m_guild_to_channels;

View File

@ -2,7 +2,6 @@
#include <utility>
//#define USE_LOCAL_PROXY
HTTPClient::HTTPClient() {
m_dispatcher.connect(sigc::mem_fun(*this, &HTTPClient::RunCallbacks));
}
@ -23,6 +22,10 @@ void HTTPClient::SetPersistentHeader(std::string name, std::string value) {
m_headers.insert_or_assign(std::move(name), std::move(value));
}
void HTTPClient::SetCookie(std::string_view cookie) {
m_cookie = cookie;
}
void HTTPClient::MakeDELETE(const std::string &path, const std::function<void(http::response_type r)> &cb) {
printf("DELETE %s\n", path.c_str());
m_futures.push_back(std::async(std::launch::async, [this, path, cb] {
@ -31,10 +34,6 @@ void HTTPClient::MakeDELETE(const std::string &path, const std::function<void(ht
req.set_header("Authorization", m_authorization);
req.set_header("Origin", "https://discord.com");
req.set_user_agent(!m_agent.empty() ? m_agent : "Abaddon");
#ifdef USE_LOCAL_PROXY
req.set_proxy("http://127.0.0.1:8888");
req.set_verify_ssl(false);
#endif
auto res = req.execute();
@ -52,10 +51,6 @@ void HTTPClient::MakePATCH(const std::string &path, const std::string &payload,
req.set_header("Origin", "https://discord.com");
req.set_user_agent(!m_agent.empty() ? m_agent : "Abaddon");
req.set_body(payload);
#ifdef USE_LOCAL_PROXY
req.set_proxy("http://127.0.0.1:8888");
req.set_verify_ssl(false);
#endif
auto res = req.execute();
@ -73,10 +68,6 @@ void HTTPClient::MakePOST(const std::string &path, const std::string &payload, c
req.set_header("Origin", "https://discord.com");
req.set_user_agent(!m_agent.empty() ? m_agent : "Abaddon");
req.set_body(payload);
#ifdef USE_LOCAL_PROXY
req.set_proxy("http://127.0.0.1:8888");
req.set_verify_ssl(false);
#endif
auto res = req.execute();
@ -95,10 +86,6 @@ void HTTPClient::MakePUT(const std::string &path, const std::string &payload, co
req.set_header("Content-Type", "application/json");
req.set_user_agent(!m_agent.empty() ? m_agent : "Abaddon");
req.set_body(payload);
#ifdef USE_LOCAL_PROXY
req.set_proxy("http://127.0.0.1:8888");
req.set_verify_ssl(false);
#endif
auto res = req.execute();
@ -113,10 +100,6 @@ void HTTPClient::MakeGET(const std::string &path, const std::function<void(http:
AddHeaders(req);
req.set_header("Authorization", m_authorization);
req.set_user_agent(!m_agent.empty() ? m_agent : "Abaddon");
#ifdef USE_LOCAL_PROXY
req.set_proxy("http://127.0.0.1:8888");
req.set_verify_ssl(false);
#endif
auto res = req.execute();
@ -128,10 +111,6 @@ http::request HTTPClient::CreateRequest(http::EMethod method, std::string path)
http::request req(method, m_api_base + path);
req.set_header("Authorization", m_authorization);
req.set_user_agent(!m_agent.empty() ? m_agent : "Abaddon");
#ifdef USE_LOCAL_PROXY
req.set_proxy("http://127.0.0.1:8888");
req.set_verify_ssl(false);
#endif
return req;
}
@ -163,6 +142,7 @@ void HTTPClient::AddHeaders(http::request &r) {
for (const auto &[name, val] : m_headers) {
r.set_header(name, val);
}
curl_easy_setopt(r.get_curl(), CURLOPT_COOKIE, m_cookie.c_str());
curl_easy_setopt(r.get_curl(), CURLOPT_ACCEPT_ENCODING, "gzip, deflate, br");
}

View File

@ -18,6 +18,7 @@ public:
void SetUserAgent(std::string agent);
void SetAuth(std::string auth);
void SetPersistentHeader(std::string name, std::string value);
void SetCookie(std::string_view cookie);
void MakeDELETE(const std::string &path, const std::function<void(http::response_type r)> &cb);
void MakeGET(const std::string &path, const std::function<void(http::response_type r)> &cb);
@ -44,4 +45,5 @@ private:
std::string m_authorization;
std::string m_agent;
std::unordered_map<std::string, std::string> m_headers;
std::string m_cookie;
};

View File

@ -2,6 +2,8 @@
#include <utility>
// #define USE_LOCAL_PROXY
namespace http {
request::request(EMethod method, std::string url)
: m_url(std::move(url)) {
@ -147,6 +149,10 @@ response request::execute() {
detail::check_init();
std::string str;
#ifdef USE_LOCAL_PROXY
set_proxy("http://127.0.0.1:8888");
set_verify_ssl(false);
#endif
curl_easy_setopt(m_curl, CURLOPT_NOSIGNAL, 1L);
curl_easy_setopt(m_curl, CURLOPT_CUSTOMREQUEST, m_method);
curl_easy_setopt(m_curl, CURLOPT_URL, m_url.c_str());

126
src/startup.cpp Normal file
View File

@ -0,0 +1,126 @@
#include "startup.hpp"
#include "abaddon.hpp"
#include <future>
#include <memory>
DiscordStartupDialog::DiscordStartupDialog(Gtk::Window &window)
: Gtk::MessageDialog(window, "", false, Gtk::MESSAGE_INFO, Gtk::BUTTONS_NONE, true) {
m_dispatcher.connect(sigc::mem_fun(*this, &DiscordStartupDialog::DispatchCallback));
property_text() = "Getting connection info...";
RunAsync();
}
std::optional<std::string> DiscordStartupDialog::GetCookie() const {
return m_cookie;
}
std::optional<uint32_t> DiscordStartupDialog::GetBuildNumber() const {
return m_build_number;
}
// good enough
std::optional<std::pair<std::string, std::string>> ParseCookie(const Glib::ustring &str) {
auto regex = Glib::Regex::create("\\t");
const std::vector<Glib::ustring> split = regex->split(str);
if (split.size() < 7) return {};
return { { split[5], split[6] } };
}
std::optional<Glib::ustring> GetJavascriptFileFromAppPage(const Glib::ustring &contents) {
auto regex = Glib::Regex::create(R"(app-mount.*(/assets/[\w\d]*.js).*/assets/[\w\d]*.js)");
Glib::MatchInfo match;
if (regex->match(contents, match)) {
return match.fetch(1);
}
return {};
}
std::optional<uint32_t> GetBuildNumberFromJSURL(const Glib::ustring &url, const std::string &cookie) {
http::request req(http::REQUEST_GET, "https://discord.com" + url);
req.set_header("Accept-Language", "en-US,en;q=0.9");
req.set_header("Sec-Fetch-Dest", "document");
req.set_header("Sec-Fetch-Mode", "navigate");
req.set_header("Sec-Fetch-Site", "none");
req.set_header("Sec-Fetch-User", "?1");
req.set_user_agent(Abaddon::Get().GetSettings().UserAgent);
curl_easy_setopt(req.get_curl(), CURLOPT_COOKIE, cookie.c_str());
auto res = req.execute();
if (res.error) return {};
auto regex = Glib::Regex::create(R"("buildNumber",null!==\(t="(\d+)\"\))");
Glib::MatchInfo match;
if (regex->match(res.text, match)) {
const auto str_value = match.fetch(1);
try {
return std::stoul(str_value);
} catch (...) { return {}; }
}
return {};
}
std::pair<std::optional<std::string>, std::string> GetCookieTask() {
http::request req(http::REQUEST_GET, "https://discord.com/app");
req.set_header("Accept-Language", "en-US,en;q=0.9");
req.set_header("Sec-Fetch-Dest", "document");
req.set_header("Sec-Fetch-Mode", "navigate");
req.set_header("Sec-Fetch-Site", "none");
req.set_header("Sec-Fetch-User", "?1");
req.set_user_agent(Abaddon::Get().GetSettings().UserAgent);
curl_easy_setopt(req.get_curl(), CURLOPT_COOKIEFILE, "");
auto res = req.execute();
if (res.error) return {};
curl_slist *slist;
if (curl_easy_getinfo(req.get_curl(), CURLINFO_COOKIELIST, &slist) != CURLE_OK) {
return {};
}
std::string dcfduid;
std::string sdcfduid;
for (auto *cur = slist; cur != nullptr; cur = cur->next) {
const auto cookie = ParseCookie(cur->data);
if (cookie.has_value()) {
if (cookie->first == "__dcfduid") {
dcfduid = cookie->second;
} else if (cookie->first == "__sdcfduid") {
sdcfduid = cookie->second;
}
}
}
curl_slist_free_all(slist);
if (!dcfduid.empty() && !sdcfduid.empty()) {
return { "__dcfduid=" + dcfduid + "; __sdcfduid=" + sdcfduid, res.text };
}
return {};
}
void DiscordStartupDialog::RunAsync() {
auto futptr = std::make_shared<std::future<void>>();
*futptr = std::async(std::launch::async, [this, futptr] {
auto [opt_cookie, app_page] = GetCookieTask();
m_cookie = opt_cookie;
if (opt_cookie.has_value()) {
auto js_url = GetJavascriptFileFromAppPage(app_page);
if (js_url.has_value()) {
m_build_number = GetBuildNumberFromJSURL(*js_url, *opt_cookie);
}
}
m_dispatcher.emit();
});
}
void DiscordStartupDialog::DispatchCallback() {
response(Gtk::RESPONSE_OK);
}

25
src/startup.hpp Normal file
View File

@ -0,0 +1,25 @@
#pragma once
#include <glibmm/dispatcher.h>
#include <gtkmm/messagedialog.h>
#include <gtkmm/window.h>
#include <optional>
// fetch cookies, build number async
class DiscordStartupDialog : public Gtk::MessageDialog {
public:
DiscordStartupDialog(Gtk::Window &window);
[[nodiscard]] std::optional<std::string> GetCookie() const;
[[nodiscard]] std::optional<uint32_t> GetBuildNumber() const;
private:
void RunAsync();
void DispatchCallback();
Glib::Dispatcher m_dispatcher;
std::optional<std::string> m_cookie;
std::optional<uint32_t> m_build_number;
};