From 0d81177a7fac84772ba4e5f2af03855c73bf1b26 Mon Sep 17 00:00:00 2001 From: Miroslav Pejic Date: Mon, 10 Jun 2024 08:19:03 +0200 Subject: [PATCH] [mirotalksfu] - add limit rooms per user option, update dep --- app/src/Server.js | 84 ++++++++++++++++++++++++++++++-------- app/src/config.template.js | 6 +++ package.json | 4 +- public/js/Room.js | 2 +- public/js/RoomClient.js | 25 +++++++++++- 5 files changed, 101 insertions(+), 20 deletions(-) diff --git a/app/src/Server.js b/app/src/Server.js index c6a7ac7f..13d053a1 100644 --- a/app/src/Server.js +++ b/app/src/Server.js @@ -42,7 +42,7 @@ dependencies: { * @license For commercial or closed source, contact us at license.mirotalk@gmail.com or purchase directly via CodeCanyon * @license CodeCanyon: https://codecanyon.net/item/mirotalk-sfu-webrtc-realtime-video-conferences/40769970 * @author Miroslav Pejic - miroslav.pejic.85@gmail.com - * @version 1.4.47 + * @version 1.4.48 * */ @@ -439,14 +439,8 @@ function startServer() { req.query, ); - const allowRoomAccess = isAllowedRoomAccess('/join/params', req, hostCfg, authHost, roomList, room); - - if (!allowRoomAccess) { - return res.status(401).json({ message: 'Direct Room Join Unauthorized' }); - } - - let peerUsername, - peerPassword = ''; + let peerUsername = ''; + let peerPassword = ''; let isPeerValid = false; let isPeerPresenter = false; @@ -459,16 +453,30 @@ function startServer() { } const { username, password, presenter } = checkXSS(decodeToken(token)); + peerUsername = username; peerPassword = password; isPeerValid = await isAuthPeer(username, password); isPeerPresenter = presenter === '1' || presenter === 'true'; + + if (isPeerPresenter) { + const roomAllowedForUser = isRoomAllowedForUser('Direct Join with token', username, room); + if (!roomAllowedForUser) { + return res.status(401).json({ message: 'Direct Room Join for this User is Unauthorized' }); + } + } } catch (err) { log.error('Direct Join JWT error', { error: err.message, token: token }); return hostCfg.protected || hostCfg.user_auth ? res.sendFile(views.login) : res.sendFile(views.landing); } + } else { + const allowRoomAccess = isAllowedRoomAccess('/join/params', req, hostCfg, authHost, roomList, room); + const roomAllowedForUser = isRoomAllowedForUser('Direct Join with token', name, room); + if (!allowRoomAccess && !roomAllowedForUser) { + return res.status(401).json({ message: 'Direct Room Join Unauthorized' }); + } } const OIDCUserAuthenticated = OIDC.enabled && req.oidc.isAuthenticated(); @@ -1061,6 +1069,11 @@ function startServer() { } else { return cb('unauthorized'); } + + const roomAllowedForUser = isRoomAllowedForUser('[Join]', peer_name, room.id); + if (!roomAllowedForUser) { + return cb('notAllowed'); + } } // check if banned... @@ -1137,6 +1150,13 @@ function startServer() { return cb('isLobby'); } + if ((hostCfg.protected || hostCfg.user_auth) && isPresenter) { + const roomAllowedForUser = isRoomAllowedForUser('[Join]', peer_name, room.id); + if (!roomAllowedForUser) { + return cb('notAllowed'); + } + } + // SCENARIO: Notify when the first user join room and is awaiting assistance... if (room.getPeersCount() === 1) { nodemailer.sendEmailAlert('join', { @@ -2409,6 +2429,13 @@ function startServer() { const roomExist = roomList.has(roomId); const roomCount = roomList.size; + const allowRoomAccess = + (!hostCfg.protected && !OIDC.enabled) || // No host protection and OIDC mode enabled (default) + OIDCUserAuthenticated || // User authenticated via OIDC + hostUserAuthenticated || // User authenticated via Login + ((OIDCUserAuthenticated || hostUserAuthenticated) && roomCount === 0) || // User authenticated joins the first room + roomExist; // User Or Guest join an existing Room + log.debug(logMessage, { OIDCUserEnabled: OIDC.enabled, OIDCUserAuthenticated: OIDCUserAuthenticated, @@ -2419,18 +2446,43 @@ function startServer() { roomExist: roomExist, roomCount: roomCount, roomId: roomId, + allowRoomAccess: allowRoomAccess, }); - const allowRoomAccess = - (!hostCfg.protected && !OIDC.enabled) || // No host protection and OIDC mode enabled (default) - OIDCUserAuthenticated || // User authenticated via OIDC - hostUserAuthenticated || // User authenticated via Login - ((OIDCUserAuthenticated || hostUserAuthenticated) && roomCount === 0) || // User authenticated joins the first room - roomExist; // User Or Guest join an existing Room - return allowRoomAccess; } + function isRoomAllowedForUser(message, username, room) { + log.debug('isRoomAllowedForUser ------>', { message, username, room }); + + if (hostCfg.protected || hostCfg.user_auth) { + const isInPresenterLists = config.presenters.list.includes(username); + + if (isInPresenterLists) { + log.debug('isRoomAllowedForUser - user in presenters list room allowed', room); + return true; + } + + const user = hostCfg.users.find((user) => user.username === username); + + if (!user) { + log.debug('isRoomAllowedForUser - user not found', username); + return false; + } + + if (!user.allowed_rooms || user.allowed_rooms.includes('*') || user.allowed_rooms.includes(room)) { + log.debug('isRoomAllowedForUser - user room allowed', room); + return true; + } + + log.debug('isRoomAllowedForUser - user room not allowed', room); + return false; + } + + log.debug('isRoomAllowedForUser - No host protected or user_auth enabled, user room allowed', room); + return true; + } + async function getPeerGeoLocation(ip) { const endpoint = config.IPLookup.getEndpoint(ip); log.debug('Get peer geo', { ip: ip, endpoint: endpoint }); diff --git a/app/src/config.template.js b/app/src/config.template.js index 8f7b1afc..c3a7d87a 100644 --- a/app/src/config.template.js +++ b/app/src/config.template.js @@ -139,10 +139,16 @@ module.exports = { { username: 'username', password: 'password', + allowed_rooms: ['*'], }, { username: 'username2', password: 'password2', + allowed_rooms: ['room1', 'room2'], + }, + { + username: 'username3', + password: 'password3', }, //... ], diff --git a/package.json b/package.json index 12a7be16..0ef0fc0f 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "mirotalksfu", - "version": "1.4.47", + "version": "1.4.48", "description": "WebRTC SFU browser-based video calls", "main": "Server.js", "scripts": { @@ -58,7 +58,7 @@ "mediasoup-client": "3.7.8", "ngrok": "^5.0.0-beta.2", "nodemailer": "^6.9.13", - "openai": "^4.49.0", + "openai": "^4.49.1", "qs": "6.12.1", "socket.io": "4.7.5", "swagger-ui-express": "5.0.1", diff --git a/public/js/Room.js b/public/js/Room.js index 1b699cdc..3b9f944d 100644 --- a/public/js/Room.js +++ b/public/js/Room.js @@ -11,7 +11,7 @@ if (location.href.substr(0, 5) !== 'https') location.href = 'https' + location.h * @license For commercial or closed source, contact us at license.mirotalk@gmail.com or purchase directly via CodeCanyon * @license CodeCanyon: https://codecanyon.net/item/mirotalk-sfu-webrtc-realtime-video-conferences/40769970 * @author Miroslav Pejic - miroslav.pejic.85@gmail.com - * @version 1.4.47 + * @version 1.4.48 * */ diff --git a/public/js/RoomClient.js b/public/js/RoomClient.js index 7c5f0430..0d6e0e4c 100644 --- a/public/js/RoomClient.js +++ b/public/js/RoomClient.js @@ -9,7 +9,7 @@ * @license For commercial or closed source, contact us at license.mirotalk@gmail.com or purchase directly via CodeCanyon * @license CodeCanyon: https://codecanyon.net/item/mirotalk-sfu-webrtc-realtime-video-conferences/40769970 * @author Miroslav Pejic - miroslav.pejic.85@gmail.com - * @version 1.4.47 + * @version 1.4.48 * */ @@ -379,6 +379,12 @@ class RoomClient { .request('join', data) .then(async (room) => { console.log('##### JOIN ROOM #####', room); + if (room === 'notAllowed') { + console.log( + '00-WARNING ----> Room is Unauthorized for current user, please provide a valid room name for this user', + ); + return this.userRoomNotAllowed(); + } if (room === 'unauthorized') { console.log( '00-WARNING ----> Room is Unauthorized for current user, please provide a valid username and password', @@ -5572,6 +5578,23 @@ class RoomClient { // HANDLE ROOM ACTION // #################################################### + userRoomNotAllowed() { + this.sound('alert'); + Swal.fire({ + allowOutsideClick: false, + allowEscapeKey: false, + background: swalBackground, + imageUrl: image.forbidden, + title: 'Oops, Room not allowed', + text: 'This room is not allowed for this user', + confirmButtonText: `OK`, + showClass: { popup: 'animate__animated animate__fadeInDown' }, + hideClass: { popup: 'animate__animated animate__fadeOutUp' }, + }).then(() => { + openURL(`/`); // Select the new allowed room name for this user and login to join + }); + } + userUnauthorized() { this.sound('alert'); Swal.fire({