diff --git a/src/entity/DMChannel.ts b/src/entity/DMChannel.ts index a9a9357..ae2a7b6 100644 --- a/src/entity/DMChannel.ts +++ b/src/entity/DMChannel.ts @@ -34,7 +34,7 @@ export class DMChannel extends Channel { }; } - public checkPermission = ( + public checkPermission = async ( user: User, permission: PERMISSION | PERMISSION[], ) => { diff --git a/src/entity/channel.ts b/src/entity/channel.ts index 2fef6c1..c78f153 100644 --- a/src/entity/channel.ts +++ b/src/entity/channel.ts @@ -27,20 +27,20 @@ export class Channel extends Actor { return this.toPublic(); } - public throwPermission = ( + public throwPermission = async ( user: User, permission: PERMISSION | PERMISSION[], ) => { // todo: which permision? - if (!this.checkPermission(user, permission)) + if (!(await this.checkPermission(user, permission))) throw new HttpError("Missing permission", 400); return true; }; - public checkPermission = ( + public checkPermission = async ( user: User, permission: PERMISSION | PERMISSION[], - ): boolean => false; + ): Promise => false; } export type PublicChannel = Pick; diff --git a/src/entity/guild.ts b/src/entity/guild.ts index 09313aa..90c01a2 100644 --- a/src/entity/guild.ts +++ b/src/entity/guild.ts @@ -53,17 +53,17 @@ export class Guild extends Actor { return this.toPublic(); } - public throwPermission = ( + public throwPermission = async ( user: User, permission: PERMISSION | PERMISSION[], ) => { // todo: which permision? - if (!this.checkPermission(user, permission)) + if (!(await this.checkPermission(user, permission))) throw new HttpError("Missing permission", 400); return true; }; - public checkPermission = ( + public checkPermission = async ( user: User, permission: PERMISSION | PERMISSION[], ) => checkPermission(user, this, permission); diff --git a/src/entity/textChannel.ts b/src/entity/textChannel.ts index 90cceb2..df6a77a 100644 --- a/src/entity/textChannel.ts +++ b/src/entity/textChannel.ts @@ -28,7 +28,7 @@ export class GuildTextChannel extends Channel { return this.toPublic(); } - public checkPermission = ( + public checkPermission = async ( user: User, permission: PERMISSION | PERMISSION[], ) => checkPermission(user, this.guild, permission); diff --git a/src/gateway/handlers/members.ts b/src/gateway/handlers/members.ts index 7e0df06..bf3f783 100644 --- a/src/gateway/handlers/members.ts +++ b/src/gateway/handlers/members.ts @@ -41,7 +41,7 @@ export const onSubscribeMembers = makeHandler(async function (payload) { const channel = await getChannel(payload.channel_id); if (!channel) throw new Error("Channel does not exist"); - channel.throwPermission( + await channel.throwPermission( User.create({ id: this.user_id }), PERMISSION.VIEW_CHANNEL, ); @@ -97,27 +97,21 @@ export const onSubscribeMembers = makeHandler(async function (payload) { const [role_members] = partition(members, (m) => m.role_id === role); items.push(role); - items.push( - ...role_members.reduce<{ id: string; name: string }[]>( - (ret, member) => { - if ( - true - // channel.checkPermission( - // User.create({ id: member.user_id }), - // PERMISSION.VIEW_CHANNEL, - // ) - ) { - listenRangeEvent(this, member.member_id); - ret.push({ - id: member.user_id, - name: member.name, - }); - } - return ret; - }, - [], - ), - ); + + for (const member of role_members) { + if ( + await channel.checkPermission( + User.create({ id: member.user_id }), + PERMISSION.VIEW_CHANNEL, + ) + ) { + listenRangeEvent(this, member.member_id); + items.push({ + id: member.user_id, + name: member.name, + }); + } + } } // Subscribe to their changes diff --git a/src/http/api/channel/#id/call.ts b/src/http/api/channel/#id/call.ts index b83fcfa..f5e728d 100644 --- a/src/http/api/channel/#id/call.ts +++ b/src/http/api/channel/#id/call.ts @@ -23,7 +23,7 @@ router.post( async (req, res) => { const channel = await getOrFetchChannel(req.params.channel_id); - channel.throwPermission(req.user, PERMISSION.CALL_CHANNEL); + await channel.throwPermission(req.user, PERMISSION.CALL_CHANNEL); // If this channel is remote, we have to request the token from them // It'll be delivered to our inbox, and we can send it to the client over gateway diff --git a/src/http/api/channel/#id/index.ts b/src/http/api/channel/#id/index.ts index 8101d97..b2b51e3 100644 --- a/src/http/api/channel/#id/index.ts +++ b/src/http/api/channel/#id/index.ts @@ -25,7 +25,7 @@ router.get( async (req, res) => { const channel = await getOrFetchChannel(req.params.channel_id); - channel.throwPermission(req.user, PERMISSION.VIEW_CHANNEL); + await channel.throwPermission(req.user, PERMISSION.VIEW_CHANNEL); return res.json(channel.toPublic()); }, @@ -45,7 +45,7 @@ router.patch( const channel = await getOrFetchChannel(req.params.channel_id); - channel.throwPermission(req.user, PERMISSION.MANAGE_CHANNELS); + await channel.throwPermission(req.user, PERMISSION.MANAGE_CHANNELS); if (channel.domain === config.federation.webapp_url.hostname) { // This is a local channel diff --git a/src/http/api/channel/#id/messages/#id/index.ts b/src/http/api/channel/#id/messages/#id/index.ts index c77a463..40156e3 100644 --- a/src/http/api/channel/#id/messages/#id/index.ts +++ b/src/http/api/channel/#id/messages/#id/index.ts @@ -18,7 +18,7 @@ router.get( async (req, res) => { const channel = await getOrFetchChannel(req.params.channel_id); - channel.throwPermission(req.user, [PERMISSION.VIEW_CHANNEL]); + await channel.throwPermission(req.user, [PERMISSION.VIEW_CHANNEL]); // TODO: fetch remote messages diff --git a/src/http/api/channel/#id/messages/index.ts b/src/http/api/channel/#id/messages/index.ts index 963de65..b2f6b31 100644 --- a/src/http/api/channel/#id/messages/index.ts +++ b/src/http/api/channel/#id/messages/index.ts @@ -24,7 +24,7 @@ router.post( const channel = await getOrFetchChannel(channel_id); - channel.throwPermission(req.user, PERMISSION.VIEW_CHANNEL); + await channel.throwPermission(req.user, PERMISSION.VIEW_CHANNEL); const message = Message.create({ channel, @@ -59,7 +59,7 @@ router.get( async (req, res) => { const channel = await getOrFetchChannel(req.params.channel_id); - channel.throwPermission(req.user, PERMISSION.VIEW_CHANNEL); + await channel.throwPermission(req.user, PERMISSION.VIEW_CHANNEL); // TODO: handle not fetched federated channels diff --git a/src/util/activitypub/inbox/handlers/create.ts b/src/util/activitypub/inbox/handlers/create.ts index f191cc8..7fb444c 100644 --- a/src/util/activitypub/inbox/handlers/create.ts +++ b/src/util/activitypub/inbox/handlers/create.ts @@ -66,7 +66,7 @@ const CreateAtChannel = async (activity: APActivity, target: Channel) => { const message = await buildMessageFromAPNote(inner, target); - target.throwPermission(message.author, [ + await target.throwPermission(message.author, [ PERMISSION.VIEW_CHANNEL, PERMISSION.SEND_MESSAGES, ]); diff --git a/src/util/activitypub/inbox/handlers/join.ts b/src/util/activitypub/inbox/handlers/join.ts index 4459334..6c761c9 100644 --- a/src/util/activitypub/inbox/handlers/join.ts +++ b/src/util/activitypub/inbox/handlers/join.ts @@ -37,7 +37,7 @@ export const JoinActivityHandler: ActivityHandler = async ( const user = await getOrFetchUser(activity.actor); - target.throwPermission(user, [ + await target.throwPermission(user, [ PERMISSION.VIEW_CHANNEL, PERMISSION.CALL_CHANNEL, ]); diff --git a/src/util/entity/guild.ts b/src/util/entity/guild.ts index 010f3c1..d658a26 100644 --- a/src/util/entity/guild.ts +++ b/src/util/entity/guild.ts @@ -248,7 +248,7 @@ export const createGuildFromRemoteOrg = async (lookup: string | APActor) => { await guild.save(); - const channels = (await Promise.all([ + const channels = await Promise.all([ ...( await resolveCollectionEntries(new URL(obj.following.toString())) ).reduce( @@ -260,9 +260,9 @@ export const createGuildFromRemoteOrg = async (lookup: string | APActor) => { }, [] as Array>, ), - ])) as GuildTextChannel[]; + ]); - guild.channels = channels; + guild.channels = channels as GuildTextChannel[]; await guild.save(); const roles = await Promise.all([ diff --git a/src/util/permission.ts b/src/util/permission.ts index ead9446..9a95e84 100644 --- a/src/util/permission.ts +++ b/src/util/permission.ts @@ -1,6 +1,7 @@ // Permissions regarding actions within a channel. -import type { Guild, User } from "../entity"; +import { type Guild, Member, Role, type User } from "../entity"; +import { getDatabase } from "./database"; // Stored within the role or channel overwrites export enum PERMISSION { @@ -27,7 +28,7 @@ export const DefaultPermissions: PERMISSION[] = [ PERMISSION.CREATE_INVITE, ]; -export const checkPermission = ( +export const checkPermission = async ( user: User, guild: Guild, permission: PERMISSION | PERMISSION[], @@ -36,9 +37,47 @@ export const checkPermission = ( if (guild.owner.id === user.id) return true; - const roles = guild.roles - // every role our user is a member of - .filter((x) => x.members.find((x) => x.user.id === user.id)); + // const roles = guild.roles + // // every role our user is a member of + // .filter((x) => x.members.find((x) => x.user.id === user.id)) + // .sort((a, b) => a.position - b.position); + + /* + const roles = ( + await Role.find({ + where: { + members: { + user: { + id: user.id, + }, + }, + guild: { + id: guild.id, + }, + }, + }) + ).sort((a, b) => a.position - b.position); + */ + + // TODO: making this function async may have consequences + const roles = ( + await getDatabase() + .getRepository(Role) + .createQueryBuilder("roles") + .leftJoin("roles.members", "members") + .where("roles.guildId = :guild_id", { guild_id: guild.id }) + .andWhere((qb) => { + const sub = qb + .subQuery() + .select("id") + .from(Member, "members") + .where("members.userId = :user_id", { user_id: user.id }) + .getQuery(); + + qb.where(`roles_members.guildMembersId in ${sub}`); + }) + .getMany() + ).sort((a, b) => a.position - b.position); let allowed = false; // for every role in order diff --git a/src/util/voice.ts b/src/util/voice.ts index 50c4e66..ee3070e 100644 --- a/src/util/voice.ts +++ b/src/util/voice.ts @@ -68,10 +68,10 @@ export const validateMediaToken = ( if (!channel) return reject(INVALID_TOKEN); if ( - !channel.checkPermission(user, [ + !(await channel.checkPermission(user, [ PERMISSION.CALL_CHANNEL, PERMISSION.VIEW_CHANNEL, - ]) + ])) ) return reject(INVALID_TOKEN);