[mirotalksfu] - Fix Room Password & Lobby

هذا الالتزام موجود في:
Miroslav Pejic
2025-04-09 12:59:10 +02:00
الأصل f69b201ecc
التزام 8e7dd48879
7 ملفات معدلة مع 121 إضافات و42 حذوفات

عرض الملف

@@ -108,13 +108,14 @@
<br/> <br/>
- You can `directly join a room` by using link like: - You can `directly join a room` by using link like:
- https://sfu.mirotalk.com/join?room=test&roomPassword=0&name=mirotalksfu&audio=0&video=0&screen=0&notify=0&duration=unlimited - https://sfu.mirotalk.com/join?room=test&roomPassword=0&name=mirotalksfu&avatar=0&audio=0&video=0&screen=0&notify=0&duration=unlimited
| Params | Type | Description | | Params | Type | Description |
| ------------ | -------------- | ------------------------- | | ------------ | -------------- | ------------------------- |
| room | string | Room Id | | room | string | Room Id |
| roomPassword | string/boolean | Room password | | roomPassword | string/boolean | Room password |
| name | string | User name | | name | string | User name |
| avatar | string/boolean | User avatar |
| audio | boolean | Audio stream | | audio | boolean | Audio stream |
| video | boolean | Video stream | | video | boolean | Video stream |
| screen | boolean | Screen stream | | screen | boolean | Screen stream |

عرض الملف

@@ -603,6 +603,7 @@ module.exports = class Room {
iceState: iceState, iceState: iceState,
}); });
this.removePeer(socket_id); this.removePeer(socket_id);
transport.close();
} }
}); });
@@ -622,6 +623,7 @@ module.exports = class Room {
dtlsState: dtlsState, dtlsState: dtlsState,
}); });
this.removePeer(socket_id); this.removePeer(socket_id);
transport.close();
} }
}); });

عرض الملف

@@ -64,7 +64,7 @@ dev dependencies: {
* @license For commercial or closed source, contact us at license.mirotalk@gmail.com or purchase directly via CodeCanyon * @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 * @license CodeCanyon: https://codecanyon.net/item/mirotalk-sfu-webrtc-realtime-video-conferences/40769970
* @author Miroslav Pejic - miroslav.pejic.85@gmail.com * @author Miroslav Pejic - miroslav.pejic.85@gmail.com
* @version 1.8.13 * @version 1.8.14
* *
*/ */

عرض الملف

@@ -1,6 +1,6 @@
{ {
"name": "mirotalksfu", "name": "mirotalksfu",
"version": "1.8.13", "version": "1.8.14",
"description": "WebRTC SFU browser-based video calls", "description": "WebRTC SFU browser-based video calls",
"main": "Server.js", "main": "Server.js",
"scripts": { "scripts": {
@@ -59,7 +59,7 @@
"dependencies": { "dependencies": {
"@mattermost/client": "10.6.0", "@mattermost/client": "10.6.0",
"@ngrok/ngrok": "1.4.1", "@ngrok/ngrok": "1.4.1",
"@sentry/node": "^9.11.0", "@sentry/node": "^9.12.0",
"axios": "^1.8.4", "axios": "^1.8.4",
"chokidar": "^4.0.3", "chokidar": "^4.0.3",
"colors": "1.4.0", "colors": "1.4.0",
@@ -81,7 +81,7 @@
"mediasoup": "3.15.7", "mediasoup": "3.15.7",
"mediasoup-client": "3.9.5", "mediasoup-client": "3.9.5",
"nodemailer": "^6.10.0", "nodemailer": "^6.10.0",
"openai": "^4.92.1", "openai": "^4.93.0",
"qs": "6.14.0", "qs": "6.14.0",
"sanitize-filename": "^1.6.3", "sanitize-filename": "^1.6.3",
"socket.io": "4.8.1", "socket.io": "4.8.1",
@@ -99,7 +99,7 @@
"proxyquire": "^2.1.3", "proxyquire": "^2.1.3",
"should": "^13.2.3", "should": "^13.2.3",
"sinon": "^20.0.0", "sinon": "^20.0.0",
"webpack": "^5.99.1", "webpack": "^5.99.5",
"webpack-cli": "^6.0.1" "webpack-cli": "^6.0.1"
} }
} }

عرض الملف

@@ -64,7 +64,7 @@ let BRAND = {
}, },
about: { about: {
imageUrl: '../images/mirotalk-logo.gif', imageUrl: '../images/mirotalk-logo.gif',
title: '<strong>WebRTC SFU v1.8.13</strong>', title: '<strong>WebRTC SFU v1.8.14</strong>',
html: ` html: `
<button <button
id="support-button" id="support-button"

عرض الملف

@@ -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 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 * @license CodeCanyon: https://codecanyon.net/item/mirotalk-sfu-webrtc-realtime-video-conferences/40769970
* @author Miroslav Pejic - miroslav.pejic.85@gmail.com * @author Miroslav Pejic - miroslav.pejic.85@gmail.com
* @version 1.8.13 * @version 1.8.14
* *
*/ */
@@ -5351,7 +5351,7 @@ function showAbout() {
position: 'center', position: 'center',
imageUrl: BRAND.about?.imageUrl && BRAND.about.imageUrl.trim() !== '' ? BRAND.about.imageUrl : image.about, imageUrl: BRAND.about?.imageUrl && BRAND.about.imageUrl.trim() !== '' ? BRAND.about.imageUrl : image.about,
customClass: { image: 'img-about' }, customClass: { image: 'img-about' },
title: BRAND.about?.title && BRAND.about.title.trim() !== '' ? BRAND.about.title : 'WebRTC SFU v1.8.13', title: BRAND.about?.title && BRAND.about.title.trim() !== '' ? BRAND.about.title : 'WebRTC SFU v1.8.14',
html: ` html: `
<br /> <br />
<div id="about"> <div id="about">

عرض الملف

@@ -9,7 +9,7 @@
* @license For commercial or closed source, contact us at license.mirotalk@gmail.com or purchase directly via CodeCanyon * @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 * @license CodeCanyon: https://codecanyon.net/item/mirotalk-sfu-webrtc-realtime-video-conferences/40769970
* @author Miroslav Pejic - miroslav.pejic.85@gmail.com * @author Miroslav Pejic - miroslav.pejic.85@gmail.com
* @version 1.8.13 * @version 1.8.14
* *
*/ */
@@ -339,7 +339,14 @@ class RoomClient {
this.localAudioStream = null; this.localAudioStream = null;
this.localScreenStream = null; this.localScreenStream = null;
// Room Password
this.RoomIsLocked = false;
this.RoomPassword = false; this.RoomPassword = false;
this.RoomPasswordValid = false;
// Room Lobby
this.RoomIsLobby = false;
this.RoomLobbyAccepted = false;
this.transcription = transcription; this.transcription = transcription;
@@ -455,50 +462,53 @@ class RoomClient {
.request('join', data) .request('join', data)
.then(async (room) => { .then(async (room) => {
console.log('##### JOIN ROOM #####', room); console.log('##### JOIN ROOM #####', room);
if (room === 'invalid') { if (room === 'invalid') {
console.log('00-WARNING ----> Invalid Room name! Path traversal pattern detected!'); console.warn('00-WARNING ----> Invalid Room name! Path traversal pattern detected!');
return this.roomInvalid(); return this.roomInvalid();
} }
if (room === 'notAllowed') { if (room === 'notAllowed') {
console.log( console.warn(
'00-WARNING ----> Room is Unauthorized for current user, please provide a valid room name for this user', '00-WARNING ----> Room is Unauthorized for current user, please provide a valid room name for this user',
); );
return this.userRoomNotAllowed(); return this.userRoomNotAllowed();
} }
if (room === 'unauthorized') { if (room === 'unauthorized') {
console.log( console.warn(
'00-WARNING ----> Room is Unauthorized for current user, please provide a valid username and password', '00-WARNING ----> Room is Unauthorized for current user, please provide a valid username and password',
); );
return this.userUnauthorized(); return this.userUnauthorized();
} }
if (room === 'isLocked') { if (room === 'isLocked') {
this.RoomIsLocked = true;
this.event(_EVENTS.roomLock); this.event(_EVENTS.roomLock);
console.log('00-WARNING ----> Room is Locked, Try to unlock by the password'); console.warn('00-WARNING ----> Room is Locked, Try to unlock by the password');
return this.unlockTheRoom(); return this.unlockTheRoom();
} }
if (room === 'isLobby') { if (room === 'isLobby') {
this.RoomIsLobby = true;
this.event(_EVENTS.lobbyOn); this.event(_EVENTS.lobbyOn);
console.log('00-WARNING ----> Room Lobby Enabled, Wait to confirm my join'); console.warn('00-WARNING ----> Room Lobby Enabled, Wait to confirm my join');
return this.waitJoinConfirm(); return this.waitJoinConfirm();
} }
if (room === 'isBanned') { if (room === 'isBanned') {
console.log('00-WARNING ----> You are Banned from the Room!'); console.warn('00-WARNING ----> You are Banned from the Room!');
return this.isBanned(); return this.isBanned();
} }
// ########################################## // ##########################################
this.peers = new Map(JSON.parse(room.peers)); this.peers = new Map(JSON.parse(room.peers));
// ########################################## // ##########################################
if (!peer_info.peer_token) { if (this.usernameExists(this.peers)) {
// hack... return this.userNameAlreadyInRoom();
for (let peer of Array.from(this.peers.keys()).filter((id) => id !== this.peer_id)) {
let peer_info = this.peers.get(peer).peer_info;
if (peer_info.peer_name == this.peer_name) {
console.log('00-WARNING ----> Username already in use');
return this.userNameAlreadyInRoom();
}
}
} }
await this.joinAllowed(room); await this.joinAllowed(room);
}) })
.catch((error) => { .catch((error) => {
@@ -508,19 +518,31 @@ class RoomClient {
}); });
} }
usernameExists(peers) {
if (!peer_info.peer_token) {
// hack...
for (let peer of Array.from(peers.keys()).filter((id) => id !== this.peer_id)) {
let peer_info = peers.get(peer).peer_info;
if (peer_info.peer_name == this.peer_name) {
console.log('07.0-WARNING ----> Username already in use');
return true;
}
}
}
return false;
}
async joinAllowed(room) { async joinAllowed(room) {
console.log('07 ----> Join Room allowed'); console.log('07 ----> Join Room allowed');
await this.handleRoomInfo(room); await this.handleRoomInfo(room);
const routerRtpCapabilities = await this.socket.request('getRouterRtpCapabilities');
routerRtpCapabilities.headerExtensions = routerRtpCapabilities.headerExtensions.filter( await this.loadDeviceAndInitTransports();
(ext) => ext.uri !== 'urn:3gpp:video-orientation',
); // ###############################################
this.device = await this.loadDevice(routerRtpCapabilities); this.socket.emit('getProducers'); // newProducers
console.log('07.3 ----> Get Router Rtp Capabilities codecs: ', this.device.rtpCapabilities.codecs); // ###############################################
await this.initTransports(this.device);
// ###################################
this.socket.emit('getProducers');
// ###################################
if (isBroadcastingEnabled) { if (isBroadcastingEnabled) {
isPresenter ? await this.startLocalMedia() : this.handleRoomBroadcasting(); isPresenter ? await this.startLocalMedia() : this.handleRoomBroadcasting();
} else { } else {
@@ -528,12 +550,34 @@ class RoomClient {
} }
} }
async loadDeviceAndInitTransports() {
// Get Router Capabilities
const routerRtpCapabilities = await this.socket.request('getRouterRtpCapabilities');
routerRtpCapabilities.headerExtensions = routerRtpCapabilities.headerExtensions.filter(
(ext) => ext.uri !== 'urn:3gpp:video-orientation',
);
// Load device
this.device = await this.loadDevice(routerRtpCapabilities);
console.log('07.3 ----> Get Router Rtp Capabilities codecs: ', this.device.rtpCapabilities.codecs);
// Init Send/Receive Transports
await this.initTransports(this.device);
}
async handleRoomInfo(room) { async handleRoomInfo(room) {
// ##########################################
this.peers = new Map(JSON.parse(room.peers));
// ##########################################
console.log('07.0 ----> Room Survey', room.survey); console.log('07.0 ----> Room Survey', room.survey);
survey = room.survey; survey = room.survey;
console.log('07.0 ----> Room Leave Redirect', room.redirect); console.log('07.0 ----> Room Leave Redirect', room.redirect);
redirect = room.redirect; redirect = room.redirect;
participantsCount = this.peers.size; participantsCount = this.peers.size;
// ME // ME
for (let peer of Array.from(this.peers.keys()).filter((id) => id == this.peer_id)) { for (let peer of Array.from(this.peers.keys()).filter((id) => id == this.peer_id)) {
let my_peer_info = this.peers.get(peer).peer_info; let my_peer_info = this.peers.get(peer).peer_info;
@@ -1075,7 +1119,28 @@ class RoomClient {
handleNewProducers = async (data) => { handleNewProducers = async (data) => {
if (data.length > 0) { if (data.length > 0) {
console.log('SocketOn New producers', data); console.log('SocketOn New producers', {
data,
password: {
roomIsLocked: this.RoomIsLocked,
roomPasswordValid: this.RoomPasswordValid,
},
lobby: {
roomIsLobby: this.RoomIsLobby,
roomLobbyAccepted: this.RoomLobbyAccepted,
}
});
if (this.RoomIsLocked && !this.RoomPasswordValid) {
console.log('Access denied: Room is locked and password has not been validated yet', data);
return;
}
if (this.RoomIsLobby && !this.RoomLobbyAccepted) {
console.log('Access pending: Lobby mode is active, waiting for approval to join', data);
return;
}
for (let { producer_id, peer_name, peer_info, type } of data) { for (let { producer_id, peer_name, peer_info, type } of data) {
await this.consume(producer_id, peer_name, peer_info, type); await this.consume(producer_id, peer_name, peer_info, type);
} }
@@ -2735,6 +2800,15 @@ class RoomClient {
} }
async getConsumeStream(producerId, peer_id, type) { async getConsumeStream(producerId, peer_id, type) {
if (!this.device) {
throw new Error('Device not initialized');
}
// Check if consumer transport exists
if (!this.consumerTransport) {
throw new Error('Consumer transport not initialized');
}
const { rtpCapabilities } = this.device; const { rtpCapabilities } = this.device;
const data = await this.socket.request('consume', { const data = await this.socket.request('consume', {
@@ -7303,13 +7377,14 @@ class RoomClient {
} }
} }
roomPassword(data) { async roomPassword(data) {
switch (data.password) { switch (data.password) {
case 'OK': case 'OK':
this.joinAllowed(data.room); this.RoomPasswordValid = true;
handleRules(isPresenter); await this.joinAllowed(data.room);
break; break;
case 'KO': case 'KO':
this.RoomPasswordValid = false;
this.roomIsLocked(); this.roomIsLocked();
break; break;
default: default:
@@ -7335,7 +7410,7 @@ class RoomClient {
peer_avatar && this.isImageURL(peer_avatar) peer_avatar && this.isImageURL(peer_avatar)
? peer_avatar ? peer_avatar
: this.isValidEmail(peer_name) : this.isValidEmail(peer_name)
? this.genGravatar(peer_name) ? this.genGravatar(peer_name, 32)
: this.genAvatarSvg(peer_name, 32); : this.genAvatarSvg(peer_name, 32);
let lobbyTb = this.getId('lobbyTb'); let lobbyTb = this.getId('lobbyTb');
@@ -7365,13 +7440,14 @@ class RoomClient {
} }
break; break;
case 'accept': case 'accept':
this.RoomLobbyAccepted = true;
await this.joinAllowed(data.room); await this.joinAllowed(data.room);
handleRules(isPresenter);
control.style.display = 'flex'; control.style.display = 'flex';
bottomButtons.style.display = 'flex'; bottomButtons.style.display = 'flex';
this.msgPopup('info', 'Your join meeting request was accepted by the moderator'); this.msgPopup('info', 'Your join meeting request was accepted by the moderator', 3000, 'top');
break; break;
case 'reject': case 'reject':
this.RoomLobbyAccepted = false;
this.sound('eject'); this.sound('eject');
Swal.fire({ Swal.fire({
icon: 'warning', icon: 'warning',