1- import jsonLogic from "json-logic-js" ;
21import pathExists from "just-has" ;
2+ import jsonLogic from "json-logic-js" ;
3+ import LRUCache from "lru-cache" ;
34import { PolicyStatementStore } from "./store/types" ;
45import { JsonLogicParser , PolicyDocument , PolicyStatement } from "./types" ;
56import {
@@ -9,8 +10,15 @@ import {
910import { PolicyDocumentValidator } from "./validator" ;
1011import { CachedStatementsStore } from "./store/cached-statements-store" ;
1112
12- interface ResourceActionResolverOptions {
13+ interface PolicyResolverOptions {
14+ /** restrict valid actions to only this list */
15+ allowedActions ?: string [ ] ;
1316 parser ?: JsonLogicParser ;
17+ cache ?: LRUCache . Options < string , CompiledFns < unknown > > ;
18+ }
19+
20+ const DEFAULT_CACHE_OPTIONS : LRUCache . Options < string , CompiledFns < unknown > > = {
21+ max : 1000
1422}
1523
1624type CompiledFns < TContext > = {
@@ -31,7 +39,7 @@ function hasAllPaths(statement: ParsedPolicyStatement, ctx: unknown) {
3139}
3240
3341export class PolicyResolver {
34- static fromDocuments ( docs : PolicyDocument [ ] ) : PolicyResolver {
42+ static fromDocuments ( docs : PolicyDocument [ ] , opts : PolicyResolverOptions = { } ) : PolicyResolver {
3543 const validator = new PolicyDocumentValidator ( ) ;
3644
3745 const statements = docs . flatMap ( ( doc ) => {
@@ -40,31 +48,33 @@ export class PolicyResolver {
4048 return doc . statement ;
4149 } ) ;
4250
43- return this . fromStatements ( statements ) ;
51+ return this . fromStatements ( statements , opts ) ;
4452 }
4553
46- static fromStatements ( statements : PolicyStatement [ ] ) : PolicyResolver {
54+ static fromStatements ( statements : PolicyStatement [ ] , opts : PolicyResolverOptions = { } ) : PolicyResolver {
4755 const parsed = statements . map ( ( statement ) =>
4856 parsePolicyStatement ( statement )
4957 ) ;
5058
5159 const store = new CachedStatementsStore ( ) ;
5260 store . addAll ( parsed ) ;
5361
54- return new PolicyResolver ( store ) ;
62+ return new PolicyResolver ( store , opts ) ;
5563 }
5664
65+ #allowedActions: string [ ] | null ;
5766 #policyStore: PolicyStatementStore ;
5867 #parser: JsonLogicParser ;
59- #cache: Map < string , CompiledFns < unknown > > ;
68+ #cache: LRUCache < string , CompiledFns < unknown > > ;
6069
6170 constructor (
6271 policyStore : PolicyStatementStore ,
63- opts : ResourceActionResolverOptions = { }
72+ opts : PolicyResolverOptions = { }
6473 ) {
6574 this . #policyStore = policyStore ;
75+ this . #allowedActions = opts . allowedActions ?? null ;
6676 this . #parser = opts . parser ?? jsonLogic ;
67- this . #cache = new Map ( ) ;
77+ this . #cache = new LRUCache ( { ... DEFAULT_CACHE_OPTIONS , ... opts . cache } ) ;
6878 }
6979
7080 /**
@@ -73,6 +83,10 @@ export class PolicyResolver {
7383 * @param context extra data that can be referenced with { "var": "path.to.resource" }
7484 */
7585 can < TContext = unknown > ( action : string , context ?: TContext ) : boolean {
86+ if ( this . #allowedActions && ! this . #allowedActions. includes ( action ) ) {
87+ return false ;
88+ }
89+
7690 if ( ! this . #cache. has ( action ) ) {
7791 this . #cache. set ( action , this . #compileAction( action ) ) ;
7892 }
@@ -89,6 +103,10 @@ export class PolicyResolver {
89103 action : string ,
90104 context ?: TContext
91105 ) : ParsedPolicyStatement [ ] {
106+ if ( this . #allowedActions && ! this . #allowedActions. includes ( action ) ) {
107+ return [ ] ;
108+ }
109+
92110 if ( ! this . #cache. has ( action ) ) {
93111 this . #cache. set ( action , this . #compileAction( action ) ) ;
94112 }
0 commit comments