summary refs log tree commit diff
diff options
context:
space:
mode:
authorRory& <root@rory.gay>2025-12-16 07:21:43 +0100
committerRory& <root@rory.gay>2025-12-16 07:21:43 +0100
commit03a966bfc45a099ccfaf7601c85ec1cac56ec84b (patch)
treec672cb10e03d7b5f41ca6e426e1ccc4b14050d11
parentUpate session info (diff)
downloadserver-ts-03a966bfc45a099ccfaf7601c85ec1cac56ec84b.tar.xz
Session fixes
-rw-r--r--src/api/util/handlers/Instance.ts4
-rw-r--r--src/gateway/opcodes/Identify.ts46
-rw-r--r--src/gateway/util/WebSocket.ts5
-rw-r--r--src/util/entities/Session.ts4
-rw-r--r--src/util/util/Token.ts10
5 files changed, 44 insertions, 25 deletions
diff --git a/src/api/util/handlers/Instance.ts b/src/api/util/handlers/Instance.ts

index e7b14c4f..f35411c8 100644 --- a/src/api/util/handlers/Instance.ts +++ b/src/api/util/handlers/Instance.ts
@@ -17,6 +17,7 @@ */ import { Session } from "@spacebar/util"; +import { Like } from "typeorm"; export async function initInstance() { // TODO: clean up database and delete tombstone data @@ -34,5 +35,6 @@ export async function initInstance() { // } // TODO: do no clear sessions for instance cluster - await Session.clear(); + // await Session.clear(); // This is now used as part of authentication... + await Session.delete({ session_id: Like("TEMP_%") }); // ...but we can still clear out temporary sessions } diff --git a/src/gateway/opcodes/Identify.ts b/src/gateway/opcodes/Identify.ts
index 0c36829e..bd6653d8 100644 --- a/src/gateway/opcodes/Identify.ts +++ b/src/gateway/opcodes/Identify.ts
@@ -95,15 +95,18 @@ export async function onIdentify(this: WebSocket, data: Payload) { this.large_threshold = identify.large_threshold || 250; const parseAndValidateTime = taskSw.getElapsedAndReset(); - const user = await tryGetUserFromToken(identify.token, { + const tokenData = await checkToken(identify.token, { relations: ["relationships", "relationships.to", "settings"], select: [...PrivateUserProjection, "relationships", "rights"], }); + + const user = tokenData.user; if (!user) { console.log("[Gateway] Failed to identify user"); return this.close(CLOSECODES.Authentication_failed); } this.user_id = user.id; + this.session = tokenData.session; const userQueryTime = taskSw.getElapsedAndReset(); // Check intents @@ -126,18 +129,25 @@ export async function onIdentify(this: WebSocket, data: Payload) { const validateIntentsAndShardingTime = taskSw.getElapsedAndReset(); // Generate a new gateway session ( id is already made, just save it in db ) - const session = Session.create({ - user_id: this.user_id, - session_id: this.session_id, - status: identify.presence?.status || "online", - client_info: { - client: identify.properties?.device || identify.properties?.$device, - os: identify.properties?.os || identify.properties?.$os, - version: 0, - }, - client_status: {}, - activities: identify.presence?.activities, // TODO: validation - }); + this.session = + tokenData.session ?? + Session.create({ + user_id: this.user_id, + session_id: "TEMP_" + this.session_id, + }); + + this.session.status = identify.presence?.status || "online"; + this.session.client_info ??= { + os: "Unknown", + client: "Unknown", + version: 0, + location: "Unknown", + }; + this.session.client_info.client = identify.properties?.device ?? identify.properties?.$device ?? this.session.client_info.client; + this.session.client_info.os = (identify.properties?.os || identify.properties?.$os) ?? this.session.client_info.os; + this.session.client_status = {}; + this.session.activities = identify.presence?.activities ?? []; // TODO: validation + const createSessionTime = taskSw.getElapsedAndReset(); // Get from database: @@ -152,7 +162,7 @@ export async function onIdentify(this: WebSocket, data: Payload) { { result: members, elapsed: membersQueryTime }, { result: recipients, elapsed: recipientsQueryTime }, ] = await Promise.all([ - timePromise(() => session.save()), + timePromise(() => this.session!.save()), timePromise(() => Application.findOne({ @@ -479,7 +489,7 @@ export async function onIdentify(this: WebSocket, data: Payload) { ).map((x) => ({ // TODO how is active determined? // in our lazy request impl, we just pick the 'most relevant' session - active: x.session_id == session.session_id, + active: x.session_id == this.session!.session_id, activities: x.activities ?? [], client_info: x.client_info, session_id: x.session_id, // TODO: discord.com sends 'all', what is that??? @@ -501,9 +511,9 @@ export async function onIdentify(this: WebSocket, data: Payload) { user_id: this.user_id, data: { user: user.toPublicUser(), - activities: session.activities, - client_status: session.client_status, - status: session.getPublicStatus(), + activities: this.session!.activities, + client_status: this.session!.client_status, + status: this.session!.getPublicStatus(), }, } as PresenceUpdateEvent), ), diff --git a/src/gateway/util/WebSocket.ts b/src/gateway/util/WebSocket.ts
index d0a42eaf..cbf8a739 100644 --- a/src/gateway/util/WebSocket.ts +++ b/src/gateway/util/WebSocket.ts
@@ -16,12 +16,10 @@ along with this program. If not, see <https://www.gnu.org/licenses/>. */ -import { Intents, ListenEventOpts, Permissions } from "@spacebar/util"; +import { Intents, ListenEventOpts, Permissions, Session } from "@spacebar/util"; import WS from "ws"; import { Deflate, Inflate } from "fast-zlib"; import { Capabilities } from "./Capabilities"; -import { ZstdCompress } from "zlib"; -import { ZstdDecompress } from "node:zlib"; import { Decoder, Encoder } from "@toondepauw/node-zstd"; import { QoSPayload } from "../opcodes/Heartbeat"; @@ -51,4 +49,5 @@ export interface WebSocket extends WS { capabilities?: Capabilities; large_threshold: number; qos?: QoSPayload; + session?: Session; } diff --git a/src/util/entities/Session.ts b/src/util/entities/Session.ts
index 093933b8..1569543f 100644 --- a/src/util/entities/Session.ts +++ b/src/util/entities/Session.ts
@@ -17,8 +17,8 @@ */ import { User } from "./User"; -import { BaseClass, BaseClassWithoutId } from "./BaseClass"; -import { ClientSession, Column, CreateDateColumn, Entity, Index, JoinColumn, ManyToOne, PrimaryColumn, RelationId } from "typeorm"; +import { BaseClassWithoutId } from "./BaseClass"; +import { Column, CreateDateColumn, Entity, Index, JoinColumn, ManyToOne, PrimaryColumn, RelationId } from "typeorm"; import { ClientStatus, Status } from "../interfaces/Status"; import { Activity } from "../interfaces/Activity"; import crypto from "crypto"; diff --git a/src/util/util/Token.ts b/src/util/util/Token.ts
index a364fa24..1f4920d8 100644 --- a/src/util/util/Token.ts +++ b/src/util/util/Token.ts
@@ -124,7 +124,7 @@ export const checkToken = ( session.last_seen = new Date(); if (opts?.ipAddress && opts?.ipAddress !== session.last_seen_ip) { session.last_seen_ip = opts.ipAddress; - let ipInfo = await IpDataClient.getIpInfo(opts.ipAddress); + const ipInfo = await IpDataClient.getIpInfo(opts.ipAddress); if (ipInfo?.ip) session.last_seen_location = `${ipInfo.emoji_flag} ${ipInfo.postal} ${ipInfo.city}, ${ipInfo.region}, ${ipInfo.country_name}`; } await session.save(); @@ -169,6 +169,14 @@ export async function generateToken(id: string, isAdminSession: boolean = false) session_id: randomUpperString(10), // readable at a glance user_id: id, is_admin_session: isAdminSession, + client_status: {}, + status: "online", + client_info: { + os: "Unknown", + client: "Unknown", + version: 0, + location: "Unknown", + }, }); } while (await Session.findOne({ where: { session_id: newSession.session_id } }));