import { s, parse, recursivelyReplacePlaceholders } from "bknd/utils"; import * as query from "core/object/query/object-query"; export const policySchema = s .strictObject({ description: s.string(), condition: s.object({}).optional() as s.Schema<{}, query.ObjectQuery | undefined>, // @todo: potentially remove this, and invert from rolePermission.effect effect: s.string({ enum: ["allow", "deny", "filter"], default: "allow" }), filter: s.object({}).optional() as s.Schema<{}, query.ObjectQuery | undefined>, }) .partial(); export type PolicySchema = s.Static; export class Policy { public content: Schema; constructor(content?: Schema) { this.content = parse(policySchema, content ?? {}, { withDefaults: true, }) as Schema; } replace(context: object, vars?: Record, fallback?: any) { return vars ? recursivelyReplacePlaceholders(context, /^@([a-zA-Z_\.]+)$/, vars, fallback) : context; } getReplacedFilter(context: object, fallback?: any) { if (!this.content.filter) return context; return this.replace(this.content.filter!, context, fallback); } meetsCondition(context: object, vars?: Record) { if (!this.content.condition) return true; return query.validate(this.replace(this.content.condition!, vars), context); } meetsFilter(subject: object, vars?: Record) { if (!this.content.filter) return true; return query.validate(this.replace(this.content.filter!, vars), subject); } getFiltered(given: Given): Given { return given.filter((item) => this.meetsFilter(item)) as Given; } toJSON() { return this.content; } }