From 94a96dd51ad1a7574886dddad9009bfe22e59ab4 Mon Sep 17 00:00:00 2001 From: l1s5 Date: Mon, 2 Nov 2026 18:13:52 +0900 Subject: [PATCH 1/2] Fix and test broken room bridge check A `m.room.member` handler check intended to determine whether a room was bridged or not ended up checking the truthiness of the db query itself, resulting in a tautology. This commit fixes the check and moves it over to matrix/utils so it may be reused and tested in isolation. --- src/m2d/event-dispatcher.js | 3 +-- src/matrix/utils.js | 13 ++++++++++++- src/matrix/utils.test.js | 14 +++++++++++++- 3 files changed, 26 insertions(+), 4 deletions(-) diff --git a/src/m2d/event-dispatcher.js b/src/m2d/event-dispatcher.js index c71f574..67e714d 100644 --- a/src/m2d/event-dispatcher.js +++ b/src/m2d/event-dispatcher.js @@ -422,8 +422,7 @@ async event => { if (utils.eventSenderIsFromDiscord(event.state_key)) return - const exists = select("channel_room", "room_id", {room_id: event.room_id}) ?? select("guild_space", "space_id", {space_id: event.room_id}) - if (!exists) return // don't cache members in unbridged rooms + if (!utils.isBridgedRoom(event.room_id)) return // don't cache members in unbridged rooms // Member is here let {powers: {[event.state_key]: memberPower}, tombstone} = await utils.getEffectivePower(event.room_id, [event.state_key], api) diff --git a/src/matrix/utils.js b/src/matrix/utils.js index 554baf3..59c8e5b 100644 --- a/src/matrix/utils.js +++ b/src/matrix/utils.js @@ -4,7 +4,7 @@ const assert = require("assert").strict const Ty = require("../types") const {tag} = require("@cloudrac3r/html-template-tag") const passthrough = require("../passthrough") -const {db} = passthrough +const {db, select} = passthrough const {reg} = require("./read-registration") const userRegex = reg.namespaces.users.map(u => new RegExp(u.regex)) @@ -41,6 +41,16 @@ function eventSenderIsFromDiscord(sender) { return false } +/** + * @param {string} roomID + * @returns {boolean} whether the room is a bridged channel or space + */ +function isBridgedRoom(roomID) { + if (select("channel_room", "room_id", {room_id: roomID}).get()) return true + if (select("guild_space", "space_id", {space_id: roomID}).get()) return true + return false +} + /** * Event IDs are really big and have more entropy than we need. * If we want to store the event ID in the database, we can store a more compact version by hashing it with this. @@ -388,6 +398,7 @@ async function setUserPowerCascade(spaceID, mxid, power, api) { module.exports.bot = bot module.exports.BLOCK_ELEMENTS = BLOCK_ELEMENTS module.exports.eventSenderIsFromDiscord = eventSenderIsFromDiscord +module.exports.isBridgedRoom = isBridgedRoom module.exports.makeMxcPublic = makeMxcPublic module.exports.getPublicUrlForMxc = getPublicUrlForMxc module.exports.getEventIDHash = getEventIDHash diff --git a/src/matrix/utils.test.js b/src/matrix/utils.test.js index 842c513..26e9fae 100644 --- a/src/matrix/utils.test.js +++ b/src/matrix/utils.test.js @@ -2,7 +2,7 @@ const {select} = require("../passthrough") const {test} = require("supertape") -const {eventSenderIsFromDiscord, getEventIDHash, MatrixStringBuilder, getViaServers, roomHasAtLeastVersion, removeCreatorsFromPowerLevels, setUserPower} = require("./utils") +const {eventSenderIsFromDiscord, isBridgedRoom, getEventIDHash, MatrixStringBuilder, getViaServers, roomHasAtLeastVersion, removeCreatorsFromPowerLevels, setUserPower} = require("./utils") const util = require("util") /** @param {string[]} mxids */ @@ -30,6 +30,18 @@ test("sender type: ooye puppet", t => { t.ok(eventSenderIsFromDiscord("@_ooye_sheep:cadence.moe")) }) +test("is bridged room: channel room", t => { + t.equal(isBridgedRoom("!kLRqKKUQXcibIMtOpl:cadence.moe"), true) +}) + +test("is bridged room: space", t => { + t.equal(isBridgedRoom("!jjmvBegULiLucuWEHU:cadence.moe"), true) +}) + +test("is bridged room: unbridged room", t => { + t.equal(isBridgedRoom("!unbridged:cadence.moe"), false) +}) + test("event hash: hash is the same each time", t => { const eventID = "$example" t.equal(getEventIDHash(eventID), getEventIDHash(eventID)) -- 2.34.1 From 75ead0edad3252b8691b75c3b0a9374ae76c08e6 Mon Sep 17 00:00:00 2001 From: l1s5 Date: Tue, 3 Nov 2026 22:08:26 +0900 Subject: [PATCH 2/2] fixup! Fix and test broken room bridge check --- .../0043-clean-unbridged-member-cache.sql | 9 +++++++++ src/m2d/event-dispatcher.js | 3 ++- src/matrix/utils.js | 13 +------------ src/matrix/utils.test.js | 14 +------------- 4 files changed, 13 insertions(+), 26 deletions(-) create mode 100644 src/db/migrations/0043-clean-unbridged-member-cache.sql diff --git a/src/db/migrations/0043-clean-unbridged-member-cache.sql b/src/db/migrations/0043-clean-unbridged-member-cache.sql new file mode 100644 index 0000000..d51b426 --- /dev/null +++ b/src/db/migrations/0043-clean-unbridged-member-cache.sql @@ -0,0 +1,9 @@ +BEGIN TRANSACTION; + +DELETE FROM member_cache +WHERE room_id NOT IN (SELECT room_id FROM channel_room) + AND room_id NOT IN (SELECT space_id FROM guild_space) + AND room_id NOT IN (SELECT room_id FROM historical_channel_room) + AND room_id NOT IN (SELECT room_id FROM invite); + +COMMIT; diff --git a/src/m2d/event-dispatcher.js b/src/m2d/event-dispatcher.js index 67e714d..0f48783 100644 --- a/src/m2d/event-dispatcher.js +++ b/src/m2d/event-dispatcher.js @@ -422,7 +422,8 @@ async event => { if (utils.eventSenderIsFromDiscord(event.state_key)) return - if (!utils.isBridgedRoom(event.room_id)) return // don't cache members in unbridged rooms + const exists = select("channel_room", "room_id", {room_id: event.room_id}).pluck().get() ?? select("guild_space", "space_id", {space_id: event.room_id}).pluck().get() + if (!exists) return // don't cache members in unbridged rooms // Member is here let {powers: {[event.state_key]: memberPower}, tombstone} = await utils.getEffectivePower(event.room_id, [event.state_key], api) diff --git a/src/matrix/utils.js b/src/matrix/utils.js index 59c8e5b..554baf3 100644 --- a/src/matrix/utils.js +++ b/src/matrix/utils.js @@ -4,7 +4,7 @@ const assert = require("assert").strict const Ty = require("../types") const {tag} = require("@cloudrac3r/html-template-tag") const passthrough = require("../passthrough") -const {db, select} = passthrough +const {db} = passthrough const {reg} = require("./read-registration") const userRegex = reg.namespaces.users.map(u => new RegExp(u.regex)) @@ -41,16 +41,6 @@ function eventSenderIsFromDiscord(sender) { return false } -/** - * @param {string} roomID - * @returns {boolean} whether the room is a bridged channel or space - */ -function isBridgedRoom(roomID) { - if (select("channel_room", "room_id", {room_id: roomID}).get()) return true - if (select("guild_space", "space_id", {space_id: roomID}).get()) return true - return false -} - /** * Event IDs are really big and have more entropy than we need. * If we want to store the event ID in the database, we can store a more compact version by hashing it with this. @@ -398,7 +388,6 @@ async function setUserPowerCascade(spaceID, mxid, power, api) { module.exports.bot = bot module.exports.BLOCK_ELEMENTS = BLOCK_ELEMENTS module.exports.eventSenderIsFromDiscord = eventSenderIsFromDiscord -module.exports.isBridgedRoom = isBridgedRoom module.exports.makeMxcPublic = makeMxcPublic module.exports.getPublicUrlForMxc = getPublicUrlForMxc module.exports.getEventIDHash = getEventIDHash diff --git a/src/matrix/utils.test.js b/src/matrix/utils.test.js index 26e9fae..842c513 100644 --- a/src/matrix/utils.test.js +++ b/src/matrix/utils.test.js @@ -2,7 +2,7 @@ const {select} = require("../passthrough") const {test} = require("supertape") -const {eventSenderIsFromDiscord, isBridgedRoom, getEventIDHash, MatrixStringBuilder, getViaServers, roomHasAtLeastVersion, removeCreatorsFromPowerLevels, setUserPower} = require("./utils") +const {eventSenderIsFromDiscord, getEventIDHash, MatrixStringBuilder, getViaServers, roomHasAtLeastVersion, removeCreatorsFromPowerLevels, setUserPower} = require("./utils") const util = require("util") /** @param {string[]} mxids */ @@ -30,18 +30,6 @@ test("sender type: ooye puppet", t => { t.ok(eventSenderIsFromDiscord("@_ooye_sheep:cadence.moe")) }) -test("is bridged room: channel room", t => { - t.equal(isBridgedRoom("!kLRqKKUQXcibIMtOpl:cadence.moe"), true) -}) - -test("is bridged room: space", t => { - t.equal(isBridgedRoom("!jjmvBegULiLucuWEHU:cadence.moe"), true) -}) - -test("is bridged room: unbridged room", t => { - t.equal(isBridgedRoom("!unbridged:cadence.moe"), false) -}) - test("event hash: hash is the same each time", t => { const eventID = "$example" t.equal(getEventIDHash(eventID), getEventIDHash(eventID)) -- 2.34.1