From 19c56ce0ccc550a446ccb8e0cd6f0280612ba95f Mon Sep 17 00:00:00 2001 From: Miroslav Pejic Date: Sat, 26 Oct 2024 10:41:42 +0200 Subject: [PATCH] [mirotalk] - refactoring mattermost --- .env.template | 2 +- app/src/mattermost.js | 88 +++++++++++++++++++++++++++++++++++++++++++ app/src/server.js | 81 ++++----------------------------------- package.json | 3 +- public/js/client.js | 4 +- 5 files changed, 100 insertions(+), 78 deletions(-) create mode 100644 app/src/mattermost.js diff --git a/.env.template b/.env.template index aa8b7d0b..f38f26bf 100644 --- a/.env.template +++ b/.env.template @@ -145,7 +145,7 @@ SLACK_SIGNING_SECRET=YourSlackSigningSecret # - Command Trigger Word: Set the trigger word to `p2p`. # - Callback URLs: Enter the URL for your Express server (e.g., `https://yourserver.com/mattermost`). # - Request Method: Select POST. -# - Enable Autocomplete: Check the box for **Autocomplete**. +# - Enable Autocomplete: Check the box for Autocomplete. # - Autocomplete Description: Provide a brief description (e.g., `Get MiroTalk P2P meeting room`). # 3. Save the slash command and copy the generated token here as MATTERMOST_TOKEN. diff --git a/app/src/mattermost.js b/app/src/mattermost.js new file mode 100644 index 00000000..d3089244 --- /dev/null +++ b/app/src/mattermost.js @@ -0,0 +1,88 @@ +'use strict'; + +const { Client4 } = require('@mattermost/client'); + +const { v4: uuidV4 } = require('uuid'); + +const Logger = require('./logs'); + +const log = new Logger('Mattermost'); + +class mattermost { + constructor(app) { + const { + MATTERMOST_ENABLED, + MATTERMOST_TOKEN, + MATTERMOST_SERVER_URL, + MATTERMOST_USERNAME, + MATTERMOST_PASSWORD, + API_DISABLED + } = process.env; + + log.debug('Mattermost config', { + enabled: MATTERMOST_ENABLED, + token: MATTERMOST_TOKEN, + server: MATTERMOST_SERVER_URL, + username: MATTERMOST_USERNAME, + password: MATTERMOST_PASSWORD, + }); + + if (MATTERMOST_ENABLED !== 'true') return; + + this.app = app; + this.disabled = JSON.parse(API_DISABLED); + this.token = MATTERMOST_TOKEN; + this.serverUrl = MATTERMOST_SERVER_URL; + this.username = MATTERMOST_USERNAME; + this.password = MATTERMOST_PASSWORD; + + this.client = new Client4(); + this.client.setUrl(this.serverUrl); + this.authenticate(); + this.setupEventHandlers(); + } + + async authenticate() { + try { + const user = await this.client.login(this.username, this.password); + log.debug('--------> Logged into Mattermost as', user.username); + } catch (error) { + log.error('Failed to log into Mattermost:', error); + } + } + + setupEventHandlers() { + this.app.post('/mattermost', (req, res) => { + // Check if endpoint allowed + if (this.disabled.includes('mattermost')) { + return res.end('`This endpoint has been disabled`. Please contact the administrator for further information.'); + } + + // Validate the token + const { token, text, command, channel_id } = req.body; + if (token !== this.token) { + return res.status(403).send('Invalid token'); + } + + // Check if the command (slash-commands) or text (outgoing-webhook) matches "/p2p" + if (command.trim() === '/p2p' || text.trim() === '/p2p') { + const meetingUrl = this.getMeetingURL(req); + return res.json({ + text: `Here is your meeting room: ${meetingUrl}`, + channel_id: channel_id, + }); + } + + // If the command is not recognized + return res.status(200).send('Command not recognized'); + }); + } + + getMeetingURL(req) { + const host = req.headers.host; + const protocol = host.includes('localhost') ? 'http' : 'https'; + return `${protocol}://${host}/join/${uuidV4()}`; + } +} + +module.exports = mattermost; diff --git a/app/src/server.js b/app/src/server.js index 5b42a0a7..87056274 100755 --- a/app/src/server.js +++ b/app/src/server.js @@ -40,7 +40,7 @@ dependencies: { * @license For commercial use or closed source, contact us at license.mirotalk@gmail.com or purchase directly from CodeCanyon * @license CodeCanyon: https://codecanyon.net/item/mirotalk-p2p-webrtc-realtime-video-conferences/38376661 * @author Miroslav Pejic - miroslav.pejic.85@gmail.com - * @version 1.3.82 + * @version 1.3.83 * */ @@ -62,6 +62,7 @@ const app = express(); const fs = require('fs'); const checkXSS = require('./xss.js'); const ServerApi = require('./api'); +const mattermostCli = require('./mattermost.js'); const Host = require('./host'); const Logs = require('./logs'); const log = new Logs('server'); @@ -231,31 +232,6 @@ const CryptoJS = require('crypto-js'); const qS = require('qs'); const slackEnabled = getEnvBoolean(process.env.SLACK_ENABLED); const slackSigningSecret = process.env.SLACK_SIGNING_SECRET; -const bodyParser = require('body-parser'); - -// Mattermost -const { Client4 } = require('@mattermost/client'); -const mattermostEnabled = getEnvBoolean(process.env.MATTERMOST_ENABLED); -const mattermostToken = process.env.MATTERMOST_TOKEN; -const mattermostServerUrl = process.env.MATTERMOST_SERVER_URL; -const mattermostUsername = process.env.MATTERMOST_USERNAME; -const mattermostPassword = process.env.MATTERMOST_PASSWORD; - -if (mattermostEnabled) { - const client = new Client4(); - - client.setUrl(mattermostServerUrl); - - async function authenticate() { - try { - const user = await client.login(mattermostUsername, mattermostPassword); - log.debug('-----------> Mattermost Logged in as:', user.username); - } catch (error) { - log.error('Mattermost client Failed to log in', error.message); - } - } - authenticate(); -} // Setup sentry client if (sentryEnabled) { @@ -385,12 +361,11 @@ const sockets = {}; // collect sockets const peers = {}; // collect peers info grp by channels const presenters = {}; // collect presenters grp by channels +app.use(express.static(dir.public)); // Use all static files from the public folder app.use(cors(corsOptions)); // Enable CORS with options app.use(compression()); // Compress all HTTP responses using GZip -app.use(express.json()); // Api parse body data as json -app.use(express.static(dir.public)); // Use all static files from the public folder -app.use(bodyParser.urlencoded({ extended: true })); // Need for Slack API body parser -app.use(bodyParser.json()); +app.use(express.json()); // Parse JSON bodies +app.use(express.urlencoded({ extended: false })); // Parse URL-encoded bodies app.use(apiBasePath + '/docs', swaggerUi.serve, swaggerUi.setup(swaggerDocument)); // api docs // Restrict access to specified IP @@ -417,6 +392,9 @@ app.use((req, res, next) => { next(); }); +// Mattermost +const mattermost = new mattermostCli(app); + // POST start from here... app.post('*', function (next) { next(); @@ -849,49 +827,6 @@ app.post('/slack', (req, res) => { return res.end('`Wrong signature` - Verification failed!'); }); -/* - MiroTalk Mattermost app v1 - https://api.slack.com/authentication/verifying-requests-from-slack -*/ - -// Mattermost request meeting room endpoint -app.post('/mattermost', (req, res) => { - // - if (!mattermostEnabled) { - return res.end('`Under maintenance` - Please check back soon.'); - } - - // Check if endpoint allowed - if (api_disabled.includes('mattermost')) { - return res.end('`This endpoint has been disabled`. Please contact the administrator for further information.'); - } - - log.debug('Mattermost', req.body); - - const { token, text, command, channel_id } = req.body; - - // Validate the token - if (token !== mattermostToken) { - return res.status(403).send('Invalid token'); - } - - // Check if the command (slash-commands) or text (outgoing-webhook) matches "/p2p" - if (command.trim() === '/p2p' || text.trim() === '/p2p') { - // Generate or retrieve your meeting URL - const host = req.headers.host; - const meetingUrl = getMeetingURL(host); - - // Send the response back to Mattermost - return res.json({ - text: `Here is your meeting room: ${meetingUrl}`, - channel_id: channel_id, - }); - } - - // If the command is not recognized - return res.status(200).send('Command not recognized'); -}); - /** * Request meeting room endpoint * @returns entrypoint / Room URL for your meeting. diff --git a/package.json b/package.json index 3cdcd45f..a48a0f0e 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "mirotalk", - "version": "1.3.82", + "version": "1.3.83", "description": "A free WebRTC browser-based video call", "main": "server.js", "scripts": { @@ -44,7 +44,6 @@ "@mattermost/client": "^10.0.0", "@sentry/node": "^8.35.0", "axios": "^1.7.7", - "body-parser": "^1.20.3", "colors": "^1.4.0", "compression": "^1.7.4", "cors": "^2.8.5", diff --git a/public/js/client.js b/public/js/client.js index df8d15a6..3632a92a 100644 --- a/public/js/client.js +++ b/public/js/client.js @@ -15,7 +15,7 @@ * @license For commercial use or closed source, contact us at license.mirotalk@gmail.com or purchase directly from CodeCanyon * @license CodeCanyon: https://codecanyon.net/item/mirotalk-p2p-webrtc-realtime-video-conferences/38376661 * @author Miroslav Pejic - miroslav.pejic.85@gmail.com - * @version 1.3.82 + * @version 1.3.83 * */ @@ -10569,7 +10569,7 @@ function showAbout() { Swal.fire({ background: swBg, position: 'center', - title: 'WebRTC P2P v1.3.82', + title: 'WebRTC P2P v1.3.83', imageAlt: 'mirotalk-about', imageUrl: images.about, customClass: { image: 'img-about' },