Chore: Move getUserRoles to service and add cache (#22345)

pull/22223/head^2
Diego Sampaio 5 years ago committed by GitHub
parent 4a28c1282b
commit f21aceef45
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
  1. 26
      app/lib/server/methods/getUserRoles.js
  2. 44
      server/services/authorization/service.ts

@ -1,33 +1,13 @@
import { Meteor } from 'meteor/meteor';
import _ from 'underscore';
import { Roles, Users } from '../../../models';
import { Authorization } from '../../../../server/sdk';
Meteor.methods({
getUserRoles() {
async getUserRoles() {
if (!Meteor.userId()) {
throw new Meteor.Error('error-invalid-user', 'Invalid user', { method: 'getUserRoles' });
}
const options = {
sort: {
username: 1,
},
fields: {
username: 1,
roles: 1,
},
};
const roles = Roles.find({ scope: 'Users', description: { $exists: 1, $ne: '' } }).fetch();
const roleIds = _.pluck(roles, '_id');
// Security issue: we should not send all user's roles to all clients, only the 'public' roles
// We must remove all roles that are not part of the query from the returned users
const users = Users.findUsersInRoles(roleIds, null, options).fetch();
for (const user of users) {
user.roles = _.intersection(user.roles, roleIds);
}
return users;
return Authorization.getUsersFromPublicRoles();
},
});

@ -11,6 +11,8 @@ import { SettingsRaw } from '../../../app/models/server/raw/Settings';
import { RoomsRaw } from '../../../app/models/server/raw/Rooms';
import { TeamMemberRaw } from '../../../app/models/server/raw/TeamMember';
import { TeamRaw } from '../../../app/models/server/raw/Team';
import { RolesRaw } from '../../../app/models/server/raw/Roles';
import { UsersRaw } from '../../../app/models/server/raw/Users';
import './canAccessRoomLivechat';
import './canAccessRoomTokenpass';
@ -27,7 +29,9 @@ export class Authorization extends ServiceClass implements IAuthorization {
private Permissions: Collection;
private Users: Collection;
private Users: UsersRaw;
private Roles: RolesRaw;
private getRolesCached = mem(this.getRoles.bind(this), { maxAge: 1000, cacheKey: JSON.stringify })
@ -37,7 +41,9 @@ export class Authorization extends ServiceClass implements IAuthorization {
super();
this.Permissions = db.collection('rocketchat_permissions');
this.Users = db.collection('users');
this.Users = new UsersRaw(db.collection('users'));
this.Roles = new RolesRaw(db.collection('rocketchat_roles'));
Subscriptions = new SubscriptionsRaw(db.collection('rocketchat_subscription'));
Settings = new SettingsRaw(db.collection('rocketchat_settings'));
@ -83,6 +89,38 @@ export class Authorization extends ServiceClass implements IAuthorization {
AuthorizationUtils.addRolePermissionWhiteList(role, permissions);
}
async getUsersFromPublicRoles(): Promise<Pick<IUser, '_id' | 'username' | 'roles'>[]> {
const roleIds = await this.getPublicRoles();
return this.getUserFromRoles(roleIds);
}
private getPublicRoles = mem(async (): Promise<string[]> => {
const roles = await this.Roles.find({ scope: 'Users', description: { $exists: 1, $ne: '' } }, { projection: { _id: 1 } }).toArray();
return roles.map(({ _id }) => _id);
}, { maxAge: 10000 });
private getUserFromRoles = mem(async (roleIds: string[]) => {
const options = {
sort: {
username: 1,
},
fields: {
username: 1,
roles: 1,
},
};
const users = await this.Users.findUsersInRoles(roleIds, null, options).toArray();
return users
.map((user) => ({
...user,
roles: user.roles.filter((roleId: string) => roleIds.includes(roleId)),
}));
}, { maxAge: 10000 });
private async rolesHasPermission(permission: string, roles: string[]): Promise<boolean> {
if (AuthorizationUtils.isPermissionRestrictedForRoleList(permission, roles)) {
return false;
@ -93,7 +131,7 @@ export class Authorization extends ServiceClass implements IAuthorization {
}
private async getRoles(uid: string, scope?: string): Promise<string[]> {
const { roles: userRoles = [] } = await this.Users.findOne<IUser>({ _id: uid }, { projection: { roles: 1 } }) || {};
const { roles: userRoles = [] } = await this.Users.findOneById(uid, { projection: { roles: 1 } }) || {};
const { roles: subscriptionsRoles = [] } = (scope && await Subscriptions.findOne({ rid: scope, 'u._id': uid }, { projection: { roles: 1 } })) || {};
return [...userRoles, ...subscriptionsRoles].sort((a, b) => a.localeCompare(b));
}

Loading…
Cancel
Save