@@ -5,6 +5,8 @@ import { AccessControl } from './';
5
5
import { Action , actions , Possession , possessions } from './enums' ;
6
6
import { IAccessInfo , IQueryInfo , AccessControlError } from './core' ;
7
7
8
+ import type { ValidRole , ValidRoleOrArray } from '.' ;
9
+
8
10
/**
9
11
* List of reserved keywords.
10
12
* i.e. Roles, resources with these names are not allowed.
@@ -64,9 +66,10 @@ const utils = {
64
66
* @param {Any } value
65
67
* @returns {string[] }
66
68
*/
67
- toStringArray ( value : any ) : string [ ] {
69
+ toValidRoleArray ( value : unknown ) : ValidRole [ ] {
68
70
if ( Array . isArray ( value ) ) return value ;
69
71
if ( typeof value === 'string' ) return value . trim ( ) . split ( / \s * [ ; , ] \s * / ) ;
72
+ if ( typeof value === 'number' ) return [ value ]
70
73
// throw new Error('Expected a string or array of strings, got ' + utils.type(value));
71
74
return [ ] ;
72
75
} ,
@@ -77,12 +80,17 @@ const utils = {
77
80
* @param {Array } arr - Array to be checked.
78
81
* @returns {Boolean }
79
82
*/
80
- isFilledStringArray ( arr : any [ ] ) : boolean {
83
+ isFilledValidRoleArray ( arr : unknown [ ] ) : arr is ValidRole [ ] {
81
84
if ( ! arr || ! Array . isArray ( arr ) ) return false ;
82
- for ( let s of arr ) {
83
- if ( typeof s !== 'string' || s . trim ( ) === '' ) return false ;
85
+ for ( let e of arr ) {
86
+ if ( typeof e !== 'number' && ( typeof e !== ' string' || e . trim ( ) === '' ) ) return false ;
84
87
}
85
- return true ;
88
+ return arr . every ( this . isValidRole )
89
+ } ,
90
+
91
+ isValidRole ( e : unknown ) : e is ValidRole {
92
+ if ( typeof e !== 'number' && ( typeof e !== 'string' || e . trim ( ) === '' ) ) return false ;
93
+ return true ;
86
94
} ,
87
95
88
96
/**
@@ -100,7 +108,7 @@ const utils = {
100
108
* @param {Any } item - Item to be pushed to array.
101
109
* @returns {Array }
102
110
*/
103
- pushUniq ( arr : string [ ] , item : string ) : string [ ] {
111
+ pushUniq ( arr : ValidRole [ ] , item : ValidRole ) : ValidRole [ ] {
104
112
if ( arr . indexOf ( item ) < 0 ) arr . push ( item ) ;
105
113
return arr ;
106
114
} ,
@@ -111,9 +119,9 @@ const utils = {
111
119
* @param {Array } arrB
112
120
* @returns {Array } - Concat'ed array.
113
121
*/
114
- uniqConcat ( arrA : string [ ] , arrB : string [ ] ) : string [ ] {
115
- const arr : string [ ] = arrA . concat ( ) ;
116
- arrB . forEach ( ( b : string ) => {
122
+ uniqConcat ( arrA : ValidRole [ ] , arrB : ValidRole [ ] ) : ValidRole [ ] {
123
+ const arr = arrA . concat ( ) ;
124
+ arrB . forEach ( ( b ) => {
117
125
utils . pushUniq ( arr , b ) ;
118
126
} ) ;
119
127
return arr ;
@@ -125,7 +133,7 @@ const utils = {
125
133
* @param {Array } arrB
126
134
* @return {Array } - Resulting array.
127
135
*/
128
- subtractArray ( arrA : string [ ] , arrB : string [ ] ) : string [ ] {
136
+ subtractArray ( arrA : ValidRole [ ] , arrB : ValidRole [ ] ) : ValidRole [ ] {
129
137
return arrA . concat ( ) . filter ( a => arrB . indexOf ( a ) === - 1 ) ;
130
138
} ,
131
139
@@ -229,12 +237,12 @@ const utils = {
229
237
* @throws {AccessControlError } - If `throwOnInvalid` is enabled and name
230
238
* is invalid.
231
239
*/
232
- validName ( name : string , throwOnInvalid : boolean = true ) : boolean {
233
- if ( typeof name !== 'string' || name . trim ( ) === '' ) {
240
+ validName ( name : ValidRole , throwOnInvalid : boolean = true ) : boolean {
241
+ if ( ! this . isValidRole ( name ) ) {
234
242
if ( ! throwOnInvalid ) return false ;
235
243
throw new AccessControlError ( 'Invalid name, expected a valid string.' ) ;
236
244
}
237
- if ( RESERVED_KEYWORDS . indexOf ( name ) >= 0 ) {
245
+ if ( RESERVED_KEYWORDS . indexOf ( name as string ) >= 0 ) {
238
246
if ( ! throwOnInvalid ) return false ;
239
247
throw new AccessControlError ( `Cannot use reserved name: "${ name } "` ) ;
240
248
}
@@ -255,7 +263,7 @@ const utils = {
255
263
*/
256
264
hasValidNames ( list : any , throwOnInvalid : boolean = true ) : boolean {
257
265
let allValid = true ;
258
- utils . each ( utils . toStringArray ( list ) , name => {
266
+ utils . each ( utils . toValidRoleArray ( list ) , name => {
259
267
if ( ! utils . validName ( name , throwOnInvalid ) ) {
260
268
allValid = false ;
261
269
return false ; // break out of loop
@@ -290,7 +298,7 @@ const utils = {
290
298
throw new AccessControlError ( `Invalid action possession: "${ action } "` ) ;
291
299
}
292
300
let perms = o [ action ] ;
293
- if ( ! utils . isEmptyArray ( perms ) && ! utils . isFilledStringArray ( perms ) ) {
301
+ if ( ! utils . isEmptyArray ( perms ) && ! utils . isFilledValidRoleArray ( perms ) ) {
294
302
throw new AccessControlError ( `Invalid resource attributes for action "${ action } ".` ) ;
295
303
}
296
304
} ) ;
@@ -318,7 +326,7 @@ const utils = {
318
326
if ( ! utils . validName ( resourceName , false ) ) {
319
327
if ( resourceName === '$extend' ) {
320
328
let extRoles : string [ ] = role [ resourceName ] ; // semantics
321
- if ( ! utils . isFilledStringArray ( extRoles ) ) {
329
+ if ( ! utils . isFilledValidRoleArray ( extRoles ) ) {
322
330
throw new AccessControlError ( `Invalid extend value for role "${ roleName } ": ${ JSON . stringify ( extRoles ) } ` ) ;
323
331
} else {
324
332
// attempt to actually extend the roles. this will throw
@@ -449,8 +457,8 @@ const utils = {
449
457
// clone the object
450
458
query = Object . assign ( { } , query ) ;
451
459
// validate and normalize role(s)
452
- query . role = utils . toStringArray ( query . role ) ;
453
- if ( ! utils . isFilledStringArray ( query . role ) ) {
460
+ query . role = utils . toValidRoleArray ( query . role ) ;
461
+ if ( ! utils . isFilledValidRoleArray ( query . role ) ) {
454
462
throw new AccessControlError ( `Invalid role(s): ${ JSON . stringify ( query . role ) } ` ) ;
455
463
}
456
464
@@ -482,14 +490,14 @@ const utils = {
482
490
// clone the object
483
491
access = Object . assign ( { } , access ) ;
484
492
// validate and normalize role(s)
485
- access . role = utils . toStringArray ( access . role ) ;
486
- if ( access . role . length === 0 || ! utils . isFilledStringArray ( access . role ) ) {
493
+ access . role = utils . toValidRoleArray ( access . role ) ;
494
+ if ( access . role . length === 0 || ! utils . isFilledValidRoleArray ( access . role ) ) {
487
495
throw new AccessControlError ( `Invalid role(s): ${ JSON . stringify ( access . role ) } ` ) ;
488
496
}
489
497
490
498
// validate and normalize resource
491
- access . resource = utils . toStringArray ( access . resource ) ;
492
- if ( access . resource . length === 0 || ! utils . isFilledStringArray ( access . resource ) ) {
499
+ access . resource = utils . toValidRoleArray ( access . resource ) ;
500
+ if ( access . resource . length === 0 || ! utils . isFilledValidRoleArray ( access . resource ) ) {
493
501
throw new AccessControlError ( `Invalid resource(s): ${ JSON . stringify ( access . resource ) } ` ) ;
494
502
}
495
503
@@ -498,7 +506,7 @@ const utils = {
498
506
access . attributes = [ ] ;
499
507
} else {
500
508
// if omitted and not denied, all attributes are allowed
501
- access . attributes = ! access . attributes ? [ '*' ] : utils . toStringArray ( access . attributes ) ;
509
+ access . attributes = ! access . attributes ? [ '*' ] : utils . toValidRoleArray ( access . attributes ) ;
502
510
}
503
511
504
512
// this part is not necessary if this is invoked from a comitter method
@@ -533,15 +541,15 @@ const utils = {
533
541
* @param {string } roleName - Role name to be inspected.
534
542
* @returns {string[] }
535
543
*/
536
- getRoleHierarchyOf ( grants : any , roleName : string , rootRole ?: string ) : string [ ] {
544
+ getRoleHierarchyOf ( grants : any , roleName : ValidRole , rootRole ?: ValidRole ) : ValidRole [ ] {
537
545
// `rootRole` is for memory storage. Do NOT set it when using;
538
546
// and do NOT document this paramter.
539
547
// rootRole = rootRole || roleName;
540
548
541
549
const role : any = grants [ roleName ] ;
542
550
if ( ! role ) throw new AccessControlError ( `Role not found: "${ roleName } "` ) ;
543
551
544
- let arr : string [ ] = [ roleName ] ;
552
+ let arr = [ roleName ] ;
545
553
if ( ! Array . isArray ( role . $extend ) || role . $extend . length === 0 ) return arr ;
546
554
547
555
role . $extend . forEach ( ( exRoleName : string ) => {
@@ -556,7 +564,7 @@ const utils = {
556
564
if ( rootRole && ( rootRole === exRoleName ) ) {
557
565
throw new AccessControlError ( `Cross inheritance is not allowed. Role "${ exRoleName } " already extends "${ rootRole } ".` ) ;
558
566
}
559
- let ext : string [ ] = utils . getRoleHierarchyOf ( grants , exRoleName , rootRole || roleName ) ;
567
+ let ext = utils . getRoleHierarchyOf ( grants , exRoleName , rootRole || roleName ) ;
560
568
arr = utils . uniqConcat ( arr , ext ) ;
561
569
} ) ;
562
570
return arr ;
@@ -565,12 +573,12 @@ const utils = {
565
573
/**
566
574
* Gets roles and extended roles in a flat array.
567
575
*/
568
- getFlatRoles ( grants : any , roles : string | string [ ] ) : string [ ] {
569
- const arrRoles : string [ ] = utils . toStringArray ( roles ) ;
576
+ getFlatRoles ( grants : any , roles : ValidRoleOrArray ) : ValidRole [ ] {
577
+ const arrRoles = utils . toValidRoleArray ( roles ) ;
570
578
if ( arrRoles . length === 0 ) {
571
579
throw new AccessControlError ( `Invalid role(s): ${ JSON . stringify ( roles ) } ` ) ;
572
580
}
573
- let arr : string [ ] = utils . uniqConcat ( [ ] , arrRoles ) ; // roles.concat();
581
+ let arr = utils . uniqConcat ( [ ] , arrRoles ) ; // roles.concat();
574
582
arrRoles . forEach ( ( roleName : string ) => {
575
583
arr = utils . uniqConcat ( arr , utils . getRoleHierarchyOf ( grants , roleName ) ) ;
576
584
} ) ;
@@ -583,11 +591,11 @@ const utils = {
583
591
* from the given roles.
584
592
* @param {Any } grants - Grants model to be checked.
585
593
* @param {string[] } roles - Roles to be checked.
586
- * @returns {string [] } - Array of non-existent roles. Empty array if
594
+ * @returns {ValidRole [] } - Array of non-existent roles. Empty array if
587
595
* all exist.
588
596
*/
589
- getNonExistentRoles ( grants : any , roles : string [ ] ) {
590
- let non : string [ ] = [ ] ;
597
+ getNonExistentRoles ( grants : any , roles : ValidRole [ ] ) {
598
+ let non : ValidRole [ ] = [ ] ;
591
599
if ( utils . isEmptyArray ( roles ) ) return non ;
592
600
for ( let role of roles ) {
593
601
if ( ! grants . hasOwnProperty ( role ) ) non . push ( role ) ;
@@ -609,8 +617,8 @@ const utils = {
609
617
* @returns {string|null } - Returns the first cross extending role. `null`
610
618
* if none.
611
619
*/
612
- getCrossExtendingRole ( grants : any , roleName : string , extenderRoles : string | string [ ] ) : string {
613
- const extenders : string [ ] = utils . toStringArray ( extenderRoles ) ;
620
+ getCrossExtendingRole ( grants : any , roleName : string , extenderRoles : ValidRoleOrArray ) : string {
621
+ const extenders : ValidRole [ ] = utils . toValidRoleArray ( extenderRoles ) ;
614
622
let crossInherited : any = null ;
615
623
utils . each ( extenders , ( e : string ) => {
616
624
if ( crossInherited || roleName === e ) {
@@ -647,22 +655,22 @@ const utils = {
647
655
* @throws {Error } If a role is extended by itself, a non-existent role or
648
656
* a cross-inherited role.
649
657
*/
650
- extendRole ( grants : any , roles : string | string [ ] , extenderRoles : string | string [ ] ) {
658
+ extendRole ( grants : any , roles : ValidRoleOrArray , extenderRoles : ValidRoleOrArray ) {
651
659
// roles cannot be omitted or an empty array
652
- roles = utils . toStringArray ( roles ) ;
660
+ roles = utils . toValidRoleArray ( roles ) ;
653
661
if ( roles . length === 0 ) {
654
662
throw new AccessControlError ( `Invalid role(s): ${ JSON . stringify ( roles ) } ` ) ;
655
663
}
656
664
657
665
// extenderRoles cannot be omitted or but can be an empty array
658
666
if ( utils . isEmptyArray ( extenderRoles ) ) return ;
659
667
660
- const arrExtRoles : string [ ] = utils . toStringArray ( extenderRoles ) . concat ( ) ;
668
+ const arrExtRoles : ValidRole [ ] = utils . toValidRoleArray ( extenderRoles ) . concat ( ) ;
661
669
if ( arrExtRoles . length === 0 ) {
662
670
throw new AccessControlError ( `Cannot inherit invalid role(s): ${ JSON . stringify ( extenderRoles ) } ` ) ;
663
671
}
664
672
665
- const nonExistentExtRoles : string [ ] = utils . getNonExistentRoles ( grants , arrExtRoles ) ;
673
+ const nonExistentExtRoles : ValidRole [ ] = utils . getNonExistentRoles ( grants , arrExtRoles ) ;
666
674
if ( nonExistentExtRoles . length > 0 ) {
667
675
throw new AccessControlError ( `Cannot inherit non-existent role(s): "${ nonExistentExtRoles . join ( ', ' ) } "` ) ;
668
676
}
@@ -699,12 +707,12 @@ const utils = {
699
707
* @param {Any } grants
700
708
* @param {string|string[] } roles
701
709
*/
702
- preCreateRoles ( grants : any , roles : string | string [ ] ) {
703
- if ( typeof roles === 'string' ) roles = utils . toStringArray ( roles ) ;
710
+ preCreateRoles ( grants : any , roles : ValidRoleOrArray ) {
711
+ if ( typeof roles === 'string' ) roles = utils . toValidRoleArray ( roles ) ;
704
712
if ( ! Array . isArray ( roles ) || roles . length === 0 ) {
705
713
throw new AccessControlError ( `Invalid role(s): ${ JSON . stringify ( roles ) } ` ) ;
706
714
}
707
- ( roles as string [ ] ) . forEach ( ( role : string ) => {
715
+ roles . forEach ( ( role : string ) => {
708
716
if ( utils . validName ( role ) && ! grants . hasOwnProperty ( role ) ) {
709
717
grants [ role ] = { } ;
710
718
}
@@ -740,7 +748,7 @@ const utils = {
740
748
// If possession (in action value or as a separate property) is
741
749
// omitted, it will default to "any". e.g. "create" —>
742
750
// "create:any"
743
- grantItem [ res ] [ ap ] = utils . toStringArray ( access . attributes ) ;
751
+ grantItem [ res ] [ ap ] = utils . toValidRoleArray ( access . attributes ) ;
744
752
} ) ;
745
753
} ) ;
746
754
} ,
@@ -764,7 +772,7 @@ const utils = {
764
772
let resource : string ;
765
773
let attrsList : Array < string [ ] > = [ ] ;
766
774
// get roles and extended roles in a flat array
767
- const roles : string [ ] = utils . getFlatRoles ( grants , query . role ) ;
775
+ const roles : ValidRole [ ] = utils . getFlatRoles ( grants , query . role ) ;
768
776
// iterate through roles and add permission attributes (array) of
769
777
// each role to attrsList (array).
770
778
roles . forEach ( ( roleName : string , index : number ) => {
0 commit comments