diff --git a/app/src/RoomClient.js b/app/src/RoomClient.js index 81e4181..200cf85 100644 --- a/app/src/RoomClient.js +++ b/app/src/RoomClient.js @@ -1595,6 +1595,50 @@ export default class RoomClient }) })); + if (this._screenSharingProducer) + { + this._screenSharingProducer.close(); + + store.dispatch( + producerActions.removeProducer(this._screenSharingProducer.id)); + + this._screenSharingProducer = null; + } + + if (this._webcamProducer) + { + this._webcamProducer.close(); + + store.dispatch( + producerActions.removeProducer(this._webcamProducer.id)); + + this._webcamProducer = null; + } + + if (this._micProducer) + { + this._micProducer.close(); + + store.dispatch( + producerActions.removeProducer(this._micProducer.id)); + + this._micProducer = null; + } + + if (this._sendTransport) + { + this._sendTransport.close(); + + this._sendTransport = null; + } + + if (this._recvTransport) + { + this._recvTransport.close(); + + this._recvTransport = null; + } + store.dispatch(roomActions.setRoomState('connecting')); }); @@ -1796,6 +1840,13 @@ export default class RoomClient break; } + + case 'roomBack': + { + await this._joinRoom({ joinVideo }); + + break; + } case 'lockRoom': { diff --git a/server/lib/Room.js b/server/lib/Room.js index 18875e9..1afe7a7 100644 --- a/server/lib/Room.js +++ b/server/lib/Room.js @@ -2,6 +2,8 @@ const EventEmitter = require('events').EventEmitter; const axios = require('axios'); const Logger = require('./Logger'); const Lobby = require('./Lobby'); +const { v4: uuidv4 } = require('uuid'); +const jwt = require('jsonwebtoken'); const userRoles = require('../userRoles'); const config = require('../config/config'); @@ -46,6 +48,8 @@ class Room extends EventEmitter super(); this.setMaxListeners(Infinity); + this._uuid = uuidv4(); + // Room ID. this._roomId = roomId; @@ -120,22 +124,41 @@ class Room extends EventEmitter this.emit('close'); } - handlePeer(peer) + verifyPeer({ id, token }) { - logger.info('handlePeer() [peer:"%s", roles:"%s"]', peer.id, peer.roles); + try + { + const decoded = jwt.verify(token, this._uuid); - // Allow reconnections, remove old peer + logger.info('verifyPeer() [decoded:"%o"]', decoded); + + return decoded.id === id; + } + catch (err) + { + logger.warn('verifyPeer() | invalid token'); + } + + return false; + } + + handlePeer({ peer, returning }) + { + logger.info('handlePeer() [peer:"%s", roles:"%s", returning:"%s"]', peer.id, peer.roles, returning); + + // Should not happen if (this._peers[peer.id]) { logger.warn( 'handleConnection() | there is already a peer with same peerId [peer:"%s"]', peer.id); - - this._peers[peer.id].close(); } + // Returning user + if (returning) + this._peerJoining(peer, true); // Always let ADMIN in, even if locked - if (peer.roles.includes(userRoles.ADMIN)) + else if (peer.roles.includes(userRoles.ADMIN)) this._peerJoining(peer); else if (this._locked) this._parkPeer(peer); @@ -332,7 +355,7 @@ class Room extends EventEmitter } } - async _peerJoining(peer) + async _peerJoining(peer, returning = false) { peer.socket.join(this._roomId); @@ -343,45 +366,58 @@ class Room extends EventEmitter this._handlePeer(peer); - let turnServers; - - if ('turnAPIURI' in config) + if (returning) { - try - { - const { data } = await axios.get( - config.turnAPIURI, - { - params : { - 'uri_schema' : 'turn', - 'transport' : 'tcp', - 'ip_ver' : 'ipv4', - 'servercount' : '2', - 'api_key' : config.turnAPIKey, - 'ip' : peer.socket.request.connection.remoteAddress - } - }); - - turnServers = [ { - urls : data.uris, - username : data.username, - credential : data.password - } ]; - } - catch (error) - { - if ('backupTurnServers' in config) - turnServers = config.backupTurnServers; - - logger.error('_peerJoining() | error on REST turn [error:"%o"]', error); - } + this._notification(peer.socket, 'roomBack'); } - else if ('backupTurnServers' in config) + else { - turnServers = config.backupTurnServers; - } + const token = jwt.sign({ id: peer.id }, this._uuid, { noTimestamp: true }); - this._notification(peer.socket, 'roomReady', { turnServers }); + peer.socket.handshake.session.token = token; + + peer.socket.handshake.session.save(); + + let turnServers; + + if ('turnAPIURI' in config) + { + try + { + const { data } = await axios.get( + config.turnAPIURI, + { + params : { + 'uri_schema' : 'turn', + 'transport' : 'tcp', + 'ip_ver' : 'ipv4', + 'servercount' : '2', + 'api_key' : config.turnAPIKey, + 'ip' : peer.socket.request.connection.remoteAddress + } + }); + + turnServers = [ { + urls : data.uris, + username : data.username, + credential : data.password + } ]; + } + catch (error) + { + if ('backupTurnServers' in config) + turnServers = config.backupTurnServers; + + logger.error('_peerJoining() | error on REST turn [error:"%o"]', error); + } + } + else if ('backupTurnServers' in config) + { + turnServers = config.backupTurnServers; + } + + this._notification(peer.socket, 'roomReady', { turnServers }); + } } _handlePeer(peer) diff --git a/server/package.json b/server/package.json index b05676d..ae1f3b9 100644 --- a/server/package.json +++ b/server/package.json @@ -25,6 +25,7 @@ "express-socket.io-session": "^1.3.5", "helmet": "^3.21.2", "ims-lti": "^3.0.2", + "jsonwebtoken": "^8.5.1", "mediasoup": "^3.5.5", "openid-client": "^3.7.3", "passport": "^0.4.0", @@ -32,6 +33,7 @@ "pidusage": "^2.0.17", "redis": "^2.8.0", "socket.io": "^2.3.0", - "spdy": "^4.0.1" + "spdy": "^4.0.1", + "uuid": "^7.0.2" } } diff --git a/server/server.js b/server/server.js index ebf951e..c1c0f61 100755 --- a/server/server.js +++ b/server/server.js @@ -464,8 +464,28 @@ async function runWebSocketServer() queue.push(async () => { + const { token } = socket.handshake.session; + const room = await getOrCreateRoom({ roomId }); - const peer = new Peer({ id: peerId, roomId, socket }); + + let peer = peers.get(peerId); + let returning = false; + + if (peer && !token) + { // Don't allow hijacking sessions + socket.disconnect(true); + + return; + } + else if (token && room.verifyPeer({ id: peerId, token })) + { // Returning user, remove if old peer exists + if (peer) + peer.close(); + + returning = true; + } + + peer = new Peer({ id: peerId, roomId, socket }); peers.set(peerId, peer); @@ -495,7 +515,7 @@ async function runWebSocketServer() } } - room.handlePeer(peer); + room.handlePeer({ peer, returning }); }) .catch((error) => {