2017-10-10 02:53:45 +08:00
|
|
|
|
|
|
|
import { Meteor } from 'meteor/meteor';
|
2017-06-19 21:13:35 +08:00
|
|
|
import { check } from 'meteor/check';
|
|
|
|
import deepMerge from '/imports/utils/deepMerge';
|
|
|
|
|
2017-10-09 20:49:07 +08:00
|
|
|
export default class Acl {
|
2017-06-19 21:13:35 +08:00
|
|
|
constructor(config, Users) {
|
|
|
|
this.Users = Users;
|
|
|
|
this.config = config;
|
|
|
|
}
|
|
|
|
|
|
|
|
can(permission, credentials) {
|
|
|
|
check(permission, String);
|
|
|
|
const permissions = this.getPermissions(credentials);
|
|
|
|
|
2017-10-09 20:49:07 +08:00
|
|
|
return this.checkToken(credentials) && this.fetchPermission(permission, permissions);
|
|
|
|
}
|
|
|
|
|
|
|
|
checkToken(credentials) {
|
2017-10-10 02:53:45 +08:00
|
|
|
// skip token check in client `can` calls since we dont have the authToken in the collection
|
|
|
|
if (!Meteor.isServer) return true;
|
|
|
|
|
2017-10-09 20:49:07 +08:00
|
|
|
const { meetingId, requesterUserId: userId, requesterToken: authToken } = credentials;
|
|
|
|
|
|
|
|
const User = this.Users.findOne({
|
|
|
|
meetingId,
|
|
|
|
userId,
|
|
|
|
authToken,
|
|
|
|
});
|
2017-06-19 21:13:35 +08:00
|
|
|
|
2017-10-09 20:49:07 +08:00
|
|
|
return !!User; // if he found a user means the meeting/user/token is valid
|
2017-06-19 21:13:35 +08:00
|
|
|
}
|
|
|
|
|
|
|
|
fetchPermission(permission, permissions) {
|
|
|
|
if (!permission) return false;
|
|
|
|
|
|
|
|
if (Match.test(permissions, String)) {
|
|
|
|
return permissions.indexOf(permission) > -1;
|
|
|
|
} else if (Match.test(permissions, Array)) {
|
|
|
|
return permissions.some(internalAcl => (this.fetchPermission(permission, internalAcl)));
|
|
|
|
} else if (Match.test(permissions, Object)) {
|
|
|
|
if (permission.indexOf('.') > -1) {
|
|
|
|
return this.fetchPermission(permission.substring(permission.indexOf('.') + 1),
|
|
|
|
permissions[permission.substring(0, permission.indexOf('.'))]);
|
|
|
|
}
|
|
|
|
return permissions[permission];
|
|
|
|
}
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
|
|
|
|
getPermissions(credentials) {
|
|
|
|
if (!credentials) {
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
|
|
|
|
const meetingId = credentials.meetingId;
|
|
|
|
const userId = credentials.requesterUserId;
|
|
|
|
|
|
|
|
const user = this.Users.findOne({
|
|
|
|
meetingId,
|
|
|
|
userId,
|
|
|
|
});
|
|
|
|
|
2017-06-07 21:02:31 +08:00
|
|
|
const containRole = Acl.containsRole(user);
|
2017-06-19 21:13:35 +08:00
|
|
|
|
2017-06-07 21:02:31 +08:00
|
|
|
if (containRole) {
|
2017-07-26 22:31:35 +08:00
|
|
|
const roles = user.roles;
|
2017-06-07 21:02:31 +08:00
|
|
|
let permissions = {};
|
2017-06-19 21:13:35 +08:00
|
|
|
|
2017-06-07 21:02:31 +08:00
|
|
|
roles.forEach((role) => {
|
2017-08-29 03:47:54 +08:00
|
|
|
// There is a big issue here, if we just send the content from the this.config
|
|
|
|
// inside the deepMerge, we change both permissions and the config.
|
|
|
|
// Couldn't find a better way to prevent the changing.
|
|
|
|
// The problems occurs in the `sources.shift()`.
|
|
|
|
permissions = deepMerge(permissions, JSON.parse(JSON.stringify(this.config[role])));
|
2017-06-07 21:02:31 +08:00
|
|
|
});
|
|
|
|
|
|
|
|
return permissions;
|
|
|
|
}
|
|
|
|
return false;
|
|
|
|
}
|
2017-06-19 21:13:35 +08:00
|
|
|
|
2017-06-07 21:02:31 +08:00
|
|
|
static containsRole(user) {
|
|
|
|
return Match.test(user, Object) &&
|
2017-08-29 03:47:54 +08:00
|
|
|
Match.test(user.roles, Array);
|
2017-06-19 21:13:35 +08:00
|
|
|
}
|
|
|
|
}
|