From 4bc7e794ab936b38ecc1631f883fba9de0433d70 Mon Sep 17 00:00:00 2001 From: Cadence Ember Date: Tue, 16 Dec 2025 00:36:11 +1300 Subject: [PATCH] Refactor private chat creation --- src/matrix/api.js | 33 +++++++++++- src/web/routes/log-in-with-matrix.js | 25 +-------- src/web/routes/log-in-with-matrix.test.js | 64 ++--------------------- 3 files changed, 36 insertions(+), 86 deletions(-) diff --git a/src/matrix/api.js b/src/matrix/api.js index ddaf9b5..d2a0e9d 100644 --- a/src/matrix/api.js +++ b/src/matrix/api.js @@ -5,7 +5,7 @@ const assert = require("assert").strict const streamWeb = require("stream/web") const passthrough = require("../passthrough") -const {sync} = passthrough +const {sync, db, select} = passthrough /** @type {import("./mreq")} */ const mreq = sync.require("./mreq") /** @type {import("./txnid")} */ @@ -513,6 +513,36 @@ function versions() { return mreq.mreq("GET", "/client/versions") } +/** + * @param {string} mxid + */ +async function usePrivateChat(mxid) { + // Check if we have an existing DM + let roomID = select("direct", "room_id", {mxid}).pluck().get() + if (roomID) { + // Check that the person is/still in the room + try { + var member = await getStateEvent(roomID, "m.room.member", mxid) + } catch (e) {} + + // Invite them back to the room if needed + if (!member || member.membership === "leave") { + await inviteToRoom(roomID, mxid) + } + return roomID + } + + // No existing DM, create a new room and invite + roomID = await createRoom({ + invite: [mxid], + is_direct: true, + preset: "trusted_private_chat" + }) + // Store the newly created room in the database (not using account data due to awkward bugs with misaligned state) + db.prepare("REPLACE INTO direct (mxid, room_id) VALUES (?, ?)").run(mxid, roomID) + return roomID +} + module.exports.path = path module.exports.register = register module.exports.createRoom = createRoom @@ -550,3 +580,4 @@ module.exports.setAccountData = setAccountData module.exports.setPresence = setPresence module.exports.getProfile = getProfile module.exports.versions = versions +module.exports.usePrivateChat = usePrivateChat diff --git a/src/web/routes/log-in-with-matrix.js b/src/web/routes/log-in-with-matrix.js index 574c312..d36d8fa 100644 --- a/src/web/routes/log-in-with-matrix.js +++ b/src/web/routes/log-in-with-matrix.js @@ -79,30 +79,7 @@ as.router.post("/api/log-in-with-matrix", defineEventHandler(async event => { } } - // Check if we have an existing DM - let roomID = select("direct", "room_id", {mxid}).pluck().get() - if (roomID) { - // Check that the person is/still in the room - try { - var member = await api.getStateEvent(roomID, "m.room.member", mxid) - } catch (e) {} - - // Invite them back to the room if needed - if (!member || member.membership === "leave") { - await api.inviteToRoom(roomID, mxid) - } - } - - // No existing DM, create a new room and invite - else { - roomID = await api.createRoom({ - invite: [mxid], - is_direct: true, - preset: "trusted_private_chat" - }) - // Store the newly created room in account data (Matrix doesn't do this for us automatically, sigh...) - db.prepare("REPLACE INTO direct (mxid, room_id) VALUES (?, ?)").run(mxid, roomID) - } + const roomID = await api.usePrivateChat(mxid) const token = randomUUID() diff --git a/src/web/routes/log-in-with-matrix.test.js b/src/web/routes/log-in-with-matrix.test.js index bc9c7e0..a403055 100644 --- a/src/web/routes/log-in-with-matrix.test.js +++ b/src/web/routes/log-in-with-matrix.test.js @@ -34,7 +34,7 @@ test("log in with matrix: checks if mxid domain format looks valid", async t => t.match(error.data.fieldErrors.mxid, /must match pattern/) }) -test("log in with matrix: sends message when there is no existing dm room", async t => { +test("log in with matrix: sends message to log in", async t => { const event = {} let called = 0 await router.test("post", "/api/log-in-with-matrix", { @@ -42,8 +42,9 @@ test("log in with matrix: sends message when there is no existing dm room", asyn mxid: "@cadence:cadence.moe" }, api: { - async createRoom() { + async usePrivateChat(mxid) { called++ + t.equal(mxid, "@cadence:cadence.moe") return "!created:cadence.moe" }, async sendEvent(roomID, type, content) { @@ -72,65 +73,6 @@ test("log in with matrix: does not send another message when a log in is in prog t.match(event.node.res.getHeader("location"), /We already sent you a link on Matrix/) }) -test("log in with matrix: reuses room from direct", async t => { - const event = {} - let called = 0 - await router.test("post", "/api/log-in-with-matrix", { - body: { - mxid: "@user1:example.org" - }, - api: { - async getStateEvent(roomID, type, key) { - called++ - t.equal(roomID, "!existing:cadence.moe") - t.equal(type, "m.room.member") - t.equal(key, "@user1:example.org") - return {membership: "join"} - }, - async sendEvent(roomID) { - called++ - t.equal(roomID, "!existing:cadence.moe") - return "" - } - }, - event - }) - t.match(event.node.res.getHeader("location"), /Please check your inbox on Matrix/) - t.equal(called, 2) -}) - -test("log in with matrix: reuses room from direct, reinviting if user has left", async t => { - const event = {} - let called = 0 - await router.test("post", "/api/log-in-with-matrix", { - body: { - mxid: "@user2:example.org" - }, - api: { - async getStateEvent(roomID, type, key) { - called++ - t.equal(roomID, "!existing:cadence.moe") - t.equal(type, "m.room.member") - t.equal(key, "@user2:example.org") - throw new MatrixServerError({errcode: "M_NOT_FOUND"}) - }, - async inviteToRoom(roomID, mxid) { - called++ - t.equal(roomID, "!existing:cadence.moe") - t.equal(mxid, "@user2:example.org") - }, - async sendEvent(roomID) { - called++ - t.equal(roomID, "!existing:cadence.moe") - return "" - } - }, - event - }) - t.match(event.node.res.getHeader("location"), /Please check your inbox on Matrix/) - t.equal(called, 3) -}) - // ***** third request *****