diff --git a/README.md b/README.md index e71c3575..34af7029 100644 --- a/README.md +++ b/README.md @@ -46,6 +46,7 @@ - Possibility to Change UI Themes - Possibility to protect your Host with username and password (default disabled) - Supports [REST API](app/api/README.md) (Application Programming Interface) +- [Slack](https://api.slack.com/apps/) API integration - [Sentry](https://sentry.io/) error reporting diff --git a/app/src/Server.js b/app/src/Server.js index d1967d69..ad970103 100644 --- a/app/src/Server.js +++ b/app/src/Server.js @@ -22,6 +22,13 @@ const swaggerDocument = yamlJS.load(path.join(__dirname + '/../api/swagger.yaml' const Sentry = require('@sentry/node'); const { CaptureConsole } = require('@sentry/integrations'); +// Slack API +const CryptoJS = require('crypto-js'); +const qS = require('qs'); +const slackEnabled = config.slack.enabled; +const slackSigningSecret = config.slack.signingSecret; +const bodyParser = require('body-parser'); + const app = express(); const options = { @@ -102,6 +109,7 @@ app.use(cors()); app.use(compression()); app.use(express.json()); app.use(express.static(dir.public)); +app.use(bodyParser.urlencoded({ extended: true })); app.use(apiBasePath + '/docs', swaggerUi.serve, swaggerUi.setup(swaggerDocument)); // api docs // Remove trailing slashes in url handle bad requests @@ -259,6 +267,37 @@ app.post(['/api/v1/join'], (req, res) => { }); }); +// #################################################### +// SLACK API +// #################################################### + +app.post('/slack', (req, res) => { + if (!slackEnabled) return res.end('`Under maintenance` - Please check back soon.'); + + log.debug('Slack', req.headers); + + if (!slackSigningSecret) return res.end('`Slack Signing Secret is empty!`'); + + let slackSignature = req.headers['x-slack-signature']; + let requestBody = qS.stringify(req.body, { format: 'RFC1738' }); + let timeStamp = req.headers['x-slack-request-timestamp']; + let time = Math.floor(new Date().getTime() / 1000); + + if (Math.abs(time - timeStamp) > 300) return res.end('`Wrong timestamp` - Ignore this request.'); + + let sigBaseString = 'v0:' + timeStamp + ':' + requestBody; + let mySignature = 'v0=' + CryptoJS.HmacSHA256(sigBaseString, slackSigningSecret); + + if (mySignature == slackSignature) { + let host = req.headers.host; + let api = new ServerApi(host); + let meetingURL = api.getMeetingURL(); + log.debug('Slack', { meeting: meetingURL }); + return res.end(meetingURL); + } + return res.end('`Wrong signature` - Verification failed!'); +}); + // not match any of page before, so 404 not found app.get('*', function (req, res) { res.sendFile(views.notFound); diff --git a/app/src/ServerApi.js b/app/src/ServerApi.js index 295abbe7..9cdfdae6 100644 --- a/app/src/ServerApi.js +++ b/app/src/ServerApi.js @@ -4,7 +4,7 @@ const config = require('./config'); const { v4: uuidV4 } = require('uuid'); module.exports = class ServerApi { - constructor(host, authorization) { + constructor(host = null, authorization = null) { this._host = host; this._authorization = authorization; this._api_key_secret = config.apiKeySecret; diff --git a/app/src/config.template.js b/app/src/config.template.js index e87bcc1f..2d1feac5 100644 --- a/app/src/config.template.js +++ b/app/src/config.template.js @@ -55,6 +55,16 @@ module.exports = { DSN: '', tracesSampleRate: 0.5, }, + slack: { + /* + 1. Goto https://api.slack.com/apps/ + 2. Create your app + 3. On Settings - Basic Information - App Credentials, chose your Signing Secret + 4. Create a Slash Commands and put as Request URL: https://your.domain.name/slack + */ + enabled: false, + signingSecret: '', + }, mediasoup: { // Worker settings numWorkers: Object.keys(os.cpus()).length, diff --git a/package.json b/package.json index 2c767f46..0738b08b 100644 --- a/package.json +++ b/package.json @@ -16,13 +16,16 @@ "author": "Miroslav Pejic", "license": "AGPL-3.0", "dependencies": { + "body-parser": "^1.20.0", "compression": "1.7.4", "cors": "2.8.5", + "crypto-js": "^4.1.1", "express": "4.18.1", "httpolyglot": "0.1.2", "mediasoup": "3.9.17", "mediasoup-client": "3.6.52", "ngrok": "4.3.1", + "qs": "^6.10.5", "@sentry/node": "7.2.0", "@sentry/integrations": "7.2.0", "socket.io": "4.5.1",