diff --git a/config/default.yaml b/config/default.yaml index 6b94fc1..3a2e560 100644 --- a/config/default.yaml +++ b/config/default.yaml @@ -34,9 +34,9 @@ dataPath: "/data/storage" # If true (the default), Mjolnir will only accept invites from users present in managementRoom. autojoinOnlyIfManager: true -# If `autojoinOnlyIfManager` is false, only the members in this group can invite +# If `autojoinOnlyIfManager` is false, only the members in this space can invite # the bot to new rooms. -acceptInvitesFromGroup: "+example:example.org" +acceptInvitesFromSpace: "!example:example.org" # Whether Mjolnir should report ignored invites to the management room (if autojoinOnlyIfManager is true). recordIgnoredInvites: false diff --git a/config/harness.yaml b/config/harness.yaml index e3c3a9d..18b992f 100644 --- a/config/harness.yaml +++ b/config/harness.yaml @@ -32,9 +32,9 @@ dataPath: "./test/harness/mjolnir-data/" # to new rooms. autojoinOnlyIfManager: true -# If `autojoinOnlyIfManager` is false, only the members in this group can invite +# If `autojoinOnlyIfManager` is false, only the members in this space can invite # the bot to new rooms. -acceptInvitesFromGroup: '+example:example.org' +acceptInvitesFromSpace: '!example:example.org' # If the bot is invited to a room and it won't accept the invite (due to the # conditions above), report it to the management room. Defaults to disabled (no diff --git a/src/Mjolnir.ts b/src/Mjolnir.ts index 1d8ea88..ce6637c 100644 --- a/src/Mjolnir.ts +++ b/src/Mjolnir.ts @@ -123,7 +123,7 @@ export class Mjolnir { * @param {string} options.managementRoom The room to report ignored invitations to if `recordIgnoredInvites` is true. * @param {boolean} options.recordIgnoredInvites Whether to report invites that will be ignored to the `managementRoom`. * @param {boolean} options.autojoinOnlyIfManager Whether to only accept an invitation by a user present in the `managementRoom`. - * @param {string} options.acceptInvitesFromGroup A group of users to accept invites from, ignores invites form users not in this group. + * @param {string} options.acceptInvitesFromSpace A space of users to accept invites from, ignores invites form users not in this space. */ private static addJoinOnInviteListener(mjolnir: Mjolnir, client: MatrixClient, options: { [key: string]: any }) { client.on("room.invite", async (roomId: string, inviteEvent: any) => { @@ -147,9 +147,18 @@ export class Mjolnir { const managers = await client.getJoinedRoomMembers(mjolnir.managementRoomId); if (!managers.includes(membershipEvent.sender)) return reportInvite(); // ignore invite } else { - const groupMembers = await client.unstableApis.getGroupUsers(options.acceptInvitesFromGroup); - const userIds = groupMembers.map(m => m.user_id); - if (!userIds.includes(membershipEvent.sender)) return reportInvite(); // ignore invite + const spaceId = await client.resolveRoom(options.acceptInvitesFromSpace); + const spaceUserIds = await client.getJoinedRoomMembers(spaceId) + .catch(async e => { + if (e.body?.errcode === "M_FORBIDDEN") { + await mjolnir.logMessage(LogLevel.ERROR, 'Mjolnir', `Mjolnir is not in the space configured for acceptInvitesFromSpace, did you invite it?`); + await client.joinRoom(spaceId); + return await client.getJoinedRoomMembers(spaceId); + } else { + return Promise.reject(e); + } + }); + if (!spaceUserIds.includes(membershipEvent.sender)) return reportInvite(); // ignore invite } return client.joinRoom(roomId); diff --git a/src/config.ts b/src/config.ts index 7bbbc2c..3d6cd3b 100644 --- a/src/config.ts +++ b/src/config.ts @@ -36,7 +36,7 @@ export interface IConfig { password: string; }; dataPath: string; - acceptInvitesFromGroup: string; + acceptInvitesFromSpace: string; autojoinOnlyIfManager: boolean; recordIgnoredInvites: boolean; managementRoom: string; @@ -115,7 +115,7 @@ const defaultConfig: IConfig = { password: "", }, dataPath: "/data/storage", - acceptInvitesFromGroup: '+example:example.org', + acceptInvitesFromSpace: '!noop:example.org', autojoinOnlyIfManager: false, recordIgnoredInvites: false, managementRoom: "!noop:example.org", diff --git a/test/integration/acceptInvitesFromSpaceTest.ts b/test/integration/acceptInvitesFromSpaceTest.ts new file mode 100644 index 0000000..3f581a5 --- /dev/null +++ b/test/integration/acceptInvitesFromSpaceTest.ts @@ -0,0 +1,48 @@ +import { MatrixClient } from "matrix-bot-sdk"; +import { Mjolnir } from "../../src/Mjolnir" +import { newTestUser } from "./clientHelper"; + +describe("Test: Accept Invites From Space", function() { + let client: MatrixClient|undefined; + this.beforeEach(async function () { + client = await newTestUser(this.config.homeserverUrl, { name: { contains: "spacee" }}); + await client.start(); + }) + this.afterEach(async function () { + await client.stop(); + }) + it("Mjolnir should accept an invite from a user in a nominated Space", async function() { + this.timeout(20000); + + const mjolnir: Mjolnir = this.mjolnir!; + const mjolnirUserId = await mjolnir.client.getUserId(); + + const space = await client.createSpace({ + name: "mjolnir space invite test", + invites: [mjolnirUserId], + isPublic: false + }); + + await this.mjolnir.client.joinRoom(space.roomId); + + // we're mutating a static object, which may affect other tests :( + mjolnir.config.autojoinOnlyIfManager = false; + mjolnir.config.acceptInvitesFromSpace = space.roomId; + + const promise = new Promise(async resolve => { + const newRoomId = await client.createRoom({ invite: [mjolnirUserId] }); + client.on("room.event", (roomId, event) => { + if ( + roomId === newRoomId + && event.type === "m.room.member" + && event.sender === mjolnirUserId + && event.content?.membership === "join" + ) { + resolve(null); + } + }); + }); + await promise; + }); +}); +