From a29d019d17690324c41acd0940feb3145c077b11 Mon Sep 17 00:00:00 2001 From: Cadence Ember Date: Wed, 5 Feb 2025 16:57:45 +1300 Subject: [PATCH] Make read-only Discord channels read-only on Matrix --- src/d2m/actions/create-room.js | 4 ++ src/d2m/actions/create-room.test.js | 79 +++++++++++++++++++++++++++++ src/web/routes/guild.test.js | 10 ++-- test/data.js | 19 +++++++ test/ooye-test-data.sql | 3 +- test/test.js | 3 +- 6 files changed, 111 insertions(+), 7 deletions(-) diff --git a/src/d2m/actions/create-room.js b/src/d2m/actions/create-room.js index cf785ac..074fa54 100644 --- a/src/d2m/actions/create-room.js +++ b/src/d2m/actions/create-room.js @@ -120,6 +120,7 @@ async function channelToKState(channel, guild, di) { } const everyonePermissions = dUtils.getPermissions([], guild.roles, undefined, channel.permission_overwrites) + const everyoneCanSend = dUtils.hasPermission(everyonePermissions, DiscordTypes.PermissionFlagsBits.SendMessages) const everyoneCanMentionEveryone = dUtils.hasAllPermissions(everyonePermissions, ["MentionEveryone"]) const globalAdmins = select("member_power", ["mxid", "power_level"], {room_id: "*"}).all() @@ -129,6 +130,7 @@ async function channelToKState(channel, guild, di) { const spacePowerEvent = await di.api.getStateEvent(guildSpaceID, "m.room.power_levels", "") const spacePower = spacePowerEvent.users + /** @type {any} */ const channelKState = { "m.room.name/": {name: convertedName}, "m.room.topic/": {topic: convertedTopic}, @@ -141,7 +143,9 @@ async function channelToKState(channel, guild, di) { }, /** @type {{join_rule: string, [x: string]: any}} */ "m.room.join_rules/": join_rules, + /** @type {Ty.Event.M_Power_Levels} */ "m.room.power_levels/": { + events_default: everyoneCanSend ? 0 : 50, notifications: { room: everyoneCanMentionEveryone ? 0 : 20 }, diff --git a/src/d2m/actions/create-room.test.js b/src/d2m/actions/create-room.test.js index 0376d65..fa4a55d 100644 --- a/src/d2m/actions/create-room.test.js +++ b/src/d2m/actions/create-room.test.js @@ -114,6 +114,85 @@ test("channel2room: matrix room that already has a custom topic set", async t => t.equal(called, 1) }) +test("channel2room: read-only discord channel", async t => { + let called = 0 + async function getStateEvent(roomID, type, key) { // getting power levels from space to apply to room + called++ + t.equal(roomID, "!jjWAGMeQdNrVZSSfvz:cadence.moe") + t.equal(type, "m.room.power_levels") + t.equal(key, "") + return {} + } + const expected = { + "chat.schildi.hide_ui/read_receipts": {}, + "m.room.avatar/": { + url: { + $url: "/icons/112760669178241024/a_f83622e09ead74f0c5c527fe241f8f8c.png?size=1024", + }, + }, + "m.room.guest_access/": { + guest_access: "can_join", + }, + "m.room.history_visibility/": { + history_visibility: "shared", + }, + "m.room.join_rules/": { + allow: [ + { + room_id: "!jjWAGMeQdNrVZSSfvz:cadence.moe", + type: "m.room_membership", + }, + ], + join_rule: "restricted", + }, + "m.room.name/": { + name: "updates", + }, + "m.room.topic/": { + topic: "Updates and release announcements for Out Of Your Element.\n\nChannel ID: 1161864271370666075\nGuild ID: 112760669178241024" + }, + "m.room.power_levels/": { + events_default: 50, // <-- it should be read-only! + notifications: { + room: 20, + }, + users: { + "@test_auto_invite:example.org": 100, + }, + }, + "m.space.parent/!jjWAGMeQdNrVZSSfvz:cadence.moe": { + canonical: true, + via: [ + "cadence.moe", + ], + }, + "uk.half-shot.bridge/moe.cadence.ooye://discord/112760669178241024/1161864271370666075": { + bridgebot: "@_ooye_bot:cadence.moe", + channel: { + displayname: "updates", + external_url: "https://discord.com/channels/112760669178241024/1161864271370666075", + id: "1161864271370666075", + }, + network: { + avatar_url: { + "$url": "/icons/112760669178241024/a_f83622e09ead74f0c5c527fe241f8f8c.png?size=1024", + }, + displayname: "Psychonauts 3", + id: "112760669178241024", + }, + protocol: { + displayname: "Discord", + id: "discord", + } + } + } + t.deepEqual( + kstateStripConditionals(await channelToKState(testData.channel.updates, testData.guild.general, {api: {getStateEvent}}).then(x => x.channelKState)), + expected + ) + t.equal(called, 1) +}) + test("convertNameAndTopic: custom name and topic", t => { t.deepEqual( _convertNameAndTopic({id: "123", name: "the-twilight-zone", topic: "Spooky stuff here. :ghost:", type: 0}, {id: "456"}, "hauntings"), diff --git a/src/web/routes/guild.test.js b/src/web/routes/guild.test.js index 671baed..746477d 100644 --- a/src/web/routes/guild.test.js +++ b/src/web/routes/guild.test.js @@ -83,9 +83,9 @@ test("web guild: unbridged self-service guild shows available spaces", async t = }) t.has(html, `Data Horde`) t.has(html, `
  • here is the space topic
  • `) - // t.match(html, //) - // t.notMatch(html, /some room<\/strong>/) - // t.notMatch(html, /somebody else's space<\/strong>/) + t.has(html, ``) + t.notMatch(html, /some room<\/strong>/) + t.notMatch(html, /somebody else's space<\/strong>/) }) @@ -106,14 +106,14 @@ test("web guild: can view bridged guild", async t => { } } }) - t.match(html, /Psychonauts 3`) nonce = html.match(/data-nonce="([a-f0-9-]+)"/)?.[1] t.ok(nonce) }) test("web invite: page loads with valid nonce", async t => { const html = await router.test("get", `/invite?nonce=${nonce}`) - t.match(html, /Invite a Matrix user/) + t.has(html, "Invite a Matrix user") }) diff --git a/test/data.js b/test/data.js index c18f173..6bb732f 100644 --- a/test/data.js +++ b/test/data.js @@ -19,6 +19,24 @@ module.exports = { default_thread_rate_limit_per_user: 0, guild_id: "112760669178241024" }, + updates: { + type: 0, + topic: "Updates and release announcements for Out Of Your Element.", + rate_limit_per_user: 0, + position: 0, + permission_overwrites: [{ + type: 0, + id: "112760669178241024", + deny: "2048", + allow: "0" + }], + parent_id: null, + nsfw: false, + name: "updates", + last_message_id: "1329413270196715564", + id: "1161864271370666075", + guild_id: "112760669178241024" + }, saving_the_world: { type: 0, topic: "Anything and everything archiving/preservation related", @@ -55,6 +73,7 @@ module.exports = { url: {$url: "/icons/112760669178241024/a_f83622e09ead74f0c5c527fe241f8f8c.png?size=1024"} }, "m.room.power_levels/": { + events_default: 0, users: { "@test_auto_invite:example.org": 100 }, diff --git a/test/ooye-test-data.sql b/test/ooye-test-data.sql index ab6c73e..221eda0 100644 --- a/test/ooye-test-data.sql +++ b/test/ooye-test-data.sql @@ -19,7 +19,8 @@ INSERT INTO channel_room (channel_id, room_id, name, nick, thread_parent, custom ('122155380120748034', '!cqeGDbPiMFAhLsqqqq:cadence.moe', 'cadences-mind', 'coding', NULL, NULL), ('176333891320283136', '!qzDBLKlildpzrrOnFZ:cadence.moe', '🌈丨davids-horse_she-took-the-kids', 'wonderland', NULL, 'mxc://cadence.moe/EVvrSkKIRONHjtRJsMLmHWLS'), ('489237891895768942', '!tnedrGVYKFNUdnegvf:tchncs.de', 'ex-room-doesnt-exist-any-more', NULL, NULL, NULL), -('1160894080998461480', '!TqlyQmifxGUggEmdBN:cadence.moe', 'ooyexperiment', NULL, NULL, NULL); +('1160894080998461480', '!TqlyQmifxGUggEmdBN:cadence.moe', 'ooyexperiment', NULL, NULL, NULL), +('1161864271370666075', '!mHmhQQPwXNananMUqq:cadence.moe', 'updates', NULL, NULL, NULL); INSERT INTO sim (user_id, username, sim_name, mxid) VALUES ('0', 'Matrix Bridge', 'bot', '@_ooye_bot:cadence.moe'), diff --git a/test/test.js b/test/test.js index eabab9f..c4b1603 100644 --- a/test/test.js +++ b/test/test.js @@ -34,7 +34,7 @@ const discord = { [data.guild.data_horde.id, data.guild.data_horde] ]), guildChannelMap: new Map([ - [data.guild.general.id, [data.channel.general.id]], + [data.guild.general.id, [data.channel.general.id, data.channel.updates.id]], [data.guild.fna.id, []], [data.guild.data_horde.id, [data.channel.saving_the_world.id]] ]), @@ -43,6 +43,7 @@ const discord = { }, channels: new Map([ [data.channel.general.id, data.channel.general], + [data.channel.updates.id, data.channel.updates], ["497161350934560778", { guild_id: "497159726455455754" }],