casbin 5.23.1 → 5.24.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/CHANGELOG.md CHANGED
@@ -1,3 +1,17 @@
1
+ # [5.24.0](https://github.com/casbin/node-casbin/compare/v5.23.2...v5.24.0) (2023-02-17)
2
+
3
+
4
+ ### Features
5
+
6
+ * add built-in FileSystem ([#430](https://github.com/casbin/node-casbin/issues/430)) ([999c34c](https://github.com/casbin/node-casbin/commit/999c34c620c7b8d608c7405550737bc0dfa974f5))
7
+
8
+ ## [5.23.2](https://github.com/casbin/node-casbin/compare/v5.23.1...v5.23.2) (2023-02-04)
9
+
10
+
11
+ ### Bug Fixes
12
+
13
+ * fix typo in subject_priority_policy.csv ([#425](https://github.com/casbin/node-casbin/issues/425)) ([ada2543](https://github.com/casbin/node-casbin/commit/ada25436fe7baa37959e1d4f67a644e833e88656))
14
+
1
15
  ## [5.23.1](https://github.com/casbin/node-casbin/compare/v5.23.0...v5.23.1) (2023-02-02)
2
16
 
3
17
 
@@ -2,7 +2,7 @@ p, root, data1, read, deny
2
2
  p, admin, data1, read, deny
3
3
 
4
4
  p, editor, data1, read, deny
5
- p, subscriber, data1, deny
5
+ p, subscriber, data1, read, deny
6
6
 
7
7
  p, jane, data1, read, allow
8
8
  p, alice, data1, read, allow
@@ -1,3 +1,4 @@
1
+ import { FileSystem } from './persist';
1
2
  export interface ConfigInterface {
2
3
  getString(key: string): string;
3
4
  getStrings(key: string): string[];
@@ -12,14 +13,22 @@ export declare class Config implements ConfigInterface {
12
13
  private static DEFAULT_COMMENT_SEM;
13
14
  private static DEFAULT_MULTI_LINE_SEPARATOR;
14
15
  private data;
16
+ private readonly fs?;
15
17
  private constructor();
16
18
  /**
17
19
  * newConfig create an empty configuration representation from file.
18
20
  *
19
21
  * @param confName the path of the model file.
20
22
  * @return the constructor of Config.
23
+ * @deprecated use {@link newConfigFromFile} instead.
21
24
  */
22
25
  static newConfig(confName: string): Config;
26
+ /**
27
+ * newConfigFromFile create an empty configuration representation from file.
28
+ * @param path the path of the model file.
29
+ * @param fs {@link FileSystem}
30
+ */
31
+ static newConfigFromFile(path: string, fs?: FileSystem): Config;
23
32
  /**
24
33
  * newConfigFromText create an empty configuration representation from text.
25
34
  *
package/lib/cjs/config.js CHANGED
@@ -1,6 +1,4 @@
1
1
  "use strict";
2
- Object.defineProperty(exports, "__esModule", { value: true });
3
- exports.Config = void 0;
4
2
  // Copyright 2018 The Casbin Authors. All Rights Reserved.
5
3
  //
6
4
  // Licensed under the Apache License, Version 2.0 (the "License");
@@ -14,20 +12,34 @@ exports.Config = void 0;
14
12
  // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
15
13
  // See the License for the specific language governing permissions and
16
14
  // limitations under the License.
17
- const fs_1 = require("fs");
15
+ Object.defineProperty(exports, "__esModule", { value: true });
16
+ exports.Config = void 0;
17
+ const persist_1 = require("./persist");
18
18
  class Config {
19
- constructor() {
19
+ constructor(fs) {
20
20
  this.data = new Map();
21
+ if (fs) {
22
+ this.fs = fs;
23
+ }
21
24
  }
22
25
  /**
23
26
  * newConfig create an empty configuration representation from file.
24
27
  *
25
28
  * @param confName the path of the model file.
26
29
  * @return the constructor of Config.
30
+ * @deprecated use {@link newConfigFromFile} instead.
27
31
  */
28
32
  static newConfig(confName) {
29
- const config = new Config();
30
- config.parse(confName);
33
+ return this.newConfigFromFile(confName);
34
+ }
35
+ /**
36
+ * newConfigFromFile create an empty configuration representation from file.
37
+ * @param path the path of the model file.
38
+ * @param fs {@link FileSystem}
39
+ */
40
+ static newConfigFromFile(path, fs) {
41
+ const config = new Config(fs);
42
+ config.parse(path);
31
43
  return config;
32
44
  }
33
45
  /**
@@ -62,8 +74,8 @@ class Config {
62
74
  }
63
75
  }
64
76
  parse(path) {
65
- const buf = fs_1.readFileSync(path);
66
- this.parseBuffer(buf);
77
+ const body = (this.fs ? this.fs : persist_1.mustGetDefaultFileSystem()).readFileSync(path);
78
+ this.parseBuffer(Buffer.isBuffer(body) ? body : Buffer.from(body));
67
79
  }
68
80
  parseBuffer(buf) {
69
81
  const lines = buf
@@ -3,6 +3,7 @@ import { FunctionMap, Model, PolicyOp } from './model';
3
3
  import { Adapter, FilteredAdapter, Watcher, BatchAdapter, UpdatableAdapter, WatcherEx } from './persist';
4
4
  import { RoleManager } from './rbac';
5
5
  import { MatchingFunc } from './rbac';
6
+ import { FileSystem } from './persist';
6
7
  /**
7
8
  * CoreEnforcer defines the core functionality of an enforcer.
8
9
  */
@@ -20,6 +21,16 @@ export declare class CoreEnforcer {
20
21
  protected autoSave: boolean;
21
22
  protected autoBuildRoleLinks: boolean;
22
23
  protected autoNotifyWatcher: boolean;
24
+ protected fs?: FileSystem;
25
+ /**
26
+ * setFileSystem sets a file system to read the model file or the policy file.
27
+ * @param fs {@link FileSystem}
28
+ */
29
+ setFileSystem(fs: FileSystem): void;
30
+ /**
31
+ * getFileSystem gets the file system,
32
+ */
33
+ getFileSystem(): FileSystem | undefined;
23
34
  private getExpression;
24
35
  /**
25
36
  * loadModel reloads the model from the model CONF file.
@@ -35,6 +35,19 @@ class CoreEnforcer {
35
35
  this.autoBuildRoleLinks = true;
36
36
  this.autoNotifyWatcher = true;
37
37
  }
38
+ /**
39
+ * setFileSystem sets a file system to read the model file or the policy file.
40
+ * @param fs {@link FileSystem}
41
+ */
42
+ setFileSystem(fs) {
43
+ this.fs = fs;
44
+ }
45
+ /**
46
+ * getFileSystem gets the file system,
47
+ */
48
+ getFileSystem() {
49
+ return this.fs;
50
+ }
38
51
  getExpression(asyncCompile, exp) {
39
52
  const matcherKey = `${asyncCompile ? 'ASYNC[' : 'SYNC['}${exp}]`;
40
53
  expression_eval_1.addBinaryOp('in', 1, util_1.customIn);
@@ -52,8 +65,7 @@ class CoreEnforcer {
52
65
  * so the policy is invalidated and needs to be reloaded by calling LoadPolicy().
53
66
  */
54
67
  loadModel() {
55
- this.model = model_1.newModel();
56
- this.model.loadModel(this.modelPath);
68
+ this.model = model_1.newModelFromFile(this.modelPath, this.fs);
57
69
  this.model.printModel();
58
70
  }
59
71
  /**
@@ -30,7 +30,7 @@ class Enforcer extends managementEnforcer_1.ManagementEnforcer {
30
30
  * @param lazyLoad lazyLoad whether to load policy at initial time
31
31
  */
32
32
  async initWithFile(modelPath, policyPath, lazyLoad = false) {
33
- const a = new persist_1.FileAdapter(policyPath);
33
+ const a = new persist_1.FileAdapter(policyPath, this.fs);
34
34
  await this.initWithAdapter(modelPath, a, lazyLoad);
35
35
  }
36
36
  /**
@@ -50,7 +50,7 @@ class Enforcer extends managementEnforcer_1.ManagementEnforcer {
50
50
  * @param lazyLoad whether to load policy at initial time
51
51
  */
52
52
  async initWithAdapter(modelPath, adapter, lazyLoad = false) {
53
- const m = model_1.newModel(modelPath, '');
53
+ const m = model_1.newModelFromFile(modelPath, this.fs);
54
54
  await this.initWithModelAndAdapter(m, adapter, lazyLoad);
55
55
  this.modelPath = modelPath;
56
56
  }
package/lib/cjs/index.js CHANGED
@@ -34,10 +34,12 @@ var __importStar = (this && this.__importStar) || function (mod) {
34
34
  var __exportStar = (this && this.__exportStar) || function(m, exports) {
35
35
  for (var p in m) if (p !== "default" && !exports.hasOwnProperty(p)) __createBinding(exports, m, p);
36
36
  };
37
+ var _a;
37
38
  Object.defineProperty(exports, "__esModule", { value: true });
38
39
  exports.Util = void 0;
39
40
  const Util = __importStar(require("./util"));
40
41
  exports.Util = Util;
42
+ const persist_1 = require("./persist");
41
43
  __exportStar(require("./config"), exports);
42
44
  __exportStar(require("./enforcer"), exports);
43
45
  __exportStar(require("./cachedEnforcer"), exports);
@@ -48,3 +50,16 @@ __exportStar(require("./persist"), exports);
48
50
  __exportStar(require("./rbac"), exports);
49
51
  __exportStar(require("./log"), exports);
50
52
  __exportStar(require("./frontend"), exports);
53
+ if (typeof process !== 'undefined' && ((_a = process === null || process === void 0 ? void 0 : process.versions) === null || _a === void 0 ? void 0 : _a.node)) {
54
+ const requireFunc = typeof __non_webpack_require__ === 'function' ? __non_webpack_require__ : require;
55
+ const fs = requireFunc('fs');
56
+ const defaultFileSystem = {
57
+ readFileSync(path, encoding) {
58
+ return fs.readFileSync(path, { encoding });
59
+ },
60
+ writeFileSync(path, text, encoding) {
61
+ return fs.writeFileSync(path, text, encoding);
62
+ },
63
+ };
64
+ persist_1.setDefaultFileSystem(defaultFileSystem);
65
+ }
@@ -1,6 +1,7 @@
1
1
  import * as rbac from '../rbac';
2
2
  import { ConfigInterface } from '../config';
3
3
  import { Assertion } from './assertion';
4
+ import { FileSystem } from '../persist/fileSystem';
4
5
  export declare const sectionNameMap: {
5
6
  [index: string]: string;
6
7
  };
@@ -19,7 +20,19 @@ export declare class Model {
19
20
  private getKeySuffix;
20
21
  private loadSection;
21
22
  addDef(sec: string, key: string, value: string): boolean;
22
- loadModel(path: string): void;
23
+ /**
24
+ * loadModel loads the model from model CONF file.
25
+ * @param path the model file path
26
+ * @param fs {@link FileSystem}
27
+ * @deprecated {@link loadModelFromFile}
28
+ */
29
+ loadModel(path: string, fs?: FileSystem): void;
30
+ /**
31
+ * loadModelFromFile loads the model from model CONF file.
32
+ * @param path the model file path
33
+ * @param fs {@link FileSystem}
34
+ */
35
+ loadModelFromFile(path: string, fs?: FileSystem): void;
23
36
  loadModelFromText(text: string): void;
24
37
  loadModelFromConfig(cfg: ConfigInterface): void;
25
38
  private hasSection;
@@ -64,7 +77,7 @@ export declare function newModel(...text: string[]): Model;
64
77
  /**
65
78
  * newModelFromFile creates a model from a .CONF file.
66
79
  */
67
- export declare function newModelFromFile(path: string): Model;
80
+ export declare function newModelFromFile(path: string, fs?: FileSystem): Model;
68
81
  /**
69
82
  * newModelFromString creates a model from a string which contains model text.
70
83
  */
@@ -123,9 +123,22 @@ class Model {
123
123
  }
124
124
  return true;
125
125
  }
126
- // loadModel loads the model from model CONF file.
127
- loadModel(path) {
128
- const cfg = config_1.Config.newConfig(path);
126
+ /**
127
+ * loadModel loads the model from model CONF file.
128
+ * @param path the model file path
129
+ * @param fs {@link FileSystem}
130
+ * @deprecated {@link loadModelFromFile}
131
+ */
132
+ loadModel(path, fs) {
133
+ this.loadModelFromFile(path, fs);
134
+ }
135
+ /**
136
+ * loadModelFromFile loads the model from model CONF file.
137
+ * @param path the model file path
138
+ * @param fs {@link FileSystem}
139
+ */
140
+ loadModelFromFile(path, fs) {
141
+ const cfg = config_1.Config.newConfigFromFile(path, fs);
129
142
  this.loadModelFromConfig(cfg);
130
143
  }
131
144
  // loadModelFromText loads the model from the text.
@@ -532,7 +545,7 @@ function newModel(...text) {
532
545
  const m = new Model();
533
546
  if (text.length === 2) {
534
547
  if (text[0] !== '') {
535
- m.loadModel(text[0]);
548
+ m.loadModelFromFile(text[0]);
536
549
  }
537
550
  }
538
551
  else if (text.length === 1) {
@@ -547,9 +560,11 @@ exports.newModel = newModel;
547
560
  /**
548
561
  * newModelFromFile creates a model from a .CONF file.
549
562
  */
550
- function newModelFromFile(path) {
563
+ function newModelFromFile(path, fs) {
551
564
  const m = new Model();
552
- m.loadModel(path);
565
+ if (path) {
566
+ m.loadModelFromFile(path, fs);
567
+ }
553
568
  return m;
554
569
  }
555
570
  exports.newModelFromFile = newModelFromFile;
@@ -1,16 +1,20 @@
1
1
  import { Adapter } from './adapter';
2
2
  import { Model } from '../model';
3
+ import { FileSystem } from './fileSystem';
3
4
  /**
4
5
  * FileAdapter is the file adapter for Casbin.
5
6
  * It can load policy from file or save policy to file.
6
7
  */
7
8
  export declare class FileAdapter implements Adapter {
8
9
  readonly filePath: string;
10
+ protected readonly fs?: FileSystem;
9
11
  /**
10
12
  * FileAdapter is the constructor for FileAdapter.
11
- * @param {string} filePath filePath the path of the policy file.
13
+ *
14
+ * @param filePath filePath the path of the policy file.
15
+ * @param fs {@link FileSystem}
12
16
  */
13
- constructor(filePath: string);
17
+ constructor(filePath: string, fs?: FileSystem);
14
18
  loadPolicy(model: Model): Promise<void>;
15
19
  private loadPolicyFile;
16
20
  /**
@@ -3,6 +3,7 @@ Object.defineProperty(exports, "__esModule", { value: true });
3
3
  exports.FileAdapter = void 0;
4
4
  const helper_1 = require("./helper");
5
5
  const util_1 = require("../util");
6
+ const fileSystem_1 = require("./fileSystem");
6
7
  /**
7
8
  * FileAdapter is the file adapter for Casbin.
8
9
  * It can load policy from file or save policy to file.
@@ -10,10 +11,13 @@ const util_1 = require("../util");
10
11
  class FileAdapter {
11
12
  /**
12
13
  * FileAdapter is the constructor for FileAdapter.
13
- * @param {string} filePath filePath the path of the policy file.
14
+ *
15
+ * @param filePath filePath the path of the policy file.
16
+ * @param fs {@link FileSystem}
14
17
  */
15
- constructor(filePath) {
18
+ constructor(filePath, fs) {
16
19
  this.filePath = filePath;
20
+ this.fs = fs;
17
21
  }
18
22
  async loadPolicy(model) {
19
23
  if (!this.filePath) {
@@ -23,7 +27,7 @@ class FileAdapter {
23
27
  await this.loadPolicyFile(model, helper_1.Helper.loadPolicyLine);
24
28
  }
25
29
  async loadPolicyFile(model, handler) {
26
- const bodyBuf = await util_1.readFile(this.filePath);
30
+ const bodyBuf = await (this.fs ? this.fs : fileSystem_1.mustGetDefaultFileSystem()).readFileSync(this.filePath);
27
31
  const lines = bodyBuf.toString().split('\n');
28
32
  lines.forEach((n, index) => {
29
33
  if (!n) {
@@ -67,7 +71,7 @@ class FileAdapter {
67
71
  return true;
68
72
  }
69
73
  async savePolicyFile(text) {
70
- await util_1.writeFile(this.filePath, text);
74
+ (this.fs ? this.fs : fileSystem_1.mustGetDefaultFileSystem()).writeFileSync(this.filePath, text);
71
75
  }
72
76
  /**
73
77
  * addPolicy adds a policy rule to the storage.
@@ -0,0 +1,8 @@
1
+ /// <reference types="node" />
2
+ export interface FileSystem {
3
+ readFileSync(path: string, encoding?: string): Buffer | string;
4
+ writeFileSync(path: string, text: string, encoding?: string): void;
5
+ }
6
+ export declare const setDefaultFileSystem: (fs?: FileSystem | undefined) => void;
7
+ export declare const getDefaultFileSystem: () => FileSystem | undefined;
8
+ export declare const mustGetDefaultFileSystem: () => FileSystem;
@@ -0,0 +1,15 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.mustGetDefaultFileSystem = exports.getDefaultFileSystem = exports.setDefaultFileSystem = void 0;
4
+ let defaultFileSystem = undefined;
5
+ const ErrorNoFileSystem = new Error('please set the default FileSystem by call the setDefaultFileSystem');
6
+ exports.setDefaultFileSystem = (fs) => {
7
+ defaultFileSystem = fs;
8
+ };
9
+ exports.getDefaultFileSystem = () => defaultFileSystem;
10
+ exports.mustGetDefaultFileSystem = () => {
11
+ if (defaultFileSystem) {
12
+ return defaultFileSystem;
13
+ }
14
+ throw ErrorNoFileSystem;
15
+ };
@@ -9,3 +9,4 @@ export * from './defaultFilteredAdapter';
9
9
  export * from './batchAdapter';
10
10
  export * from './batchFileAdapter';
11
11
  export * from './updatableAdapter';
12
+ export * from './fileSystem';
@@ -21,3 +21,4 @@ __exportStar(require("./defaultFilteredAdapter"), exports);
21
21
  __exportStar(require("./batchAdapter"), exports);
22
22
  __exportStar(require("./batchFileAdapter"), exports);
23
23
  __exportStar(require("./updatableAdapter"), exports);
24
+ __exportStar(require("./fileSystem"), exports);
@@ -12,30 +12,11 @@
12
12
  // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13
13
  // See the License for the specific language governing permissions and
14
14
  // limitations under the License.
15
- var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
16
- if (k2 === undefined) k2 = k;
17
- Object.defineProperty(o, k2, { enumerable: true, get: function() { return m[k]; } });
18
- }) : (function(o, m, k, k2) {
19
- if (k2 === undefined) k2 = k;
20
- o[k2] = m[k];
21
- }));
22
- var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) {
23
- Object.defineProperty(o, "default", { enumerable: true, value: v });
24
- }) : function(o, v) {
25
- o["default"] = v;
26
- });
27
- var __importStar = (this && this.__importStar) || function (mod) {
28
- if (mod && mod.__esModule) return mod;
29
- var result = {};
30
- if (mod != null) for (var k in mod) if (k !== "default" && Object.hasOwnProperty.call(mod, k)) __createBinding(result, mod, k);
31
- __setModuleDefault(result, mod);
32
- return result;
33
- };
34
15
  Object.defineProperty(exports, "__esModule", { value: true });
35
16
  exports.bracketCompatible = exports.customIn = exports.deepCopy = exports.generatorRunAsync = exports.generatorRunSync = exports.getEvalValue = exports.replaceEval = exports.hasEval = exports.writeFile = exports.readFile = exports.setEquals = exports.paramsToString = exports.arrayToString = exports.arrayRemoveDuplicates = exports.array2DEquals = exports.arrayEquals = exports.removeComments = exports.escapeAssertion = void 0;
36
- const fs = __importStar(require("fs"));
37
17
  // escapeAssertion escapes the dots in the assertion,
38
18
  // because the expression evaluation doesn't support such variable names.
19
+ const persist_1 = require("../persist");
39
20
  function escapeAssertion(s) {
40
21
  s = s.replace(/r\./g, 'r_');
41
22
  s = s.replace(/p\./g, 'p_');
@@ -100,25 +81,29 @@ function setEquals(a, b) {
100
81
  exports.setEquals = setEquals;
101
82
  // readFile return a promise for readFile.
102
83
  function readFile(path, encoding) {
84
+ const fs = persist_1.mustGetDefaultFileSystem();
103
85
  return new Promise((resolve, reject) => {
104
- fs.readFile(path, encoding || 'utf8', (error, data) => {
105
- if (error) {
106
- reject(error);
107
- }
108
- resolve(data);
109
- });
86
+ try {
87
+ fs.readFileSync(path, encoding || 'utf8');
88
+ resolve();
89
+ }
90
+ catch (e) {
91
+ reject(e);
92
+ }
110
93
  });
111
94
  }
112
95
  exports.readFile = readFile;
113
96
  // writeFile return a promise for writeFile.
114
97
  function writeFile(path, file, encoding) {
98
+ const fs = persist_1.mustGetDefaultFileSystem();
115
99
  return new Promise((resolve, reject) => {
116
- fs.writeFile(path, file, encoding || 'utf8', (error) => {
117
- if (error) {
118
- reject(error);
119
- }
120
- resolve(true);
121
- });
100
+ try {
101
+ fs.writeFileSync(path, file, encoding || 'utf-8');
102
+ resolve();
103
+ }
104
+ catch (e) {
105
+ reject(e);
106
+ }
122
107
  });
123
108
  }
124
109
  exports.writeFile = writeFile;
@@ -1,3 +1,4 @@
1
+ import { FileSystem } from './persist';
1
2
  export interface ConfigInterface {
2
3
  getString(key: string): string;
3
4
  getStrings(key: string): string[];
@@ -12,14 +13,22 @@ export declare class Config implements ConfigInterface {
12
13
  private static DEFAULT_COMMENT_SEM;
13
14
  private static DEFAULT_MULTI_LINE_SEPARATOR;
14
15
  private data;
16
+ private readonly fs?;
15
17
  private constructor();
16
18
  /**
17
19
  * newConfig create an empty configuration representation from file.
18
20
  *
19
21
  * @param confName the path of the model file.
20
22
  * @return the constructor of Config.
23
+ * @deprecated use {@link newConfigFromFile} instead.
21
24
  */
22
25
  static newConfig(confName: string): Config;
26
+ /**
27
+ * newConfigFromFile create an empty configuration representation from file.
28
+ * @param path the path of the model file.
29
+ * @param fs {@link FileSystem}
30
+ */
31
+ static newConfigFromFile(path: string, fs?: FileSystem): Config;
23
32
  /**
24
33
  * newConfigFromText create an empty configuration representation from text.
25
34
  *
package/lib/esm/config.js CHANGED
@@ -11,20 +11,32 @@
11
11
  // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12
12
  // See the License for the specific language governing permissions and
13
13
  // limitations under the License.
14
- import { readFileSync } from 'fs';
14
+ import { mustGetDefaultFileSystem } from './persist';
15
15
  export class Config {
16
- constructor() {
16
+ constructor(fs) {
17
17
  this.data = new Map();
18
+ if (fs) {
19
+ this.fs = fs;
20
+ }
18
21
  }
19
22
  /**
20
23
  * newConfig create an empty configuration representation from file.
21
24
  *
22
25
  * @param confName the path of the model file.
23
26
  * @return the constructor of Config.
27
+ * @deprecated use {@link newConfigFromFile} instead.
24
28
  */
25
29
  static newConfig(confName) {
26
- const config = new Config();
27
- config.parse(confName);
30
+ return this.newConfigFromFile(confName);
31
+ }
32
+ /**
33
+ * newConfigFromFile create an empty configuration representation from file.
34
+ * @param path the path of the model file.
35
+ * @param fs {@link FileSystem}
36
+ */
37
+ static newConfigFromFile(path, fs) {
38
+ const config = new Config(fs);
39
+ config.parse(path);
28
40
  return config;
29
41
  }
30
42
  /**
@@ -59,8 +71,8 @@ export class Config {
59
71
  }
60
72
  }
61
73
  parse(path) {
62
- const buf = readFileSync(path);
63
- this.parseBuffer(buf);
74
+ const body = (this.fs ? this.fs : mustGetDefaultFileSystem()).readFileSync(path);
75
+ this.parseBuffer(Buffer.isBuffer(body) ? body : Buffer.from(body));
64
76
  }
65
77
  parseBuffer(buf) {
66
78
  const lines = buf
@@ -3,6 +3,7 @@ import { FunctionMap, Model, PolicyOp } from './model';
3
3
  import { Adapter, FilteredAdapter, Watcher, BatchAdapter, UpdatableAdapter, WatcherEx } from './persist';
4
4
  import { RoleManager } from './rbac';
5
5
  import { MatchingFunc } from './rbac';
6
+ import { FileSystem } from './persist';
6
7
  /**
7
8
  * CoreEnforcer defines the core functionality of an enforcer.
8
9
  */
@@ -20,6 +21,16 @@ export declare class CoreEnforcer {
20
21
  protected autoSave: boolean;
21
22
  protected autoBuildRoleLinks: boolean;
22
23
  protected autoNotifyWatcher: boolean;
24
+ protected fs?: FileSystem;
25
+ /**
26
+ * setFileSystem sets a file system to read the model file or the policy file.
27
+ * @param fs {@link FileSystem}
28
+ */
29
+ setFileSystem(fs: FileSystem): void;
30
+ /**
31
+ * getFileSystem gets the file system,
32
+ */
33
+ getFileSystem(): FileSystem | undefined;
23
34
  private getExpression;
24
35
  /**
25
36
  * loadModel reloads the model from the model CONF file.
@@ -13,7 +13,7 @@
13
13
  // limitations under the License.
14
14
  import { compile, compileAsync, addBinaryOp } from 'expression-eval';
15
15
  import { DefaultEffector, Effect } from './effect';
16
- import { FunctionMap, newModel } from './model';
16
+ import { FunctionMap, newModelFromFile } from './model';
17
17
  import { DefaultRoleManager } from './rbac';
18
18
  import { escapeAssertion, generateGFunction, generateSyncedGFunction, getEvalValue, hasEval, replaceEval, generatorRunSync, generatorRunAsync, customIn, bracketCompatible, } from './util';
19
19
  import { getLogger, logPrint } from './log';
@@ -32,6 +32,19 @@ export class CoreEnforcer {
32
32
  this.autoBuildRoleLinks = true;
33
33
  this.autoNotifyWatcher = true;
34
34
  }
35
+ /**
36
+ * setFileSystem sets a file system to read the model file or the policy file.
37
+ * @param fs {@link FileSystem}
38
+ */
39
+ setFileSystem(fs) {
40
+ this.fs = fs;
41
+ }
42
+ /**
43
+ * getFileSystem gets the file system,
44
+ */
45
+ getFileSystem() {
46
+ return this.fs;
47
+ }
35
48
  getExpression(asyncCompile, exp) {
36
49
  const matcherKey = `${asyncCompile ? 'ASYNC[' : 'SYNC['}${exp}]`;
37
50
  addBinaryOp('in', 1, customIn);
@@ -49,8 +62,7 @@ export class CoreEnforcer {
49
62
  * so the policy is invalidated and needs to be reloaded by calling LoadPolicy().
50
63
  */
51
64
  loadModel() {
52
- this.model = newModel();
53
- this.model.loadModel(this.modelPath);
65
+ this.model = newModelFromFile(this.modelPath, this.fs);
54
66
  this.model.printModel();
55
67
  }
56
68
  /**
@@ -12,7 +12,7 @@
12
12
  // See the License for the specific language governing permissions and
13
13
  // limitations under the License.
14
14
  import { ManagementEnforcer } from './managementEnforcer';
15
- import { newModel } from './model';
15
+ import { newModelFromFile } from './model';
16
16
  import { FileAdapter, StringAdapter } from './persist';
17
17
  import { getLogger } from './log';
18
18
  import { arrayRemoveDuplicates } from './util';
@@ -27,7 +27,7 @@ export class Enforcer extends ManagementEnforcer {
27
27
  * @param lazyLoad lazyLoad whether to load policy at initial time
28
28
  */
29
29
  async initWithFile(modelPath, policyPath, lazyLoad = false) {
30
- const a = new FileAdapter(policyPath);
30
+ const a = new FileAdapter(policyPath, this.fs);
31
31
  await this.initWithAdapter(modelPath, a, lazyLoad);
32
32
  }
33
33
  /**
@@ -47,7 +47,7 @@ export class Enforcer extends ManagementEnforcer {
47
47
  * @param lazyLoad whether to load policy at initial time
48
48
  */
49
49
  async initWithAdapter(modelPath, adapter, lazyLoad = false) {
50
- const m = newModel(modelPath, '');
50
+ const m = newModelFromFile(modelPath, this.fs);
51
51
  await this.initWithModelAndAdapter(m, adapter, lazyLoad);
52
52
  this.modelPath = modelPath;
53
53
  }
package/lib/esm/index.js CHANGED
@@ -11,7 +11,9 @@
11
11
  // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12
12
  // See the License for the specific language governing permissions and
13
13
  // limitations under the License.
14
+ var _a;
14
15
  import * as Util from './util';
16
+ import { setDefaultFileSystem } from './persist';
15
17
  export * from './config';
16
18
  export * from './enforcer';
17
19
  export * from './cachedEnforcer';
@@ -23,3 +25,16 @@ export * from './rbac';
23
25
  export * from './log';
24
26
  export * from './frontend';
25
27
  export { Util };
28
+ if (typeof process !== 'undefined' && ((_a = process === null || process === void 0 ? void 0 : process.versions) === null || _a === void 0 ? void 0 : _a.node)) {
29
+ const requireFunc = typeof __non_webpack_require__ === 'function' ? __non_webpack_require__ : require;
30
+ const fs = requireFunc('fs');
31
+ const defaultFileSystem = {
32
+ readFileSync(path, encoding) {
33
+ return fs.readFileSync(path, { encoding });
34
+ },
35
+ writeFileSync(path, text, encoding) {
36
+ return fs.writeFileSync(path, text, encoding);
37
+ },
38
+ };
39
+ setDefaultFileSystem(defaultFileSystem);
40
+ }
@@ -1,6 +1,7 @@
1
1
  import * as rbac from '../rbac';
2
2
  import { ConfigInterface } from '../config';
3
3
  import { Assertion } from './assertion';
4
+ import { FileSystem } from '../persist/fileSystem';
4
5
  export declare const sectionNameMap: {
5
6
  [index: string]: string;
6
7
  };
@@ -19,7 +20,19 @@ export declare class Model {
19
20
  private getKeySuffix;
20
21
  private loadSection;
21
22
  addDef(sec: string, key: string, value: string): boolean;
22
- loadModel(path: string): void;
23
+ /**
24
+ * loadModel loads the model from model CONF file.
25
+ * @param path the model file path
26
+ * @param fs {@link FileSystem}
27
+ * @deprecated {@link loadModelFromFile}
28
+ */
29
+ loadModel(path: string, fs?: FileSystem): void;
30
+ /**
31
+ * loadModelFromFile loads the model from model CONF file.
32
+ * @param path the model file path
33
+ * @param fs {@link FileSystem}
34
+ */
35
+ loadModelFromFile(path: string, fs?: FileSystem): void;
23
36
  loadModelFromText(text: string): void;
24
37
  loadModelFromConfig(cfg: ConfigInterface): void;
25
38
  private hasSection;
@@ -64,7 +77,7 @@ export declare function newModel(...text: string[]): Model;
64
77
  /**
65
78
  * newModelFromFile creates a model from a .CONF file.
66
79
  */
67
- export declare function newModelFromFile(path: string): Model;
80
+ export declare function newModelFromFile(path: string, fs?: FileSystem): Model;
68
81
  /**
69
82
  * newModelFromString creates a model from a string which contains model text.
70
83
  */
@@ -101,9 +101,22 @@ export class Model {
101
101
  }
102
102
  return true;
103
103
  }
104
- // loadModel loads the model from model CONF file.
105
- loadModel(path) {
106
- const cfg = Config.newConfig(path);
104
+ /**
105
+ * loadModel loads the model from model CONF file.
106
+ * @param path the model file path
107
+ * @param fs {@link FileSystem}
108
+ * @deprecated {@link loadModelFromFile}
109
+ */
110
+ loadModel(path, fs) {
111
+ this.loadModelFromFile(path, fs);
112
+ }
113
+ /**
114
+ * loadModelFromFile loads the model from model CONF file.
115
+ * @param path the model file path
116
+ * @param fs {@link FileSystem}
117
+ */
118
+ loadModelFromFile(path, fs) {
119
+ const cfg = Config.newConfigFromFile(path, fs);
107
120
  this.loadModelFromConfig(cfg);
108
121
  }
109
122
  // loadModelFromText loads the model from the text.
@@ -509,7 +522,7 @@ export function newModel(...text) {
509
522
  const m = new Model();
510
523
  if (text.length === 2) {
511
524
  if (text[0] !== '') {
512
- m.loadModel(text[0]);
525
+ m.loadModelFromFile(text[0]);
513
526
  }
514
527
  }
515
528
  else if (text.length === 1) {
@@ -523,9 +536,11 @@ export function newModel(...text) {
523
536
  /**
524
537
  * newModelFromFile creates a model from a .CONF file.
525
538
  */
526
- export function newModelFromFile(path) {
539
+ export function newModelFromFile(path, fs) {
527
540
  const m = new Model();
528
- m.loadModel(path);
541
+ if (path) {
542
+ m.loadModelFromFile(path, fs);
543
+ }
529
544
  return m;
530
545
  }
531
546
  /**
@@ -1,16 +1,20 @@
1
1
  import { Adapter } from './adapter';
2
2
  import { Model } from '../model';
3
+ import { FileSystem } from './fileSystem';
3
4
  /**
4
5
  * FileAdapter is the file adapter for Casbin.
5
6
  * It can load policy from file or save policy to file.
6
7
  */
7
8
  export declare class FileAdapter implements Adapter {
8
9
  readonly filePath: string;
10
+ protected readonly fs?: FileSystem;
9
11
  /**
10
12
  * FileAdapter is the constructor for FileAdapter.
11
- * @param {string} filePath filePath the path of the policy file.
13
+ *
14
+ * @param filePath filePath the path of the policy file.
15
+ * @param fs {@link FileSystem}
12
16
  */
13
- constructor(filePath: string);
17
+ constructor(filePath: string, fs?: FileSystem);
14
18
  loadPolicy(model: Model): Promise<void>;
15
19
  private loadPolicyFile;
16
20
  /**
@@ -1,5 +1,6 @@
1
1
  import { Helper } from './helper';
2
- import { arrayToString, readFile, writeFile } from '../util';
2
+ import { arrayToString } from '../util';
3
+ import { mustGetDefaultFileSystem } from './fileSystem';
3
4
  /**
4
5
  * FileAdapter is the file adapter for Casbin.
5
6
  * It can load policy from file or save policy to file.
@@ -7,10 +8,13 @@ import { arrayToString, readFile, writeFile } from '../util';
7
8
  export class FileAdapter {
8
9
  /**
9
10
  * FileAdapter is the constructor for FileAdapter.
10
- * @param {string} filePath filePath the path of the policy file.
11
+ *
12
+ * @param filePath filePath the path of the policy file.
13
+ * @param fs {@link FileSystem}
11
14
  */
12
- constructor(filePath) {
15
+ constructor(filePath, fs) {
13
16
  this.filePath = filePath;
17
+ this.fs = fs;
14
18
  }
15
19
  async loadPolicy(model) {
16
20
  if (!this.filePath) {
@@ -20,7 +24,7 @@ export class FileAdapter {
20
24
  await this.loadPolicyFile(model, Helper.loadPolicyLine);
21
25
  }
22
26
  async loadPolicyFile(model, handler) {
23
- const bodyBuf = await readFile(this.filePath);
27
+ const bodyBuf = await (this.fs ? this.fs : mustGetDefaultFileSystem()).readFileSync(this.filePath);
24
28
  const lines = bodyBuf.toString().split('\n');
25
29
  lines.forEach((n, index) => {
26
30
  if (!n) {
@@ -64,7 +68,7 @@ export class FileAdapter {
64
68
  return true;
65
69
  }
66
70
  async savePolicyFile(text) {
67
- await writeFile(this.filePath, text);
71
+ (this.fs ? this.fs : mustGetDefaultFileSystem()).writeFileSync(this.filePath, text);
68
72
  }
69
73
  /**
70
74
  * addPolicy adds a policy rule to the storage.
@@ -0,0 +1,8 @@
1
+ /// <reference types="node" />
2
+ export interface FileSystem {
3
+ readFileSync(path: string, encoding?: string): Buffer | string;
4
+ writeFileSync(path: string, text: string, encoding?: string): void;
5
+ }
6
+ export declare const setDefaultFileSystem: (fs?: FileSystem | undefined) => void;
7
+ export declare const getDefaultFileSystem: () => FileSystem | undefined;
8
+ export declare const mustGetDefaultFileSystem: () => FileSystem;
@@ -0,0 +1,12 @@
1
+ let defaultFileSystem = undefined;
2
+ const ErrorNoFileSystem = new Error('please set the default FileSystem by call the setDefaultFileSystem');
3
+ export const setDefaultFileSystem = (fs) => {
4
+ defaultFileSystem = fs;
5
+ };
6
+ export const getDefaultFileSystem = () => defaultFileSystem;
7
+ export const mustGetDefaultFileSystem = () => {
8
+ if (defaultFileSystem) {
9
+ return defaultFileSystem;
10
+ }
11
+ throw ErrorNoFileSystem;
12
+ };
@@ -9,3 +9,4 @@ export * from './defaultFilteredAdapter';
9
9
  export * from './batchAdapter';
10
10
  export * from './batchFileAdapter';
11
11
  export * from './updatableAdapter';
12
+ export * from './fileSystem';
@@ -9,3 +9,4 @@ export * from './defaultFilteredAdapter';
9
9
  export * from './batchAdapter';
10
10
  export * from './batchFileAdapter';
11
11
  export * from './updatableAdapter';
12
+ export * from './fileSystem';
@@ -11,9 +11,9 @@
11
11
  // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12
12
  // See the License for the specific language governing permissions and
13
13
  // limitations under the License.
14
- import * as fs from 'fs';
15
14
  // escapeAssertion escapes the dots in the assertion,
16
15
  // because the expression evaluation doesn't support such variable names.
16
+ import { mustGetDefaultFileSystem } from '../persist';
17
17
  function escapeAssertion(s) {
18
18
  s = s.replace(/r\./g, 'r_');
19
19
  s = s.replace(/p\./g, 'p_');
@@ -70,24 +70,28 @@ function setEquals(a, b) {
70
70
  }
71
71
  // readFile return a promise for readFile.
72
72
  function readFile(path, encoding) {
73
+ const fs = mustGetDefaultFileSystem();
73
74
  return new Promise((resolve, reject) => {
74
- fs.readFile(path, encoding || 'utf8', (error, data) => {
75
- if (error) {
76
- reject(error);
77
- }
78
- resolve(data);
79
- });
75
+ try {
76
+ fs.readFileSync(path, encoding || 'utf8');
77
+ resolve();
78
+ }
79
+ catch (e) {
80
+ reject(e);
81
+ }
80
82
  });
81
83
  }
82
84
  // writeFile return a promise for writeFile.
83
85
  function writeFile(path, file, encoding) {
86
+ const fs = mustGetDefaultFileSystem();
84
87
  return new Promise((resolve, reject) => {
85
- fs.writeFile(path, file, encoding || 'utf8', (error) => {
86
- if (error) {
87
- reject(error);
88
- }
89
- resolve(true);
90
- });
88
+ try {
89
+ fs.writeFileSync(path, file, encoding || 'utf-8');
90
+ resolve();
91
+ }
92
+ catch (e) {
93
+ reject(e);
94
+ }
91
95
  });
92
96
  }
93
97
  const evalRegG = new RegExp(/\beval\(([^),]*)\)/g);
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "casbin",
3
- "version": "5.23.1",
3
+ "version": "5.24.0",
4
4
  "description": "An authorization library that supports access control models like ACL, RBAC, ABAC in Node.JS",
5
5
  "main": "lib/cjs/index.js",
6
6
  "typings": "lib/cjs/index.d.ts",