From cb8000f3378263f772a8426c5e4f84e27beb06e2 Mon Sep 17 00:00:00 2001 From: Half-Shot Date: Thu, 7 May 2020 12:35:14 +0100 Subject: [PATCH 1/5] Add config option --- config/config.sample.yaml | 2 ++ config/slack-config-schema.yaml | 2 ++ src/IConfig.ts | 1 + 3 files changed, 5 insertions(+) diff --git a/config/config.sample.yaml b/config/config.sample.yaml index a4ea8716..27223c59 100644 --- a/config/config.sample.yaml +++ b/config/config.sample.yaml @@ -104,6 +104,8 @@ provisioning: enabled: true # Should the bridge deny users bridging channels to private rooms. require_public_room: true + # Should the bridge allow usesr to bridge private channels. + allow_private_channels: true limits: room_count: 20 team_count: 1 diff --git a/config/slack-config-schema.yaml b/config/slack-config-schema.yaml index c19b5c21..5f464ed4 100644 --- a/config/slack-config-schema.yaml +++ b/config/slack-config-schema.yaml @@ -112,6 +112,8 @@ properties: type: boolean require_public_room: type: boolean + allow_private_channels: + type: boolean limits: type: object properties: diff --git a/src/IConfig.ts b/src/IConfig.ts index b7faea2c..ab889cd7 100644 --- a/src/IConfig.ts +++ b/src/IConfig.ts @@ -83,6 +83,7 @@ export interface IConfig { provisioning?: { enable: boolean; require_public_room?: boolean; + allow_private_channels?: boolean; limits?: { team_count?: number; room_count?: number; From b80146898ae6b6ae536609f3c48cfcca93956f2e Mon Sep 17 00:00:00 2001 From: Half-Shot Date: Thu, 7 May 2020 12:35:21 +0100 Subject: [PATCH 2/5] List channels by userId --- src/Provisioning.ts | 34 ++++++++++++++++++++++++---------- 1 file changed, 24 insertions(+), 10 deletions(-) diff --git a/src/Provisioning.ts b/src/Provisioning.ts index 40aba67d..3501337f 100644 --- a/src/Provisioning.ts +++ b/src/Provisioning.ts @@ -87,6 +87,20 @@ export class Provisioner { return (currentCount >= this.main.config.provisioning?.limits?.room_count); } + private async determineSlackIdForRequest(matrixUserId, teamId) { + const matrixUser = await this.main.datastore.getMatrixUser(matrixUserId); + if (matrixUser === null) { + throw Error('No users found'); + } + const accounts: {[userId: string]: {team_id: string}} = matrixUser.get("accounts"); + for (const [key, value] of Object.entries(accounts)) { + if (value.team_id === teamId) { + return key; + } + } + return null; + } + @command() private async getconfig(_, res) { const hasRoomLimit = this.main.config.provisioning?.limits?.room_count; @@ -150,14 +164,9 @@ export class Provisioner { @command("user_id", "team_id") private async channels(req, res, userId, teamId) { log.debug(`${userId} for ${teamId} requested their channels`); - const matrixUser = await this.main.datastore.getMatrixUser(userId); - const isAllowed = matrixUser !== null && - Object.values(matrixUser.get("accounts") as {[key: string]: {team_id: string}}).find((acct) => - acct.team_id === teamId, - ); - if (!isAllowed) { - res.status(HTTP_CODES.CLIENT_ERROR).json({error: "User is not part of this team!"}); - throw undefined; + const slackUserId = await this.determineSlackIdForRequest(userId, teamId); + if (!slackUserId) { + return res.status(HTTP_CODES.CLIENT_ERROR).json({error: "User is not part of this team!"}); } const team = await this.main.datastore.getTeam(teamId); if (team === null) { @@ -165,10 +174,15 @@ export class Provisioner { } const cli = await this.main.clientFactory.getTeamClient(teamId); try { - const response = (await cli.conversations.list({ + let types = "public_channel"; + if (this.main.config.provisioning?.allow_private_channels !== false) { + types = `public_channel,private_channel`; + } + const response = (await cli.users.list({ exclude_archived: true, limit: 1000, // TODO: Pagination - types: "public_channel", // TODO: In order to show private channels, we need the identity of the caller. + user: slackUserId, // In order to show private channels, we need the identity of the caller. + types, })) as ConversationsListResponse; if (!response.ok) { throw Error(response.error); From d1ab2fef75fecef05548d60317a4b6ba35377bf8 Mon Sep 17 00:00:00 2001 From: Half-Shot Date: Thu, 7 May 2020 12:39:33 +0100 Subject: [PATCH 3/5] changelog --- changelog.d/403.bugfix | 1 + 1 file changed, 1 insertion(+) create mode 100644 changelog.d/403.bugfix diff --git a/changelog.d/403.bugfix b/changelog.d/403.bugfix new file mode 100644 index 00000000..87d38701 --- /dev/null +++ b/changelog.d/403.bugfix @@ -0,0 +1 @@ +Allow bridging to private channels via the provisioner \ No newline at end of file From ae75e4b3525186bb0e453ca46eb0354afbcd31fc Mon Sep 17 00:00:00 2001 From: Half-Shot Date: Mon, 11 May 2020 13:37:32 +0100 Subject: [PATCH 4/5] Fix getMatrixUser types --- src/datastore/postgres/PgDatastore.ts | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/datastore/postgres/PgDatastore.ts b/src/datastore/postgres/PgDatastore.ts index f4a8a5d2..7f8fd5b8 100644 --- a/src/datastore/postgres/PgDatastore.ts +++ b/src/datastore/postgres/PgDatastore.ts @@ -47,7 +47,7 @@ export class PgDatastore implements Datastore { }); } - public async getUser(id: string): Promise { + public async getUser(id: string): Promise { const dbEntry = await this.postgresDb.oneOrNone("SELECT * FROM users WHERE userId = ${id}", { id }); if (!dbEntry) { return null; @@ -55,7 +55,7 @@ export class PgDatastore implements Datastore { return JSON.parse(dbEntry.json); } - public async getMatrixUser(userId: string): Promise { + public async getMatrixUser(userId: string): Promise { userId = new MatrixUser(userId).getId(); // Ensure ID correctness const userData = await this.getUser(userId); return userData !== null ? new MatrixUser(userId, userData) : null; From 6b0b37a81c30687b01e5fb12b06543283f58a82c Mon Sep 17 00:00:00 2001 From: Half-Shot Date: Mon, 11 May 2020 13:37:43 +0100 Subject: [PATCH 5/5] Twiddle --- src/Provisioning.ts | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/src/Provisioning.ts b/src/Provisioning.ts index 3501337f..f0da1196 100644 --- a/src/Provisioning.ts +++ b/src/Provisioning.ts @@ -89,8 +89,9 @@ export class Provisioner { private async determineSlackIdForRequest(matrixUserId, teamId) { const matrixUser = await this.main.datastore.getMatrixUser(matrixUserId); - if (matrixUser === null) { - throw Error('No users found'); + if (!matrixUser) { + // No Slack user entry found for MXID + return null; } const accounts: {[userId: string]: {team_id: string}} = matrixUser.get("accounts"); for (const [key, value] of Object.entries(accounts)) { @@ -175,6 +176,7 @@ export class Provisioner { const cli = await this.main.clientFactory.getTeamClient(teamId); try { let types = "public_channel"; + // Unless we *explicity* set this to false, allow it. if (this.main.config.provisioning?.allow_private_channels !== false) { types = `public_channel,private_channel`; }