@wxn0brp/gate-warden 0.1.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.
Files changed (52) hide show
  1. package/.github/dependabot.yml +11 -0
  2. package/.github/workflows/build.yml +14 -0
  3. package/CHANGELOG.md +30 -0
  4. package/LICENSE +21 -0
  5. package/README.md +89 -0
  6. package/dist/createDb.d.ts +4 -0
  7. package/dist/createDb.d.ts.map +1 -0
  8. package/dist/createDb.js +7 -0
  9. package/dist/createDb.js.map +1 -0
  10. package/dist/index.d.ts +6 -0
  11. package/dist/index.d.ts.map +1 -0
  12. package/dist/index.js +5 -0
  13. package/dist/index.js.map +1 -0
  14. package/dist/log.d.ts +8 -0
  15. package/dist/log.d.ts.map +1 -0
  16. package/dist/log.js +8 -0
  17. package/dist/log.js.map +1 -0
  18. package/dist/mgr.d.ts +18 -0
  19. package/dist/mgr.d.ts.map +1 -0
  20. package/dist/mgr.js +42 -0
  21. package/dist/mgr.js.map +1 -0
  22. package/dist/test/ramStorage.d.ts +4 -0
  23. package/dist/test/ramStorage.d.ts.map +1 -0
  24. package/dist/test/ramStorage.js +13 -0
  25. package/dist/test/ramStorage.js.map +1 -0
  26. package/dist/test/test.d.ts +2 -0
  27. package/dist/test/test.d.ts.map +1 -0
  28. package/dist/test/test.js +49 -0
  29. package/dist/test/test.js.map +1 -0
  30. package/dist/types/system.d.ts +27 -0
  31. package/dist/types/system.d.ts.map +1 -0
  32. package/dist/types/system.js +2 -0
  33. package/dist/types/system.js.map +1 -0
  34. package/dist/user.d.ts +52 -0
  35. package/dist/user.d.ts.map +1 -0
  36. package/dist/user.js +89 -0
  37. package/dist/user.js.map +1 -0
  38. package/dist/warden.d.ts +10 -0
  39. package/dist/warden.d.ts.map +1 -0
  40. package/dist/warden.js +122 -0
  41. package/dist/warden.js.map +1 -0
  42. package/package.json +34 -0
  43. package/src/createDb.ts +7 -0
  44. package/src/index.ts +11 -0
  45. package/src/log.ts +7 -0
  46. package/src/mgr.ts +54 -0
  47. package/src/types/system.ts +32 -0
  48. package/src/user.ts +96 -0
  49. package/src/warden.ts +145 -0
  50. package/suglite.json +11 -0
  51. package/tsconfig.dev.json +6 -0
  52. package/tsconfig.json +26 -0
@@ -0,0 +1,11 @@
1
+ version: 2
2
+ updates:
3
+ - package-ecosystem: "npm"
4
+ directory: "/"
5
+ schedule:
6
+ interval: "daily"
7
+ allow:
8
+ - dependency-name: "@wx0brp/db"
9
+ commit-message:
10
+ prefix: "chore"
11
+ include: "scope"
@@ -0,0 +1,14 @@
1
+ name: Build
2
+
3
+ on:
4
+ push:
5
+ branches:
6
+ - master
7
+
8
+ workflow_dispatch:
9
+
10
+ jobs:
11
+ build:
12
+ uses: wxn0brP/workflow-dist/.github/workflows/build-ts.yml@main
13
+ with:
14
+ scriptsHandling: "remove-all"
package/CHANGELOG.md ADDED
@@ -0,0 +1,30 @@
1
+ # Changelog
2
+
3
+ All notable changes to this project will be documented in this file. See [standard-version](https://github.com/conventional-changelog/standard-version) for commit guidelines.
4
+
5
+ ## 0.1.0 (2025-05-05)
6
+
7
+
8
+ ### ⚠ BREAKING CHANGES
9
+
10
+ * change result format
11
+ * make logic is logic
12
+
13
+ ### Features
14
+
15
+ * add GitHub Actions workflow for build process ([3d12dfe](https://github.com/wxn0brP/gate-warden/commit/3d12dfe739397c1b8b3a57e61425a40206779c1c))
16
+ * add README.md ([3b0f311](https://github.com/wxn0brP/gate-warden/commit/3b0f31115d740f63a0f3e94dc89bdacc30e95b63))
17
+ * add simple gui ([c1f4b27](https://github.com/wxn0brP/gate-warden/commit/c1f4b27004a6f07c949d37822d47a80d2b350f46))
18
+ * add user manager and organize files ([120277b](https://github.com/wxn0brP/gate-warden/commit/120277b18ffcff71afb1de7a893f0e82577ba43c))
19
+ * bump @wxn0brp/db version ([fc58a56](https://github.com/wxn0brP/gate-warden/commit/fc58a56947654baa69f9bacba412ac8130da6e2a))
20
+ * bump version to 0.0.3 and update @wxn0brp/db dependency to >=0.5.7; refactor database initialization to use createDb function ([053936e](https://github.com/wxn0brP/gate-warden/commit/053936e02e3af530ef07902bb31148b9f091ab36))
21
+ * change result format ([7948190](https://github.com/wxn0brP/gate-warden/commit/79481900193252c3ff6d52c9e3211fe822fbbc07))
22
+ * **core:** etch the first decrees of the Gatekeeper's will ([c0caa09](https://github.com/wxn0brP/gate-warden/commit/c0caa09f527adad97d3edbeaae180936eeced10c))
23
+ * make logic is logic ([6d4d466](https://github.com/wxn0brP/gate-warden/commit/6d4d466a35d142808fdbd3ec850a080b338b81a4))
24
+ * update ACLRule ([b9e78f2](https://github.com/wxn0brP/gate-warden/commit/b9e78f25da0467b5cb486d5709739a99a72017e7))
25
+
26
+
27
+ ### Bug Fixes
28
+
29
+ * aclCheck function to include rules without uid ([0420a69](https://github.com/wxn0brP/gate-warden/commit/0420a6936874c1c0849379e07b912f1e3a11105c))
30
+ * update build workflow to include package.json in distribution files ([5de0f99](https://github.com/wxn0brP/gate-warden/commit/5de0f99b54ad211b08e31fbec0d9de80dfd6c809))
package/LICENSE ADDED
@@ -0,0 +1,21 @@
1
+ MIT License
2
+
3
+ Copyright (c) 2025 wxn0brP
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining a copy
6
+ of this software and associated documentation files (the "Software"), to deal
7
+ in the Software without restriction, including without limitation the rights
8
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9
+ copies of the Software, and to permit persons to whom the Software is
10
+ furnished to do so, subject to the following conditions:
11
+
12
+ The above copyright notice and this permission notice shall be included in all
13
+ copies or substantial portions of the Software.
14
+
15
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21
+ SOFTWARE.
package/README.md ADDED
@@ -0,0 +1,89 @@
1
+ # Gate Warden
2
+
3
+ Gate Warden is a lightweight access control library that supports ACL, RBAC, and ABAC models. It is designed to manage and enforce permissions for users and entities in a flexible and extensible way.
4
+
5
+ ## Features
6
+
7
+ - **ACL (Access Control List):** Define permissions for specific users on specific entities.
8
+ - **RBAC (Role-Based Access Control):** Assign roles to users and define permissions for roles on entities.
9
+ - **ABAC (Attribute-Based Access Control):** Use dynamic conditions based on user and entity attributes to determine access.
10
+
11
+ ## Installation
12
+
13
+ Install the library using npm or yarn:
14
+
15
+ ```bash
16
+ yarn add github:wxn0brp/gate-warden#dist
17
+ ```
18
+
19
+ ## Usage
20
+
21
+ ### GateWarden
22
+
23
+ The `GateWarden` class is the main entry point for checking access permissions.
24
+
25
+ ```typescript
26
+ import { GateWarden } from "@wxn0brp/gate-warden";
27
+ import { Valthera } from "@wxn0brp/db";
28
+
29
+ const wardenString = new GateWarden("dir");
30
+ // or
31
+ const wardenDB = new GateWarden(new Valthera("dir"));
32
+
33
+ const hasAccess = await warden.hasAccess("userId", "entityId", 0b001);
34
+ console.log(`Access granted: ${hasAccess}`);
35
+ ```
36
+
37
+ ### UserManager
38
+
39
+ The `UserManager` class provides methods to manage users.
40
+
41
+ ```typescript
42
+ import { UserManager } from "@wxn0brp/gate-warden";
43
+
44
+ const userManager = new UserManager(db);
45
+
46
+ // Create a new user
47
+ await userManager.createUser({ _id: "userId", roles: ["roleId"] });
48
+
49
+ // Update user attributes
50
+ await userManager.updateAttributes("userId", { key: "value" });
51
+ ```
52
+
53
+ ### WardenManager
54
+
55
+ The `WardenManager` class provides methods to manage roles and rules.
56
+
57
+ ```typescript
58
+ import { WardenManager } from "@wxn0brp/gate-warden";
59
+
60
+ const wardenManager = new WardenManager(db);
61
+
62
+ // Add a new role
63
+ await wardenManager.addRole({ _id: "roleId", name: "Admin" });
64
+
65
+ // Add an ACL rule
66
+ await wardenManager.addACLRule("entityId", 0b001, "userId");
67
+
68
+ // Add an ABAC rule
69
+ await wardenManager.addABACRule("entityId", 0b001, (user, entity) => user.attrib.isAdmin);
70
+ ```
71
+
72
+ ## Debug Logging
73
+
74
+ Set the `debugLog` level in `GateWarden` to enable debug messages:
75
+ - `0`: No logs
76
+ - `1`: Basic logs
77
+ - `2`: Detailed logs
78
+
79
+ ## Project Structure
80
+
81
+ - **src/warden.ts:** Core access control logic.
82
+ - **src/user.ts:** User management.
83
+ - **src/mgr.ts:** Role and rule management.
84
+ - **src/types/system.ts:** Type definitions for roles, rules, and users.
85
+ - **src/log.ts:** Logging utilities.
86
+
87
+ ## License
88
+
89
+ This project is licensed under the MIT License. See the [LICENSE](LICENSE) file for details.
@@ -0,0 +1,4 @@
1
+ import { Valthera } from "@wxn0brp/db";
2
+ import { Remote } from "@wxn0brp/db/dist/client/remote";
3
+ export declare function createDb(valthera: string | Valthera | Remote): Valthera;
4
+ //# sourceMappingURL=createDb.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"createDb.d.ts","sourceRoot":"","sources":["../src/createDb.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,QAAQ,EAAsB,MAAM,aAAa,CAAC;AAC3D,OAAO,EAAE,MAAM,EAAE,MAAM,gCAAgC,CAAC;AAExD,wBAAgB,QAAQ,CAAC,QAAQ,EAAE,MAAM,GAAG,QAAQ,GAAG,MAAM,GAAG,QAAQ,CAGvE"}
@@ -0,0 +1,7 @@
1
+ import { Valthera, ValtheraAutoCreate } from "@wxn0brp/db";
2
+ export function createDb(valthera) {
3
+ if (valthera instanceof Valthera)
4
+ return valthera;
5
+ return ValtheraAutoCreate(valthera);
6
+ }
7
+ //# sourceMappingURL=createDb.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"createDb.js","sourceRoot":"","sources":["../src/createDb.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,QAAQ,EAAE,kBAAkB,EAAE,MAAM,aAAa,CAAC;AAG3D,MAAM,UAAU,QAAQ,CAAC,QAAoC;IACzD,IAAI,QAAQ,YAAY,QAAQ;QAAE,OAAO,QAAQ,CAAC;IAClD,OAAO,kBAAkB,CAAC,QAAQ,CAAa,CAAC;AACpD,CAAC"}
@@ -0,0 +1,6 @@
1
+ import GateWarden from "./warden.js";
2
+ import UserManager from "./user.js";
3
+ import WardenManager from "./mgr.js";
4
+ import { AccessResult } from "./types/system.js";
5
+ export { GateWarden, UserManager, WardenManager, AccessResult };
6
+ //# sourceMappingURL=index.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA,OAAO,UAAU,MAAM,UAAU,CAAC;AAClC,OAAO,WAAW,MAAM,QAAQ,CAAC;AACjC,OAAO,aAAa,MAAM,OAAO,CAAC;AAClC,OAAO,EAAE,YAAY,EAAE,MAAM,gBAAgB,CAAC;AAE9C,OAAO,EACH,UAAU,EACV,WAAW,EACX,aAAa,EACb,YAAY,EACf,CAAC"}
package/dist/index.js ADDED
@@ -0,0 +1,5 @@
1
+ import GateWarden from "./warden.js";
2
+ import UserManager from "./user.js";
3
+ import WardenManager from "./mgr.js";
4
+ export { GateWarden, UserManager, WardenManager };
5
+ //# sourceMappingURL=index.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA,OAAO,UAAU,MAAM,UAAU,CAAC;AAClC,OAAO,WAAW,MAAM,QAAQ,CAAC;AACjC,OAAO,aAAa,MAAM,OAAO,CAAC;AAGlC,OAAO,EACH,UAAU,EACV,WAAW,EACX,aAAa,EAEhB,CAAC"}
package/dist/log.d.ts ADDED
@@ -0,0 +1,8 @@
1
+ export declare const COLORS: {
2
+ reset: string;
3
+ green: string;
4
+ yellow: string;
5
+ red: string;
6
+ blue: string;
7
+ };
8
+ //# sourceMappingURL=log.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"log.d.ts","sourceRoot":"","sources":["../src/log.ts"],"names":[],"mappings":"AAAA,eAAO,MAAM,MAAM;;;;;;CAMlB,CAAC"}
package/dist/log.js ADDED
@@ -0,0 +1,8 @@
1
+ export const COLORS = {
2
+ reset: "\x1b[0m",
3
+ green: "\x1b[32m",
4
+ yellow: "\x1b[33m",
5
+ red: "\x1b[31m",
6
+ blue: "\x1b[34m",
7
+ };
8
+ //# sourceMappingURL=log.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"log.js","sourceRoot":"","sources":["../src/log.ts"],"names":[],"mappings":"AAAA,MAAM,CAAC,MAAM,MAAM,GAAG;IAClB,KAAK,EAAE,SAAS;IAChB,KAAK,EAAE,UAAU;IACjB,MAAM,EAAE,UAAU;IAClB,GAAG,EAAE,UAAU;IACf,IAAI,EAAE,UAAU;CACnB,CAAC"}
package/dist/mgr.d.ts ADDED
@@ -0,0 +1,18 @@
1
+ import { Id, Valthera } from "@wxn0brp/db";
2
+ import { ABACRule, Role } from "./types/system.js";
3
+ import { Remote } from "@wxn0brp/db/dist/client/remote";
4
+ declare class WardenManager<A = any> {
5
+ private db;
6
+ constructor(valthera: string | Valthera | Remote);
7
+ changeRoleNameToId(name: string): Promise<Id>;
8
+ addRole(role: Role): Promise<Role>;
9
+ addACLRule(entityId: string, p: number, uid?: Id): Promise<void>;
10
+ addRBACRule(role_id: string, entity_id: string, p: number): Promise<void>;
11
+ addABACRule(entity_id: string, flag: number, condition: ABACRule<A>["conditions"]): Promise<void>;
12
+ removeRole(roleId: string): Promise<boolean>;
13
+ removeACLRule(entityId: string, uid?: string): Promise<boolean>;
14
+ removeRBACRule(roleId: string, entityId: string): Promise<boolean>;
15
+ removeABACRule(entityId: string, flag: number): Promise<boolean>;
16
+ }
17
+ export default WardenManager;
18
+ //# sourceMappingURL=mgr.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"mgr.d.ts","sourceRoot":"","sources":["../src/mgr.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,EAAE,EAAE,QAAQ,EAAE,MAAM,aAAa,CAAC;AAC3C,OAAO,EAAE,QAAQ,EAAW,IAAI,EAAE,MAAM,gBAAgB,CAAC;AACzD,OAAO,EAAE,MAAM,EAAE,MAAM,gCAAgC,CAAC;AAGxD,cAAM,aAAa,CAAC,CAAC,GAAG,GAAG;IACvB,OAAO,CAAC,EAAE,CAAW;gBACT,QAAQ,EAAE,MAAM,GAAG,QAAQ,GAAG,MAAM;IAI1C,kBAAkB,CAAC,IAAI,EAAE,MAAM,GAAG,OAAO,CAAC,EAAE,CAAC;IAK7C,OAAO,CAAC,IAAI,EAAE,IAAI,GAAG,OAAO,CAAC,IAAI,CAAC;IAIlC,UAAU,CAAC,QAAQ,EAAE,MAAM,EAAE,CAAC,EAAE,MAAM,EAAE,GAAG,CAAC,EAAE,EAAE,GAAG,OAAO,CAAC,IAAI,CAAC;IAMhE,WAAW,CAAC,OAAO,EAAE,MAAM,EAAE,SAAS,EAAE,MAAM,EAAE,CAAC,EAAE,MAAM,GAAG,OAAO,CAAC,IAAI,CAAC;IAIzE,WAAW,CAAC,SAAS,EAAE,MAAM,EAAE,IAAI,EAAE,MAAM,EAAE,SAAS,EAAE,QAAQ,CAAC,CAAC,CAAC,CAAC,YAAY,CAAC,GAAG,OAAO,CAAC,IAAI,CAAC;IAKjG,UAAU,CAAC,MAAM,EAAE,MAAM,GAAG,OAAO,CAAC,OAAO,CAAC;IAI5C,aAAa,CAAC,QAAQ,EAAE,MAAM,EAAE,GAAG,CAAC,EAAE,MAAM,GAAG,OAAO,CAAC,OAAO,CAAC;IAK/D,cAAc,CAAC,MAAM,EAAE,MAAM,EAAE,QAAQ,EAAE,MAAM,GAAG,OAAO,CAAC,OAAO,CAAC;IAIlE,cAAc,CAAC,QAAQ,EAAE,MAAM,EAAE,IAAI,EAAE,MAAM,GAAG,OAAO,CAAC,OAAO,CAAC;CAGzE;AAED,eAAe,aAAa,CAAC"}
package/dist/mgr.js ADDED
@@ -0,0 +1,42 @@
1
+ import { createDb } from "./createDb.js";
2
+ class WardenManager {
3
+ db;
4
+ constructor(valthera) {
5
+ this.db = createDb(valthera);
6
+ }
7
+ async changeRoleNameToId(name) {
8
+ return await this.db.findOne("roles", { name });
9
+ }
10
+ // ADD
11
+ async addRole(role) {
12
+ return await this.db.add("roles", role);
13
+ }
14
+ async addACLRule(entityId, p, uid) {
15
+ const rule = { p };
16
+ if (uid)
17
+ rule.uid = uid;
18
+ return await this.db.add("acl/" + entityId, rule, false);
19
+ }
20
+ async addRBACRule(role_id, entity_id, p) {
21
+ return await this.db.add("role/" + role_id, { _id: entity_id, p }, false);
22
+ }
23
+ async addABACRule(entity_id, flag, condition) {
24
+ return await this.db.add("abac/" + entity_id, { flag, conditions: condition.toString() }, true);
25
+ }
26
+ // DELETE
27
+ async removeRole(roleId) {
28
+ return await this.db.removeOne("roles", { roleId });
29
+ }
30
+ async removeACLRule(entityId, uid) {
31
+ const q = uid ? { uid } : { $not: { $exists: { "uid": true } } };
32
+ return await this.db.removeOne("acl/" + entityId, q);
33
+ }
34
+ async removeRBACRule(roleId, entityId) {
35
+ return await this.db.removeOne("role/" + roleId, { _id: entityId });
36
+ }
37
+ async removeABACRule(entityId, flag) {
38
+ return await this.db.removeOne("abac/" + entityId, { flag });
39
+ }
40
+ }
41
+ export default WardenManager;
42
+ //# sourceMappingURL=mgr.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"mgr.js","sourceRoot":"","sources":["../src/mgr.ts"],"names":[],"mappings":"AAGA,OAAO,EAAE,QAAQ,EAAE,MAAM,YAAY,CAAC;AAEtC,MAAM,aAAa;IACP,EAAE,CAAW;IACrB,YAAY,QAAoC;QAC5C,IAAI,CAAC,EAAE,GAAG,QAAQ,CAAC,QAAQ,CAAC,CAAC;IACjC,CAAC;IAED,KAAK,CAAC,kBAAkB,CAAC,IAAY;QACjC,OAAO,MAAM,IAAI,CAAC,EAAE,CAAC,OAAO,CAAC,OAAO,EAAE,EAAE,IAAI,EAAE,CAAC,CAAC;IACpD,CAAC;IAED,MAAM;IACN,KAAK,CAAC,OAAO,CAAC,IAAU;QACpB,OAAO,MAAM,IAAI,CAAC,EAAE,CAAC,GAAG,CAAC,OAAO,EAAE,IAAI,CAAC,CAAC;IAC5C,CAAC;IAED,KAAK,CAAC,UAAU,CAAC,QAAgB,EAAE,CAAS,EAAE,GAAQ;QAClD,MAAM,IAAI,GAAY,EAAE,CAAC,EAAE,CAAC;QAC5B,IAAI,GAAG;YAAE,IAAI,CAAC,GAAG,GAAG,GAAG,CAAC;QACxB,OAAO,MAAM,IAAI,CAAC,EAAE,CAAC,GAAG,CAAC,MAAM,GAAC,QAAQ,EAAE,IAAI,EAAE,KAAK,CAAC,CAAC;IAC3D,CAAC;IAED,KAAK,CAAC,WAAW,CAAC,OAAe,EAAE,SAAiB,EAAE,CAAS;QAC3D,OAAO,MAAM,IAAI,CAAC,EAAE,CAAC,GAAG,CAAC,OAAO,GAAG,OAAO,EAAE,EAAE,GAAG,EAAE,SAAS,EAAE,CAAC,EAAE,EAAE,KAAK,CAAC,CAAC;IAC9E,CAAC;IAED,KAAK,CAAC,WAAW,CAAC,SAAiB,EAAE,IAAY,EAAE,SAAoC;QACnF,OAAO,MAAM,IAAI,CAAC,EAAE,CAAC,GAAG,CAAC,OAAO,GAAC,SAAS,EAAE,EAAE,IAAI,EAAE,UAAU,EAAE,SAAS,CAAC,QAAQ,EAAE,EAAE,EAAE,IAAI,CAAC,CAAC;IAClG,CAAC;IAED,SAAS;IACT,KAAK,CAAC,UAAU,CAAC,MAAc;QAC3B,OAAO,MAAM,IAAI,CAAC,EAAE,CAAC,SAAS,CAAC,OAAO,EAAE,EAAE,MAAM,EAAE,CAAC,CAAC;IACxD,CAAC;IAED,KAAK,CAAC,aAAa,CAAC,QAAgB,EAAE,GAAY;QAC9C,MAAM,CAAC,GAAG,GAAG,CAAC,CAAC,CAAC,EAAE,GAAG,EAAE,CAAC,CAAC,CAAC,EAAE,IAAI,EAAE,EAAE,OAAO,EAAE,EAAE,KAAK,EAAE,IAAI,EAAE,EAAE,EAAE,CAAC;QACjE,OAAO,MAAM,IAAI,CAAC,EAAE,CAAC,SAAS,CAAC,MAAM,GAAG,QAAQ,EAAE,CAAC,CAAC,CAAC;IACzD,CAAC;IAED,KAAK,CAAC,cAAc,CAAC,MAAc,EAAE,QAAgB;QACjD,OAAO,MAAM,IAAI,CAAC,EAAE,CAAC,SAAS,CAAC,OAAO,GAAG,MAAM,EAAE,EAAE,GAAG,EAAE,QAAQ,EAAE,CAAC,CAAC;IACxE,CAAC;IAED,KAAK,CAAC,cAAc,CAAC,QAAgB,EAAE,IAAY;QAC/C,OAAO,MAAM,IAAI,CAAC,EAAE,CAAC,SAAS,CAAC,OAAO,GAAG,QAAQ,EAAE,EAAE,IAAI,EAAE,CAAC,CAAC;IACjE,CAAC;CACJ;AAED,eAAe,aAAa,CAAC"}
@@ -0,0 +1,4 @@
1
+ import { CustomFileCpu } from "@wxn0brp/db";
2
+ declare const fCPU: CustomFileCpu;
3
+ export default fCPU;
4
+ //# sourceMappingURL=ramStorage.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"ramStorage.d.ts","sourceRoot":"","sources":["../../src/test/ramStorage.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,aAAa,EAAE,MAAM,aAAa,CAAC;AAa5C,QAAA,MAAM,IAAI,eAAmC,CAAC;AAC9C,eAAe,IAAI,CAAC"}
@@ -0,0 +1,13 @@
1
+ import { CustomFileCpu } from "@wxn0brp/db";
2
+ const temp = new Map();
3
+ async function _read(file) {
4
+ if (temp.has(file))
5
+ return temp.get(file) || [];
6
+ return [];
7
+ }
8
+ async function _write(file, data) {
9
+ temp.set(file, data);
10
+ }
11
+ const fCPU = new CustomFileCpu(_read, _write);
12
+ export default fCPU;
13
+ //# sourceMappingURL=ramStorage.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"ramStorage.js","sourceRoot":"","sources":["../../src/test/ramStorage.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,aAAa,EAAE,MAAM,aAAa,CAAC;AAE5C,MAAM,IAAI,GAAG,IAAI,GAAG,EAAiB,CAAC;AAEtC,KAAK,UAAU,KAAK,CAAC,IAAY;IAC7B,IAAI,IAAI,CAAC,GAAG,CAAC,IAAI,CAAC;QAAE,OAAO,IAAI,CAAC,GAAG,CAAC,IAAI,CAAC,IAAI,EAAE,CAAC;IAChD,OAAO,EAAE,CAAC;AACd,CAAC;AAED,KAAK,UAAU,MAAM,CAAC,IAAY,EAAE,IAAW;IAC3C,IAAI,CAAC,GAAG,CAAC,IAAI,EAAE,IAAI,CAAC,CAAC;AACzB,CAAC;AAED,MAAM,IAAI,GAAG,IAAI,aAAa,CAAC,KAAK,EAAE,MAAM,CAAC,CAAC;AAC9C,eAAe,IAAI,CAAC"}
@@ -0,0 +1,2 @@
1
+ export {};
2
+ //# sourceMappingURL=test.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"test.d.ts","sourceRoot":"","sources":["../../src/test/test.ts"],"names":[],"mappings":""}
@@ -0,0 +1,49 @@
1
+ import { GateWarden, UserManager, WardenManager } from "../index.js";
2
+ import sourceMapSupport from "source-map-support";
3
+ import { Valthera } from "@wxn0brp/db";
4
+ import { rmSync } from "fs";
5
+ sourceMapSupport.install();
6
+ let total = 0;
7
+ let ok = 0;
8
+ var PermissionFlags;
9
+ (function (PermissionFlags) {
10
+ PermissionFlags[PermissionFlags["VIEW"] = 1] = "VIEW";
11
+ PermissionFlags[PermissionFlags["EDIT"] = 2] = "EDIT";
12
+ PermissionFlags[PermissionFlags["DELETE"] = 4] = "DELETE";
13
+ PermissionFlags[PermissionFlags["ADMIN"] = 8] = "ADMIN";
14
+ })(PermissionFlags || (PermissionFlags = {}));
15
+ rmSync("test.db", { recursive: true, force: true });
16
+ const db = new Valthera("test.db", {});
17
+ const gw = new GateWarden(db, 2);
18
+ const gwMgr = new WardenManager(db);
19
+ const userMgr = new UserManager(db);
20
+ // @ts-ignore
21
+ db.add("test", "test", false);
22
+ // debugger
23
+ const admin = await gwMgr.addRole({ _id: "admin", name: "admin" });
24
+ const user = await gwMgr.addRole({ _id: "user", name: "user" });
25
+ const manager = await gwMgr.addRole({ _id: "manager", name: "manager" });
26
+ await gwMgr.addRBACRule(admin._id, "doc123", PermissionFlags.VIEW | PermissionFlags.EDIT | PermissionFlags.DELETE | PermissionFlags.ADMIN);
27
+ await gwMgr.addRBACRule(user._id, "doc123", PermissionFlags.VIEW);
28
+ await gwMgr.addRBACRule(manager._id, "doc123", PermissionFlags.VIEW | PermissionFlags.EDIT);
29
+ await userMgr.createUser({ _id: "alice", roles: [user._id], attrib: { dep: "HR", level: 1 } });
30
+ await userMgr.createUser({ _id: "bob", roles: [manager._id], attrib: { dep: "IT", level: 7 } });
31
+ await userMgr.createUser({ _id: "charlie", roles: [admin._id], attrib: { dep: "IT", level: 5 } });
32
+ await gwMgr.addACLRule("doc123", PermissionFlags.EDIT, "alice");
33
+ await gwMgr.addABACRule("doc123", PermissionFlags.DELETE, (user, entity) => user.attrib.level >= 4);
34
+ const log = (result, required = true) => {
35
+ total++;
36
+ ok += result.granted === required ? 1 : 0;
37
+ console.log(result.granted === required ? "OK" : "FAIL");
38
+ };
39
+ log(await gw.hasAccess("alice", "doc123", PermissionFlags.VIEW), true);
40
+ log(await gw.hasAccess("alice", "doc123", PermissionFlags.EDIT), true);
41
+ log(await gw.hasAccess("alice", "doc999", PermissionFlags.EDIT), false);
42
+ log(await gw.hasAccess("bob", "doc123", PermissionFlags.DELETE), true);
43
+ log(await gw.hasAccess("charlie", "doc123", PermissionFlags.DELETE), true);
44
+ log(await gw.hasAccess("alice", "doc123", PermissionFlags.DELETE), false);
45
+ const userManager = new UserManager(db);
46
+ await userManager.updateAttributes("bob", { level: 1 });
47
+ log(await gw.hasAccess("bob", "doc123", PermissionFlags.DELETE), false);
48
+ console.log(`\nOK: ${ok}/${total} (${(ok / total * 100).toFixed(2)}%)`);
49
+ //# sourceMappingURL=test.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"test.js","sourceRoot":"","sources":["../../src/test/test.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,27 @@
1
+ import { Id } from "@wxn0brp/db";
2
+ export interface Role {
3
+ _id: Id;
4
+ name: string;
5
+ }
6
+ export interface RoleEntity {
7
+ _id: Id;
8
+ p: number;
9
+ }
10
+ export interface ACLRule {
11
+ uid?: Id;
12
+ p: number;
13
+ }
14
+ export interface ABACRule<A> {
15
+ flag: number;
16
+ conditions: (user: User<A>, entity: any) => boolean;
17
+ }
18
+ export interface User<A> {
19
+ _id: Id;
20
+ roles: Id[];
21
+ attrib: A;
22
+ }
23
+ export interface AccessResult {
24
+ granted: boolean;
25
+ via: "ACL" | "RBAC" | "ABAC" | "user-404" | "entity-404" | "not-permitted";
26
+ }
27
+ //# sourceMappingURL=system.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"system.d.ts","sourceRoot":"","sources":["../../src/types/system.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,EAAE,EAAE,MAAM,aAAa,CAAC;AAEjC,MAAM,WAAW,IAAI;IACjB,GAAG,EAAE,EAAE,CAAC;IACR,IAAI,EAAE,MAAM,CAAC;CAChB;AAED,MAAM,WAAW,UAAU;IACvB,GAAG,EAAE,EAAE,CAAC;IACR,CAAC,EAAE,MAAM,CAAC;CACb;AAED,MAAM,WAAW,OAAO;IACpB,GAAG,CAAC,EAAE,EAAE,CAAC;IACT,CAAC,EAAE,MAAM,CAAC;CACb;AAED,MAAM,WAAW,QAAQ,CAAC,CAAC;IACvB,IAAI,EAAE,MAAM,CAAC;IACb,UAAU,EAAE,CAAC,IAAI,EAAE,IAAI,CAAC,CAAC,CAAC,EAAE,MAAM,EAAE,GAAG,KAAK,OAAO,CAAC;CACvD;AAED,MAAM,WAAW,IAAI,CAAC,CAAC;IACnB,GAAG,EAAE,EAAE,CAAC;IACR,KAAK,EAAE,EAAE,EAAE,CAAC;IACZ,MAAM,EAAE,CAAC,CAAC;CACb;AAED,MAAM,WAAW,YAAY;IACzB,OAAO,EAAE,OAAO,CAAC;IACjB,GAAG,EAAE,KAAK,GAAG,MAAM,GAAG,MAAM,GAAG,UAAU,GAAG,YAAY,GAAG,eAAe,CAAC;CAC9E"}
@@ -0,0 +1,2 @@
1
+ export {};
2
+ //# sourceMappingURL=system.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"system.js","sourceRoot":"","sources":["../../src/types/system.ts"],"names":[],"mappings":""}
package/dist/user.d.ts ADDED
@@ -0,0 +1,52 @@
1
+ import { Id, Valthera } from "@wxn0brp/db";
2
+ import { User } from "./types/system.js";
3
+ declare class UserManager<A = any> {
4
+ private db;
5
+ constructor(valthera: string | Valthera);
6
+ /**
7
+ * Creates a new user
8
+ * @param userData User data (_id is required)
9
+ */
10
+ createUser(userData: {
11
+ _id: Id;
12
+ roles?: Id[];
13
+ attrib?: A;
14
+ }): Promise<void>;
15
+ /**
16
+ * Retrieves a user by _id
17
+ * @param user_id User _id
18
+ * @returns User or null if it doesn't exist
19
+ */
20
+ getUser(user_id: Id): Promise<User<A> | null>;
21
+ /**
22
+ * Updates a user's data
23
+ * @param user_id User _id
24
+ * @param updates Object with fields to update
25
+ */
26
+ updateUser(user_id: Id, updates: Partial<User<A>>): Promise<void>;
27
+ /**
28
+ * Deletes a user
29
+ * @param user_id User _id
30
+ */
31
+ deleteUser(user_id: Id): Promise<void>;
32
+ /**
33
+ * Adds a role to a user
34
+ * @param user_id User _id
35
+ * @param role_id Role _id
36
+ */
37
+ addRoleToUser(user_id: Id, role_id: Id): Promise<void>;
38
+ /**
39
+ * Removes a role from a user
40
+ * @param user_id User _id
41
+ * @param role_id Role _id
42
+ */
43
+ removeRoleFromUser(user_id: Id, role_id: Id): Promise<void>;
44
+ /**
45
+ * Updates a user's attributes
46
+ * @param user_id User _id
47
+ * @param attributes New attributes to merge
48
+ */
49
+ updateAttributes(user_id: Id, attributes: Partial<A>): Promise<void>;
50
+ }
51
+ export default UserManager;
52
+ //# sourceMappingURL=user.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"user.d.ts","sourceRoot":"","sources":["../src/user.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,EAAE,EAAE,QAAQ,EAAE,MAAM,aAAa,CAAC;AAC3C,OAAO,EAAE,IAAI,EAAE,MAAM,gBAAgB,CAAC;AAGtC,cAAM,WAAW,CAAC,CAAC,GAAG,GAAG;IACrB,OAAO,CAAC,EAAE,CAAW;gBAET,QAAQ,EAAE,MAAM,GAAG,QAAQ;IAIvC;;;OAGG;IACG,UAAU,CAAC,QAAQ,EAAE;QAAE,GAAG,EAAE,EAAE,CAAC;QAAC,KAAK,CAAC,EAAE,EAAE,EAAE,CAAC;QAAC,MAAM,CAAC,EAAE,CAAC,CAAA;KAAE,GAAG,OAAO,CAAC,IAAI,CAAC;IAShF;;;;OAIG;IACG,OAAO,CAAC,OAAO,EAAE,EAAE,GAAG,OAAO,CAAC,IAAI,CAAC,CAAC,CAAC,GAAG,IAAI,CAAC;IAInD;;;;OAIG;IACG,UAAU,CAAC,OAAO,EAAE,EAAE,EAAE,OAAO,EAAE,OAAO,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC,GAAG,OAAO,CAAC,IAAI,CAAC;IAOvE;;;OAGG;IACG,UAAU,CAAC,OAAO,EAAE,EAAE,GAAG,OAAO,CAAC,IAAI,CAAC;IAI5C;;;;OAIG;IACG,aAAa,CAAC,OAAO,EAAE,EAAE,EAAE,OAAO,EAAE,EAAE,GAAG,OAAO,CAAC,IAAI,CAAC;IAS5D;;;;OAIG;IACG,kBAAkB,CAAC,OAAO,EAAE,EAAE,EAAE,OAAO,EAAE,EAAE,GAAG,OAAO,CAAC,IAAI,CAAC;IAUjE;;;;OAIG;IACG,gBAAgB,CAAC,OAAO,EAAE,EAAE,EAAE,UAAU,EAAE,OAAO,CAAC,CAAC,CAAC,GAAG,OAAO,CAAC,IAAI,CAAC;CAM7E;AAED,eAAe,WAAW,CAAC"}
package/dist/user.js ADDED
@@ -0,0 +1,89 @@
1
+ import { createDb } from "./createDb.js";
2
+ class UserManager {
3
+ db;
4
+ constructor(valthera) {
5
+ this.db = createDb(valthera);
6
+ }
7
+ /**
8
+ * Creates a new user
9
+ * @param userData User data (_id is required)
10
+ */
11
+ async createUser(userData) {
12
+ const newUser = {
13
+ _id: userData._id,
14
+ roles: userData.roles || [],
15
+ attrib: userData.attrib || {},
16
+ };
17
+ await this.db.add("users", newUser, false);
18
+ }
19
+ /**
20
+ * Retrieves a user by _id
21
+ * @param user_id User _id
22
+ * @returns User or null if it doesn't exist
23
+ */
24
+ async getUser(user_id) {
25
+ return this.db.findOne("users", { _id: user_id });
26
+ }
27
+ /**
28
+ * Updates a user's data
29
+ * @param user_id User _id
30
+ * @param updates Object with fields to update
31
+ */
32
+ async updateUser(user_id, updates) {
33
+ const existingUser = await this.getUser(user_id);
34
+ if (!existingUser)
35
+ throw new Error("User not found");
36
+ const updatedUser = { ...existingUser, ...updates };
37
+ await this.db.update("users", { _id: user_id }, updatedUser);
38
+ }
39
+ /**
40
+ * Deletes a user
41
+ * @param user_id User _id
42
+ */
43
+ async deleteUser(user_id) {
44
+ await this.db.removeOne("users", { _id: user_id });
45
+ }
46
+ /**
47
+ * Adds a role to a user
48
+ * @param user_id User _id
49
+ * @param role_id Role _id
50
+ */
51
+ async addRoleToUser(user_id, role_id) {
52
+ const user = await this.getUser(user_id);
53
+ if (!user)
54
+ throw new Error("User not found");
55
+ if (!user.roles.includes(role_id)) {
56
+ user.roles.push(role_id);
57
+ await this.db.update("users", { _id: user_id }, user);
58
+ }
59
+ }
60
+ /**
61
+ * Removes a role from a user
62
+ * @param user_id User _id
63
+ * @param role_id Role _id
64
+ */
65
+ async removeRoleFromUser(user_id, role_id) {
66
+ const user = await this.getUser(user_id);
67
+ if (!user)
68
+ throw new Error("User not found");
69
+ const index = user.roles.indexOf(role_id);
70
+ if (index !== -1) {
71
+ user.roles.splice(index, 1);
72
+ await this.db.update("users", { _id: user_id }, user);
73
+ }
74
+ }
75
+ /**
76
+ * Updates a user's attributes
77
+ * @param user_id User _id
78
+ * @param attributes New attributes to merge
79
+ */
80
+ async updateAttributes(user_id, attributes) {
81
+ const user = await this.getUser(user_id);
82
+ if (!user)
83
+ throw new Error("User not found");
84
+ user.attrib = { ...user.attrib, ...attributes };
85
+ await this.db.update("users", { _id: user_id }, user);
86
+ }
87
+ }
88
+ export default UserManager;
89
+ //# sourceMappingURL=user.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"user.js","sourceRoot":"","sources":["../src/user.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,10 @@
1
+ import { Valthera } from "@wxn0brp/db";
2
+ import { AccessResult } from "./types/system.js";
3
+ declare class GateWarden<A = any> {
4
+ debugLog: number;
5
+ private db;
6
+ constructor(valthera: string | Valthera, debugLog?: number);
7
+ hasAccess(userId: string, entityId: string, flag: number): Promise<AccessResult>;
8
+ }
9
+ export default GateWarden;
10
+ //# sourceMappingURL=warden.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"warden.d.ts","sourceRoot":"","sources":["../src/warden.ts"],"names":[],"mappings":"AAAA,OAAO,EAAM,QAAQ,EAAE,MAAM,aAAa,CAAC;AAC3C,OAAO,EAAY,YAAY,EAA6B,MAAM,gBAAgB,CAAC;AA0GnF,cAAM,UAAU,CAAC,CAAC,GAAG,GAAG;IAG4B,QAAQ,EAAE,MAAM;IAFhE,OAAO,CAAC,EAAE,CAAW;gBAET,QAAQ,EAAE,MAAM,GAAG,QAAQ,EAAS,QAAQ,GAAE,MAAU;IAI9D,SAAS,CAAC,MAAM,EAAE,MAAM,EAAE,QAAQ,EAAE,MAAM,EAAE,IAAI,EAAE,MAAM,GAAG,OAAO,CAAC,YAAY,CAAC;CA4BzF;AAED,eAAe,UAAU,CAAC"}
package/dist/warden.js ADDED
@@ -0,0 +1,122 @@
1
+ import { COLORS } from "./log.js";
2
+ import { createDb } from "./createDb.js";
3
+ function logAccess(userId, entityId, via, debugLog) {
4
+ if (debugLog < 1)
5
+ return;
6
+ console.log(`${COLORS.green}[GW] Access granted to ${COLORS.yellow}${entityId}${COLORS.green} via ` +
7
+ `${COLORS.yellow}${via}${COLORS.green} by ${COLORS.yellow}${userId}${COLORS.reset}`);
8
+ }
9
+ async function fetchUser(db, userId) {
10
+ const user = await db.findOne("users", { _id: userId });
11
+ if (!user)
12
+ throw new Error("User not found");
13
+ return user;
14
+ }
15
+ async function aclCheck({ db, entityId, flag, user }) {
16
+ if (!await db.issetCollection("acl/" + entityId))
17
+ return -1;
18
+ const rules = await db.find("acl/" + entityId, {
19
+ $or: [
20
+ { uid: user._id },
21
+ {
22
+ $not: {
23
+ $exists: { "uid": true }
24
+ }
25
+ }
26
+ ]
27
+ });
28
+ if (rules.length === 0)
29
+ return -1;
30
+ for (const rule of rules) {
31
+ if (rule.p & flag)
32
+ return 1;
33
+ }
34
+ return 0;
35
+ }
36
+ async function rbacCheck({ db, flag, user, entityId }) {
37
+ for (const role of user.roles) {
38
+ const rolesEntity = await db.find("role/" + role, { _id: entityId });
39
+ for (const entity of rolesEntity) {
40
+ if (entity.p & flag)
41
+ return true;
42
+ }
43
+ }
44
+ return false;
45
+ }
46
+ async function abacCheck({ db, entityId, flag, user, debugLog }) {
47
+ if (!await db.issetCollection("abac/" + entityId))
48
+ return false;
49
+ const rules = await db.find("abac/" + entityId, { flag });
50
+ for (const rule of rules) {
51
+ try {
52
+ const conditions = new Function("user", "entity", `return ${rule.conditions}`)();
53
+ if (debugLog >= 1)
54
+ console.log(COLORS.blue + `[GW] ABAC rule: ${COLORS.yellow}${rule.conditions}${COLORS.blue} ` +
55
+ `-> ${COLORS.yellow}${conditions(user, entityId)}` + COLORS.reset);
56
+ if (conditions(user, entityId))
57
+ return true;
58
+ }
59
+ catch (e) {
60
+ if (debugLog >= 1)
61
+ console.log(COLORS.red + `[GW] ABAC rule error: ${e}` + COLORS.reset);
62
+ }
63
+ }
64
+ return false;
65
+ }
66
+ async function matchPermission(db, entityId, flag, user, debugLog) {
67
+ const checks = [
68
+ { name: "ACL", method: aclCheck },
69
+ { name: "RBAC", method: rbacCheck },
70
+ { name: "ABAC", method: abacCheck },
71
+ ];
72
+ const results = [];
73
+ const checkParams = { db, entityId, flag, user, debugLog };
74
+ for (const check of checks) {
75
+ const result = await check.method(checkParams);
76
+ results.push(result);
77
+ if (result === true || result === 1) {
78
+ return { granted: true, via: check.name };
79
+ }
80
+ }
81
+ if (results[0] === -1) {
82
+ return { granted: false, via: "entity-404" };
83
+ }
84
+ return { granted: false, via: null };
85
+ }
86
+ class GateWarden {
87
+ debugLog;
88
+ db;
89
+ constructor(valthera, debugLog = 0) {
90
+ this.debugLog = debugLog;
91
+ this.db = createDb(valthera);
92
+ }
93
+ async hasAccess(userId, entityId, flag) {
94
+ const user = await fetchUser(this.db, userId);
95
+ if (!user) {
96
+ if (this.debugLog >= 1)
97
+ console.log(COLORS.red + "[GW] User not found." + COLORS.reset);
98
+ return {
99
+ granted: false,
100
+ via: "user-404"
101
+ };
102
+ }
103
+ const matched = await matchPermission(this.db, entityId, flag, user, this.debugLog);
104
+ if (matched.granted) {
105
+ logAccess(userId, entityId, matched.via, this.debugLog);
106
+ return matched;
107
+ }
108
+ if (!matched.granted && matched.via === "entity-404") {
109
+ if (this.debugLog >= 1)
110
+ console.log(COLORS.red + `[GW] Entity not found: ${entityId}` + COLORS.reset);
111
+ return matched;
112
+ }
113
+ if (this.debugLog >= 1)
114
+ console.log(COLORS.red + `[GW] Access denied to ${entityId} by ${userId}.` + COLORS.reset);
115
+ return {
116
+ granted: false,
117
+ via: "not-permitted"
118
+ };
119
+ }
120
+ }
121
+ export default GateWarden;
122
+ //# sourceMappingURL=warden.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"warden.js","sourceRoot":"","sources":["../src/warden.ts"],"names":[],"mappings":"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"}
package/package.json ADDED
@@ -0,0 +1,34 @@
1
+ {
2
+ "name": "@wxn0brp/gate-warden",
3
+ "version": "0.1.0",
4
+ "main": "dist/index.js",
5
+ "types": "dist/index.d.ts",
6
+ "author": "wxn0brP",
7
+ "license": "MIT",
8
+ "type": "module",
9
+ "scripts": {
10
+ "build": "tsc && tsc-alias",
11
+ "build-dev": "tsc -p tsconfig.dev.json && tsc-alias",
12
+ "test": "node dist/test/test.js"
13
+ },
14
+ "devDependencies": {
15
+ "@types/node": "^22.13.11",
16
+ "@wxn0brp/db": ">=0.7.1",
17
+ "source-map-support": "^0.5.21",
18
+ "tsc-alias": "^1.8.10",
19
+ "typescript": "^5.7.3"
20
+ },
21
+ "peerDependencies": {
22
+ "@wxn0brp/db": ">=0.7.1"
23
+ },
24
+ "exports": {
25
+ ".": {
26
+ "types": "./dist/index.d.ts",
27
+ "import": "./dist/index.js"
28
+ },
29
+ "./*": {
30
+ "types": "./*",
31
+ "import": "./*"
32
+ }
33
+ }
34
+ }
@@ -0,0 +1,7 @@
1
+ import { Valthera, ValtheraAutoCreate } from "@wxn0brp/db";
2
+ import { Remote } from "@wxn0brp/db/dist/client/remote";
3
+
4
+ export function createDb(valthera: string | Valthera | Remote): Valthera {
5
+ if (valthera instanceof Valthera) return valthera;
6
+ return ValtheraAutoCreate(valthera) as Valthera;
7
+ }
package/src/index.ts ADDED
@@ -0,0 +1,11 @@
1
+ import GateWarden from "./warden";
2
+ import UserManager from "./user";
3
+ import WardenManager from "./mgr";
4
+ import { AccessResult } from "./types/system";
5
+
6
+ export {
7
+ GateWarden,
8
+ UserManager,
9
+ WardenManager,
10
+ AccessResult
11
+ };
package/src/log.ts ADDED
@@ -0,0 +1,7 @@
1
+ export const COLORS = {
2
+ reset: "\x1b[0m",
3
+ green: "\x1b[32m",
4
+ yellow: "\x1b[33m",
5
+ red: "\x1b[31m",
6
+ blue: "\x1b[34m",
7
+ };
package/src/mgr.ts ADDED
@@ -0,0 +1,54 @@
1
+ import { Id, Valthera } from "@wxn0brp/db";
2
+ import { ABACRule, ACLRule, Role } from "./types/system";
3
+ import { Remote } from "@wxn0brp/db/dist/client/remote";
4
+ import { createDb } from "./createDb";
5
+
6
+ class WardenManager<A = any> {
7
+ private db: Valthera;
8
+ constructor(valthera: string | Valthera | Remote) {
9
+ this.db = createDb(valthera);
10
+ }
11
+
12
+ async changeRoleNameToId(name: string): Promise<Id> {
13
+ return await this.db.findOne("roles", { name });
14
+ }
15
+
16
+ // ADD
17
+ async addRole(role: Role): Promise<Role> {
18
+ return await this.db.add("roles", role);
19
+ }
20
+
21
+ async addACLRule(entityId: string, p: number, uid?: Id): Promise<void> {
22
+ const rule: ACLRule = { p };
23
+ if (uid) rule.uid = uid;
24
+ return await this.db.add("acl/"+entityId, rule, false);
25
+ }
26
+
27
+ async addRBACRule(role_id: string, entity_id: string, p: number): Promise<void> {
28
+ return await this.db.add("role/" + role_id, { _id: entity_id, p }, false);
29
+ }
30
+
31
+ async addABACRule(entity_id: string, flag: number, condition: ABACRule<A>["conditions"]): Promise<void> {
32
+ return await this.db.add("abac/"+entity_id, { flag, conditions: condition.toString() }, true);
33
+ }
34
+
35
+ // DELETE
36
+ async removeRole(roleId: string): Promise<boolean> {
37
+ return await this.db.removeOne("roles", { roleId });
38
+ }
39
+
40
+ async removeACLRule(entityId: string, uid?: string): Promise<boolean> {
41
+ const q = uid ? { uid } : { $not: { $exists: { "uid": true } } };
42
+ return await this.db.removeOne("acl/" + entityId, q);
43
+ }
44
+
45
+ async removeRBACRule(roleId: string, entityId: string): Promise<boolean> {
46
+ return await this.db.removeOne("role/" + roleId, { _id: entityId });
47
+ }
48
+
49
+ async removeABACRule(entityId: string, flag: number): Promise<boolean> {
50
+ return await this.db.removeOne("abac/" + entityId, { flag });
51
+ }
52
+ }
53
+
54
+ export default WardenManager;
@@ -0,0 +1,32 @@
1
+ import { Id } from "@wxn0brp/db";
2
+
3
+ export interface Role {
4
+ _id: Id;
5
+ name: string;
6
+ }
7
+
8
+ export interface RoleEntity {
9
+ _id: Id;
10
+ p: number;
11
+ }
12
+
13
+ export interface ACLRule {
14
+ uid?: Id;
15
+ p: number;
16
+ }
17
+
18
+ export interface ABACRule<A> {
19
+ flag: number;
20
+ conditions: (user: User<A>, entity: any) => boolean;
21
+ }
22
+
23
+ export interface User<A> {
24
+ _id: Id;
25
+ roles: Id[];
26
+ attrib: A;
27
+ }
28
+
29
+ export interface AccessResult {
30
+ granted: boolean;
31
+ via: "ACL" | "RBAC" | "ABAC" | "user-404" | "entity-404" | "not-permitted";
32
+ }
package/src/user.ts ADDED
@@ -0,0 +1,96 @@
1
+ import { Id, Valthera } from "@wxn0brp/db";
2
+ import { User } from "./types/system";
3
+ import { createDb } from "./createDb";
4
+
5
+ class UserManager<A = any> {
6
+ private db: Valthera;
7
+
8
+ constructor(valthera: string | Valthera) {
9
+ this.db = createDb(valthera);
10
+ }
11
+
12
+ /**
13
+ * Creates a new user
14
+ * @param userData User data (_id is required)
15
+ */
16
+ async createUser(userData: { _id: Id; roles?: Id[]; attrib?: A }): Promise<void> {
17
+ const newUser: User<A> = {
18
+ _id: userData._id,
19
+ roles: userData.roles || [],
20
+ attrib: userData.attrib || {} as A,
21
+ };
22
+ await this.db.add("users", newUser, false);
23
+ }
24
+
25
+ /**
26
+ * Retrieves a user by _id
27
+ * @param user_id User _id
28
+ * @returns User or null if it doesn't exist
29
+ */
30
+ async getUser(user_id: Id): Promise<User<A> | null> {
31
+ return this.db.findOne<User<A>>("users", { _id: user_id });
32
+ }
33
+
34
+ /**
35
+ * Updates a user's data
36
+ * @param user_id User _id
37
+ * @param updates Object with fields to update
38
+ */
39
+ async updateUser(user_id: Id, updates: Partial<User<A>>): Promise<void> {
40
+ const existingUser = await this.getUser(user_id);
41
+ if (!existingUser) throw new Error("User not found");
42
+ const updatedUser = { ...existingUser, ...updates };
43
+ await this.db.update("users", { _id: user_id }, updatedUser);
44
+ }
45
+
46
+ /**
47
+ * Deletes a user
48
+ * @param user_id User _id
49
+ */
50
+ async deleteUser(user_id: Id): Promise<void> {
51
+ await this.db.removeOne("users", { _id: user_id });
52
+ }
53
+
54
+ /**
55
+ * Adds a role to a user
56
+ * @param user_id User _id
57
+ * @param role_id Role _id
58
+ */
59
+ async addRoleToUser(user_id: Id, role_id: Id): Promise<void> {
60
+ const user = await this.getUser(user_id);
61
+ if (!user) throw new Error("User not found");
62
+ if (!user.roles.includes(role_id)) {
63
+ user.roles.push(role_id);
64
+ await this.db.update("users", { _id: user_id }, user);
65
+ }
66
+ }
67
+
68
+ /**
69
+ * Removes a role from a user
70
+ * @param user_id User _id
71
+ * @param role_id Role _id
72
+ */
73
+ async removeRoleFromUser(user_id: Id, role_id: Id): Promise<void> {
74
+ const user = await this.getUser(user_id);
75
+ if (!user) throw new Error("User not found");
76
+ const index = user.roles.indexOf(role_id);
77
+ if (index !== -1) {
78
+ user.roles.splice(index, 1);
79
+ await this.db.update("users", { _id: user_id }, user);
80
+ }
81
+ }
82
+
83
+ /**
84
+ * Updates a user's attributes
85
+ * @param user_id User _id
86
+ * @param attributes New attributes to merge
87
+ */
88
+ async updateAttributes(user_id: Id, attributes: Partial<A>): Promise<void> {
89
+ const user = await this.getUser(user_id);
90
+ if (!user) throw new Error("User not found");
91
+ user.attrib = { ...user.attrib, ...attributes };
92
+ await this.db.update("users", { _id: user_id }, user);
93
+ }
94
+ }
95
+
96
+ export default UserManager;
package/src/warden.ts ADDED
@@ -0,0 +1,145 @@
1
+ import { Id, Valthera } from "@wxn0brp/db";
2
+ import { ABACRule, AccessResult, ACLRule, RoleEntity, User } from "./types/system";
3
+ import { COLORS } from "./log";
4
+ import { createDb } from "./createDb";
5
+
6
+ interface CheckParams<A> {
7
+ db: Valthera;
8
+ entityId: Id;
9
+ flag: number;
10
+ user: User<A>;
11
+ debugLog: number;
12
+ }
13
+
14
+ function logAccess(userId: Id, entityId: Id, via: string, debugLog: number) {
15
+ if (debugLog < 1) return;
16
+ console.log(
17
+ `${COLORS.green}[GW] Access granted to ${COLORS.yellow}${entityId}${COLORS.green} via ` +
18
+ `${COLORS.yellow}${via}${COLORS.green} by ${COLORS.yellow}${userId}${COLORS.reset}`
19
+ );
20
+ }
21
+
22
+ async function fetchUser<A>(db: Valthera, userId: Id): Promise<User<A>> {
23
+ const user = await db.findOne<User<A>>("users", { _id: userId });
24
+ if (!user) throw new Error("User not found");
25
+ return user;
26
+ }
27
+
28
+ async function aclCheck<A>({ db, entityId, flag, user }: CheckParams<A>): Promise<number> {
29
+ if (!await db.issetCollection("acl/" + entityId)) return -1;
30
+ const rules = await db.find<ACLRule>("acl/" + entityId, {
31
+ $or: [
32
+ { uid: user._id },
33
+ {
34
+ $not: {
35
+ $exists: { "uid": true }
36
+ }
37
+ }
38
+ ]
39
+ });
40
+ if (rules.length === 0) return -1;
41
+ for (const rule of rules) {
42
+ if (rule.p & flag) return 1;
43
+ }
44
+ return 0;
45
+ }
46
+
47
+ async function rbacCheck<A>({ db, flag, user, entityId }: CheckParams<A>): Promise<boolean> {
48
+ for (const role of user.roles) {
49
+ const rolesEntity = await db.find<RoleEntity>("role/" + role, { _id: entityId });
50
+ for (const entity of rolesEntity) {
51
+ if (entity.p & flag) return true;
52
+ }
53
+ }
54
+ return false;
55
+ }
56
+
57
+ async function abacCheck<A>({ db, entityId, flag, user, debugLog }: CheckParams<A>): Promise<boolean> {
58
+ if (!await db.issetCollection("abac/" + entityId)) return false;
59
+ const rules = await db.find<ABACRule<A>>("abac/" + entityId, { flag });
60
+ for (const rule of rules) {
61
+ try {
62
+ const conditions = new Function("user", "entity", `return ${rule.conditions}`)();
63
+ if (debugLog >= 1)
64
+ console.log(
65
+ COLORS.blue + `[GW] ABAC rule: ${COLORS.yellow}${rule.conditions}${COLORS.blue} ` +
66
+ `-> ${COLORS.yellow}${conditions(user, entityId)}` + COLORS.reset
67
+ );
68
+
69
+ if (conditions(user, entityId)) return true;
70
+ } catch (e) {
71
+ if (debugLog >= 1) console.log(COLORS.red + `[GW] ABAC rule error: ${e}` + COLORS.reset);
72
+ }
73
+ }
74
+ return false;
75
+ }
76
+
77
+ async function matchPermission<A>(
78
+ db: Valthera,
79
+ entityId: Id,
80
+ flag: number,
81
+ user: User<A>,
82
+ debugLog: number
83
+ ): Promise<AccessResult> {
84
+ const checks = [
85
+ { name: "ACL", method: aclCheck },
86
+ { name: "RBAC", method: rbacCheck },
87
+ { name: "ABAC", method: abacCheck },
88
+ ] as const;
89
+
90
+ const results = [];
91
+
92
+ const checkParams: CheckParams<A> = { db, entityId, flag, user, debugLog };
93
+ for (const check of checks) {
94
+ const result = await check.method(checkParams);
95
+ results.push(result);
96
+ if (result === true || result === 1) {
97
+ return { granted: true, via: check.name };
98
+ }
99
+ }
100
+
101
+ if (results[0] === -1) {
102
+ return { granted: false, via: "entity-404" };
103
+ }
104
+
105
+ return { granted: false, via: null };
106
+ }
107
+
108
+ class GateWarden<A = any> {
109
+ private db: Valthera;
110
+
111
+ constructor(valthera: string | Valthera, public debugLog: number = 0) {
112
+ this.db = createDb(valthera);
113
+ }
114
+
115
+ async hasAccess(userId: string, entityId: string, flag: number): Promise<AccessResult> {
116
+ const user = await fetchUser<A>(this.db, userId);
117
+ if (!user) {
118
+ if (this.debugLog >= 1) console.log(COLORS.red + "[GW] User not found." + COLORS.reset);
119
+ return {
120
+ granted: false,
121
+ via: "user-404"
122
+ };
123
+ }
124
+
125
+ const matched = await matchPermission(this.db, entityId, flag, user, this.debugLog);
126
+
127
+ if (matched.granted) {
128
+ logAccess(userId, entityId, matched.via, this.debugLog);
129
+ return matched;
130
+ }
131
+
132
+ if (!matched.granted && matched.via === "entity-404") {
133
+ if (this.debugLog >= 1) console.log(COLORS.red + `[GW] Entity not found: ${entityId}` + COLORS.reset);
134
+ return matched;
135
+ }
136
+
137
+ if (this.debugLog >= 1) console.log(COLORS.red + `[GW] Access denied to ${entityId} by ${userId}.` + COLORS.reset);
138
+ return {
139
+ granted: false,
140
+ via: "not-permitted"
141
+ };
142
+ }
143
+ }
144
+
145
+ export default GateWarden;
package/suglite.json ADDED
@@ -0,0 +1,11 @@
1
+ {
2
+ "cmd": "yarn build-dev && yarn test",
3
+ "watch": [
4
+ "src"
5
+ ],
6
+ "restart_cmd": "clear",
7
+ "events": {
8
+ "rs": "clear",
9
+ "clear": "rm -rf dist"
10
+ }
11
+ }
@@ -0,0 +1,6 @@
1
+ {
2
+ "extends": "./tsconfig.json",
3
+ "exclude": [
4
+ "node_modules"
5
+ ]
6
+ }
package/tsconfig.json ADDED
@@ -0,0 +1,26 @@
1
+ {
2
+ "compilerOptions": {
3
+ "module": "ES2022",
4
+ "target": "ES2022",
5
+ "moduleResolution": "Node",
6
+ "paths": {},
7
+ "esModuleInterop": true,
8
+ "skipLibCheck": true,
9
+ "outDir": "./dist",
10
+ "inlineSourceMap": false,
11
+ "sourceMap": true,
12
+ "declaration": true,
13
+ "declarationMap": true,
14
+ },
15
+ "include": [
16
+ "./src"
17
+ ],
18
+ "exclude": [
19
+ "node_modules",
20
+ "src/test"
21
+ ],
22
+ "tsc-alias": {
23
+ "resolveFullPaths": true,
24
+ "verbose": false
25
+ }
26
+ }