From f35bbdca598dd0ceed162b3c860891663c4b9e0d Mon Sep 17 00:00:00 2001 From: Caramel Date: Tue, 28 Nov 2023 20:04:34 +0100 Subject: [PATCH] Lock the login permission for guest --- backend/src/collections/role-db/role-db.service.ts | 12 ++++++++++++ backend/src/models/constants/roles.const.ts | 11 ++++++++++- backend/src/routes/api/roles/roles.controller.ts | 2 ++ .../settings-roles-edit.component.html | 1 + .../settings-roles-edit.component.ts | 5 +++++ frontend/src/app/services/api/static-info.service.ts | 1 + shared/src/dto/api/roles.dto.ts | 2 ++ 7 files changed, 33 insertions(+), 1 deletion(-) diff --git a/backend/src/collections/role-db/role-db.service.ts b/backend/src/collections/role-db/role-db.service.ts index 2057a32..eeec810 100644 --- a/backend/src/collections/role-db/role-db.service.ts +++ b/backend/src/collections/role-db/role-db.service.ts @@ -14,6 +14,7 @@ import { ERoleBackend } from '../../database/entities/users/role.entity'; import { Permissions } from '../../models/constants/permissions.const'; import { ImmutableRolesList, + RolePermissionsLocks, UndeletableRolesList, } from '../../models/constants/roles.const'; @@ -114,6 +115,17 @@ export class RoleDbService { return Fail(FT.Permission, 'Cannot modify immutable role'); } + // If the permission are missing a role specified in RolePermissionsLocks[roleToModify.name], fail + const missingPermissions = RolePermissionsLocks[roleToModify.name].filter( + (permission) => !permissions.includes(permission), + ); + if (missingPermissions.length > 0) { + return Fail( + FT.Permission, + `Cannot remove permissions: ${missingPermissions.join(', ')}`, + ); + } + roleToModify.permissions = makeUnique(permissions); try { diff --git a/backend/src/models/constants/roles.const.ts b/backend/src/models/constants/roles.const.ts index 7fa85f9..81cd012 100644 --- a/backend/src/models/constants/roles.const.ts +++ b/backend/src/models/constants/roles.const.ts @@ -15,6 +15,15 @@ const UndeletableRolesTuple = tuple( // These roles will be applied by default to new users export const DefaultRolesList: string[] = ['user']; +// These permissions will be locked for the specified roles +export const RolePermissionsLocks: { + [key in string]: Permission[]; +} = { + guest: [Permission.UserLogin], + user: [], + admin: [], +}; + // Derivatives export const SoulBoundRolesList: string[] = SoulBoundRolesTuple; export const ImmutableRolesList: string[] = ImmutableRolesTuple; @@ -29,9 +38,9 @@ const SystemRoleDefaultsTyped: { [key in SystemRole]: Permissions; } = { guest: [ + Permission.UserLogin, Permission.ImageView, Permission.ImageDeleteKey, - Permission.UserLogin, ], user: [ Permission.ImageView, diff --git a/backend/src/routes/api/roles/roles.controller.ts b/backend/src/routes/api/roles/roles.controller.ts index 66da454..cd1e135 100644 --- a/backend/src/routes/api/roles/roles.controller.ts +++ b/backend/src/routes/api/roles/roles.controller.ts @@ -21,6 +21,7 @@ import { Permission } from '../../../models/constants/permissions.const'; import { DefaultRolesList, ImmutableRolesList, + RolePermissionsLocks, SoulBoundRolesList, UndeletableRolesList, } from '../../../models/constants/roles.const'; @@ -113,6 +114,7 @@ export class RolesController { ImmutableRoles: ImmutableRolesList, UndeletableRoles: UndeletableRolesList, DefaultRoles: DefaultRolesList, + LockedPermissions: RolePermissionsLocks, }; } } diff --git a/frontend/src/app/routes/settings/roles/settings-roles-edit/settings-roles-edit.component.html b/frontend/src/app/routes/settings/roles/settings-roles-edit/settings-roles-edit.component.html index 7fff9cc..89625ba 100644 --- a/frontend/src/app/routes/settings/roles/settings-roles-edit/settings-roles-edit.component.html +++ b/frontend/src/app/routes/settings/roles/settings-roles-edit/settings-roles-edit.component.html @@ -32,6 +32,7 @@ name="permission" [value-mapper]="UIFriendlyPermission" [control]="model.permissions" + [disabled-list]="lockedPermissions" [selection-list]="allPermissions" > diff --git a/frontend/src/app/routes/settings/roles/settings-roles-edit/settings-roles-edit.component.ts b/frontend/src/app/routes/settings/roles/settings-roles-edit/settings-roles-edit.component.ts index 25f68ae..e9f1e1e 100644 --- a/frontend/src/app/routes/settings/roles/settings-roles-edit/settings-roles-edit.component.ts +++ b/frontend/src/app/routes/settings/roles/settings-roles-edit/settings-roles-edit.component.ts @@ -25,6 +25,7 @@ export class SettingsRolesEditComponent implements OnInit { model = new UpdateRoleControl(); allPermissions: string[] = []; + lockedPermissions: string[] = []; get adding() { return this.mode === EditMode.add; @@ -57,6 +58,10 @@ export class SettingsRolesEditComponent implements OnInit { this.mode = EditMode.edit; this.model.putRoleName(rolename); + // Get special permissions + const SpecialRoles = await this.staticInfo.getSpecialRoles(); + this.lockedPermissions = SpecialRoles.LockedPermissions[rolename]; + // Fetch data and populate form const role = await this.rolesService.getRole(rolename); if (HasFailed(role)) diff --git a/frontend/src/app/services/api/static-info.service.ts b/frontend/src/app/services/api/static-info.service.ts index 9448271..2cf686b 100644 --- a/frontend/src/app/services/api/static-info.service.ts +++ b/frontend/src/app/services/api/static-info.service.ts @@ -28,6 +28,7 @@ export class StaticInfoService { ImmutableRoles: [], SoulBoundRoles: [], UndeletableRoles: [], + LockedPermissions: {}, }, () => this.api.get(SpecialRolesResponse, '/api/roles/special').result, ); diff --git a/shared/src/dto/api/roles.dto.ts b/shared/src/dto/api/roles.dto.ts index 070196a..4b195d7 100644 --- a/shared/src/dto/api/roles.dto.ts +++ b/shared/src/dto/api/roles.dto.ts @@ -4,6 +4,7 @@ import { createZodDto } from '../../util/create-zod-dto'; import { IsPosInt } from '../../validators/positive-int.validator'; import { IsRoleName } from '../../validators/role.validators'; import { IsStringList } from '../../validators/string-list.validator'; +import { Permission } from '../permissions.enum'; // RoleInfo export const RoleInfoRequestSchema = z.object({ @@ -59,6 +60,7 @@ export const SpecialRolesResponseSchema = z.object({ ImmutableRoles: IsStringList(), UndeletableRoles: IsStringList(), DefaultRoles: IsStringList(), + LockedPermissions: z.record(z.string(), z.array(z.nativeEnum(Permission))), }); export class SpecialRolesResponse extends createZodDto( SpecialRolesResponseSchema,