From f228561f4c2059d3568d4cf7dd8fc98dd0260c2a Mon Sep 17 00:00:00 2001 From: Madeline <46743919+MaddyUnderStars@users.noreply.github.com> Date: Mon, 13 Mar 2023 19:02:52 +1100 Subject: Initial identify rewrite --- src/util/interfaces/Event.ts | 31 ++++++++++++++++--------------- 1 file changed, 16 insertions(+), 15 deletions(-) (limited to 'src/util/interfaces/Event.ts') diff --git a/src/util/interfaces/Event.ts b/src/util/interfaces/Event.ts index c3bfbf9b..492821f1 100644 --- a/src/util/interfaces/Event.ts +++ b/src/util/interfaces/Event.ts @@ -40,6 +40,9 @@ import { UserSettings, IReadyGuildDTO, ReadState, + UserPrivate, + ReadyUserGuildSettingsEntries, + ReadyPrivateChannel, } from "@fosscord/util"; export interface Event { @@ -68,20 +71,8 @@ export interface PublicRelationship { export interface ReadyEventData { v: number; - user: PublicUser & { - mobile: boolean; - desktop: boolean; - email: string | undefined; - flags: string; - mfa_enabled: boolean; - nsfw_allowed: boolean; - phone: string | undefined; - premium: boolean; - premium_type: number; - verified: boolean; - bot: boolean; - }; - private_channels: Channel[]; // this will be empty for bots + user: UserPrivate; + private_channels: ReadyPrivateChannel[]; // this will be empty for bots session_id: string; // resuming guilds: IReadyGuildDTO[]; analytics_token?: string; @@ -115,7 +106,7 @@ export interface ReadyEventData { version: number; }; user_guild_settings?: { - entries: UserGuildSettings[]; + entries: ReadyUserGuildSettingsEntries[]; version: number; partial: boolean; }; @@ -127,6 +118,16 @@ export interface ReadyEventData { // probably all users who the user is in contact with users?: PublicUser[]; sessions: unknown[]; + api_code_version: number; + tutorial: number | null; + resume_gateway_url: string; + session_type: string; + required_action?: + | "REQUIRE_VERIFIED_EMAIL" + | "REQUIRE_VERIFIED_PHONE" + | "REQUIRE_CAPTCHA" // TODO: allow these to be triggered + | "TOS_UPDATE_ACKNOWLEDGMENT" + | "AGREEMENTS"; } export interface ReadyEvent extends Event { -- cgit 1.5.1 From d944dd4ef42e0991a69e912636b1d60bb0f843ee Mon Sep 17 00:00:00 2001 From: Madeline <46743919+MaddyUnderStars@users.noreply.github.com> Date: Sat, 1 Apr 2023 19:49:54 +1100 Subject: allow all role props through ready --- src/gateway/opcodes/Identify.ts | 16 +++++----------- src/util/interfaces/Event.ts | 1 + 2 files changed, 6 insertions(+), 11 deletions(-) (limited to 'src/util/interfaces/Event.ts') diff --git a/src/gateway/opcodes/Identify.ts b/src/gateway/opcodes/Identify.ts index 6ae1f9c2..6aa152d3 100644 --- a/src/gateway/opcodes/Identify.ts +++ b/src/gateway/opcodes/Identify.ts @@ -249,21 +249,14 @@ export async function onIdentify(this: WebSocket, data: Payload) { // Generate guilds list ( make them unavailable if user is bot ) const guilds: GuildOrUnavailable[] = members.map((member) => { - // Some Discord libraries do `'blah' in object` instead of - // checking if the type is correct - member.guild.roles.forEach((role) => { - for (const key in role) { - // eslint-disable-next-line @typescript-eslint/ban-ts-comment - //@ts-ignore - if (!role[key]) role[key] = undefined; - } - }); - // filter guild channels we don't have permission to view // TODO: check if this causes issues when the user is granted other roles? member.guild.channels = member.guild.channels.filter((channel) => { const perms = Permissions.finalPermission({ - user: { id: member.id, roles: member.roles.map((x) => x.id) }, + user: { + id: member.id, + roles: member.roles.map((x) => x.id), + }, guild: member.guild, channel, }); @@ -422,6 +415,7 @@ export async function onIdentify(this: WebSocket, data: Payload) { Config.get().gateway.endpointPublic || "ws://127.0.0.1:3001", session_type: "normal", // TODO + auth_session_id_hash: "", // TODO // lol hack whatever required_action: diff --git a/src/util/interfaces/Event.ts b/src/util/interfaces/Event.ts index cbfa0767..21c34c6c 100644 --- a/src/util/interfaces/Event.ts +++ b/src/util/interfaces/Event.ts @@ -121,6 +121,7 @@ export interface ReadyEventData { tutorial: number | null; resume_gateway_url: string; session_type: string; + auth_session_id_hash: string; required_action?: | "REQUIRE_VERIFIED_EMAIL" | "REQUIRE_VERIFIED_PHONE" -- cgit 1.5.1 From 6ee26082efddfa4f996b4b0424a664a6a592501c Mon Sep 17 00:00:00 2001 From: Madeline <46743919+MaddyUnderStars@users.noreply.github.com> Date: Mon, 3 Apr 2023 23:50:48 +1000 Subject: Respect CLIENT_STATE_V2 capability --- src/gateway/opcodes/Identify.ts | 20 +++++++++++++++----- src/gateway/util/Capabilities.ts | 26 ++++++++++++++++++++++++++ src/gateway/util/WebSocket.ts | 2 ++ src/gateway/util/index.ts | 1 + src/util/interfaces/Event.ts | 3 ++- 5 files changed, 46 insertions(+), 6 deletions(-) create mode 100644 src/gateway/util/Capabilities.ts (limited to 'src/util/interfaces/Event.ts') diff --git a/src/gateway/opcodes/Identify.ts b/src/gateway/opcodes/Identify.ts index 6aa152d3..f035fe15 100644 --- a/src/gateway/opcodes/Identify.ts +++ b/src/gateway/opcodes/Identify.ts @@ -16,7 +16,15 @@ along with this program. If not, see . */ -import { WebSocket, Payload, setupListener } from "@spacebar/gateway"; +import { + WebSocket, + Payload, + setupListener, + Capabilities, + CLOSECODES, + OPCODES, + Send, +} from "@spacebar/gateway"; import { checkToken, Intents, @@ -45,11 +53,9 @@ import { Permissions, DMChannel, GuildOrUnavailable, + Recipient, } from "@spacebar/util"; -import { Send } from "../util/Send"; -import { CLOSECODES, OPCODES } from "../util/Constants"; import { check } from "./instanceOf"; -import { Recipient } from "@spacebar/util"; // TODO: user sharding // TODO: check privileged intents, if defined in the config @@ -73,6 +79,8 @@ export async function onIdentify(this: WebSocket, data: Payload) { check.call(this, IdentifySchema, data.d); const identify: IdentifySchema = data.d; + this.capabilities = new Capabilities(identify.capabilities || 0); + // Check auth // TODO: the checkToken call will fetch user, and then we have to refetch with different select // checkToken should be able to select what we want @@ -374,7 +382,9 @@ export async function onIdentify(this: WebSocket, data: Payload) { : undefined, user: user.toPrivateUser(), user_settings: user.settings, - guilds: guilds.map((x) => new ReadyGuildDTO(x).toJSON()), + guilds: this.capabilities.has(Capabilities.FLAGS.CLIENT_STATE_V2) + ? guilds.map((x) => new ReadyGuildDTO(x).toJSON()) + : guilds, relationships: user.relationships.map((x) => x.toPublicRelationship()), read_state: { entries: read_states, diff --git a/src/gateway/util/Capabilities.ts b/src/gateway/util/Capabilities.ts new file mode 100644 index 00000000..6c94bb45 --- /dev/null +++ b/src/gateway/util/Capabilities.ts @@ -0,0 +1,26 @@ +import { BitField, BitFieldResolvable, BitFlag } from "@spacebar/util"; + +export type CapabilityResolvable = BitFieldResolvable | CapabilityString; +type CapabilityString = keyof typeof Capabilities.FLAGS; + +export class Capabilities extends BitField { + static FLAGS = { + // Thanks, Opencord! + // https://github.com/MateriiApps/OpenCord/blob/master/app/src/main/java/com/xinto/opencord/gateway/io/Capabilities.kt + LAZY_USER_NOTES: BitFlag(0), + NO_AFFINE_USER_IDS: BitFlag(1), + VERSIONED_READ_STATES: BitFlag(2), + VERSIONED_USER_GUILD_SETTINGS: BitFlag(3), + DEDUPLICATE_USER_OBJECTS: BitFlag(4), + PRIORITIZED_READY_PAYLOAD: BitFlag(5), + MULTIPLE_GUILD_EXPERIMENT_POPULATIONS: BitFlag(6), + NON_CHANNEL_READ_STATES: BitFlag(7), + AUTH_TOKEN_REFRESH: BitFlag(8), + USER_SETTINGS_PROTO: BitFlag(9), + CLIENT_STATE_V2: BitFlag(10), + PASSIVE_GUILD_UPDATE: BitFlag(11), + }; + + any = (capability: CapabilityResolvable) => super.any(capability); + has = (capability: CapabilityResolvable) => super.has(capability); +} diff --git a/src/gateway/util/WebSocket.ts b/src/gateway/util/WebSocket.ts index 972129c7..833756ff 100644 --- a/src/gateway/util/WebSocket.ts +++ b/src/gateway/util/WebSocket.ts @@ -19,6 +19,7 @@ import { Intents, ListenEventOpts, Permissions } from "@spacebar/util"; import WS from "ws"; import { Deflate, Inflate } from "fast-zlib"; +import { Capabilities } from "./Capabilities"; // import { Client } from "@spacebar/webrtc"; export interface WebSocket extends WS { @@ -40,5 +41,6 @@ export interface WebSocket extends WS { events: Record unknown)>; member_events: Record unknown>; listen_options: ListenEventOpts; + capabilities?: Capabilities; // client?: Client; } diff --git a/src/gateway/util/index.ts b/src/gateway/util/index.ts index 627f12b2..6ef694d9 100644 --- a/src/gateway/util/index.ts +++ b/src/gateway/util/index.ts @@ -21,3 +21,4 @@ export * from "./Send"; export * from "./SessionUtils"; export * from "./Heartbeat"; export * from "./WebSocket"; +export * from "./Capabilities"; diff --git a/src/util/interfaces/Event.ts b/src/util/interfaces/Event.ts index 21c34c6c..16df48aa 100644 --- a/src/util/interfaces/Event.ts +++ b/src/util/interfaces/Event.ts @@ -42,6 +42,7 @@ import { UserPrivate, ReadyUserGuildSettingsEntries, ReadyPrivateChannel, + GuildOrUnavailable, } from "@spacebar/util"; export interface Event { @@ -73,7 +74,7 @@ export interface ReadyEventData { user: UserPrivate; private_channels: ReadyPrivateChannel[]; // this will be empty for bots session_id: string; // resuming - guilds: IReadyGuildDTO[]; + guilds: IReadyGuildDTO[] | GuildOrUnavailable[]; // depends on capability analytics_token?: string; connected_accounts?: ConnectedAccount[]; consents?: { -- cgit 1.5.1 From 4c0b1391b19cd55127350aa8605362e2799d5407 Mon Sep 17 00:00:00 2001 From: Madeline <46743919+MaddyUnderStars@users.noreply.github.com> Date: Mon, 31 Jul 2023 19:42:27 +1000 Subject: send empty READY_SUPPLEMENTAL for client compatibility --- src/gateway/opcodes/Identify.ts | 21 ++++++++++++++++++++- src/util/interfaces/Event.ts | 1 + 2 files changed, 21 insertions(+), 1 deletion(-) (limited to 'src/util/interfaces/Event.ts') diff --git a/src/gateway/opcodes/Identify.ts b/src/gateway/opcodes/Identify.ts index 0f91df3e..bab52279 100644 --- a/src/gateway/opcodes/Identify.ts +++ b/src/gateway/opcodes/Identify.ts @@ -53,6 +53,7 @@ import { DMChannel, GuildOrUnavailable, Recipient, + OPCodes, } from "@spacebar/util"; import { check } from "./instanceOf"; @@ -441,7 +442,25 @@ export async function onIdentify(this: WebSocket, data: Payload) { ), ); - //TODO send READY_SUPPLEMENTAL + // TODO: ready supplemental + await Send(this, { + op: OPCodes.DISPATCH, + t: EVENTEnum.ReadySupplemental, + s: this.sequence++, + d: { + merged_presences: { + guilds: [], + friends: [], + }, + // these merged members seem to be all users currently in vc in your guilds + merged_members: [], + lazy_private_channels: [], + guilds: [], // { voice_states: [], id: string, embedded_activities: [] } + // embedded_activities are users currently in an activity? + disclose: ["pomelo"], + }, + }); + //TODO send GUILD_MEMBER_LIST_UPDATE //TODO send VOICE_STATE_UPDATE to let the client know if another device is already connected to a voice channel diff --git a/src/util/interfaces/Event.ts b/src/util/interfaces/Event.ts index 7ddb763d..deb54428 100644 --- a/src/util/interfaces/Event.ts +++ b/src/util/interfaces/Event.ts @@ -583,6 +583,7 @@ export type EventData = export enum EVENTEnum { Ready = "READY", + ReadySupplemental = "READY_SUPPLEMENTAL", ChannelCreate = "CHANNEL_CREATE", ChannelUpdate = "CHANNEL_UPDATE", ChannelDelete = "CHANNEL_DELETE", -- cgit 1.5.1