From 7c26fc59190cb7fd9e66dadc6b1bfe3abc65d608 Mon Sep 17 00:00:00 2001 From: MathMan05 Date: Thu, 30 Oct 2025 17:19:43 -0500 Subject: [PATCH] fix full user object being exposed --- .../messages/#message_id/reactions.ts | 80 +++++-------------- src/api/routes/channels/#channel_id/typing.ts | 5 +- src/api/routes/guilds/#guild_id/bans.ts | 40 +++------- src/api/routes/guilds/#guild_id/bulk-ban.ts | 25 ++---- src/api/routes/users/@me/guilds.ts | 26 ++---- src/api/util/handlers/Message.ts | 18 +++-- src/util/entities/Member.ts | 53 +++--------- 7 files changed, 62 insertions(+), 185 deletions(-) diff --git a/src/api/routes/channels/#channel_id/messages/#message_id/reactions.ts b/src/api/routes/channels/#channel_id/messages/#message_id/reactions.ts index dcd98ff5..fe2a2509 100644 --- a/src/api/routes/channels/#channel_id/messages/#message_id/reactions.ts +++ b/src/api/routes/channels/#channel_id/messages/#message_id/reactions.ts @@ -110,11 +110,7 @@ router.delete( where: { id: message_id, channel_id }, }); - const already_added = message.reactions.find( - (x) => - (x.emoji.id === emoji.id && emoji.id) || - x.emoji.name === emoji.name, - ); + const already_added = message.reactions.find((x) => (x.emoji.id === emoji.id && emoji.id) || x.emoji.name === emoji.name); if (!already_added) throw new HTTPError("Reaction not found", 404); message.reactions.remove(already_added); @@ -158,19 +154,17 @@ router.get( const message = await Message.findOneOrFail({ where: { id: message_id, channel_id }, }); - const reaction = message.reactions.find( - (x) => - (x.emoji.id === emoji.id && emoji.id) || - x.emoji.name === emoji.name, - ); + const reaction = message.reactions.find((x) => (x.emoji.id === emoji.id && emoji.id) || x.emoji.name === emoji.name); if (!reaction) throw new HTTPError("Reaction not found", 404); - const users = await User.find({ - where: { - id: In(reaction.user_ids), - }, - select: PublicUserProjection, - }); + const users = ( + await User.find({ + where: { + id: In(reaction.user_ids), + }, + select: PublicUserProjection, + }) + ).map((user) => user.toPublicUser()); res.json(users); }, @@ -201,11 +195,7 @@ router.put( const message = await Message.findOneOrFail({ where: { id: message_id, channel_id }, }); - const already_added = message.reactions.find( - (x) => - (x.emoji.id === emoji.id && emoji.id) || - x.emoji.name === emoji.name, - ); + const already_added = message.reactions.find((x) => (x.emoji.id === emoji.id && emoji.id) || x.emoji.name === emoji.name); if (!already_added) req.permission?.hasThrow("ADD_REACTIONS"); @@ -213,15 +203,13 @@ router.put( const external_emoji = await Emoji.findOneOrFail({ where: { id: emoji.id }, }); - if (!already_added && channel.guild_id != external_emoji.guild_id) - req.permission?.hasThrow("USE_EXTERNAL_EMOJIS"); + if (!already_added && channel.guild_id != external_emoji.guild_id) req.permission?.hasThrow("USE_EXTERNAL_EMOJIS"); emoji.animated = external_emoji.animated; emoji.name = external_emoji.name; } if (already_added) { - if (already_added.user_ids.includes(req.user_id)) - return res.sendStatus(204); // Do not throw an error ¯\_(ツ)_/¯ as discord also doesn't throw any error + if (already_added.user_ids.includes(req.user_id)) return res.sendStatus(204); // Do not throw an error ¯\_(ツ)_/¯ as discord also doesn't throw any error already_added.count++; already_added.user_ids.push(req.user_id); } else @@ -286,30 +274,17 @@ router.delete( if (user_id === "@me") user_id = req.user_id; else { - const permissions = await getPermission( - req.user_id, - undefined, - channel_id, - ); + const permissions = await getPermission(req.user_id, undefined, channel_id); permissions.hasThrow("MANAGE_MESSAGES"); } - const already_added = message.reactions.find( - (x) => - (x.emoji.id === emoji.id && emoji.id) || - x.emoji.name === emoji.name, - ); - if (!already_added || !already_added.user_ids.includes(user_id)) - throw new HTTPError("Reaction not found", 404); + const already_added = message.reactions.find((x) => (x.emoji.id === emoji.id && emoji.id) || x.emoji.name === emoji.name); + if (!already_added || !already_added.user_ids.includes(user_id)) throw new HTTPError("Reaction not found", 404); already_added.count--; if (already_added.count <= 0) message.reactions.remove(already_added); - else - already_added.user_ids.splice( - already_added.user_ids.indexOf(user_id), - 1, - ); + else already_added.user_ids.splice(already_added.user_ids.indexOf(user_id), 1); await message.save(); @@ -356,30 +331,17 @@ router.delete( if (user_id === "@me") user_id = req.user_id; else { - const permissions = await getPermission( - req.user_id, - undefined, - channel_id, - ); + const permissions = await getPermission(req.user_id, undefined, channel_id); permissions.hasThrow("MANAGE_MESSAGES"); } - const already_added = message.reactions.find( - (x) => - (x.emoji.id === emoji.id && emoji.id) || - x.emoji.name === emoji.name, - ); - if (!already_added || !already_added.user_ids.includes(user_id)) - throw new HTTPError("Reaction not found", 404); + const already_added = message.reactions.find((x) => (x.emoji.id === emoji.id && emoji.id) || x.emoji.name === emoji.name); + if (!already_added || !already_added.user_ids.includes(user_id)) throw new HTTPError("Reaction not found", 404); already_added.count--; if (already_added.count <= 0) message.reactions.remove(already_added); - else - already_added.user_ids.splice( - already_added.user_ids.indexOf(user_id), - 1, - ); + else already_added.user_ids.splice(already_added.user_ids.indexOf(user_id), 1); await message.save(); diff --git a/src/api/routes/channels/#channel_id/typing.ts b/src/api/routes/channels/#channel_id/typing.ts index 7ef36150..8c36add1 100644 --- a/src/api/routes/channels/#channel_id/typing.ts +++ b/src/api/routes/channels/#channel_id/typing.ts @@ -17,7 +17,7 @@ */ import { route } from "@spacebar/api"; -import { Channel, emitEvent, Member, TypingStartEvent } from "@spacebar/util"; +import { Channel, emitEvent, Member, TypingStartEvent, User } from "@spacebar/util"; import { Request, Response, Router } from "express"; const router: Router = Router({ mergeParams: true }); @@ -43,7 +43,6 @@ router.post( where: { id: user_id, guild_id: channel.guild_id }, relations: ["roles", "user"], }); - await emitEvent({ event: "TYPING_START", channel_id: channel_id, @@ -51,7 +50,7 @@ router.post( ...(member ? { member: { - ...member, + ...member.toPublicMember(), roles: member?.roles?.map((x) => x.id), }, } diff --git a/src/api/routes/guilds/#guild_id/bans.ts b/src/api/routes/guilds/#guild_id/bans.ts index 69fa9476..e253bef9 100644 --- a/src/api/routes/guilds/#guild_id/bans.ts +++ b/src/api/routes/guilds/#guild_id/bans.ts @@ -17,18 +17,10 @@ */ import { getIpAdress, route } from "@spacebar/api"; -import { - Ban, - DiscordApiErrors, - GuildBanAddEvent, - GuildBanRemoveEvent, - Member, - User, - emitEvent, -} from "@spacebar/util"; +import { Ban, DiscordApiErrors, GuildBanAddEvent, GuildBanRemoveEvent, Member, User, emitEvent } from "@spacebar/util"; import { Request, Response, Router } from "express"; import { HTTPError } from "lambert-server"; -import { APIBansArray, BanRegistrySchema, GuildBansResponse } from "@spacebar/schemas" +import { APIBansArray, BanRegistrySchema, GuildBansResponse } from "@spacebar/schemas"; const router: Router = Router({ mergeParams: true }); @@ -87,14 +79,12 @@ router.get( query: { query: { type: "string", - description: - "Query to match username(s) and display name(s) against (1-32 characters)", + description: "Query to match username(s) and display name(s) against (1-32 characters)", required: true, }, limit: { type: "number", - description: - "Max number of members to return (1-10, default 10)", + description: "Max number of members to return (1-10, default 10)", required: false, }, }, @@ -111,14 +101,11 @@ router.get( const { guild_id } = req.params; const limit = Number(req.query.limit) || 10; - if (limit > 10 || limit < 1) - throw new HTTPError("Limit must be between 1 and 10"); + if (limit > 10 || limit < 1) throw new HTTPError("Limit must be between 1 and 10"); const query = String(req.query.query); if (!query || query.trim().length === 0 || query.length > 32) { - throw new HTTPError( - "The query must be between 1 and 32 characters in length", - ); + throw new HTTPError("The query must be between 1 and 32 characters in length"); } let bans = await Ban.createQueryBuilder("ban") @@ -212,17 +199,10 @@ router.put( const { guild_id } = req.params; const banned_user_id = req.params.user_id; - if ( - req.user_id === banned_user_id && - banned_user_id === req.permission?.cache.guild?.owner_id - ) - throw new HTTPError( - "You are the guild owner, hence can't ban yourself", - 403, - ); + if (req.user_id === banned_user_id && banned_user_id === req.permission?.cache.guild?.owner_id) + throw new HTTPError("You are the guild owner, hence can't ban yourself", 403); - if (req.permission?.cache.guild?.owner_id === banned_user_id) - throw new HTTPError("You can't ban the owner", 400); + if (req.permission?.cache.guild?.owner_id === banned_user_id) throw new HTTPError("You can't ban the owner", 400); const existingBan = await Ban.findOne({ where: { guild_id: guild_id, user_id: banned_user_id }, @@ -247,7 +227,7 @@ router.put( event: "GUILD_BAN_ADD", data: { guild_id: guild_id, - user: banned_user, + user: banned_user.toPublicUser(), }, guild_id: guild_id, } as GuildBanAddEvent), diff --git a/src/api/routes/guilds/#guild_id/bulk-ban.ts b/src/api/routes/guilds/#guild_id/bulk-ban.ts index 6de43231..3d3ed1c3 100644 --- a/src/api/routes/guilds/#guild_id/bulk-ban.ts +++ b/src/api/routes/guilds/#guild_id/bulk-ban.ts @@ -17,14 +17,7 @@ */ import { getIpAdress, route } from "@spacebar/api"; -import { - Ban, - DiscordApiErrors, - GuildBanAddEvent, - Member, - User, - emitEvent, -} from "@spacebar/util"; +import { Ban, DiscordApiErrors, GuildBanAddEvent, Member, User, emitEvent } from "@spacebar/util"; import { Request, Response, Router } from "express"; import { HTTPError } from "lambert-server"; import { Config } from "@spacebar/util"; @@ -54,19 +47,12 @@ router.post( const userIds: Array = req.body.user_ids; if (!userIds) throw new HTTPError("The user_ids array is missing", 400); - if (userIds.length > Config.get().limits.guild.maxBulkBanUsers) - throw new HTTPError( - "The user_ids array must be between 1 and 200 in length", - 400, - ); + if (userIds.length > Config.get().limits.guild.maxBulkBanUsers) throw new HTTPError("The user_ids array must be between 1 and 200 in length", 400); const banned_users = []; const failed_users = []; for await (const banned_user_id of userIds) { - if ( - req.user_id === banned_user_id && - banned_user_id === req.permission?.cache.guild?.owner_id - ) { + if (req.user_id === banned_user_id && banned_user_id === req.permission?.cache.guild?.owner_id) { failed_users.push(banned_user_id); continue; } @@ -108,7 +94,7 @@ router.post( event: "GUILD_BAN_ADD", data: { guild_id: guild_id, - user: banned_user, + user: banned_user.toPublicUser(), }, guild_id: guild_id, } as GuildBanAddEvent), @@ -120,8 +106,7 @@ router.post( } } - if (banned_users.length === 0 && failed_users.length > 0) - throw DiscordApiErrors.BULK_BAN_FAILED; + if (banned_users.length === 0 && failed_users.length > 0) throw DiscordApiErrors.BULK_BAN_FAILED; return res.json({ banned_users: banned_users, failed_users: failed_users, diff --git a/src/api/routes/users/@me/guilds.ts b/src/api/routes/users/@me/guilds.ts index 78adbbd4..701e6604 100644 --- a/src/api/routes/users/@me/guilds.ts +++ b/src/api/routes/users/@me/guilds.ts @@ -17,15 +17,7 @@ */ import { route } from "@spacebar/api"; -import { - Config, - Guild, - GuildDeleteEvent, - GuildMemberRemoveEvent, - Member, - User, - emitEvent, -} from "@spacebar/util"; +import { Config, Guild, GuildDeleteEvent, GuildMemberRemoveEvent, Member, User, emitEvent } from "@spacebar/util"; import { Request, Response, Router } from "express"; import { HTTPError } from "lambert-server"; @@ -79,17 +71,9 @@ router.delete( }); if (!guild) throw new HTTPError("Guild doesn't exist", 404); - if (guild.owner_id === req.user_id) - throw new HTTPError("You can't leave your own guild", 400); - if ( - autoJoin.enabled && - autoJoin.guilds.includes(guild_id) && - !autoJoin.canLeave - ) { - throw new HTTPError( - "You can't leave instance auto join guilds", - 400, - ); + if (guild.owner_id === req.user_id) throw new HTTPError("You can't leave your own guild", 400); + if (autoJoin.enabled && autoJoin.guilds.includes(guild_id) && !autoJoin.canLeave) { + throw new HTTPError("You can't leave instance auto join guilds", 400); } await Promise.all([ @@ -109,7 +93,7 @@ router.delete( event: "GUILD_MEMBER_REMOVE", data: { guild_id: guild_id, - user: user, + user: user.toPublicUser(), }, guild_id: guild_id, } as GuildMemberRemoveEvent); diff --git a/src/api/util/handlers/Message.ts b/src/api/util/handlers/Message.ts index 5cb7a56b..32b24ab7 100644 --- a/src/api/util/handlers/Message.ts +++ b/src/api/util/handlers/Message.ts @@ -362,14 +362,16 @@ export async function postHandleMessage(message: Message) { const hasUrl = !!embed.url; return !hasUrl; }); - await Promise.all([ - emitEvent({ - event: "MESSAGE_UPDATE", - channel_id: message.channel_id, - data, - } as MessageUpdateEvent), - Message.update({ id: message.id, channel_id: message.channel_id }, { embeds: data.embeds }), - ]); + const author = data.author?.toPublicUser(); + const event = { + event: "MESSAGE_UPDATE", + channel_id: message.channel_id, + data: { + ...data, + author, + }, + } as MessageUpdateEvent; + await Promise.all([emitEvent(event), Message.update({ id: message.id, channel_id: message.channel_id }, { embeds: data.embeds })]); return; } diff --git a/src/util/entities/Member.ts b/src/util/entities/Member.ts index 1e23cd58..98f6e687 100644 --- a/src/util/entities/Member.ts +++ b/src/util/entities/Member.ts @@ -17,30 +17,10 @@ */ import { HTTPError } from "lambert-server"; -import { - BeforeInsert, - BeforeUpdate, - Column, - Entity, - Index, - JoinColumn, - JoinTable, - ManyToMany, - ManyToOne, - Not, - PrimaryGeneratedColumn, - RelationId, -} from "typeorm"; +import { BeforeInsert, BeforeUpdate, Column, Entity, Index, JoinColumn, JoinTable, ManyToMany, ManyToOne, Not, PrimaryGeneratedColumn, RelationId } from "typeorm"; import { Ban, Channel, PublicGuildRelations } from "."; import { ReadyGuildDTO } from "../dtos"; -import { - GuildCreateEvent, - GuildDeleteEvent, - GuildMemberAddEvent, - GuildMemberRemoveEvent, - GuildMemberUpdateEvent, - MessageCreateEvent, -} from "../interfaces"; +import { GuildCreateEvent, GuildDeleteEvent, GuildMemberAddEvent, GuildMemberRemoveEvent, GuildMemberUpdateEvent, MessageCreateEvent } from "../interfaces"; import { Config, emitEvent } from "../util"; import { DiscordApiErrors } from "../util/Constants"; import { BaseClassWithoutId } from "./BaseClass"; @@ -186,8 +166,7 @@ export class Member extends BaseClassWithoutId { select: ["owner_id"], where: { id: guild_id }, }); - if (guild.owner_id === user_id) - throw new Error("The owner cannot be removed of the guild"); + if (guild.owner_id === user_id) throw new Error("The owner cannot be removed of the guild"); const member = await Member.findOneOrFail({ where: { id: user_id, guild_id }, relations: ["user"], @@ -210,7 +189,7 @@ export class Member extends BaseClassWithoutId { } as GuildDeleteEvent), emitEvent({ event: "GUILD_MEMBER_REMOVE", - data: { guild_id, user: member.user }, + data: { guild_id, user: member.user.toPublicUser() }, guild_id, } as GuildMemberRemoveEvent), ]); @@ -249,11 +228,7 @@ export class Member extends BaseClassWithoutId { ]); } - static async removeRole( - user_id: string, - guild_id: string, - role_id: string, - ) { + static async removeRole(user_id: string, guild_id: string, role_id: string) { const [member] = await Promise.all([ Member.findOneOrFail({ where: { id: user_id, guild_id }, @@ -283,11 +258,7 @@ export class Member extends BaseClassWithoutId { ]); } - static async changeNickname( - user_id: string, - guild_id: string, - nickname: string, - ) { + static async changeNickname(user_id: string, guild_id: string, nickname: string) { const member = await Member.findOneOrFail({ where: { id: user_id, @@ -323,10 +294,7 @@ export class Member extends BaseClassWithoutId { const { maxGuilds } = Config.get().limits.user; const guild_count = await Member.count({ where: { id: user_id } }); if (guild_count >= maxGuilds) { - throw new HTTPError( - `You are at the ${maxGuilds} server limit.`, - 403, - ); + throw new HTTPError(`You are at the ${maxGuilds} server limit.`, 403); } const guild = await Guild.findOneOrFail({ @@ -338,10 +306,7 @@ export class Member extends BaseClassWithoutId { }); for await (const channel of guild.channels) { - channel.position = await Channel.calculatePosition( - channel.id, - guild_id, - ); + channel.position = await Channel.calculatePosition(channel.id, guild_id); } const memberCount = await Member.count({ where: { guild_id } }); @@ -407,7 +372,7 @@ export class Member extends BaseClassWithoutId { event: "GUILD_MEMBER_ADD", data: { ...member, - user, + user: user.toPublicUser(), guild_id, }, guild_id,