From 20043cc18d0bf43e29b613334d72a4db4ed276ba Mon Sep 17 00:00:00 2001 From: Paul Date: Thu, 10 Jun 2021 14:23:33 +0100 Subject: [PATCH] API: Client-side permissions calculator. --- src/api/permissions.ts | 125 +++++++++++++++++++++++++++++++++++++++++ src/maps/Servers.ts | 6 +- src/maps/Users.ts | 6 +- 3 files changed, 132 insertions(+), 5 deletions(-) create mode 100644 src/api/permissions.ts diff --git a/src/api/permissions.ts b/src/api/permissions.ts new file mode 100644 index 00000000..ba9a10b2 --- /dev/null +++ b/src/api/permissions.ts @@ -0,0 +1,125 @@ +import { Client } from '../Client'; +import { Users } from './objects'; + +export const UserPermission = { + Access: 0b00000000000000000000000000000001, // 1 + ViewProfile: 0b00000000000000000000000000000010, // 2 + SendMessage: 0b00000000000000000000000000000100, // 4 + Invite: 0b00000000000000000000000000001000, // 8 +} + +export const ChannelPermission = { + View: 0b00000000000000000000000000000001, // 1 + SendMessage: 0b00000000000000000000000000000010, // 2 + ManageMessages: 0b00000000000000000000000000000100, // 4 + ManageChannel: 0b00000000000000000000000000001000, // 8 + VoiceCall: 0b00000000000000000000000000010000, // 16 + InviteOthers: 0b00000000000000000000000000100000, // 32 +} + +export const ServerPermission = { + View: 0b00000000000000000000000000000001, // 1 + ManageMembers: 0b00000000000000000000000000000010, // 2 + ManageChannels: 0b00000000000000000000000000000100, // 4 + ManageServer: 0b00000000000000000000000000001000, // 8 + KickMembers: 0b00000000000000000000000000010000, // 16 + BanMembers: 0b00000000000000000000000000100000, // 32 + ChangeNickname: 0b00000000000000000001000000000000, // 4096 + ManageNicknames: 0b00000000000000000010000000000000, // 8192 + ChangeAvatar: 0b00000000000000000100000000000000, // 16392 + RemoveAvatars: 0b00000000000000001000000000000000, // 32784 +} + +const U32_MAX = 2**32 - 1; // 4294967295 + +class PermissionCalculator { + client: Client; + + constructor(client: Client) { + this.client = client; + } + + forUser(user_id: string): number { + let user = this.client.users.get(user_id); + if (typeof user === 'undefined') return 0; + + let permissions = 0; + switch (user.relationship) { + case Users.Relationship.Friend: + case Users.Relationship.User: + return U32_MAX; + case Users.Relationship.Blocked: + case Users.Relationship.BlockedOther: + return UserPermission.Access; + case Users.Relationship.Incoming: + case Users.Relationship.Outgoing: + permissions = UserPermission.Access; + } + + if (this.client.channels.toArray().find(channel => + (channel.channel_type === 'Group' || channel.channel_type === 'DirectMessage') + && channel.recipients.includes(user_id) + )) { + permissions |= UserPermission.Access | UserPermission.ViewProfile; + } + + return permissions; + } + + forChannel(channel_id: string): number { + let channel = this.client.channels.get(channel_id); + if (typeof channel === 'undefined') return 0; + + // This takes assumptions in the fact that + // by having the channel in the channel map, + // we are part of the channel, hence have + // access to it. + + switch (channel.channel_type) { + case 'SavedMessages': return U32_MAX; + case 'DirectMessage': { + let recipient = this.client.channels.getRecipient(channel_id); + let user_permissions = this.forUser(recipient); + + if (user_permissions & UserPermission.SendMessage) { + return ChannelPermission.View + + ChannelPermission.SendMessage + + ChannelPermission.VoiceCall; + } else { + return 0; + } + } + case 'Group': return ChannelPermission.View + + ChannelPermission.SendMessage + + ChannelPermission.ManageChannel + + ChannelPermission.VoiceCall + + ChannelPermission.InviteOthers; + case 'TextChannel': { + let server = this.client.servers.get(channel.server); + if (typeof server === 'undefined') return 0; + + if (server.owner === this.client.user?._id) { + return U32_MAX; + } else { + return ChannelPermission.View + + ChannelPermission.SendMessage + + ChannelPermission.InviteOthers; + } + } + } + } + + forServer(server_id: string): number { + let server = this.client.servers.get(server_id); + if (typeof server === 'undefined') return 0; + + if (server.owner === this.client.user?._id) { + return U32_MAX; + } else { + return ServerPermission.View + + ServerPermission.ChangeNickname + + ServerPermission.ChangeAvatar; + } + } +} + diff --git a/src/maps/Servers.ts b/src/maps/Servers.ts index 3fcc252b..942f5dc1 100644 --- a/src/maps/Servers.ts +++ b/src/maps/Servers.ts @@ -155,10 +155,10 @@ export default class Servers extends Collection { /** * Get the banner URL of a server * @param id ID of the target server - * @param size Size to resize image to + * @param width Width to resize image to * @param allowAnimation Whether to allow links to the original GIFs to be returned */ - getBannerURL(id: string, size?: number, allowAnimation?: boolean) { + getBannerURL(id: string, width?: number, allowAnimation?: boolean) { let url = this.client.configuration?.features.autumn.url; let server = this.getMutable(id); if (server?.banner) { @@ -166,7 +166,7 @@ export default class Servers extends Collection { if (allowAnimation && server.banner.content_type === 'image/gif') { return baseURL; } else { - return baseURL + (size ? `?size=${size}` : ''); + return baseURL + (width ? `?width=${width}` : ''); } } } diff --git a/src/maps/Users.ts b/src/maps/Users.ts index 1e493837..248e0ce5 100644 --- a/src/maps/Users.ts +++ b/src/maps/Users.ts @@ -136,8 +136,10 @@ export default class Users extends Collection { * Get the avatar URL of a user * @param id ID of the target user * @param size Size to resize image to + * @param allowAnimation Whether to allow GIFs to play + * @param disableFallback Don't return default avatar if no avatar */ - getAvatarURL(id: string, size?: number, allowAnimation?: boolean) { + getAvatarURL(id: string, size?: number, allowAnimation?: boolean, disableFallback?: boolean) { let url = this.client.configuration?.features.autumn.url; let attachment = this.getMutable(id)?.avatar; if (url && attachment) { @@ -147,7 +149,7 @@ export default class Users extends Collection { } else { return baseURL + (size ? `?size=${size}` : ''); } - } else { + } else if (!disableFallback) { return this.getDefaultAvatarURL(id); } }