forked from cadence/out-of-your-element
Compare commits
No commits in common. "903669b45931ad8d7512e43d04f41b8fe7cc9be4" and "a968bacffd47f5c85359cd380539f2d7ca17139a" have entirely different histories.
903669b459
...
a968bacffd
4 changed files with 36 additions and 91 deletions
|
|
@ -24,7 +24,3 @@ test("api path: real world mxid", t => {
|
|||
test("api path: extras number works", t => {
|
||||
t.equal(path(`/client/v3/rooms/!example/timestamp_to_event`, null, {ts: 1687324651120}), "/client/v3/rooms/!example/timestamp_to_event?ts=1687324651120")
|
||||
})
|
||||
|
||||
test("api path: multiple via params", t => {
|
||||
t.equal(path(`/client/v3/rooms/!example/join`, null, {via: ["cadence.moe", "matrix.org"], ts: 1687324651120}), "/client/v3/rooms/!example/join?via=cadence.moe&via=matrix.org&ts=1687324651120")
|
||||
})
|
||||
|
|
|
|||
|
|
@ -54,10 +54,6 @@ block body
|
|||
.s-page-title.mb24
|
||||
h1.s-page-title--header= guild.name
|
||||
|
||||
form(method="post" action=rel("/api/unlink-space") hx-confirm="Do you want to unlink this server?\nThis will unlink every channels listed below.\nIt may take a moment to clean up Matrix resources.")
|
||||
input(type="hidden" name="guild_id" value=guild.id)
|
||||
button.s-btn.s-btn__muted.s-btn__xs(hx-post=rel("/api/unlink-space") hx-trigger="click" hx-disabled-elt="this")!= icons.Icons.IconLinkSm
|
||||
|
||||
.d-flex.g16(class="sm:fw-wrap")
|
||||
.fl-grow1
|
||||
h2.fs-headline1 Invite a Matrix user
|
||||
|
|
|
|||
|
|
@ -12,8 +12,6 @@ const auth = sync.require("../auth")
|
|||
const mreq = sync.require("../../matrix/mreq")
|
||||
const {reg} = require("../../matrix/read-registration")
|
||||
|
||||
const me = `@${reg.sender_localpart}:${reg.ooye.server_name}`
|
||||
|
||||
/**
|
||||
* @param {H3Event} event
|
||||
* @returns {import("../../matrix/api")}
|
||||
|
|
@ -41,48 +39,6 @@ function getCreateSpace(event) {
|
|||
return event.context.createSpace || sync.require("../../d2m/actions/create-space")
|
||||
}
|
||||
|
||||
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"})
|
||||
}
|
||||
|
||||
function validateBotIsInGuild(guild) {
|
||||
if (!guild)
|
||||
throw createError({status: 400, message: "Bad Request", data: "Discord guild does not exist or bot has not joined it"})
|
||||
}
|
||||
|
||||
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)
|
||||
validateBotIsInGuild(guild)
|
||||
|
||||
return guild
|
||||
}
|
||||
|
||||
async function doRoomUnlink(createRoom, channel_id, guild_id) {
|
||||
// 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 = {
|
||||
linkSpace: z.object({
|
||||
guild_id: z.string(),
|
||||
|
|
@ -96,20 +52,18 @@ const schema = {
|
|||
unlink: z.object({
|
||||
guild_id: z.string(),
|
||||
channel_id: z.string()
|
||||
}),
|
||||
unlinkSpace: z.object({
|
||||
guild_id: z.string(),
|
||||
}),
|
||||
})
|
||||
}
|
||||
|
||||
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
|
||||
await validateUserHaveRightsOnGuild(event, guildID)
|
||||
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 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"})
|
||||
|
|
@ -129,6 +83,7 @@ as.router.post("/api/link-space", defineEventHandler(async event => {
|
|||
}
|
||||
|
||||
// Check bridge has PL 100
|
||||
const me = `@${reg.sender_localpart}:${reg.ooye.server_name}`
|
||||
/** @type {Ty.Event.M_Power_Levels?} */
|
||||
let powerLevelsStateContent = null
|
||||
try {
|
||||
|
|
@ -153,12 +108,18 @@ 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
|
||||
guild = await validateGuildAccess(event, guildID)
|
||||
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 spaceID = await createSpace.ensureSpace(guild)
|
||||
|
||||
// Check channel exists
|
||||
|
|
@ -222,39 +183,33 @@ 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)
|
||||
const createRoom = getCreateRoom(event)
|
||||
await validateGuildAccess(event, guild_id)
|
||||
|
||||
await doRoomUnlink(createRoom, channel_id, guild_id)
|
||||
|
||||
setResponseHeader(event, "HX-Refresh", "true")
|
||||
return null // 204
|
||||
}))
|
||||
|
||||
as.router.post("/api/unlink-space", defineEventHandler(async event => {
|
||||
const {guild_id} = await readValidatedBody(event, schema.unlinkSpace.parse)
|
||||
const api = getAPI(event)
|
||||
await validateGuildAccess(event, guild_id)
|
||||
|
||||
// TODO: check valid spaceID etc.
|
||||
const spaceID = select("guild_space", "space_id", {guild_id: guild_id}).pluck().get()
|
||||
const channelIDs = discord.guildChannelMap.get(guild_id)
|
||||
const linkedChannels = select("channel_room", ["channel_id", "room_id", "name", "nick"], {channel_id: channelIDs}).all()
|
||||
|
||||
linkedChannels.forEach(async channel => {
|
||||
// FIXME: not sure about how to create a proper createRoom.
|
||||
// Can we tinker with event to add channel_id information?
|
||||
const createRoom = getCreateRoom(event)
|
||||
await doRoomUnlink(createRoom, channel.channel_id, 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)
|
||||
// NOTE: Do not clean invites, as we may need it to get a correct "via" HS later if we want to re-link without invite
|
||||
// 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"})
|
||||
|
||||
// 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)
|
||||
|
||||
setResponseHeader(event, "HX-Refresh", "true")
|
||||
return null // 204
|
||||
|
|
|
|||
|
|
@ -17,8 +17,6 @@ const {reg} = require("../src/matrix/read-registration")
|
|||
reg.ooye.discord_token = "Njg0MjgwMTkyNTUzODQ0NzQ3.Xl3zlw.baby"
|
||||
reg.ooye.server_origin = "https://matrix.cadence.moe" // so that tests will pass even when hard-coded
|
||||
reg.ooye.server_name = "cadence.moe"
|
||||
reg.ooye.namespace_prefix = "_ooye_"
|
||||
reg.sender_localpart = "_ooye_bot"
|
||||
reg.id = "baby"
|
||||
reg.as_token = "don't actually take authenticated actions on the server"
|
||||
reg.hs_token = "don't actually take authenticated actions on the server"
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue