refactor frontend guards

This commit is contained in:
rubikscraft 2022-03-28 16:57:37 +02:00
parent 060247c0db
commit d93ade9594
No known key found for this signature in database
GPG key ID: 1463EBE9200A5CD4
3 changed files with 47 additions and 18 deletions

View file

@ -1,10 +1,6 @@
import { isArray, isEnum, isString } from 'class-validator';
import { isPermissionsArray as isPArr } from 'picsur-shared/dist/validators/permissions.validator';
import { Permissions, PermissionsList } from '../dto/permissions.dto';
export function isPermissionsArray(value: any): value is Permissions {
if (!isArray(value)) return false;
if (!value.every((item: unknown) => isString(item))) return false;
if (!value.every((item: string) => isEnum(item, PermissionsList)))
return false;
return true;
return isPArr(value, PermissionsList);
}

View file

@ -6,17 +6,34 @@ import {
Router,
RouterStateSnapshot
} from '@angular/router';
import { HasFailed } from 'picsur-shared/dist/types';
import { isPermissionsArray } from 'picsur-shared/dist/validators/permissions.validator';
import { PRouteData } from '../models/picsur-routes';
import { PermissionService } from '../services/api/permission.service';
import { Logger } from '../services/logger/logger.service';
@Injectable({
providedIn: 'root',
})
export class PermissionGuard implements CanActivate, CanActivateChild {
private readonly logger = new Logger('PermissionGuard');
private allPermissionsArray: string[] | null = null;
constructor(
private permissionService: PermissionService,
private router: Router
) {}
) {
this.setupAllPermissions().catch(this.logger.error);
}
private async setupAllPermissions() {
const permissions = await this.permissionService.fetchAllPermission();
if (HasFailed(permissions)) {
return this.logger.error(`Could not fetch all permissions`);
}
this.allPermissionsArray = permissions;
}
async canActivateChild(
childRoute: ActivatedRouteSnapshot,
@ -33,25 +50,29 @@ export class PermissionGuard implements CanActivate, CanActivateChild {
private async can(route: ActivatedRouteSnapshot, state: RouterStateSnapshot) {
const requiredPermissions: string[] = this.nestedPermissions(route);
// TODO: revive
// if (!isPermissionsArray(requiredPermissions)) {
// throw new Error(
// `PermissionGuard: route data 'permissions' must be an array of Permission values`
// );
// }
// Check if permissions array is valid
// But only if we actually have the data
if (
this.allPermissionsArray !== null &&
!isPermissionsArray(requiredPermissions, this.allPermissionsArray)
) {
this.logger.error(`Permissions array is invalid: ${requiredPermissions}`);
return false;
}
const ourPermissions = await this.permissionService.loadedSnapshot();
const isOk = requiredPermissions.every((permission) =>
const weHavePermission = requiredPermissions.every((permission) =>
ourPermissions.includes(permission)
);
if (!isOk) {
if (!weHavePermission)
this.router.navigate(['/error/401'], { replaceUrl: true });
}
return isOk;
return weHavePermission;
}
// This aggregates nested permission for deep routes
private nestedPermissions(route: ActivatedRouteSnapshot): string[] {
const data: PRouteData = route.data;

View file

@ -0,0 +1,12 @@
import { isArray, isEnum, isString } from 'class-validator';
export function isPermissionsArray(
value: any,
permissionsList: string[],
): value is string[] {
if (!isArray(value)) return false;
if (!value.every((item: unknown) => isString(item))) return false;
if (!value.every((item: string) => isEnum(item, permissionsList)))
return false;
return true;
}