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

Add support for X-Super-Properties. #25

Merged
merged 3 commits into from
Jun 13, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
116 changes: 116 additions & 0 deletions src/discord/DiscordClientConfig.cpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,116 @@
#include "DiscordClientConfig.hpp"
#include <boost/base64/base64.hpp>

// TODO: Fetch some of these properties from the system (e.g. system locale)

// This configuration simulates a Microsoft Edge web client on Microsoft Windows 10.

DiscordClientConfig* GetClientConfig()
{
static DiscordClientConfig s_config;
return &s_config;
}

DiscordClientConfig::DiscordClientConfig()
{
// Setup here
m_os = "Windows";
m_browser = "Chrome";
m_systemLocale = "en-US";
m_timeZone = "Europe/Bucharest"; // TODO: UTC here
m_browserVersion = "125.0.0.0";
m_browserVersionSimple = "125";
m_webKitVersion = "537.36";
m_osVersion = "10";
m_releaseChannel = "stable";
m_clientBuildNumber = 301663;
m_device = "";
m_referrer = "";
m_referrerCurrent = "";
m_referringDomain = "";
m_referringDomainCurrent = "";
m_designId = 0;

m_browserUserAgent =
"Mozilla/5.0 (Windows NT "
+ m_osVersion
+ ".0; Win64; x64) AppleWebKit/"
+ m_webKitVersion
+ " (KHTML, like Gecko) Chrome/"
+ m_browserVersion
+ " Safari/"
+ m_webKitVersion
+ " Edg/"
+ m_browserVersion;

m_secChUa = "\"Chromium\";v=\"" + m_browserVersionSimple + "\", \"Microsoft Edge\";v=\"125\", \"Not-A.Brand\";v=\"99\"";

// Ok, now serialize it
nlohmann::json j = Serialize();

std::string str = j.dump();
m_serializedJsonBlob = str;

char* buffer = new char[base64::encoded_size(str.size()) + 1];
size_t sz = base64::encode(buffer, str.data(), str.size());
std::string dataToSend(buffer, sz);
delete[] buffer;

m_serializedBase64Blob = dataToSend;
}

nlohmann::json DiscordClientConfig::Serialize() const
{
nlohmann::json j;
j["os"] = m_os;
j["browser"] = m_browser;
j["device"] = m_device;
j["system_locale"] = m_systemLocale;
j["browser_user_agent"] = m_browserUserAgent;
j["browser_version"] = m_browserVersion;
j["os_version"] = m_osVersion;
j["referrer"] = m_referrer;
j["referring_domain"] = m_referringDomain;
j["referrer_current"] = m_referrerCurrent;
j["referring_domain_current"] = m_referringDomainCurrent;
j["release_channel"] = m_releaseChannel;
j["client_build_number"] = m_clientBuildNumber;
j["client_event_source"] = nullptr;
j["design_id"] = m_designId;
return j;
}

const std::string& DiscordClientConfig::GetSerializedJsonBlob() const
{
return m_serializedJsonBlob;
}

const std::string& DiscordClientConfig::GetSerializedBase64Blob() const
{
return m_serializedBase64Blob;
}

const std::string& DiscordClientConfig::GetUserAgent() const
{
return m_browserUserAgent;
}

const std::string& DiscordClientConfig::GetSecChUa() const
{
return m_secChUa;
}

const std::string& DiscordClientConfig::GetLocale() const
{
return m_systemLocale;
}

const std::string& DiscordClientConfig::GetTimezone() const
{
return m_timeZone;
}

const std::string& DiscordClientConfig::GetOS() const
{
return m_os;
}
48 changes: 48 additions & 0 deletions src/discord/DiscordClientConfig.hpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,48 @@
#pragma once

#include <nlohmann/json.h>
#include <string>

class DiscordClientConfig
{
public:
DiscordClientConfig();

const std::string& GetUserAgent() const;
const std::string& GetSecChUa() const;
const std::string& GetLocale() const;
const std::string& GetTimezone() const;
const std::string& GetOS() const;

nlohmann::json Serialize() const;
const std::string& GetSerializedJsonBlob() const;
const std::string& GetSerializedBase64Blob() const;

private:
std::string m_os;
std::string m_browser;
std::string m_device;
std::string m_systemLocale;
std::string m_browserUserAgent;
std::string m_browserVersion;
std::string m_osVersion;
std::string m_referrer;
std::string m_referringDomain;
std::string m_referrerCurrent;
std::string m_referringDomainCurrent;
std::string m_releaseChannel;
int m_clientBuildNumber;
int m_designId;

// not part of the actual header itself, just the user agent
std::string m_webKitVersion;


std::string m_browserVersionSimple;
std::string m_secChUa;
std::string m_timeZone;
std::string m_serializedJsonBlob;
std::string m_serializedBase64Blob;
};

DiscordClientConfig* GetClientConfig();
3 changes: 2 additions & 1 deletion src/discord/DiscordInstance.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@
#include "Util.hpp"
#include "Frontend.hpp"
#include "HTTPClient.hpp"
#include "DiscordClientConfig.hpp"

#define DISCORD_WSS_DETAILS "?encoding=json&v=" DISCORD_API_VERSION

Expand Down Expand Up @@ -1144,7 +1145,7 @@ void DiscordInstance::HandleGatewayMessage(const std::string& payload)
presenceData["since"] = 0;
presenceData["status"] = "online";

GetFrontend()->GetIdentifyProperties(propertiesData);
propertiesData = GetClientConfig()->Serialize();

data["presence"] = presenceData;
data["properties"] = propertiesData;
Expand Down
8 changes: 2 additions & 6 deletions src/discord/Frontend.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -83,14 +83,10 @@ class Frontend

// Quit
virtual void RequestQuit() = 0;

// Queries
virtual bool IsWindowMinimized() = 0;

// User stuff
virtual void GetIdentifyProperties(nlohmann::json& j) = 0;
virtual std::string GetUserAgent() = 0;


// Strings
virtual std::string GetDirectMessagesText() = 0;
virtual std::string GetPleaseWaitText() = 0;
Expand Down
6 changes: 5 additions & 1 deletion src/discord/LocalSettings.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -116,6 +116,9 @@ bool LocalSettings::Load()

if (j.contains("RemindUpdateCheckOn"))
m_remindUpdatesOn = (time_t) (long long) j["RemindUpdateCheckOn"];

if (j.contains("AddExtraHeaders"))
m_bAddExtraHeaders = j["AddExtraHeaders"];

return true;
}
Expand Down Expand Up @@ -144,7 +147,8 @@ bool LocalSettings::Save()
j["ImageBackgroundFileName"] = m_imageBackgroundFileName;
j["WatermarkAlignment"] = int(m_imageAlignment);
j["UserScale"] = m_userScale;

j["AddExtraHeaders"] = m_bAddExtraHeaders;

if (m_bSaveWindowSize) {
j["WindowWidth"] = m_width;
j["WindowHeight"] = m_height;
Expand Down
7 changes: 7 additions & 0 deletions src/discord/LocalSettings.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -108,6 +108,12 @@ class LocalSettings
void SetEnableTLSVerification(bool b) {
m_bEnableTLSVerification = b;
}
bool AddExtraHeaders() const {
return m_bAddExtraHeaders;
}
void SetAddExtraHeaders(bool b) {
m_bAddExtraHeaders = b;
}
void StopUpdateCheckTemporarily();
bool DisableFormatting() const {
return m_bDisableFormatting;
Expand Down Expand Up @@ -158,6 +164,7 @@ class LocalSettings
bool m_bDisableFormatting = false;
bool m_bShowScrollBarOnGuildList = false;
bool m_bCompactMemberList = false;
bool m_bAddExtraHeaders = true;
time_t m_remindUpdatesOn = 0;
int m_width = 1000;
int m_height = 700;
Expand Down
3 changes: 2 additions & 1 deletion src/discord/WebsocketClient.cpp
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
#include "WebsocketClient.hpp"
#include "DiscordClientConfig.hpp"
#include "Frontend.hpp"
#include "Util.hpp"
#include "LocalSettings.hpp"
Expand Down Expand Up @@ -216,7 +217,7 @@ int WebsocketClient::Connect(const std::string& uri)
return -1;
}

con->append_header("User-Agent", GetFrontend()->GetUserAgent());
con->append_header("User-Agent", GetClientConfig()->GetUserAgent());
con->append_header("Origin", "https://discord.com");

int newID = m_nextId++;
Expand Down
4 changes: 2 additions & 2 deletions src/resource.h
Original file line number Diff line number Diff line change
Expand Up @@ -381,7 +381,6 @@
#define IDC_UPLOADING_ETA 878
#define IDC_UPLOADING_XFERRATE 879
#define IDC_UPLOADING_ACTION 880
#define IDC_ANIMATE1 881
#define IDC_PROGRESS_ANIMATE 881
#define IDC_MESSAGE_STYLE 882
#define IDC_ACTIVE_IMAGE_BROWSE 884
Expand All @@ -391,6 +390,7 @@
#define IDC_COMBO_ALIGNMENT 889
#define IDC_COMBO_GUI_SCALE 890
#define IDC_NOTIFICATION_HINT 891
#define IDC_TOGGLE_XSUPERPROPS 892
#define ID_FILE_PREFERENCES 1001
#define ID_FILE_STOPALLSPEECH 1002
#define ID_FILE_EXIT 1003
Expand Down Expand Up @@ -469,7 +469,7 @@
#ifndef APSTUDIO_READONLY_SYMBOLS
#define _APS_NEXT_RESOURCE_VALUE 101
#define _APS_NEXT_COMMAND_VALUE 1069
#define _APS_NEXT_CONTROL_VALUE 892
#define _APS_NEXT_CONTROL_VALUE 893
#define _APS_NEXT_SYMED_VALUE 40000
#endif
#endif
8 changes: 5 additions & 3 deletions src/resource.rc
Original file line number Diff line number Diff line change
Expand Up @@ -595,10 +595,10 @@ BEGIN
EDITTEXT IDC_EDIT_DISCORDCDN,72,33,174,14,ES_AUTOHSCROLL
PUSHBUTTON "Revert to official Discord backend",IDC_REVERTTODEFAULT,12,116,118,14
PUSHBUTTON "Update",IDC_UPDATE,198,116,50,14
ICON IDI_WARNING_IC,IDC_ICON_WARN_CONNECT,12,55,21,20,SS_REALSIZEIMAGE
ICON IDI_WARNING_IC,IDC_ICON_WARN_CONNECT,12,54,21,20,SS_REALSIZEIMAGE
LTEXT "For security reasons, when you update the URLs that Discord Messenger uses to interface with Discord's backend, you will be logged out. (your token is forgotten but not revoked)",IDC_STATIC,33,54,215,31
ICON IDI_WARNING_IC,IDC_ICON_WARN_WEBSOCKETSTUFF,12,87,21,20,SS_REALSIZEIMAGE
LTEXT "Wondering where the websocket gateway URL is located? Well, Discord Messenger issues a request to API_URL/gateway, which tells it the websocket URL to use.",IDC_STATIC,33,87,215,29
ICON IDI_WARNING_IC,IDC_ICON_WARN_WEBSOCKETSTUFF,12,82,21,20,SS_REALSIZEIMAGE
LTEXT "NOTE: Discord Messenger automatically fetches the websocket gateway URL using the API_URL/gateway endpoint.",IDC_STATIC,33,82,214,19
GROUPBOX "Security Settings",IDC_STATIC,6,139,248,48
ICON IDI_WARNING_IC,IDC_ICON_WARN_WEBSOCKETSTUFF2,12,166,21,20,SS_REALSIZEIMAGE
LTEXT "WARNING: Disabling TLS certificate verification could expose you to MITM (man-in-the-middle) attacks via certificate spoofing!",IDC_STATIC,33,165,215,19
Expand All @@ -608,6 +608,8 @@ BEGIN
CONTROL "Check for updates using the GitHub API",IDC_CHECK_UPDATES,
"Button",BS_AUTOCHECKBOX | WS_TABSTOP,12,204,236,10
LTEXT "iProgramInCpp cannot see your IP address via the update service.",IDC_STATIC,12,219,231,10
CONTROL "Add extra headers such as X-Super-Properties to HTTP requests.",IDC_TOGGLE_XSUPERPROPS,
"Button",BS_AUTOCHECKBOX | WS_TABSTOP,12,104,231,10
END

IDD_DIALOG_UPLOADING DIALOGEX 0, 0, 275, 135
Expand Down
24 changes: 0 additions & 24 deletions src/windows/Frontend_Win32.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -10,8 +10,6 @@
#include "../discord/UpdateChecker.hpp"
#include "../discord/LocalSettings.hpp"

const std::string g_UserAgent = "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) discord/1.0.284 Chrome/120.0.6099.283 Electron/28.2.3 Safari/537.36";

void Frontend_Win32::OnLoginAgain()
{
SendMessage(g_Hwnd, WM_LOGINAGAIN, 0, 0);
Expand Down Expand Up @@ -406,23 +404,6 @@ bool Frontend_Win32::IsWindowMinimized()
return IsIconic(g_Hwnd);
}

void Frontend_Win32::GetIdentifyProperties(nlohmann::json& j)
{
j["app_arch"] = "x64";
j["browser"] = "Discord Client";
j["browser_user_agent"] = g_UserAgent;
j["browser_version"] = "28.2.3";
j["client_build_number"] = 269579;
j["client_event_source"] = nullptr;
j["client_version"] = "1.0.284";
j["native_build_number"] = 44304;
j["os"] = "Windows";
j["os_arch"] = "x64";
j["os_version"] = "10.0.19044";
j["release_channel"] = "canary";
j["system_locale"] = "en-US";
}

#ifdef USE_DEBUG_PRINTS

void DbgPrintWV(const char* fmt, va_list vl)
Expand All @@ -449,11 +430,6 @@ void Frontend_Win32::DebugPrint(const char* fmt, va_list vl)

#endif

std::string Frontend_Win32::GetUserAgent()
{
return g_UserAgent;
}

void Frontend_Win32::SetHeartbeatInterval(int timeMs)
{
::SetHeartbeatInterval(timeMs);
Expand Down
2 changes: 0 additions & 2 deletions src/windows/Frontend_Win32.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -60,8 +60,6 @@ class Frontend_Win32 : public Frontend
void RegisterChannelIcon(Snowflake sf, const std::string& avatarlnk) override;
void RequestQuit() override;
bool IsWindowMinimized() override;
void GetIdentifyProperties(nlohmann::json& j) override;
std::string GetUserAgent() override;
std::string GetDirectMessagesText() override;
std::string GetPleaseWaitText() override;
std::string GetMonthName(int index) override;
Expand Down
18 changes: 17 additions & 1 deletion src/windows/NetworkerThread.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@
#include "../discord/DiscordRequest.hpp"
#include "../discord/LocalSettings.hpp"
#include "../discord/Frontend.hpp"
#include "../discord/DiscordClientConfig.hpp"

#define CPPHTTPLIB_OPENSSL_SUPPORT

Expand All @@ -29,6 +30,11 @@ static bool g_bQuittingFromSSLError;

int g_latestSSLError = 0; // HACK - used by httplib.h, to debug some weird issue

bool AddExtraHeaders()
{
return GetLocalSettings()->AddExtraHeaders();
}

int NetRequest::Priority() const
{
int prio = 0;
Expand Down Expand Up @@ -203,7 +209,17 @@ void NetworkerThread::FulfillRequest(NetRequest& req)
client.set_follow_location(true);

Headers headers;
headers.insert(std::make_pair("User-Agent", GetFrontend()->GetUserAgent()));
headers.insert(std::make_pair("User-Agent", GetClientConfig()->GetUserAgent()));

if (AddExtraHeaders())
{
headers.insert(std::make_pair("X-Super-Properties", GetClientConfig()->GetSerializedBase64Blob()));
headers.insert(std::make_pair("X-Discord-Timezone", GetClientConfig()->GetTimezone()));
headers.insert(std::make_pair("X-Discord-Locale", GetClientConfig()->GetLocale()));
headers.insert(std::make_pair("Sec-Ch-Ua", GetClientConfig()->GetSecChUa()));
headers.insert(std::make_pair("Sec-Ch-Ua-Mobile", "?0"));
headers.insert(std::make_pair("Sec-Ch-Ua-Platform", GetClientConfig()->GetOS()));
}

if (req.authorization.size())
{
Expand Down
Loading