refactor frontend guards
This commit is contained in:
parent
060247c0db
commit
d93ade9594
|
@ -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;
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -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;
|
||||||
|
|
||||||
|
|
12
shared/src/validators/permissions.validator.ts
Normal file
12
shared/src/validators/permissions.validator.ts
Normal 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;
|
||||||
|
}
|
Loading…
Reference in a new issue