diff --git a/bigbluebutton-html5/imports/api/users/server/methods/kickUser.js b/bigbluebutton-html5/imports/api/users/server/methods/kickUser.js index ac08500ba75028082a1c0effb72051333785fa7c..86f189f8a562500544de2dba93216e7e4b27f75b 100755 --- a/bigbluebutton-html5/imports/api/users/server/methods/kickUser.js +++ b/bigbluebutton-html5/imports/api/users/server/methods/kickUser.js @@ -1,4 +1,4 @@ -import Meteor from 'meteor/meteor'; +import { Meteor } from 'meteor/meteor'; import { check } from 'meteor/check'; import RedisPubSub from '/imports/startup/server/redis'; import Logger from '/imports/startup/server/logger'; diff --git a/bigbluebutton-html5/imports/api/users/server/methods/listenOnlyRequestToggle.js b/bigbluebutton-html5/imports/api/users/server/methods/listenOnlyRequestToggle.js index 97ea0c07418ff661dc1f35f9a0ab589d2f98bad3..bf5a4e0f87e9f76cabe34072480839c1353c4c8e 100755 --- a/bigbluebutton-html5/imports/api/users/server/methods/listenOnlyRequestToggle.js +++ b/bigbluebutton-html5/imports/api/users/server/methods/listenOnlyRequestToggle.js @@ -1,4 +1,4 @@ -import Meteor from 'meteor/meteor'; +import { Meteor } from 'meteor/meteor'; import { check } from 'meteor/check'; import RedisPubSub from '/imports/startup/server/redis'; import Logger from '/imports/startup/server/logger'; diff --git a/bigbluebutton-html5/imports/api/users/server/methods/userLeaving.js b/bigbluebutton-html5/imports/api/users/server/methods/userLeaving.js index 776b135cf4341f2fafcbf25b99f7049d588764b2..bd5bb3ecb021543b86449b37f540c814cae2a4fb 100644 --- a/bigbluebutton-html5/imports/api/users/server/methods/userLeaving.js +++ b/bigbluebutton-html5/imports/api/users/server/methods/userLeaving.js @@ -1,9 +1,11 @@ -import Meteor from 'meteor/meteor'; +import { Meteor } from 'meteor/meteor'; import { check } from 'meteor/check'; import RedisPubSub from '/imports/startup/server/redis'; import Logger from '/imports/startup/server/logger'; import { isAllowedTo } from '/imports/startup/server/userPermissions'; +import Users from '/imports/api/users'; +import setConnectionStatus from '../modifiers/setConnectionStatus'; import listenOnlyRequestToggle from './listenOnlyRequestToggle'; export default function userLeaving(credentials, userId) { @@ -28,6 +30,8 @@ export default function userLeaving(credentials, userId) { 'user-not-found', `You need a valid user to be able to toggle audio`); } + setConnectionStatus(meetingId, requesterUserId, 'offline'); + if (User.user.listenOnly) { listenOnlyRequestToggle(credentials, false); } diff --git a/bigbluebutton-html5/imports/api/users/server/methods/userLogout.js b/bigbluebutton-html5/imports/api/users/server/methods/userLogout.js index 1b0176df362036efbe251c45e1a239060e87b569..4aeb73bed100d2ab3158da7bc34618eab9d76ebc 100755 --- a/bigbluebutton-html5/imports/api/users/server/methods/userLogout.js +++ b/bigbluebutton-html5/imports/api/users/server/methods/userLogout.js @@ -1,4 +1,4 @@ -import Meteor from 'meteor/meteor'; +import { Meteor } from 'meteor/meteor'; import { isAllowedTo } from '/imports/startup/server/userPermissions'; import userLeaving from './userLeaving'; diff --git a/bigbluebutton-html5/imports/api/users/server/methods/validateAuthToken.js b/bigbluebutton-html5/imports/api/users/server/methods/validateAuthToken.js index 0ceda1f59dbed39220e80315b167eab1b7f27091..b767b0538c1279f6245235b2af298b53b3aad092 100755 --- a/bigbluebutton-html5/imports/api/users/server/methods/validateAuthToken.js +++ b/bigbluebutton-html5/imports/api/users/server/methods/validateAuthToken.js @@ -1,34 +1,43 @@ -import { logger } from '/imports/startup/server/logger'; +import { Meteor } from 'meteor/meteor'; +import { check } from 'meteor/check'; +import RedisPubSub from '/imports/startup/server/redis'; +import Logger from '/imports/startup/server/logger'; +import { isAllowedTo } from '/imports/startup/server/userPermissions'; +import Users from '/imports/api/users'; + import { createDummyUser } from '/imports/api/users/server/modifiers/createDummyUser'; -import { publish } from '/imports/api/common/server/helpers'; - -Meteor.methods({ - // Construct and send a message to bbb-web to validate the user - validateAuthToken(credentials) { - const REDIS_CONFIG = Meteor.settings.redis; - const { meetingId, requesterUserId, requesterToken } = credentials; - logger.info('sending a validate_auth_token with', { - userid: requesterUserId, - authToken: requesterToken, - meetingid: meetingId, - }); - let message = { - payload: { - auth_token: requesterToken, - userid: requesterUserId, - meeting_id: meetingId, - }, - header: { - timestamp: new Date().getTime(), - reply_to: `${meetingId}/${requesterUserId}`, - name: 'validate_auth_token', - }, - }; - if ((requesterToken != null) && (requesterUserId != null) && (meetingId != null)) { - createDummyUser(meetingId, requesterUserId, requesterToken); - return publish(REDIS_CONFIG.channels.toBBBApps.meeting, message); - } else { - return logger.info('did not have enough information to send a validate_auth_token message'); - } - }, -}); + +export default function validateAuthToken(credentials) { + const REDIS_CONFIG = Meteor.settings.redis; + const CHANNEL = REDIS_CONFIG.channels.toBBBApps.meeting; + const EVENT_NAME = 'validate_auth_token'; + + const { meetingId, requesterUserId, requesterToken } = credentials; + + check(meetingId, String); + check(requesterUserId, String); + check(requesterToken, String); + + const User = Users.findOne({ + meetingId, + userId: requesterUserId, + }); + + if (!User) { + createDummyUser(meetingId, requesterUserId, requesterToken); + } + + let payload = { + auth_token: requesterToken, + userid: requesterUserId, + meeting_id: meetingId, + }; + + const header = { + reply_to: `${meetingId}/${requesterUserId}`, + }; + + Logger.verbose(`User '${requesterUserId}' is trying to validate auth token for meeting '${meetingId}'`); + + return RedisPubSub.publish(CHANNEL, EVENT_NAME, payload, header); +}; diff --git a/bigbluebutton-html5/imports/api/users/server/modifiers/requestUserLeaving.js b/bigbluebutton-html5/imports/api/users/server/modifiers/requestUserLeaving.js deleted file mode 100755 index 1d5e768fca672dfdc9e81d5c4064f4c8dea7eab3..0000000000000000000000000000000000000000 --- a/bigbluebutton-html5/imports/api/users/server/modifiers/requestUserLeaving.js +++ /dev/null @@ -1,82 +0,0 @@ -import { publish } from '/imports/api/common/server/helpers'; -import Meetings from '/imports/api/meetings'; -import Users from '/imports/api/users'; -import { logger } from '/imports/startup/server/logger'; - -// Corresponds to a valid action on the HTML clientside -// After authorization, publish a user_leaving_request in redis -// params: meetingid, userid as defined in BBB-App -export function requestUserLeaving(meetingId, userId) { - const REDIS_CONFIG = Meteor.settings.redis; - let voiceConf; - const userObject = Users.findOne({ - meetingId: meetingId, - userId: userId, - }); - const meetingObject = Meetings.findOne({ - meetingId: meetingId, - }); - - if (meetingObject != null) { - voiceConf = meetingObject.voiceConf; - } - - if ((userObject != null) && (voiceConf != null) && (userId != null) && (meetingId != null)) { - let lOnly = false; - if (userObject.hasOwnProperty('user') && userObject.user.hasOwnProperty('listenOnly')) { - lOnly = userObject.user.listenOnly; - } - - // end listenOnly audio for the departing user - if (lOnly) { - const listenOnlyMessage = { - payload: { - userid: userId, - meeting_id: meetingId, - voice_conf: voiceConf, - name: userObject.user.name, - }, - header: { - timestamp: new Date().getTime(), - name: 'user_disconnected_from_global_audio', - }, - }; - publish(REDIS_CONFIG.channels.toBBBApps.meeting, listenOnlyMessage); - } - - // remove user from meeting - const message = { - payload: { - meeting_id: meetingId, - userid: userId, - }, - header: { - timestamp: new Date().getTime(), - name: 'user_leaving_request', - }, - }; - logger.info(`sending a user_leaving_request for ${meetingId}:${userId}`); - return publish(REDIS_CONFIG.channels.toBBBApps.users, message); - } else { - return logger.info('did not have enough information to send a user_leaving_request'); - } -}; - - - - - - - - - - -if (this.connection == null) { - Meteor.users.update(update.id,{ - $set: { - "profile.name": update.name - } - }); -} else { - throw new Meteor.Error('server-only-method', 'Sorry, this method can only be called from the server.'); -} diff --git a/bigbluebutton-html5/imports/api/users/server/modifiers/setConnectionStatus.js b/bigbluebutton-html5/imports/api/users/server/modifiers/setConnectionStatus.js index c5a618f88e285cd616c6f24f1575731787ee1a88..f3fe568993f45194f1d6aa0d7aa217cf4ef3cdaa 100644 --- a/bigbluebutton-html5/imports/api/users/server/modifiers/setConnectionStatus.js +++ b/bigbluebutton-html5/imports/api/users/server/modifiers/setConnectionStatus.js @@ -7,7 +7,7 @@ const VALID_CONNECTION_STATUS = ['online', 'offline']; export default function setConnectionStatus(meetingId, userId, status = 'online') { check(meetingId, String); check(userId, String); - check(connectionStatus, String); + check(status, String); if (!VALID_CONNECTION_STATUS.includes(status)) { throw `Invalid connection status, received ${status} expecting ${VALID_CONNECTION_STATUS.join()}`; diff --git a/bigbluebutton-html5/imports/api/users/server/publications.js b/bigbluebutton-html5/imports/api/users/server/publications.js deleted file mode 100755 index 1b7edc1300078ede14a69d2664fd209856f42ef6..0000000000000000000000000000000000000000 --- a/bigbluebutton-html5/imports/api/users/server/publications.js +++ /dev/null @@ -1,77 +0,0 @@ -import Users from '/imports/api/users'; -import { isAllowedTo } from '/imports/startup/server/userPermissions'; -import { logger } from '/imports/startup/server/logger'; -import { requestUserLeaving } from '/imports/api/users/server/modifiers/requestUserLeaving'; - -// Publish only the online users that are in the particular meetingId -// Also contains reconnection and connection_status info -Meteor.publish('users', function (credentials) { - const meetingId = credentials.meetingId; - const userid = credentials.requesterUserId; - const authToken = credentials.requesterToken; - - logger.info(`attempt publishing users for ${meetingId}, ${userid}, ${authToken}`); - const userObject = Users.findOne({ - userId: userid, - meetingId: meetingId, - }); - - if (!!userObject && !!userObject.user) { - let username = 'UNKNOWN'; - if (isAllowedTo('subscribeUsers', credentials)) { - logger.info(`${userid} was allowed to subscribe to 'users'`); - username = userObject.user.name; - - // offline -> online - if (userObject.user.connection_status !== 'online') { - Meteor.call('validateAuthToken', credentials); - setConnectionStatus(meetingId, userid, 'online'); - } - - this._session.socket.on('close', Meteor.bindEnvironment((function (_this) { - return function () { - logger.info(`a user lost connection: session.id=${_this._session.id}` + - ` userId = ${userid}, username=${username}, meeting=${meetingId}`); - setConnectionStatus(meetingId, userid, 'offline'); - return requestUserLeaving(meetingId, userid); - }; - })(this))); - - return getUsers(meetingId); - } else { - logger.warn('was not authorized to subscribe to users'); - return this.error(new Meteor.Error(402, 'User was not authorized to subscribe to users')); - } - } else { //subscribing before the user was added to the collection - Meteor.call('validateAuthToken', credentials); - logger.info(`Sending validateAuthTokenthere for user ${userid} in ${meetingId}.`); - return getUsers(meetingId); - } -}); - -const getUsers = function (meetingId) { - //publish the users which are not offline - return Users.find({ - meetingId: meetingId, - 'user.connection_status': { - $in: ['online', ''], - }, - }, { - fields: { - authToken: false, - }, - }); -}; - -const setConnectionStatus = function (meetingId, userId, statusStr) { - Users.update({ - meetingId: meetingId, - userId: userId, - }, { - $set: { - 'user.connection_status': statusStr, - }, - }, (err, numChanged) => { - logger.info(`User ${userId} in ${meetingId} goes ${statusStr}`); - }); -}; diff --git a/bigbluebutton-html5/imports/api/users/server/publishers.js b/bigbluebutton-html5/imports/api/users/server/publishers.js index 12d59c5429fcf69d517599f0053cb7ec9cb0a431..ee361f3c50e9cf31b34558385a8c6c86ef145d6f 100644 --- a/bigbluebutton-html5/imports/api/users/server/publishers.js +++ b/bigbluebutton-html5/imports/api/users/server/publishers.js @@ -4,27 +4,33 @@ import { check } from 'meteor/check'; import Logger from '/imports/startup/server/logger'; import { isAllowedTo } from '/imports/startup/server/userPermissions'; -import setConnectionStatus from './modifiers/setConnectionStatus'; - -Meteor.publish('Users', function (credentials) { - // TODO: Some publishers have ACL and others dont - // if (!isAllowedTo('@@@', credentials)) { - // this.error(new Meteor.Error(402, "The user was not authorized to subscribe for 'Users'")); - // } +import userLeaving from './methods/userLeaving'; +import validateAuthToken from './methods/validateAuthToken'; +Meteor.publish('users', function (credentials) { const { meetingId, requesterUserId, requesterToken } = credentials; check(meetingId, String); check(requesterUserId, String); check(requesterToken, String); - // TODO: - // - Add reconnection handlers - // - Add validateAuthToken stuff - // - Update `connection_status` when the user disconnects + let initializing = true; + + validateAuthToken(credentials); + + // const User = Users.find({ meetingId, userId: requesterUserId }).observeChanges({ + // changed: (id, fields) => { + // console.log(fields); + // }, + // }); + + if (!isAllowedTo('subscribeUsers', credentials)) { + console.error('lul'); + this.error(new Meteor.Error(402, "The user was not authorized to subscribe for 'Users'")); + } this.onStop(() => { - setConnectionStatus(meetingId, requesterUserId, 'offline'); + userLeaving(credentials, requesterUserId); }); const selector = { diff --git a/bigbluebutton-html5/server/main.js b/bigbluebutton-html5/server/main.js index e9c6f8f1341adf897807d390068f77413b1f52bb..c4f5b40dad02bd11d30eb35a3ac7e22f76dec739 100755 --- a/bigbluebutton-html5/server/main.js +++ b/bigbluebutton-html5/server/main.js @@ -37,7 +37,6 @@ import '/imports/api/users/server/modifiers/clearUsersCollection'; import '/imports/api/users/server/modifiers/createDummyUser'; import '/imports/api/users/server/modifiers/handleLockingMic'; import '/imports/api/users/server/modifiers/markUserOffline'; -import '/imports/api/users/server/modifiers/requestUserLeaving'; import '/imports/api/users/server/modifiers/setUserLockedStatus'; import '/imports/api/users/server/modifiers/updateVoiceUser'; import '/imports/api/users/server/modifiers/userJoined';