Merge branch 'Acl' into Refactor2x

* Acl:
  Add check to undefined role
  Lint to eslint
  Missing merge file
  Fix lint problems
  Change Acl lookup
  Change ACL to be more extensible
  Fix a few review comments
  Acl refactor working
  Mostly working, still problems with user subs
  Code refactored
This commit is contained in:
Klaus Klein 2017-06-19 11:28:17 -03:00
commit ca09b69555
36 changed files with 220 additions and 188 deletions

View File

@ -1,7 +1,8 @@
import Breakouts from '/imports/api/1.1/breakouts';
import { Meteor } from 'meteor/meteor';
import mapToAcl from '/imports/startup/mapToAcl';
Meteor.publish('breakouts', (credentials) => {
function breakouts(credentials) {
const {
meetingId,
requesterUserId,
@ -17,4 +18,11 @@ Meteor.publish('breakouts', (credentials) => {
},
],
});
});
}
function publish(...args) {
const boundBreakouts = breakouts.bind(this);
return mapToAcl('subscriptions.breakouts', boundBreakouts)(args);
}
Meteor.publish('breakouts', publish);

View File

@ -2,14 +2,9 @@ import Captions from '/imports/api/1.1/captions';
import { Meteor } from 'meteor/meteor';
import { check } from 'meteor/check';
import Logger from '/imports/startup/server/logger';
import { isAllowedTo } from '/imports/startup/server/userPermissions';
Meteor.publish('captions', (credentials) => {
// TODO: Some publishers have ACL and others dont
// if (isAllowedTo('subscribeCaptions', credentials)) {
// this.error(new Meteor.Error(402, "The user was not authorized to subscribe for 'captions'"));
// }
import mapToAcl from '/imports/startup/mapToAcl';
function captions(credentials) {
const { meetingId, requesterUserId, requesterToken } = credentials;
check(meetingId, String);
@ -19,4 +14,11 @@ Meteor.publish('captions', (credentials) => {
Logger.verbose(`Publishing Captions for ${meetingId} ${requesterUserId} ${requesterToken}`);
return Captions.find({ meetingId });
});
}
function publish(...args) {
const boundCaptions = captions.bind(this);
return mapToAcl('subscriptions.captions', boundCaptions)(args);
}
Meteor.publish('captions', publish);

View File

@ -1,6 +1,7 @@
import mapToAcl from '/imports/startup/mapToAcl';
import { Meteor } from 'meteor/meteor';
import sendChat from './methods/sendChat';
Meteor.methods({
Meteor.methods(mapToAcl(['methods.sendChat'], {
sendChat,
});
}));

View File

@ -2,7 +2,6 @@ import { Meteor } from 'meteor/meteor';
import { check } from 'meteor/check';
import Logger from '/imports/startup/server/logger';
import RedisPubSub from '/imports/startup/server/redis';
import { isAllowedTo } from '/imports/startup/server/userPermissions';
import { translateHTML5ToFlash } from '/imports/api/common/server/helpers';
import RegexWebUrl from '/imports/utils/regex-weburl';
@ -55,11 +54,6 @@ export default function sendChat(credentials, message) {
actionName = 'chatPublic';
}
if (!isAllowedTo(actionName, credentials)
&& message.from_userid !== requesterUserId) {
throw new Meteor.Error('not-allowed', 'You are not allowed to sendChat');
}
const payload = {
message,
meeting_id: meetingId,

View File

@ -2,13 +2,10 @@ import Chat from '/imports/api/1.1/chat';
import { Meteor } from 'meteor/meteor';
import { check } from 'meteor/check';
import Logger from '/imports/startup/server/logger';
import { isAllowedTo } from '/imports/startup/server/userPermissions';
Meteor.publish('chat', function (credentials) {
if (!isAllowedTo('subscribeChat', credentials)) {
this.error(new Meteor.Error(402, "The user was not authorized to subscribe for 'chats'"));
}
import mapToAcl from '/imports/startup/mapToAcl';
function chat(credentials) {
const CHAT_CONFIG = Meteor.settings.public.chat;
const PUBLIC_CHAT_TYPE = CHAT_CONFIG.type_public;
@ -34,4 +31,11 @@ Meteor.publish('chat', function (credentials) {
},
],
});
});
}
function publish(...args) {
const boundChat = chat.bind(this);
return mapToAcl('subscriptions.chat', boundChat)(args);
}
Meteor.publish('chat', publish);

View File

@ -2,14 +2,10 @@ import Cursor from '/imports/api/1.1/cursor';
import { Meteor } from 'meteor/meteor';
import { check } from 'meteor/check';
import Logger from '/imports/startup/server/logger';
import { isAllowedTo } from '/imports/startup/server/userPermissions';
Meteor.publish('cursor', (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 'cursor'"));
// }
import mapToAcl from '/imports/startup/mapToAcl';
function cursor(credentials) {
const { meetingId, requesterUserId, requesterToken } = credentials;
check(meetingId, String);
@ -19,4 +15,12 @@ Meteor.publish('cursor', (credentials) => {
Logger.debug(`Publishing Cursor for ${meetingId} ${requesterUserId} ${requesterToken}`);
return Cursor.find({ meetingId });
});
}
function publish(...args) {
const boundCursor = cursor.bind(this);
return mapToAcl('subscriptions.cursor', boundCursor)(args);
}
Meteor.publish('cursor', publish);

View File

@ -1,8 +1,17 @@
import Deskshare from '/imports/api/1.1/deskshare';
import { logger } from '/imports/startup/server/logger';
import mapToAcl from '/imports/startup/mapToAcl';
Meteor.publish('deskshare', (credentials) => {
function deskshare(credentials) {
const { meetingId } = credentials;
logger.info(`publishing deskshare for ${meetingId}`);
return Deskshare.find({ meetingId });
});
}
function publish(...args) {
const boundDeskshare = deskshare.bind(this);
return mapToAcl('subscriptions.deskshare', boundDeskshare)(args);
}
Meteor.publish('deskshare', publish);

View File

@ -3,7 +3,7 @@ import handleMeetingDestruction from './handlers/meetingDestruction';
import handleRecordingStatusChange from './handlers/recordingStatusChange';
import handlePermissionSettingsChange from './handlers/permissionSettingsChange';
import handleMeetingCreation from './handlers/meetingCreation';
import handleGetAllMettings from './handlers/getAllMeetings';
import handleGetAllMeetings from './handlers/getAllMeetings';
import handleStunTurnReply from './handlers/stunTurnReply';
RedisPubSub.on('meeting_destroyed_event', handleMeetingDestruction);
@ -13,5 +13,5 @@ RedisPubSub.on('disconnect_all_users_message', handleMeetingDestruction);
RedisPubSub.on('recording_status_changed_message', handleRecordingStatusChange);
RedisPubSub.on('new_permission_settings', handlePermissionSettingsChange);
RedisPubSub.on('meeting_created_message', handleMeetingCreation);
RedisPubSub.on('get_all_meetings_reply_message', handleGetAllMettings);
RedisPubSub.on('get_all_meetings_reply_message', handleGetAllMeetings);
RedisPubSub.on('send_stun_turn_info_reply_message', handleStunTurnReply);

View File

@ -4,7 +4,7 @@ import Meetings from '/imports/api/1.1/meetings';
import addMeeting from '../modifiers/addMeeting';
import removeMeeting from '../modifiers/removeMeeting';
export default function handleGetAllMettings({ payload }) {
export default function handleGetAllMeetings({ payload }) {
let meetings = payload.meetings;
check(meetings, Array);

View File

@ -2,8 +2,9 @@ import { Meteor } from 'meteor/meteor';
import { check } from 'meteor/check';
import Meetings from '/imports/api/1.1/meetings';
import Logger from '/imports/startup/server/logger';
import mapToAcl from '/imports/startup/mapToAcl';
Meteor.publish('meetings', (credentials) => {
function meetings(credentials) {
const { meetingId, requesterUserId, requesterToken } = credentials;
check(meetingId, String);
@ -15,4 +16,12 @@ Meteor.publish('meetings', (credentials) => {
return Meetings.find({
meetingId,
});
});
}
function publish(...args) {
const boundMeetings = meetings.bind(this);
return mapToAcl('subscriptions.meetings', boundMeetings)(args);
}
Meteor.publish('meetings', publish);

View File

@ -1,6 +1,7 @@
import { Meteor } from 'meteor/meteor';
import publishVote from './methods/publishVote';
import mapToAcl from '/imports/startup/mapToAcl';
Meteor.methods({
Meteor.methods(mapToAcl(['methods.publishVote'], {
publishVote,
});
}));

View File

@ -1,4 +1,3 @@
import { isAllowedTo } from '/imports/startup/server/userPermissions';
import RedisPubSub from '/imports/startup/server/redis';
import { check } from 'meteor/check';
import Polls from '/imports/api/1.1/polls';
@ -9,11 +8,7 @@ export default function publishVote(credentials, pollId, pollAnswerId) { // TODO
const CHANNEL = REDIS_CONFIG.channels.toBBBApps.polling;
const EVENT_NAME = 'vote_poll_user_request_message';
if (!isAllowedTo('subscribePoll', credentials)) {
throw new Meteor.Error('not-allowed', 'You are not allowed to publishVote');
}
const { meetingId, requesterUserId, requesterToken } = credentials;
const { meetingId, requesterUserId } = credentials;
const currentPoll = Polls.findOne({
users: requesterUserId,
@ -47,12 +42,12 @@ export default function publishVote(credentials, pollId, pollAnswerId) { // TODO
},
};
const cb = (err, numChanged) => {
const cb = (err) => {
if (err) {
return Logger.error(`Updating Polls collection: ${err}`);
}
Logger.info(`Updating Polls collection (meetingId: ${meetingId},
return Logger.info(`Updating Polls collection (meetingId: ${meetingId},
pollId: ${currentPoll.poll.id}!)`);
};

View File

@ -1,15 +1,9 @@
import { Meteor } from 'meteor/meteor';
import { isAllowedTo } from '/imports/startup/server/userPermissions';
import Polls from '/imports/api/1.1/polls';
import { check } from 'meteor/check';
import { logger } from '/imports/startup/server/logger';
Meteor.publish('polls', function (credentials) {
// checking if it is allowed to see Poll Collection in general
if (!isAllowedTo('subscribePoll', credentials)) {
this.error(new Meteor.Error(402, "The user was not authorized to subscribe for 'polls'"));
}
import Polls from '/imports/api/1.1/polls';
import mapToAcl from '/imports/startup/mapToAcl';
function polls(credentials) {
const { meetingId, requesterUserId, requesterToken } = credentials;
check(meetingId, String);
@ -21,15 +15,13 @@ Meteor.publish('polls', function (credentials) {
users: requesterUserId,
};
let options = {};
return Polls.find(selector);
}
if (!isAllowedTo('subscribeAnswers', credentials)) {
options = {
fields: {
'poll.answers.num_votes': 0,
},
};
}
function publish(...args) {
const boundPolls = polls.bind(this);
return mapToAcl('subscriptions.polls', boundPolls)(args);
}
Meteor.publish('polls', publish);
return Polls.find(selector, options);
});

View File

@ -2,15 +2,9 @@ import { Meteor } from 'meteor/meteor';
import { check } from 'meteor/check';
import Presentations from './../';
import Logger from '/imports/startup/server/logger';
import { isAllowedTo } from '/imports/startup/server/userPermissions';
Meteor.publish('presentations', (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 'presentations'"));
// }
import mapToAcl from '/imports/startup/mapToAcl';
function presentations(credentials) {
const { meetingId, requesterUserId, requesterToken } = credentials;
check(meetingId, String);
@ -20,4 +14,12 @@ Meteor.publish('presentations', (credentials) => {
Logger.info(`Publishing Presentations for ${meetingId} ${requesterUserId} ${requesterToken}`);
return Presentations.find({ meetingId });
});
}
function publish(...args) {
const boundPresentations = presentations.bind(this);
return mapToAcl('subscriptions.presentations', boundPresentations)(args);
}
Meteor.publish('presentations', publish);

View File

@ -2,14 +2,9 @@ import Shapes from './../';
import { Meteor } from 'meteor/meteor';
import { check } from 'meteor/check';
import Logger from '/imports/startup/server/logger';
import { isAllowedTo } from '/imports/startup/server/userPermissions';
Meteor.publish('shapes', (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 'shapes'"));
// }
import mapToAcl from '/imports/startup/mapToAcl';
function shapes(credentials) {
const { meetingId, requesterUserId, requesterToken } = credentials;
check(meetingId, String);
@ -19,4 +14,11 @@ Meteor.publish('shapes', (credentials) => {
Logger.info(`Publishing Shapes for ${meetingId} ${requesterUserId} ${requesterToken}`);
return Shapes.find({ meetingId });
});
}
function publish(...args) {
const boundShapes = shapes.bind(this);
return mapToAcl('subscriptions.shapes', boundShapes)(args);
}
Meteor.publish('shapes', publish);

View File

@ -1,7 +1,8 @@
import { Meteor } from 'meteor/meteor';
import mapToAcl from '/imports/startup/mapToAcl';
import switchSlide from './methods/switchSlide';
Meteor.methods({
Meteor.methods(mapToAcl(['methods.switchSlide', 'methods.switchSlideMessage'], {
switchSlide,
switchSlideMessage: switchSlide, // legacy
});
}));

View File

@ -3,7 +3,6 @@ import Slides from './../../';
import { Meteor } from 'meteor/meteor';
import { check } from 'meteor/check';
import RedisPubSub from '/imports/startup/server/redis';
import { isAllowedTo } from '/imports/startup/server/userPermissions';
export default function switchSlide(credentials, slideNumber) {
const REDIS_CONFIG = Meteor.settings.redis;
@ -18,10 +17,6 @@ export default function switchSlide(credentials, slideNumber) {
check(requesterToken, String);
check(slideNumber, Number);
if (!isAllowedTo('switchSlide', credentials)) {
throw new Meteor.Error('not-allowed', 'You are not allowed to switchSlide');
}
const Presentation = Presentations.findOne({
meetingId,
'presentation.current': true,
@ -35,7 +30,7 @@ export default function switchSlide(credentials, slideNumber) {
const Slide = Slides.findOne({
meetingId,
presentationId: Presentation.presentation.id,
'slide.num': parseInt(slideNumber),
'slide.num': parseInt(slideNumber, 2),
});
if (!Slide) {

View File

@ -2,14 +2,9 @@ import Slides from './../';
import { Meteor } from 'meteor/meteor';
import { check } from 'meteor/check';
import Logger from '/imports/startup/server/logger';
import { isAllowedTo } from '/imports/startup/server/userPermissions';
Meteor.publish('slides', (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 'slides'"));
// }
import mapToAcl from '/imports/startup/mapToAcl';
function slides(credentials) {
const { meetingId, requesterUserId, requesterToken } = credentials;
check(meetingId, String);
@ -19,4 +14,11 @@ Meteor.publish('slides', (credentials) => {
Logger.info(`Publishing Slides for ${meetingId} ${requesterUserId} ${requesterToken}`);
return Slides.find({ meetingId });
});
}
function publish(...args) {
const boundSlides = slides.bind(this);
return mapToAcl('subscriptions.slides', boundSlides)(args);
}
Meteor.publish('slides', publish);

View File

@ -6,14 +6,18 @@ import assignPresenter from './methods/assignPresenter';
import muteToggle from './methods/muteToggle';
import setEmojiStatus from './methods/setEmojiStatus';
import validateAuthToken from './methods/validateAuthToken';
import mapToAcl from '/imports/startup/mapToAcl';
Meteor.methods({
kickUser,
listenOnlyToggle,
userLogout,
assignPresenter,
setEmojiStatus,
validateAuthToken,
muteUser: (...args) => muteToggle(...args, true),
unmuteUser: (...args) => muteToggle(...args, false),
});
Meteor.methods(mapToAcl(['methods.kickUser', 'methods.listenOnlyToggle', 'methods.userLogout',
'methods.assignPresenter', 'methods.setEmojiStatus', 'methods.muteUser', 'methods.unmuteUser',
], {
kickUser,
listenOnlyToggle,
userLogout,
assignPresenter,
setEmojiStatus,
muteUser: (...args) => muteToggle(...args, true),
unmuteUser: (...args) => muteToggle(...args, false),
}));
Meteor.methods({ validateAuthToken });

View File

@ -2,7 +2,6 @@ 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/1.1/users';
export default function assignPresenter(credentials, userId) {
@ -16,14 +15,11 @@ export default function assignPresenter(credentials, userId) {
check(requesterUserId, String);
check(userId, String);
if (!isAllowedTo('setPresenter', credentials)) {
throw new Meteor.Error('not-allowed', 'You are not allowed to setPresenter');
}
const User = Users.findOne({
meetingId,
userId,
});
if (!User) {
throw new Meteor.Error(
'user-not-found', 'You need a valid user to be able to set presenter');

View File

@ -2,7 +2,6 @@ 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';
export default function kickUser(credentials, userId) {
const REDIS_CONFIG = Meteor.settings.redis;
@ -15,10 +14,6 @@ export default function kickUser(credentials, userId) {
check(requesterUserId, String);
check(userId, String);
if (!isAllowedTo('kickUser', credentials)) {
throw new Meteor.Error('not-allowed', 'You are not allowed to kickUser');
}
const payload = {
userid: userId,
ejected_by: requesterUserId,

View File

@ -2,7 +2,6 @@ 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 Meetings from '/imports/api/1.1/meetings';
import Users from '/imports/api/1.1/users';
@ -20,23 +19,17 @@ export default function listenOnlyToggle(credentials, isJoining = true) {
if (isJoining) {
EVENT_NAME = 'user_connected_to_global_audio';
if (!isAllowedTo('joinListenOnly', credentials)) {
throw new Meteor.Error('not-allowed', 'You are not allowed to joinListenOnly');
}
} else {
EVENT_NAME = 'user_disconnected_from_global_audio';
if (!isAllowedTo('leaveListenOnly', credentials)) {
throw new Meteor.Error('not-allowed', 'You are not allowed to leaveListenOnly');
}
}
const Metting = Meetings.findOne({ meetingId });
if (!Metting) {
const Meeting = Meetings.findOne({ meetingId });
if (!Meeting) {
throw new Meteor.Error(
'metting-not-found', 'You need a valid meeting to be able to toggle audio');
'meeting-not-found', 'You need a valid meeting to be able to toggle audio');
}
check(Metting.voiceConf, String);
check(Meeting.voiceConf, String);
const User = Users.findOne({
meetingId,
@ -53,7 +46,7 @@ export default function listenOnlyToggle(credentials, isJoining = true) {
const payload = {
userid: requesterUserId,
meeting_id: meetingId,
voice_conf: Metting.voiceConf,
voice_conf: Meeting.voiceConf,
name: User.user.name,
};

View File

@ -2,7 +2,6 @@ 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';
export default function muteToggle(credentials, userId, isMuted = true) {
const REDIS_CONFIG = Meteor.settings.redis;
@ -15,16 +14,6 @@ export default function muteToggle(credentials, userId, isMuted = true) {
check(requesterUserId, String);
check(userId, String);
let action = userId === requesterUserId ? 'muteSelf' : 'muteOther';
if (!isMuted) {
action = `un${action}`;
}
if (!isAllowedTo(action, credentials)) {
throw new Meteor.Error('not-allowed', `You are not allowed to ${action}`);
}
const payload = {
user_id: userId,
meeting_id: meetingId,

View File

@ -2,7 +2,6 @@ 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';
export default function setEmojiStatus(credentials, userId, status) {
const REDIS_CONFIG = Meteor.settings.redis;
@ -15,10 +14,6 @@ export default function setEmojiStatus(credentials, userId, status) {
check(requesterUserId, String);
check(userId, String);
if (!isAllowedTo('setEmojiStatus', credentials)) {
throw new Meteor.Error('not-allowed', 'You are not allowed to setEmojiStatus');
}
const payload = {
emoji_status: status,
userid: userId,

View File

@ -2,7 +2,6 @@ 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/1.1/users';
import setConnectionStatus from '../modifiers/setConnectionStatus';

View File

@ -1,14 +1,8 @@
import { Meteor } from 'meteor/meteor';
import { isAllowedTo } from '/imports/startup/server/userPermissions';
import Logger from '/imports/startup/server/logger';
import userLeaving from './userLeaving';
export default function userLogout(credentials) {
if (!isAllowedTo('logoutSelf', credentials)) {
throw new Meteor.Error('not-allowed', 'You are not allowed to logoutSelf');
}
const { requesterUserId } = credentials;
try {

View File

@ -2,7 +2,6 @@ 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/1.1/users';
import createDummyUser from '../modifiers/createDummyUser';

View File

@ -26,12 +26,17 @@ export default function addUser(meetingId, user) {
// override moderator status of html5 client users, depending on a system flag
const dummyUser = Users.findOne(selector);
if (dummyUser &&
dummyUser.clientType === 'HTML5' &&
user.role === ROLE_MODERATOR &&
!ALLOW_HTML5_MODERATOR) {
dummyUser.clientType === 'HTML5' &&
user.role === ROLE_MODERATOR &&
!ALLOW_HTML5_MODERATOR) {
user.role = ROLE_VIEWER;
}
const userRoles = [];
userRoles.push('viewer');
userRoles.push(user.presenter ? 'presenter' : undefined);
userRoles.push(user.role === 'MODERATOR' ? 'moderator' : undefined);
const modifier = {
$set: {
meetingId,
@ -40,6 +45,7 @@ export default function addUser(meetingId, user) {
'user.userid': userId,
'user.extern_userid': user.extern_userid,
'user.role': user.role,
'user.roles': userRoles,
'user.name': user.name,
'user._sort_name': user.name.trim().toLowerCase(),
'user.avatarURL': user.avatarURL,

View File

@ -2,7 +2,7 @@ import Users from './../';
import { Meteor } from 'meteor/meteor';
import { check } from 'meteor/check';
import Logger from '/imports/startup/server/logger';
import { isAllowedTo } from '/imports/startup/server/userPermissions';
import mapToAcl from '/imports/startup/mapToAcl';
import userLeaving from './methods/userLeaving';
@ -28,17 +28,17 @@ Meteor.publish('current-user', (credentials) => {
return Users.find(selector, options);
});
Meteor.publish('users', function (credentials) {
const { meetingId, requesterUserId, requesterToken } = credentials;
function users(credentials) {
const {
meetingId,
requesterUserId,
requesterToken,
} = credentials;
check(meetingId, String);
check(requesterUserId, String);
check(requesterToken, String);
if (!isAllowedTo('subscribeUsers', credentials)) {
this.error(new Meteor.Error(402, "The user was not authorized to subscribe for 'Users'"));
}
this.onStop(() => {
try {
userLeaving(credentials, requesterUserId);
@ -60,4 +60,11 @@ Meteor.publish('users', function (credentials) {
Logger.info(`Publishing Users for ${meetingId} ${requesterUserId} ${requesterToken}`);
return Users.find(selector, options);
});
}
function publish(...args) {
const boundUsers = users.bind(this);
return mapToAcl('subscriptions.users', boundUsers)(args);
}
Meteor.publish('users', publish);

View File

@ -52,17 +52,24 @@ export class Acl {
userId,
});
if (!user) {
return false;
const containRole = Acl.containsRole(user);
if (containRole) {
const roles = user.user.roles;
let permissions = {};
roles.forEach((role) => {
permissions = deepMerge(permissions, this.config[role]);
});
return permissions;
}
return false;
}
const roles = user.user.roles;
let permissions = {};
roles.forEach((role) => {
permissions = deepMerge(permissions, this.config[role]);
});
return permissions;
static containsRole(user) {
return Match.test(user, Object) &&
Match.test(user.user, Object) &&
Match.test(user.user.roles, Array);
}
}

View File

@ -1,6 +1,4 @@
import { Meteor } from 'meteor/meteor';
import logClient from './methods/logClient';
Meteor.methods({
logClient,
});
Meteor.methods({ 'methods.logClient': logClient });

View File

@ -1,7 +1,9 @@
import Logger from '/imports/startup/server/logger';
export default function logClient() {
const logClient = () => {
const args = Array.prototype.slice.call(arguments, 1);
Logger.log(arguments[0], 'Client Log', args);
}
};
export default logClient;

View File

@ -109,8 +109,8 @@ class UserList extends Component {
}
if (Args[0].keyCode === KEY_CODES.ENTER
|| Args[0].keyCode === KEY_CODES.ARROW_RIGHT
|| Args[0].keyCode === KEY_CODES.ARROW_LEFT) {
|| Args[0].keyCode === KEY_CODES.ARROW_RIGHT
|| Args[0].keyCode === KEY_CODES.ARROW_LEFT) {
active.firstChild.click();
}
@ -151,7 +151,6 @@ class UserList extends Component {
componentWillUnmount() {
this._msgsList.removeEventListener('keypress', (event) => {}, false);
this._usersList.removeEventListener('keypress', (event) => {}, false);
}

View File

@ -186,8 +186,7 @@ class Auth {
});
});
const credentials = this.credentials;
makeCall('validateAuthToken', credentials);
makeCall('validateAuthToken');
});
}

View File

@ -0,0 +1,30 @@
acl:
viewer:
subscriptions:
- 'users'
- 'cursor'
- 'deskshare'
- 'meetings'
- 'polls'
- 'chat'
- 'presentations'
- 'shapes'
- 'slides'
- 'captions'
- 'breakouts'
methods:
- 'listenOnlyToggle'
- 'userLogout'
- 'setEmojiStatus'
- 'publishVote'
- 'sendChat'
moderator:
methods:
- 'kickUser'
- 'muteUser'
- 'unmuteUser'
presenter:
methods:
- 'assignPresenter'
- 'switchSlide'
- 'switchSlideMessage'

View File

@ -19,4 +19,3 @@ import '/imports/api/2.0/users/server';
import '/imports/api/log-client/server';
import '/imports/api/common/server/helpers';
import '/imports/startup/server/logger';
import '/imports/startup/server/userPermissions';