From bb65901e25cb734e9c41a445d48129a1b96bde8c Mon Sep 17 00:00:00 2001 From: Abhinav Kumar Date: Thu, 26 Oct 2023 01:17:41 +0530 Subject: [PATCH] feat: using slack apps for slack-bridge (#30630) Co-authored-by: Pierre Lehnen <55164754+pierre-lehnen-rc@users.noreply.github.com> --- .changeset/late-pants-switch.md | 6 + .../meteor/app/slackbridge/server/SlackAPI.js | 77 ++- .../app/slackbridge/server/SlackAdapter.js | 236 ++++++- .../app/slackbridge/server/slackbridge.js | 136 ++++- apps/meteor/package.json | 1 + .../rocketchat-i18n/i18n/en.i18n.json | 9 +- apps/meteor/server/settings/slackbridge.ts | 78 ++- yarn.lock | 578 +++++++++++++++++- 8 files changed, 1041 insertions(+), 80 deletions(-) create mode 100644 .changeset/late-pants-switch.md diff --git a/.changeset/late-pants-switch.md b/.changeset/late-pants-switch.md new file mode 100644 index 0000000000000..d376ee7b87f82 --- /dev/null +++ b/.changeset/late-pants-switch.md @@ -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 diff --git a/apps/meteor/app/slackbridge/server/SlackAPI.js b/apps/meteor/app/slackbridge/server/SlackAPI.js index 63774024dc7ea..540aa3b911605 100644 --- a/apps/meteor/app/slackbridge/server/SlackAPI.js +++ b/apps/meteor/app/slackbridge/server/SlackAPI.js @@ -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, @@ -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, @@ -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, }, @@ -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 }), @@ -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, }); @@ -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, }); @@ -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, }); @@ -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, }); @@ -130,6 +150,9 @@ 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, }); @@ -137,12 +160,12 @@ export class SlackAPI { 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; @@ -150,8 +173,10 @@ export class SlackAPI { async getPins(channelId) { const request = await fetch('https://slack.com/api/pins.list', { + headers: { + Authorization: `Bearer ${this.token}`, + }, params: { - token: this.apiToken, channel: channelId, }, }); @@ -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; + } } diff --git a/apps/meteor/app/slackbridge/server/SlackAdapter.js b/apps/meteor/app/slackbridge/server/SlackAdapter.js index d5379c0825076..0fb4ee8a71254 100644 --- a/apps/meteor/app/slackbridge/server/SlackAdapter.js +++ b/apps/meteor/app/slackbridge/server/SlackAdapter.js @@ -4,6 +4,7 @@ import url from 'url'; import { Message } from '@rocket.chat/core-services'; import { Messages, Rooms, Users, ReadReceipts } from '@rocket.chat/models'; +import { App as SlackApp } from '@slack/bolt'; import { RTMClient } from '@slack/rtm-api'; import { Meteor } from 'meteor/meteor'; @@ -28,6 +29,8 @@ export default class SlackAdapter { this.slackBridge = slackBridge; this.rtm = {}; // slack-client Real Time Messaging API this.apiToken = {}; // Slack API Token passed in via Connect + this.slackApp = {}; + this.appCredential = {}; // On Slack, a rocket integration bot will be added to slack channels, this is the list of those channels, key is Rocket Ch ID this.slackChannelRocketBotMembershipMap = new Map(); // Key=RocketChannelID, Value=SlackChannel this.rocket = {}; @@ -37,48 +40,96 @@ export default class SlackAdapter { this.slackAPI = {}; } + async connect({ apiToken, appCredential }) { + try { + const connectResult = await (appCredential ? this.connectApp(appCredential) : this.connectLegacy(apiToken)); + + if (connectResult) { + slackLogger.info('Connected to Slack'); + slackLogger.debug('Slack connection result: ', connectResult); + Meteor.startup(async () => { + try { + await this.populateMembershipChannelMap(); // If run outside of Meteor.startup, HTTP is not defined + } catch (err) { + slackLogger.error({ msg: 'Error attempting to connect to Slack', err }); + if (err.data.error === 'invalid_auth') { + slackLogger.error('The provided token is invalid'); + } + this.slackBridge.disconnect(); + } + }); + } + } catch (err) { + slackLogger.error({ msg: 'Error attempting to connect to Slack', err }); + this.slackBridge.disconnect(); + } + } + + /** + * Connect to the remote Slack server using the passed in app credential and register for Slack events. + * @typedef {Object} AppCredential + * @property {string} botToken + * @property {string} appToken + * @property {string} signingSecret + * @param {AppCredential} appCredential + */ + async connectApp(appCredential) { + this.appCredential = appCredential; + + // Invalid app credentials causes unhandled errors + if (!(await SlackAPI.verifyAppCredentials(appCredential))) { + throw new Error('Invalid app credentials (botToken or appToken) for the slack app'); + } + this.slackAPI = new SlackAPI(this.appCredential.botToken); + + this.slackApp = new SlackApp({ + appToken: this.appCredential.appToken, + signingSecret: this.appCredential.signingSecret, + token: this.appCredential.botToken, + socketMode: true, + }); + + this.registerForEvents(); + + const connectionResult = await this.slackApp.start(); + + return connectionResult; + } + /** - * Connect to the remote Slack server using the passed in token API and register for Slack events + * Connect to the remote Slack server using the passed in token API and register for Slack events. * @param apiToken + * @deprecated */ - async connect(apiToken) { + async connectLegacy(apiToken) { this.apiToken = apiToken; + // Invalid apiToken causes unhandled errors + if (!(await SlackAPI.verifyToken(apiToken))) { + throw new Error('Invalid ApiToken for the slack legacy bot integration'); + } + if (RTMClient != null) { RTMClient.disconnect; } this.slackAPI = new SlackAPI(this.apiToken); this.rtm = new RTMClient(this.apiToken); - await this.rtm - .start() - .then((res) => slackLogger.debug('Connecting to slack', res)) - .catch((err) => { - slackLogger.error({ msg: 'Error attempting to connect to Slack', err }); - if (err.data.error === 'invalid_auth') { - throw new Error('The provided token is invalid'); - } - throw new Error(err); - }); + this.registerForEventsLegacy(); - this.registerForEvents(); + const connectionResult = await this.rtm.start(); - Meteor.startup(async () => { - try { - await this.populateMembershipChannelMap(); // If run outside of Meteor.startup, HTTP is not defined - } catch (err) { - slackLogger.error({ msg: 'Error attempting to connect to Slack', err }); - this.slackBridge.disconnect(); - } - }); + return connectionResult; } /** * Unregister for slack events and disconnect from Slack */ - disconnect() { + async disconnect() { if (this.rtm.connected && this.rtm.disconnect) { - this.rtm.disconnect(); + await this.rtm.disconnect(); + } else if (this.slackApp.stop) { + await this.slackApp.stop(); } } @@ -87,6 +138,119 @@ export default class SlackAdapter { } registerForEvents() { + /** + * message: { + * "client_msg_id": "caab144d-41e7-47cc-87fa-af5d50c02784", + * "type": "message", + * "text": "heyyyyy", + * "user": "U060WD4QW81", + * "ts": "1697054782.214569", + * "blocks": [], + * "team": "T060383CUDV", + * "channel": "C060HSLQPCN", + * "event_ts": "1697054782.214569", + * "channel_type": "channel" + * } + */ + this.slackApp.message(async ({ message }) => { + slackLogger.debug('OnSlackEvent-MESSAGE: ', message); + if (message) { + try { + await this.onMessage(message); + } catch (err) { + slackLogger.error({ msg: 'Unhandled error onMessage', err }); + } + } + }); + + /** + * Event fired when a message is reacted in a channel or group app is added in + * event: { + * "type": "reaction_added", + * "user": "U060WD4QW81", + * "reaction": "telephone_receiver", + * "item": { + * "type": "message", + * "channel": "C06196XMUMN", + * "ts": "1697037020.309679" + * }, + * "item_user": "U060WD4QW81", + * "event_ts": "1697037219.001600" + * } + */ + this.slackApp.event('reaction_added', async ({ event }) => { + slackLogger.debug('OnSlackEvent-REACTION_ADDED: ', event); + try { + slackLogger.error({ event }); + await this.onReactionAdded(event); + } catch (err) { + slackLogger.error({ msg: 'Unhandled error onReactionAdded', err }); + } + }); + + /** + * Event fired when a reaction is removed from a message in a channel or group app is added in. + * event: { + * "type": "reaction_removed", + * "user": "U060WD4QW81", + * "reaction": "raised_hands", + * "item": { + * "type": "message", + * "channel": "C06196XMUMN", + * "ts": "1697028997.057629" + * }, + * "item_user": "U060WD4QW81", + * "event_ts": "1697029220.000600" + * } + */ + this.slackApp.event('reaction_removed', async ({ event }) => { + slackLogger.debug('OnSlackEvent-REACTION_REMOVED: ', event); + try { + await this.onReactionRemoved(event); + } catch (err) { + slackLogger.error({ msg: 'Unhandled error onReactionRemoved', err }); + } + }); + + /** + * Event fired when a members joins a channel + * event: { + * "type": "member_joined_channel", + * "user": "U06039U8WK1", + * "channel": "C060HT033E2", + * "channel_type": "C", + * "team": "T060383CUDV", + * "inviter": "U060WD4QW81", + * "event_ts": "1697042377.000800" + * } + */ + this.slackApp.event('member_joined_channel', async ({ event, context }) => { + slackLogger.debug('OnSlackEvent-CHANNEL_LEFT: ', event); + try { + await this.processMemberJoinChannel(event, context); + } catch (err) { + slackLogger.error({ msg: 'Unhandled error onChannelLeft', err }); + } + }); + + this.slackApp.event('channel_left', async ({ event }) => { + slackLogger.debug('OnSlackEvent-CHANNEL_LEFT: ', event); + try { + this.onChannelLeft(event); + } catch (err) { + slackLogger.error({ msg: 'Unhandled error onChannelLeft', err }); + } + }); + + this.slackApp.error((error) => { + slackLogger.error({ msg: 'Error on SlackApp', error }); + }); + } + + /** + * @deprecated + */ + registerForEventsLegacy() { slackLogger.debug('Register for events'); this.rtm.on('authenticated', () => { slackLogger.info('Connected to Slack'); @@ -586,7 +750,6 @@ export default class SlackAdapter { async postReactionAdded(reaction, slackChannel, slackTS) { if (reaction && slackChannel && slackTS) { const data = { - token: this.apiToken, name: reaction, channel: slackChannel, timestamp: slackTS, @@ -606,7 +769,6 @@ export default class SlackAdapter { async postReactionRemove(reaction, slackChannel, slackTS) { if (reaction && slackChannel && slackTS) { const data = { - token: this.apiToken, name: reaction, channel: slackChannel, timestamp: slackTS, @@ -626,7 +788,6 @@ export default class SlackAdapter { if (slackChannel != null) { const data = { - token: this.apiToken, ts: this.getTimeStamp(rocketMessage), channel: this.getSlackChannel(rocketMessage.rid).id, as_user: true, @@ -681,7 +842,6 @@ export default class SlackAdapter { iconUrl = Meteor.absoluteUrl().replace(/\/$/, '') + iconUrl; } const data = { - token: this.apiToken, text: rocketMessage.msg, channel: slackChannel.id, username: rocketMessage.u && rocketMessage.u.username, @@ -722,7 +882,6 @@ export default class SlackAdapter { async postMessageUpdate(slackChannel, rocketMessage) { if (slackChannel && slackChannel.id) { const data = { - token: this.apiToken, ts: this.getTimeStamp(rocketMessage), channel: slackChannel.id, text: rocketMessage.msg, @@ -736,6 +895,18 @@ export default class SlackAdapter { } } + async processMemberJoinChannel(event, context) { + slackLogger.debug('Member join channel', event.channel); + const rocketCh = await this.rocket.getChannel({ channel: event.channel }); + if (rocketCh != null) { + this.addSlackChannel(rocketCh._id, event.channel); + if (context?.botUserId !== event?.user) { + const rocketChatUser = await this.rocket.getUser(event.user); + await addUserToRoom(rocketCh._id, rocketChatUser); + } + } + } + async processChannelJoin(slackMessage) { slackLogger.debug('Channel join', slackMessage.channel.id); const rocketCh = await this.rocket.addChannel(slackMessage.channel); @@ -1142,9 +1313,9 @@ export default class SlackAdapter { }); } - async importFromHistory(family, options) { + async importFromHistory(options) { slackLogger.debug('Importing messages history'); - const data = await this.slackAPI.getHistory(family, options); + const data = await this.slackAPI.getHistory(options); if (Array.isArray(data.messages) && data.messages.length) { let latest = 0; for await (const message of data.messages.reverse()) { @@ -1245,13 +1416,14 @@ export default class SlackAdapter { await this.copyChannelInfo(rid, this.getSlackChannel(rid)); slackLogger.debug('Importing messages from Slack to Rocket.Chat', this.getSlackChannel(rid), rid); - let results = await this.importFromHistory(this.getSlackChannel(rid).family, { + + let results = await this.importFromHistory({ channel: this.getSlackChannel(rid).id, oldest: 1, }); while (results && results.has_more) { // eslint-disable-next-line no-await-in-loop - results = await this.importFromHistory(this.getSlackChannel(rid).family, { + results = await this.importFromHistory({ channel: this.getSlackChannel(rid).id, oldest: results.ts, }); diff --git a/apps/meteor/app/slackbridge/server/slackbridge.js b/apps/meteor/app/slackbridge/server/slackbridge.js index 3198b750145fd..b5983e7fff584 100644 --- a/apps/meteor/app/slackbridge/server/slackbridge.js +++ b/apps/meteor/app/slackbridge/server/slackbridge.js @@ -1,3 +1,5 @@ +import { debounce } from 'lodash'; + import { settings } from '../../settings/server'; import RocketAdapter from './RocketAdapter.js'; import SlackAdapter from './SlackAdapter.js'; @@ -8,6 +10,8 @@ import { classLogger, connLogger } from './logger'; */ class SlackBridgeClass { constructor() { + this.isEnabled = false; + this.isLegacyRTM = true; this.slackAdapters = []; this.rocket = new RocketAdapter(this); this.reactionsMap = new Map(); // Sync object between rocket and slack @@ -17,6 +21,9 @@ class SlackBridgeClass { // Settings that we cache versus looking up at runtime this.apiTokens = false; + this.botTokens = false; + this.appTokens = false; + this.signingSecrets = false; this.aliasFormat = ''; this.excludeBotnames = ''; this.isReactionsEnabled = true; @@ -29,16 +36,43 @@ class SlackBridgeClass { this.slackAdapters = []; this.rocket.clearSlackAdapters(); - const tokenList = this.apiTokens.split('\n'); + if (this.isLegacyRTM) { + const tokenList = this.apiTokens.split('\n'); + + tokenList.forEach((apiToken) => { + const slack = new SlackAdapter(this); + slack.setRocket(this.rocket); + this.rocket.addSlack(slack); + this.slackAdapters.push(slack); - tokenList.forEach((apiToken) => { - const slack = new SlackAdapter(this); - slack.setRocket(this.rocket); - this.rocket.addSlack(slack); - this.slackAdapters.push(slack); + slack.connect({ apiToken }).catch((err) => connLogger.error('error connecting to slack', err)); + }); + } else { + const botTokenList = this.botTokens.split('\n'); // Bot token list + const appTokenList = this.appTokens.split('\n'); // App token list + const signingSecretList = this.signingSecrets.split('\n'); // Signing secret list + + // Check if the number of tokens are the same + if (botTokenList.length !== appTokenList.length || botTokenList.length !== signingSecretList.length) { + connLogger.error('error connecting to slack: number of tokens are not the same'); + return; + } - slack.connect(apiToken).catch((err) => connLogger.error('error connecting to slack', err)); - }); + const appCredentials = botTokenList.map((botToken, i) => ({ + botToken, + appToken: appTokenList[i], + signingSecret: signingSecretList[i], + })); + + appCredentials.forEach((appCredential) => { + const slack = new SlackAdapter(this); + slack.setRocket(this.rocket); + this.rocket.addSlack(slack); + this.slackAdapters.push(slack); + + slack.connect({ appCredential }).catch((err) => connLogger.error('error connecting to slack', err)); + }); + } if (settings.get('SlackBridge_Out_Enabled')) { this.rocket.connect(); @@ -49,27 +83,76 @@ class SlackBridgeClass { } } - disconnect() { - if (this.connected === true) { - this.rocket.disconnect(); - this.slackAdapters.forEach((slack) => { - slack.disconnect(); - }); - this.slackAdapters = []; - this.connected = false; - connLogger.info('Disabled'); + async reconnect() { + await this.disconnect(); + // connect if either apiTokens or appCredentials are set + if (this.isLegacyRTM && this.apiTokens) { + this.connect(); + } else if (!this.isLegacyRTM && this.botTokens && this.appTokens && this.signingSecrets) { + this.connect(); + } + } + + debouncedReconnectIfEnabled = debounce(() => { + if (this.isEnabled) { + this.reconnect(); + } + }, 500); + + async disconnect() { + try { + if (this.connected === true) { + await this.rocket.disconnect(); + await Promise.all(this.slackAdapters.map((slack) => slack.disconnect())); + this.slackAdapters = []; + this.connected = false; + connLogger.info('Slack Bridge Disconnected'); + } + } catch (error) { + connLogger.error('An error occurred during disconnection', error); } } processSettings() { + // Check if legacy realtime api is enabled + settings.watch('SlackBridge_UseLegacy', (value) => { + if (value !== this.isLegacyRTM) { + this.isLegacyRTM = value; + this.debouncedReconnectIfEnabled(); + } + classLogger.debug('Setting: SlackBridge_UseLegacy', value); + }); + + // Slack installtion Bot token + settings.watch('SlackBridge_BotToken', (value) => { + if (value !== this.botTokens) { + this.botTokens = value; + this.debouncedReconnectIfEnabled(); + } + classLogger.debug('Setting: SlackBridge_BotToken', value); + }); + // Slack installtion App token + settings.watch('SlackBridge_AppToken', (value) => { + if (value !== this.appTokens) { + this.appTokens = value; + this.debouncedReconnectIfEnabled(); + } + classLogger.debug('Setting: SlackBridge_AppToken', value); + }); + // Slack installtion Signing token + settings.watch('SlackBridge_SigningSecret', (value) => { + if (value !== this.signingSecrets) { + this.signingSecrets = value; + this.debouncedReconnectIfEnabled(); + } + classLogger.debug('Setting: SlackBridge_SigningSecret', value); + }); + // Slack installation API token settings.watch('SlackBridge_APIToken', (value) => { if (value !== this.apiTokens) { this.apiTokens = value; - if (this.connected) { - this.disconnect(); - this.connect(); - } + this.debouncedReconnectIfEnabled(); } classLogger.debug('Setting: SlackBridge_APIToken', value); @@ -95,10 +178,13 @@ class SlackBridgeClass { // Is this entire SlackBridge enabled settings.watch('SlackBridge_Enabled', (value) => { - if (value && this.apiTokens) { - this.connect(); - } else { - this.disconnect(); + if (this.isEnabled !== value) { + this.isEnabled = value; + if (this.isEnabled) { + this.debouncedReconnectIfEnabled(); + } else { + this.disconnect(); + } } classLogger.debug('Setting: SlackBridge_Enabled', value); }); diff --git a/apps/meteor/package.json b/apps/meteor/package.json index b137af6adaa75..51f5adc3eec0d 100644 --- a/apps/meteor/package.json +++ b/apps/meteor/package.json @@ -278,6 +278,7 @@ "@rocket.chat/ui-theming": "workspace:^", "@rocket.chat/ui-video-conf": "workspace:^", "@rocket.chat/web-ui-registration": "workspace:^", + "@slack/bolt": "^3.14.0", "@slack/rtm-api": "^6.0.0", "@tanstack/react-query": "^4.16.1", "@types/cookie": "^0.5.1", diff --git a/apps/meteor/packages/rocketchat-i18n/i18n/en.i18n.json b/apps/meteor/packages/rocketchat-i18n/i18n/en.i18n.json index 6855cba6bd530..d86de4957f3fc 100644 --- a/apps/meteor/packages/rocketchat-i18n/i18n/en.i18n.json +++ b/apps/meteor/packages/rocketchat-i18n/i18n/en.i18n.json @@ -4759,8 +4759,15 @@ "SLA_Policies": "SLA Policies", "SLA_removed": "SLA removed", "Slack_Users": "Slack's Users CSV", - "SlackBridge_APIToken": "API Tokens", + "SlackBridge_APIToken": "API Tokens (Legacy)", + "SlackBridge_UseLegacy": "Use Legacy API Tokens", "SlackBridge_APIToken_Description": "You can configure multiple slack servers by adding one API Token per line.", + "SlackBridge_BotToken": "Bot Tokens", + "SlackBridge_BotToken_Description": "You can configure multiple slack servers by adding one Bot Token per line.", + "SlackBridge_AppToken": "App Tokens", + "SlackBridge_AppToken_Description": "You can configure multiple slack servers by adding one App Token per line.", + "SlackBridge_SigningSecret": "Signing Secret", + "SlackBridge_SigningSecret_Description": "You can configure multiple slack servers by adding one signing secret per line.", "Slackbridge_channel_links_removed_successfully": "The slackbridge channel links have been removed successfully.", "SlackBridge_Description": "Enable Rocket.Chat to communicate directly with Slack.", "SlackBridge_error": "SlackBridge got an error while importing your messages at %s: %s", diff --git a/apps/meteor/server/settings/slackbridge.ts b/apps/meteor/server/settings/slackbridge.ts index ea16f07db42a6..bf3b8c090c9a1 100644 --- a/apps/meteor/server/settings/slackbridge.ts +++ b/apps/meteor/server/settings/slackbridge.ts @@ -8,18 +8,90 @@ export const createSlackBridgeSettings = () => public: true, }); - await this.add('SlackBridge_APIToken', '', { - type: 'string', - multiline: true, + await this.add('SlackBridge_UseLegacy', true, { + type: 'boolean', enableQuery: { _id: 'SlackBridge_Enabled', value: true, }, + i18nLabel: 'SlackBridge_UseLegacy', + i18nDescription: 'SlackBridge_UseLegacy_Description', + public: true, + packageValue: true, + }); + + await this.add('SlackBridge_APIToken', '', { + type: 'string', + multiline: true, + enableQuery: [ + { + _id: 'SlackBridge_UseLegacy', + value: true, + }, + { + _id: 'SlackBridge_Enabled', + value: true, + }, + ], i18nLabel: 'SlackBridge_APIToken', i18nDescription: 'SlackBridge_APIToken_Description', secret: true, }); + await this.add('SlackBridge_BotToken', '', { + type: 'string', + multiline: true, + enableQuery: [ + { + _id: 'SlackBridge_UseLegacy', + value: false, + }, + { + _id: 'SlackBridge_Enabled', + value: true, + }, + ], + i18nLabel: 'SlackBridge_BotToken', + i18nDescription: 'SlackBridge_BotToken_Description', + secret: true, + }); + + await this.add('SlackBridge_SigningSecret', '', { + type: 'string', + multiline: true, + enableQuery: [ + { + _id: 'SlackBridge_UseLegacy', + value: false, + }, + { + _id: 'SlackBridge_Enabled', + value: true, + }, + ], + i18nLabel: 'SlackBridge_SigningSecret', + i18nDescription: 'SlackBridge_SigningSecret_Description', + secret: true, + }); + + await this.add('SlackBridge_AppToken', '', { + type: 'string', + multiline: true, + enableQuery: [ + { + _id: 'SlackBridge_UseLegacy', + value: false, + }, + { + _id: 'SlackBridge_Enabled', + value: true, + }, + ], + i18nLabel: 'SlackBridge_AppToken', + i18nDescription: 'SlackBridge_AppToken_Description', + secret: true, + }); + await this.add('SlackBridge_FileUpload_Enabled', true, { type: 'boolean', enableQuery: { diff --git a/yarn.lock b/yarn.lock index cf1b4e1ee5bf2..ee9d80dfeb684 100644 --- a/yarn.lock +++ b/yarn.lock @@ -8716,6 +8716,7 @@ __metadata: "@rocket.chat/ui-video-conf": "workspace:^" "@rocket.chat/web-ui-registration": "workspace:^" "@settlin/spacebars-loader": ^1.0.9 + "@slack/bolt": ^3.14.0 "@slack/rtm-api": ^6.0.0 "@storybook/addon-a11y": 6.5.16 "@storybook/addon-essentials": ~6.5.16 @@ -9927,6 +9928,29 @@ __metadata: languageName: node linkType: hard +"@slack/bolt@npm:^3.14.0": + version: 3.14.0 + resolution: "@slack/bolt@npm:3.14.0" + dependencies: + "@slack/logger": ^4.0.0 + "@slack/oauth": ^2.6.1 + "@slack/socket-mode": ^1.3.2 + "@slack/types": ^2.8.0 + "@slack/web-api": ^6.7.1 + "@types/express": ^4.16.1 + "@types/promise.allsettled": ^1.0.3 + "@types/tsscmp": ^1.0.0 + axios: ^0.27.2 + express: ^4.16.4 + path-to-regexp: ^6.2.1 + please-upgrade-node: ^3.2.0 + promise.allsettled: ^1.0.2 + raw-body: ^2.3.3 + tsscmp: ^1.0.6 + checksum: 2f8775cc244b09b5f74d0586f94acca2e86b1d68d695839a1951b77a75e874a64aa7ce0b09305d53edfb37e8b8beb802cd55524f1e39c70dc60b229705177497 + languageName: node + linkType: hard + "@slack/logger@npm:>=1.0.0 <3.0.0": version: 2.0.0 resolution: "@slack/logger@npm:2.0.0" @@ -9936,6 +9960,38 @@ __metadata: languageName: node linkType: hard +"@slack/logger@npm:^3.0.0": + version: 3.0.0 + resolution: "@slack/logger@npm:3.0.0" + dependencies: + "@types/node": ">=12.0.0" + checksum: 6512d0e9e4be47ea465705ab9b6e6901f36fa981da0d4a657fde649d452b567b351002049b5ee0a22569b5119bf6c2f61befd5b8022d878addb7a99c91b03389 + languageName: node + linkType: hard + +"@slack/logger@npm:^4.0.0": + version: 4.0.0 + resolution: "@slack/logger@npm:4.0.0" + dependencies: + "@types/node": ">=18.0.0" + checksum: dc79e9d2032c4bf9ce01d96cc72882f003dd376d036f172d4169662cfc2c9b384a80d5546b06021578dd473e7059f064303f0ba851eeb153387f2081a1e3062e + languageName: node + linkType: hard + +"@slack/oauth@npm:^2.6.1": + version: 2.6.1 + resolution: "@slack/oauth@npm:2.6.1" + dependencies: + "@slack/logger": ^3.0.0 + "@slack/web-api": ^6.3.0 + "@types/jsonwebtoken": ^8.3.7 + "@types/node": ">=12" + jsonwebtoken: ^9.0.0 + lodash.isstring: ^4.0.1 + checksum: d86baf8e729f94d108c6fb2c94bd9553dd5070232d6c86da9399769abed69abab84dad6e47b4aeebab140fc4911b7c8e2941ea370ab87149e487092c66e6c348 + languageName: node + linkType: hard + "@slack/rtm-api@npm:^6.0.0": version: 6.0.0 resolution: "@slack/rtm-api@npm:6.0.0" @@ -9954,6 +10010,24 @@ __metadata: languageName: node linkType: hard +"@slack/socket-mode@npm:^1.3.2": + version: 1.3.2 + resolution: "@slack/socket-mode@npm:1.3.2" + dependencies: + "@slack/logger": ^3.0.0 + "@slack/web-api": ^6.2.3 + "@types/node": ">=12.0.0" + "@types/p-queue": ^2.3.2 + "@types/ws": ^7.4.7 + eventemitter3: ^3.1.0 + finity: ^0.5.4 + p-cancelable: ^1.1.0 + p-queue: ^2.4.2 + ws: ^7.5.3 + checksum: ab955ed97798e3c13973f984c1eaa2f58a542af0fc6b0ecc6210f049bdb01a6f2b8705312a4e04ff999f27f190e483d14610d12c7d41004ba2bd0e31c23caf16 + languageName: node + linkType: hard + "@slack/types@npm:^1.7.0": version: 1.10.0 resolution: "@slack/types@npm:1.10.0" @@ -9961,6 +10035,13 @@ __metadata: languageName: node linkType: hard +"@slack/types@npm:^2.8.0": + version: 2.9.0 + resolution: "@slack/types@npm:2.9.0" + checksum: 98fc451928865c65526311189bdb91364834bd071cabd960657838bda6aa1b5918e5b92a6b89967457bcbafe59f420b7d0b642ce6add3e32c5ad2935e57fcd51 + languageName: node + linkType: hard + "@slack/web-api@npm:^5.3.0": version: 5.15.0 resolution: "@slack/web-api@npm:5.15.0" @@ -9979,6 +10060,25 @@ __metadata: languageName: node linkType: hard +"@slack/web-api@npm:^6.2.3, @slack/web-api@npm:^6.3.0, @slack/web-api@npm:^6.7.1": + version: 6.9.0 + resolution: "@slack/web-api@npm:6.9.0" + dependencies: + "@slack/logger": ^3.0.0 + "@slack/types": ^2.8.0 + "@types/is-stream": ^1.1.0 + "@types/node": ">=12.0.0" + axios: ^0.27.2 + eventemitter3: ^3.1.0 + form-data: ^2.5.0 + is-electron: 2.2.2 + is-stream: ^1.1.0 + p-queue: ^6.6.1 + p-retry: ^4.0.0 + checksum: 534518ac573f55bcaead562620dc173e6569bdcf4974f953df22feab06012eceff8a63a5f858da1185b1c237a764b07c44254adc55e450d059a05b6aaee17b0b + languageName: node + linkType: hard + "@storybook/addon-a11y@npm:6.5.16": version: 6.5.16 resolution: "@storybook/addon-a11y@npm:6.5.16" @@ -12289,6 +12389,18 @@ __metadata: languageName: node linkType: hard +"@types/express@npm:^4.16.1": + version: 4.17.18 + resolution: "@types/express@npm:4.17.18" + dependencies: + "@types/body-parser": "*" + "@types/express-serve-static-core": ^4.17.33 + "@types/qs": "*" + "@types/serve-static": "*" + checksum: 8c178da4f0edff1f006d871fbdc3f849620986ff10bad252f3dfd45b57554e26aaa28c602285df028930d5216e257a06fbaf795070f8bb42f7d87e3b689cba50 + languageName: node + linkType: hard + "@types/fibers@npm:^3.1.1": version: 3.1.1 resolution: "@types/fibers@npm:3.1.1" @@ -12524,6 +12636,15 @@ __metadata: languageName: node linkType: hard +"@types/jsonwebtoken@npm:^8.3.7": + version: 8.5.9 + resolution: "@types/jsonwebtoken@npm:8.5.9" + dependencies: + "@types/node": "*" + checksum: 33815ab02d1371b423118316b7706d2f2ec03eeee5e1494be72da50425d2384e5e0a09ea193f7a5ab4b4f6a9c5847147305f50e965f3d927a95bdf8adb471b2a + languageName: node + linkType: hard + "@types/jsrsasign@npm:^10.5.8": version: 10.5.8 resolution: "@types/jsrsasign@npm:10.5.8" @@ -12755,6 +12876,15 @@ __metadata: languageName: node linkType: hard +"@types/node@npm:>=12, @types/node@npm:>=18.0.0": + version: 20.8.4 + resolution: "@types/node@npm:20.8.4" + dependencies: + undici-types: ~5.25.1 + checksum: 2106b9ef9750297cac68249428d7067c4d22c26908854165b70a164e34e900f4c34bb9bf3887c9391206b500d3e87171d03b1846e25788925236a0354390d278 + languageName: node + linkType: hard + "@types/node@npm:^12.7.1": version: 12.20.55 resolution: "@types/node@npm:12.20.55" @@ -12892,6 +13022,13 @@ __metadata: languageName: node linkType: hard +"@types/promise.allsettled@npm:^1.0.3": + version: 1.0.4 + resolution: "@types/promise.allsettled@npm:1.0.4" + checksum: 239fd638f8d96153759c68af486cbe643f1025f05a32a6a3f66471090b8aaf04c4e88bc345f6170d3870f9d47ee262967640cdf9f776ae4a3e53b26c98e90523 + languageName: node + linkType: hard + "@types/prop-types@npm:*": version: 15.7.4 resolution: "@types/prop-types@npm:15.7.4" @@ -13255,6 +13392,13 @@ __metadata: languageName: node linkType: hard +"@types/tsscmp@npm:^1.0.0": + version: 1.0.0 + resolution: "@types/tsscmp@npm:1.0.0" + checksum: 019825388505048db08fa26f41e29f2ca6ea94f7fa4567e5fd7903f49cadac9aa0f2771e9d6e9e17cf241ec0db74308f99de78bbe9062d5b7673bd4e27036621 + languageName: node + linkType: hard + "@types/ua-parser-js@npm:^0.7.36": version: 0.7.36 resolution: "@types/ua-parser-js@npm:0.7.36" @@ -13391,7 +13535,7 @@ __metadata: languageName: node linkType: hard -"@types/ws@npm:^7.2.5": +"@types/ws@npm:^7.2.5, @types/ws@npm:^7.4.7": version: 7.4.7 resolution: "@types/ws@npm:7.4.7" dependencies: @@ -14859,6 +15003,19 @@ __metadata: languageName: node linkType: hard +"array.prototype.map@npm:^1.0.5": + version: 1.0.6 + resolution: "array.prototype.map@npm:1.0.6" + dependencies: + call-bind: ^1.0.2 + define-properties: ^1.2.0 + es-abstract: ^1.22.1 + es-array-method-boxes-properly: ^1.0.0 + is-string: ^1.0.7 + checksum: dfba063cdfb5faba9ee32d5836dc23f3963c2bf7c7ea7d745ee0a96bacf663cbb32ab0bf17d8f65ac6e8c91a162efdea8edbc8b36aed9d17687ce482ba60d91f + languageName: node + linkType: hard + "array.prototype.tosorted@npm:^1.1.1": version: 1.1.1 resolution: "array.prototype.tosorted@npm:1.1.1" @@ -14872,6 +15029,21 @@ __metadata: languageName: node linkType: hard +"arraybuffer.prototype.slice@npm:^1.0.2": + version: 1.0.2 + resolution: "arraybuffer.prototype.slice@npm:1.0.2" + dependencies: + array-buffer-byte-length: ^1.0.0 + call-bind: ^1.0.2 + define-properties: ^1.2.0 + es-abstract: ^1.22.1 + get-intrinsic: ^1.2.1 + is-array-buffer: ^3.0.2 + is-shared-array-buffer: ^1.0.2 + checksum: c200faf437786f5b2c80d4564ff5481c886a16dee642ef02abdc7306c7edd523d1f01d1dd12b769c7eb42ac9bc53874510db19a92a2c035c0f6696172aafa5d3 + languageName: node + linkType: hard + "arrify@npm:^1.0.1": version: 1.0.1 resolution: "arrify@npm:1.0.1" @@ -15843,6 +16015,26 @@ __metadata: languageName: node linkType: hard +"body-parser@npm:1.20.1": + version: 1.20.1 + resolution: "body-parser@npm:1.20.1" + dependencies: + bytes: 3.1.2 + content-type: ~1.0.4 + debug: 2.6.9 + depd: 2.0.0 + destroy: 1.2.0 + http-errors: 2.0.0 + iconv-lite: 0.4.24 + on-finished: 2.4.1 + qs: 6.11.0 + raw-body: 2.5.1 + type-is: ~1.6.18 + unpipe: 1.0.0 + checksum: f1050dbac3bede6a78f0b87947a8d548ce43f91ccc718a50dd774f3c81f2d8b04693e52acf62659fad23101827dd318da1fb1363444ff9a8482b886a3e4a5266 + languageName: node + linkType: hard + "body-parser@npm:1.20.2, body-parser@npm:^1.19.0, body-parser@npm:^1.20.2": version: 1.20.2 resolution: "body-parser@npm:1.20.2" @@ -17767,7 +17959,7 @@ __metadata: languageName: node linkType: hard -"cookie@npm:^0.5.0": +"cookie@npm:0.5.0, cookie@npm:^0.5.0": version: 0.5.0 resolution: "cookie@npm:0.5.0" checksum: 1f4bd2ca5765f8c9689a7e8954183f5332139eb72b6ff783d8947032ec1fdf43109852c178e21a953a30c0dd42257828185be01b49d1eb1a67fd054ca588a180 @@ -19033,6 +19225,17 @@ __metadata: languageName: node linkType: hard +"define-data-property@npm:^1.0.1": + version: 1.1.0 + resolution: "define-data-property@npm:1.1.0" + dependencies: + get-intrinsic: ^1.2.1 + gopd: ^1.0.1 + has-property-descriptors: ^1.0.0 + checksum: 7ad4ee84cca8ad427a4831f5693526804b62ce9dfd4efac77214e95a4382aed930072251d4075dc8dc9fc949a353ed51f19f5285a84a788ba9216cc51472a093 + languageName: node + linkType: hard + "define-lazy-prop@npm:^2.0.0": version: 2.0.0 resolution: "define-lazy-prop@npm:2.0.0" @@ -20076,6 +20279,53 @@ __metadata: languageName: node linkType: hard +"es-abstract@npm:^1.22.1": + version: 1.22.2 + resolution: "es-abstract@npm:1.22.2" + dependencies: + array-buffer-byte-length: ^1.0.0 + arraybuffer.prototype.slice: ^1.0.2 + available-typed-arrays: ^1.0.5 + call-bind: ^1.0.2 + es-set-tostringtag: ^2.0.1 + es-to-primitive: ^1.2.1 + function.prototype.name: ^1.1.6 + get-intrinsic: ^1.2.1 + get-symbol-description: ^1.0.0 + globalthis: ^1.0.3 + gopd: ^1.0.1 + has: ^1.0.3 + has-property-descriptors: ^1.0.0 + has-proto: ^1.0.1 + has-symbols: ^1.0.3 + internal-slot: ^1.0.5 + is-array-buffer: ^3.0.2 + is-callable: ^1.2.7 + is-negative-zero: ^2.0.2 + is-regex: ^1.1.4 + is-shared-array-buffer: ^1.0.2 + is-string: ^1.0.7 + is-typed-array: ^1.1.12 + is-weakref: ^1.0.2 + object-inspect: ^1.12.3 + object-keys: ^1.1.1 + object.assign: ^4.1.4 + regexp.prototype.flags: ^1.5.1 + safe-array-concat: ^1.0.1 + safe-regex-test: ^1.0.0 + string.prototype.trim: ^1.2.8 + string.prototype.trimend: ^1.0.7 + string.prototype.trimstart: ^1.0.7 + typed-array-buffer: ^1.0.0 + typed-array-byte-length: ^1.0.0 + typed-array-byte-offset: ^1.0.0 + typed-array-length: ^1.0.4 + unbox-primitive: ^1.0.2 + which-typed-array: ^1.1.11 + checksum: cc70e592d360d7d729859013dee7a610c6b27ed8630df0547c16b0d16d9fe6505a70ee14d1af08d970fdd132b3f88c9ca7815ce72c9011608abf8ab0e55fc515 + languageName: node + linkType: hard + "es-array-method-boxes-properly@npm:^1.0.0": version: 1.0.0 resolution: "es-array-method-boxes-properly@npm:1.0.0" @@ -20107,6 +20357,17 @@ __metadata: languageName: node linkType: hard +"es-set-tostringtag@npm:^2.0.1": + version: 2.0.1 + resolution: "es-set-tostringtag@npm:2.0.1" + dependencies: + get-intrinsic: ^1.1.3 + has: ^1.0.3 + has-tostringtag: ^1.0.0 + checksum: ec416a12948cefb4b2a5932e62093a7cf36ddc3efd58d6c58ca7ae7064475ace556434b869b0bbeb0c365f1032a8ccd577211101234b69837ad83ad204fff884 + languageName: node + linkType: hard + "es-shim-unscopables@npm:^1.0.0": version: 1.0.0 resolution: "es-shim-unscopables@npm:1.0.0" @@ -21042,6 +21303,45 @@ __metadata: languageName: node linkType: hard +"express@npm:^4.16.4": + version: 4.18.2 + resolution: "express@npm:4.18.2" + dependencies: + accepts: ~1.3.8 + array-flatten: 1.1.1 + body-parser: 1.20.1 + content-disposition: 0.5.4 + content-type: ~1.0.4 + cookie: 0.5.0 + cookie-signature: 1.0.6 + debug: 2.6.9 + depd: 2.0.0 + encodeurl: ~1.0.2 + escape-html: ~1.0.3 + etag: ~1.8.1 + finalhandler: 1.2.0 + fresh: 0.5.2 + http-errors: 2.0.0 + merge-descriptors: 1.0.1 + methods: ~1.1.2 + on-finished: 2.4.1 + parseurl: ~1.3.3 + path-to-regexp: 0.1.7 + proxy-addr: ~2.0.7 + qs: 6.11.0 + range-parser: ~1.2.1 + safe-buffer: 5.2.1 + send: 0.18.0 + serve-static: 1.15.0 + setprototypeof: 1.2.0 + statuses: 2.0.1 + type-is: ~1.6.18 + utils-merge: 1.0.1 + vary: ~1.1.2 + checksum: 3c4b9b076879442f6b968fe53d85d9f1eeacbb4f4c41e5f16cc36d77ce39a2b0d81b3f250514982110d815b2f7173f5561367f9110fcc541f9371948e8c8b037 + languageName: node + linkType: hard + "express@npm:^4.17.1, express@npm:^4.17.2, express@npm:^4.17.3": version: 4.17.3 resolution: "express@npm:4.17.3" @@ -21625,6 +21925,21 @@ __metadata: languageName: node linkType: hard +"finalhandler@npm:1.2.0": + version: 1.2.0 + resolution: "finalhandler@npm:1.2.0" + dependencies: + debug: 2.6.9 + encodeurl: ~1.0.2 + escape-html: ~1.0.3 + on-finished: 2.4.1 + parseurl: ~1.3.3 + statuses: 2.0.1 + unpipe: ~1.0.0 + checksum: 92effbfd32e22a7dff2994acedbd9bcc3aa646a3e919ea6a53238090e87097f8ef07cced90aa2cc421abdf993aefbdd5b00104d55c7c5479a8d00ed105b45716 + languageName: node + linkType: hard + "find-cache-dir@npm:^2.0.0, find-cache-dir@npm:^2.1.0": version: 2.1.0 resolution: "find-cache-dir@npm:2.1.0" @@ -22174,6 +22489,18 @@ __metadata: languageName: node linkType: hard +"function.prototype.name@npm:^1.1.6": + version: 1.1.6 + resolution: "function.prototype.name@npm:1.1.6" + dependencies: + call-bind: ^1.0.2 + define-properties: ^1.2.0 + es-abstract: ^1.22.1 + functions-have-names: ^1.2.3 + checksum: 7a3f9bd98adab09a07f6e1f03da03d3f7c26abbdeaeee15223f6c04a9fb5674792bdf5e689dac19b97ac71de6aad2027ba3048a9b883aa1b3173eed6ab07f479 + languageName: node + linkType: hard + "functional-red-black-tree@npm:^1.0.1": version: 1.0.1 resolution: "functional-red-black-tree@npm:1.0.1" @@ -22717,6 +23044,15 @@ __metadata: languageName: node linkType: hard +"globalthis@npm:^1.0.3": + version: 1.0.3 + resolution: "globalthis@npm:1.0.3" + dependencies: + define-properties: ^1.1.3 + checksum: fbd7d760dc464c886d0196166d92e5ffb4c84d0730846d6621a39fbbc068aeeb9c8d1421ad330e94b7bca4bb4ea092f5f21f3d36077812af5d098b4dc006c998 + languageName: node + linkType: hard + "globby@npm:^10.0.0": version: 10.0.2 resolution: "globby@npm:10.0.2" @@ -24397,7 +24733,7 @@ __metadata: languageName: node linkType: hard -"internal-slot@npm:^1.0.3, internal-slot@npm:^1.0.4": +"internal-slot@npm:^1.0.3, internal-slot@npm:^1.0.4, internal-slot@npm:^1.0.5": version: 1.0.5 resolution: "internal-slot@npm:1.0.5" dependencies: @@ -24806,6 +25142,13 @@ __metadata: languageName: node linkType: hard +"is-electron@npm:2.2.2": + version: 2.2.2 + resolution: "is-electron@npm:2.2.2" + checksum: de5aa8bd8d72c96675b8d0f93fab4cc21f62be5440f65bc05c61338ca27bd851a64200f31f1bf9facbaa01b3dbfed7997b2186741d84b93b63e0aff1db6a9494 + languageName: node + linkType: hard + "is-extendable@npm:^0.1.0, is-extendable@npm:^0.1.1": version: 0.1.1 resolution: "is-extendable@npm:0.1.1" @@ -25236,7 +25579,7 @@ __metadata: languageName: node linkType: hard -"is-typed-array@npm:^1.1.10, is-typed-array@npm:^1.1.3": +"is-typed-array@npm:^1.1.10, is-typed-array@npm:^1.1.12, is-typed-array@npm:^1.1.3, is-typed-array@npm:^1.1.9": version: 1.1.12 resolution: "is-typed-array@npm:1.1.12" dependencies: @@ -26556,6 +26899,24 @@ __metadata: languageName: node linkType: hard +"jsonwebtoken@npm:^9.0.0": + version: 9.0.2 + resolution: "jsonwebtoken@npm:9.0.2" + dependencies: + jws: ^3.2.2 + lodash.includes: ^4.3.0 + lodash.isboolean: ^3.0.3 + lodash.isinteger: ^4.0.4 + lodash.isnumber: ^3.0.3 + lodash.isplainobject: ^4.0.6 + lodash.isstring: ^4.0.1 + lodash.once: ^4.0.0 + ms: ^2.1.1 + semver: ^7.5.4 + checksum: fc739a6a8b33f1974f9772dca7f8493ca8df4cc31c5a09dcfdb7cff77447dcf22f4236fb2774ef3fe50df0abeb8e1c6f4c41eba82f500a804ab101e2fbc9d61a + languageName: node + linkType: hard + "jsprim@npm:^1.2.2": version: 1.4.2 resolution: "jsprim@npm:1.4.2" @@ -29737,6 +30098,13 @@ __metadata: languageName: node linkType: hard +"object-inspect@npm:^1.12.3": + version: 1.12.3 + resolution: "object-inspect@npm:1.12.3" + checksum: dabfd824d97a5f407e6d5d24810d888859f6be394d8b733a77442b277e0808860555176719c5905e765e3743a7cada6b8b0a3b85e5331c530fd418cc8ae991db + languageName: node + linkType: hard + "object-is@npm:^1.0.1, object-is@npm:^1.1.5": version: 1.1.5 resolution: "object-is@npm:1.1.5" @@ -32229,6 +32597,20 @@ __metadata: languageName: node linkType: hard +"promise.allsettled@npm:^1.0.2": + version: 1.0.7 + resolution: "promise.allsettled@npm:1.0.7" + dependencies: + array.prototype.map: ^1.0.5 + call-bind: ^1.0.2 + define-properties: ^1.2.0 + es-abstract: ^1.22.1 + get-intrinsic: ^1.2.1 + iterate-value: ^1.0.2 + checksum: 96186392286e5ab9aef1a1a725c061c8cf268b6cf141f151daa3834bb8e1680f3b159af6536ce59cf80d4a6a5ad1d8371d05759980cc6c90d58800ddb0a7c119 + languageName: node + linkType: hard + "promise.prototype.finally@npm:^3.1.0": version: 3.1.3 resolution: "promise.prototype.finally@npm:3.1.3" @@ -32766,7 +33148,19 @@ __metadata: languageName: node linkType: hard -"raw-body@npm:2.5.2, raw-body@npm:^2.2.0": +"raw-body@npm:2.5.1": + version: 2.5.1 + resolution: "raw-body@npm:2.5.1" + dependencies: + bytes: 3.1.2 + http-errors: 2.0.0 + iconv-lite: 0.4.24 + unpipe: 1.0.0 + checksum: 5362adff1575d691bb3f75998803a0ffed8c64eabeaa06e54b4ada25a0cd1b2ae7f4f5ec46565d1bec337e08b5ac90c76eaa0758de6f72a633f025d754dec29e + languageName: node + linkType: hard + +"raw-body@npm:2.5.2, raw-body@npm:^2.2.0, raw-body@npm:^2.3.3": version: 2.5.2 resolution: "raw-body@npm:2.5.2" dependencies: @@ -33689,6 +34083,17 @@ __metadata: languageName: node linkType: hard +"regexp.prototype.flags@npm:^1.5.1": + version: 1.5.1 + resolution: "regexp.prototype.flags@npm:1.5.1" + dependencies: + call-bind: ^1.0.2 + define-properties: ^1.2.0 + set-function-name: ^2.0.0 + checksum: 869edff00288442f8d7fa4c9327f91d85f3b3acf8cbbef9ea7a220345cf23e9241b6def9263d2c1ebcf3a316b0aa52ad26a43a84aa02baca3381717b3e307f47 + languageName: node + linkType: hard + "regexpp@npm:^3.1.0": version: 3.2.0 resolution: "regexpp@npm:3.2.0" @@ -34401,6 +34806,18 @@ __metadata: languageName: node linkType: hard +"safe-array-concat@npm:^1.0.1": + version: 1.0.1 + resolution: "safe-array-concat@npm:1.0.1" + dependencies: + call-bind: ^1.0.2 + get-intrinsic: ^1.2.1 + has-symbols: ^1.0.3 + isarray: ^2.0.5 + checksum: 001ecf1d8af398251cbfabaf30ed66e3855127fbceee178179524b24160b49d15442f94ed6c0db0b2e796da76bb05b73bf3cc241490ec9c2b741b41d33058581 + languageName: node + linkType: hard + "safe-buffer@npm:5.1.1": version: 5.1.1 resolution: "safe-buffer@npm:5.1.1" @@ -34789,6 +35206,17 @@ __metadata: languageName: node linkType: hard +"semver@npm:^7.5.4": + version: 7.5.4 + resolution: "semver@npm:7.5.4" + dependencies: + lru-cache: ^6.0.0 + bin: + semver: bin/semver.js + checksum: 12d8ad952fa353b0995bf180cdac205a4068b759a140e5d3c608317098b3575ac2f1e09182206bf2eb26120e1c0ed8fb92c48c592f6099680de56bb071423ca3 + languageName: node + linkType: hard + "semver@npm:~5.3.0": version: 5.3.0 resolution: "semver@npm:5.3.0" @@ -34828,6 +35256,27 @@ __metadata: languageName: node linkType: hard +"send@npm:0.18.0": + version: 0.18.0 + resolution: "send@npm:0.18.0" + dependencies: + debug: 2.6.9 + depd: 2.0.0 + destroy: 1.2.0 + encodeurl: ~1.0.2 + escape-html: ~1.0.3 + etag: ~1.8.1 + fresh: 0.5.2 + http-errors: 2.0.0 + mime: 1.6.0 + ms: 2.1.3 + on-finished: 2.4.1 + range-parser: ~1.2.1 + statuses: 2.0.1 + checksum: 74fc07ebb58566b87b078ec63e5a3e41ecd987e4272ba67b7467e86c6ad51bc6b0b0154133b6d8b08a2ddda360464f71382f7ef864700f34844a76c8027817a8 + languageName: node + linkType: hard + "sentence-case@npm:^3.0.4": version: 3.0.4 resolution: "sentence-case@npm:3.0.4" @@ -34931,6 +35380,18 @@ __metadata: languageName: node linkType: hard +"serve-static@npm:1.15.0": + version: 1.15.0 + resolution: "serve-static@npm:1.15.0" + dependencies: + encodeurl: ~1.0.2 + escape-html: ~1.0.3 + parseurl: ~1.3.3 + send: 0.18.0 + checksum: af57fc13be40d90a12562e98c0b7855cf6e8bd4c107fe9a45c212bf023058d54a1871b1c89511c3958f70626fff47faeb795f5d83f8cf88514dbaeb2b724464d + languageName: node + linkType: hard + "serve@npm:^11.3.2": version: 11.3.2 resolution: "serve@npm:11.3.2" @@ -34957,6 +35418,17 @@ __metadata: languageName: node linkType: hard +"set-function-name@npm:^2.0.0": + version: 2.0.1 + resolution: "set-function-name@npm:2.0.1" + dependencies: + define-data-property: ^1.0.1 + functions-have-names: ^1.2.3 + has-property-descriptors: ^1.0.0 + checksum: 4975d17d90c40168eee2c7c9c59d023429f0a1690a89d75656306481ece0c3c1fb1ebcc0150ea546d1913e35fbd037bace91372c69e543e51fc5d1f31a9fa126 + languageName: node + linkType: hard + "set-value@npm:^2.0.0, set-value@npm:^2.0.1": version: 2.0.1 resolution: "set-value@npm:2.0.1" @@ -36135,6 +36607,17 @@ __metadata: languageName: node linkType: hard +"string.prototype.trim@npm:^1.2.8": + version: 1.2.8 + resolution: "string.prototype.trim@npm:1.2.8" + dependencies: + call-bind: ^1.0.2 + define-properties: ^1.2.0 + es-abstract: ^1.22.1 + checksum: 49eb1a862a53aba73c3fb6c2a53f5463173cb1f4512374b623bcd6b43ad49dd559a06fb5789bdec771a40fc4d2a564411c0a75d35fb27e76bbe738c211ecff07 + languageName: node + linkType: hard + "string.prototype.trimend@npm:^1.0.5": version: 1.0.5 resolution: "string.prototype.trimend@npm:1.0.5" @@ -36146,6 +36629,17 @@ __metadata: languageName: node linkType: hard +"string.prototype.trimend@npm:^1.0.7": + version: 1.0.7 + resolution: "string.prototype.trimend@npm:1.0.7" + dependencies: + call-bind: ^1.0.2 + define-properties: ^1.2.0 + es-abstract: ^1.22.1 + checksum: 2375516272fd1ba75992f4c4aa88a7b5f3c7a9ca308d963bcd5645adf689eba6f8a04ebab80c33e30ec0aefc6554181a3a8416015c38da0aa118e60ec896310c + languageName: node + linkType: hard + "string.prototype.trimstart@npm:^1.0.5": version: 1.0.5 resolution: "string.prototype.trimstart@npm:1.0.5" @@ -36157,6 +36651,17 @@ __metadata: languageName: node linkType: hard +"string.prototype.trimstart@npm:^1.0.7": + version: 1.0.7 + resolution: "string.prototype.trimstart@npm:1.0.7" + dependencies: + call-bind: ^1.0.2 + define-properties: ^1.2.0 + es-abstract: ^1.22.1 + checksum: 13d0c2cb0d5ff9e926fa0bec559158b062eed2b68cd5be777ffba782c96b2b492944e47057274e064549b94dd27cf81f48b27a31fee8af5b574cff253e7eb613 + languageName: node + linkType: hard + "string_decoder@npm:^1.0.0, string_decoder@npm:^1.1.1, string_decoder@npm:^1.3.0": version: 1.3.0 resolution: "string_decoder@npm:1.3.0" @@ -37592,6 +38097,13 @@ __metadata: languageName: node linkType: hard +"tsscmp@npm:^1.0.6": + version: 1.0.6 + resolution: "tsscmp@npm:1.0.6" + checksum: 1512384def36bccc9125cabbd4c3b0e68608d7ee08127ceaa0b84a71797263f1a01c7f82fa69be8a3bd3c1396e2965d2f7b52d581d3a5eeaf3967fbc52e3b3bf + languageName: node + linkType: hard + "tsup@npm:^6.7.0": version: 6.7.0 resolution: "tsup@npm:6.7.0" @@ -37931,6 +38443,53 @@ __metadata: languageName: node linkType: hard +"typed-array-buffer@npm:^1.0.0": + version: 1.0.0 + resolution: "typed-array-buffer@npm:1.0.0" + dependencies: + call-bind: ^1.0.2 + get-intrinsic: ^1.2.1 + is-typed-array: ^1.1.10 + checksum: 3e0281c79b2a40cd97fe715db803884301993f4e8c18e8d79d75fd18f796e8cd203310fec8c7fdb5e6c09bedf0af4f6ab8b75eb3d3a85da69328f28a80456bd3 + languageName: node + linkType: hard + +"typed-array-byte-length@npm:^1.0.0": + version: 1.0.0 + resolution: "typed-array-byte-length@npm:1.0.0" + dependencies: + call-bind: ^1.0.2 + for-each: ^0.3.3 + has-proto: ^1.0.1 + is-typed-array: ^1.1.10 + checksum: b03db16458322b263d87a702ff25388293f1356326c8a678d7515767ef563ef80e1e67ce648b821ec13178dd628eb2afdc19f97001ceae7a31acf674c849af94 + languageName: node + linkType: hard + +"typed-array-byte-offset@npm:^1.0.0": + version: 1.0.0 + resolution: "typed-array-byte-offset@npm:1.0.0" + dependencies: + available-typed-arrays: ^1.0.5 + call-bind: ^1.0.2 + for-each: ^0.3.3 + has-proto: ^1.0.1 + is-typed-array: ^1.1.10 + checksum: 04f6f02d0e9a948a95fbfe0d5a70b002191fae0b8fe0fe3130a9b2336f043daf7a3dda56a31333c35a067a97e13f539949ab261ca0f3692c41603a46a94e960b + languageName: node + linkType: hard + +"typed-array-length@npm:^1.0.4": + version: 1.0.4 + resolution: "typed-array-length@npm:1.0.4" + dependencies: + call-bind: ^1.0.2 + for-each: ^0.3.3 + is-typed-array: ^1.1.9 + checksum: 2228febc93c7feff142b8c96a58d4a0d7623ecde6c7a24b2b98eb3170e99f7c7eff8c114f9b283085cd59dcd2bd43aadf20e25bba4b034a53c5bb292f71f8956 + languageName: node + linkType: hard + "typedarray-to-buffer@npm:^3.1.5": version: 3.1.5 resolution: "typedarray-to-buffer@npm:3.1.5" @@ -38053,6 +38612,13 @@ __metadata: languageName: node linkType: hard +"undici-types@npm:~5.25.1": + version: 5.25.3 + resolution: "undici-types@npm:5.25.3" + checksum: ec9d2cc36520cbd9fbe3b3b6c682a87fe5be214699e1f57d1e3d9a2cb5be422e62735f06e0067dc325fd3dd7404c697e4d479f9147dc8a804e049e29f357f2ff + languageName: node + linkType: hard + "unfetch@npm:^4.2.0": version: 4.2.0 resolution: "unfetch@npm:4.2.0" @@ -39934,7 +40500,7 @@ __metadata: languageName: node linkType: hard -"ws@npm:^7.0.0, ws@npm:^7.3.1, ws@npm:^7.4.6": +"ws@npm:^7.0.0, ws@npm:^7.3.1, ws@npm:^7.4.6, ws@npm:^7.5.3": version: 7.5.9 resolution: "ws@npm:7.5.9" peerDependencies: