• Home
  • Features
  • Pricing
  • Docs
  • Announcements
  • Sign In

casbin / node-casbin / 17973450686

24 Sep 2025 10:10AM UTC coverage: 78.51%. First build
17973450686

Pull #505

github

web-flow
Merge 399da2786 into 83d74da14
Pull Request #505: feat: Added methods to enforcer for adding, removing and updating policies without usage of adapter (even if autoSave is true)

847 of 1167 branches covered (72.58%)

Branch coverage included in aggregate %.

42 of 54 new or added lines in 3 files covered. (77.78%)

1619 of 1974 relevant lines covered (82.02%)

370.75 hits per line

Source File
Press 'n' to go to next uncovered line, 'b' for previous

18.67
/src/syncedEnforcer.ts
1
// Copyright 2020 The Casbin Authors. All Rights Reserved.
2
//
3
// Licensed under the Apache License, Version 2.0 (the "License");
4
// you may not use this file except in compliance with the License.
5
// You may obtain a copy of the License at
6
//
7
//      http://www.apache.org/licenses/LICENSE-2.0
8
//
9
// Unless required by applicable law or agreed to in writing, software
10
// distributed under the License is distributed on an "AS IS" BASIS,
11
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12
// See the License for the specific language governing permissions and
13
// limitations under the License.
14

15
import { Enforcer, newEnforcerWithClass } from './enforcer';
30✔
16
import AwaitLock from 'await-lock';
30✔
17
import { Watcher } from './persist';
18
import { MatchingFunc } from './rbac';
19

20
// SyncedEnforcer wraps Enforcer and provides synchronized access
21
export class SyncedEnforcer extends Enforcer {
30✔
22
  private lock = new AwaitLock();
6✔
23

24
  /**
25
   * setWatcher sets the current watcher.
26
   *
27
   * @param watcher the watcher.
28
   */
29

30
  public setWatcher(watcher: Watcher): void {
31
    this.watcher = watcher;
×
32
    this.watcher.setUpdateCallback(() => this.loadPolicy());
×
33
  }
34

35
  /**
36
   * loadPolicy reloads the policy from file/database.
37
   */
38
  public async loadPolicy(): Promise<void> {
39
    await this.lock.acquireAsync();
2✔
40
    return super.loadPolicy().finally(() => this.lock.release());
2✔
41
  }
42

43
  /**
44
   * clearPolicy clears all policy.
45
   */
46
  public clearPolicy(): void {
47
    this.lock
×
48
      .acquireAsync()
49
      .then(() => super.clearPolicy())
×
50
      .finally(() => this.lock.release());
×
51
  }
52

53
  /**
54
   * savePolicy saves the current policy (usually after changed with Casbin API) back to file/database.
55
   */
56
  public async savePolicy(): Promise<boolean> {
57
    await this.lock.acquireAsync();
×
58
    return super.savePolicy().finally(() => this.lock.release());
×
59
  }
60

61
  /**
62
   * buildRoleLinks manually rebuild the role inheritance relations.
63
   */
64
  public async buildRoleLinks(): Promise<void> {
65
    await this.lock.acquireAsync();
×
66
    return super.buildRoleLinks().finally(() => this.lock.release());
×
67
  }
68

69
  /**
70
   * If the matchers does not contain an asynchronous method, call it faster.
71
   *
72
   * enforceWithSyncCompile decides whether a "subject" can access a "object" with
73
   * the operation "action", input parameters are usually: (sub, obj, act).
74
   *
75
   * @param rvals the request needs to be mediated, usually an array
76
   *              of strings, can be class instances if ABAC is used.
77
   * @return whether to allow the request.
78
   */
79
  public enforceWithSyncCompile(...rvals: any[]): boolean {
80
    return super.enforceWithSyncCompile(...rvals);
×
81
  }
82

83
  /**
84
   * enforce decides whether a "subject" can access a "object" with
85
   * the operation "action", input parameters are usually: (sub, obj, act).
86
   *
87
   * @param rvals the request needs to be mediated, usually an array
88
   *              of strings, can be class instances if ABAC is used.
89
   * @return whether to allow the request.
90
   */
91
  public async enforce(...rvals: any[]): Promise<boolean> {
92
    await this.lock.acquireAsync();
×
93
    return super.enforce(...rvals).finally(() => this.lock.release());
×
94
  }
95

96
  /**
97
   * getAllSubjects gets the list of subjects that show up in the current policy.
98
   *
99
   * @return all the subjects in "p" policy rules. It actually collects the
100
   *         0-index elements of "p" policy rules. So make sure your subject
101
   *         is the 0-index element, like (sub, obj, act). Duplicates are removed.
102
   */
103
  public async getAllSubjects(): Promise<string[]> {
104
    return this.getAllNamedSubjects('p');
×
105
  }
106

107
  /**
108
   * getAllNamedSubjects gets the list of subjects that show up in the currentnamed policy.
109
   *
110
   * @param ptype the policy type, can be "p", "p2", "p3", ..
111
   * @return all the subjects in policy rules of the ptype type. It actually
112
   *         collects the 0-index elements of the policy rules. So make sure
113
   *         your subject is the 0-index element, like (sub, obj, act).
114
   *         Duplicates are removed.
115
   */
116
  public async getAllNamedSubjects(ptype: string): Promise<string[]> {
117
    await this.lock.acquireAsync();
×
118
    return super.getAllNamedSubjects(ptype).finally(() => this.lock.release());
×
119
  }
120

121
  /**
122
   * getAllObjects gets the list of objects that show up in the current policy.
123
   *
124
   * @return all the objects in "p" policy rules. It actually collects the
125
   *         1-index elements of "p" policy rules. So make sure your object
126
   *         is the 1-index element, like (sub, obj, act).
127
   *         Duplicates are removed.
128
   */
129
  public async getAllObjects(): Promise<string[]> {
130
    return this.getAllNamedObjects('p');
×
131
  }
132

133
  /**
134
   * getAllNamedObjects gets the list of objects that show up in the current named policy.
135
   *
136
   * @param ptype the policy type, can be "p", "p2", "p3", ..
137
   * @return all the objects in policy rules of the ptype type. It actually
138
   *         collects the 1-index elements of the policy rules. So make sure
139
   *         your object is the 1-index element, like (sub, obj, act).
140
   *         Duplicates are removed.
141
   */
142
  public async getAllNamedObjects(ptype: string): Promise<string[]> {
143
    await this.lock.acquireAsync();
×
144
    return super.getAllNamedObjects(ptype).finally(() => this.lock.release());
×
145
  }
146

147
  /**
148
   * getAllActions gets the list of actions that show up in the current policy.
149
   *
150
   * @return all the actions in "p" policy rules. It actually collects
151
   *         the 2-index elements of "p" policy rules. So make sure your action
152
   *         is the 2-index element, like (sub, obj, act).
153
   *         Duplicates are removed.
154
   */
155
  public async getAllActions(): Promise<string[]> {
156
    return this.getAllNamedActions('p');
×
157
  }
158

159
  /**
160
   * GetAllNamedActions gets the list of actions that show up in the current named policy.
161
   *
162
   * @param ptype the policy type, can be "p", "p2", "p3", ..
163
   * @return all the actions in policy rules of the ptype type. It actually
164
   *         collects the 2-index elements of the policy rules. So make sure
165
   *         your action is the 2-index element, like (sub, obj, act).
166
   *         Duplicates are removed.
167
   */
168
  public async getAllNamedActions(ptype: string): Promise<string[]> {
169
    await this.lock.acquireAsync();
×
170
    return super.getAllNamedActions(ptype).finally(() => this.lock.release());
×
171
  }
172

173
  /**
174
   * getAllRoles gets the list of roles that show up in the current policy.
175
   *
176
   * @return all the roles in "g" policy rules. It actually collects
177
   *         the 1-index elements of "g" policy rules. So make sure your
178
   *         role is the 1-index element, like (sub, role).
179
   *         Duplicates are removed.
180
   */
181
  public async getAllRoles(): Promise<string[]> {
182
    return this.getAllNamedRoles('g');
×
183
  }
184

185
  /**
186
   * getAllNamedRoles gets the list of roles that show up in the current named policy.
187
   *
188
   * @param ptype the policy type, can be "g", "g2", "g3", ..
189
   * @return all the subjects in policy rules of the ptype type. It actually
190
   *         collects the 0-index elements of the policy rules. So make
191
   *         sure your subject is the 0-index element, like (sub, obj, act).
192
   *         Duplicates are removed.
193
   */
194
  public async getAllNamedRoles(ptype: string): Promise<string[]> {
195
    await this.lock.acquireAsync();
×
196
    return super.getAllNamedRoles(ptype).finally(() => this.lock.release());
×
197
  }
198

199
  /**
200
   * getPolicy gets all the authorization rules in the policy.
201
   *
202
   * @return all the "p" policy rules.
203
   */
204
  public async getPolicy(): Promise<string[][]> {
205
    return this.getNamedPolicy('p');
×
206
  }
207

208
  /**
209
   * getFilteredPolicy gets all the authorization rules in the policy, field filters can be specified.
210
   *
211
   * @param fieldIndex the policy rule's start index to be matched.
212
   * @param fieldValues the field values to be matched, value ""
213
   *                    means not to match this field.
214
   * @return the filtered "p" policy rules.
215
   */
216
  public async getFilteredPolicy(fieldIndex: number, ...fieldValues: string[]): Promise<string[][]> {
217
    return this.getFilteredNamedPolicy('p', fieldIndex, ...fieldValues);
×
218
  }
219

220
  /**
221
   * getNamedPolicy gets all the authorization rules in the named policy.
222
   *
223
   * @param ptype the policy type, can be "p", "p2", "p3", ..
224
   * @return the "p" policy rules of the specified ptype.
225
   */
226
  public async getNamedPolicy(ptype: string): Promise<string[][]> {
227
    await this.lock.acquireAsync();
×
228
    return super.getNamedPolicy(ptype).finally(() => this.lock.release());
×
229
  }
230

231
  /**
232
   * getFilteredNamedPolicy gets all the authorization rules in the named policy, field filters can be specified.
233
   *
234
   * @param ptype the policy type, can be "p", "p2", "p3", ..
235
   * @param fieldIndex the policy rule's start index to be matched.
236
   * @param fieldValues the field values to be matched, value ""
237
   *                    means not to match this field.
238
   * @return the filtered "p" policy rules of the specified ptype.
239
   */
240
  public async getFilteredNamedPolicy(ptype: string, fieldIndex: number, ...fieldValues: string[]): Promise<string[][]> {
241
    await this.lock.acquireAsync();
×
242
    return super.getFilteredNamedPolicy(ptype, fieldIndex, ...fieldValues).finally(() => this.lock.release());
×
243
  }
244

245
  /**
246
   * getGroupingPolicy gets all the role inheritance rules in the policy.
247
   *
248
   * @return all the "g" policy rules.
249
   */
250
  public async getGroupingPolicy(): Promise<string[][]> {
251
    return this.getNamedGroupingPolicy('g');
×
252
  }
253

254
  /**
255
   * getFilteredGroupingPolicy gets all the role inheritance rules in the policy, field filters can be specified.
256
   *
257
   * @param fieldIndex the policy rule's start index to be matched.
258
   * @param fieldValues the field values to be matched, value "" means not to match this field.
259
   * @return the filtered "g" policy rules.
260
   */
261
  public async getFilteredGroupingPolicy(fieldIndex: number, ...fieldValues: string[]): Promise<string[][]> {
262
    return this.getFilteredNamedGroupingPolicy('g', fieldIndex, ...fieldValues);
×
263
  }
264

265
  /**
266
   * getNamedGroupingPolicy gets all the role inheritance rules in the policy.
267
   *
268
   * @param ptype the policy type, can be "g", "g2", "g3", ..
269
   * @return the "g" policy rules of the specified ptype.
270
   */
271
  public async getNamedGroupingPolicy(ptype: string): Promise<string[][]> {
272
    await this.lock.acquireAsync();
×
273
    return super.getNamedGroupingPolicy(ptype).finally(() => this.lock.release());
×
274
  }
275

276
  /**
277
   * getFilteredNamedGroupingPolicy gets all the role inheritance rules in the policy, field filters can be specified.
278
   *
279
   * @param ptype the policy type, can be "g", "g2", "g3", ..
280
   * @param fieldIndex the policy rule's start index to be matched.
281
   * @param fieldValues the field values to be matched, value ""
282
   *                    means not to match this field.
283
   * @return the filtered "g" policy rules of the specified ptype.
284
   */
285
  public async getFilteredNamedGroupingPolicy(ptype: string, fieldIndex: number, ...fieldValues: string[]): Promise<string[][]> {
286
    await this.lock.acquireAsync();
×
287
    return super.getFilteredNamedGroupingPolicy(ptype, fieldIndex, ...fieldValues).finally(() => this.lock.release());
×
288
  }
289

290
  /**
291
   * hasPolicy determines whether an authorization rule exists.
292
   *
293
   * @param params the "p" policy rule, ptype "p" is implicitly used.
294
   * @return whether the rule exists.
295
   */
296
  public async hasPolicy(...params: string[]): Promise<boolean> {
297
    return this.hasNamedPolicy('p', ...params);
×
298
  }
299

300
  /**
301
   * hasNamedPolicy determines whether a named authorization rule exists.
302
   *
303
   * @param ptype the policy type, can be "p", "p2", "p3", ..
304
   * @param params the "p" policy rule.
305
   * @return whether the rule exists.
306
   */
307
  public async hasNamedPolicy(ptype: string, ...params: string[]): Promise<boolean> {
308
    await this.lock.acquireAsync();
×
309
    return super.hasNamedPolicy(ptype, ...params).finally(() => this.lock.release());
×
310
  }
311

312
  /**
313
   * addPolicy adds an authorization rule to the current policy.
314
   * If the rule already exists, the function returns false and the rule will not be added.
315
   * Otherwise the function returns true by adding the new rule.
316
   *
317
   * @param params the "p" policy rule, ptype "p" is implicitly used.
318
   * @return succeeds or not.
319
   */
320
  public async addPolicy(...params: string[]): Promise<boolean> {
321
    return this.addNamedPolicy('p', ...params);
16✔
322
  }
323

324
  /**
325
   * addNamedPolicy adds an authorization rule to the current named policy.
326
   * If the rule already exists, the function returns false and the rule will not be added.
327
   * Otherwise the function returns true by adding the new rule.
328
   *
329
   * @param ptype the policy type, can be "p", "p2", "p3", ..
330
   * @param params the "p" policy rule.
331
   * @return succeeds or not.
332
   */
333
  public async addNamedPolicy(ptype: string, ...params: string[]): Promise<boolean> {
334
    await this.lock.acquireAsync();
16✔
335
    return super.addNamedPolicy(ptype, ...params).finally(() => this.lock.release());
16✔
336
  }
337

338
  /**
339
   * removePolicy removes an authorization rule from the current policy.
340
   *
341
   * @param params the "p" policy rule, ptype "p" is implicitly used.
342
   * @return succeeds or not.
343
   */
344
  public async removePolicy(...params: string[]): Promise<boolean> {
345
    return this.removeNamedPolicy('p', ...params);
×
346
  }
347

348
  /**
349
   * removeFilteredPolicy removes an authorization rule from the current policy, field filters can be specified.
350
   *
351
   * @param fieldIndex the policy rule's start index to be matched.
352
   * @param fieldValues the field values to be matched, value ""
353
   *                    means not to match this field.
354
   * @return succeeds or not.
355
   */
356
  public async removeFilteredPolicy(fieldIndex: number, ...fieldValues: string[]): Promise<boolean> {
357
    return this.removeFilteredNamedPolicy('p', fieldIndex, ...fieldValues);
×
358
  }
359

360
  /**
361
   * removeNamedPolicy removes an authorization rule from the current named policy.
362
   *
363
   * @param ptype the policy type, can be "p", "p2", "p3", ..
364
   * @param params the "p" policy rule.
365
   * @return succeeds or not.
366
   */
367
  public async removeNamedPolicy(ptype: string, ...params: string[]): Promise<boolean> {
368
    await this.lock.acquireAsync();
×
NEW
369
    return this.removePolicyInternal('p', ptype, params, true, true).finally(() => this.lock.release());
×
370
  }
371

372
  /**
373
   * removeFilteredNamedPolicy removes an authorization rule from the current named policy, field filters can be specified.
374
   *
375
   * @param ptype the policy type, can be "p", "p2", "p3", ..
376
   * @param fieldIndex the policy rule's start index to be matched.
377
   * @param fieldValues the field values to be matched, value ""
378
   *                    means not to match this field.
379
   * @return succeeds or not.
380
   */
381
  public async removeFilteredNamedPolicy(ptype: string, fieldIndex: number, ...fieldValues: string[]): Promise<boolean> {
382
    await this.lock.acquireAsync();
×
383
    return super.removeFilteredNamedPolicy(ptype, fieldIndex, ...fieldValues).finally(() => this.lock.release());
×
384
  }
385

386
  /**
387
   * hasGroupingPolicy determines whether a role inheritance rule exists.
388
   *
389
   * @param params the "g" policy rule, ptype "g" is implicitly used.
390
   * @return whether the rule exists.
391
   */
392
  public async hasGroupingPolicy(...params: string[]): Promise<boolean> {
393
    return this.hasNamedGroupingPolicy('g', ...params);
×
394
  }
395

396
  /**
397
   * hasNamedGroupingPolicy determines whether a named role inheritance rule exists.
398
   *
399
   * @param ptype the policy type, can be "g", "g2", "g3", ..
400
   * @param params the "g" policy rule.
401
   * @return whether the rule exists.
402
   */
403
  public async hasNamedGroupingPolicy(ptype: string, ...params: string[]): Promise<boolean> {
404
    await this.lock.acquireAsync();
×
405
    return super.hasNamedGroupingPolicy(ptype, ...params).finally(() => this.lock.release());
×
406
  }
407

408
  /**
409
   * addGroupingPolicy adds a role inheritance rule to the current policy.
410
   * If the rule already exists, the function returns false and the rule will not be added.
411
   * Otherwise the function returns true by adding the new rule.
412
   *
413
   * @param params the "g" policy rule, ptype "g" is implicitly used.
414
   * @return succeeds or not.
415
   */
416
  public async addGroupingPolicy(...params: string[]): Promise<boolean> {
417
    return this.addNamedGroupingPolicy('g', ...params);
6✔
418
  }
419

420
  /**
421
   * addNamedGroupingPolicy adds a named role inheritance rule to the current policy.
422
   * If the rule already exists, the function returns false and the rule will not be added.
423
   * Otherwise the function returns true by adding the new rule.
424
   *
425
   * @param ptype the policy type, can be "g", "g2", "g3", ..
426
   * @param params the "g" policy rule.
427
   * @return succeeds or not.
428
   */
429
  public async addNamedGroupingPolicy(ptype: string, ...params: string[]): Promise<boolean> {
430
    await this.lock.acquireAsync();
6✔
431
    return super.addNamedGroupingPolicy(ptype, ...params).finally(() => this.lock.release());
6✔
432
  }
433

434
  /**
435
   * removeGroupingPolicy removes a role inheritance rule from the current policy.
436
   *
437
   * @param params the "g" policy rule, ptype "g" is implicitly used.
438
   * @return succeeds or not.
439
   */
440
  public async removeGroupingPolicy(...params: string[]): Promise<boolean> {
441
    return this.removeNamedGroupingPolicy('g', ...params);
×
442
  }
443

444
  /**
445
   * removeFilteredGroupingPolicy removes a role inheritance rule from the current policy, field filters can be specified.
446
   *
447
   * @param fieldIndex the policy rule's start index to be matched.
448
   * @param fieldValues the field values to be matched, value ""
449
   *                    means not to match this field.
450
   * @return succeeds or not.
451
   */
452
  public async removeFilteredGroupingPolicy(fieldIndex: number, ...fieldValues: string[]): Promise<boolean> {
453
    return this.removeFilteredNamedGroupingPolicy('g', fieldIndex, ...fieldValues);
×
454
  }
455

456
  /**
457
   * removeNamedGroupingPolicy removes a role inheritance rule from the current named policy.
458
   *
459
   * @param ptype the policy type, can be "g", "g2", "g3", ..
460
   * @param params the "g" policy rule.
461
   * @return succeeds or not.
462
   */
463
  public async removeNamedGroupingPolicy(ptype: string, ...params: string[]): Promise<boolean> {
464
    await this.lock.acquireAsync();
×
465
    return super.removeNamedGroupingPolicy(ptype, ...params).finally(() => this.lock.release());
×
466
  }
467

468
  /**
469
   * removeFilteredNamedGroupingPolicy removes a role inheritance rule from the current named policy, field filters can be specified.
470
   *
471
   * @param ptype the policy type, can be "g", "g2", "g3", ..
472
   * @param fieldIndex the policy rule's start index to be matched.
473
   * @param fieldValues the field values to be matched, value ""
474
   *                    means not to match this field.
475
   * @return succeeds or not.
476
   */
477
  public async removeFilteredNamedGroupingPolicy(ptype: string, fieldIndex: number, ...fieldValues: string[]): Promise<boolean> {
478
    await this.lock.acquireAsync();
×
479
    return super.removeFilteredNamedGroupingPolicy(ptype, fieldIndex, ...fieldValues).finally(() => this.lock.release());
×
480
  }
481

482
  /**
483
   * UpdateGroupingPolicy updates an rule to the current named policy.
484
   *
485
   * @param oldRule the old rule.
486
   * @param newRule the new rule.
487
   * @return succeeds or not.
488
   */
489
  public async updateGroupingPolicy(oldRule: string[], newRule: string[]): Promise<boolean> {
490
    return super.updateGroupingPolicy(oldRule, newRule);
×
491
  }
492

493
  /**
494
   * updateNamedGroupingPolicy updates an rule to the current named policy.
495
   *
496
   * @param ptype the policy type, can be "g", "g2", "g3", ..
497
   * @param oldRule the old rule.
498
   * @param newRule the new rule.
499
   * @return succeeds or not.
500
   */
501
  public async updateNamedGroupingPolicy(ptype: string, oldRule: string[], newRule: string[]): Promise<boolean> {
502
    return super.updateNamedGroupingPolicy(ptype, oldRule, newRule);
×
503
  }
504

505
  /**
506
   * add matching function to RoleManager by ptype
507
   * @param ptype g
508
   * @param fn the function will be added
509
   */
510
  public async addNamedMatchingFunc(ptype: string, fn: MatchingFunc): Promise<void> {
511
    await this.lock.acquireAsync();
×
512
    return super.addNamedMatchingFunc(ptype, fn).finally(() => this.lock.release());
×
513
  }
514

515
  /**
516
   * add domain matching function to RoleManager by ptype
517
   * @param ptype g
518
   * @param fn the function will be added
519
   */
520
  public async addNamedDomainMatchingFunc(ptype: string, fn: MatchingFunc): Promise<void> {
521
    await this.lock.acquireAsync();
×
522
    return super.addNamedDomainMatchingFunc(ptype, fn).finally(() => {
×
523
      this.lock.release();
×
524
    });
525
  }
526
}
527

528
// newSyncedEnforcer creates a synchronized enforcer via file or DB.
529
export async function newSyncedEnforcer(...params: any[]): Promise<SyncedEnforcer> {
30✔
530
  return newEnforcerWithClass(SyncedEnforcer, ...params);
6✔
531
}
STATUS · Troubleshooting · Open an Issue · Sales · Support · CAREERS · ENTERPRISE · START FREE · SCHEDULE DEMO
ANNOUNCEMENTS · TWITTER · TOS & SLA · Supported CI Services · What's a CI service? · Automated Testing

© 2026 Coveralls, Inc