pretend to be a real client a little better

This commit is contained in:
ouwou
2020-12-14 03:05:16 -05:00
parent 33ed25b2f6
commit 22578921b9
10 changed files with 134 additions and 43 deletions

View File

@@ -15,6 +15,7 @@ void from_json(const nlohmann::json &j, Channel &m) {
JS_O("user_limit", m.UserLimit);
JS_O("rate_limit_per_user", m.RateLimitPerUser);
JS_O("recipients", m.Recipients);
JS_O("recipient_ids", m.RecipientIDs);
JS_ON("icon", m.Icon);
JS_O("owner_id", m.OwnerID);
JS_O("application_id", m.ApplicationID);
@@ -45,3 +46,22 @@ void Channel::update_from_json(const nlohmann::json &j) {
std::optional<PermissionOverwrite> Channel::GetOverwrite(Snowflake id) const {
return Abaddon::Get().GetDiscordClient().GetPermissionOverwrite(ID, id);
}
std::vector<User> Channel::GetDMRecipients() const {
const auto &discord = Abaddon::Get().GetDiscordClient();
if (Recipients.has_value())
return *Recipients;
if (RecipientIDs.has_value()) {
std::vector<User> ret;
for (const auto &id : *RecipientIDs) {
auto user = discord.GetUser(id);
if (user.has_value())
ret.push_back(std::move(*user));
}
return ret;
}
return std::vector<User>();
}

View File

@@ -30,7 +30,8 @@ struct Channel {
std::optional<int> UserLimit;
std::optional<int> RateLimitPerUser;
std::optional<std::vector<User>> Recipients; // only access id
std::optional<std::string> Icon; // null
std::optional<std::vector<Snowflake>> RecipientIDs;
std::optional<std::string> Icon; // null
std::optional<Snowflake> OwnerID;
std::optional<Snowflake> ApplicationID;
std::optional<Snowflake> ParentID; // null
@@ -40,4 +41,5 @@ struct Channel {
void update_from_json(const nlohmann::json &j);
std::optional<PermissionOverwrite> GetOverwrite(Snowflake id) const;
std::vector<User> GetDMRecipients() const;
};

View File

@@ -403,7 +403,8 @@ std::optional<Snowflake> DiscordClient::FindDM(Snowflake user_id) {
const auto &channels = m_store.GetChannels();
for (const auto &id : channels) {
const auto channel = m_store.GetChannel(id);
if (channel->Recipients->size() == 1 && channel->Recipients.value()[0].ID == user_id)
const auto recipients = channel->GetDMRecipients();
if (recipients.size() == 1 && recipients[0].ID == user_id)
return id;
}
@@ -612,13 +613,17 @@ void DiscordClient::HandleGatewayReady(const GatewayMessage &msg) {
m_store.BeginTransaction();
for (const auto &dm : data.PrivateChannels) {
m_store.SetChannel(dm.ID, dm);
for (const auto &recipient : *dm.Recipients)
m_store.SetUser(recipient.ID, recipient);
if (dm.Recipients.has_value())
for (const auto &recipient : *dm.Recipients)
m_store.SetUser(recipient.ID, recipient);
}
if (data.Users.has_value())
for (const auto &user : *data.Users)
m_store.SetUser(user.ID, user);
m_store.EndTransaction();
m_session_id = data.SessionID;
m_user_data = data.User;
m_user_data = data.SelfUser;
m_user_settings = data.UserSettings;
m_signal_gateway_ready.emit();
}
@@ -857,10 +862,28 @@ void DiscordClient::HeartbeatThread() {
void DiscordClient::SendIdentify() {
IdentifyMessage msg;
msg.Properties.OS = "OpenBSD";
msg.Properties.Device = GatewayIdentity;
msg.Properties.Browser = GatewayIdentity;
msg.Token = m_token;
msg.Capabilities = 61; // no idea what 61 means
msg.Properties.OS = "Windows";
msg.Properties.Browser = "";
msg.Properties.Device = "Chrome";
msg.Properties.BrowserUserAgent = "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/67.0.3396.87 Safari/537.36";
msg.Properties.BrowserVersion = "67.0.3396.87";
msg.Properties.OSVersion = "10";
msg.Properties.Referrer = "";
msg.Properties.ReferringDomain = "";
msg.Properties.ReferrerCurrent = "";
msg.Properties.ReferringDomainCurrent = "";
msg.Properties.ReleaseChannel = "stable";
msg.Properties.ClientBuildNumber = 73363;
msg.Properties.ClientEventSource = "";
msg.Presence.Status = "online";
msg.Presence.Since = 0;
msg.Presence.IsAFK = false;
msg.DoesSupportCompression = false;
msg.ClientState.HighestLastMessageID = "0";
msg.ClientState.ReadStateVersion = 0;
msg.ClientState.UserGuildSettingsVersion = -1;
m_websocket.Send(msg);
}

View File

@@ -52,7 +52,6 @@ class DiscordClient {
public:
static const constexpr char *DiscordGateway = "wss://gateway.discord.gg/?v=8&encoding=json&compress=zlib-stream";
static const constexpr char *DiscordAPI = "https://discord.com/api";
static const constexpr char *GatewayIdentity = "Discord";
public:
DiscordClient(bool mem_store = false);

View File

@@ -94,29 +94,51 @@ void to_json(nlohmann::json &j, const UpdateStatusMessage &m) {
void from_json(const nlohmann::json &j, ReadyEventData &m) {
JS_D("v", m.GatewayVersion);
JS_D("user", m.User);
JS_D("user", m.SelfUser);
JS_D("guilds", m.Guilds);
JS_D("session_id", m.SessionID);
JS_D("analytics_token", m.AnalyticsToken);
JS_D("friend_suggestion_count", m.FriendSuggestionCount);
JS_O("analytics_token", m.AnalyticsToken);
JS_O("friend_suggestion_count", m.FriendSuggestionCount);
JS_D("user_settings", m.UserSettings);
JS_D("private_channels", m.PrivateChannels);
JS_O("users", m.Users);
}
void to_json(nlohmann::json &j, const IdentifyProperties &m) {
j["$os"] = m.OS;
j["$browser"] = m.Browser;
j["$device"] = m.Device;
j["os"] = m.OS;
j["browser"] = m.Browser;
j["device"] = m.Device;
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;
if (m.ClientEventSource == "")
j["client_event_source"] = nullptr;
else
j["client_event_source"] = m.ClientEventSource;
}
void to_json(nlohmann::json &j, const ClientStateProperties &m) {
j["guild_hashes"] = m.GuildHashes;
j["highest_last_message_id"] = m.HighestLastMessageID;
j["read_state_version"] = m.ReadStateVersion;
j["user_guild_settings_version"] = m.UserGuildSettingsVersion;
}
void to_json(nlohmann::json &j, const IdentifyMessage &m) {
j["op"] = GatewayOp::Identify;
j["d"] = nlohmann::json::object();
j["d"]["token"] = m.Token;
j["d"]["capabilities"] = m.Capabilities;
j["d"]["properties"] = m.Properties;
if (m.LargeThreshold)
j["d"]["large_threshold"] = m.LargeThreshold;
j["d"]["presence"] = m.Presence;
j["d"]["compress"] = m.DoesSupportCompression;
j["d"]["client_state"] = m.ClientState;
}
void to_json(nlohmann::json &j, const HeartbeatMessage &m) {

View File

@@ -146,21 +146,23 @@ struct UpdateStatusMessage {
std::vector<Activity> Activities; // null (but never sent as such)
std::string Status;
bool IsAFK;
int Since = 0;
friend void to_json(nlohmann::json &j, const UpdateStatusMessage &m);
};
struct ReadyEventData {
int GatewayVersion; //
User User; //
std::vector<Guild> Guilds; //
std::string SessionID; //
std::vector<Channel> PrivateChannels; //
int GatewayVersion;
User SelfUser;
std::vector<Guild> Guilds;
std::string SessionID;
std::vector<Channel> PrivateChannels;
// undocumented
std::string AnalyticsToken; // opt
int FriendSuggestionCount; // opt
UserSettings UserSettings; // opt
std::optional<std::vector<User>> Users;
std::optional<std::string> AnalyticsToken;
std::optional<int> FriendSuggestionCount;
UserSettings UserSettings;
// std::vector<Unknown> ConnectedAccounts; // opt
// std::map<std::string, Unknown> Consents; // opt
// std::vector<Unknown> Experiments; // opt
@@ -179,15 +181,36 @@ struct IdentifyProperties {
std::string OS;
std::string Browser;
std::string Device;
std::string BrowserUserAgent;
std::string BrowserVersion;
std::string OSVersion;
std::string Referrer;
std::string ReferringDomain;
std::string ReferrerCurrent;
std::string ReferringDomainCurrent;
std::string ReleaseChannel;
int ClientBuildNumber;
std::string ClientEventSource; // empty -> null
friend void to_json(nlohmann::json &j, const IdentifyProperties &m);
};
struct ClientStateProperties {
std::map<std::string, std::string> GuildHashes;
std::string HighestLastMessageID = "0";
int ReadStateVersion = 0;
int UserGuildSettingsVersion = -1;
friend void to_json(nlohmann::json &j, const ClientStateProperties &m);
};
struct IdentifyMessage : GatewayMessage {
std::string Token;
IdentifyProperties Properties;
UpdateStatusMessage Presence;
ClientStateProperties ClientState;
bool DoesSupportCompression = false;
int LargeThreshold = 0;
int Capabilities;
friend void to_json(nlohmann::json &j, const IdentifyMessage &m);
};

View File

@@ -69,6 +69,8 @@ void Store::SetChannel(Snowflake id, const Channel &chan) {
for (const auto &u : *chan.Recipients)
ids.push_back(u.ID);
Bind(m_set_chan_stmt, 13, nlohmann::json(ids).dump());
} else if (chan.RecipientIDs.has_value()) {
Bind(m_set_chan_stmt, 13, nlohmann::json(*chan.RecipientIDs).dump());
} else {
Bind(m_set_chan_stmt, 13, nullptr);
}
@@ -297,11 +299,7 @@ std::optional<Channel> Store::GetChannel(Snowflake id) const {
if (!IsNull(m_get_chan_stmt, 12)) {
std::string tmps;
Get(m_get_chan_stmt, 12, tmps);
// dummy users
ret.Recipients = std::vector<User>();
auto ids = nlohmann::json::parse(tmps).get<std::vector<Snowflake>>();
for (const auto &id : ids)
ret.Recipients->emplace_back().ID = id;
ret.RecipientIDs = nlohmann::json::parse(tmps).get<std::vector<Snowflake>>();
}
Get(m_get_chan_stmt, 13, ret.Icon);
Get(m_get_chan_stmt, 14, ret.OwnerID);