import { test } from "node:test"; import assert from "node:assert/strict"; import { authorize, DROP } from "../src/authorize.mjs"; import { binding, message, IDS } from "./helpers.mjs"; const b = binding(); const threads = new Map([ [IDS.threadOfAdmin, { type: 11, parentId: IDS.admin, name: "admin-thread", guildId: IDS.guild }], [IDS.threadOfOther, { type: 11, parentId: IDS.other, name: "other-thread", guildId: IDS.guild }], ["100000000000000030", { type: 12, parentId: IDS.general, name: "private-general-thread", guildId: IDS.guild }], ["100000000000000031", { type: 0, parentId: null, name: "text-not-thread", guildId: IDS.guild }], ]); const info = (id) => threads.get(id); const botMention = [{ id: IDS.bot, username: "bot" }]; const table = [ ["open channel, listed user", message(), { ok: true, channel: IDS.admin, thread: null }], ["wrong guild", message({ guild_id: "100000000000000099" }), { ok: false, reason: DROP.GUILD }], ["no guild (DM)", message({ guild_id: undefined }), { ok: false, reason: DROP.GUILD }], ["unlisted channel", message({ channel_id: IDS.other }), { ok: false, reason: DROP.CHANNEL }], ["unknown channel, no info", message({ channel_id: "100000000000000098" }), { ok: false, reason: DROP.CHANNEL }], ["thread of listed parent", message({ channel_id: IDS.threadOfAdmin }), { ok: true, channel: IDS.admin, thread: IDS.threadOfAdmin }], ["thread of unlisted parent", message({ channel_id: IDS.threadOfOther }), { ok: false, reason: DROP.THREAD_PARENT }], ["text channel that is not a thread and not listed", message({ channel_id: "100000000000000031" }), { ok: false, reason: DROP.CHANNEL }], ["unlisted user", message({ author: { id: IDS.stranger } }), { ok: false, reason: DROP.USER }], ["no author", message({ author: undefined }), { ok: false, reason: DROP.USER }], ["bot author (listed id, bot flag)", message({ author: { id: IDS.owner, bot: true } }), { ok: false, reason: DROP.BOT }], ["system author", message({ author: { id: IDS.owner, system: true } }), { ok: false, reason: DROP.BOT }], ["the bot itself", message({ author: { id: IDS.bot } }), { ok: false, reason: DROP.SELF }], ["webhook", message({ webhook_id: "100000000000000050" }), { ok: false, reason: DROP.WEBHOOK }], ["mention channel without mention", message({ channel_id: IDS.general }), { ok: false, reason: DROP.MENTION }], ["mention channel with bot mention", message({ channel_id: IDS.general, mentions: botMention }), { ok: true, channel: IDS.general, thread: null }], ["mention channel with @everyone only", message({ channel_id: IDS.general, mention_everyone: true, content: "@everyone hi" }), { ok: false, reason: DROP.MENTION }], ["mention channel mentioning someone else", message({ channel_id: IDS.general, mentions: [{ id: IDS.stranger }] }), { ok: false, reason: DROP.MENTION }], ["mention channel, content says @bot but mentions empty", message({ channel_id: IDS.general, content: `<@${IDS.bot}> hi` }), { ok: false, reason: DROP.MENTION }], ["private thread under mention channel, mentioned", message({ channel_id: "100000000000000030", mentions: botMention }), { ok: true, channel: IDS.general, thread: "100000000000000030" }], ["private thread under mention channel, not mentioned", message({ channel_id: "100000000000000030" }), { ok: false, reason: DROP.MENTION }], ["thread in another guild per channel info", message({ channel_id: IDS.threadOfAdmin, guild_id: IDS.guild }), { ok: true, channel: IDS.admin, thread: IDS.threadOfAdmin }], ["not an object", null, { ok: false, reason: DROP.NOT_OBJECT }], ["no id", message({ id: "" }), { ok: false, reason: DROP.NO_ID }], ["oversize content is accepted and flagged", message({ content: "x".repeat(4001) }), { ok: true, channel: IDS.admin, thread: null, oversize: true }], ["exactly the limit is not oversize", message({ content: "x".repeat(4000) }), { ok: true, channel: IDS.admin, thread: null, oversize: false }], ]; for (const [name, msg, expected] of table) { test(`authorize: ${name}`, () => { const r = authorize(b, msg, info); assert.equal(r.ok, expected.ok, JSON.stringify(r)); if (!expected.ok) assert.equal(r.reason, expected.reason); else { assert.equal(r.channel.id, expected.channel); assert.equal(r.thread ? r.thread.id : null, expected.thread); if (expected.oversize !== undefined) assert.equal(r.oversize, expected.oversize); } }); } test("authorize: order puts wrong guild before user, and user before channel (no channel lookup for strangers)", () => { let looked = 0; const spy = (id) => { looked += 1; return info(id); }; assert.equal(authorize(b, message({ guild_id: "100000000000000099", author: { id: IDS.stranger } }), spy).reason, DROP.GUILD); assert.equal(authorize(b, message({ channel_id: IDS.threadOfAdmin, author: { id: IDS.stranger } }), spy).reason, DROP.USER); assert.equal(looked, 0); });