diff --git a/src/d2m/actions/create-room.js b/src/d2m/actions/create-room.js index da2462d9..ff5782dc 100644 --- a/src/d2m/actions/create-room.js +++ b/src/d2m/actions/create-room.js @@ -459,12 +459,12 @@ async function unbridgeDeletedChannel(channel, guildID) { const webhook = select("webhook", ["webhook_id", "webhook_token"], {channel_id: channel.id}).get() if (webhook) { await discord.snow.webhook.deleteWebhook(webhook.webhook_id, webhook.webhook_token) - await db.prepare("DELETE FROM webhook WHERE channel_id = ?").run(channel.id) + db.prepare("DELETE FROM webhook WHERE channel_id = ?").run(channel.id) } // delete room from database - await db.prepare("DELETE FROM member_cache WHERE room_id = ?").run(roomID) - await db.prepare("DELETE FROM channel_room WHERE room_id = ? AND channel_id = ?").run(roomID, channel.id) // cascades to most other tables, like messages + db.prepare("DELETE FROM member_cache WHERE room_id = ?").run(roomID) + db.prepare("DELETE FROM channel_room WHERE room_id = ? AND channel_id = ?").run(roomID, channel.id) // cascades to most other tables, like messages if (!botInRoom) return @@ -507,7 +507,6 @@ async function unbridgeDeletedChannel(channel, guildID) { } // leave room - await api.setUserPower(roomID, bot, 0) await api.leaveRoom(roomID) } diff --git a/src/web/routes/link.js b/src/web/routes/link.js index 054f60e7..4698dfe6 100644 --- a/src/web/routes/link.js +++ b/src/web/routes/link.js @@ -41,6 +41,33 @@ function getCreateSpace(event) { return event.context.createSpace || sync.require("../../d2m/actions/create-space") } +/** + * @param {H3Event} event + * @param {string} guild_id + */ +async function validateUserHaveRightsOnGuild(event, guild_id) { + const managed = await auth.getManagedGuilds(event) + if (!managed.has(guild_id)) + throw createError({status: 403, message: "Forbidden", data: "Can't edit a guild you don't have Manage Server permissions in"}) +} + +/** + * @param {H3Event} event + * @param {string} guild_id + * @returns {Promise} + */ +async function validateGuildAccess(event, guild_id) { + // Check guild ID or nonce + await validateUserHaveRightsOnGuild(event, guild_id) + + // Check guild exists + const guild = discord.guilds.get(guild_id) + if (!guild) + throw createError({status: 400, message: "Bad Request", data: "Discord guild does not exist or bot has not joined it"}) + + return guild +} + /** * @param {H3Event} event * @param {string} channel_id @@ -90,12 +117,11 @@ const schema = { as.router.post("/api/link-space", defineEventHandler(async event => { const parsedBody = await readValidatedBody(event, schema.linkSpace.parse) const session = await auth.useSession(event) - const managed = await auth.getManagedGuilds(event) const api = getAPI(event) // Check guild ID const guildID = parsedBody.guild_id - if (!managed.has(guildID)) throw createError({status: 403, message: "Forbidden", data: "Can't edit a guild you don't have Manage Server permissions in"}) + await validateUserHaveRightsOnGuild(event, guildID) // Check space ID if (!session.data.mxid) throw createError({status: 403, message: "Forbidden", data: "Can't link with your Matrix space if you aren't logged in to Matrix"}) @@ -143,18 +169,12 @@ as.router.post("/api/link-space", defineEventHandler(async event => { as.router.post("/api/link", defineEventHandler(async event => { const parsedBody = await readValidatedBody(event, schema.link.parse) - const managed = await auth.getManagedGuilds(event) const api = getAPI(event) const createRoom = getCreateRoom(event) const createSpace = getCreateSpace(event) - // Check guild ID or nonce const guildID = parsedBody.guild_id - if (!managed.has(guildID)) throw createError({status: 403, message: "Forbidden", data: "Can't edit a guild you don't have Manage Server permissions in"}) - - // Check guild is bridged - const guild = discord.guilds.get(guildID) - if (!guild) throw createError({status: 400, message: "Bad Request", data: "Discord guild does not exist or bot has not joined it"}) + const guild = await validateGuildAccess(event, guildID) const spaceID = await createSpace.ensureSpace(guild) // Check channel exists @@ -232,14 +252,7 @@ as.router.post("/api/link", defineEventHandler(async event => { as.router.post("/api/unlink", defineEventHandler(async event => { const {channel_id, guild_id} = await readValidatedBody(event, schema.unlink.parse) - const managed = await auth.getManagedGuilds(event) - - // Check guild ID or nonce - if (!managed.has(guild_id)) throw createError({status: 403, message: "Forbidden", data: "Can't edit a guild you don't have Manage Server permissions in"}) - - // Check guild exists - const guild = discord.guilds.get(guild_id) - if (!guild) throw createError({status: 400, message: "Bad Request", data: "Discord guild does not exist or bot has not joined it"}) + await validateGuildAccess(event, guild_id) await doRoomUnlink(event, channel_id, guild_id) @@ -249,20 +262,12 @@ as.router.post("/api/unlink", defineEventHandler(async event => { as.router.post("/api/unlink-space", defineEventHandler(async event => { const {guild_id} = await readValidatedBody(event, schema.unlinkSpace.parse) - const managed = await auth.getManagedGuilds(event) const api = getAPI(event) - - // Check guild ID or nonce - if (!managed.has(guild_id)) throw createError({status: 403, message: "Forbidden", data: "Can't edit a guild you don't have Manage Server permissions in"}) - - // Check guild exists - const guild = discord.guilds.get(guild_id) - if (!guild) throw createError({status: 400, message: "Bad Request", data: "Discord guild does not exist or bot has not joined it"}) + await validateGuildAccess(event, guild_id) const spaceID = select("guild_space", "space_id", {guild_id: guild_id}).pluck().get() - if (!spaceID) { + if (!spaceID) throw createError({status: 400, message: "Bad Request", data: "Matrix space does not exist or bot has not linked it"}) - } const linkedChannels = select("channel_room", ["channel_id", "room_id", "name", "nick"], {guild_id: guild_id}).all() @@ -271,18 +276,21 @@ as.router.post("/api/unlink-space", defineEventHandler(async event => { } const remainingLinkedChannels = select("channel_room", ["channel_id", "room_id", "name", "nick"], {guild_id: guild_id}).all() - if (remainingLinkedChannels.length !== 0) { + if (remainingLinkedChannels.length !== 0) throw createError({status: 500, message: "Internal Server Error", data: "Some linked room still exists after trying to unlink all of them. Aborting the space unlinking..."}) - } await api.setUserPower(spaceID, me, 0) await api.leaveRoom(spaceID) - await db.prepare("DELETE FROM guild_space WHERE guild_id=? AND space_id=?").run(guild_id, spaceID) - await db.prepare("DELETE FROM guild_active WHERE guild_id=?").run(guild_id) - await discord.snow.user.leaveGuild(guild_id) - await db.prepare("DELETE FROM invite WHERE room_id=?").run(spaceID) + db.prepare("DELETE FROM guild_space WHERE guild_id=? AND space_id=?").run(guild_id, spaceID) - setResponseHeader(event, "HX-Redirect", "/") - return null + // NOTE: not deleting from guild_active as this can lead to inconsistent state: + // if we only delete from DB, the guild is still displayed on the top-right dropdown, + // but when selected we get the "Please add the bot to your server using the buttons on the home page." page + // + // So either keep as-is, or delete from guild_active, but also leave the discord guild? Not sure if we want that or not + // db.prepare("DELETE FROM guild_active WHERE guild_id=?").run(guild_id) + + setResponseHeader(event, "HX-Refresh", "true") + return null // 204 }))