From f5ee130463e9a2157a58c840794d669d536d595f Mon Sep 17 00:00:00 2001 From: Bea Date: Sun, 8 Mar 2026 22:11:28 +0000 Subject: [PATCH] Handle expired invites & fix test registration (#73) This PR addresses a bridge crash discovered while backfilling old channels, alongside a wee QoL fix for the test suite. * **Expired Events (`d2m`):** Wraps Discord scheduled event/invite link lookups in a try-catch block. If a link is expired (404 or Discord error 10006), the bridge now posts a fallback `m.notice` rather than throwing an error and halting message conversion. * **Test Suite Setup:** Updates `test.js` to initialize the mock registration object using `getTemplateRegistration()` preventing test runner crashes when running without a local `registration.yaml` file. Co-authored-by: Cadence Ember Reviewed-on: https://gitdab.com/cadence/out-of-your-element/pulls/73 Co-authored-by: Bea Co-committed-by: Bea --- src/d2m/converters/message-to-event.js | 13 +++++++- src/d2m/converters/message-to-event.test.js | 22 +++++++++++++ test/test.js | 36 ++++++++++----------- 3 files changed, 51 insertions(+), 20 deletions(-) diff --git a/src/d2m/converters/message-to-event.js b/src/d2m/converters/message-to-event.js index b1af2e3..81c821f 100644 --- a/src/d2m/converters/message-to-event.js +++ b/src/d2m/converters/message-to-event.js @@ -770,7 +770,18 @@ async function messageToEvent(message, guild, options = {}, di) { // Then scheduled events if (message.content && di?.snow) { for (const match of [...message.content.matchAll(/discord\.gg\/([A-Za-z0-9]+)\?event=([0-9]{18,})/g)]) { // snowflake has minimum 18 because the events feature is at least that old - const invite = await di.snow.invite.getInvite(match[1], {guild_scheduled_event_id: match[2]}) + let invite + try { + invite = await di.snow.invite.getInvite(match[1], {guild_scheduled_event_id: match[2]}) + } catch (e) { + // Skip expired/invalid invites and events + if (e.message === `{"message": "Unknown Invite", "code": 10006}`) { + break + } else { + throw e + } + } + const event = invite.guild_scheduled_event if (!event) continue // the event ID provided was not valid diff --git a/src/d2m/converters/message-to-event.test.js b/src/d2m/converters/message-to-event.test.js index 1a73aea..f071417 100644 --- a/src/d2m/converters/message-to-event.test.js +++ b/src/d2m/converters/message-to-event.test.js @@ -1538,6 +1538,28 @@ test("message2event: vc invite event renders embed with room link", async t => { ]) }) +test("message2event: expired/invalid invites are sent as-is", async t => { + const events = await messageToEvent({content: "https://discord.gg/placeholder?event=1381190945646710824"}, {}, {}, { + snow: { + invite: { + async getInvite() { + throw new Error(`{"message": "Unknown Invite", "code": 10006}`) + } + } + } + }) + t.deepEqual(events, [ + { + $type: "m.room.message", + body: "https://discord.gg/placeholder?event=1381190945646710824", + format: "org.matrix.custom.html", + formatted_body: "https://discord.gg/placeholder?event=1381190945646710824", + "m.mentions": {}, + msgtype: "m.text", + } + ]) +}) + test("message2event: channel links are converted even inside lists (parser post-processer descends into list items)", async t => { let called = 0 const events = await messageToEvent({ diff --git a/test/test.js b/test/test.js index e05b687..da6bcba 100644 --- a/test/test.js +++ b/test/test.js @@ -6,31 +6,29 @@ const sqlite = require("better-sqlite3") const {Writable} = require("stream") const migrate = require("../src/db/migrate") const HeatSync = require("heatsync") -const {test, extend} = require("supertape") +const {test} = require("supertape") const data = require("./data") const {green} = require("ansi-colors") +const mixin = require("@cloudrac3r/mixin-deep") const passthrough = require("../src/passthrough") const db = new sqlite(":memory:") -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" -reg.namespaces = { - users: [{regex: "@_ooye_.*:cadence.moe", exclusive: true}], - aliases: [{regex: "#_ooye_.*:cadence.moe", exclusive: true}] -} -reg.ooye.bridge_origin = "https://bridge.example.org" -reg.ooye.time_zone = "Pacific/Auckland" -reg.ooye.max_file_size = 5000000 -reg.ooye.web_password = "password123" -reg.ooye.include_user_id_in_mxid = false +const registration = require("../src/matrix/read-registration") +registration.reg = mixin(registration.getTemplateRegistration("cadence.moe"), { + id: "baby", + url: "http://localhost:6693", + as_token: "don't actually take authenticated actions on the server", + hs_token: "don't actually take authenticated actions on the server", + ooye: { + server_origin: "https://matrix.cadence.moe", + bridge_origin: "https://bridge.example.org", + discord_token: "Njg0MjgwMTkyNTUzODQ0NzQ3.Xl3zlw.baby", + discord_client_secret: "baby", + web_password: "password123", + time_zone: "Pacific/Auckland", + } +}) const sync = new HeatSync({watchFS: false})