Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

feat: using slack apps for slack-bridge #30630

Merged
merged 10 commits into from
Oct 25, 2023
6 changes: 6 additions & 0 deletions .changeset/late-pants-switch.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
---
'@rocket.chat/meteor': minor
'@rocket.chat/i18n': patch
---

Updated slack bridge to add support for connecting using slack apps in addition to the slack legacy bot
77 changes: 64 additions & 13 deletions apps/meteor/app/slackbridge/server/SlackAPI.js
Original file line number Diff line number Diff line change
@@ -1,15 +1,17 @@
import { serverFetch as fetch } from '@rocket.chat/server-fetch';

export class SlackAPI {
constructor(apiToken) {
this.apiToken = apiToken;
constructor(apiOrBotToken) {
this.token = apiOrBotToken;
}

async getChannels(cursor = null) {
let channels = [];
const request = await fetch('https://slack.com/api/conversations.list', {
headers: {
Authorization: `Bearer ${this.token}`,
},
params: {
token: this.apiToken,
types: 'public_channel',
exclude_archived: true,
limit: 1000,
Expand All @@ -32,8 +34,10 @@ export class SlackAPI {
async getGroups(cursor = null) {
let groups = [];
const request = await fetch('https://slack.com/api/conversations.list', {
headers: {
Authorization: `Bearer ${this.token}`,
},
params: {
token: this.apiToken,
types: 'private_channel',
exclude_archived: true,
limit: 1000,
Expand All @@ -55,8 +59,10 @@ export class SlackAPI {

async getRoomInfo(roomId) {
const request = await fetch(`https://slack.com/api/conversations.info`, {
headers: {
Authorization: `Bearer ${this.token}`,
},
params: {
token: this.apiToken,
channel: roomId,
include_num_members: true,
},
Expand All @@ -73,8 +79,10 @@ export class SlackAPI {
for (let index = 0; index < num_members; index += MAX_MEMBERS_PER_CALL) {
// eslint-disable-next-line no-await-in-loop
const request = await fetch('https://slack.com/api/conversations.members', {
headers: {
Authorization: `Bearer ${this.token}`,
},
params: {
token: this.apiToken,
channel: channelId,
limit: MAX_MEMBERS_PER_CALL,
...(currentCursor && { cursor: currentCursor }),
Expand All @@ -95,6 +103,9 @@ export class SlackAPI {

async react(data) {
const request = await fetch('https://slack.com/api/reactions.add', {
headers: {
Authorization: `Bearer ${this.token}`,
},
method: 'POST',
params: data,
});
Expand All @@ -104,6 +115,9 @@ export class SlackAPI {

async removeReaction(data) {
const request = await fetch('https://slack.com/api/reactions.remove', {
headers: {
Authorization: `Bearer ${this.token}`,
},
method: 'POST',
params: data,
});
Expand All @@ -113,6 +127,9 @@ export class SlackAPI {

async removeMessage(data) {
const request = await fetch('https://slack.com/api/chat.delete', {
headers: {
Authorization: `Bearer ${this.token}`,
},
method: 'POST',
params: data,
});
Expand All @@ -122,6 +139,9 @@ export class SlackAPI {

async sendMessage(data) {
const request = await fetch('https://slack.com/api/chat.postMessage', {
headers: {
Authorization: `Bearer ${this.token}`,
},
method: 'POST',
params: data,
});
Expand All @@ -130,28 +150,33 @@ export class SlackAPI {

async updateMessage(data) {
const request = await fetch('https://slack.com/api/chat.update', {
headers: {
Authorization: `Bearer ${this.token}`,
},
method: 'POST',
params: data,
});
const response = await request.json();
return response && request.status === 200 && response && request.ok;
}

async getHistory(family, options) {
const request = await fetch(`https://slack.com/api/${family}.history`, {
params: {
token: this.apiToken,
...options,
async getHistory(options) {
const request = await fetch(`https://slack.com/api/conversations.history`, {
headers: {
Authorization: `Bearer ${this.token}`,
},
params: options,
});
const response = await request.json();
return response;
}

async getPins(channelId) {
const request = await fetch('https://slack.com/api/pins.list', {
headers: {
Authorization: `Bearer ${this.token}`,
},
params: {
token: this.apiToken,
channel: channelId,
},
});
Expand All @@ -161,12 +186,38 @@ export class SlackAPI {

async getUser(userId) {
const request = await fetch('https://slack.com/api/users.info', {
headers: {
Authorization: `Bearer ${this.token}`,
},
params: {
token: this.apiToken,
user: userId,
},
});
const response = await request.json();
return response && response && request.status === 200 && request.ok && response.user;
}

static async verifyToken(token) {
const request = await fetch('https://slack.com/api/auth.test', {
headers: {
Authorization: `Bearer ${token}`,
},
method: 'POST',
});
const response = await request.json();
return response && response && request.status === 200 && request.ok && response.ok;
}

static async verifyAppCredentials({ botToken, appToken }) {
const request = await fetch('https://slack.com/api/apps.connections.open', {
headers: {
Authorization: `Bearer ${appToken}`,
},
method: 'POST',
});
const response = await request.json();
const isAppTokenOk = response && response && request.status === 200 && request.ok && response.ok;
const isBotTokenOk = await this.verifyToken(botToken);
return isAppTokenOk && isBotTokenOk;
}
}