diff --git a/src/provisioner.ts b/src/provisioner.ts index 478e81e6a343ce83b34eed06d0c33862120167b2..6d863ced8a35ac198b1a5609c7659ac331607c05 100644 --- a/src/provisioner.ts +++ b/src/provisioner.ts @@ -10,7 +10,7 @@ const PERMISSION_REQUEST_TIMEOUT = 300000; // 5 minutes export class Provisioner { private bridge: Bridge; - private pendingRequests: { [channelId: string]: (approved: boolean) => void } = {}; // [channelId]: resolver fn + private pendingRequests: Map<string, (approved: boolean) => void> = new Map(); // [channelId]: resolver fn public SetBridge(bridge: Bridge): void { this.bridge = bridge; @@ -32,38 +32,47 @@ export class Provisioner { return this.bridge.getRoomStore().removeEntriesByRemoteRoomId(remoteRoom.getId()); } - public async AskBridgePermission(channel: Discord.TextChannel, requestor: string): Promise<void> { + public async AskBridgePermission( + channel: Discord.TextChannel, + requestor: string, + timeout: number = PERMISSION_REQUEST_TIMEOUT): Promise<string> { const channelId = `${channel.guild.id}/${channel.id}`; let responded = false; + let resolve: (msg: string) => void; + let reject: (err: string) => void; + const deferP: Promise<string> = new Promise((res, rej) => {resolve = res; reject = rej;}); + const approveFn = (approved: boolean, expired = false) => { if (responded) { return; } responded = true; - delete this.pendingRequests[channelId]; + this.pendingRequests.delete(channelId); if (approved) { - return; + resolve("Approved"); } else { if (expired) { - throw new Error("Timed out waiting for a response from the Discord owners"); + reject("Timed out waiting for a response from the Discord owners"); } else { - throw new Error("The bridge has been declined by the Discord guild"); + reject("The bridge has been declined by the Discord guild"); } } }; - this.pendingRequests[channelId] = approveFn; - setTimeout(() => approveFn(false, true), PERMISSION_REQUEST_TIMEOUT); + this.pendingRequests.set(channelId, approveFn); + setTimeout(() => approveFn(false, true), timeout); - await channel.sendMessage(`${requestor} on matrix would like to bridge this channel. Someone with permission` + + await channel.send(`${requestor} on matrix would like to bridge this channel. Someone with permission` + " to manage webhooks please reply with !approve or !deny in the next 5 minutes"); + return await deferP; + } public HasPendingRequest(channel: Discord.TextChannel): boolean { const channelId = `${channel.guild.id}/${channel.id}`; - return !!this.pendingRequests[channelId]; + return this.pendingRequests.has(channelId); } public async MarkApproved( @@ -72,17 +81,17 @@ export class Provisioner { allow: boolean, ): Promise<boolean> { const channelId = `${channel.guild.id}/${channel.id}`; - if (!this.pendingRequests[channelId]) { + if (!this.pendingRequests.has(channelId)) { return false; // no change, so false } const perms = channel.permissionsFor(member); - if (!perms || !perms.hasPermission(Discord.Permissions.FLAGS.MANAGE_WEBHOOKS as Discord.PermissionResolvable)) { + if (!perms || !perms.has(Discord.Permissions.FLAGS.MANAGE_WEBHOOKS as Discord.PermissionResolvable)) { // Missing permissions, so just reject it throw new Error("You do not have permission to manage webhooks in this channel"); } - this.pendingRequests[channelId](allow); + this.pendingRequests.get(channelId)!(allow); return true; // replied, so true } }