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