@c9up/warden 0.1.3 → 0.1.4
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/dist/AuthManager.d.ts +98 -0
- package/dist/AuthManager.d.ts.map +1 -0
- package/dist/AuthManager.js +147 -0
- package/dist/AuthManager.js.map +1 -0
- package/dist/AuthRateLimiter.d.ts +29 -0
- package/dist/AuthRateLimiter.d.ts.map +1 -0
- package/dist/AuthRateLimiter.js +88 -0
- package/dist/AuthRateLimiter.js.map +1 -0
- package/dist/Guard.d.ts +26 -0
- package/dist/Guard.d.ts.map +1 -0
- package/dist/Guard.js +52 -0
- package/dist/Guard.js.map +1 -0
- package/dist/RefreshTokenStore.d.ts +34 -0
- package/dist/RefreshTokenStore.d.ts.map +1 -0
- package/dist/RefreshTokenStore.js +48 -0
- package/dist/RefreshTokenStore.js.map +1 -0
- package/dist/TokenBlacklist.d.ts +30 -0
- package/dist/TokenBlacklist.d.ts.map +1 -0
- package/dist/TokenBlacklist.js +50 -0
- package/dist/TokenBlacklist.js.map +1 -0
- package/dist/WardenProvider.d.ts +19 -0
- package/dist/WardenProvider.d.ts.map +1 -0
- package/dist/WardenProvider.js +61 -0
- package/dist/WardenProvider.js.map +1 -0
- package/dist/bouncer/AuthorizationResponse.d.ts +25 -0
- package/dist/bouncer/AuthorizationResponse.d.ts.map +1 -0
- package/dist/bouncer/AuthorizationResponse.js +31 -0
- package/dist/bouncer/AuthorizationResponse.js.map +1 -0
- package/dist/bouncer/BasePolicy.d.ts +47 -0
- package/dist/bouncer/BasePolicy.d.ts.map +1 -0
- package/dist/bouncer/BasePolicy.js +36 -0
- package/dist/bouncer/BasePolicy.js.map +1 -0
- package/dist/bouncer/Bouncer.d.ts +47 -0
- package/dist/bouncer/Bouncer.d.ts.map +1 -0
- package/dist/bouncer/Bouncer.js +134 -0
- package/dist/bouncer/Bouncer.js.map +1 -0
- package/dist/bouncer/PolicyAuthorizer.d.ts +24 -0
- package/dist/bouncer/PolicyAuthorizer.d.ts.map +1 -0
- package/dist/bouncer/PolicyAuthorizer.js +92 -0
- package/dist/bouncer/PolicyAuthorizer.js.map +1 -0
- package/dist/bouncer/decorators.d.ts +25 -0
- package/dist/bouncer/decorators.d.ts.map +1 -0
- package/dist/bouncer/decorators.js +36 -0
- package/dist/bouncer/decorators.js.map +1 -0
- package/dist/bouncer/evaluate.d.ts +36 -0
- package/dist/bouncer/evaluate.d.ts.map +1 -0
- package/dist/bouncer/evaluate.js +64 -0
- package/dist/bouncer/evaluate.js.map +1 -0
- package/dist/bouncer/policyContext.d.ts +29 -0
- package/dist/bouncer/policyContext.d.ts.map +1 -0
- package/dist/bouncer/policyContext.js +36 -0
- package/dist/bouncer/policyContext.js.map +1 -0
- package/dist/bouncer/types.d.ts +52 -0
- package/dist/bouncer/types.d.ts.map +1 -0
- package/dist/bouncer/types.js +9 -0
- package/dist/bouncer/types.js.map +1 -0
- package/dist/config.d.ts +42 -0
- package/dist/config.d.ts.map +1 -0
- package/dist/config.js +21 -0
- package/dist/config.js.map +1 -0
- package/dist/configure.d.ts +10 -0
- package/dist/configure.d.ts.map +1 -0
- package/dist/configure.js +44 -0
- package/dist/configure.js.map +1 -0
- package/dist/errors.d.ts +18 -0
- package/dist/errors.d.ts.map +1 -0
- package/dist/errors.js +21 -0
- package/dist/errors.js.map +1 -0
- package/dist/firstcontact/FirstContactManager.d.ts +25 -0
- package/dist/firstcontact/FirstContactManager.d.ts.map +1 -0
- package/dist/firstcontact/FirstContactManager.js +38 -0
- package/dist/firstcontact/FirstContactManager.js.map +1 -0
- package/dist/firstcontact/drivers/GitHubDriver.d.ts +14 -0
- package/dist/firstcontact/drivers/GitHubDriver.d.ts.map +1 -0
- package/dist/firstcontact/drivers/GitHubDriver.js +61 -0
- package/dist/firstcontact/drivers/GitHubDriver.js.map +1 -0
- package/dist/firstcontact/drivers/GoogleDriver.d.ts +14 -0
- package/dist/firstcontact/drivers/GoogleDriver.d.ts.map +1 -0
- package/dist/firstcontact/drivers/GoogleDriver.js +64 -0
- package/dist/firstcontact/drivers/GoogleDriver.js.map +1 -0
- package/dist/firstcontact/types.d.ts +34 -0
- package/dist/firstcontact/types.d.ts.map +1 -0
- package/dist/firstcontact/types.js +5 -0
- package/dist/firstcontact/types.js.map +1 -0
- package/dist/index.d.ts +38 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +27 -0
- package/dist/index.js.map +1 -0
- package/dist/middleware.d.ts +51 -0
- package/dist/middleware.d.ts.map +1 -0
- package/dist/middleware.js +201 -0
- package/dist/middleware.js.map +1 -0
- package/dist/native.d.ts +14 -0
- package/dist/native.d.ts.map +1 -0
- package/dist/native.js +39 -0
- package/dist/native.js.map +1 -0
- package/dist/rights/MemoryRightsStore.d.ts +29 -0
- package/dist/rights/MemoryRightsStore.d.ts.map +1 -0
- package/dist/rights/MemoryRightsStore.js +70 -0
- package/dist/rights/MemoryRightsStore.js.map +1 -0
- package/dist/rights/RightsResolver.d.ts +29 -0
- package/dist/rights/RightsResolver.d.ts.map +1 -0
- package/dist/rights/RightsResolver.js +73 -0
- package/dist/rights/RightsResolver.js.map +1 -0
- package/dist/rights/types.d.ts +55 -0
- package/dist/rights/types.d.ts.map +1 -0
- package/dist/rights/types.js +18 -0
- package/dist/rights/types.js.map +1 -0
- package/dist/services/main.d.ts +19 -0
- package/dist/services/main.d.ts.map +1 -0
- package/dist/services/main.js +32 -0
- package/dist/services/main.js.map +1 -0
- package/dist/standalone.d.ts +37 -0
- package/dist/standalone.d.ts.map +1 -0
- package/dist/standalone.js +92 -0
- package/dist/standalone.js.map +1 -0
- package/dist/strategies/ApiKeyStrategy.d.ts +28 -0
- package/dist/strategies/ApiKeyStrategy.d.ts.map +1 -0
- package/dist/strategies/ApiKeyStrategy.js +36 -0
- package/dist/strategies/ApiKeyStrategy.js.map +1 -0
- package/dist/strategies/JwtStrategy.d.ts +51 -0
- package/dist/strategies/JwtStrategy.d.ts.map +1 -0
- package/dist/strategies/JwtStrategy.js +150 -0
- package/dist/strategies/JwtStrategy.js.map +1 -0
- package/dist/strategies/SessionStrategy.d.ts +58 -0
- package/dist/strategies/SessionStrategy.d.ts.map +1 -0
- package/dist/strategies/SessionStrategy.js +70 -0
- package/dist/strategies/SessionStrategy.js.map +1 -0
- package/index.darwin-arm64.node +0 -0
- package/index.darwin-x64.node +0 -0
- package/index.linux-arm64-gnu.node +0 -0
- package/index.linux-x64-gnu.node +0 -0
- package/index.win32-x64-msvc.node +0 -0
- package/package.json +1 -1
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"TokenBlacklist.js","sourceRoot":"","sources":["../src/TokenBlacklist.ts"],"names":[],"mappings":"AAAA;;;;;;GAMG;AAQH,2CAA2C;AAC3C,MAAM,OAAO,qBAAqB;IACzB,OAAO,GAAwB,IAAI,GAAG,EAAE,CAAC;IAEjD,KAAK,CAAC,GAAG,CAAC,GAAW,EAAE,SAAiB;QACvC,IAAI,CAAC,OAAO,CAAC,GAAG,CAAC,GAAG,EAAE,SAAS,CAAC,CAAC;IAClC,CAAC;IAED,KAAK,CAAC,GAAG,CAAC,GAAW;QACpB,MAAM,SAAS,GAAG,IAAI,CAAC,OAAO,CAAC,GAAG,CAAC,GAAG,CAAC,CAAC;QACxC,IAAI,SAAS,KAAK,SAAS;YAAE,OAAO,KAAK,CAAC;QAC1C,IAAI,SAAS,GAAG,IAAI,CAAC,GAAG,EAAE,EAAE,CAAC;YAC5B,IAAI,CAAC,OAAO,CAAC,MAAM,CAAC,GAAG,CAAC,CAAC;YACzB,OAAO,KAAK,CAAC;QACd,CAAC;QACD,OAAO,IAAI,CAAC;IACb,CAAC;IAED,KAAK,CAAC,OAAO;QACZ,MAAM,GAAG,GAAG,IAAI,CAAC,GAAG,EAAE,CAAC;QACvB,KAAK,MAAM,CAAC,GAAG,EAAE,GAAG,CAAC,IAAI,IAAI,CAAC,OAAO,EAAE,CAAC;YACvC,IAAI,GAAG,GAAG,GAAG;gBAAE,IAAI,CAAC,OAAO,CAAC,MAAM,CAAC,GAAG,CAAC,CAAC;QACzC,CAAC;IACF,CAAC;CACD;AAED,MAAM,OAAO,cAAc;IACN;IAApB,YAAoB,MAAuB;QAAvB,WAAM,GAAN,MAAM,CAAiB;IAAG,CAAC;IAE/C,uCAAuC;IACvC,KAAK,CAAC,MAAM,CAAC,GAAW,EAAE,SAAiB;QAC1C,MAAM,IAAI,CAAC,MAAM,CAAC,GAAG,CAAC,GAAG,EAAE,SAAS,CAAC,CAAC;IACvC,CAAC;IAED,2CAA2C;IAC3C,KAAK,CAAC,SAAS,CAAC,GAAW;QAC1B,OAAO,IAAI,CAAC,MAAM,CAAC,GAAG,CAAC,GAAG,CAAC,CAAC;IAC7B,CAAC;IAED,8BAA8B;IAC9B,KAAK,CAAC,OAAO;QACZ,OAAO,IAAI,CAAC,MAAM,CAAC,OAAO,EAAE,CAAC;IAC9B,CAAC;CACD"}
|
|
@@ -0,0 +1,19 @@
|
|
|
1
|
+
interface WardenContainer {
|
|
2
|
+
singleton(token: unknown, factory: () => unknown): void;
|
|
3
|
+
resolve(token: unknown): unknown;
|
|
4
|
+
}
|
|
5
|
+
interface WardenConfigStore {
|
|
6
|
+
get<T = unknown>(key: string): T | undefined;
|
|
7
|
+
}
|
|
8
|
+
export interface WardenAppContext {
|
|
9
|
+
container: WardenContainer;
|
|
10
|
+
config: WardenConfigStore;
|
|
11
|
+
}
|
|
12
|
+
export default class WardenProvider {
|
|
13
|
+
protected app: WardenAppContext;
|
|
14
|
+
constructor(app: WardenAppContext);
|
|
15
|
+
register(): void;
|
|
16
|
+
boot(): Promise<void>;
|
|
17
|
+
}
|
|
18
|
+
export {};
|
|
19
|
+
//# sourceMappingURL=WardenProvider.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"WardenProvider.d.ts","sourceRoot":"","sources":["../src/WardenProvider.ts"],"names":[],"mappings":"AAQA,UAAU,eAAe;IACxB,SAAS,CAAC,KAAK,EAAE,OAAO,EAAE,OAAO,EAAE,MAAM,OAAO,GAAG,IAAI,CAAC;IACxD,OAAO,CAAC,KAAK,EAAE,OAAO,GAAG,OAAO,CAAC;CACjC;AAED,UAAU,iBAAiB;IAC1B,GAAG,CAAC,CAAC,GAAG,OAAO,EAAE,GAAG,EAAE,MAAM,GAAG,CAAC,GAAG,SAAS,CAAC;CAC7C;AAED,MAAM,WAAW,gBAAgB;IAChC,SAAS,EAAE,eAAe,CAAC;IAC3B,MAAM,EAAE,iBAAiB,CAAC;CAC1B;AAED,MAAM,CAAC,OAAO,OAAO,cAAc;IACtB,SAAS,CAAC,GAAG,EAAE,gBAAgB;gBAArB,GAAG,EAAE,gBAAgB;IAE3C,QAAQ;IAuDF,IAAI;CAGV"}
|
|
@@ -0,0 +1,61 @@
|
|
|
1
|
+
import { AuthManager } from "./AuthManager.js";
|
|
2
|
+
import { WardenError } from "./errors.js";
|
|
3
|
+
import { MemoryRightsStore } from "./rights/MemoryRightsStore.js";
|
|
4
|
+
import { RightsResolver } from "./rights/RightsResolver.js";
|
|
5
|
+
import { setAuth } from "./services/main.js";
|
|
6
|
+
import { JwtStrategy } from "./strategies/JwtStrategy.js";
|
|
7
|
+
export default class WardenProvider {
|
|
8
|
+
app;
|
|
9
|
+
constructor(app) {
|
|
10
|
+
this.app = app;
|
|
11
|
+
}
|
|
12
|
+
register() {
|
|
13
|
+
// Register JwtStrategy first so it's available before AuthManager resolves.
|
|
14
|
+
// The previous version nested the JwtStrategy registration inside the
|
|
15
|
+
// AuthManager factory — that was order-dependent and fragile.
|
|
16
|
+
const config = this.app.config.get("auth");
|
|
17
|
+
// Fail-fast at register-time so the operator gets a clear actionable
|
|
18
|
+
// error during boot instead of an opaque runtime crash on the first
|
|
19
|
+
// protected request. Previously, missing `config.auth` produced an
|
|
20
|
+
// AuthManager with `strategies: {}` and `defaultStrategy: 'jwt'`,
|
|
21
|
+
// passing the (then-permissive) constructor and erroring deep in the
|
|
22
|
+
// middleware loop.
|
|
23
|
+
if (!config?.jwt) {
|
|
24
|
+
throw new WardenError("WARDEN_NO_AUTH_CONFIG", `@c9up/warden: no authentication strategies configured. Set config.warden.auth.jwt (or another strategy) in your reamrc.ts before registering WardenProvider.`);
|
|
25
|
+
}
|
|
26
|
+
const jwt = new JwtStrategy(config.jwt);
|
|
27
|
+
this.app.container.singleton(JwtStrategy, () => jwt);
|
|
28
|
+
// Rights layer (Epic 56): one resolver singleton backs BOTH the coarse
|
|
29
|
+
// RBAC helpers (injected into AuthManager below) and — once 56.6 lands —
|
|
30
|
+
// the Bouncer construction, so a coarse question and a policy question
|
|
31
|
+
// resolve through the SAME instance (single unification point, AC-E3).
|
|
32
|
+
// The store defaults to an in-memory driver and is exposed (by class)
|
|
33
|
+
// so an app can seed roles/grants at boot, or supply its own via
|
|
34
|
+
// `config.auth.rights.store` (AD5).
|
|
35
|
+
const rightsStore = config.rights?.store ?? new MemoryRightsStore();
|
|
36
|
+
const rightsResolver = new RightsResolver(rightsStore);
|
|
37
|
+
this.app.container.singleton(RightsResolver, () => rightsResolver);
|
|
38
|
+
if (rightsStore instanceof MemoryRightsStore) {
|
|
39
|
+
this.app.container.singleton(MemoryRightsStore, () => rightsStore);
|
|
40
|
+
}
|
|
41
|
+
this.app.container.singleton(AuthManager, () => {
|
|
42
|
+
const strategies = { jwt };
|
|
43
|
+
return new AuthManager({
|
|
44
|
+
defaultStrategy: config.defaultStrategy ?? "jwt",
|
|
45
|
+
strategies,
|
|
46
|
+
rights: rightsResolver,
|
|
47
|
+
});
|
|
48
|
+
});
|
|
49
|
+
// String alias so consumers that can't import the AuthManager class
|
|
50
|
+
// (e.g. @c9up/station, which stays agnostic of warden) can resolve
|
|
51
|
+
// it by name. Mirrors the convention other providers follow
|
|
52
|
+
// (events → "bus", rosetta → "i18n"). Without this, Station's
|
|
53
|
+
// `container.resolve("auth")` threw and its admin auth gate
|
|
54
|
+
// silently fell back to open-mode.
|
|
55
|
+
this.app.container.singleton("auth", () => this.app.container.resolve(AuthManager));
|
|
56
|
+
}
|
|
57
|
+
async boot() {
|
|
58
|
+
setAuth(this.app.container.resolve(AuthManager));
|
|
59
|
+
}
|
|
60
|
+
}
|
|
61
|
+
//# sourceMappingURL=WardenProvider.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"WardenProvider.js","sourceRoot":"","sources":["../src/WardenProvider.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,WAAW,EAAE,MAAM,kBAAkB,CAAC;AAE/C,OAAO,EAAE,WAAW,EAAE,MAAM,aAAa,CAAC;AAC1C,OAAO,EAAE,iBAAiB,EAAE,MAAM,+BAA+B,CAAC;AAClE,OAAO,EAAE,cAAc,EAAE,MAAM,4BAA4B,CAAC;AAC5D,OAAO,EAAE,OAAO,EAAE,MAAM,oBAAoB,CAAC;AAC7C,OAAO,EAAE,WAAW,EAAE,MAAM,6BAA6B,CAAC;AAgB1D,MAAM,CAAC,OAAO,OAAO,cAAc;IACZ;IAAtB,YAAsB,GAAqB;QAArB,QAAG,GAAH,GAAG,CAAkB;IAAG,CAAC;IAE/C,QAAQ;QACP,4EAA4E;QAC5E,sEAAsE;QACtE,8DAA8D;QAC9D,MAAM,MAAM,GAAG,IAAI,CAAC,GAAG,CAAC,MAAM,CAAC,GAAG,CAAe,MAAM,CAAC,CAAC;QAEzD,qEAAqE;QACrE,oEAAoE;QACpE,mEAAmE;QACnE,kEAAkE;QAClE,qEAAqE;QACrE,mBAAmB;QACnB,IAAI,CAAC,MAAM,EAAE,GAAG,EAAE,CAAC;YAClB,MAAM,IAAI,WAAW,CACpB,uBAAuB,EACvB,8JAA8J,CAC9J,CAAC;QACH,CAAC;QAED,MAAM,GAAG,GAAG,IAAI,WAAW,CAAC,MAAM,CAAC,GAAG,CAAC,CAAC;QACxC,IAAI,CAAC,GAAG,CAAC,SAAS,CAAC,SAAS,CAAC,WAAW,EAAE,GAAG,EAAE,CAAC,GAAG,CAAC,CAAC;QAErD,uEAAuE;QACvE,yEAAyE;QACzE,uEAAuE;QACvE,uEAAuE;QACvE,sEAAsE;QACtE,iEAAiE;QACjE,oCAAoC;QACpC,MAAM,WAAW,GAAG,MAAM,CAAC,MAAM,EAAE,KAAK,IAAI,IAAI,iBAAiB,EAAE,CAAC;QACpE,MAAM,cAAc,GAAG,IAAI,cAAc,CAAC,WAAW,CAAC,CAAC;QACvD,IAAI,CAAC,GAAG,CAAC,SAAS,CAAC,SAAS,CAAC,cAAc,EAAE,GAAG,EAAE,CAAC,cAAc,CAAC,CAAC;QACnE,IAAI,WAAW,YAAY,iBAAiB,EAAE,CAAC;YAC9C,IAAI,CAAC,GAAG,CAAC,SAAS,CAAC,SAAS,CAAC,iBAAiB,EAAE,GAAG,EAAE,CAAC,WAAW,CAAC,CAAC;QACpE,CAAC;QAED,IAAI,CAAC,GAAG,CAAC,SAAS,CAAC,SAAS,CAAC,WAAW,EAAE,GAAG,EAAE;YAC9C,MAAM,UAAU,GAAgC,EAAE,GAAG,EAAE,CAAC;YACxD,OAAO,IAAI,WAAW,CAAC;gBACtB,eAAe,EAAE,MAAM,CAAC,eAAe,IAAI,KAAK;gBAChD,UAAU;gBACV,MAAM,EAAE,cAAc;aACtB,CAAC,CAAC;QACJ,CAAC,CAAC,CAAC;QACH,oEAAoE;QACpE,mEAAmE;QACnE,4DAA4D;QAC5D,8DAA8D;QAC9D,4DAA4D;QAC5D,mCAAmC;QACnC,IAAI,CAAC,GAAG,CAAC,SAAS,CAAC,SAAS,CAAC,MAAM,EAAE,GAAG,EAAE,CACzC,IAAI,CAAC,GAAG,CAAC,SAAS,CAAC,OAAO,CAAC,WAAW,CAAC,CACvC,CAAC;IACH,CAAC;IAED,KAAK,CAAC,IAAI;QACT,OAAO,CAAC,IAAI,CAAC,GAAG,CAAC,SAAS,CAAC,OAAO,CAAC,WAAW,CAAgB,CAAC,CAAC;IACjE,CAAC;CACD"}
|
|
@@ -0,0 +1,25 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* AuthorizationResponse — the value type every Bouncer check resolves to.
|
|
3
|
+
*
|
|
4
|
+
* Layer 2 (EVALUATION) of Warden's unified authorization (Epic 56). Faithful
|
|
5
|
+
* to AdonisJS Bouncer's `AuthorizationResponse`: instances are produced only by
|
|
6
|
+
* the `allow()` / `deny()` static constructors (the constructor is private), a
|
|
7
|
+
* denial defaults to HTTP 403, and a `translation` field is carried for shape
|
|
8
|
+
* parity with Adonis's i18n hook (always `undefined` in 56.2 — D6).
|
|
9
|
+
*/
|
|
10
|
+
export declare class AuthorizationResponse {
|
|
11
|
+
readonly authorized: boolean;
|
|
12
|
+
readonly message?: string;
|
|
13
|
+
readonly status?: number;
|
|
14
|
+
/** Parity placeholder for an i18n binding (always undefined in 56.2 — D6). */
|
|
15
|
+
readonly translation?: {
|
|
16
|
+
identifier: string;
|
|
17
|
+
data?: Record<string, unknown>;
|
|
18
|
+
};
|
|
19
|
+
private constructor();
|
|
20
|
+
/** Authorized response (no status). */
|
|
21
|
+
static allow(): AuthorizationResponse;
|
|
22
|
+
/** Denied response; `status` defaults to 403 (D6). */
|
|
23
|
+
static deny(message?: string, status?: number): AuthorizationResponse;
|
|
24
|
+
}
|
|
25
|
+
//# sourceMappingURL=AuthorizationResponse.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"AuthorizationResponse.d.ts","sourceRoot":"","sources":["../../src/bouncer/AuthorizationResponse.ts"],"names":[],"mappings":"AAAA;;;;;;;;GAQG;AACH,qBAAa,qBAAqB;IACjC,QAAQ,CAAC,UAAU,EAAE,OAAO,CAAC;IAC7B,QAAQ,CAAC,OAAO,CAAC,EAAE,MAAM,CAAC;IAC1B,QAAQ,CAAC,MAAM,CAAC,EAAE,MAAM,CAAC;IACzB,8EAA8E;IAC9E,QAAQ,CAAC,WAAW,CAAC,EAAE;QAAE,UAAU,EAAE,MAAM,CAAC;QAAC,IAAI,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAA;KAAE,CAAC;IAE9E,OAAO;IAYP,uCAAuC;IACvC,MAAM,CAAC,KAAK,IAAI,qBAAqB;IAIrC,sDAAsD;IACtD,MAAM,CAAC,IAAI,CAAC,OAAO,CAAC,EAAE,MAAM,EAAE,MAAM,SAAM,GAAG,qBAAqB;CAGlE"}
|
|
@@ -0,0 +1,31 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* AuthorizationResponse — the value type every Bouncer check resolves to.
|
|
3
|
+
*
|
|
4
|
+
* Layer 2 (EVALUATION) of Warden's unified authorization (Epic 56). Faithful
|
|
5
|
+
* to AdonisJS Bouncer's `AuthorizationResponse`: instances are produced only by
|
|
6
|
+
* the `allow()` / `deny()` static constructors (the constructor is private), a
|
|
7
|
+
* denial defaults to HTTP 403, and a `translation` field is carried for shape
|
|
8
|
+
* parity with Adonis's i18n hook (always `undefined` in 56.2 — D6).
|
|
9
|
+
*/
|
|
10
|
+
export class AuthorizationResponse {
|
|
11
|
+
authorized;
|
|
12
|
+
message;
|
|
13
|
+
status;
|
|
14
|
+
/** Parity placeholder for an i18n binding (always undefined in 56.2 — D6). */
|
|
15
|
+
translation;
|
|
16
|
+
constructor(authorized, message, status, translation) {
|
|
17
|
+
this.authorized = authorized;
|
|
18
|
+
this.message = message;
|
|
19
|
+
this.status = status;
|
|
20
|
+
this.translation = translation;
|
|
21
|
+
}
|
|
22
|
+
/** Authorized response (no status). */
|
|
23
|
+
static allow() {
|
|
24
|
+
return new AuthorizationResponse(true);
|
|
25
|
+
}
|
|
26
|
+
/** Denied response; `status` defaults to 403 (D6). */
|
|
27
|
+
static deny(message, status = 403) {
|
|
28
|
+
return new AuthorizationResponse(false, message, status);
|
|
29
|
+
}
|
|
30
|
+
}
|
|
31
|
+
//# sourceMappingURL=AuthorizationResponse.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"AuthorizationResponse.js","sourceRoot":"","sources":["../../src/bouncer/AuthorizationResponse.ts"],"names":[],"mappings":"AAAA;;;;;;;;GAQG;AACH,MAAM,OAAO,qBAAqB;IACxB,UAAU,CAAU;IACpB,OAAO,CAAU;IACjB,MAAM,CAAU;IACzB,8EAA8E;IACrE,WAAW,CAA0D;IAE9E,YACC,UAAmB,EACnB,OAAgB,EAChB,MAAe,EACf,WAAoE;QAEpE,IAAI,CAAC,UAAU,GAAG,UAAU,CAAC;QAC7B,IAAI,CAAC,OAAO,GAAG,OAAO,CAAC;QACvB,IAAI,CAAC,MAAM,GAAG,MAAM,CAAC;QACrB,IAAI,CAAC,WAAW,GAAG,WAAW,CAAC;IAChC,CAAC;IAED,uCAAuC;IACvC,MAAM,CAAC,KAAK;QACX,OAAO,IAAI,qBAAqB,CAAC,IAAI,CAAC,CAAC;IACxC,CAAC;IAED,sDAAsD;IACtD,MAAM,CAAC,IAAI,CAAC,OAAgB,EAAE,MAAM,GAAG,GAAG;QACzC,OAAO,IAAI,qBAAqB,CAAC,KAAK,EAAE,OAAO,EAAE,MAAM,CAAC,CAAC;IAC1D,CAAC;CACD"}
|
|
@@ -0,0 +1,47 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* BasePolicy — extend it to group authorization checks for a resource. Action
|
|
3
|
+
* methods are positional `(user, resource?) => AuthorizerResponse` (D3); decorate
|
|
4
|
+
* a method with `@allowGuest()` / `@action({ allowGuest: true })` to let a guest
|
|
5
|
+
* (null user) reach it. The optional `before` / `after` hooks run around every
|
|
6
|
+
* action in the Adonis evaluation order (D5 — see PolicyAuthorizer).
|
|
7
|
+
*/
|
|
8
|
+
import type { UserPayload } from "../AuthManager.js";
|
|
9
|
+
import type { EffectivePermissions, Scope } from "../rights/types.js";
|
|
10
|
+
import type { AuthorizationResponse } from "./AuthorizationResponse.js";
|
|
11
|
+
import type { HookResponse } from "./types.js";
|
|
12
|
+
export declare abstract class BasePolicy {
|
|
13
|
+
/**
|
|
14
|
+
* Runs before the action. A non-`undefined` return short-circuits the action
|
|
15
|
+
* (a `boolean`/`AuthorizationResponse` becomes the result) — this is how a
|
|
16
|
+
* moderator bypass or an early `deny('not found', 404)` works, including for
|
|
17
|
+
* a guest. `undefined`/`void` falls through to the action.
|
|
18
|
+
*/
|
|
19
|
+
before?(user: UserPayload | null, action: string, ...args: unknown[]): HookResponse;
|
|
20
|
+
/**
|
|
21
|
+
* Runs after the action (or after a `before` short-circuit), receiving the
|
|
22
|
+
* resolved response. A non-`undefined` return overrides it; `undefined`
|
|
23
|
+
* keeps it.
|
|
24
|
+
*/
|
|
25
|
+
after?(user: UserPayload | null, action: string, result: AuthorizationResponse): HookResponse;
|
|
26
|
+
/**
|
|
27
|
+
* The Bouncer's active scope for the in-flight check (56.3). Defaults to
|
|
28
|
+
* `"global"` when the policy is used without a Bouncer context.
|
|
29
|
+
*/
|
|
30
|
+
protected get scope(): Scope;
|
|
31
|
+
/**
|
|
32
|
+
* The resolved `EffectivePermissions` for the Bouncer's `(user, scope)` (56.3):
|
|
33
|
+
* role-derived ∪ ACL grants with global→tenant inheritance (per 56.1). A guest,
|
|
34
|
+
* a no-resolver Bouncer, or a standalone policy ⇒ empty permissions.
|
|
35
|
+
*/
|
|
36
|
+
protected get permissions(): EffectivePermissions;
|
|
37
|
+
/**
|
|
38
|
+
* Tenant-isolation helper (D5 — enforceable, not automatic). `true` under the
|
|
39
|
+
* `global` scope (single-tenant — no boundary); under `{ tenant: T }` it is
|
|
40
|
+
* `resource.tenantId === T`. A policy enforces explicitly, e.g.
|
|
41
|
+
* `if (!this.sameTenant(post)) return false`.
|
|
42
|
+
*/
|
|
43
|
+
protected sameTenant(resource: {
|
|
44
|
+
tenantId?: string | null;
|
|
45
|
+
}): boolean;
|
|
46
|
+
}
|
|
47
|
+
//# sourceMappingURL=BasePolicy.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"BasePolicy.d.ts","sourceRoot":"","sources":["../../src/bouncer/BasePolicy.ts"],"names":[],"mappings":"AAAA;;;;;;GAMG;AAEH,OAAO,KAAK,EAAE,WAAW,EAAE,MAAM,mBAAmB,CAAC;AACrD,OAAO,KAAK,EAAE,oBAAoB,EAAE,KAAK,EAAE,MAAM,oBAAoB,CAAC;AACtE,OAAO,KAAK,EAAE,qBAAqB,EAAE,MAAM,4BAA4B,CAAC;AAExE,OAAO,KAAK,EAAE,YAAY,EAAE,MAAM,YAAY,CAAC;AAE/C,8BAAsB,UAAU;IAC/B;;;;;OAKG;IACH,MAAM,CAAC,CACN,IAAI,EAAE,WAAW,GAAG,IAAI,EACxB,MAAM,EAAE,MAAM,EACd,GAAG,IAAI,EAAE,OAAO,EAAE,GAChB,YAAY;IAEf;;;;OAIG;IACH,KAAK,CAAC,CACL,IAAI,EAAE,WAAW,GAAG,IAAI,EACxB,MAAM,EAAE,MAAM,EACd,MAAM,EAAE,qBAAqB,GAC3B,YAAY;IAEf;;;OAGG;IACH,SAAS,KAAK,KAAK,IAAI,KAAK,CAE3B;IAED;;;;OAIG;IACH,SAAS,KAAK,WAAW,IAAI,oBAAoB,CAEhD;IAED;;;;;OAKG;IACH,SAAS,CAAC,UAAU,CAAC,QAAQ,EAAE;QAAE,QAAQ,CAAC,EAAE,MAAM,GAAG,IAAI,CAAA;KAAE,GAAG,OAAO;CAIrE"}
|
|
@@ -0,0 +1,36 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* BasePolicy — extend it to group authorization checks for a resource. Action
|
|
3
|
+
* methods are positional `(user, resource?) => AuthorizerResponse` (D3); decorate
|
|
4
|
+
* a method with `@allowGuest()` / `@action({ allowGuest: true })` to let a guest
|
|
5
|
+
* (null user) reach it. The optional `before` / `after` hooks run around every
|
|
6
|
+
* action in the Adonis evaluation order (D5 — see PolicyAuthorizer).
|
|
7
|
+
*/
|
|
8
|
+
import { emptyPermissions, getPolicyContext } from "./policyContext.js";
|
|
9
|
+
export class BasePolicy {
|
|
10
|
+
/**
|
|
11
|
+
* The Bouncer's active scope for the in-flight check (56.3). Defaults to
|
|
12
|
+
* `"global"` when the policy is used without a Bouncer context.
|
|
13
|
+
*/
|
|
14
|
+
get scope() {
|
|
15
|
+
return getPolicyContext(this)?.scope ?? "global";
|
|
16
|
+
}
|
|
17
|
+
/**
|
|
18
|
+
* The resolved `EffectivePermissions` for the Bouncer's `(user, scope)` (56.3):
|
|
19
|
+
* role-derived ∪ ACL grants with global→tenant inheritance (per 56.1). A guest,
|
|
20
|
+
* a no-resolver Bouncer, or a standalone policy ⇒ empty permissions.
|
|
21
|
+
*/
|
|
22
|
+
get permissions() {
|
|
23
|
+
return getPolicyContext(this)?.permissions ?? emptyPermissions("global");
|
|
24
|
+
}
|
|
25
|
+
/**
|
|
26
|
+
* Tenant-isolation helper (D5 — enforceable, not automatic). `true` under the
|
|
27
|
+
* `global` scope (single-tenant — no boundary); under `{ tenant: T }` it is
|
|
28
|
+
* `resource.tenantId === T`. A policy enforces explicitly, e.g.
|
|
29
|
+
* `if (!this.sameTenant(post)) return false`.
|
|
30
|
+
*/
|
|
31
|
+
sameTenant(resource) {
|
|
32
|
+
const scope = this.scope;
|
|
33
|
+
return scope === "global" ? true : resource.tenantId === scope.tenant;
|
|
34
|
+
}
|
|
35
|
+
}
|
|
36
|
+
//# sourceMappingURL=BasePolicy.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"BasePolicy.js","sourceRoot":"","sources":["../../src/bouncer/BasePolicy.ts"],"names":[],"mappings":"AAAA;;;;;;GAMG;AAKH,OAAO,EAAE,gBAAgB,EAAE,gBAAgB,EAAE,MAAM,oBAAoB,CAAC;AAGxE,MAAM,OAAgB,UAAU;IAwB/B;;;OAGG;IACH,IAAc,KAAK;QAClB,OAAO,gBAAgB,CAAC,IAAI,CAAC,EAAE,KAAK,IAAI,QAAQ,CAAC;IAClD,CAAC;IAED;;;;OAIG;IACH,IAAc,WAAW;QACxB,OAAO,gBAAgB,CAAC,IAAI,CAAC,EAAE,WAAW,IAAI,gBAAgB,CAAC,QAAQ,CAAC,CAAC;IAC1E,CAAC;IAED;;;;;OAKG;IACO,UAAU,CAAC,QAAsC;QAC1D,MAAM,KAAK,GAAG,IAAI,CAAC,KAAK,CAAC;QACzB,OAAO,KAAK,KAAK,QAAQ,CAAC,CAAC,CAAC,IAAI,CAAC,CAAC,CAAC,QAAQ,CAAC,QAAQ,KAAK,KAAK,CAAC,MAAM,CAAC;IACvE,CAAC;CACD"}
|
|
@@ -0,0 +1,47 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Bouncer — Layer 2 (EVALUATION) of Warden's unified authorization (Epic 56).
|
|
3
|
+
*
|
|
4
|
+
* A Bouncer-faithful evaluation core (verified context7 `/adonisjs/bouncer`,
|
|
5
|
+
* 2026-06-01): standalone abilities via `Bouncer.ability`, class-based policies
|
|
6
|
+
* via `with(Policy)`, the four verbs `allows`/`denies`/`authorize`/`execute`,
|
|
7
|
+
* and guest-denied-by-default. The user is `UserPayload | null` (guest = null,
|
|
8
|
+
* D3); `authorize` throws `WARDEN_AUTHORIZATION_FAILURE` carrying `status: 403`
|
|
9
|
+
* (D2). 56.2 ships PURE mechanics — it does NOT consult the Layer-1
|
|
10
|
+
* `RightsResolver` (D4); abilities/policy methods receive `(user, ...args)` and
|
|
11
|
+
* the developer writes the predicate, exactly as Adonis does.
|
|
12
|
+
*/
|
|
13
|
+
import type { UserPayload } from "../AuthManager.js";
|
|
14
|
+
import type { Scope } from "../rights/types.js";
|
|
15
|
+
import { AuthorizationResponse } from "./AuthorizationResponse.js";
|
|
16
|
+
import type { BasePolicy } from "./BasePolicy.js";
|
|
17
|
+
import { PolicyAuthorizer } from "./PolicyAuthorizer.js";
|
|
18
|
+
import type { Ability, AbilityOptions, AuthorizerResponse, BouncerContext } from "./types.js";
|
|
19
|
+
export declare class Bouncer {
|
|
20
|
+
#private;
|
|
21
|
+
constructor(user: UserPayload | null, abilities?: Record<string, Ability<never[]>>, policies?: Record<string, new () => BasePolicy>, context?: BouncerContext);
|
|
22
|
+
/** The active resolution scope (default `"global"`). */
|
|
23
|
+
get scope(): Scope;
|
|
24
|
+
/**
|
|
25
|
+
* Define a standalone ability. Guest (null user) denied by default; pass
|
|
26
|
+
* `{ allowGuest: true }` to let the callback run for a guest (D5 step 2).
|
|
27
|
+
*/
|
|
28
|
+
static ability<Args extends unknown[]>(callback: (user: UserPayload, ...args: Args) => AuthorizerResponse): Ability<Args>;
|
|
29
|
+
static ability<Args extends unknown[]>(options: AbilityOptions, callback: (user: UserPayload | null, ...args: Args) => AuthorizerResponse): Ability<Args>;
|
|
30
|
+
/** Convenience — equivalent to `AuthorizationResponse.deny` (Adonis `bouncer.deny`). */
|
|
31
|
+
deny(message?: string, status?: number): AuthorizationResponse;
|
|
32
|
+
/** Open a policy for checks (D8 — fresh `new PolicyClass()` per check). */
|
|
33
|
+
with(policy: (new () => BasePolicy) | string): PolicyAuthorizer;
|
|
34
|
+
/** Run an ability check and resolve to the full response. */
|
|
35
|
+
execute<Args extends unknown[]>(ability: Ability<Args>, ...args: Args): Promise<AuthorizationResponse>;
|
|
36
|
+
execute(ability: string, ...args: unknown[]): Promise<AuthorizationResponse>;
|
|
37
|
+
/** True iff the ability is authorized. Never throws on denial. */
|
|
38
|
+
allows<Args extends unknown[]>(ability: Ability<Args>, ...args: Args): Promise<boolean>;
|
|
39
|
+
allows(ability: string, ...args: unknown[]): Promise<boolean>;
|
|
40
|
+
/** Boolean negation of {@link allows}. Never throws on denial. */
|
|
41
|
+
denies<Args extends unknown[]>(ability: Ability<Args>, ...args: Args): Promise<boolean>;
|
|
42
|
+
denies(ability: string, ...args: unknown[]): Promise<boolean>;
|
|
43
|
+
/** Resolves on allow; throws `WARDEN_AUTHORIZATION_FAILURE` on deny (D2). */
|
|
44
|
+
authorize<Args extends unknown[]>(ability: Ability<Args>, ...args: Args): Promise<void>;
|
|
45
|
+
authorize(ability: string, ...args: unknown[]): Promise<void>;
|
|
46
|
+
}
|
|
47
|
+
//# sourceMappingURL=Bouncer.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"Bouncer.d.ts","sourceRoot":"","sources":["../../src/bouncer/Bouncer.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;GAWG;AAEH,OAAO,KAAK,EAAE,WAAW,EAAE,MAAM,mBAAmB,CAAC;AAGrD,OAAO,KAAK,EAAwB,KAAK,EAAE,MAAM,oBAAoB,CAAC;AACtE,OAAO,EAAE,qBAAqB,EAAE,MAAM,4BAA4B,CAAC;AACnE,OAAO,KAAK,EAAE,UAAU,EAAE,MAAM,iBAAiB,CAAC;AAElD,OAAO,EAAE,gBAAgB,EAAE,MAAM,uBAAuB,CAAC;AAEzD,OAAO,KAAK,EACX,OAAO,EACP,cAAc,EACd,kBAAkB,EAClB,cAAc,EACd,MAAM,YAAY,CAAC;AAEpB,qBAAa,OAAO;;gBAUlB,IAAI,EAAE,WAAW,GAAG,IAAI,EACxB,SAAS,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,KAAK,EAAE,CAAC,CAAC,EAC5C,QAAQ,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,UAAU,UAAU,CAAC,EAC/C,OAAO,CAAC,EAAE,cAAc;IASzB,wDAAwD;IACxD,IAAI,KAAK,IAAI,KAAK,CAEjB;IAkBD;;;OAGG;IACH,MAAM,CAAC,OAAO,CAAC,IAAI,SAAS,OAAO,EAAE,EACpC,QAAQ,EAAE,CAAC,IAAI,EAAE,WAAW,EAAE,GAAG,IAAI,EAAE,IAAI,KAAK,kBAAkB,GAChE,OAAO,CAAC,IAAI,CAAC;IAChB,MAAM,CAAC,OAAO,CAAC,IAAI,SAAS,OAAO,EAAE,EACpC,OAAO,EAAE,cAAc,EACvB,QAAQ,EAAE,CAAC,IAAI,EAAE,WAAW,GAAG,IAAI,EAAE,GAAG,IAAI,EAAE,IAAI,KAAK,kBAAkB,GACvE,OAAO,CAAC,IAAI,CAAC;IAmChB,wFAAwF;IACxF,IAAI,CAAC,OAAO,CAAC,EAAE,MAAM,EAAE,MAAM,CAAC,EAAE,MAAM,GAAG,qBAAqB;IAI9D,2EAA2E;IAC3E,IAAI,CAAC,MAAM,EAAE,CAAC,UAAU,UAAU,CAAC,GAAG,MAAM,GAAG,gBAAgB;IAY/D,6DAA6D;IAC7D,OAAO,CAAC,IAAI,SAAS,OAAO,EAAE,EAC7B,OAAO,EAAE,OAAO,CAAC,IAAI,CAAC,EACtB,GAAG,IAAI,EAAE,IAAI,GACX,OAAO,CAAC,qBAAqB,CAAC;IACjC,OAAO,CAAC,OAAO,EAAE,MAAM,EAAE,GAAG,IAAI,EAAE,OAAO,EAAE,GAAG,OAAO,CAAC,qBAAqB,CAAC;IAQ5E,kEAAkE;IAClE,MAAM,CAAC,IAAI,SAAS,OAAO,EAAE,EAC5B,OAAO,EAAE,OAAO,CAAC,IAAI,CAAC,EACtB,GAAG,IAAI,EAAE,IAAI,GACX,OAAO,CAAC,OAAO,CAAC;IACnB,MAAM,CAAC,OAAO,EAAE,MAAM,EAAE,GAAG,IAAI,EAAE,OAAO,EAAE,GAAG,OAAO,CAAC,OAAO,CAAC;IAQ7D,kEAAkE;IAClE,MAAM,CAAC,IAAI,SAAS,OAAO,EAAE,EAC5B,OAAO,EAAE,OAAO,CAAC,IAAI,CAAC,EACtB,GAAG,IAAI,EAAE,IAAI,GACX,OAAO,CAAC,OAAO,CAAC;IACnB,MAAM,CAAC,OAAO,EAAE,MAAM,EAAE,GAAG,IAAI,EAAE,OAAO,EAAE,GAAG,OAAO,CAAC,OAAO,CAAC;IAQ7D,6EAA6E;IAC7E,SAAS,CAAC,IAAI,SAAS,OAAO,EAAE,EAC/B,OAAO,EAAE,OAAO,CAAC,IAAI,CAAC,EACtB,GAAG,IAAI,EAAE,IAAI,GACX,OAAO,CAAC,IAAI,CAAC;IAChB,SAAS,CAAC,OAAO,EAAE,MAAM,EAAE,GAAG,IAAI,EAAE,OAAO,EAAE,GAAG,OAAO,CAAC,IAAI,CAAC;CAwD7D"}
|
|
@@ -0,0 +1,134 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Bouncer — Layer 2 (EVALUATION) of Warden's unified authorization (Epic 56).
|
|
3
|
+
*
|
|
4
|
+
* A Bouncer-faithful evaluation core (verified context7 `/adonisjs/bouncer`,
|
|
5
|
+
* 2026-06-01): standalone abilities via `Bouncer.ability`, class-based policies
|
|
6
|
+
* via `with(Policy)`, the four verbs `allows`/`denies`/`authorize`/`execute`,
|
|
7
|
+
* and guest-denied-by-default. The user is `UserPayload | null` (guest = null,
|
|
8
|
+
* D3); `authorize` throws `WARDEN_AUTHORIZATION_FAILURE` carrying `status: 403`
|
|
9
|
+
* (D2). 56.2 ships PURE mechanics — it does NOT consult the Layer-1
|
|
10
|
+
* `RightsResolver` (D4); abilities/policy methods receive `(user, ...args)` and
|
|
11
|
+
* the developer writes the predicate, exactly as Adonis does.
|
|
12
|
+
*/
|
|
13
|
+
import { WardenError } from "../errors.js";
|
|
14
|
+
import { AuthorizationResponse } from "./AuthorizationResponse.js";
|
|
15
|
+
import { evaluate, isAction, throwAuthorizationFailure } from "./evaluate.js";
|
|
16
|
+
import { PolicyAuthorizer } from "./PolicyAuthorizer.js";
|
|
17
|
+
import { emptyPermissions } from "./policyContext.js";
|
|
18
|
+
export class Bouncer {
|
|
19
|
+
#user;
|
|
20
|
+
#abilities;
|
|
21
|
+
#policies;
|
|
22
|
+
#scope;
|
|
23
|
+
#resolver;
|
|
24
|
+
/** Memoized resolution — a Bouncer is fixed per `(user, scope)`, so resolve once (D3). */
|
|
25
|
+
#resolved;
|
|
26
|
+
constructor(user, abilities, policies, context) {
|
|
27
|
+
this.#user = user;
|
|
28
|
+
this.#abilities = abilities ?? {};
|
|
29
|
+
this.#policies = policies ?? {};
|
|
30
|
+
this.#scope = context?.scope ?? "global";
|
|
31
|
+
this.#resolver = context?.resolver;
|
|
32
|
+
}
|
|
33
|
+
/** The active resolution scope (default `"global"`). */
|
|
34
|
+
get scope() {
|
|
35
|
+
return this.#scope;
|
|
36
|
+
}
|
|
37
|
+
/**
|
|
38
|
+
* Resolve this Bouncer's `(user, scope)` to `EffectivePermissions`, memoized
|
|
39
|
+
* once per instance (D3). Guest (`user === null`) or no resolver ⇒ empty
|
|
40
|
+
* permissions — `resolve()` is never called for a guest (D9). 56.6 relocates
|
|
41
|
+
* this cache to the request context without changing the policy-facing API.
|
|
42
|
+
*/
|
|
43
|
+
#resolvePermissions() {
|
|
44
|
+
if (this.#resolved === undefined) {
|
|
45
|
+
this.#resolved =
|
|
46
|
+
this.#resolver !== undefined && this.#user !== null
|
|
47
|
+
? this.#resolver.resolve(this.#user, this.#scope)
|
|
48
|
+
: Promise.resolve(emptyPermissions(this.#scope));
|
|
49
|
+
}
|
|
50
|
+
return this.#resolved;
|
|
51
|
+
}
|
|
52
|
+
static ability(optionsOrCallback, maybeCallback) {
|
|
53
|
+
let allowGuest = false;
|
|
54
|
+
let raw;
|
|
55
|
+
if (typeof optionsOrCallback === "function") {
|
|
56
|
+
raw = optionsOrCallback;
|
|
57
|
+
}
|
|
58
|
+
else {
|
|
59
|
+
allowGuest = optionsOrCallback.allowGuest ?? false;
|
|
60
|
+
raw = maybeCallback;
|
|
61
|
+
}
|
|
62
|
+
// The typed overloads above carry the real callback signature for the
|
|
63
|
+
// caller; the impl param is the universal-function supertype so both
|
|
64
|
+
// overloads are accepted. `isAction` reinterprets it as the invokable
|
|
65
|
+
// `Action` shape (a type guard, not a cast — a function's parameter types
|
|
66
|
+
// are not observable at runtime).
|
|
67
|
+
if (!isAction(raw)) {
|
|
68
|
+
throw new WardenError("INVALID_ABILITY", "Bouncer.ability requires a callback alongside the options object.", { hint: "Bouncer.ability({ allowGuest: true }, (user) => ...)" });
|
|
69
|
+
}
|
|
70
|
+
const callback = raw;
|
|
71
|
+
const execute = (user, ...args) => callback(user, ...args);
|
|
72
|
+
return { allowGuest, execute };
|
|
73
|
+
}
|
|
74
|
+
/** Convenience — equivalent to `AuthorizationResponse.deny` (Adonis `bouncer.deny`). */
|
|
75
|
+
deny(message, status) {
|
|
76
|
+
return AuthorizationResponse.deny(message, status);
|
|
77
|
+
}
|
|
78
|
+
/** Open a policy for checks (D8 — fresh `new PolicyClass()` per check). */
|
|
79
|
+
with(policy) {
|
|
80
|
+
const factory = typeof policy === "string"
|
|
81
|
+
? this.#resolvePolicyClass(policy)
|
|
82
|
+
: () => new policy();
|
|
83
|
+
// The PolicyAuthorizer inherits the Bouncer's scope + the shared memoized
|
|
84
|
+
// resolve so every policy check sees the active `(user, scope)` (AC1/AC3).
|
|
85
|
+
return new PolicyAuthorizer(this.#user, factory, this.#scope, () => this.#resolvePermissions());
|
|
86
|
+
}
|
|
87
|
+
execute(ability, ...args) {
|
|
88
|
+
return this.#evaluateAbility(ability, args);
|
|
89
|
+
}
|
|
90
|
+
async allows(ability, ...args) {
|
|
91
|
+
return (await this.#evaluateAbility(ability, args)).authorized;
|
|
92
|
+
}
|
|
93
|
+
async denies(ability, ...args) {
|
|
94
|
+
return !(await this.#evaluateAbility(ability, args)).authorized;
|
|
95
|
+
}
|
|
96
|
+
async authorize(ability, ...args) {
|
|
97
|
+
const response = await this.#evaluateAbility(ability, args);
|
|
98
|
+
if (!response.authorized) {
|
|
99
|
+
throwAuthorizationFailure(response);
|
|
100
|
+
}
|
|
101
|
+
}
|
|
102
|
+
async #evaluateAbility(ability, args) {
|
|
103
|
+
const resolved = typeof ability === "string" ? this.#resolveAbility(ability) : ability;
|
|
104
|
+
return evaluate({
|
|
105
|
+
user: this.#user,
|
|
106
|
+
action: typeof ability === "string" ? ability : "(ability)",
|
|
107
|
+
allowGuest: resolved.allowGuest,
|
|
108
|
+
run: (user) => resolved.execute(user, ...args),
|
|
109
|
+
args,
|
|
110
|
+
});
|
|
111
|
+
}
|
|
112
|
+
#resolveAbility(name) {
|
|
113
|
+
const found = this.#abilities[name];
|
|
114
|
+
if (found === undefined) {
|
|
115
|
+
throw new WardenError("UNKNOWN_ABILITY", `No ability "${name}" is registered on this Bouncer.`, { hint: "Register it via new Bouncer(user, { [name]: ability })." });
|
|
116
|
+
}
|
|
117
|
+
return found;
|
|
118
|
+
}
|
|
119
|
+
#resolvePolicyClass(name) {
|
|
120
|
+
// Lazy: the lookup runs when a verb constructs the policy, so an unknown
|
|
121
|
+
// name surfaces as a promise rejection (like every other verb error),
|
|
122
|
+
// not a synchronous throw at `with()` time.
|
|
123
|
+
return () => {
|
|
124
|
+
const ctor = this.#policies[name];
|
|
125
|
+
if (ctor === undefined) {
|
|
126
|
+
throw new WardenError("UNKNOWN_POLICY", `No policy "${name}" is registered on this Bouncer.`, {
|
|
127
|
+
hint: "Register it via new Bouncer(user, abilities, { [name]: Policy }).",
|
|
128
|
+
});
|
|
129
|
+
}
|
|
130
|
+
return new ctor();
|
|
131
|
+
};
|
|
132
|
+
}
|
|
133
|
+
}
|
|
134
|
+
//# sourceMappingURL=Bouncer.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"Bouncer.js","sourceRoot":"","sources":["../../src/bouncer/Bouncer.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;GAWG;AAGH,OAAO,EAAE,WAAW,EAAE,MAAM,cAAc,CAAC;AAG3C,OAAO,EAAE,qBAAqB,EAAE,MAAM,4BAA4B,CAAC;AAEnE,OAAO,EAAE,QAAQ,EAAE,QAAQ,EAAE,yBAAyB,EAAE,MAAM,eAAe,CAAC;AAC9E,OAAO,EAAE,gBAAgB,EAAE,MAAM,uBAAuB,CAAC;AACzD,OAAO,EAAE,gBAAgB,EAAE,MAAM,oBAAoB,CAAC;AAQtD,MAAM,OAAO,OAAO;IACV,KAAK,CAAqB;IAC1B,UAAU,CAAmC;IAC7C,SAAS,CAAuC;IAChD,MAAM,CAAQ;IACd,SAAS,CAA6B;IAC/C,0FAA0F;IAC1F,SAAS,CAA4C;IAErD,YACC,IAAwB,EACxB,SAA4C,EAC5C,QAA+C,EAC/C,OAAwB;QAExB,IAAI,CAAC,KAAK,GAAG,IAAI,CAAC;QAClB,IAAI,CAAC,UAAU,GAAG,SAAS,IAAI,EAAE,CAAC;QAClC,IAAI,CAAC,SAAS,GAAG,QAAQ,IAAI,EAAE,CAAC;QAChC,IAAI,CAAC,MAAM,GAAG,OAAO,EAAE,KAAK,IAAI,QAAQ,CAAC;QACzC,IAAI,CAAC,SAAS,GAAG,OAAO,EAAE,QAAQ,CAAC;IACpC,CAAC;IAED,wDAAwD;IACxD,IAAI,KAAK;QACR,OAAO,IAAI,CAAC,MAAM,CAAC;IACpB,CAAC;IAED;;;;;OAKG;IACH,mBAAmB;QAClB,IAAI,IAAI,CAAC,SAAS,KAAK,SAAS,EAAE,CAAC;YAClC,IAAI,CAAC,SAAS;gBACb,IAAI,CAAC,SAAS,KAAK,SAAS,IAAI,IAAI,CAAC,KAAK,KAAK,IAAI;oBAClD,CAAC,CAAC,IAAI,CAAC,SAAS,CAAC,OAAO,CAAC,IAAI,CAAC,KAAK,EAAE,IAAI,CAAC,MAAM,CAAC;oBACjD,CAAC,CAAC,OAAO,CAAC,OAAO,CAAC,gBAAgB,CAAC,IAAI,CAAC,MAAM,CAAC,CAAC,CAAC;QACpD,CAAC;QACD,OAAO,IAAI,CAAC,SAAS,CAAC;IACvB,CAAC;IAaD,MAAM,CAAC,OAAO,CACb,iBAE6C,EAC7C,aAAwD;QAExD,IAAI,UAAU,GAAG,KAAK,CAAC;QACvB,IAAI,GAAY,CAAC;QACjB,IAAI,OAAO,iBAAiB,KAAK,UAAU,EAAE,CAAC;YAC7C,GAAG,GAAG,iBAAiB,CAAC;QACzB,CAAC;aAAM,CAAC;YACP,UAAU,GAAG,iBAAiB,CAAC,UAAU,IAAI,KAAK,CAAC;YACnD,GAAG,GAAG,aAAa,CAAC;QACrB,CAAC;QACD,sEAAsE;QACtE,qEAAqE;QACrE,sEAAsE;QACtE,0EAA0E;QAC1E,kCAAkC;QAClC,IAAI,CAAC,QAAQ,CAAC,GAAG,CAAC,EAAE,CAAC;YACpB,MAAM,IAAI,WAAW,CACpB,iBAAiB,EACjB,mEAAmE,EACnE,EAAE,IAAI,EAAE,sDAAsD,EAAE,CAChE,CAAC;QACH,CAAC;QACD,MAAM,QAAQ,GAAG,GAAG,CAAC;QACrB,MAAM,OAAO,GAAG,CACf,IAAwB,EACxB,GAAG,IAAe,EACG,EAAE,CAAC,QAAQ,CAAC,IAAI,EAAE,GAAG,IAAI,CAAC,CAAC;QACjD,OAAO,EAAE,UAAU,EAAE,OAAO,EAAE,CAAC;IAChC,CAAC;IAED,wFAAwF;IACxF,IAAI,CAAC,OAAgB,EAAE,MAAe;QACrC,OAAO,qBAAqB,CAAC,IAAI,CAAC,OAAO,EAAE,MAAM,CAAC,CAAC;IACpD,CAAC;IAED,2EAA2E;IAC3E,IAAI,CAAC,MAAuC;QAC3C,MAAM,OAAO,GACZ,OAAO,MAAM,KAAK,QAAQ;YACzB,CAAC,CAAC,IAAI,CAAC,mBAAmB,CAAC,MAAM,CAAC;YAClC,CAAC,CAAC,GAAG,EAAE,CAAC,IAAI,MAAM,EAAE,CAAC;QACvB,0EAA0E;QAC1E,2EAA2E;QAC3E,OAAO,IAAI,gBAAgB,CAAC,IAAI,CAAC,KAAK,EAAE,OAAO,EAAE,IAAI,CAAC,MAAM,EAAE,GAAG,EAAE,CAClE,IAAI,CAAC,mBAAmB,EAAE,CAC1B,CAAC;IACH,CAAC;IAQD,OAAO,CACN,OAAkC,EAClC,GAAG,IAAe;QAElB,OAAO,IAAI,CAAC,gBAAgB,CAAC,OAAO,EAAE,IAAI,CAAC,CAAC;IAC7C,CAAC;IAQD,KAAK,CAAC,MAAM,CACX,OAAkC,EAClC,GAAG,IAAe;QAElB,OAAO,CAAC,MAAM,IAAI,CAAC,gBAAgB,CAAC,OAAO,EAAE,IAAI,CAAC,CAAC,CAAC,UAAU,CAAC;IAChE,CAAC;IAQD,KAAK,CAAC,MAAM,CACX,OAAkC,EAClC,GAAG,IAAe;QAElB,OAAO,CAAC,CAAC,MAAM,IAAI,CAAC,gBAAgB,CAAC,OAAO,EAAE,IAAI,CAAC,CAAC,CAAC,UAAU,CAAC;IACjE,CAAC;IAQD,KAAK,CAAC,SAAS,CACd,OAAkC,EAClC,GAAG,IAAe;QAElB,MAAM,QAAQ,GAAG,MAAM,IAAI,CAAC,gBAAgB,CAAC,OAAO,EAAE,IAAI,CAAC,CAAC;QAC5D,IAAI,CAAC,QAAQ,CAAC,UAAU,EAAE,CAAC;YAC1B,yBAAyB,CAAC,QAAQ,CAAC,CAAC;QACrC,CAAC;IACF,CAAC;IAED,KAAK,CAAC,gBAAgB,CACrB,OAAkC,EAClC,IAAe;QAEf,MAAM,QAAQ,GACb,OAAO,OAAO,KAAK,QAAQ,CAAC,CAAC,CAAC,IAAI,CAAC,eAAe,CAAC,OAAO,CAAC,CAAC,CAAC,CAAC,OAAO,CAAC;QACvE,OAAO,QAAQ,CAAC;YACf,IAAI,EAAE,IAAI,CAAC,KAAK;YAChB,MAAM,EAAE,OAAO,OAAO,KAAK,QAAQ,CAAC,CAAC,CAAC,OAAO,CAAC,CAAC,CAAC,WAAW;YAC3D,UAAU,EAAE,QAAQ,CAAC,UAAU;YAC/B,GAAG,EAAE,CAAC,IAAI,EAAE,EAAE,CAAC,QAAQ,CAAC,OAAO,CAAC,IAAI,EAAE,GAAG,IAAI,CAAC;YAC9C,IAAI;SACJ,CAAC,CAAC;IACJ,CAAC;IAED,eAAe,CAAC,IAAY;QAC3B,MAAM,KAAK,GAAG,IAAI,CAAC,UAAU,CAAC,IAAI,CAAC,CAAC;QACpC,IAAI,KAAK,KAAK,SAAS,EAAE,CAAC;YACzB,MAAM,IAAI,WAAW,CACpB,iBAAiB,EACjB,eAAe,IAAI,kCAAkC,EACrD,EAAE,IAAI,EAAE,yDAAyD,EAAE,CACnE,CAAC;QACH,CAAC;QACD,OAAO,KAAK,CAAC;IACd,CAAC;IAED,mBAAmB,CAAC,IAAY;QAC/B,yEAAyE;QACzE,sEAAsE;QACtE,4CAA4C;QAC5C,OAAO,GAAG,EAAE;YACX,MAAM,IAAI,GAAG,IAAI,CAAC,SAAS,CAAC,IAAI,CAAC,CAAC;YAClC,IAAI,IAAI,KAAK,SAAS,EAAE,CAAC;gBACxB,MAAM,IAAI,WAAW,CACpB,gBAAgB,EAChB,cAAc,IAAI,kCAAkC,EACpD;oBACC,IAAI,EAAE,mEAAmE;iBACzE,CACD,CAAC;YACH,CAAC;YACD,OAAO,IAAI,IAAI,EAAE,CAAC;QACnB,CAAC,CAAC;IACH,CAAC;CACD"}
|
|
@@ -0,0 +1,24 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* PolicyAuthorizer — the object returned by `bouncer.with(Policy)`. Exposes the
|
|
3
|
+
* same four verbs as the Bouncer, dispatched to a named action method on a
|
|
4
|
+
* freshly-constructed policy instance (D8 — `new PolicyClass()` per check). The
|
|
5
|
+
* `before`/`after` hooks and the per-method `@allowGuest` rule run through the
|
|
6
|
+
* shared D5 pipeline.
|
|
7
|
+
*/
|
|
8
|
+
import type { UserPayload } from "../AuthManager.js";
|
|
9
|
+
import type { EffectivePermissions, Scope } from "../rights/types.js";
|
|
10
|
+
import type { AuthorizationResponse } from "./AuthorizationResponse.js";
|
|
11
|
+
import { BasePolicy } from "./BasePolicy.js";
|
|
12
|
+
export declare class PolicyAuthorizer {
|
|
13
|
+
#private;
|
|
14
|
+
constructor(user: UserPayload | null, factory: () => BasePolicy, scope?: Scope, resolvePermissions?: () => Promise<EffectivePermissions>);
|
|
15
|
+
/** Run a check and resolve to the full response (D8 — fresh policy per check). */
|
|
16
|
+
execute(action: string, ...args: unknown[]): Promise<AuthorizationResponse>;
|
|
17
|
+
/** True iff the action is authorized. Never throws on denial. */
|
|
18
|
+
allows(action: string, ...args: unknown[]): Promise<boolean>;
|
|
19
|
+
/** Boolean negation of {@link allows}. Never throws on denial. */
|
|
20
|
+
denies(action: string, ...args: unknown[]): Promise<boolean>;
|
|
21
|
+
/** Resolves on allow; throws `WARDEN_AUTHORIZATION_FAILURE` on deny (D2). */
|
|
22
|
+
authorize(action: string, ...args: unknown[]): Promise<void>;
|
|
23
|
+
}
|
|
24
|
+
//# sourceMappingURL=PolicyAuthorizer.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"PolicyAuthorizer.d.ts","sourceRoot":"","sources":["../../src/bouncer/PolicyAuthorizer.ts"],"names":[],"mappings":"AAAA;;;;;;GAMG;AAEH,OAAO,KAAK,EAAE,WAAW,EAAE,MAAM,mBAAmB,CAAC;AAErD,OAAO,KAAK,EAAE,oBAAoB,EAAE,KAAK,EAAE,MAAM,oBAAoB,CAAC;AACtE,OAAO,KAAK,EAAE,qBAAqB,EAAE,MAAM,4BAA4B,CAAC;AACxE,OAAO,EAAE,UAAU,EAAE,MAAM,iBAAiB,CAAC;AAqD7C,qBAAa,gBAAgB;;gBAO3B,IAAI,EAAE,WAAW,GAAG,IAAI,EACxB,OAAO,EAAE,MAAM,UAAU,EACzB,KAAK,GAAE,KAAgB,EACvB,kBAAkB,GAAE,MAAM,OAAO,CAAC,oBAAoB,CACb;IAQ1C,kFAAkF;IAC5E,OAAO,CACZ,MAAM,EAAE,MAAM,EACd,GAAG,IAAI,EAAE,OAAO,EAAE,GAChB,OAAO,CAAC,qBAAqB,CAAC;IAmBjC,iEAAiE;IAC3D,MAAM,CAAC,MAAM,EAAE,MAAM,EAAE,GAAG,IAAI,EAAE,OAAO,EAAE,GAAG,OAAO,CAAC,OAAO,CAAC;IAIlE,kEAAkE;IAC5D,MAAM,CAAC,MAAM,EAAE,MAAM,EAAE,GAAG,IAAI,EAAE,OAAO,EAAE,GAAG,OAAO,CAAC,OAAO,CAAC;IAIlE,6EAA6E;IACvE,SAAS,CAAC,MAAM,EAAE,MAAM,EAAE,GAAG,IAAI,EAAE,OAAO,EAAE,GAAG,OAAO,CAAC,IAAI,CAAC;CAMlE"}
|
|
@@ -0,0 +1,92 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* PolicyAuthorizer — the object returned by `bouncer.with(Policy)`. Exposes the
|
|
3
|
+
* same four verbs as the Bouncer, dispatched to a named action method on a
|
|
4
|
+
* freshly-constructed policy instance (D8 — `new PolicyClass()` per check). The
|
|
5
|
+
* `before`/`after` hooks and the per-method `@allowGuest` rule run through the
|
|
6
|
+
* shared D5 pipeline.
|
|
7
|
+
*/
|
|
8
|
+
import { WardenError } from "../errors.js";
|
|
9
|
+
import { BasePolicy } from "./BasePolicy.js";
|
|
10
|
+
import { getActionMetadata } from "./decorators.js";
|
|
11
|
+
import { evaluate, isAction, throwAuthorizationFailure, } from "./evaluate.js";
|
|
12
|
+
import { emptyPermissions, setPolicyContext } from "./policyContext.js";
|
|
13
|
+
/**
|
|
14
|
+
* Resolve a named action method declared anywhere on the policy's own subclass
|
|
15
|
+
* chain (so an action inherited from an intermediate policy base class still
|
|
16
|
+
* dispatches). Rejects `constructor`, the `before`/`after` hooks, and any
|
|
17
|
+
* `BasePolicy`/`Object.prototype` member so a verb call can never dispatch to a
|
|
18
|
+
* non-action method — a guard the adversarial review specifically probes.
|
|
19
|
+
*/
|
|
20
|
+
function resolveActionMethod(policy, action) {
|
|
21
|
+
// Reject the hooks + constructor by name, then accept an action declared
|
|
22
|
+
// anywhere on the policy's own subclass chain — the immediate prototype up to
|
|
23
|
+
// (but not including) BasePolicy.prototype / Object.prototype — so a method
|
|
24
|
+
// inherited from an intermediate policy base class (`class A extends B`) still
|
|
25
|
+
// dispatches, while BasePolicy's own members (scope/permissions getters) and
|
|
26
|
+
// Object.prototype members stay unreachable.
|
|
27
|
+
const isHookOrCtor = action === "constructor" || action === "before" || action === "after";
|
|
28
|
+
let declaredHere = false;
|
|
29
|
+
for (let proto = Object.getPrototypeOf(policy); proto !== null &&
|
|
30
|
+
proto !== BasePolicy.prototype &&
|
|
31
|
+
proto !== Object.prototype; proto = Object.getPrototypeOf(proto)) {
|
|
32
|
+
if (Object.hasOwn(proto, action)) {
|
|
33
|
+
declaredHere = true;
|
|
34
|
+
break;
|
|
35
|
+
}
|
|
36
|
+
}
|
|
37
|
+
const candidate = Reflect.get(policy, action);
|
|
38
|
+
if (isHookOrCtor) {
|
|
39
|
+
declaredHere = false;
|
|
40
|
+
}
|
|
41
|
+
if (!declaredHere || !isAction(candidate)) {
|
|
42
|
+
throw new WardenError("UNKNOWN_POLICY_ACTION", `Policy "${policy.constructor.name}" has no action "${action}"`, { hint: "Declare the action as a method on the policy class." });
|
|
43
|
+
}
|
|
44
|
+
return candidate.bind(policy);
|
|
45
|
+
}
|
|
46
|
+
export class PolicyAuthorizer {
|
|
47
|
+
#user;
|
|
48
|
+
#factory;
|
|
49
|
+
#scope;
|
|
50
|
+
#resolvePermissions;
|
|
51
|
+
constructor(user, factory, scope = "global", resolvePermissions = () => Promise.resolve(emptyPermissions(scope))) {
|
|
52
|
+
this.#user = user;
|
|
53
|
+
this.#factory = factory;
|
|
54
|
+
this.#scope = scope;
|
|
55
|
+
this.#resolvePermissions = resolvePermissions;
|
|
56
|
+
}
|
|
57
|
+
/** Run a check and resolve to the full response (D8 — fresh policy per check). */
|
|
58
|
+
async execute(action, ...args) {
|
|
59
|
+
const policy = this.#factory();
|
|
60
|
+
// Attach the active scope + resolved permissions BEFORE dispatch so the
|
|
61
|
+
// before/method/after pipeline all read `this.scope` / `this.permissions`.
|
|
62
|
+
const permissions = await this.#resolvePermissions();
|
|
63
|
+
setPolicyContext(policy, { scope: this.#scope, permissions });
|
|
64
|
+
const method = resolveActionMethod(policy, action);
|
|
65
|
+
const options = getActionMetadata(policy, action);
|
|
66
|
+
return evaluate({
|
|
67
|
+
user: this.#user,
|
|
68
|
+
action,
|
|
69
|
+
allowGuest: options.allowGuest ?? false,
|
|
70
|
+
run: (user) => method(user, ...args),
|
|
71
|
+
args,
|
|
72
|
+
before: policy.before?.bind(policy),
|
|
73
|
+
after: policy.after?.bind(policy),
|
|
74
|
+
});
|
|
75
|
+
}
|
|
76
|
+
/** True iff the action is authorized. Never throws on denial. */
|
|
77
|
+
async allows(action, ...args) {
|
|
78
|
+
return (await this.execute(action, ...args)).authorized;
|
|
79
|
+
}
|
|
80
|
+
/** Boolean negation of {@link allows}. Never throws on denial. */
|
|
81
|
+
async denies(action, ...args) {
|
|
82
|
+
return !(await this.execute(action, ...args)).authorized;
|
|
83
|
+
}
|
|
84
|
+
/** Resolves on allow; throws `WARDEN_AUTHORIZATION_FAILURE` on deny (D2). */
|
|
85
|
+
async authorize(action, ...args) {
|
|
86
|
+
const response = await this.execute(action, ...args);
|
|
87
|
+
if (!response.authorized) {
|
|
88
|
+
throwAuthorizationFailure(response);
|
|
89
|
+
}
|
|
90
|
+
}
|
|
91
|
+
}
|
|
92
|
+
//# sourceMappingURL=PolicyAuthorizer.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"PolicyAuthorizer.js","sourceRoot":"","sources":["../../src/bouncer/PolicyAuthorizer.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,25 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Bouncer policy decorators — `@allowGuest()` / `@action()` mark policy methods
|
|
3
|
+
* that a guest (null user) may reach. Mirrors the `Guard.ts` idiom (D9):
|
|
4
|
+
* `reflect-metadata` side-effect import, a `Symbol.for` key, the legacy
|
|
5
|
+
* `MethodDecorator` signature, and a `getActionMetadata` reader.
|
|
6
|
+
*/
|
|
7
|
+
import "reflect-metadata";
|
|
8
|
+
import type { AbilityOptions } from "./types.js";
|
|
9
|
+
/**
|
|
10
|
+
* `@action({ allowGuest })` — configure a policy method's evaluation options.
|
|
11
|
+
*/
|
|
12
|
+
export declare function action(options: AbilityOptions): MethodDecorator;
|
|
13
|
+
/**
|
|
14
|
+
* `@allowGuest()` — let a guest (null user) reach this policy method.
|
|
15
|
+
* Equivalent to `@action({ allowGuest: true })`.
|
|
16
|
+
*/
|
|
17
|
+
export declare function allowGuest(): MethodDecorator;
|
|
18
|
+
/**
|
|
19
|
+
* Read a policy method's action metadata. Walks the prototype chain
|
|
20
|
+
* (`Reflect.getMetadata`) so it resolves from a policy INSTANCE — legacy
|
|
21
|
+
* decorators write metadata onto the class prototype, where the instance
|
|
22
|
+
* inherits it. Absent ⇒ `{}` (⇒ `allowGuest` falsy ⇒ guest denied).
|
|
23
|
+
*/
|
|
24
|
+
export declare function getActionMetadata(target: object, propertyKey: string | symbol): AbilityOptions;
|
|
25
|
+
//# sourceMappingURL=decorators.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"decorators.d.ts","sourceRoot":"","sources":["../../src/bouncer/decorators.ts"],"names":[],"mappings":"AAAA;;;;;GAKG;AAIH,OAAO,kBAAkB,CAAC;AAC1B,OAAO,KAAK,EAAE,cAAc,EAAE,MAAM,YAAY,CAAC;AAKjD;;GAEG;AACH,wBAAgB,MAAM,CAAC,OAAO,EAAE,cAAc,GAAG,eAAe,CAI/D;AAED;;;GAGG;AACH,wBAAgB,UAAU,IAAI,eAAe,CAE5C;AAED;;;;;GAKG;AACH,wBAAgB,iBAAiB,CAChC,MAAM,EAAE,MAAM,EACd,WAAW,EAAE,MAAM,GAAG,MAAM,GAC1B,cAAc,CAEhB"}
|