diff --git a/HAproxy.md b/HAproxy.md index 095a6bf..b738097 100644 --- a/HAproxy.md +++ b/HAproxy.md @@ -83,7 +83,7 @@ trustProxy : ['192.0.2.5'], ## Deploy HA proxy -* Configure cerificate / letsencrypt for `meet.example.com` +* Configure certificate / letsencrypt for `meet.example.com` * In this example we put a complete chain and private key in /root/certificate.pem. * Install and setup haproxy diff --git a/LTI/LTI.md b/LTI/LTI.md index ff6b9ec..15b6e6e 100644 --- a/LTI/LTI.md +++ b/LTI/LTI.md @@ -2,7 +2,7 @@ ## LTI -Read more about IMS Global defined interface for tools like our VideoConference system integration with Learning Managment Systems(LMS) (e.g. moodle). +Read more about IMS Global defined interface for tools like our VideoConference system integration with Learning Management Systems(LMS) (e.g. moodle). See: [IMS Global Learning Tool Interoperability](https://www.imsglobal.org/activity/learning-tools-interoperability) We implemented LTI interface version 1.0/1.1 @@ -57,5 +57,5 @@ Open fully the settings **Click on show more!!** ## moodle plugin -Alternativly you can use multipartymeeting moodle plugin: +Alternatively you can use multipartymeeting moodle plugin: [https://github.com/misi/moodle-mod_multipartymeeting](https://github.com/misi/moodle-mod_multipartymeeting) diff --git a/README.md b/README.md index 0a47de2..de7fb96 100644 --- a/README.md +++ b/README.md @@ -23,7 +23,7 @@ If you want the ansible approach, you can find ansible role [here](https://githu ## Manual installation * Prerequisites: -Currently multiparty-meeting will only run on nodejs v10.* +Currently multiparty-meeting will only run on nodejs v13.x To install see here [here](https://github.com/nodesource/distributions/blob/master/README.md#debinstall). ```bash @@ -76,7 +76,7 @@ $ npm install $ cd server $ npm start ``` -* Note: Do not run the server as root. If you need to use port 80/443 make a iptables-mapping for that or use systemd configuration for that (see futher down this doc). +* Note: Do not run the server as root. If you need to use port 80/443 make a iptables-mapping for that or use systemd configuration for that (see further down this doc). * Test your service in a webRTC enabled browser: `https://yourDomainOrIPAdress:3443/roomname` ## Deploy it in a server @@ -102,7 +102,7 @@ $ systemctl enable multiparty-meeting ## Ports and firewall * 3443/tcp (default https webserver and signaling - adjustable in `server/config.js`) -* 4443/tcp (default `npm start` port for developing with live browser reload, not needed in production enviroments - adjustable in app/package.json) +* 4443/tcp (default `npm start` port for developing with live browser reload, not needed in production environments - adjustable in app/package.json) * 40000-49999/udp/tcp (media ports - adjustable in `server/config.js`) ## Load balanced installation @@ -113,7 +113,7 @@ To integrate with an LMS (e.g. Moodle), have a look at [LTI](LTI/LTI.md). ## TURN configuration -* You need an addtional [TURN](https://github.com/coturn/coturn)-server for clients located behind restrictive firewalls! Add your server and credentials to `app/config.js` +* You need an additional [TURN](https://github.com/coturn/coturn)-server for clients located behind restrictive firewalls! Add your server and credentials to `app/config.js` ## Authors diff --git a/app/package.json b/app/package.json index d68f4f3..fc6c575 100644 --- a/app/package.json +++ b/app/package.json @@ -29,7 +29,7 @@ "react-intl": "^3.4.0", "react-redux": "^7.1.1", "react-router-dom": "^5.1.2", - "react-scripts": "3.0.1", + "react-scripts": "3.4.1", "react-wakelock-react16": "0.0.7", "redux": "^4.0.4", "redux-logger": "^3.0.6", diff --git a/app/src/RoomClient.js b/app/src/RoomClient.js index 747401b..8d0e01f 100644 --- a/app/src/RoomClient.js +++ b/app/src/RoomClient.js @@ -151,7 +151,7 @@ export default class RoomClient // Whether we should produce. this._produce = produce; - // Wheter we force TCP + // Whether we force TCP this._forceTcp = forceTcp; // Use displayName @@ -282,7 +282,7 @@ export default class RoomClient _startKeyListener() { - // Add keypress event listner on document + // Add keydown event listener on document document.addEventListener('keydown', (event) => { if (event.repeat) return; @@ -626,7 +626,7 @@ export default class RoomClient type : 'error', text : intl.formatMessage({ id : 'room.changeDisplayNameError', - defaultMessage : 'An error occured while changing your display name' + defaultMessage : 'An error occurred while changing your display name' }) })); } @@ -1065,7 +1065,7 @@ export default class RoomClient { // The exact formula to convert from dBs (-100..0) to linear (0..1) is: // Math.pow(10, dBs / 20) - // However it does not produce a visually useful output, so let exagerate + // However it does not produce a visually useful output, so let exaggerate // it a bit. Also, let convert it from 0..1 to 0..10 and avoid value 1 to // minimize component renderings. let volume = Math.round(Math.pow(10, dBs / 85) * 10); @@ -1136,7 +1136,8 @@ export default class RoomClient } }); - if(stream){ + if (stream) + { const track = stream.getVideoTracks()[0]; if (track) @@ -1155,8 +1156,7 @@ export default class RoomClient } }); } - - + store.dispatch( producerActions.setProducerTrack(this._webcamProducer.id, track)); } @@ -1840,7 +1840,7 @@ export default class RoomClient { // The exact formula to convert from dBs (-100..0) to linear (0..1) is: // Math.pow(10, dBs / 20) - // However it does not produce a visually useful output, so let exagerate + // However it does not produce a visually useful output, so let exaggerate // it a bit. Also, let convert it from 0..1 to 0..10 and avoid value 1 to // minimize component renderings. let volume = Math.round(Math.pow(10, dBs / 85) * 10); @@ -2628,7 +2628,7 @@ export default class RoomClient this.updateSpotlights(spotlights); }); - // Don't produce if explicitely requested to not to do it. + // Don't produce if explicitly requested to not to do it. if (this._produce) { if (this._mediasoupDevice.canProduce('audio')) @@ -2645,7 +2645,7 @@ export default class RoomClient store.dispatch(roomActions.setRoomState('connected')); - // Clean all the existing notifcations. + // Clean all the existing notifications. store.dispatch(notificationActions.removeAllNotifications()); this.getServerHistory(); @@ -2834,7 +2834,7 @@ export default class RoomClient const stream = await navigator.mediaDevices.getUserMedia( { audio : { - deviceId : { exact: deviceId } + deviceId : { ideal: deviceId } } } ); @@ -2912,7 +2912,7 @@ export default class RoomClient { // The exact formula to convert from dBs (-100..0) to linear (0..1) is: // Math.pow(10, dBs / 20) - // However it does not produce a visually useful output, so let exagerate + // However it does not produce a visually useful output, so let exaggerate // it a bit. Also, let convert it from 0..1 to 0..10 and avoid value 1 to // minimize component renderings. let volume = Math.round(Math.pow(10, dBs / 85) * 10); @@ -2947,7 +2947,7 @@ export default class RoomClient type : 'error', text : intl.formatMessage({ id : 'devices.microphoneError', - defaultMessage : 'An error occured while accessing your microphone' + defaultMessage : 'An error occurred while accessing your microphone' }) })); @@ -3114,7 +3114,7 @@ export default class RoomClient type : 'error', text : intl.formatMessage({ id : 'devices.screenSharingError', - defaultMessage : 'An error occured while accessing your screen' + defaultMessage : 'An error occurred while accessing your screen' }) })); @@ -3192,7 +3192,7 @@ export default class RoomClient { video : { - deviceId : { exact: deviceId }, + deviceId : { ideal: deviceId }, ...VIDEO_CONSTRAINS[resolution] } }); @@ -3287,7 +3287,7 @@ export default class RoomClient type : 'error', text : intl.formatMessage({ id : 'devices.cameraError', - defaultMessage : 'An error occured while accessing your camera' + defaultMessage : 'An error occurred while accessing your camera' }) })); diff --git a/app/src/__tests__/RoomClient.spec.js b/app/src/__tests__/RoomClient.spec.js index 086e6a5..5e1191c 100644 --- a/app/src/__tests__/RoomClient.spec.js +++ b/app/src/__tests__/RoomClient.spec.js @@ -1,6 +1,6 @@ import RoomClient from '../RoomClient'; -describe('new RoomClient() without paramaters throws Error', () => +describe('new RoomClient() without parameters throws Error', () => { test('Matches the snapshot', () => { diff --git a/app/src/components/App.js b/app/src/components/App.js index 0b6b473..6d98847 100644 --- a/app/src/components/App.js +++ b/app/src/components/App.js @@ -14,7 +14,7 @@ const App = (props) => room } = props; - const { id } = useParams(); + const id = useParams().id.toLowerCase(); useEffect(() => { diff --git a/app/src/components/Selectors.js b/app/src/components/Selectors.js index 34bb647..a87ce16 100644 --- a/app/src/components/Selectors.js +++ b/app/src/components/Selectors.js @@ -82,7 +82,7 @@ export const spotlightSortedPeersSelector = createSelector( spotlightsSelector, peersValueSelector, (spotlights, peers) => peers.filter((peer) => spotlights.includes(peer.id)) - .sort((a, b) => a.displayName.localeCompare(b.displayName)) + .sort((a, b) => String(a.displayName || '').localeCompare(String(b.displayName || ''))) ); export const peersLengthSelector = createSelector( @@ -94,7 +94,7 @@ export const passivePeersSelector = createSelector( peersValueSelector, spotlightsSelector, (peers, spotlights) => peers.filter((peer) => !spotlights.includes(peer.id)) - .sort((a, b) => a.displayName.localeCompare(b.displayName)) + .sort((a, b) => String(a.displayName || '').localeCompare(String(b.displayName || ''))) ); export const videoBoxesSelector = createSelector( diff --git a/app/src/reducers/lobbyPeers.js b/app/src/reducers/lobbyPeers.js index fef9190..4cf9cc1 100644 --- a/app/src/reducers/lobbyPeers.js +++ b/app/src/reducers/lobbyPeers.js @@ -44,7 +44,7 @@ const lobbyPeers = (state = {}, action) => if (!oldLobbyPeer) { - // Tried to update non-existant lobbyPeer. Has probably been promoted, or left. + // Tried to update non-existent lobbyPeer. Has probably been promoted, or left. return state; } diff --git a/app/src/translations/hr.json b/app/src/translations/hr.json index 5f0d6a6..120b1a5 100644 --- a/app/src/translations/hr.json +++ b/app/src/translations/hr.json @@ -6,7 +6,7 @@ "room.chooseRoom": "Izaberite ime sobe u koju se želite prijaviti", "room.cookieConsent": "Ova stranica koristi kolačiće radi poboljšanja korisničkog iskustva", - "room.consentUnderstand": "I understand", + "room.consentUnderstand": "Razumijem", "room.joined": "Prijavljeni ste u sobu", "room.cantJoin": "Prijava u sobu nije moguća", "room.youLocked": "Zaključali ste sobu", @@ -15,10 +15,10 @@ "room.cantUnLock": "Otključavanje sobe nije moguće", "room.locked": "Soba je sada zaključana", "room.unlocked": "Soba je sada otključana", - "room.newLobbyPeer": "U predvorju je novi učesnik", - "room.lobbyPeerLeft": "Učesnik je napustio predvorje", - "room.lobbyPeerChangedDisplayName": "Učesnik u predvorju je promijenio ime u {displayName}", - "room.lobbyPeerChangedPicture": "Učesnik u predvorju je promijenio sliku", + "room.newLobbyPeer": "Novi sudionik čeka u predvorju", + "room.lobbyPeerLeft": "Sudionik je napustio predvorje", + "room.lobbyPeerChangedDisplayName": "Sudionik u predvorju je promijenio ime u {displayName}", + "room.lobbyPeerChangedPicture": "Sudionik u predvorju je promijenio sliku", "room.setAccessCode": "Obnovljena pristupna šifra za sobu", "room.accessCodeOn": "Pristupna šifra sobe je aktivna", "room.accessCodeOff":"Pristupna šifra sobe je neaktivna", @@ -40,21 +40,21 @@ "room.audioVideo": "Zvuk i slika", "room.youAreReady": "Spremni ste", "room.emptyRequireLogin": "Soba je trenutno prazna! Prijavite se za pokretanje sastanka, ili sačekajte organizatora" , - "room.locketWait": "Soba je zaključana - pričekajte odobrenje ...", + "room.locketWait": "Soba je zaključana - pričekajte odobrenje...", "room.lobbyAdministration":"Upravljanje predvorjem", - "room.peersInLobby":"Učesnici u predvorju", + "room.peersInLobby":"Sudionici u predvorju", "room.lobbyEmpty": "Trenutno nema nikoga u predvorju", "room.hiddenPeers": "{hiddenPeersCount, plural, one {participant} other {participants}}", "room.me": "Ja", - "room.spotlights": "Učesnici u fokusu", - "room.passive": "Pasivni učesnici", + "room.spotlights": "Sudionici u fokusu", + "room.passive": "Pasivni sudionici", "room.videoPaused": "Video pauziran", - "room.muteAll": null, - "room.stopAllVideo": null, - "room.closeMeeting": null, - "room.speechUnsupported": null, + "room.muteAll": "Utišaj sve", + "room.stopAllVideo": "Ugasi sve kamere", + "room.closeMeeting": "Završi sastanak", + "room.speechUnsupported": "Vaš preglednik ne podržava prepoznavanje govora", - "me.mutedPTT": null, + "me.mutedPTT": "Utišani ste, pritisnite i držite SPACE tipku za razgovor", "tooltip.login": "Prijava", "tooltip.logout": "Odjava", @@ -66,7 +66,7 @@ "tooltip.lobby": "Prikaži predvorje", "tooltip.settings": "Prikaži postavke", "tooltip.participants": "Pokažite sudionike", - "tooltip.kickParticipant": null, + "tooltip.kickParticipant": "Izbaci sudionika", "label.roomName": "Naziv sobe", "label.chooseRoomButton": "Nastavi", @@ -78,7 +78,7 @@ "label.chatInput":"Uđi u razgovor porukama", "label.chat": "Razgovor", "label.filesharing": "Dijeljenje datoteka", - "label.participants": "Učesnici", + "label.participants": "Sudionici", "label.shareFile": "Dijeli datoteku", "label.fileSharingUnsupported": "Dijeljenje datoteka nije podržano", "label.unknown": "Nepoznato", diff --git a/munin/mm-plugin b/munin/mm-plugin index d319ad1..978995b 100755 --- a/munin/mm-plugin +++ b/munin/mm-plugin @@ -42,7 +42,7 @@ fi if [ "$1" = "config" ]; then echo 'graph_title MM stats' #echo 'graph_args --base 1000 -l 0' - echo 'graph_vlabel Actual Seesion Count' + echo 'graph_vlabel Actual Session Count' echo 'graph_category other' echo 'graph_info This graph shows the mm stats.' echo 'rooms.label rooms' diff --git a/server/config/config.example.js b/server/config/config.example.js index ada1553..32ca836 100644 --- a/server/config/config.example.js +++ b/server/config/config.example.js @@ -38,6 +38,13 @@ module.exports = // URI and key for requesting geoip-based TURN server closest to the client turnAPIKey : 'examplekey', turnAPIURI : 'https://example.com/api/turn', + turnAPIparams : { + 'uri_schema' : 'turn', + 'transport' : 'tcp', + 'ip_ver' : 'ipv4', + 'servercount' : '2' + }, + // Backup turnservers if REST fails or is not configured backupTurnServers : [ { @@ -59,7 +66,7 @@ module.exports = key : `${__dirname}/../certs/mediasoup-demo.localhost.key.pem` }, // listening Host or IP - // If ommitted listens on every IP. ("0.0.0.0" and "::") + // If omitted listens on every IP. ("0.0.0.0" and "::") //listeningHost: 'localhost', // Listening port for https server. listeningPort : 443, diff --git a/server/lib/Room.js b/server/lib/Room.js index f75ec29..b436671 100644 --- a/server/lib/Room.js +++ b/server/lib/Room.js @@ -383,10 +383,7 @@ class Room extends EventEmitter config.turnAPIURI, { params : { - 'uri_schema' : 'turn', - 'transport' : 'tcp', - 'ip_ver' : 'ipv4', - 'servercount' : '2', + ...config.turnAPIparams, 'api_key' : config.turnAPIKey, 'ip' : peer.socket.request.connection.remoteAddress } diff --git a/server/server.js b/server/server.js index 9253bec..e2eeb5b 100755 --- a/server/server.js +++ b/server/server.js @@ -203,7 +203,7 @@ function setupLTI(ltiConfig) if (lti.user_id && lti.custom_room) { user.id = lti.user_id; - user._lti = lti; + user._userinfo = { "lti" : lti }; } if (lti.custom_room) @@ -259,12 +259,15 @@ function setupOIDC(oidcIssuer) { client: oidcClient, params, passReqToCallback, usePKCE }, (tokenset, userinfo, done) => { + if (userinfo && tokenset) { + userinfo._tokenset_claims = tokenset.claims(); + } + const user = { id : tokenset.claims.sub, provider : tokenset.claims.iss, - _userinfo : userinfo, - _claims : tokenset.claims + _userinfo : userinfo }; return done(null, user);