Skip to content

Commit

Permalink
fix(core): Validate all Role permissions on bootstrap
Browse files Browse the repository at this point in the history
Relates to #450
  • Loading branch information
michaelbromley committed Oct 26, 2020
1 parent d525a32 commit 60c8a0e
Show file tree
Hide file tree
Showing 2 changed files with 31 additions and 8 deletions.
1 change: 1 addition & 0 deletions packages/core/src/common/permission-definition.ts
Original file line number Diff line number Diff line change
Expand Up @@ -156,6 +156,7 @@ export class CrudPermissionDefinition extends PermissionDefinition {
name: `${operation}${this.config.name}`,
description: `Grants permission to ${operation.toLocaleLowerCase()} ${this.config.name}`,
assignable: true,
internal: false,
}));
}

Expand Down
38 changes: 30 additions & 8 deletions packages/core/src/service/services/role.service.ts
Original file line number Diff line number Diff line change
Expand Up @@ -48,6 +48,7 @@ export class RoleService {
async initRoles() {
await this.ensureSuperAdminRoleExists();
await this.ensureCustomerRoleExists();
await this.ensureRolesHaveValidPermissions();
}

findAll(ctx: RequestContext, options?: ListQueryOptions<Role>): Promise<PaginatedList<Role>> {
Expand Down Expand Up @@ -198,10 +199,7 @@ export class RoleService {
if (!permissions) {
return;
}
const { customPermissions } = this.configService.authOptions;
const allAssignablePermissions = getAllPermissionsMetadata(customPermissions)
.filter(p => p.assignable)
.map(p => p.name as Permission);
const allAssignablePermissions = this.getAllAssignablePermissions();
for (const permission of permissions) {
if (!allAssignablePermissions.includes(permission) || permission === Permission.SuperAdmin) {
throw new UserInputError('error.permission-invalid', { permission });
Expand All @@ -219,10 +217,7 @@ export class RoleService {
* Ensure that the SuperAdmin role exists and that it has all possible Permissions.
*/
private async ensureSuperAdminRoleExists() {
const { customPermissions } = this.configService.authOptions;
const assignablePermissions = getAllPermissionsMetadata(customPermissions)
.filter(p => p.assignable)
.map(p => p.name as Permission);
const assignablePermissions = this.getAllAssignablePermissions();
try {
const superAdminRole = await this.getSuperAdminRole();
superAdminRole.permissions = assignablePermissions;
Expand All @@ -240,6 +235,9 @@ export class RoleService {
}
}

/**
* The Customer Role is a special case which must always exist.
*/
private async ensureCustomerRoleExists() {
try {
await this.getCustomerRole();
Expand All @@ -256,6 +254,24 @@ export class RoleService {
}
}

/**
* Since custom permissions can be added and removed by config, there may exist one or more Roles with
* invalid permissions (i.e. permissions that were set previously to a custom permission, which has been
* subsequently removed from config). This method should run on startup to ensure that any such invalid
* permissions are removed from those Roles.
*/
private async ensureRolesHaveValidPermissions() {
const roles = await this.connection.getRepository(Role).find();
const assignablePermissions = this.getAllAssignablePermissions();
for (const role of roles) {
const invalidPermissions = role.permissions.filter(p => !assignablePermissions.includes(p));
if (invalidPermissions.length) {
role.permissions = role.permissions.filter(p => assignablePermissions.includes(p));
await this.connection.getRepository(Role).save(role);
}
}
}

private createRoleForChannels(ctx: RequestContext, input: CreateRoleInput, channels: Channel[]) {
const role = new Role({
code: input.code,
Expand All @@ -265,4 +281,10 @@ export class RoleService {
role.channels = channels;
return this.connection.getRepository(ctx, Role).save(role);
}

private getAllAssignablePermissions(): Permission[] {
return getAllPermissionsMetadata(this.configService.authOptions.customPermissions)
.filter(p => p.assignable)
.map(p => p.name as Permission);
}
}

0 comments on commit 60c8a0e

Please sign in to comment.