spoof a bunch of headers like the web client

This commit is contained in:
ouwou 2022-08-11 23:37:39 -04:00
parent baf96da80c
commit dc28eae95a
9 changed files with 96 additions and 2 deletions

View File

@ -647,12 +647,17 @@ void Abaddon::ActionJoinGuildDialog() {
} }
void Abaddon::ActionChannelOpened(Snowflake id, bool expand_to) { void Abaddon::ActionChannelOpened(Snowflake id, bool expand_to) {
if (!id.IsValid() || id == m_main_window->GetChatActiveChannel()) return; if (!id.IsValid()) {
m_discord.SetReferringChannel(Snowflake::Invalid);
return;
}
if (id == m_main_window->GetChatActiveChannel()) return;
m_main_window->GetChatWindow()->SetTopic(""); m_main_window->GetChatWindow()->SetTopic("");
const auto channel = m_discord.GetChannel(id); const auto channel = m_discord.GetChannel(id);
if (!channel.has_value()) { if (!channel.has_value()) {
m_discord.SetReferringChannel(Snowflake::Invalid);
m_main_window->UpdateChatActiveChannel(Snowflake::Invalid, false); m_main_window->UpdateChatActiveChannel(Snowflake::Invalid, false);
m_main_window->UpdateChatWindowContents(); m_main_window->UpdateChatWindowContents();
return; return;
@ -701,6 +706,7 @@ void Abaddon::ActionChannelOpened(Snowflake id, bool expand_to) {
} }
m_main_window->UpdateMenus(); m_main_window->UpdateMenus();
m_discord.SetReferringChannel(id);
} }
void Abaddon::ActionChatLoadHistory(Snowflake id) { void Abaddon::ActionChatLoadHistory(Snowflake id) {

View File

@ -30,6 +30,7 @@ void DiscordClient::Start() {
if (m_client_started) return; if (m_client_started) return;
m_http.SetBase(GetAPIURL()); m_http.SetBase(GetAPIURL());
SetHeaders();
std::memset(&m_zstream, 0, sizeof(m_zstream)); std::memset(&m_zstream, 0, sizeof(m_zstream));
inflateInit2(&m_zstream, MAX_WBITS + 32); inflateInit2(&m_zstream, MAX_WBITS + 32);
@ -1110,6 +1111,25 @@ void DiscordClient::AcceptVerificationGate(Snowflake guild_id, VerificationGateI
}); });
} }
void DiscordClient::SetReferringChannel(Snowflake id) {
if (!id.IsValid()) {
m_http.SetPersistentHeader("Referer", "https://discord.com/channels/@me");
} else {
const auto channel = GetChannel(id);
if (channel.has_value()) {
if (channel->IsDM()) {
m_http.SetPersistentHeader("Referer", "https://discord.com/channels/@me/" + std::to_string(id));
} else if (channel->GuildID.has_value()) {
m_http.SetPersistentHeader("Referer", "https://discord.com/channels/" + std::to_string(*channel->GuildID) + "/" + std::to_string(id));
} else {
m_http.SetPersistentHeader("Referer", "https://discord.com/channels/@me");
}
} else {
m_http.SetPersistentHeader("Referer", "https://discord.com/channels/@me");
}
}
}
void DiscordClient::UpdateToken(const std::string &token) { void DiscordClient::UpdateToken(const std::string &token) {
if (!IsStarted()) { if (!IsStarted()) {
m_token = token; m_token = token;
@ -2245,6 +2265,7 @@ void DiscordClient::SendIdentify() {
msg.ClientState.HighestLastMessageID = "0"; msg.ClientState.HighestLastMessageID = "0";
msg.ClientState.ReadStateVersion = 0; msg.ClientState.ReadStateVersion = 0;
msg.ClientState.UserGuildSettingsVersion = -1; msg.ClientState.UserGuildSettingsVersion = -1;
SetSuperPropertiesFromIdentity(msg);
const bool b = m_websocket.GetPrintMessages(); const bool b = m_websocket.GetPrintMessages();
m_websocket.SetPrintMessages(false); m_websocket.SetPrintMessages(false);
m_websocket.Send(msg); m_websocket.Send(msg);
@ -2259,6 +2280,36 @@ void DiscordClient::SendResume() {
m_websocket.Send(msg); m_websocket.Send(msg);
} }
void DiscordClient::SetHeaders() {
m_http.SetPersistentHeader("Sec-Fetch-Dest", "empty");
m_http.SetPersistentHeader("Sec-Fetch-Mode", "cors");
m_http.SetPersistentHeader("Sec-Fetch-Site", "same-origin");
m_http.SetPersistentHeader("X-Debug-Options", "bugReporterEnabled");
m_http.SetPersistentHeader("Accept-Language", "en-US,en;q=0.9");
SetReferringChannel(Snowflake::Invalid);
}
void DiscordClient::SetSuperPropertiesFromIdentity(const IdentifyMessage &identity) {
nlohmann::ordered_json j;
j["os"] = identity.Properties.OS;
j["browser"] = identity.Properties.Browser;
j["device"] = identity.Properties.Device;
j["system_locale"] = identity.Properties.SystemLocale;
j["browser_user_agent"] = identity.Properties.BrowserUserAgent;
j["browser_version"] = identity.Properties.BrowserVersion;
j["os_version"] = identity.Properties.OSVersion;
j["referrer"] = identity.Properties.Referrer;
j["referring_domain"] = identity.Properties.ReferringDomain;
j["referrer_current"] = identity.Properties.ReferrerCurrent;
j["referring_domain_current"] = identity.Properties.ReferringDomainCurrent;
j["release_channel"] = identity.Properties.ReleaseChannel;
j["client_build_number"] = identity.Properties.ClientBuildNumber;
j["client_event_source"] = nullptr; // probably will never be non-null ("") anyways
m_http.SetPersistentHeader("X-Super-Properties", Glib::Base64::encode(j.dump()));
m_http.SetPersistentHeader("X-Discord-Locale", identity.Properties.SystemLocale);
}
void DiscordClient::HandleSocketOpen() { void DiscordClient::HandleSocketOpen() {
} }

View File

@ -201,6 +201,8 @@ public:
void GetVerificationGateInfo(Snowflake guild_id, const sigc::slot<void(std::optional<VerificationGateInfoObject>)> &callback); 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 AcceptVerificationGate(Snowflake guild_id, VerificationGateInfoObject info, const sigc::slot<void(DiscordError code)> &callback);
void SetReferringChannel(Snowflake id);
void UpdateToken(const std::string &token); void UpdateToken(const std::string &token);
void SetUserAgent(const std::string &agent); void SetUserAgent(const std::string &agent);
@ -282,6 +284,9 @@ private:
void SendIdentify(); void SendIdentify();
void SendResume(); void SendResume();
void SetHeaders();
void SetSuperPropertiesFromIdentity(const IdentifyMessage &identity);
void HandleSocketOpen(); void HandleSocketOpen();
void HandleSocketClose(uint16_t code); void HandleSocketClose(uint16_t code);

View File

@ -19,11 +19,17 @@ void HTTPClient::SetAuth(std::string auth) {
m_authorization = std::move(auth); m_authorization = std::move(auth);
} }
void HTTPClient::SetPersistentHeader(std::string name, std::string value) {
m_headers.insert_or_assign(std::move(name), std::move(value));
}
void HTTPClient::MakeDELETE(const std::string &path, const std::function<void(http::response_type r)> &cb) { void HTTPClient::MakeDELETE(const std::string &path, const std::function<void(http::response_type r)> &cb) {
printf("DELETE %s\n", path.c_str()); printf("DELETE %s\n", path.c_str());
m_futures.push_back(std::async(std::launch::async, [this, path, cb] { m_futures.push_back(std::async(std::launch::async, [this, path, cb] {
http::request req(http::REQUEST_DELETE, m_api_base + path); http::request req(http::REQUEST_DELETE, m_api_base + path);
AddHeaders(req);
req.set_header("Authorization", m_authorization); req.set_header("Authorization", m_authorization);
req.set_header("Origin", "https://discord.com");
req.set_user_agent(!m_agent.empty() ? m_agent : "Abaddon"); req.set_user_agent(!m_agent.empty() ? m_agent : "Abaddon");
#ifdef USE_LOCAL_PROXY #ifdef USE_LOCAL_PROXY
req.set_proxy("http://127.0.0.1:8888"); req.set_proxy("http://127.0.0.1:8888");
@ -40,8 +46,10 @@ void HTTPClient::MakePATCH(const std::string &path, const std::string &payload,
printf("PATCH %s\n", path.c_str()); printf("PATCH %s\n", path.c_str());
m_futures.push_back(std::async(std::launch::async, [this, path, cb, payload] { m_futures.push_back(std::async(std::launch::async, [this, path, cb, payload] {
http::request req(http::REQUEST_PATCH, m_api_base + path); http::request req(http::REQUEST_PATCH, m_api_base + path);
AddHeaders(req);
req.set_header("Authorization", m_authorization); req.set_header("Authorization", m_authorization);
req.set_header("Content-Type", "application/json"); req.set_header("Content-Type", "application/json");
req.set_header("Origin", "https://discord.com");
req.set_user_agent(!m_agent.empty() ? m_agent : "Abaddon"); req.set_user_agent(!m_agent.empty() ? m_agent : "Abaddon");
req.set_body(payload); req.set_body(payload);
#ifdef USE_LOCAL_PROXY #ifdef USE_LOCAL_PROXY
@ -59,8 +67,10 @@ void HTTPClient::MakePOST(const std::string &path, const std::string &payload, c
printf("POST %s\n", path.c_str()); printf("POST %s\n", path.c_str());
m_futures.push_back(std::async(std::launch::async, [this, path, cb, payload] { m_futures.push_back(std::async(std::launch::async, [this, path, cb, payload] {
http::request req(http::REQUEST_POST, m_api_base + path); http::request req(http::REQUEST_POST, m_api_base + path);
AddHeaders(req);
req.set_header("Authorization", m_authorization); req.set_header("Authorization", m_authorization);
req.set_header("Content-Type", "application/json"); req.set_header("Content-Type", "application/json");
req.set_header("Origin", "https://discord.com");
req.set_user_agent(!m_agent.empty() ? m_agent : "Abaddon"); req.set_user_agent(!m_agent.empty() ? m_agent : "Abaddon");
req.set_body(payload); req.set_body(payload);
#ifdef USE_LOCAL_PROXY #ifdef USE_LOCAL_PROXY
@ -78,7 +88,9 @@ void HTTPClient::MakePUT(const std::string &path, const std::string &payload, co
printf("PUT %s\n", path.c_str()); printf("PUT %s\n", path.c_str());
m_futures.push_back(std::async(std::launch::async, [this, path, cb, payload] { m_futures.push_back(std::async(std::launch::async, [this, path, cb, payload] {
http::request req(http::REQUEST_PUT, m_api_base + path); http::request req(http::REQUEST_PUT, m_api_base + path);
AddHeaders(req);
req.set_header("Authorization", m_authorization); req.set_header("Authorization", m_authorization);
req.set_header("Origin", "https://discord.com");
if (!payload.empty()) if (!payload.empty())
req.set_header("Content-Type", "application/json"); req.set_header("Content-Type", "application/json");
req.set_user_agent(!m_agent.empty() ? m_agent : "Abaddon"); req.set_user_agent(!m_agent.empty() ? m_agent : "Abaddon");
@ -98,8 +110,8 @@ void HTTPClient::MakeGET(const std::string &path, const std::function<void(http:
printf("GET %s\n", path.c_str()); printf("GET %s\n", path.c_str());
m_futures.push_back(std::async(std::launch::async, [this, path, cb] { m_futures.push_back(std::async(std::launch::async, [this, path, cb] {
http::request req(http::REQUEST_GET, m_api_base + path); http::request req(http::REQUEST_GET, m_api_base + path);
AddHeaders(req);
req.set_header("Authorization", m_authorization); req.set_header("Authorization", m_authorization);
req.set_header("Content-Type", "application/json");
req.set_user_agent(!m_agent.empty() ? m_agent : "Abaddon"); req.set_user_agent(!m_agent.empty() ? m_agent : "Abaddon");
#ifdef USE_LOCAL_PROXY #ifdef USE_LOCAL_PROXY
req.set_proxy("http://127.0.0.1:8888"); req.set_proxy("http://127.0.0.1:8888");
@ -128,6 +140,13 @@ void HTTPClient::RunCallbacks() {
m_mutex.unlock(); m_mutex.unlock();
} }
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_ACCEPT_ENCODING, "gzip, deflate, br");
}
void HTTPClient::OnResponse(const http::response_type &r, const std::function<void(http::response_type r)> &cb) { void HTTPClient::OnResponse(const http::response_type &r, const std::function<void(http::response_type r)> &cb) {
CleanupFutures(); CleanupFutures();
try { try {

View File

@ -17,6 +17,8 @@ public:
void SetUserAgent(std::string agent); void SetUserAgent(std::string agent);
void SetAuth(std::string auth); void SetAuth(std::string auth);
void SetPersistentHeader(std::string name, std::string value);
void MakeDELETE(const std::string &path, const std::function<void(http::response_type r)> &cb); 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); void MakeGET(const std::string &path, const std::function<void(http::response_type r)> &cb);
void MakePATCH(const std::string &path, const std::string &payload, const std::function<void(http::response_type r)> &cb); void MakePATCH(const std::string &path, const std::string &payload, const std::function<void(http::response_type r)> &cb);
@ -24,6 +26,8 @@ public:
void MakePUT(const std::string &path, const std::string &payload, const std::function<void(http::response_type r)> &cb); void MakePUT(const std::string &path, const std::string &payload, const std::function<void(http::response_type r)> &cb);
private: private:
void AddHeaders(http::request &r);
void OnResponse(const http::response_type &r, const std::function<void(http::response_type r)> &cb); void OnResponse(const http::response_type &r, const std::function<void(http::response_type r)> &cb);
void CleanupFutures(); void CleanupFutures();
@ -36,4 +40,5 @@ private:
std::string m_api_base; std::string m_api_base;
std::string m_authorization; std::string m_authorization;
std::string m_agent; std::string m_agent;
std::unordered_map<std::string, std::string> m_headers;
}; };

View File

@ -262,6 +262,7 @@ void to_json(nlohmann::json &j, const ClientStateProperties &m) {
j["highest_last_message_id"] = m.HighestLastMessageID; j["highest_last_message_id"] = m.HighestLastMessageID;
j["read_state_version"] = m.ReadStateVersion; j["read_state_version"] = m.ReadStateVersion;
j["user_guild_settings_version"] = m.UserGuildSettingsVersion; j["user_guild_settings_version"] = m.UserGuildSettingsVersion;
j["user_settings_version"] = m.UserSettingsVersion;
} }
void to_json(nlohmann::json &j, const IdentifyMessage &m) { void to_json(nlohmann::json &j, const IdentifyMessage &m) {

View File

@ -382,6 +382,7 @@ struct ClientStateProperties {
std::string HighestLastMessageID = "0"; std::string HighestLastMessageID = "0";
int ReadStateVersion = 0; int ReadStateVersion = 0;
int UserGuildSettingsVersion = -1; int UserGuildSettingsVersion = -1;
int UserSettingsVersion = -1;
friend void to_json(nlohmann::json &j, const ClientStateProperties &m); friend void to_json(nlohmann::json &j, const ClientStateProperties &m);
}; };

View File

@ -57,6 +57,10 @@ void request::set_user_agent(const std::string &data) {
curl_easy_setopt(m_curl, CURLOPT_USERAGENT, data.c_str()); curl_easy_setopt(m_curl, CURLOPT_USERAGENT, data.c_str());
} }
CURL *request::get_curl() {
return m_curl;
}
response request::execute() { response request::execute() {
if (m_curl == nullptr) { if (m_curl == nullptr) {
auto response = detail::make_response(m_url, EStatusCode::ClientErrorCURLInit); auto response = detail::make_response(m_url, EStatusCode::ClientErrorCURLInit);

View File

@ -108,6 +108,8 @@ struct request {
response execute(); response execute();
CURL *get_curl();
private: private:
void prepare(); void prepare();