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'; import { Permissions, PermissionsList } from '../dto/permissions.dto';
export function isPermissionsArray(value: any): value is Permissions { export function isPermissionsArray(value: any): value is Permissions {
if (!isArray(value)) return false; return isPArr(value, PermissionsList);
if (!value.every((item: unknown) => isString(item))) return false;
if (!value.every((item: string) => isEnum(item, PermissionsList)))
return false;
return true;
} }

View file

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