forked from cadence/out-of-your-element
Compare commits
3 commits
ce47199ba3
...
9e0e0023f0
| Author | SHA1 | Date | |
|---|---|---|---|
| 9e0e0023f0 | |||
| 4c4e17e520 | |||
| 978de797ba |
2 changed files with 98 additions and 37 deletions
6
.editorconfig
Normal file
6
.editorconfig
Normal file
|
|
@ -0,0 +1,6 @@
|
||||||
|
[*]
|
||||||
|
indent_style = tab
|
||||||
|
|
||||||
|
[*.pug]
|
||||||
|
indent_style = space
|
||||||
|
indent_size = 2
|
||||||
|
|
@ -12,6 +12,8 @@ const auth = sync.require("../auth")
|
||||||
const mreq = sync.require("../../matrix/mreq")
|
const mreq = sync.require("../../matrix/mreq")
|
||||||
const {reg} = require("../../matrix/read-registration")
|
const {reg} = require("../../matrix/read-registration")
|
||||||
|
|
||||||
|
const me = `@${reg.sender_localpart}:${reg.ooye.server_name}`
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @param {H3Event} event
|
* @param {H3Event} event
|
||||||
* @returns {import("../../matrix/api")}
|
* @returns {import("../../matrix/api")}
|
||||||
|
|
@ -39,6 +41,60 @@ function getCreateSpace(event) {
|
||||||
return event.context.createSpace || sync.require("../../d2m/actions/create-space")
|
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<DiscordTypes.APIGuild & {members: DiscordTypes.APIGuildMember[]}>}
|
||||||
|
*/
|
||||||
|
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
|
||||||
|
* @param {string} guild_id
|
||||||
|
*/
|
||||||
|
async function doRoomUnlink(event, channel_id, guild_id) {
|
||||||
|
const createRoom = getCreateRoom(event)
|
||||||
|
|
||||||
|
// Check that the channel (if it exists) is part of this guild
|
||||||
|
/** @type {any} */
|
||||||
|
let channel = discord.channels.get(channel_id)
|
||||||
|
if (channel) {
|
||||||
|
if (!("guild_id" in channel) || channel.guild_id !== guild_id) throw createError({status: 400, message: "Bad Request", data: `Channel ID ${channel_id} is not part of guild ${guild_id}`})
|
||||||
|
} else {
|
||||||
|
// Otherwise, if the channel isn't cached, it must have been deleted.
|
||||||
|
// There's no other authentication here - it's okay for anyone to unlink a deleted channel just by knowing its ID.
|
||||||
|
channel = {id: channel_id}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Check channel is currently bridged
|
||||||
|
const row = select("channel_room", "channel_id", {channel_id: channel_id}).get()
|
||||||
|
if (!row) throw createError({status: 400, message: "Bad Request", data: `Channel ID ${channel_id} is not currently bridged`})
|
||||||
|
|
||||||
|
// Do it
|
||||||
|
await createRoom.unbridgeDeletedChannel(channel, guild_id)
|
||||||
|
}
|
||||||
|
|
||||||
const schema = {
|
const schema = {
|
||||||
linkSpace: z.object({
|
linkSpace: z.object({
|
||||||
guild_id: z.string(),
|
guild_id: z.string(),
|
||||||
|
|
@ -52,18 +108,20 @@ const schema = {
|
||||||
unlink: z.object({
|
unlink: z.object({
|
||||||
guild_id: z.string(),
|
guild_id: z.string(),
|
||||||
channel_id: z.string()
|
channel_id: z.string()
|
||||||
})
|
}),
|
||||||
|
unlinkSpace: z.object({
|
||||||
|
guild_id: z.string(),
|
||||||
|
}),
|
||||||
}
|
}
|
||||||
|
|
||||||
as.router.post("/api/link-space", defineEventHandler(async event => {
|
as.router.post("/api/link-space", defineEventHandler(async event => {
|
||||||
const parsedBody = await readValidatedBody(event, schema.linkSpace.parse)
|
const parsedBody = await readValidatedBody(event, schema.linkSpace.parse)
|
||||||
const session = await auth.useSession(event)
|
const session = await auth.useSession(event)
|
||||||
const managed = await auth.getManagedGuilds(event)
|
|
||||||
const api = getAPI(event)
|
const api = getAPI(event)
|
||||||
|
|
||||||
// Check guild ID
|
// Check guild ID
|
||||||
const guildID = parsedBody.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
|
// 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"})
|
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"})
|
||||||
|
|
@ -83,7 +141,6 @@ as.router.post("/api/link-space", defineEventHandler(async event => {
|
||||||
}
|
}
|
||||||
|
|
||||||
// Check bridge has PL 100
|
// Check bridge has PL 100
|
||||||
const me = `@${reg.sender_localpart}:${reg.ooye.server_name}`
|
|
||||||
/** @type {Ty.Event.M_Power_Levels?} */
|
/** @type {Ty.Event.M_Power_Levels?} */
|
||||||
let powerLevelsStateContent = null
|
let powerLevelsStateContent = null
|
||||||
try {
|
try {
|
||||||
|
|
@ -108,18 +165,12 @@ as.router.post("/api/link-space", defineEventHandler(async event => {
|
||||||
|
|
||||||
as.router.post("/api/link", defineEventHandler(async event => {
|
as.router.post("/api/link", defineEventHandler(async event => {
|
||||||
const parsedBody = await readValidatedBody(event, schema.link.parse)
|
const parsedBody = await readValidatedBody(event, schema.link.parse)
|
||||||
const managed = await auth.getManagedGuilds(event)
|
|
||||||
const api = getAPI(event)
|
const api = getAPI(event)
|
||||||
const createRoom = getCreateRoom(event)
|
const createRoom = getCreateRoom(event)
|
||||||
const createSpace = getCreateSpace(event)
|
const createSpace = getCreateSpace(event)
|
||||||
|
|
||||||
// Check guild ID or nonce
|
|
||||||
const guildID = parsedBody.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"})
|
const guild = await validateGuildAccess(event, guildID)
|
||||||
|
|
||||||
// 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 spaceID = await createSpace.ensureSpace(guild)
|
const spaceID = await createSpace.ensureSpace(guild)
|
||||||
|
|
||||||
// Check channel exists
|
// Check channel exists
|
||||||
|
|
@ -183,33 +234,37 @@ as.router.post("/api/link", defineEventHandler(async event => {
|
||||||
|
|
||||||
as.router.post("/api/unlink", defineEventHandler(async event => {
|
as.router.post("/api/unlink", defineEventHandler(async event => {
|
||||||
const {channel_id, guild_id} = await readValidatedBody(event, schema.unlink.parse)
|
const {channel_id, guild_id} = await readValidatedBody(event, schema.unlink.parse)
|
||||||
const managed = await auth.getManagedGuilds(event)
|
await validateGuildAccess(event, guild_id)
|
||||||
const createRoom = getCreateRoom(event)
|
|
||||||
|
|
||||||
// Check guild ID or nonce
|
await doRoomUnlink(event, channel_id, guild_id)
|
||||||
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"})
|
|
||||||
|
setResponseHeader(event, "HX-Refresh", "true")
|
||||||
// Check guild exists
|
return null // 204
|
||||||
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"})
|
|
||||||
|
as.router.post("/api/unlink-space", defineEventHandler(async event => {
|
||||||
// Check that the channel (if it exists) is part of this guild
|
const {guild_id} = await readValidatedBody(event, schema.unlinkSpace.parse)
|
||||||
/** @type {any} */
|
const api = getAPI(event)
|
||||||
let channel = discord.channels.get(channel_id)
|
await validateGuildAccess(event, guild_id)
|
||||||
if (channel) {
|
|
||||||
if (!("guild_id" in channel) || channel.guild_id !== guild_id) throw createError({status: 400, message: "Bad Request", data: `Channel ID ${channel_id} is not part of guild ${guild_id}`})
|
// TODO: check valid spaceID etc.
|
||||||
} else {
|
const spaceID = select("guild_space", "space_id", {guild_id: guild_id}).pluck().get()
|
||||||
// Otherwise, if the channel isn't cached, it must have been deleted.
|
const channelIDs = discord.guildChannelMap.get(guild_id)
|
||||||
// There's no other authentication here - it's okay for anyone to unlink a deleted channel just by knowing its ID.
|
const linkedChannels = select("channel_room", ["channel_id", "room_id", "name", "nick"], {channel_id: channelIDs}).all()
|
||||||
channel = {id: channel_id}
|
|
||||||
}
|
linkedChannels.forEach(async channel => {
|
||||||
|
// FIXME: not sure about how to create a proper createRoom.
|
||||||
// Check channel is currently bridged
|
// Can we tinker with event to add channel_id information?
|
||||||
const row = select("channel_room", "channel_id", {channel_id: channel_id}).get()
|
const createRoom = getCreateRoom(event)
|
||||||
if (!row) throw createError({status: 400, message: "Bad Request", data: `Channel ID ${channel_id} is not currently bridged`})
|
await doRoomUnlink(createRoom, channel.channel_id, guild_id)
|
||||||
|
});
|
||||||
// Do it
|
|
||||||
await createRoom.unbridgeDeletedChannel(channel, guild_id)
|
// TODO: add a check that no remaining bridged rooms are in the space
|
||||||
|
|
||||||
|
await api.setUserPower(spaceID, me, 0)
|
||||||
|
await api.leaveRoom(spaceID)
|
||||||
|
|
||||||
|
db.prepare("DELETE FROM guild_space WHERE guild_id=? AND space_id=?").run(guild_id, spaceID)
|
||||||
|
|
||||||
setResponseHeader(event, "HX-Refresh", "true")
|
setResponseHeader(event, "HX-Refresh", "true")
|
||||||
return null // 204
|
return null // 204
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue