@astram/guard 0.18.0 → 0.20.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/audit/audit-chain-sealer.d.ts +90 -0
- package/dist/audit/audit-chain-sealer.d.ts.map +1 -0
- package/dist/audit/audit-chain-sealer.js +520 -0
- package/dist/audit/audit-seal-config.d.ts +22 -0
- package/dist/audit/audit-seal-config.d.ts.map +1 -0
- package/dist/audit/audit-seal-config.js +35 -0
- package/dist/audit/audit-sealer.service.d.ts +62 -0
- package/dist/audit/audit-sealer.service.d.ts.map +1 -0
- package/dist/audit/audit-sealer.service.js +197 -0
- package/dist/audit/node-sha256-hash.d.ts +6 -0
- package/dist/audit/node-sha256-hash.d.ts.map +1 -0
- package/dist/audit/node-sha256-hash.js +16 -0
- package/dist/auth/account.controller.d.ts +3 -1
- package/dist/auth/account.controller.d.ts.map +1 -1
- package/dist/auth/account.controller.js +79 -6
- package/dist/auth/admin-signin-controls.d.ts +80 -0
- package/dist/auth/admin-signin-controls.d.ts.map +1 -0
- package/dist/auth/admin-signin-controls.js +91 -0
- package/dist/auth/auth-audit.d.ts +59 -0
- package/dist/auth/auth-audit.d.ts.map +1 -0
- package/dist/auth/auth-audit.js +93 -0
- package/dist/auth/auth.controller.d.ts +53 -6
- package/dist/auth/auth.controller.d.ts.map +1 -1
- package/dist/auth/auth.controller.js +330 -44
- package/dist/auth/auth.module.d.ts +49 -0
- package/dist/auth/auth.module.d.ts.map +1 -1
- package/dist/auth/auth.module.js +149 -4
- package/dist/auth/captcha-gate.d.ts +103 -0
- package/dist/auth/captcha-gate.d.ts.map +1 -0
- package/dist/auth/captcha-gate.js +245 -0
- package/dist/auth/dto.d.ts +22 -1
- package/dist/auth/dto.d.ts.map +1 -1
- package/dist/auth/login-name-count-boot.d.ts +24 -0
- package/dist/auth/login-name-count-boot.d.ts.map +1 -0
- package/dist/auth/login-name-count-boot.js +47 -0
- package/dist/auth/logout-proof.d.ts +55 -0
- package/dist/auth/logout-proof.d.ts.map +1 -0
- package/dist/auth/logout-proof.js +127 -0
- package/dist/auth/pending-mfa-store.d.ts +5 -0
- package/dist/auth/pending-mfa-store.d.ts.map +1 -1
- package/dist/auth/pending-mfa-store.js +2 -0
- package/dist/auth/persistence.module.d.ts +2 -2
- package/dist/auth/persistence.module.d.ts.map +1 -1
- package/dist/auth/persistence.module.js +19 -3
- package/dist/auth/ports/audit-sink.d.ts +5 -2
- package/dist/auth/ports/audit-sink.d.ts.map +1 -1
- package/dist/auth/ports/mfa-device-store.d.ts +7 -0
- package/dist/auth/ports/mfa-device-store.d.ts.map +1 -1
- package/dist/auth/profile-resolver.d.ts +6 -0
- package/dist/auth/profile-resolver.d.ts.map +1 -1
- package/dist/auth/rate-limit/attempt-limiter.d.ts +6 -0
- package/dist/auth/rate-limit/attempt-limiter.d.ts.map +1 -1
- package/dist/auth/rate-limit/attempt-limiter.js +14 -0
- package/dist/auth/tokens.d.ts +59 -0
- package/dist/auth/tokens.d.ts.map +1 -1
- package/dist/auth/tokens.js +61 -1
- package/dist/authentication/credential-provisioner.d.ts +7 -0
- package/dist/authentication/credential-provisioner.d.ts.map +1 -1
- package/dist/authentication/mariadb-credential-provisioner.d.ts +1 -0
- package/dist/authentication/mariadb-credential-provisioner.d.ts.map +1 -1
- package/dist/authentication/mariadb-credential-provisioner.js +7 -0
- package/dist/authentication/mariadb-credential-resolver.d.ts +23 -2
- package/dist/authentication/mariadb-credential-resolver.d.ts.map +1 -1
- package/dist/authentication/mariadb-credential-resolver.js +45 -1
- package/dist/authentication/mariadb-mfa-device-store.d.ts +7 -0
- package/dist/authentication/mariadb-mfa-device-store.d.ts.map +1 -1
- package/dist/authentication/mariadb-mfa-device-store.js +32 -0
- package/dist/authentication/mariadb-mfa-requirement-source.d.ts +55 -0
- package/dist/authentication/mariadb-mfa-requirement-source.d.ts.map +1 -0
- package/dist/authentication/mariadb-mfa-requirement-source.js +164 -0
- package/dist/authentication/mariadb-mfa-resetter.d.ts +42 -0
- package/dist/authentication/mariadb-mfa-resetter.d.ts.map +1 -0
- package/dist/authentication/mariadb-mfa-resetter.js +59 -0
- package/dist/authentication/mariadb-profile-writer.d.ts.map +1 -1
- package/dist/authentication/mariadb-profile-writer.js +5 -0
- package/dist/authentication/sign-in-with.d.ts +14 -0
- package/dist/authentication/sign-in-with.d.ts.map +1 -0
- package/dist/authentication/sign-in-with.js +36 -0
- package/dist/authz/core-access.d.ts +11 -0
- package/dist/authz/core-access.d.ts.map +1 -0
- package/dist/authz/core-access.js +14 -0
- package/dist/authz/list-scope-sql.d.ts.map +1 -1
- package/dist/authz/list-scope-sql.js +15 -5
- package/dist/authz/wire-record-authorization.d.ts.map +1 -1
- package/dist/authz/wire-record-authorization.js +21 -3
- package/dist/captcha/captcha.providers.d.ts +18 -0
- package/dist/captcha/captcha.providers.d.ts.map +1 -0
- package/dist/captcha/captcha.providers.js +78 -0
- package/dist/captcha/recaptcha-verifier.d.ts +20 -0
- package/dist/captcha/recaptcha-verifier.d.ts.map +1 -0
- package/dist/captcha/recaptcha-verifier.js +48 -0
- package/dist/captcha/siteverify.d.ts +47 -0
- package/dist/captcha/siteverify.d.ts.map +1 -0
- package/dist/captcha/siteverify.js +98 -0
- package/dist/captcha/turnstile-verifier.d.ts +18 -0
- package/dist/captcha/turnstile-verifier.d.ts.map +1 -0
- package/dist/captcha/turnstile-verifier.js +41 -0
- package/dist/config/captcha-config.d.ts +47 -0
- package/dist/config/captcha-config.d.ts.map +1 -0
- package/dist/config/captcha-config.js +163 -0
- package/dist/config/reserved-principal-ids.d.ts +15 -0
- package/dist/config/reserved-principal-ids.d.ts.map +1 -1
- package/dist/config/reserved-principal-ids.js +20 -3
- package/dist/enforcement/global-enforcement.guard.d.ts +9 -1
- package/dist/enforcement/global-enforcement.guard.d.ts.map +1 -1
- package/dist/enforcement/global-enforcement.guard.js +52 -10
- package/dist/enforcement/reenroll-allowlist.d.ts +5 -0
- package/dist/enforcement/reenroll-allowlist.d.ts.map +1 -1
- package/dist/enforcement/reenroll-allowlist.js +5 -0
- package/dist/identity/auth-facts.controller.d.ts +31 -4
- package/dist/identity/auth-facts.controller.d.ts.map +1 -1
- package/dist/identity/auth-facts.controller.js +46 -11
- package/dist/identity/identity-actions.d.ts +2 -2
- package/dist/identity/identity-actions.d.ts.map +1 -1
- package/dist/identity/module-registry.bridge.d.ts.map +1 -1
- package/dist/identity/module-registry.bridge.js +3 -6
- package/dist/identity/permission-facts.adapter.d.ts +22 -0
- package/dist/identity/permission-facts.adapter.d.ts.map +1 -1
- package/dist/identity/permission-facts.adapter.js +26 -1
- package/dist/index.d.ts +11 -2
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +43 -11
- package/dist/internal.d.ts +27 -0
- package/dist/internal.d.ts.map +1 -1
- package/dist/internal.js +36 -1
- package/dist/module/shield.module.d.ts +27 -0
- package/dist/module/shield.module.d.ts.map +1 -1
- package/dist/module/shield.module.js +10 -0
- package/dist/request-auth/request-principal.d.ts +8 -1
- package/dist/request-auth/request-principal.d.ts.map +1 -1
- package/dist/request-auth/request-principal.js +11 -4
- package/dist/request-auth/session-token-binder.d.ts +82 -0
- package/dist/request-auth/session-token-binder.d.ts.map +1 -1
- package/dist/request-auth/session-token-binder.js +203 -1
- package/dist/session/mfa-requirement-service.d.ts +168 -0
- package/dist/session/mfa-requirement-service.d.ts.map +1 -0
- package/dist/session/mfa-requirement-service.js +461 -0
- package/dist/session/session-restriction-store.d.ts +36 -0
- package/dist/session/session-restriction-store.d.ts.map +1 -1
- package/dist/session/session-restriction-store.js +57 -6
- package/dist/session/session-restriction.d.ts +22 -0
- package/dist/session/session-restriction.d.ts.map +1 -0
- package/dist/session/session-restriction.js +23 -0
- package/package.json +10 -5
|
@@ -0,0 +1,91 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.RedisAccountUnlocker = exports.TotpAdminStepUp = exports.AdminControlUnavailableError = void 0;
|
|
4
|
+
exports.accountUnlockKeys = accountUnlockKeys;
|
|
5
|
+
const captcha_config_js_1 = require("../config/captcha-config.js");
|
|
6
|
+
/** A store the admin control needs could not answer; nothing is claimed (caller → 503). */
|
|
7
|
+
class AdminControlUnavailableError extends Error {
|
|
8
|
+
constructor() {
|
|
9
|
+
super('admin sign-in control unavailable');
|
|
10
|
+
this.name = 'AdminControlUnavailableError';
|
|
11
|
+
}
|
|
12
|
+
}
|
|
13
|
+
exports.AdminControlUnavailableError = AdminControlUnavailableError;
|
|
14
|
+
class TotpAdminStepUp {
|
|
15
|
+
deps;
|
|
16
|
+
constructor(deps) {
|
|
17
|
+
this.deps = deps;
|
|
18
|
+
}
|
|
19
|
+
async verify(principalId, code) {
|
|
20
|
+
const { devices, verifier, limiter } = this.deps;
|
|
21
|
+
if (!devices || !verifier || !limiter || !principalId)
|
|
22
|
+
return 'unavailable';
|
|
23
|
+
let secrets;
|
|
24
|
+
try {
|
|
25
|
+
secrets = await devices.listConfirmedSecrets(principalId);
|
|
26
|
+
}
|
|
27
|
+
catch {
|
|
28
|
+
return 'unavailable';
|
|
29
|
+
}
|
|
30
|
+
if (!Array.isArray(secrets) || secrets.length === 0)
|
|
31
|
+
return 'no_factor';
|
|
32
|
+
const presented = typeof code === 'string' ? code.trim() : '';
|
|
33
|
+
if (presented === '')
|
|
34
|
+
return 'missing';
|
|
35
|
+
const key = `mfa:pid:${principalId}`;
|
|
36
|
+
let allowed;
|
|
37
|
+
try {
|
|
38
|
+
({ allowed } = await limiter.consume(key));
|
|
39
|
+
}
|
|
40
|
+
catch {
|
|
41
|
+
return 'unavailable';
|
|
42
|
+
}
|
|
43
|
+
if (!allowed)
|
|
44
|
+
return 'locked';
|
|
45
|
+
let satisfied;
|
|
46
|
+
try {
|
|
47
|
+
satisfied = (await verifier.verify({ factor: 'totp', payload: { code: presented } }, secrets.join('\n')))?.satisfied;
|
|
48
|
+
}
|
|
49
|
+
catch {
|
|
50
|
+
// No verdict (replay guard / Redis down): give the attempt back, fail closed.
|
|
51
|
+
await limiter.refund(key);
|
|
52
|
+
return 'unavailable';
|
|
53
|
+
}
|
|
54
|
+
if (satisfied !== true)
|
|
55
|
+
return 'rejected';
|
|
56
|
+
await limiter.reset(key);
|
|
57
|
+
return 'verified';
|
|
58
|
+
}
|
|
59
|
+
}
|
|
60
|
+
exports.TotpAdminStepUp = TotpAdminStepUp;
|
|
61
|
+
/** The keys one unlock clears (limiter keys without the `shield:attempts:` namespace). */
|
|
62
|
+
function accountUnlockKeys(principalId) {
|
|
63
|
+
return {
|
|
64
|
+
login: `login:pid:${principalId}`,
|
|
65
|
+
mfa: `mfa:pid:${principalId}`,
|
|
66
|
+
recovery: `recovery:${principalId}`,
|
|
67
|
+
captcha: captcha_config_js_1.CAPTCHA_ENDPOINTS.map((ep) => `${ep}:pid:${principalId}`),
|
|
68
|
+
};
|
|
69
|
+
}
|
|
70
|
+
class RedisAccountUnlocker {
|
|
71
|
+
deps;
|
|
72
|
+
constructor(deps) {
|
|
73
|
+
this.deps = deps;
|
|
74
|
+
}
|
|
75
|
+
async unlock(principalId) {
|
|
76
|
+
if (typeof principalId !== 'string' || principalId === '') {
|
|
77
|
+
throw new AdminControlUnavailableError();
|
|
78
|
+
}
|
|
79
|
+
const keys = accountUnlockKeys(principalId);
|
|
80
|
+
try {
|
|
81
|
+
await this.deps.login.clear(keys.login);
|
|
82
|
+
await this.deps.mfa.clear(keys.mfa);
|
|
83
|
+
await this.deps.recovery.clear(keys.recovery);
|
|
84
|
+
await this.deps.captcha.clearStrict(keys.captcha);
|
|
85
|
+
}
|
|
86
|
+
catch {
|
|
87
|
+
throw new AdminControlUnavailableError();
|
|
88
|
+
}
|
|
89
|
+
}
|
|
90
|
+
}
|
|
91
|
+
exports.RedisAccountUnlocker = RedisAccountUnlocker;
|
|
@@ -0,0 +1,59 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Auth audit events and counters (R12.2–R12.4, AC-18).
|
|
3
|
+
*
|
|
4
|
+
* Events (through the auth {@link AuditSink}, fire-and-forget, errors swallowed):
|
|
5
|
+
* - `auth.login.succeeded` / `auth.login.failed` (`authentication`), attribute `method`:
|
|
6
|
+
* `password`, or the MFA step's `totp` / `recovery_code`.
|
|
7
|
+
* - `auth.logout` (`session_lifecycle`), attribute `proven`.
|
|
8
|
+
* - `auth.mfa.enrolled` / `auth.mfa.removed` (`authentication`).
|
|
9
|
+
*
|
|
10
|
+
* Actor and tenant always come from the RESOLVED principal or session, never from the request.
|
|
11
|
+
* No event carries the typed hint, a password, a code or a token.
|
|
12
|
+
*
|
|
13
|
+
* Bounding (R12.3): a failure row is written only for a resolved account, and only by the attempt
|
|
14
|
+
* that OPENS the account's limiter window ({@link opensFailureWindow}: the increment-first count is
|
|
15
|
+
* 1). The limiter's counter is atomic (Lua `INCR`), so of N parallel failures exactly one sees 1,
|
|
16
|
+
* and the window is fixed (not extended by later attempts), so an account yields at most one
|
|
17
|
+
* failure row per lockout window, plus the existing lockout row on the edge. No extra Redis key and
|
|
18
|
+
* no extra round trip; with no limiter there is no window and no failure row. Unknown names write
|
|
19
|
+
* no row at all; they only count.
|
|
20
|
+
*
|
|
21
|
+
* Counters (R12.4): one structured log line per occurrence with fixed keys and no personal data,
|
|
22
|
+
* the style of `recordUnprovenLogout` (`logout-proof.ts`):
|
|
23
|
+
* - `{ counter: 'auth.login.failed', method, account: 'known' | 'unknown' }`
|
|
24
|
+
* - `{ counter: 'auth.lockout', method, account: 'known' | 'unknown' | 'ip' }`
|
|
25
|
+
*/
|
|
26
|
+
import { Logger } from '@nestjs/common';
|
|
27
|
+
import type { AuditSink, AuthAuditEvent } from './ports/audit-sink.js';
|
|
28
|
+
/** The sign-in factor an event or counter refers to. */
|
|
29
|
+
export type AuthMethod = 'password' | 'totp' | 'recovery_code';
|
|
30
|
+
/** Whether the failing name resolved to an account (`ip` = the per-IP lockout, no account). */
|
|
31
|
+
export type AccountLabel = 'known' | 'unknown' | 'ip';
|
|
32
|
+
export declare const AUTH_LOGIN_SUCCEEDED = "auth.login.succeeded";
|
|
33
|
+
export declare const AUTH_LOGIN_FAILED = "auth.login.failed";
|
|
34
|
+
export declare const AUTH_LOGOUT = "auth.logout";
|
|
35
|
+
export declare const AUTH_MFA_ENROLLED = "auth.mfa.enrolled";
|
|
36
|
+
export declare const AUTH_MFA_REMOVED = "auth.mfa.removed";
|
|
37
|
+
/** Counter keys (R12.4). */
|
|
38
|
+
export declare const LOGIN_FAILED_COUNTER = "auth.login.failed";
|
|
39
|
+
export declare const LOCKOUT_COUNTER = "auth.lockout";
|
|
40
|
+
/** Record one event, fire-and-forget. A missing sink is a no-op; a sink error never propagates. */
|
|
41
|
+
export declare function emitAuthAudit(sink: AuditSink | null | undefined, event: AuthAuditEvent): void;
|
|
42
|
+
/** An `authentication` event about `actorId` in `tenantId`. */
|
|
43
|
+
export declare function authEvent(action: string, actorId: string, tenantId: string, attributes: Record<string, unknown>, nowMs?: number): AuthAuditEvent;
|
|
44
|
+
/** The `auth.logout` event (`session_lifecycle`) for a revoked session. */
|
|
45
|
+
export declare function logoutEvent(actorId: string, tenantId: string, proven: boolean, nowMs?: number): AuthAuditEvent;
|
|
46
|
+
/**
|
|
47
|
+
* True when this failed attempt opened the account's limiter window (its increment-first count
|
|
48
|
+
* is 1), so it may write the window's one `auth.login.failed` row. `null` (no limiter) → false.
|
|
49
|
+
*/
|
|
50
|
+
export declare function opensFailureWindow(verdict: {
|
|
51
|
+
count: number;
|
|
52
|
+
} | null | undefined): boolean;
|
|
53
|
+
/** Count one failed sign-in (R12.4). */
|
|
54
|
+
export declare function countLoginFailure(method: AuthMethod, account: 'known' | 'unknown', logger?: Pick<Logger, 'log'>): void;
|
|
55
|
+
/** Count one lockout (the edge where a limiter trips; R12.4). */
|
|
56
|
+
export declare function countLockout(method: AuthMethod, account: AccountLabel, logger?: Pick<Logger, 'log'>): void;
|
|
57
|
+
/** The tenant id in resolved credential claims, or `null`. */
|
|
58
|
+
export declare function tenantOfClaims(claims: unknown): string | null;
|
|
59
|
+
//# sourceMappingURL=auth-audit.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"auth-audit.d.ts","sourceRoot":"","sources":["../../src/auth/auth-audit.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;;GAwBG;AAEH,OAAO,EAAE,MAAM,EAAE,MAAM,gBAAgB,CAAC;AACxC,OAAO,KAAK,EAAE,SAAS,EAAE,cAAc,EAAE,MAAM,uBAAuB,CAAC;AAEvE,wDAAwD;AACxD,MAAM,MAAM,UAAU,GAAG,UAAU,GAAG,MAAM,GAAG,eAAe,CAAC;AAE/D,+FAA+F;AAC/F,MAAM,MAAM,YAAY,GAAG,OAAO,GAAG,SAAS,GAAG,IAAI,CAAC;AAEtD,eAAO,MAAM,oBAAoB,yBAAyB,CAAC;AAC3D,eAAO,MAAM,iBAAiB,sBAAsB,CAAC;AACrD,eAAO,MAAM,WAAW,gBAAgB,CAAC;AACzC,eAAO,MAAM,iBAAiB,sBAAsB,CAAC;AACrD,eAAO,MAAM,gBAAgB,qBAAqB,CAAC;AAEnD,4BAA4B;AAC5B,eAAO,MAAM,oBAAoB,sBAAsB,CAAC;AACxD,eAAO,MAAM,eAAe,iBAAiB,CAAC;AAI9C,mGAAmG;AACnG,wBAAgB,aAAa,CAAC,IAAI,EAAE,SAAS,GAAG,IAAI,GAAG,SAAS,EAAE,KAAK,EAAE,cAAc,GAAG,IAAI,CAS7F;AAED,+DAA+D;AAC/D,wBAAgB,SAAS,CACvB,MAAM,EAAE,MAAM,EACd,OAAO,EAAE,MAAM,EACf,QAAQ,EAAE,MAAM,EAChB,UAAU,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,EACnC,KAAK,GAAE,MAAmB,GACzB,cAAc,CAEhB;AAED,2EAA2E;AAC3E,wBAAgB,WAAW,CACzB,OAAO,EAAE,MAAM,EACf,QAAQ,EAAE,MAAM,EAChB,MAAM,EAAE,OAAO,EACf,KAAK,GAAE,MAAmB,GACzB,cAAc,CAShB;AAED;;;GAGG;AACH,wBAAgB,kBAAkB,CAAC,OAAO,EAAE;IAAE,KAAK,EAAE,MAAM,CAAA;CAAE,GAAG,IAAI,GAAG,SAAS,GAAG,OAAO,CAEzF;AAED,wCAAwC;AACxC,wBAAgB,iBAAiB,CAC/B,MAAM,EAAE,UAAU,EAClB,OAAO,EAAE,OAAO,GAAG,SAAS,EAC5B,MAAM,GAAE,IAAI,CAAC,MAAM,EAAE,KAAK,CAAiB,GAC1C,IAAI,CAEN;AAED,iEAAiE;AACjE,wBAAgB,YAAY,CAC1B,MAAM,EAAE,UAAU,EAClB,OAAO,EAAE,YAAY,EACrB,MAAM,GAAE,IAAI,CAAC,MAAM,EAAE,KAAK,CAAiB,GAC1C,IAAI,CAEN;AAED,8DAA8D;AAC9D,wBAAgB,cAAc,CAAC,MAAM,EAAE,OAAO,GAAG,MAAM,GAAG,IAAI,CAG7D"}
|
|
@@ -0,0 +1,93 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
/**
|
|
3
|
+
* Auth audit events and counters (R12.2–R12.4, AC-18).
|
|
4
|
+
*
|
|
5
|
+
* Events (through the auth {@link AuditSink}, fire-and-forget, errors swallowed):
|
|
6
|
+
* - `auth.login.succeeded` / `auth.login.failed` (`authentication`), attribute `method`:
|
|
7
|
+
* `password`, or the MFA step's `totp` / `recovery_code`.
|
|
8
|
+
* - `auth.logout` (`session_lifecycle`), attribute `proven`.
|
|
9
|
+
* - `auth.mfa.enrolled` / `auth.mfa.removed` (`authentication`).
|
|
10
|
+
*
|
|
11
|
+
* Actor and tenant always come from the RESOLVED principal or session, never from the request.
|
|
12
|
+
* No event carries the typed hint, a password, a code or a token.
|
|
13
|
+
*
|
|
14
|
+
* Bounding (R12.3): a failure row is written only for a resolved account, and only by the attempt
|
|
15
|
+
* that OPENS the account's limiter window ({@link opensFailureWindow}: the increment-first count is
|
|
16
|
+
* 1). The limiter's counter is atomic (Lua `INCR`), so of N parallel failures exactly one sees 1,
|
|
17
|
+
* and the window is fixed (not extended by later attempts), so an account yields at most one
|
|
18
|
+
* failure row per lockout window, plus the existing lockout row on the edge. No extra Redis key and
|
|
19
|
+
* no extra round trip; with no limiter there is no window and no failure row. Unknown names write
|
|
20
|
+
* no row at all; they only count.
|
|
21
|
+
*
|
|
22
|
+
* Counters (R12.4): one structured log line per occurrence with fixed keys and no personal data,
|
|
23
|
+
* the style of `recordUnprovenLogout` (`logout-proof.ts`):
|
|
24
|
+
* - `{ counter: 'auth.login.failed', method, account: 'known' | 'unknown' }`
|
|
25
|
+
* - `{ counter: 'auth.lockout', method, account: 'known' | 'unknown' | 'ip' }`
|
|
26
|
+
*/
|
|
27
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
28
|
+
exports.LOCKOUT_COUNTER = exports.LOGIN_FAILED_COUNTER = exports.AUTH_MFA_REMOVED = exports.AUTH_MFA_ENROLLED = exports.AUTH_LOGOUT = exports.AUTH_LOGIN_FAILED = exports.AUTH_LOGIN_SUCCEEDED = void 0;
|
|
29
|
+
exports.emitAuthAudit = emitAuthAudit;
|
|
30
|
+
exports.authEvent = authEvent;
|
|
31
|
+
exports.logoutEvent = logoutEvent;
|
|
32
|
+
exports.opensFailureWindow = opensFailureWindow;
|
|
33
|
+
exports.countLoginFailure = countLoginFailure;
|
|
34
|
+
exports.countLockout = countLockout;
|
|
35
|
+
exports.tenantOfClaims = tenantOfClaims;
|
|
36
|
+
const common_1 = require("@nestjs/common");
|
|
37
|
+
exports.AUTH_LOGIN_SUCCEEDED = 'auth.login.succeeded';
|
|
38
|
+
exports.AUTH_LOGIN_FAILED = 'auth.login.failed';
|
|
39
|
+
exports.AUTH_LOGOUT = 'auth.logout';
|
|
40
|
+
exports.AUTH_MFA_ENROLLED = 'auth.mfa.enrolled';
|
|
41
|
+
exports.AUTH_MFA_REMOVED = 'auth.mfa.removed';
|
|
42
|
+
/** Counter keys (R12.4). */
|
|
43
|
+
exports.LOGIN_FAILED_COUNTER = 'auth.login.failed';
|
|
44
|
+
exports.LOCKOUT_COUNTER = 'auth.lockout';
|
|
45
|
+
const counterLogger = new common_1.Logger('ShieldAuth');
|
|
46
|
+
/** Record one event, fire-and-forget. A missing sink is a no-op; a sink error never propagates. */
|
|
47
|
+
function emitAuthAudit(sink, event) {
|
|
48
|
+
if (sink === undefined || sink === null)
|
|
49
|
+
return;
|
|
50
|
+
try {
|
|
51
|
+
void sink.record(event).catch(() => {
|
|
52
|
+
/* best-effort: an audit failure never changes the response */
|
|
53
|
+
});
|
|
54
|
+
}
|
|
55
|
+
catch {
|
|
56
|
+
/* a synchronous throw from a consumer sink is swallowed too */
|
|
57
|
+
}
|
|
58
|
+
}
|
|
59
|
+
/** An `authentication` event about `actorId` in `tenantId`. */
|
|
60
|
+
function authEvent(action, actorId, tenantId, attributes, nowMs = Date.now()) {
|
|
61
|
+
return { type: 'authentication', occurredAtMs: nowMs, actorId, tenantId, action, attributes };
|
|
62
|
+
}
|
|
63
|
+
/** The `auth.logout` event (`session_lifecycle`) for a revoked session. */
|
|
64
|
+
function logoutEvent(actorId, tenantId, proven, nowMs = Date.now()) {
|
|
65
|
+
return {
|
|
66
|
+
type: 'session_lifecycle',
|
|
67
|
+
occurredAtMs: nowMs,
|
|
68
|
+
actorId,
|
|
69
|
+
tenantId,
|
|
70
|
+
action: exports.AUTH_LOGOUT,
|
|
71
|
+
attributes: { proven },
|
|
72
|
+
};
|
|
73
|
+
}
|
|
74
|
+
/**
|
|
75
|
+
* True when this failed attempt opened the account's limiter window (its increment-first count
|
|
76
|
+
* is 1), so it may write the window's one `auth.login.failed` row. `null` (no limiter) → false.
|
|
77
|
+
*/
|
|
78
|
+
function opensFailureWindow(verdict) {
|
|
79
|
+
return verdict !== null && verdict !== undefined && verdict.count === 1;
|
|
80
|
+
}
|
|
81
|
+
/** Count one failed sign-in (R12.4). */
|
|
82
|
+
function countLoginFailure(method, account, logger = counterLogger) {
|
|
83
|
+
logger.log({ counter: exports.LOGIN_FAILED_COUNTER, method, account });
|
|
84
|
+
}
|
|
85
|
+
/** Count one lockout (the edge where a limiter trips; R12.4). */
|
|
86
|
+
function countLockout(method, account, logger = counterLogger) {
|
|
87
|
+
logger.log({ counter: exports.LOCKOUT_COUNTER, method, account });
|
|
88
|
+
}
|
|
89
|
+
/** The tenant id in resolved credential claims, or `null`. */
|
|
90
|
+
function tenantOfClaims(claims) {
|
|
91
|
+
const t = claims?.tenantId;
|
|
92
|
+
return typeof t === 'string' && t !== '' ? t : null;
|
|
93
|
+
}
|
|
@@ -65,6 +65,10 @@ import type { AttemptLimiter } from './rate-limit/attempt-limiter.js';
|
|
|
65
65
|
import { TrustProxyBootCheck } from './rate-limit/trust-proxy-check.js';
|
|
66
66
|
import { PendingMfaStore } from './pending-mfa-store.js';
|
|
67
67
|
import { type SessionTokenBinder } from '../request-auth/session-token-binder.js';
|
|
68
|
+
import type { CaptchaGate } from './captcha-gate.js';
|
|
69
|
+
import type { SignInMethod } from '../authentication/sign-in-with.js';
|
|
70
|
+
import type { MfaRequirementService } from '../session/mfa-requirement-service.js';
|
|
71
|
+
import { type LogoutProofVerifier } from './logout-proof.js';
|
|
68
72
|
import type { CurrentUserProfile, ProfileResolver } from './profile-resolver.js';
|
|
69
73
|
import type { CredentialResolver } from '@astram/core';
|
|
70
74
|
import type { ResetTokenStore } from './ports/reset-token-store.js';
|
|
@@ -75,7 +79,7 @@ import type { SessionSweeper } from './ports/session-sweeper.js';
|
|
|
75
79
|
import type { RecoveryCodeStore } from './ports/recovery-code-store.js';
|
|
76
80
|
import type { AuditSink } from './ports/audit-sink.js';
|
|
77
81
|
import type { MariaDbPermissionFactsAdapter } from '../identity/permission-facts.adapter.js';
|
|
78
|
-
import type { LoginRequest, LoginResponse, LogoutRequest, MfaRequest, RefreshRequest, SessionSuccess } from './dto.js';
|
|
82
|
+
import type { LoginOptionsView, LoginRequest, LoginResponse, LogoutRequest, MfaRequest, RefreshRequest, SessionSuccess } from './dto.js';
|
|
79
83
|
/**
|
|
80
84
|
* The framework-owned auth endpoints. Registered into `AuthModule`'s `controllers`
|
|
81
85
|
* by the integration owner / Team B (this controller is EXPORTED for that purpose;
|
|
@@ -117,7 +121,19 @@ export declare class AuthController {
|
|
|
117
121
|
private readonly sessionRestrictions?;
|
|
118
122
|
private readonly emailChangeTokens?;
|
|
119
123
|
private readonly messageDispatcher?;
|
|
120
|
-
|
|
124
|
+
private readonly logoutProof?;
|
|
125
|
+
private readonly logoutRequiresProof?;
|
|
126
|
+
private readonly mfaRequirement?;
|
|
127
|
+
private readonly captchaGate?;
|
|
128
|
+
private readonly signInWith?;
|
|
129
|
+
constructor(authenticator: Authenticator, sessionAuthority: SessionAuthority, pendingMfa: PendingMfaStore, tokenBinder?: SessionTokenBinder | undefined, profileResolver?: ProfileResolver | undefined, credentialResolver?: (CredentialResolver | null) | undefined, resetTokenStore?: (ResetTokenStore | null) | undefined, emailSender?: (EmailSender | null) | undefined, credentialWriter?: (CredentialWriter | null) | undefined, sessionSweeper?: (SessionSweeper | null) | undefined, passwordHasher?: PasswordHasher | undefined, resetLinkBaseUrl?: string | undefined, recoveryCodes?: (RecoveryCodeStore | null) | undefined, loginLimiter?: (AttemptLimiter | null) | undefined, loginIpLimiter?: (AttemptLimiter | null) | undefined, trustProxyCheck?: (TrustProxyBootCheck | null) | undefined, recoveryLimiter?: (AttemptLimiter | null) | undefined, forgotLimiter?: (AttemptLimiter | null) | undefined, forgotHintLimiter?: (AttemptLimiter | null) | undefined, resetLimiter?: (AttemptLimiter | null) | undefined, auditSink?: (AuditSink | null) | undefined, sessionFactsProjector?: (SessionFactsProjector | null) | undefined, scopeSubtreeResolver?: (ScopeSubtreeResolver | null) | undefined, membershipChecker?: (MembershipChecker | null) | undefined, permissionFacts?: (MariaDbPermissionFactsAdapter | null) | undefined, mfaLimiter?: (AttemptLimiter | null) | undefined, mfaStepUp?: (MfaStepUp | null) | undefined, clock?: (Clock | null) | undefined, lifetimes?: (SessionLifetimeConfig | null) | undefined, rootIds?: (readonly string[] | null) | undefined, sessionRecords?: (Pick<SessionRecordStore, "findSessionById"> | null) | undefined, sessionRestrictions?: (SessionRestrictionStore | null) | undefined, emailChangeTokens?: (EmailChangeTokenStore | null) | undefined, messageDispatcher?: (MessageDispatcher | null) | undefined, logoutProof?: (LogoutProofVerifier | null) | undefined, logoutRequiresProof?: boolean | null | undefined, mfaRequirement?: (MfaRequirementService | null) | undefined, captchaGate?: (CaptchaGate | null) | undefined, signInWith?: (readonly SignInMethod[] | null) | undefined);
|
|
130
|
+
/** True when bootstrap confirmed an explicit `trust proxy` (per-IP limits and CAPTCHA IP keys). */
|
|
131
|
+
private perIpEnabled;
|
|
132
|
+
/**
|
|
133
|
+
* R7.3: count one failure toward the CAPTCHA counters and say whether the next attempt needs a
|
|
134
|
+
* challenge. No gate (or endpoint not covered) ⇒ `false`.
|
|
135
|
+
*/
|
|
136
|
+
private captchaAfterFailure;
|
|
121
137
|
/**
|
|
122
138
|
* The access-token binding TTL for an establishment (security hardening #8):
|
|
123
139
|
* `clamp(session.expiresAtMs − now, 1, accessTtlMs)` — on login AND refresh. Never derived
|
|
@@ -132,6 +148,13 @@ export declare class AuthController {
|
|
|
132
148
|
* gets valid tokens); the guard fails closed if the binding is absent.
|
|
133
149
|
*/
|
|
134
150
|
private bindSession;
|
|
151
|
+
/**
|
|
152
|
+
* The mandatory-2FA state to bind at sign-in (R2.3, R2.4), or `undefined` when the policy feature
|
|
153
|
+
* is not wired. `'required'` is also marked on the durable session BEFORE any token leaves, so a
|
|
154
|
+
* binding rebuilt after a Redis loss stays restricted. Any failure revokes the session and
|
|
155
|
+
* answers the generic 503 (fail closed).
|
|
156
|
+
*/
|
|
157
|
+
private evaluateMfaAtLogin;
|
|
135
158
|
/**
|
|
136
159
|
* Project coarse grants for a principal id + tenant (ADR-0011), distinguishing THREE
|
|
137
160
|
* outcomes for the REFRESH path (which must know whether to carry the existing cache
|
|
@@ -239,6 +262,13 @@ export declare class AuthController {
|
|
|
239
262
|
* outage. NEVER logs the request body.
|
|
240
263
|
*/
|
|
241
264
|
login(body: LoginRequest, ip: string): Promise<LoginResponse>;
|
|
265
|
+
/**
|
|
266
|
+
* `GET /auth/login-options` (auth capabilities R7.3, R13.2, AC-23) — what the sign-in page needs
|
|
267
|
+
* before a session exists: the accepted sign-in forms and the public CAPTCHA settings
|
|
268
|
+
* (`{ provider, siteKey, mode }`, or `null` when CAPTCHA is off). Never the secret. `@Public()`:
|
|
269
|
+
* pre-session, reveals nothing about any account.
|
|
270
|
+
*/
|
|
271
|
+
loginOptions(): LoginOptionsView;
|
|
242
272
|
/**
|
|
243
273
|
* `GET /auth/me` — the signed-in user's **display profile** (name, email, active
|
|
244
274
|
* company name, role names) for the UI header/card. Fills the flagged gap: login
|
|
@@ -318,6 +348,7 @@ export declare class AuthController {
|
|
|
318
348
|
*/
|
|
319
349
|
forgotPassword(body: {
|
|
320
350
|
identityHint?: string;
|
|
351
|
+
captchaToken?: string;
|
|
321
352
|
}, ip: string): Promise<void>;
|
|
322
353
|
/**
|
|
323
354
|
* The detached per-account half of {@link forgotPassword} (review F1):
|
|
@@ -358,6 +389,7 @@ export declare class AuthController {
|
|
|
358
389
|
resetPassword(body: {
|
|
359
390
|
token?: string;
|
|
360
391
|
newPassword?: string;
|
|
392
|
+
captchaToken?: string;
|
|
361
393
|
}, ip: string): Promise<void>;
|
|
362
394
|
/**
|
|
363
395
|
* `POST /auth/mfa` — complete a pending MFA login. Consumes the single-use
|
|
@@ -420,6 +452,15 @@ export declare class AuthController {
|
|
|
420
452
|
* the neutral notice the account owner needs to act on it.
|
|
421
453
|
*/
|
|
422
454
|
private notifyRecoveryUsed;
|
|
455
|
+
/** R12.2: `auth.login.succeeded` for an established session (fire-and-forget). */
|
|
456
|
+
private auditSignIn;
|
|
457
|
+
/** R12.2/R12.3: `auth.login.failed` for a RESOLVED account (the caller bounds it per window). */
|
|
458
|
+
private auditFailure;
|
|
459
|
+
/**
|
|
460
|
+
* The durable session `logout` is about to end, when it is ACTIVE and a sink is bound; else
|
|
461
|
+
* `null` (no row). A store error → `null` (the logout itself is unaffected).
|
|
462
|
+
*/
|
|
463
|
+
private activeSessionForAudit;
|
|
423
464
|
/**
|
|
424
465
|
* Record an auth-SECURITY event (best-effort, fire-and-forget) and OPTIONALLY notify
|
|
425
466
|
* the account owner. The REUSABLE audit+notify primitive (feature #140) — it
|
|
@@ -505,11 +546,17 @@ export declare class AuthController {
|
|
|
505
546
|
*/
|
|
506
547
|
private rebuildBinding;
|
|
507
548
|
/**
|
|
508
|
-
* `POST /auth/logout` — revoke the session
|
|
509
|
-
*
|
|
510
|
-
*
|
|
549
|
+
* `POST /auth/logout` — revoke the session the caller proves it owns (R15.1, D-9).
|
|
550
|
+
* Proof is a bearer access token bound to `sessionId` or a refresh token of it
|
|
551
|
+
* ({@link LogoutProofVerifier}):
|
|
552
|
+
* - proven → revoke + unbind;
|
|
553
|
+
* - proof for another session, or an unknown/invalid token → revoke nothing;
|
|
554
|
+
* - no proof (an old frontend), or a proof lookup outage → revoke only while
|
|
555
|
+
* `logoutRequiresProof` is false (counted `auth.logout.unproven`, one deprecation warning);
|
|
556
|
+
* strict mode revokes nothing (fail closed).
|
|
557
|
+
* Always 204 — never a 500, never an existence or ownership signal. Tokens are never logged.
|
|
511
558
|
*/
|
|
512
|
-
logout(body: LogoutRequest): Promise<void>;
|
|
559
|
+
logout(body: LogoutRequest, authorization?: string): Promise<void>;
|
|
513
560
|
/**
|
|
514
561
|
* Establish a session for an authenticated principal, mapping the engine's
|
|
515
562
|
* generic `SessionRejectedError` (a malformed principal or a store outage at
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"auth.controller.d.ts","sourceRoot":"","sources":["../../src/auth/auth.controller.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GAqDG;AAeH,OAAO,KAAK,EACV,aAAa,EAIb,cAAc,EAGd,gBAAgB,EAEjB,MAAM,cAAc,CAAC;AAkCtB,OAAO,KAAK,EAAE,qBAAqB,EAAE,MAAM,qCAAqC,CAAC;AAEjF,OAAO,KAAK,EAAE,uBAAuB,EAAE,MAAM,yCAAyC,CAAC;AACvF,OAAO,KAAK,EAAE,kBAAkB,EAAE,MAAM,cAAc,CAAC;AACvD,OAAO,KAAK,EAAE,KAAK,EAAE,qBAAqB,EAAE,MAAM,cAAc,CAAC;AAQjE,OAAO,EAA2C,KAAK,SAAS,EAAE,MAAM,kBAAkB,CAAC;AAE3F,OAAO,KAAK,EAAE,qBAAqB,EAAE,MAAM,oCAAoC,CAAC;AAChF,OAAO,KAAK,EAAE,oBAAoB,EAAE,MAAM,mCAAmC,CAAC;AAC9E,OAAO,KAAK,EAAE,iBAAiB,EAAE,MAAM,+BAA+B,CAAC;AACvE,OAAO,KAAK,EAAE,cAAc,EAAkB,MAAM,iCAAiC,CAAC;AAOtF,OAAO,EAAE,mBAAmB,EAAE,MAAM,mCAAmC,CAAC;AACxE,OAAO,EAAE,eAAe,EAAE,MAAM,wBAAwB,CAAC;AAEzD,OAAO,EAIL,KAAK,kBAAkB,EACxB,MAAM,yCAAyC,CAAC;
|
|
1
|
+
{"version":3,"file":"auth.controller.d.ts","sourceRoot":"","sources":["../../src/auth/auth.controller.ts"],"names":[],"mappings":"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"}
|