@astram/guard 0.11.2 → 0.12.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/auth/account.controller.d.ts +2 -1
- package/dist/auth/account.controller.d.ts.map +1 -1
- package/dist/auth/account.controller.js +21 -2
- package/dist/auth/auth.module.d.ts.map +1 -1
- package/dist/auth/auth.module.js +40 -1
- package/dist/auth/ports/profile-writer.d.ts +8 -0
- package/dist/auth/ports/profile-writer.d.ts.map +1 -1
- package/dist/auth/ports/profile-writer.js +13 -0
- package/dist/auth/tokens.d.ts +6 -0
- package/dist/auth/tokens.d.ts.map +1 -1
- package/dist/auth/tokens.js +7 -1
- package/dist/authentication/mariadb-profile-writer.d.ts +1 -1
- package/dist/authentication/mariadb-profile-writer.d.ts.map +1 -1
- package/dist/authentication/mariadb-profile-writer.js +18 -1
- package/dist/config/app-config.d.ts +13 -0
- package/dist/config/app-config.d.ts.map +1 -1
- package/dist/config/app-config.js +14 -0
- package/dist/index.d.ts +3 -2
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +9 -3
- package/dist/session/index.d.ts +1 -0
- package/dist/session/index.d.ts.map +1 -1
- package/dist/session/index.js +3 -1
- package/dist/session/redis-recent-rotation-store.d.ts +19 -0
- package/dist/session/redis-recent-rotation-store.d.ts.map +1 -0
- package/dist/session/redis-recent-rotation-store.js +115 -0
- package/package.json +3 -3
|
@@ -53,7 +53,7 @@ import type { AttemptLimiter } from './rate-limit/attempt-limiter.js';
|
|
|
53
53
|
import type { CredentialWriter } from './ports/credential-writer.js';
|
|
54
54
|
import type { MfaDevice, MfaDeviceStore } from './ports/mfa-device-store.js';
|
|
55
55
|
import type { CurrentUserProfile, ProfileResolver } from './profile-resolver.js';
|
|
56
|
-
import type
|
|
56
|
+
import { type ProfileWriter } from './ports/profile-writer.js';
|
|
57
57
|
import type { RecoveryCodeStore } from './ports/recovery-code-store.js';
|
|
58
58
|
import type { SessionSweeper } from './ports/session-sweeper.js';
|
|
59
59
|
/** The minimal response surface the 202 answer needs (Express-compatible). */
|
|
@@ -177,6 +177,7 @@ export declare class AccountController {
|
|
|
177
177
|
* `authentication_unavailable` (the token is issued before the second factor is checked, so
|
|
178
178
|
* a STORE outage never spends a recovery code or a TOTP; a failed proof burns that token. A
|
|
179
179
|
* mail failure after a successful proof does spend it — the proof precedes the send)
|
|
180
|
+
* • the name is taken (`ProfileNameTakenError`) → 409 `name_taken` (KI #97)
|
|
180
181
|
* • name only → 200 (the refreshed CurrentUserProfile)
|
|
181
182
|
* • email accepted → 202 `{ pendingEmail: true, profile }`
|
|
182
183
|
*
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"account.controller.d.ts","sourceRoot":"","sources":["../../src/auth/account.controller.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GA2CG;AAmBH,OAAO,KAAK,EAAE,cAAc,EAAE,cAAc,EAAa,MAAM,cAAc,CAAC;AAK9E,OAAO,KAAK,EAEV,kBAAkB,EACnB,MAAM,yCAAyC,CAAC;AAqBjD,OAAO,KAAK,EAAE,SAAS,EAAE,MAAM,uBAAuB,CAAC;AACvD,OAAO,KAAK,EAAE,WAAW,EAAE,MAAM,yBAAyB,CAAC;AAC3D,OAAO,KAAK,EAAE,qBAAqB,EAAE,MAAM,qCAAqC,CAAC;AACjF,OAAO,KAAK,EAAE,mBAAmB,EAAE,MAAM,kCAAkC,CAAC;AAQ5E,OAAO,KAAK,EAAE,uBAAuB,EAAE,MAAM,yCAAyC,CAAC;AACvF,OAAO,KAAK,EAAE,cAAc,EAAE,MAAM,iCAAiC,CAAC;AAEtE,OAAO,KAAK,EAAE,gBAAgB,EAAE,MAAM,8BAA8B,CAAC;AACrE,OAAO,KAAK,EAAE,SAAS,EAAE,cAAc,EAAE,MAAM,6BAA6B,CAAC;AAC7E,OAAO,KAAK,EAAE,kBAAkB,EAAE,eAAe,EAAE,MAAM,uBAAuB,CAAC;AACjF,OAAO,KAAK,
|
|
1
|
+
{"version":3,"file":"account.controller.d.ts","sourceRoot":"","sources":["../../src/auth/account.controller.ts"],"names":[],"mappings":"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"}
|
|
@@ -67,6 +67,7 @@ const tokens_js_2 = require("./tokens.js");
|
|
|
67
67
|
const email_address_js_1 = require("./email-address.js");
|
|
68
68
|
const email_change_messages_js_1 = require("./email-change-messages.js");
|
|
69
69
|
const canonical_hint_js_1 = require("./rate-limit/canonical-hint.js");
|
|
70
|
+
const profile_writer_js_1 = require("./ports/profile-writer.js");
|
|
70
71
|
const totp_enrollment_js_1 = require("./totp-enrollment.js");
|
|
71
72
|
/** Max length of a device name (matches the `md_name VARCHAR(120)` column). */
|
|
72
73
|
const MAX_DEVICE_NAME_LEN = 120;
|
|
@@ -167,6 +168,23 @@ function unprocessable(error) {
|
|
|
167
168
|
* `code`. Missing → this 400 (the client then asks for the code); a wrong code is the generic
|
|
168
169
|
* {@link badRequest}.
|
|
169
170
|
*/
|
|
171
|
+
function nameTaken() {
|
|
172
|
+
throw new common_1.HttpException({ error: 'name_taken' }, common_1.HttpStatus.CONFLICT);
|
|
173
|
+
}
|
|
174
|
+
/**
|
|
175
|
+
* KI #97: apply a name through the writer; a taken name is a 409 `name_taken` (the writer's typed
|
|
176
|
+
* conflict), never the driver's 500. Other errors propagate unchanged.
|
|
177
|
+
*/
|
|
178
|
+
async function writeProfile(writer, principalId, changes) {
|
|
179
|
+
try {
|
|
180
|
+
return await writer.update(principalId, changes);
|
|
181
|
+
}
|
|
182
|
+
catch (err) {
|
|
183
|
+
if (err instanceof profile_writer_js_1.ProfileNameTakenError)
|
|
184
|
+
nameTaken();
|
|
185
|
+
throw err;
|
|
186
|
+
}
|
|
187
|
+
}
|
|
170
188
|
function mfaRequired() {
|
|
171
189
|
throw new common_1.HttpException({ error: 'mfa_required' }, common_1.HttpStatus.BAD_REQUEST);
|
|
172
190
|
}
|
|
@@ -410,6 +428,7 @@ let AccountController = class AccountController {
|
|
|
410
428
|
* `authentication_unavailable` (the token is issued before the second factor is checked, so
|
|
411
429
|
* a STORE outage never spends a recovery code or a TOTP; a failed proof burns that token. A
|
|
412
430
|
* mail failure after a successful proof does spend it — the proof precedes the send)
|
|
431
|
+
* • the name is taken (`ProfileNameTakenError`) → 409 `name_taken` (KI #97)
|
|
413
432
|
* • name only → 200 (the refreshed CurrentUserProfile)
|
|
414
433
|
* • email accepted → 202 `{ pendingEmail: true, profile }`
|
|
415
434
|
*
|
|
@@ -441,11 +460,11 @@ let AccountController = class AccountController {
|
|
|
441
460
|
}
|
|
442
461
|
const profileWriter = this.profileWriter;
|
|
443
462
|
if (email === undefined) {
|
|
444
|
-
return profileWriter
|
|
463
|
+
return writeProfile(profileWriter, claims.id, { name: name });
|
|
445
464
|
}
|
|
446
465
|
await this.requestEmailChange(claims, email, body);
|
|
447
466
|
// A name in the same body still applies at once; the email waits for confirmation.
|
|
448
|
-
const profile = await profileWriter
|
|
467
|
+
const profile = await writeProfile(profileWriter, claims.id, name === undefined ? {} : { name });
|
|
449
468
|
res.status(common_1.HttpStatus.ACCEPTED);
|
|
450
469
|
return { pendingEmail: true, profile };
|
|
451
470
|
}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"auth.module.d.ts","sourceRoot":"","sources":["../../src/auth/auth.module.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GA+DG;AAEH,OAAO,EAAkB,KAAK,aAAa,EAAiB,MAAM,gBAAgB,CAAC;AAanF,OAAO,KAAK,EAGV,kBAAkB,EAOlB,QAAQ,EACR,cAAc,
|
|
1
|
+
{"version":3,"file":"auth.module.d.ts","sourceRoot":"","sources":["../../src/auth/auth.module.ts"],"names":[],"mappings":"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"}
|
package/dist/auth/auth.module.js
CHANGED
|
@@ -479,11 +479,22 @@ const clockProvider = {
|
|
|
479
479
|
useFactory: () => new index_js_1.SystemClock(),
|
|
480
480
|
};
|
|
481
481
|
// --- Composed core engines --------------------------------------------------
|
|
482
|
+
/**
|
|
483
|
+
* KI #51 / #54 (ADR-0036): the sealed recent-rotation store over the shared Redis client, keyed and
|
|
484
|
+
* sealed with the refresh-token HMAC secret. `null` when `REFRESH_REPLAY_WINDOW_MS=0` (window off).
|
|
485
|
+
*/
|
|
486
|
+
const recentRotationStoreProvider = {
|
|
487
|
+
provide: tokens_js_1.SHIELD_RECENT_ROTATION_STORE,
|
|
488
|
+
useFactory: (redis, config) => config.refreshReplayWindowMs === 0
|
|
489
|
+
? null
|
|
490
|
+
: new index_js_1.RedisRecentRotationStore(redis, (0, app_config_js_1.assertRefreshHmacKey)(config.refreshHmacKey)),
|
|
491
|
+
inject: [tokens_js_1.SHIELD_REDIS, config_module_js_1.APP_CONFIG],
|
|
492
|
+
};
|
|
482
493
|
/** The composed SessionAuthority (core) — establish / rotate / revoke. */
|
|
483
494
|
const sessionAuthorityProvider = {
|
|
484
495
|
provide: tokens_js_1.SHIELD_SESSION_AUTHORITY,
|
|
485
496
|
// async: loads the core factory lazily (CJS→ESM, see loadCore()); Nest awaits it.
|
|
486
|
-
useFactory: async (recordStore, hotStore, tokenGenerator, refreshHasher, clock, lifetimes) => {
|
|
497
|
+
useFactory: async (recordStore, hotStore, tokenGenerator, refreshHasher, clock, lifetimes, config, recentRotations, auditSink) => {
|
|
487
498
|
const { createSessionAuthority } = await loadCore();
|
|
488
499
|
return createSessionAuthority({
|
|
489
500
|
recordStore,
|
|
@@ -492,6 +503,30 @@ const sessionAuthorityProvider = {
|
|
|
492
503
|
refreshHasher,
|
|
493
504
|
clock,
|
|
494
505
|
lifetimes,
|
|
506
|
+
// KI #51 / #54 (ADR-0036): a repeated refresh inside the window gets the same successor.
|
|
507
|
+
// Every such answer is audited (ids only; never a token). Validated by core at construction.
|
|
508
|
+
...(config.refreshReplayWindowMs !== undefined
|
|
509
|
+
? { replayWindowMs: config.refreshReplayWindowMs }
|
|
510
|
+
: {}),
|
|
511
|
+
...(recentRotations !== null
|
|
512
|
+
? {
|
|
513
|
+
recentRotations,
|
|
514
|
+
onReplayTolerated: (event) => {
|
|
515
|
+
void auditSink
|
|
516
|
+
?.record({
|
|
517
|
+
type: 'authentication',
|
|
518
|
+
occurredAtMs: Date.now(),
|
|
519
|
+
actorId: event.principalId,
|
|
520
|
+
tenantId: event.tenantId,
|
|
521
|
+
action: 'session.refresh_replay_tolerated',
|
|
522
|
+
attributes: { sessionId: event.sessionId },
|
|
523
|
+
})
|
|
524
|
+
.catch(() => {
|
|
525
|
+
/* best-effort: an audit failure never changes the response */
|
|
526
|
+
});
|
|
527
|
+
},
|
|
528
|
+
}
|
|
529
|
+
: {}),
|
|
495
530
|
});
|
|
496
531
|
},
|
|
497
532
|
inject: [
|
|
@@ -501,6 +536,9 @@ const sessionAuthorityProvider = {
|
|
|
501
536
|
index_js_1.SHIELD_REFRESH_HASHER,
|
|
502
537
|
index_js_1.SHIELD_CLOCK,
|
|
503
538
|
index_js_1.SHIELD_SESSION_LIFETIMES,
|
|
539
|
+
config_module_js_1.APP_CONFIG,
|
|
540
|
+
tokens_js_1.SHIELD_RECENT_ROTATION_STORE,
|
|
541
|
+
tokens_js_1.SHIELD_AUDIT_SINK,
|
|
504
542
|
],
|
|
505
543
|
};
|
|
506
544
|
/**
|
|
@@ -931,6 +969,7 @@ let AuthModule = AuthModule_1 = class AuthModule {
|
|
|
931
969
|
tokenGeneratorProvider,
|
|
932
970
|
refreshHasherProvider,
|
|
933
971
|
clockProvider,
|
|
972
|
+
recentRotationStoreProvider,
|
|
934
973
|
sessionAuthorityProvider,
|
|
935
974
|
// The login TOTP verifier (OR across devices + Redis replay guard, M-B), shared by
|
|
936
975
|
// the authenticator and the MFA step-up.
|
|
@@ -13,4 +13,12 @@ export interface ProfileWriter {
|
|
|
13
13
|
email?: string;
|
|
14
14
|
}): Promise<CurrentUserProfile>;
|
|
15
15
|
}
|
|
16
|
+
/**
|
|
17
|
+
* KI #97: the requested display name is already taken (`u_username` is UNIQUE). A writer throws
|
|
18
|
+
* this instead of the driver error; `PATCH /account/profile` answers 409 `name_taken`. The message
|
|
19
|
+
* never carries the value.
|
|
20
|
+
*/
|
|
21
|
+
export declare class ProfileNameTakenError extends Error {
|
|
22
|
+
constructor();
|
|
23
|
+
}
|
|
16
24
|
//# sourceMappingURL=profile-writer.d.ts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"profile-writer.d.ts","sourceRoot":"","sources":["../../../src/auth/ports/profile-writer.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,kBAAkB,EAAE,MAAM,wBAAwB,CAAC;AAEjE;;;;;;;GAOG;AACH,MAAM,WAAW,aAAa;IAC5B,MAAM,CACJ,WAAW,EAAE,MAAM,EACnB,OAAO,EAAE;QAAE,IAAI,CAAC,EAAE,MAAM,CAAC;QAAC,KAAK,CAAC,EAAE,MAAM,CAAA;KAAE,GACzC,OAAO,CAAC,kBAAkB,CAAC,CAAC;CAChC"}
|
|
1
|
+
{"version":3,"file":"profile-writer.d.ts","sourceRoot":"","sources":["../../../src/auth/ports/profile-writer.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,kBAAkB,EAAE,MAAM,wBAAwB,CAAC;AAEjE;;;;;;;GAOG;AACH,MAAM,WAAW,aAAa;IAC5B,MAAM,CACJ,WAAW,EAAE,MAAM,EACnB,OAAO,EAAE;QAAE,IAAI,CAAC,EAAE,MAAM,CAAC;QAAC,KAAK,CAAC,EAAE,MAAM,CAAA;KAAE,GACzC,OAAO,CAAC,kBAAkB,CAAC,CAAC;CAChC;AAED;;;;GAIG;AACH,qBAAa,qBAAsB,SAAQ,KAAK;;CAK/C"}
|
|
@@ -1,2 +1,15 @@
|
|
|
1
1
|
"use strict";
|
|
2
2
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.ProfileNameTakenError = void 0;
|
|
4
|
+
/**
|
|
5
|
+
* KI #97: the requested display name is already taken (`u_username` is UNIQUE). A writer throws
|
|
6
|
+
* this instead of the driver error; `PATCH /account/profile` answers 409 `name_taken`. The message
|
|
7
|
+
* never carries the value.
|
|
8
|
+
*/
|
|
9
|
+
class ProfileNameTakenError extends Error {
|
|
10
|
+
constructor() {
|
|
11
|
+
super('That name is already in use.');
|
|
12
|
+
this.name = 'ProfileNameTakenError';
|
|
13
|
+
}
|
|
14
|
+
}
|
|
15
|
+
exports.ProfileNameTakenError = ProfileNameTakenError;
|
package/dist/auth/tokens.d.ts
CHANGED
|
@@ -68,6 +68,12 @@ export declare const SHIELD_AUTHENTICATOR: unique symbol;
|
|
|
68
68
|
* and `/auth/mfa` (establish after factor).
|
|
69
69
|
*/
|
|
70
70
|
export declare const SHIELD_SESSION_AUTHORITY: unique symbol;
|
|
71
|
+
/**
|
|
72
|
+
* KI #51 / #54 (ADR-0036): the recent-rotation store core's session authority uses to answer a
|
|
73
|
+
* repeated refresh with the same successor (`RedisRecentRotationStore`), or `null` when
|
|
74
|
+
* `REFRESH_REPLAY_WINDOW_MS=0` turns the window off.
|
|
75
|
+
*/
|
|
76
|
+
export declare const SHIELD_RECENT_ROTATION_STORE: unique symbol;
|
|
71
77
|
/**
|
|
72
78
|
* The `CredentialWriter` (guard port, `../auth/ports/credential-writer.ts`) — the
|
|
73
79
|
* WRITE side of the credential store (set password hash, read the stored hash by
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"tokens.d.ts","sourceRoot":"","sources":["../../src/auth/tokens.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;GAsBG;AAEH,OAAO,EAAE,sBAAsB,EAAE,MAAM,+CAA+C,CAAC;AAEvF;;;;;;GAMG;AACH,eAAO,MAAM,cAAc,eAA2B,CAAC;AAEvD;;;;GAIG;AACH,eAAO,MAAM,YAAY,eAAyB,CAAC;AAEnD;;;;;;GAMG;AACH,eAAO,MAAM,0BAA0B,eAAuC,CAAC;AAE/E;;;;;;;GAOG;AACH,eAAO,MAAM,uBAAuB,eAAoC,CAAC;AAEzE;;;;;GAKG;AACH,eAAO,MAAM,oBAAoB,eAAiC,CAAC;AAEnE;;;;;;GAMG;AACH,eAAO,MAAM,wBAAwB,eAAqC,CAAC;
|
|
1
|
+
{"version":3,"file":"tokens.d.ts","sourceRoot":"","sources":["../../src/auth/tokens.ts"],"names":[],"mappings":"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"}
|
package/dist/auth/tokens.js
CHANGED
|
@@ -23,7 +23,7 @@
|
|
|
23
23
|
* ADR-0003: no framework/DB/crypto imports here — just Symbols (+ one re-export).
|
|
24
24
|
*/
|
|
25
25
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
26
|
-
exports.SHIELD_SESSION_RESTRICTIONS = exports.SHIELD_PERMISSION_VERSION_CACHE = exports.SHIELD_PERMISSION_FACTS = exports.SHIELD_RESET_LIMITER = exports.SHIELD_FORGOT_HINT_LIMITER = exports.SHIELD_FORGOT_LIMITER = exports.SHIELD_LOGIN_TOTP_VERIFIER = exports.SHIELD_MFA_STEP_UP = exports.SHIELD_MFA_LIMITER = exports.SHIELD_RECOVERY_LIMITER = exports.SHIELD_LOGIN_IP_LIMITER = exports.SHIELD_LOGIN_LIMITER = exports.SHIELD_MEMBERSHIP_CHECKER = exports.SHIELD_SCOPE_SUBTREE_RESOLVER = exports.SHIELD_SESSION_FACTS_PROJECTOR = exports.SHIELD_ROOT_IDS = exports.SHIELD_TOTP_VERIFIER_OVERRIDE = exports.SHIELD_TOTP_VERIFIER = exports.SHIELD_RESET_LINK_BASE_URL = exports.SHIELD_SESSION_SWEEPER = exports.SHIELD_MFA_DEVICE_STORE = exports.SHIELD_AUDIT_SINK = exports.SHIELD_PROFILE_WRITER = exports.SHIELD_RECOVERY_CODE_STORE = exports.SHIELD_EMAIL_SENDER = exports.SHIELD_CONFIRM_EMAIL_LIMITER = exports.SHIELD_EMAIL_CHANGE_LIMITER = exports.SHIELD_EMAIL_CHANGE_LINK_BASE_URL = exports.SHIELD_EMAIL_ADDRESS_CHANGER = exports.SHIELD_EMAIL_CHANGE_TOKEN_STORE = exports.SHIELD_RESET_TOKEN_STORE = exports.SHIELD_CREDENTIAL_WRITER = exports.SHIELD_SESSION_AUTHORITY = exports.SHIELD_AUTHENTICATOR = exports.SHIELD_PROFILE_RESOLVER = exports.SHIELD_CREDENTIAL_RESOLVER = exports.SHIELD_REDIS = exports.SHIELD_DB_POOL = exports.SHIELD_PASSWORD_HASHER = void 0;
|
|
26
|
+
exports.SHIELD_SESSION_RESTRICTIONS = exports.SHIELD_PERMISSION_VERSION_CACHE = exports.SHIELD_PERMISSION_FACTS = exports.SHIELD_RESET_LIMITER = exports.SHIELD_FORGOT_HINT_LIMITER = exports.SHIELD_FORGOT_LIMITER = exports.SHIELD_LOGIN_TOTP_VERIFIER = exports.SHIELD_MFA_STEP_UP = exports.SHIELD_MFA_LIMITER = exports.SHIELD_RECOVERY_LIMITER = exports.SHIELD_LOGIN_IP_LIMITER = exports.SHIELD_LOGIN_LIMITER = exports.SHIELD_MEMBERSHIP_CHECKER = exports.SHIELD_SCOPE_SUBTREE_RESOLVER = exports.SHIELD_SESSION_FACTS_PROJECTOR = exports.SHIELD_ROOT_IDS = exports.SHIELD_TOTP_VERIFIER_OVERRIDE = exports.SHIELD_TOTP_VERIFIER = exports.SHIELD_RESET_LINK_BASE_URL = exports.SHIELD_SESSION_SWEEPER = exports.SHIELD_MFA_DEVICE_STORE = exports.SHIELD_AUDIT_SINK = exports.SHIELD_PROFILE_WRITER = exports.SHIELD_RECOVERY_CODE_STORE = exports.SHIELD_EMAIL_SENDER = exports.SHIELD_CONFIRM_EMAIL_LIMITER = exports.SHIELD_EMAIL_CHANGE_LIMITER = exports.SHIELD_EMAIL_CHANGE_LINK_BASE_URL = exports.SHIELD_EMAIL_ADDRESS_CHANGER = exports.SHIELD_EMAIL_CHANGE_TOKEN_STORE = exports.SHIELD_RESET_TOKEN_STORE = exports.SHIELD_CREDENTIAL_WRITER = exports.SHIELD_RECENT_ROTATION_STORE = exports.SHIELD_SESSION_AUTHORITY = exports.SHIELD_AUTHENTICATOR = exports.SHIELD_PROFILE_RESOLVER = exports.SHIELD_CREDENTIAL_RESOLVER = exports.SHIELD_REDIS = exports.SHIELD_DB_POOL = exports.SHIELD_PASSWORD_HASHER = void 0;
|
|
27
27
|
var argon2id_password_hasher_js_1 = require("../authentication/argon2id-password-hasher.js");
|
|
28
28
|
Object.defineProperty(exports, "SHIELD_PASSWORD_HASHER", { enumerable: true, get: function () { return argon2id_password_hasher_js_1.SHIELD_PASSWORD_HASHER; } });
|
|
29
29
|
/**
|
|
@@ -72,6 +72,12 @@ exports.SHIELD_AUTHENTICATOR = Symbol('SHIELD_AUTHENTICATOR');
|
|
|
72
72
|
* and `/auth/mfa` (establish after factor).
|
|
73
73
|
*/
|
|
74
74
|
exports.SHIELD_SESSION_AUTHORITY = Symbol('SHIELD_SESSION_AUTHORITY');
|
|
75
|
+
/**
|
|
76
|
+
* KI #51 / #54 (ADR-0036): the recent-rotation store core's session authority uses to answer a
|
|
77
|
+
* repeated refresh with the same successor (`RedisRecentRotationStore`), or `null` when
|
|
78
|
+
* `REFRESH_REPLAY_WINDOW_MS=0` turns the window off.
|
|
79
|
+
*/
|
|
80
|
+
exports.SHIELD_RECENT_ROTATION_STORE = Symbol('SHIELD_RECENT_ROTATION_STORE');
|
|
75
81
|
// ---------------------------------------------------------------------------
|
|
76
82
|
// Account & credential surface seams (forgot/reset, change-password, MFA
|
|
77
83
|
// enrollment, profile edit). All OPTIONAL, consumer-plugged through
|
|
@@ -5,7 +5,7 @@
|
|
|
5
5
|
* display profile has ONE source of truth (names, never UUIDs). Fail-closed: throws if the re-read is null.
|
|
6
6
|
*/
|
|
7
7
|
import type { Pool } from 'mariadb';
|
|
8
|
-
import type
|
|
8
|
+
import { type ProfileWriter } from '../auth/ports/profile-writer.js';
|
|
9
9
|
import type { CurrentUserProfile } from '../auth/profile-resolver.js';
|
|
10
10
|
export declare class MariaDbProfileWriter implements ProfileWriter {
|
|
11
11
|
private readonly pool;
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"mariadb-profile-writer.d.ts","sourceRoot":"","sources":["../../src/authentication/mariadb-profile-writer.ts"],"names":[],"mappings":"AAAA;;;;;GAKG;AACH,OAAO,KAAK,EAAE,IAAI,EAAE,MAAM,SAAS,CAAC;AACpC,OAAO,KAAK,
|
|
1
|
+
{"version":3,"file":"mariadb-profile-writer.d.ts","sourceRoot":"","sources":["../../src/authentication/mariadb-profile-writer.ts"],"names":[],"mappings":"AAAA;;;;;GAKG;AACH,OAAO,KAAK,EAAE,IAAI,EAAE,MAAM,SAAS,CAAC;AACpC,OAAO,EAAyB,KAAK,aAAa,EAAE,MAAM,iCAAiC,CAAC;AAC5F,OAAO,KAAK,EAAE,kBAAkB,EAAE,MAAM,6BAA6B,CAAC;AAgBtE,qBAAa,oBAAqB,YAAW,aAAa;IAE5C,OAAO,CAAC,QAAQ,CAAC,IAAI;IADjC,OAAO,CAAC,QAAQ,CAAC,QAAQ,CAAyB;gBACrB,IAAI,EAAE,IAAI;IAIjC,MAAM,CACV,WAAW,EAAE,MAAM,EACnB,OAAO,EAAE;QAAE,IAAI,CAAC,EAAE,MAAM,CAAC;QAAC,KAAK,CAAC,EAAE,MAAM,CAAA;KAAE,GACzC,OAAO,CAAC,kBAAkB,CAAC;CAgD/B"}
|
|
@@ -1,7 +1,16 @@
|
|
|
1
1
|
"use strict";
|
|
2
2
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
3
|
exports.MariaDbProfileWriter = void 0;
|
|
4
|
+
const profile_writer_js_1 = require("../auth/ports/profile-writer.js");
|
|
4
5
|
const mariadb_profile_resolver_js_1 = require("./mariadb-profile-resolver.js");
|
|
6
|
+
/** MariaDB `ER_DUP_ENTRY`: here `IDX_users_username` refused the name (KI #97). */
|
|
7
|
+
const ER_DUP_ENTRY = 1062;
|
|
8
|
+
function isDuplicateKey(err) {
|
|
9
|
+
if (typeof err !== 'object' || err === null)
|
|
10
|
+
return false;
|
|
11
|
+
const e = err;
|
|
12
|
+
return e.errno === ER_DUP_ENTRY || e.code === 'ER_DUP_ENTRY';
|
|
13
|
+
}
|
|
5
14
|
class MariaDbProfileWriter {
|
|
6
15
|
pool;
|
|
7
16
|
resolver;
|
|
@@ -24,7 +33,15 @@ class MariaDbProfileWriter {
|
|
|
24
33
|
}
|
|
25
34
|
if (sets.length > 0) {
|
|
26
35
|
params.push(principalId);
|
|
27
|
-
|
|
36
|
+
try {
|
|
37
|
+
await this.pool.query(`UPDATE \`shield_app\`.\`users\` SET ${sets.join(', ')} WHERE u_uuid = ?`, params);
|
|
38
|
+
}
|
|
39
|
+
catch (err) {
|
|
40
|
+
// KI #97: the driver message quotes the value; drop it and answer a typed conflict.
|
|
41
|
+
if (isDuplicateKey(err))
|
|
42
|
+
throw new profile_writer_js_1.ProfileNameTakenError();
|
|
43
|
+
throw err;
|
|
44
|
+
}
|
|
28
45
|
}
|
|
29
46
|
// Resolve the caller's active company so the re-read profile is tenant-correct.
|
|
30
47
|
const active = (await this.pool.query("SELECT cm_company_uuid FROM `shield_app`.`company_membership` WHERE cm_user_uuid = ? AND cm_is_active = 1 AND cm_status = 'active' LIMIT 1", [principalId]));
|
|
@@ -67,6 +67,13 @@ export interface AppConfig {
|
|
|
67
67
|
* (50 failures / 15 min). Read from `LOGIN_IP_MAX_FAILURES` / `LOGIN_IP_WINDOW_MS`.
|
|
68
68
|
*/
|
|
69
69
|
readonly loginIpLimit?: LoginIpLimitConfig;
|
|
70
|
+
/**
|
|
71
|
+
* KI #51 / #54 (ADR-0036): the refresh replay window in ms (`REFRESH_REPLAY_WINDOW_MS`). A
|
|
72
|
+
* repeated refresh of one token inside it gets the same successor while that successor is unused.
|
|
73
|
+
* `undefined` ⇒ core's default (20 000); `0` disables; core rejects anything outside 0–120 000 at
|
|
74
|
+
* composition (boot fails loud).
|
|
75
|
+
*/
|
|
76
|
+
readonly refreshReplayWindowMs?: number;
|
|
70
77
|
}
|
|
71
78
|
/** The per-client-IP login failure limit (failures within `windowMs` that lock the IP). */
|
|
72
79
|
export interface LoginIpLimitConfig {
|
|
@@ -224,6 +231,12 @@ export declare function loadSessionLifetimes(env?: NodeJS.ProcessEnv): SessionLi
|
|
|
224
231
|
* windowMs ← LOGIN_IP_WINDOW_MS (default 900000 = 15 min)
|
|
225
232
|
*/
|
|
226
233
|
export declare function loadLoginIpLimit(env?: NodeJS.ProcessEnv): LoginIpLimitConfig;
|
|
234
|
+
/**
|
|
235
|
+
* Read `REFRESH_REPLAY_WINDOW_MS` (KI #51). Blank/absent ⇒ `undefined` (core default 20 s). Any
|
|
236
|
+
* other value is passed through as a number (`NaN` for garbage) so core's construction-time check
|
|
237
|
+
* fails the auth composition loudly instead of silently picking a window. Total; never throws.
|
|
238
|
+
*/
|
|
239
|
+
export declare function loadRefreshReplayWindowMs(env?: NodeJS.ProcessEnv): number | undefined;
|
|
227
240
|
/**
|
|
228
241
|
* Read the refresh-token HMAC key from env (raw; `''` when absent/blank). Total —
|
|
229
242
|
* does NOT throw, so {@link loadAppConfig} stays boot-safe for a non-auth scaffold.
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"app-config.d.ts","sourceRoot":"","sources":["../../src/config/app-config.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;;GAwBG;AACH,OAAO,KAAK,EAAE,eAAe,EAAE,MAAM,cAAc,CAAC;AAGpD,MAAM,WAAW,SAAS;IACxB,yCAAyC;IACzC,QAAQ,CAAC,IAAI,EAAE,MAAM,CAAC;IACtB,oEAAoE;IACpE,QAAQ,CAAC,WAAW,EAAE,aAAa,GAAG,MAAM,GAAG,YAAY,CAAC;IAC5D,wEAAwE;IACxE,QAAQ,CAAC,IAAI,EAAE,gBAAgB,CAAC;IAGhC;;;;OAIG;IACH,QAAQ,CAAC,EAAE,EAAE,QAAQ,CAAC;IACtB;;;OAGG;IACH,QAAQ,CAAC,KAAK,EAAE,WAAW,CAAC;IAC5B;;;;;;;;;;OAUG;IACH,QAAQ,CAAC,cAAc,EAAE,MAAM,CAAC;IAChC;;;;;OAKG;IACH,QAAQ,CAAC,SAAS,EAAE,wBAAwB,CAAC;IAC7C;;;;OAIG;IACH,QAAQ,CAAC,YAAY,CAAC,EAAE,kBAAkB,CAAC;
|
|
1
|
+
{"version":3,"file":"app-config.d.ts","sourceRoot":"","sources":["../../src/config/app-config.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;;GAwBG;AACH,OAAO,KAAK,EAAE,eAAe,EAAE,MAAM,cAAc,CAAC;AAGpD,MAAM,WAAW,SAAS;IACxB,yCAAyC;IACzC,QAAQ,CAAC,IAAI,EAAE,MAAM,CAAC;IACtB,oEAAoE;IACpE,QAAQ,CAAC,WAAW,EAAE,aAAa,GAAG,MAAM,GAAG,YAAY,CAAC;IAC5D,wEAAwE;IACxE,QAAQ,CAAC,IAAI,EAAE,gBAAgB,CAAC;IAGhC;;;;OAIG;IACH,QAAQ,CAAC,EAAE,EAAE,QAAQ,CAAC;IACtB;;;OAGG;IACH,QAAQ,CAAC,KAAK,EAAE,WAAW,CAAC;IAC5B;;;;;;;;;;OAUG;IACH,QAAQ,CAAC,cAAc,EAAE,MAAM,CAAC;IAChC;;;;;OAKG;IACH,QAAQ,CAAC,SAAS,EAAE,wBAAwB,CAAC;IAC7C;;;;OAIG;IACH,QAAQ,CAAC,YAAY,CAAC,EAAE,kBAAkB,CAAC;IAC3C;;;;;OAKG;IACH,QAAQ,CAAC,qBAAqB,CAAC,EAAE,MAAM,CAAC;CACzC;AAED,2FAA2F;AAC3F,MAAM,WAAW,kBAAkB;IACjC,QAAQ,CAAC,WAAW,EAAE,MAAM,CAAC;IAC7B,QAAQ,CAAC,QAAQ,EAAE,MAAM,CAAC;CAC3B;AAED,sEAAsE;AACtE,eAAO,MAAM,sBAAsB,EAAE,kBAGpC,CAAC;AAEF;;;;;;GAMG;AACH,MAAM,WAAW,QAAQ;IACvB,QAAQ,CAAC,IAAI,EAAE,MAAM,CAAC;IACtB,QAAQ,CAAC,IAAI,EAAE,MAAM,CAAC;IACtB,QAAQ,CAAC,IAAI,EAAE,MAAM,CAAC;IACtB,kEAAkE;IAClE,QAAQ,CAAC,QAAQ,EAAE,MAAM,CAAC;IAC1B,QAAQ,CAAC,QAAQ,EAAE,MAAM,CAAC;CAC3B;AAED;;;;;GAKG;AACH,MAAM,WAAW,WAAW;IAC1B,6EAA6E;IAC7E,QAAQ,CAAC,GAAG,EAAE,MAAM,CAAC;IACrB;;;;OAIG;IACH,QAAQ,CAAC,gBAAgB,CAAC,EAAE,MAAM,CAAC;CACpC;AAED,8FAA8F;AAC9F,eAAO,MAAM,gCAAgC,OAAO,CAAC;AAErD;;;;;;GAMG;AACH,MAAM,WAAW,wBAAwB;IACvC,4EAA4E;IAC5E,QAAQ,CAAC,WAAW,CAAC,EAAE,MAAM,CAAC;IAC9B,gEAAgE;IAChE,QAAQ,CAAC,aAAa,CAAC,EAAE,MAAM,CAAC;IAChC,yDAAyD;IACzD,QAAQ,CAAC,oBAAoB,CAAC,EAAE,MAAM,CAAC;CACxC;AAED;;;;GAIG;AACH,MAAM,WAAW,gBAAgB;IAC/B;;;;OAIG;IACH,QAAQ,CAAC,OAAO,EAAE,MAAM,CAAC;IACzB;;;OAGG;IACH,QAAQ,CAAC,cAAc,EAAE,MAAM,CAAC;IAChC;;;OAGG;IACH,QAAQ,CAAC,QAAQ,EAAE,MAAM,CAAC;IAC1B,6EAA6E;IAC7E,QAAQ,CAAC,aAAa,EAAE,mBAAmB,CAAC;CAC7C;AAED;;;;GAIG;AACH,MAAM,WAAW,mBAAmB;IAClC,qEAAqE;IACrE,QAAQ,CAAC,WAAW,EAAE,MAAM,CAAC;IAC7B,8CAA8C;IAC9C,QAAQ,CAAC,eAAe,EAAE,MAAM,CAAC;IACjC,wEAAwE;IACxE,QAAQ,CAAC,iBAAiB,EAAE,MAAM,CAAC;CACpC;AAED,wEAAwE;AACxE,eAAO,MAAM,mBAAmB,EAAE,gBASjC,CAAC;AAEF,gFAAgF;AAChF,eAAO,MAAM,wBAAwB,IAAI,CAAC;AAoB1C;;;;;GAKG;AACH,wBAAgB,kBAAkB,CAAC,GAAG,EAAE,MAAM,GAAG,SAAS,GAAG,OAAO,CAEnE;AAaD;;;;;;;;;GASG;AACH,wBAAgB,cAAc,CAAC,GAAG,GAAE,MAAM,CAAC,UAAwB,GAAG,gBAAgB,CAuBrF;AAQD,uFAAuF;AACvF,eAAO,MAAM,iBAAiB,EAAE,IAAI,CAAC,QAAQ,EAAE,UAAU,CAKxD,CAAC;AAEF,6DAA6D;AAC7D,eAAO,MAAM,iBAAiB,2BAA2B,CAAC;AAoB1D;;;;;;;;;;GAUG;AACH,wBAAgB,YAAY,CAAC,GAAG,GAAE,MAAM,CAAC,UAAwB,GAAG,QAAQ,CAQ3E;AAED;;;;GAIG;AACH,wBAAgB,eAAe,CAAC,GAAG,GAAE,MAAM,CAAC,UAAwB,GAAG,WAAW,CAiBjF;AAED;;;;;;;;;GASG;AACH,wBAAgB,oBAAoB,CAClC,GAAG,GAAE,MAAM,CAAC,UAAwB,GACnC,wBAAwB,CAa1B;AAED;;;;;;GAMG;AACH,wBAAgB,gBAAgB,CAAC,GAAG,GAAE,MAAM,CAAC,UAAwB,GAAG,kBAAkB,CAKzF;AAED;;;;GAIG;AACH,wBAAgB,yBAAyB,CACvC,GAAG,GAAE,MAAM,CAAC,UAAwB,GACnC,MAAM,GAAG,SAAS,CAIpB;AAED;;;;;GAKG;AACH,wBAAgB,kBAAkB,CAAC,GAAG,GAAE,MAAM,CAAC,UAAwB,GAAG,MAAM,CAE/E;AAED;;;;;;;;;;;;;;GAcG;AACH,wBAAgB,oBAAoB,CAAC,GAAG,EAAE,MAAM,GAAG,MAAM,CASxD;AAED;;;;;;;;;;GAUG;AACH,wBAAgB,aAAa,CAAC,GAAG,GAAE,MAAM,CAAC,UAAwB,GAAG,SAAS,CAa7E;AAED;;;;;;;;;;;;;GAaG;AACH,wBAAsB,kBAAkB,CACtC,QAAQ,CAAC,EAAE,eAAe,EAC1B,GAAG,GAAE,MAAM,CAAC,UAAwB,GACnC,OAAO,CAAC,SAAS,CAAC,CAIpB;AAMD,mFAAmF;AACnF,MAAM,WAAW,oBAAoB;IACnC,2DAA2D;IAC3D,QAAQ,CAAC,oBAAoB,EAAE,MAAM,CAAC;IACtC,+EAA+E;IAC/E,QAAQ,CAAC,kBAAkB,EAAE,MAAM,CAAC;IACpC,0EAA0E;IAC1E,QAAQ,CAAC,mBAAmB,EAAE,MAAM,CAAC;IACrC,qEAAqE;IACrE,QAAQ,CAAC,KAAK,EAAE,MAAM,CAAC;IACvB,qDAAqD;IACrD,QAAQ,CAAC,YAAY,EAAE,OAAO,CAAC;IAC/B,0EAA0E;IAC1E,QAAQ,CAAC,sBAAsB,EAAE,OAAO,CAAC;CAC1C;AAED;;;GAGG;AACH,wBAAgB,kBAAkB,CAAC,GAAG,EAAE,gBAAgB,GAAG,oBAAoB,CAgB9E"}
|
|
@@ -7,6 +7,7 @@ exports.loadDbConfig = loadDbConfig;
|
|
|
7
7
|
exports.loadRedisConfig = loadRedisConfig;
|
|
8
8
|
exports.loadSessionLifetimes = loadSessionLifetimes;
|
|
9
9
|
exports.loadLoginIpLimit = loadLoginIpLimit;
|
|
10
|
+
exports.loadRefreshReplayWindowMs = loadRefreshReplayWindowMs;
|
|
10
11
|
exports.loadRefreshHmacKey = loadRefreshHmacKey;
|
|
11
12
|
exports.assertRefreshHmacKey = assertRefreshHmacKey;
|
|
12
13
|
exports.loadAppConfig = loadAppConfig;
|
|
@@ -201,6 +202,17 @@ function loadLoginIpLimit(env = process.env) {
|
|
|
201
202
|
windowMs: parsePositiveInt(env.LOGIN_IP_WINDOW_MS, exports.DEFAULT_LOGIN_IP_LIMIT.windowMs),
|
|
202
203
|
};
|
|
203
204
|
}
|
|
205
|
+
/**
|
|
206
|
+
* Read `REFRESH_REPLAY_WINDOW_MS` (KI #51). Blank/absent ⇒ `undefined` (core default 20 s). Any
|
|
207
|
+
* other value is passed through as a number (`NaN` for garbage) so core's construction-time check
|
|
208
|
+
* fails the auth composition loudly instead of silently picking a window. Total; never throws.
|
|
209
|
+
*/
|
|
210
|
+
function loadRefreshReplayWindowMs(env = process.env) {
|
|
211
|
+
const raw = env.REFRESH_REPLAY_WINDOW_MS;
|
|
212
|
+
if (raw === undefined || raw.trim() === '')
|
|
213
|
+
return undefined;
|
|
214
|
+
return Number(raw.trim());
|
|
215
|
+
}
|
|
204
216
|
/**
|
|
205
217
|
* Read the refresh-token HMAC key from env (raw; `''` when absent/blank). Total —
|
|
206
218
|
* does NOT throw, so {@link loadAppConfig} stays boot-safe for a non-auth scaffold.
|
|
@@ -245,6 +257,7 @@ function assertRefreshHmacKey(key) {
|
|
|
245
257
|
* auth-composition time (see its doc).
|
|
246
258
|
*/
|
|
247
259
|
function loadAppConfig(env = process.env) {
|
|
260
|
+
const refreshReplayWindowMs = loadRefreshReplayWindowMs(env);
|
|
248
261
|
return {
|
|
249
262
|
port: parsePort(env.PORT, 3000),
|
|
250
263
|
environment: parseEnvironment(env.NODE_ENV),
|
|
@@ -254,6 +267,7 @@ function loadAppConfig(env = process.env) {
|
|
|
254
267
|
refreshHmacKey: loadRefreshHmacKey(env),
|
|
255
268
|
lifetimes: loadSessionLifetimes(env),
|
|
256
269
|
loginIpLimit: loadLoginIpLimit(env),
|
|
270
|
+
...(refreshReplayWindowMs !== undefined ? { refreshReplayWindowMs } : {}),
|
|
257
271
|
};
|
|
258
272
|
}
|
|
259
273
|
/**
|
package/dist/index.d.ts
CHANGED
|
@@ -35,7 +35,7 @@ export { stubDecisionAuthority, type Effect, type CoreDecisionAuthority, type Co
|
|
|
35
35
|
export { Argon2idPasswordHasher, argon2idHasherProvider, SHIELD_PASSWORD_HASHER, type Argon2idParams, } from './authentication/argon2id-password-hasher.js';
|
|
36
36
|
export { LocalKekCrypto } from './encryption/local-kek-crypto.js';
|
|
37
37
|
export { EncryptedFileSecretsProvider } from './secrets/encrypted-file-secrets.js';
|
|
38
|
-
export { MariaDbSessionRecordStore, SHIELD_SESSION_RECORD_STORE, RedisHotSessionStore, SHIELD_HOT_SESSION_STORE, CryptoTokenGenerator, Sha256RefreshTokenHasher, SystemClock, cryptoTokenGeneratorProvider, refreshHasherProvider, systemClockProvider, SHIELD_TOKEN_GENERATOR, SHIELD_REFRESH_HASHER, SHIELD_CLOCK, HotRevokingSessionRecordStore, type SessionHotRevoker, type LineageSessionLookup, SHIELD_SESSION_LIFETIMES, ROTATE_GRACE_MS, accessBindingTtlMs, } from './session/index.js';
|
|
38
|
+
export { MariaDbSessionRecordStore, SHIELD_SESSION_RECORD_STORE, RedisHotSessionStore, SHIELD_HOT_SESSION_STORE, RedisRecentRotationStore, type RedisRecentRotationStoreOptions, CryptoTokenGenerator, Sha256RefreshTokenHasher, SystemClock, cryptoTokenGeneratorProvider, refreshHasherProvider, systemClockProvider, SHIELD_TOKEN_GENERATOR, SHIELD_REFRESH_HASHER, SHIELD_CLOCK, HotRevokingSessionRecordStore, type SessionHotRevoker, type LineageSessionLookup, SHIELD_SESSION_LIFETIMES, ROTATE_GRACE_MS, accessBindingTtlMs, } from './session/index.js';
|
|
39
39
|
export { MariaDbRecordPermissionRuleAdapter, SHIELD_RECORD_RULE_PORT, type RuleQueryable, } from './authz/mariadb-record-rule-adapter.js';
|
|
40
40
|
export { MariaDbPolicyStore, SHIELD_POLICY_STORE, type RuleQueryable as PolicyStoreQueryable, } from './authz/mariadb-policy-store.js';
|
|
41
41
|
export { MariaDbListScopeAdapter, SHIELD_LIST_SCOPE_PORT, type ListScopeQueryable, } from './authz/mariadb-list-scope-adapter.js';
|
|
@@ -55,7 +55,7 @@ export { MariaDbSessionRestrictionStore, type SessionRestrictionStore, type Sess
|
|
|
55
55
|
export { buildListScopeFn, type ListScopeFn } from './authz/wire-record-authorization.js';
|
|
56
56
|
export { BootSequence, assertPoolBudget } from './boot/boot-sequence.js';
|
|
57
57
|
export { APP_CONFIG } from './config/config.module.js';
|
|
58
|
-
export { loadAppConfig, loadPoolBudget, evaluatePoolBudget, DEFAULT_POOL_BUDGET, SCHEMA_SVC_POOL_HARD_CAP, type AppConfig, type PoolBudgetConfig, type PoolBudgetEvaluation, type RuntimeAccountPools, loadDbConfig, loadRedisConfig, loadSessionLifetimes, loadRefreshHmacKey, assertRefreshHmacKey, DEFAULT_DB_CONFIG, DEFAULT_REDIS_URL, type DbConfig, type RedisConfig, type SessionLifetimeOverrides, loadLoginIpLimit, DEFAULT_LOGIN_IP_LIMIT, isDevOrTestNodeEnv, type LoginIpLimitConfig, } from './config/app-config.js';
|
|
58
|
+
export { loadAppConfig, loadPoolBudget, evaluatePoolBudget, DEFAULT_POOL_BUDGET, SCHEMA_SVC_POOL_HARD_CAP, type AppConfig, type PoolBudgetConfig, type PoolBudgetEvaluation, type RuntimeAccountPools, loadDbConfig, loadRedisConfig, loadSessionLifetimes, loadRefreshHmacKey, assertRefreshHmacKey, DEFAULT_DB_CONFIG, DEFAULT_REDIS_URL, type DbConfig, type RedisConfig, type SessionLifetimeOverrides, loadLoginIpLimit, loadRefreshReplayWindowMs, DEFAULT_LOGIN_IP_LIMIT, isDevOrTestNodeEnv, type LoginIpLimitConfig, } from './config/app-config.js';
|
|
59
59
|
export { SHIELD_REDIS, SHIELD_CREDENTIAL_RESOLVER, SHIELD_PROFILE_RESOLVER, SHIELD_AUTHENTICATOR, SHIELD_SESSION_AUTHORITY, SHIELD_CREDENTIAL_WRITER, SHIELD_RESET_TOKEN_STORE, SHIELD_EMAIL_CHANGE_TOKEN_STORE, SHIELD_EMAIL_SENDER, SHIELD_RECOVERY_CODE_STORE, SHIELD_PROFILE_WRITER, SHIELD_SESSION_SWEEPER, SHIELD_AUDIT_SINK, SHIELD_MFA_DEVICE_STORE, SHIELD_TOTP_VERIFIER_OVERRIDE, } from './auth/tokens.js';
|
|
60
60
|
export { MariaDbCredentialResolver } from './authentication/mariadb-credential-resolver.js';
|
|
61
61
|
export type { SessionView, SessionTokensView, SessionSuccess, LoginRequest, MfaChallengeResponse, LoginResponse, MfaRequest, MfaResponse, RefreshRequest, RefreshResponse, LogoutRequest, LogoutAck, } from './auth/dto.js';
|
|
@@ -73,6 +73,7 @@ export type { EmailAddressChanger, EmailChangeRequest, EmailChangeOutcome, Curre
|
|
|
73
73
|
export type { EmailSender, EmailMessage } from './auth/ports/email-sender.js';
|
|
74
74
|
export type { RecoveryCodeStore } from './auth/ports/recovery-code-store.js';
|
|
75
75
|
export type { ProfileWriter } from './auth/ports/profile-writer.js';
|
|
76
|
+
export { ProfileNameTakenError } from './auth/ports/profile-writer.js';
|
|
76
77
|
export type { SessionSweeper } from './auth/ports/session-sweeper.js';
|
|
77
78
|
export type { MfaDeviceStore, MfaDevice } from './auth/ports/mfa-device-store.js';
|
|
78
79
|
export type { AuditSink, AuthAuditEvent } from './auth/ports/audit-sink.js';
|
package/dist/index.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"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"}
|
package/dist/index.js
CHANGED
|
@@ -16,9 +16,10 @@
|
|
|
16
16
|
* `@nestjs/core`, `reflect-metadata`, `rxjs` so the host owns one copy of each.
|
|
17
17
|
*/
|
|
18
18
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
19
|
-
exports.
|
|
20
|
-
exports.
|
|
21
|
-
exports.
|
|
19
|
+
exports.SHIELD_TOKEN_GENERATOR = exports.systemClockProvider = exports.refreshHasherProvider = exports.cryptoTokenGeneratorProvider = exports.SystemClock = exports.Sha256RefreshTokenHasher = exports.CryptoTokenGenerator = exports.RedisRecentRotationStore = exports.SHIELD_HOT_SESSION_STORE = exports.RedisHotSessionStore = exports.SHIELD_SESSION_RECORD_STORE = exports.MariaDbSessionRecordStore = exports.EncryptedFileSecretsProvider = exports.LocalKekCrypto = exports.SHIELD_PASSWORD_HASHER = exports.argon2idHasherProvider = exports.Argon2idPasswordHasher = exports.stubDecisionAuthority = exports.GlobalEnforcementGuard = exports.NO_SESSION_FACTS = exports.SHIELD_SESSION_FACTS_ALS = exports.MariaDbApiKeyStore = exports.isApiKey = exports.extractBearerToken = exports.principalFromClaims = exports.resolveRequestAuth = exports.resolveRequestPrincipal = exports.SessionTokenBinder = exports.SHIELD_SERVICE_AUTHENTICATOR = exports.SHIELD_SESSION_TOKEN_BINDER = exports.CatalogGatabilityError = exports.CatalogReconciler = exports.OperationInventoryScanner = exports.uuidArrayField = exports.optionalUuidField = exports.uuidField = exports.UuidPipe = exports.normalizeClassification = exports.DEFAULT_CLASSIFIED_ACTION = exports.CLASSIFICATION_METADATA = exports.Classified = exports.Public = exports.SHIELD_RECORD_AUTHORIZATION = exports.SHIELD_DECISION_AUTHORITY = exports.ShieldModule = exports.actionsFor = exports.IDENTITY_ACTIONS = exports.MODULE_KEY = exports.buildIdentityModuleRegistry = exports.guardMigrationsDir = void 0;
|
|
20
|
+
exports.loadSessionLifetimes = exports.loadRedisConfig = exports.loadDbConfig = exports.SCHEMA_SVC_POOL_HARD_CAP = exports.DEFAULT_POOL_BUDGET = exports.evaluatePoolBudget = exports.loadPoolBudget = exports.loadAppConfig = exports.APP_CONFIG = exports.assertPoolBudget = exports.BootSequence = exports.buildListScopeFn = exports.MariaDbSessionRestrictionStore = exports.SHIELD_SESSION_RESTRICTIONS = exports.SHIELD_PERMISSION_VERSION_CACHE = exports.DEFAULT_PERMISSION_VERSION_TTL_MS = exports.PERMISSION_VERSION_KEY_PREFIX = exports.RedisPermissionVersionCache = exports.withRedisPermissionVersion = exports.buildRecordAuthorization = exports.SHIELD_OPERATION_AUTHORITY_PORT = exports.ManifestOperationAuthorityAdapter = exports.GrantStoreUnavailableError = exports.InvalidGrantError = exports.GrantNotPermittedError = exports.SHIELD_CROSS_TENANT_GRANT_WRITER = exports.CrossTenantGrantWriter = exports.SHIELD_CROSS_TENANT_GRANT_PORT = exports.MariaDbCrossTenantGrantAdapter = exports.makeShareDeleteCascade = exports.ShareStoreUnavailableError = exports.ShareNotPermittedError = exports.SHIELD_RECORD_SHARE_WRITER = exports.RecordShareWriter = exports.SHIELD_RECORD_SHARE_PORT = exports.MariaDbRecordShareAdapter = exports.UnknownScopeFieldError = exports.translateListScope = exports.SHIELD_LIST_SCOPE_PORT = exports.MariaDbListScopeAdapter = exports.SHIELD_POLICY_STORE = exports.MariaDbPolicyStore = exports.SHIELD_RECORD_RULE_PORT = exports.MariaDbRecordPermissionRuleAdapter = exports.accessBindingTtlMs = exports.ROTATE_GRACE_MS = exports.SHIELD_SESSION_LIFETIMES = exports.HotRevokingSessionRecordStore = exports.SHIELD_CLOCK = exports.SHIELD_REFRESH_HASHER = void 0;
|
|
21
|
+
exports.buildClosureRows = exports.ConfirmEmailController = exports.AccountController = exports.generateRecoveryCodes = exports.buildOtpauthUri = exports.generateTotpSecret = exports.SHIELD_LOGIN_TOTP_VERIFIER = exports.SHIELD_MFA_STEP_UP = exports.SHIELD_MFA_LIMITER = exports.challengeMatches = exports.credentialFingerprint = exports.CredentialMfaStepUp = exports.RedisPendingMfaStore = exports.PendingMfaStore = exports.AuthController = exports.SHIELD_SCOPE_SUBTREE_RESOLVER = exports.SHIELD_SESSION_FACTS_PROJECTOR = exports.ProfileNameTakenError = exports.MariaDbEmailAddressChanger = exports.maskEmail = exports.isEmailShaped = exports.canonicalEmail = exports.hmacSha1 = exports.resolveTotpVerifier = exports.makeDefaultTotpVerifier = exports.AuthModule = exports.MariaDbCredentialResolver = exports.SHIELD_TOTP_VERIFIER_OVERRIDE = exports.SHIELD_MFA_DEVICE_STORE = exports.SHIELD_AUDIT_SINK = exports.SHIELD_SESSION_SWEEPER = exports.SHIELD_PROFILE_WRITER = exports.SHIELD_RECOVERY_CODE_STORE = exports.SHIELD_EMAIL_SENDER = exports.SHIELD_EMAIL_CHANGE_TOKEN_STORE = exports.SHIELD_RESET_TOKEN_STORE = exports.SHIELD_CREDENTIAL_WRITER = exports.SHIELD_SESSION_AUTHORITY = exports.SHIELD_AUTHENTICATOR = exports.SHIELD_PROFILE_RESOLVER = exports.SHIELD_CREDENTIAL_RESOLVER = exports.SHIELD_REDIS = exports.isDevOrTestNodeEnv = exports.DEFAULT_LOGIN_IP_LIMIT = exports.loadRefreshReplayWindowMs = exports.loadLoginIpLimit = exports.DEFAULT_REDIS_URL = exports.DEFAULT_DB_CONFIG = exports.assertRefreshHmacKey = exports.loadRefreshHmacKey = void 0;
|
|
22
|
+
exports.ScopeUnknownParentError = exports.ScopeDepthError = exports.ScopeCycleError = void 0;
|
|
22
23
|
// Framework authz migrations (shield_authz DDL — permission / role_permission /
|
|
23
24
|
// authz_permission_version). Absolute path a consumer's `@astram/migrate` setup merges in.
|
|
24
25
|
var migrations_dir_js_1 = require("./migrations-dir.js");
|
|
@@ -138,6 +139,8 @@ Object.defineProperty(exports, "MariaDbSessionRecordStore", { enumerable: true,
|
|
|
138
139
|
Object.defineProperty(exports, "SHIELD_SESSION_RECORD_STORE", { enumerable: true, get: function () { return index_js_1.SHIELD_SESSION_RECORD_STORE; } });
|
|
139
140
|
Object.defineProperty(exports, "RedisHotSessionStore", { enumerable: true, get: function () { return index_js_1.RedisHotSessionStore; } });
|
|
140
141
|
Object.defineProperty(exports, "SHIELD_HOT_SESSION_STORE", { enumerable: true, get: function () { return index_js_1.SHIELD_HOT_SESSION_STORE; } });
|
|
142
|
+
// KI #51 / #54 (ADR-0036): the sealed recent-rotation window store.
|
|
143
|
+
Object.defineProperty(exports, "RedisRecentRotationStore", { enumerable: true, get: function () { return index_js_1.RedisRecentRotationStore; } });
|
|
141
144
|
Object.defineProperty(exports, "CryptoTokenGenerator", { enumerable: true, get: function () { return index_js_1.CryptoTokenGenerator; } });
|
|
142
145
|
Object.defineProperty(exports, "Sha256RefreshTokenHasher", { enumerable: true, get: function () { return index_js_1.Sha256RefreshTokenHasher; } });
|
|
143
146
|
Object.defineProperty(exports, "SystemClock", { enumerable: true, get: function () { return index_js_1.SystemClock; } });
|
|
@@ -309,6 +312,7 @@ Object.defineProperty(exports, "DEFAULT_REDIS_URL", { enumerable: true, get: fun
|
|
|
309
312
|
// Security hardening #5/#6 (additive): the per-IP login failure limit (D3) and the
|
|
310
313
|
// raw-NODE_ENV dev/test predicate that gates the dev email logger.
|
|
311
314
|
Object.defineProperty(exports, "loadLoginIpLimit", { enumerable: true, get: function () { return app_config_js_1.loadLoginIpLimit; } });
|
|
315
|
+
Object.defineProperty(exports, "loadRefreshReplayWindowMs", { enumerable: true, get: function () { return app_config_js_1.loadRefreshReplayWindowMs; } });
|
|
312
316
|
Object.defineProperty(exports, "DEFAULT_LOGIN_IP_LIMIT", { enumerable: true, get: function () { return app_config_js_1.DEFAULT_LOGIN_IP_LIMIT; } });
|
|
313
317
|
Object.defineProperty(exports, "isDevOrTestNodeEnv", { enumerable: true, get: function () { return app_config_js_1.isDevOrTestNodeEnv; } });
|
|
314
318
|
// ---------------------------------------------------------------------------
|
|
@@ -377,6 +381,8 @@ Object.defineProperty(exports, "maskEmail", { enumerable: true, get: function ()
|
|
|
377
381
|
// follow, pending-token burn). Guard's confirm route uses it; identity's admin path constructs it.
|
|
378
382
|
var mariadb_email_address_changer_js_1 = require("./authentication/mariadb-email-address-changer.js");
|
|
379
383
|
Object.defineProperty(exports, "MariaDbEmailAddressChanger", { enumerable: true, get: function () { return mariadb_email_address_changer_js_1.MariaDbEmailAddressChanger; } });
|
|
384
|
+
var profile_writer_js_1 = require("./auth/ports/profile-writer.js");
|
|
385
|
+
Object.defineProperty(exports, "ProfileNameTakenError", { enumerable: true, get: function () { return profile_writer_js_1.ProfileNameTakenError; } });
|
|
380
386
|
var tokens_js_5 = require("./auth/tokens.js");
|
|
381
387
|
Object.defineProperty(exports, "SHIELD_SESSION_FACTS_PROJECTOR", { enumerable: true, get: function () { return tokens_js_5.SHIELD_SESSION_FACTS_PROJECTOR; } });
|
|
382
388
|
var tokens_js_6 = require("./auth/tokens.js");
|
package/dist/session/index.d.ts
CHANGED
|
@@ -13,6 +13,7 @@
|
|
|
13
13
|
*/
|
|
14
14
|
export { MariaDbSessionRecordStore, SHIELD_SESSION_RECORD_STORE, } from './mariadb-session-record-store.js';
|
|
15
15
|
export { RedisHotSessionStore, SHIELD_HOT_SESSION_STORE } from './redis-hot-session-store.js';
|
|
16
|
+
export { RedisRecentRotationStore, type RedisRecentRotationStoreOptions, } from './redis-recent-rotation-store.js';
|
|
16
17
|
export { HotRevokingSessionRecordStore, type SessionHotRevoker, type LineageSessionLookup, } from './hot-revoking-session-record-store.js';
|
|
17
18
|
export { SHIELD_SESSION_LIFETIMES, ROTATE_GRACE_MS, DEFAULT_ACCESS_TTL_MS, accessBindingTtlMs, } from './session-lifetimes.js';
|
|
18
19
|
export { CryptoTokenGenerator, Sha256RefreshTokenHasher, SystemClock, cryptoTokenGeneratorProvider, refreshHasherProvider, systemClockProvider, SHIELD_TOKEN_GENERATOR, SHIELD_REFRESH_HASHER, SHIELD_CLOCK, } from './crypto-adapters.js';
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/session/index.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;GAYG;AAEH,OAAO,EACL,yBAAyB,EACzB,2BAA2B,GAC5B,MAAM,mCAAmC,CAAC;AAE3C,OAAO,EAAE,oBAAoB,EAAE,wBAAwB,EAAE,MAAM,8BAA8B,CAAC;AAE9F,OAAO,EACL,6BAA6B,EAC7B,KAAK,iBAAiB,EACtB,KAAK,oBAAoB,GAC1B,MAAM,wCAAwC,CAAC;AAEhD,OAAO,EACL,wBAAwB,EACxB,eAAe,EACf,qBAAqB,EACrB,kBAAkB,GACnB,MAAM,wBAAwB,CAAC;AAEhC,OAAO,EACL,oBAAoB,EACpB,wBAAwB,EACxB,WAAW,EACX,4BAA4B,EAC5B,qBAAqB,EACrB,mBAAmB,EACnB,sBAAsB,EACtB,qBAAqB,EACrB,YAAY,GACb,MAAM,sBAAsB,CAAC"}
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/session/index.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;GAYG;AAEH,OAAO,EACL,yBAAyB,EACzB,2BAA2B,GAC5B,MAAM,mCAAmC,CAAC;AAE3C,OAAO,EAAE,oBAAoB,EAAE,wBAAwB,EAAE,MAAM,8BAA8B,CAAC;AAE9F,OAAO,EACL,wBAAwB,EACxB,KAAK,+BAA+B,GACrC,MAAM,kCAAkC,CAAC;AAE1C,OAAO,EACL,6BAA6B,EAC7B,KAAK,iBAAiB,EACtB,KAAK,oBAAoB,GAC1B,MAAM,wCAAwC,CAAC;AAEhD,OAAO,EACL,wBAAwB,EACxB,eAAe,EACf,qBAAqB,EACrB,kBAAkB,GACnB,MAAM,wBAAwB,CAAC;AAEhC,OAAO,EACL,oBAAoB,EACpB,wBAAwB,EACxB,WAAW,EACX,4BAA4B,EAC5B,qBAAqB,EACrB,mBAAmB,EACnB,sBAAsB,EACtB,qBAAqB,EACrB,YAAY,GACb,MAAM,sBAAsB,CAAC"}
|
package/dist/session/index.js
CHANGED
|
@@ -13,13 +13,15 @@
|
|
|
13
13
|
* A consumer wires these + `createSessionAuthority(...)` from `@astram/core`.
|
|
14
14
|
*/
|
|
15
15
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
16
|
-
exports.SHIELD_CLOCK = exports.SHIELD_REFRESH_HASHER = exports.SHIELD_TOKEN_GENERATOR = exports.systemClockProvider = exports.refreshHasherProvider = exports.cryptoTokenGeneratorProvider = exports.SystemClock = exports.Sha256RefreshTokenHasher = exports.CryptoTokenGenerator = exports.accessBindingTtlMs = exports.DEFAULT_ACCESS_TTL_MS = exports.ROTATE_GRACE_MS = exports.SHIELD_SESSION_LIFETIMES = exports.HotRevokingSessionRecordStore = exports.SHIELD_HOT_SESSION_STORE = exports.RedisHotSessionStore = exports.SHIELD_SESSION_RECORD_STORE = exports.MariaDbSessionRecordStore = void 0;
|
|
16
|
+
exports.SHIELD_CLOCK = exports.SHIELD_REFRESH_HASHER = exports.SHIELD_TOKEN_GENERATOR = exports.systemClockProvider = exports.refreshHasherProvider = exports.cryptoTokenGeneratorProvider = exports.SystemClock = exports.Sha256RefreshTokenHasher = exports.CryptoTokenGenerator = exports.accessBindingTtlMs = exports.DEFAULT_ACCESS_TTL_MS = exports.ROTATE_GRACE_MS = exports.SHIELD_SESSION_LIFETIMES = exports.HotRevokingSessionRecordStore = exports.RedisRecentRotationStore = exports.SHIELD_HOT_SESSION_STORE = exports.RedisHotSessionStore = exports.SHIELD_SESSION_RECORD_STORE = exports.MariaDbSessionRecordStore = void 0;
|
|
17
17
|
var mariadb_session_record_store_js_1 = require("./mariadb-session-record-store.js");
|
|
18
18
|
Object.defineProperty(exports, "MariaDbSessionRecordStore", { enumerable: true, get: function () { return mariadb_session_record_store_js_1.MariaDbSessionRecordStore; } });
|
|
19
19
|
Object.defineProperty(exports, "SHIELD_SESSION_RECORD_STORE", { enumerable: true, get: function () { return mariadb_session_record_store_js_1.SHIELD_SESSION_RECORD_STORE; } });
|
|
20
20
|
var redis_hot_session_store_js_1 = require("./redis-hot-session-store.js");
|
|
21
21
|
Object.defineProperty(exports, "RedisHotSessionStore", { enumerable: true, get: function () { return redis_hot_session_store_js_1.RedisHotSessionStore; } });
|
|
22
22
|
Object.defineProperty(exports, "SHIELD_HOT_SESSION_STORE", { enumerable: true, get: function () { return redis_hot_session_store_js_1.SHIELD_HOT_SESSION_STORE; } });
|
|
23
|
+
var redis_recent_rotation_store_js_1 = require("./redis-recent-rotation-store.js");
|
|
24
|
+
Object.defineProperty(exports, "RedisRecentRotationStore", { enumerable: true, get: function () { return redis_recent_rotation_store_js_1.RedisRecentRotationStore; } });
|
|
23
25
|
var hot_revoking_session_record_store_js_1 = require("./hot-revoking-session-record-store.js");
|
|
24
26
|
Object.defineProperty(exports, "HotRevokingSessionRecordStore", { enumerable: true, get: function () { return hot_revoking_session_record_store_js_1.HotRevokingSessionRecordStore; } });
|
|
25
27
|
var session_lifetimes_js_1 = require("./session-lifetimes.js");
|
|
@@ -0,0 +1,19 @@
|
|
|
1
|
+
import type Redis from 'ioredis';
|
|
2
|
+
import type { RecentRotation, RecentRotationStore } from '@astram/core';
|
|
3
|
+
export interface RedisRecentRotationStoreOptions {
|
|
4
|
+
/** How often `recall` re-reads while waiting (default 25 ms). */
|
|
5
|
+
readonly pollMs?: number;
|
|
6
|
+
}
|
|
7
|
+
export declare class RedisRecentRotationStore implements RecentRotationStore {
|
|
8
|
+
private readonly redis;
|
|
9
|
+
private readonly secret;
|
|
10
|
+
private readonly keyNameKey;
|
|
11
|
+
private readonly pollMs;
|
|
12
|
+
constructor(redis: Redis, serverSecret: string, options?: RedisRecentRotationStoreOptions);
|
|
13
|
+
remember(previousRefreshToken: string, rotation: RecentRotation, ttlMs: number): Promise<void>;
|
|
14
|
+
recall(previousRefreshToken: string, waitMs: number): Promise<RecentRotation | null>;
|
|
15
|
+
private open;
|
|
16
|
+
private keyFor;
|
|
17
|
+
private sealKey;
|
|
18
|
+
}
|
|
19
|
+
//# sourceMappingURL=redis-recent-rotation-store.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"redis-recent-rotation-store.d.ts","sourceRoot":"","sources":["../../src/session/redis-recent-rotation-store.ts"],"names":[],"mappings":"AAqBA,OAAO,KAAK,KAAK,MAAM,SAAS,CAAC;AACjC,OAAO,KAAK,EAAE,cAAc,EAAE,mBAAmB,EAAE,MAAM,cAAc,CAAC;AASxE,MAAM,WAAW,+BAA+B;IAC9C,iEAAiE;IACjE,QAAQ,CAAC,MAAM,CAAC,EAAE,MAAM,CAAC;CAC1B;AAiBD,qBAAa,wBAAyB,YAAW,mBAAmB;IAMhE,OAAO,CAAC,QAAQ,CAAC,KAAK;IALxB,OAAO,CAAC,QAAQ,CAAC,MAAM,CAAS;IAChC,OAAO,CAAC,QAAQ,CAAC,UAAU,CAAS;IACpC,OAAO,CAAC,QAAQ,CAAC,MAAM,CAAS;gBAGb,KAAK,EAAE,KAAK,EAC7B,YAAY,EAAE,MAAM,EACpB,OAAO,GAAE,+BAAoC;IAYzC,QAAQ,CACZ,oBAAoB,EAAE,MAAM,EAC5B,QAAQ,EAAE,cAAc,EACxB,KAAK,EAAE,MAAM,GACZ,OAAO,CAAC,IAAI,CAAC;IAqBV,MAAM,CAAC,oBAAoB,EAAE,MAAM,EAAE,MAAM,EAAE,MAAM,GAAG,OAAO,CAAC,cAAc,GAAG,IAAI,CAAC;IAW1F,OAAO,CAAC,IAAI;IAkBZ,OAAO,CAAC,MAAM;IAOd,OAAO,CAAC,OAAO;CAKhB"}
|
|
@@ -0,0 +1,115 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.RedisRecentRotationStore = void 0;
|
|
4
|
+
/**
|
|
5
|
+
* `RedisRecentRotationStore` — the guard adapter for core's OPTIONAL {@link RecentRotationStore}
|
|
6
|
+
* port (KI #51 / KI #54, ADR-0036): remembers a rotation's successor pair for a few seconds so a
|
|
7
|
+
* repeated refresh of the same token gets the SAME pair instead of killing the lineage.
|
|
8
|
+
*
|
|
9
|
+
* The pair is made of RAW tokens, so it is never stored in the clear:
|
|
10
|
+
* - key `shield:rotated:<HMAC-SHA-256(K_name, old token)>`, K_name = HKDF(server secret, info
|
|
11
|
+
* 'astram/recent-rotation/key-name') — no token in it, and never equal to a refresh-token
|
|
12
|
+
* hash (those are HMAC under the raw secret);
|
|
13
|
+
* - value AES-256-GCM over the JSON pair, under a key derived (HKDF-SHA-256) from the OLD raw
|
|
14
|
+
* refresh token with the server secret as salt; the Redis key is the AAD (a value moved under
|
|
15
|
+
* another key does not open). Only a caller presenting the old token can open it; Redis alone
|
|
16
|
+
* (or the DB, which holds only HMAC hashes) yields nothing usable.
|
|
17
|
+
* - `SET … PX <window> NX` (first write wins).
|
|
18
|
+
*
|
|
19
|
+
* `recall` polls for up to `waitMs` (a concurrent winner may still be writing). A malformed,
|
|
20
|
+
* tampered or foreign value is `null`; a Redis error propagates, and the engine treats it as no
|
|
21
|
+
* entry, so the replay revokes the lineage (fail closed). The engine re-proves every answer against
|
|
22
|
+
* the durable store, so this adapter can never create a session on its own.
|
|
23
|
+
*/
|
|
24
|
+
const node_crypto_1 = require("node:crypto");
|
|
25
|
+
const KEY_PREFIX = 'shield:rotated:';
|
|
26
|
+
const HKDF_INFO = 'astram/recent-rotation/v1';
|
|
27
|
+
const KEY_NAME_INFO = 'astram/recent-rotation/key-name';
|
|
28
|
+
const IV_BYTES = 12;
|
|
29
|
+
const TAG_BYTES = 16;
|
|
30
|
+
const DEFAULT_POLL_MS = 25;
|
|
31
|
+
function sleep(ms) {
|
|
32
|
+
return new Promise((resolve) => setTimeout(resolve, ms));
|
|
33
|
+
}
|
|
34
|
+
function isRotation(value) {
|
|
35
|
+
if (value === null || typeof value !== 'object')
|
|
36
|
+
return false;
|
|
37
|
+
const v = value;
|
|
38
|
+
return (typeof v.accessToken === 'string' &&
|
|
39
|
+
typeof v.refreshToken === 'string' &&
|
|
40
|
+
typeof v.accessExpiresAtMs === 'number' &&
|
|
41
|
+
typeof v.rotatedAtMs === 'number');
|
|
42
|
+
}
|
|
43
|
+
class RedisRecentRotationStore {
|
|
44
|
+
redis;
|
|
45
|
+
secret;
|
|
46
|
+
keyNameKey;
|
|
47
|
+
pollMs;
|
|
48
|
+
constructor(redis, serverSecret, options = {}) {
|
|
49
|
+
this.redis = redis;
|
|
50
|
+
if (typeof serverSecret !== 'string' || serverSecret.length === 0) {
|
|
51
|
+
throw new Error('RedisRecentRotationStore: a non-empty server secret is required');
|
|
52
|
+
}
|
|
53
|
+
this.secret = Buffer.from(serverSecret, 'utf8');
|
|
54
|
+
this.keyNameKey = Buffer.from((0, node_crypto_1.hkdfSync)('sha256', this.secret, Buffer.alloc(0), KEY_NAME_INFO, 32));
|
|
55
|
+
this.pollMs = Math.max(1, Math.floor(options.pollMs ?? DEFAULT_POLL_MS));
|
|
56
|
+
}
|
|
57
|
+
async remember(previousRefreshToken, rotation, ttlMs) {
|
|
58
|
+
const key = this.keyFor(previousRefreshToken);
|
|
59
|
+
const iv = (0, node_crypto_1.randomBytes)(IV_BYTES);
|
|
60
|
+
const cipher = (0, node_crypto_1.createCipheriv)('aes-256-gcm', this.sealKey(previousRefreshToken), iv);
|
|
61
|
+
cipher.setAAD(Buffer.from(key, 'utf8'));
|
|
62
|
+
const body = Buffer.concat([
|
|
63
|
+
cipher.update(JSON.stringify({
|
|
64
|
+
accessToken: rotation.accessToken,
|
|
65
|
+
refreshToken: rotation.refreshToken,
|
|
66
|
+
accessExpiresAtMs: rotation.accessExpiresAtMs,
|
|
67
|
+
rotatedAtMs: rotation.rotatedAtMs,
|
|
68
|
+
}), 'utf8'),
|
|
69
|
+
cipher.final(),
|
|
70
|
+
]);
|
|
71
|
+
const sealed = Buffer.concat([iv, cipher.getAuthTag(), body]).toString('base64');
|
|
72
|
+
await this.redis.set(key, sealed, 'PX', Math.max(1, Math.floor(ttlMs)), 'NX');
|
|
73
|
+
}
|
|
74
|
+
async recall(previousRefreshToken, waitMs) {
|
|
75
|
+
const key = this.keyFor(previousRefreshToken);
|
|
76
|
+
const deadline = Date.now() + Math.max(0, waitMs);
|
|
77
|
+
for (;;) {
|
|
78
|
+
const sealed = await this.redis.get(key);
|
|
79
|
+
if (sealed !== null)
|
|
80
|
+
return this.open(previousRefreshToken, key, sealed);
|
|
81
|
+
if (Date.now() >= deadline)
|
|
82
|
+
return null;
|
|
83
|
+
await sleep(Math.min(this.pollMs, Math.max(1, deadline - Date.now())));
|
|
84
|
+
}
|
|
85
|
+
}
|
|
86
|
+
open(previousRefreshToken, key, sealed) {
|
|
87
|
+
try {
|
|
88
|
+
const raw = Buffer.from(sealed, 'base64');
|
|
89
|
+
if (raw.length <= IV_BYTES + TAG_BYTES)
|
|
90
|
+
return null;
|
|
91
|
+
const iv = raw.subarray(0, IV_BYTES);
|
|
92
|
+
const tag = raw.subarray(IV_BYTES, IV_BYTES + TAG_BYTES);
|
|
93
|
+
const body = raw.subarray(IV_BYTES + TAG_BYTES);
|
|
94
|
+
const decipher = (0, node_crypto_1.createDecipheriv)('aes-256-gcm', this.sealKey(previousRefreshToken), iv);
|
|
95
|
+
decipher.setAAD(Buffer.from(key, 'utf8'));
|
|
96
|
+
decipher.setAuthTag(tag);
|
|
97
|
+
const json = Buffer.concat([decipher.update(body), decipher.final()]).toString('utf8');
|
|
98
|
+
const parsed = JSON.parse(json);
|
|
99
|
+
return isRotation(parsed) ? parsed : null;
|
|
100
|
+
}
|
|
101
|
+
catch {
|
|
102
|
+
return null; // wrong token, wrong secret, tampered or malformed
|
|
103
|
+
}
|
|
104
|
+
}
|
|
105
|
+
keyFor(previousRefreshToken) {
|
|
106
|
+
const digest = (0, node_crypto_1.createHmac)('sha256', this.keyNameKey)
|
|
107
|
+
.update(previousRefreshToken, 'utf8')
|
|
108
|
+
.digest('hex');
|
|
109
|
+
return `${KEY_PREFIX}${digest}`;
|
|
110
|
+
}
|
|
111
|
+
sealKey(previousRefreshToken) {
|
|
112
|
+
return Buffer.from((0, node_crypto_1.hkdfSync)('sha256', Buffer.from(previousRefreshToken, 'utf8'), this.secret, HKDF_INFO, 32));
|
|
113
|
+
}
|
|
114
|
+
}
|
|
115
|
+
exports.RedisRecentRotationStore = RedisRecentRotationStore;
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@astram/guard",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.12.0",
|
|
4
4
|
"license": "MIT",
|
|
5
5
|
"description": "Astram framework — the enforcement guard + real-world adapters (the 'hands'). One global deny-by-default gate every request passes through (ADR-0002), classification decorators, boot-pool assertion (ADR-0018), the forRoot() registration seam, and the DB/Redis/crypto adapters that connect the sealed core to a real backend. Depends on @astram/core (ADR-0003, ADR-0023).",
|
|
6
6
|
"type": "commonjs",
|
|
@@ -35,8 +35,8 @@
|
|
|
35
35
|
"argon2": "^0.41.1",
|
|
36
36
|
"ioredis": "^5.4.1",
|
|
37
37
|
"mariadb": "^3.5.4",
|
|
38
|
-
"@astram/engine": "0.5.
|
|
39
|
-
"@astram/core": "1.
|
|
38
|
+
"@astram/engine": "0.5.3",
|
|
39
|
+
"@astram/core": "1.5.0"
|
|
40
40
|
},
|
|
41
41
|
"peerDependencies": {
|
|
42
42
|
"@nestjs/common": "^11",
|