@astram/guard 0.16.0 → 0.18.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 +3 -1
- package/dist/auth/account.controller.d.ts.map +1 -1
- package/dist/auth/account.controller.js +10 -6
- package/dist/auth/auth.controller.d.ts +3 -1
- package/dist/auth/auth.controller.d.ts.map +1 -1
- package/dist/auth/auth.controller.js +13 -11
- package/dist/auth/auth.module.d.ts +14 -2
- package/dist/auth/auth.module.d.ts.map +1 -1
- package/dist/auth/auth.module.js +54 -7
- package/dist/auth/confirm-email.controller.d.ts +3 -1
- package/dist/auth/confirm-email.controller.d.ts.map +1 -1
- package/dist/auth/confirm-email.controller.js +9 -5
- package/dist/auth/email-change-messages.d.ts +2 -0
- package/dist/auth/email-change-messages.d.ts.map +1 -1
- package/dist/auth/email-change-messages.js +2 -0
- package/dist/auth/password-reset-message.d.ts +7 -0
- package/dist/auth/password-reset-message.d.ts.map +1 -0
- package/dist/auth/password-reset-message.js +17 -0
- package/dist/auth/ports/email-sender.d.ts +7 -7
- package/dist/auth/ports/email-sender.d.ts.map +1 -1
- package/dist/auth/tokens.d.ts +14 -0
- package/dist/auth/tokens.d.ts.map +1 -1
- package/dist/auth/tokens.js +15 -1
- package/dist/authentication/argon2id-password-hasher.d.ts +3 -0
- package/dist/authentication/argon2id-password-hasher.d.ts.map +1 -1
- package/dist/authentication/argon2id-password-hasher.js +21 -0
- package/dist/authentication/credential-provisioner.d.ts +35 -0
- package/dist/authentication/credential-provisioner.d.ts.map +1 -0
- package/dist/authentication/credential-provisioner.js +16 -0
- package/dist/authentication/mariadb-credential-provisioner.d.ts +27 -0
- package/dist/authentication/mariadb-credential-provisioner.d.ts.map +1 -0
- package/dist/authentication/mariadb-credential-provisioner.js +95 -0
- package/dist/authz/operation-marker-check.d.ts +14 -0
- package/dist/authz/operation-marker-check.d.ts.map +1 -0
- package/dist/authz/operation-marker-check.js +25 -0
- package/dist/authz/wire-record-authorization.d.ts.map +1 -1
- package/dist/authz/wire-record-authorization.js +3 -2
- package/dist/config/message-config.d.ts +70 -0
- package/dist/config/message-config.d.ts.map +1 -0
- package/dist/config/message-config.js +249 -0
- package/dist/config/reserved-principal-ids.d.ts +14 -0
- package/dist/config/reserved-principal-ids.d.ts.map +1 -0
- package/dist/config/reserved-principal-ids.js +24 -0
- package/dist/config/root-ids-from-env.d.ts +2 -0
- package/dist/config/root-ids-from-env.d.ts.map +1 -0
- package/dist/config/root-ids-from-env.js +41 -0
- package/dist/index.d.ts +10 -2
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +24 -4
- package/dist/internal.d.ts +11 -0
- package/dist/internal.d.ts.map +1 -1
- package/dist/internal.js +15 -1
- package/dist/messaging/deliver-email.d.ts +10 -0
- package/dist/messaging/deliver-email.d.ts.map +1 -0
- package/dist/messaging/deliver-email.js +19 -0
- package/dist/messaging/email-delivery.d.ts +42 -0
- package/dist/messaging/email-delivery.d.ts.map +1 -0
- package/dist/messaging/email-delivery.js +117 -0
- package/dist/messaging/message-dispatcher.d.ts +66 -0
- package/dist/messaging/message-dispatcher.d.ts.map +1 -0
- package/dist/messaging/message-dispatcher.js +133 -0
- package/dist/messaging/recipient-mask.d.ts +7 -0
- package/dist/messaging/recipient-mask.d.ts.map +1 -0
- package/dist/messaging/recipient-mask.js +15 -0
- package/dist/module/shield.module.d.ts +5 -3
- package/dist/module/shield.module.d.ts.map +1 -1
- package/dist/module/shield.module.js +4 -0
- package/package.json +10 -5
|
@@ -46,6 +46,7 @@ import type { FactorVerifier, PasswordHasher } from '@astram/core';
|
|
|
46
46
|
import type { SessionTokenBinder } from '../request-auth/session-token-binder.js';
|
|
47
47
|
import type { AuditSink } from './ports/audit-sink.js';
|
|
48
48
|
import type { EmailSender } from './ports/email-sender.js';
|
|
49
|
+
import type { MessageDispatcher } from '../messaging/message-dispatcher.js';
|
|
49
50
|
import type { EmailChangeTokenStore } from './ports/email-change-token-store.js';
|
|
50
51
|
import type { EmailAddressChanger } from './ports/email-address-changer.js';
|
|
51
52
|
import type { SessionRestrictionStore } from '../session/session-restriction-store.js';
|
|
@@ -85,7 +86,8 @@ export declare class AccountController {
|
|
|
85
86
|
private readonly emailChangeLinkBaseUrl?;
|
|
86
87
|
private readonly emailChangeLimiter?;
|
|
87
88
|
private readonly auditSink?;
|
|
88
|
-
|
|
89
|
+
private readonly messageDispatcher?;
|
|
90
|
+
constructor(binder?: SessionTokenBinder | undefined, hasher?: PasswordHasher | undefined, writer?: (CredentialWriter | null) | undefined, sweeper?: (SessionSweeper | null) | undefined, recoveryCodes?: (RecoveryCodeStore | null) | undefined, totpVerifier?: (FactorVerifier | null) | undefined, profileResolver?: (ProfileResolver | null) | undefined, profileWriter?: (ProfileWriter | null) | undefined, mfaDevices?: (MfaDeviceStore | null) | undefined, sessionRestrictions?: (SessionRestrictionStore | null) | undefined, loginTotpVerifier?: (FactorVerifier | null) | undefined, mfaLimiter?: (AttemptLimiter | null) | undefined, loginLimiter?: (AttemptLimiter | null) | undefined, emailChangeTokens?: (EmailChangeTokenStore | null) | undefined, emailAddresses?: (EmailAddressChanger | null) | undefined, emailSender?: (EmailSender | null) | undefined, emailChangeLinkBaseUrl?: string | null | undefined, emailChangeLimiter?: (AttemptLimiter | null) | undefined, auditSink?: (AuditSink | null) | undefined, messageDispatcher?: (MessageDispatcher | null) | undefined);
|
|
89
91
|
/**
|
|
90
92
|
* Resolve a human-readable otpauth account LABEL for the caller (email, else display
|
|
91
93
|
* name) via the profile resolver. Best-effort: no resolver / null profile / a thrown
|
|
@@ -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;
|
|
1
|
+
{"version":3,"file":"account.controller.d.ts","sourceRoot":"","sources":["../../src/auth/account.controller.ts"],"names":[],"mappings":"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"}
|
|
@@ -64,6 +64,7 @@ const classification_decorator_js_1 = require("../enforcement/classification.dec
|
|
|
64
64
|
const request_principal_js_1 = require("../request-auth/request-principal.js");
|
|
65
65
|
const tokens_js_1 = require("../request-auth/tokens.js");
|
|
66
66
|
const tokens_js_2 = require("./tokens.js");
|
|
67
|
+
const deliver_email_js_1 = require("../messaging/deliver-email.js");
|
|
67
68
|
const email_address_js_1 = require("./email-address.js");
|
|
68
69
|
const email_change_messages_js_1 = require("./email-change-messages.js");
|
|
69
70
|
const canonical_hint_js_1 = require("./rate-limit/canonical-hint.js");
|
|
@@ -212,7 +213,8 @@ let AccountController = class AccountController {
|
|
|
212
213
|
emailChangeLinkBaseUrl;
|
|
213
214
|
emailChangeLimiter;
|
|
214
215
|
auditSink;
|
|
215
|
-
|
|
216
|
+
messageDispatcher;
|
|
217
|
+
constructor(binder, hasher, writer, sweeper, recoveryCodes, totpVerifier, profileResolver, profileWriter, mfaDevices, sessionRestrictions, loginTotpVerifier, mfaLimiter, loginLimiter, emailChangeTokens, emailAddresses, emailSender, emailChangeLinkBaseUrl, emailChangeLimiter, auditSink, messageDispatcher) {
|
|
216
218
|
this.binder = binder;
|
|
217
219
|
this.hasher = hasher;
|
|
218
220
|
this.writer = writer;
|
|
@@ -232,6 +234,7 @@ let AccountController = class AccountController {
|
|
|
232
234
|
this.emailChangeLinkBaseUrl = emailChangeLinkBaseUrl;
|
|
233
235
|
this.emailChangeLimiter = emailChangeLimiter;
|
|
234
236
|
this.auditSink = auditSink;
|
|
237
|
+
this.messageDispatcher = messageDispatcher;
|
|
235
238
|
}
|
|
236
239
|
/**
|
|
237
240
|
* Resolve a human-readable otpauth account LABEL for the caller (email, else display
|
|
@@ -577,10 +580,9 @@ let AccountController = class AccountController {
|
|
|
577
580
|
}
|
|
578
581
|
}
|
|
579
582
|
const link = (0, email_change_messages_js_1.emailChangeLink)(this.emailChangeLinkBaseUrl ?? email_change_messages_js_1.DEFAULT_EMAIL_CHANGE_LINK_BASE_URL, rawToken);
|
|
580
|
-
|
|
581
|
-
|
|
582
|
-
|
|
583
|
-
catch {
|
|
583
|
+
// G-010: bounded and audited (purpose `email_change_confirm`).
|
|
584
|
+
const delivered = await (0, deliver_email_js_1.deliverEmail)(this.messageDispatcher, sender, 'email_change_confirm', (0, email_change_messages_js_1.confirmEmailChangeMessage)(email, link), { actorId: claims.id, tenantId: claims.tenantId });
|
|
585
|
+
if (delivered === 'failed') {
|
|
584
586
|
// Undeliverable: burn the token so no orphan link can be used later, and say "retry".
|
|
585
587
|
await tokens.invalidateAllForPrincipal(claims.id).catch(() => undefined);
|
|
586
588
|
retryableUnavailable();
|
|
@@ -1041,5 +1043,7 @@ exports.AccountController = AccountController = __decorate([
|
|
|
1041
1043
|
__param(17, (0, common_1.Inject)(tokens_js_2.SHIELD_EMAIL_CHANGE_LIMITER)),
|
|
1042
1044
|
__param(18, (0, common_1.Optional)()),
|
|
1043
1045
|
__param(18, (0, common_1.Inject)(tokens_js_2.SHIELD_AUDIT_SINK)),
|
|
1044
|
-
|
|
1046
|
+
__param(19, (0, common_1.Optional)()),
|
|
1047
|
+
__param(19, (0, common_1.Inject)(tokens_js_2.SHIELD_MESSAGE_DISPATCHER)),
|
|
1048
|
+
__metadata("design:paramtypes", [Function, Object, Object, Object, Object, Object, Object, Object, Object, Object, Object, Object, Object, Object, Object, Object, Object, Object, Object, Object])
|
|
1045
1049
|
], AccountController);
|
|
@@ -69,6 +69,7 @@ import type { CurrentUserProfile, ProfileResolver } from './profile-resolver.js'
|
|
|
69
69
|
import type { CredentialResolver } from '@astram/core';
|
|
70
70
|
import type { ResetTokenStore } from './ports/reset-token-store.js';
|
|
71
71
|
import type { EmailSender } from './ports/email-sender.js';
|
|
72
|
+
import type { MessageDispatcher } from '../messaging/message-dispatcher.js';
|
|
72
73
|
import type { CredentialWriter } from './ports/credential-writer.js';
|
|
73
74
|
import type { SessionSweeper } from './ports/session-sweeper.js';
|
|
74
75
|
import type { RecoveryCodeStore } from './ports/recovery-code-store.js';
|
|
@@ -115,7 +116,8 @@ export declare class AuthController {
|
|
|
115
116
|
private readonly sessionRecords?;
|
|
116
117
|
private readonly sessionRestrictions?;
|
|
117
118
|
private readonly emailChangeTokens?;
|
|
118
|
-
|
|
119
|
+
private readonly messageDispatcher?;
|
|
120
|
+
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);
|
|
119
121
|
/**
|
|
120
122
|
* The access-token binding TTL for an establishment (security hardening #8):
|
|
121
123
|
* `clamp(session.expiresAtMs − now, 1, accessTtlMs)` — on login AND refresh. Never derived
|
|
@@ -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;
|
|
1
|
+
{"version":3,"file":"auth.controller.d.ts","sourceRoot":"","sources":["../../src/auth/auth.controller.ts"],"names":[],"mappings":"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"}
|
|
@@ -85,6 +85,8 @@ const tokens_js_2 = require("../request-auth/tokens.js");
|
|
|
85
85
|
const session_token_binder_js_1 = require("../request-auth/session-token-binder.js");
|
|
86
86
|
const request_principal_js_1 = require("../request-auth/request-principal.js");
|
|
87
87
|
const tokens_js_3 = require("./tokens.js");
|
|
88
|
+
const deliver_email_js_1 = require("../messaging/deliver-email.js");
|
|
89
|
+
const password_reset_message_js_1 = require("./password-reset-message.js");
|
|
88
90
|
/**
|
|
89
91
|
* The core `Authenticator`'s generic transient reason (see authenticator.ts —
|
|
90
92
|
* `REASON_AUTH_UNAVAILABLE`). A `rejected` result carrying THIS reason is the
|
|
@@ -218,7 +220,8 @@ let AuthController = class AuthController {
|
|
|
218
220
|
sessionRecords;
|
|
219
221
|
sessionRestrictions;
|
|
220
222
|
emailChangeTokens;
|
|
221
|
-
|
|
223
|
+
messageDispatcher;
|
|
224
|
+
constructor(authenticator, sessionAuthority, pendingMfa, tokenBinder, profileResolver, credentialResolver, resetTokenStore, emailSender, credentialWriter, sessionSweeper, passwordHasher, resetLinkBaseUrl, recoveryCodes, loginLimiter, loginIpLimiter, trustProxyCheck, recoveryLimiter, forgotLimiter, forgotHintLimiter, resetLimiter, auditSink, sessionFactsProjector, scopeSubtreeResolver, membershipChecker, permissionFacts, mfaLimiter, mfaStepUp, clock, lifetimes, rootIds, sessionRecords, sessionRestrictions, emailChangeTokens, messageDispatcher) {
|
|
222
225
|
this.authenticator = authenticator;
|
|
223
226
|
this.sessionAuthority = sessionAuthority;
|
|
224
227
|
this.pendingMfa = pendingMfa;
|
|
@@ -252,6 +255,7 @@ let AuthController = class AuthController {
|
|
|
252
255
|
this.sessionRecords = sessionRecords;
|
|
253
256
|
this.sessionRestrictions = sessionRestrictions;
|
|
254
257
|
this.emailChangeTokens = emailChangeTokens;
|
|
258
|
+
this.messageDispatcher = messageDispatcher;
|
|
255
259
|
}
|
|
256
260
|
/**
|
|
257
261
|
* The access-token binding TTL for an establishment (security hardening #8):
|
|
@@ -998,15 +1002,11 @@ let AuthController = class AuthController {
|
|
|
998
1002
|
});
|
|
999
1003
|
if (!profile?.email)
|
|
1000
1004
|
return;
|
|
1001
|
-
// The framework composes the link (EmailSender stays URL-agnostic).
|
|
1005
|
+
// The framework composes the link (EmailSender stays URL-agnostic); the HTML escapes it.
|
|
1002
1006
|
const base = this.resetLinkBaseUrl ?? 'http://localhost:5173/reset-password';
|
|
1003
1007
|
const link = `${base}?token=${rawToken}`;
|
|
1004
|
-
|
|
1005
|
-
|
|
1006
|
-
subject: 'Reset your password',
|
|
1007
|
-
text: `Reset your password: ${link}`,
|
|
1008
|
-
html: `<p>Reset your password: <a href="${link}">${link}</a></p>`,
|
|
1009
|
-
});
|
|
1008
|
+
// G-010: bounded and audited (`message.sent` / `message.failed`, purpose `password_reset`).
|
|
1009
|
+
await (0, deliver_email_js_1.deliverEmail)(this.messageDispatcher, sender, 'password_reset', (0, password_reset_message_js_1.passwordResetMessage)(profile.email, link), { actorId: principalId, tenantId });
|
|
1010
1010
|
}
|
|
1011
1011
|
/**
|
|
1012
1012
|
* `POST /auth/reset-password` — complete a password reset with the emailed token.
|
|
@@ -1345,7 +1345,7 @@ let AuthController = class AuthController {
|
|
|
1345
1345
|
});
|
|
1346
1346
|
if (!profile?.email)
|
|
1347
1347
|
return; // no email on file → cannot notify (login unaffected)
|
|
1348
|
-
await
|
|
1348
|
+
await (0, deliver_email_js_1.deliverEmail)(this.messageDispatcher, sender, 'security_notice', {
|
|
1349
1349
|
to: profile.email,
|
|
1350
1350
|
subject: 'A recovery code was used to sign in',
|
|
1351
1351
|
text: 'A recovery code was just used to sign in to your account. ' +
|
|
@@ -1355,7 +1355,7 @@ let AuthController = class AuthController {
|
|
|
1355
1355
|
'<p>If this was you, you can ignore this message. If this was <strong>not</strong> ' +
|
|
1356
1356
|
'you, secure your account now: change your password and re-enroll a new ' +
|
|
1357
1357
|
'authenticator device.</p>',
|
|
1358
|
-
});
|
|
1358
|
+
}, { actorId: principalId, tenantId });
|
|
1359
1359
|
})().catch(() => {
|
|
1360
1360
|
/* best-effort: a resolver/email failure never fails the login */
|
|
1361
1361
|
});
|
|
@@ -1788,7 +1788,9 @@ exports.AuthController = AuthController = __decorate([
|
|
|
1788
1788
|
__param(31, (0, common_1.Inject)(tokens_js_1.SHIELD_SESSION_RESTRICTIONS)),
|
|
1789
1789
|
__param(32, (0, common_2.Optional)()),
|
|
1790
1790
|
__param(32, (0, common_1.Inject)(tokens_js_1.SHIELD_EMAIL_CHANGE_TOKEN_STORE)),
|
|
1791
|
-
|
|
1791
|
+
__param(33, (0, common_2.Optional)()),
|
|
1792
|
+
__param(33, (0, common_1.Inject)(tokens_js_1.SHIELD_MESSAGE_DISPATCHER)),
|
|
1793
|
+
__metadata("design:paramtypes", [Object, Object, pending_mfa_store_js_1.PendingMfaStore, Function, Object, Object, Object, Object, Object, Object, Object, String, Object, Object, Object, Object, Object, Object, Object, Object, Object, Object, Object, Object, Object, Object, Object, Object, Object, Object, Object, Object, Object, Object])
|
|
1792
1794
|
], AuthController);
|
|
1793
1795
|
/**
|
|
1794
1796
|
* Narrow an `authenticated` result to its guaranteed principal. The core engine
|
|
@@ -67,6 +67,7 @@ import type { CredentialResolver, HmacSha1, FactorVerifier } from '@astram/core'
|
|
|
67
67
|
import type { SessionFactsProjector } from './ports/session-facts-projector.js';
|
|
68
68
|
import type { ScopeSubtreeResolver } from './ports/scope-subtree-resolver.js';
|
|
69
69
|
import type { MembershipChecker } from './ports/membership-checker.js';
|
|
70
|
+
import { AttemptLimiter, type AttemptLimiterConfig } from './rate-limit/attempt-limiter.js';
|
|
70
71
|
import type { ProfileResolver } from './profile-resolver.js';
|
|
71
72
|
import type { CredentialWriter } from './ports/credential-writer.js';
|
|
72
73
|
import type { ResetTokenStore } from './ports/reset-token-store.js';
|
|
@@ -150,9 +151,13 @@ export interface AuthModuleOptions {
|
|
|
150
151
|
* delivered or printed, one startup warning;
|
|
151
152
|
* - omitted → the dev `LogEmailSender` (prints reset links to stdout) ONLY when the raw
|
|
152
153
|
* `NODE_ENV` is `development` or `test`; otherwise (incl. unset `NODE_ENV`) auth
|
|
153
|
-
* composition throws "auth:true requires `emailSender` (or `emailSender: 'disabled'`)"
|
|
154
|
+
* composition throws "auth:true requires `emailSender` (or `emailSender: 'disabled'`)";
|
|
155
|
+
* - `'env'` (G-010) → the provider named by `EMAIL_PROVIDER` (smtp, brevo, sendgrid,
|
|
156
|
+
* mailgun or disabled), built by the optional peer `@astram/messaging`; bad config refuses
|
|
157
|
+
* boot (`loadMessageConfig`).
|
|
158
|
+
* Every framework send goes through `SHIELD_MESSAGE_DISPATCHER` (bounded, audited).
|
|
154
159
|
*/
|
|
155
|
-
readonly emailSender?: EmailSender | 'disabled';
|
|
160
|
+
readonly emailSender?: EmailSender | 'disabled' | 'env';
|
|
156
161
|
readonly recoveryCodeStore?: RecoveryCodeStore;
|
|
157
162
|
readonly profileWriter?: ProfileWriter;
|
|
158
163
|
readonly sessionSweeper?: SessionSweeper;
|
|
@@ -234,6 +239,13 @@ export interface AuthModuleOptions {
|
|
|
234
239
|
*/
|
|
235
240
|
readonly emailChangeLinkBaseUrl?: string;
|
|
236
241
|
}
|
|
242
|
+
/**
|
|
243
|
+
* The per-account email-change REQUEST limiter (Phase 12) — `email-change:pid:<id>`, 3 per 60-min
|
|
244
|
+
* window, so the route cannot spam an inbox. `consume` fails closed (503).
|
|
245
|
+
*/
|
|
246
|
+
/** Builds guard limiters for identity's invite (G-010 P-5); see {@link SHIELD_ATTEMPT_LIMITER_FACTORY}. */
|
|
247
|
+
export type AttemptLimiterFactory = (cfg: AttemptLimiterConfig) => AttemptLimiter;
|
|
248
|
+
export declare const attemptLimiterFactoryProvider: Provider;
|
|
237
249
|
/**
|
|
238
250
|
* The no-override default sender decision (pure apart from the warning). Exported for
|
|
239
251
|
* the unit test only — not part of the package's public surface.
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"auth.module.d.ts","sourceRoot":"","sources":["../../src/auth/auth.module.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GA+DG;AAEH,OAAO,EAGL,KAAK,aAAa,EAElB,KAAK,QAAQ,EACd,MAAM,gBAAgB,CAAC;AAaxB,OAAO,KAAK,EAGV,kBAAkB,EAOlB,QAAQ,EACR,cAAc,EAIf,MAAM,cAAc,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
|
@@ -104,7 +104,7 @@ var __importStar = (this && this.__importStar) || (function () {
|
|
|
104
104
|
})();
|
|
105
105
|
var AuthModule_1;
|
|
106
106
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
107
|
-
exports.AuthModule = exports.singleLayoutProbeProvider = exports.SHIELD_SINGLE_LAYOUT_PROBE = exports.hmacSha1 = void 0;
|
|
107
|
+
exports.AuthModule = exports.attemptLimiterFactoryProvider = exports.singleLayoutProbeProvider = exports.SHIELD_SINGLE_LAYOUT_PROBE = exports.hmacSha1 = void 0;
|
|
108
108
|
exports.resolveTotpVerifier = resolveTotpVerifier;
|
|
109
109
|
exports.makeDefaultTotpVerifier = makeDefaultTotpVerifier;
|
|
110
110
|
exports.resolveDefaultEmailSender = resolveDefaultEmailSender;
|
|
@@ -145,6 +145,8 @@ const permission_version_cache_js_1 = require("../authz/permission-version-cache
|
|
|
145
145
|
const session_restriction_store_js_1 = require("../session/session-restriction-store.js");
|
|
146
146
|
const attempt_limiter_js_1 = require("./rate-limit/attempt-limiter.js");
|
|
147
147
|
const trust_proxy_check_js_1 = require("./rate-limit/trust-proxy-check.js");
|
|
148
|
+
const email_delivery_js_1 = require("../messaging/email-delivery.js");
|
|
149
|
+
const message_dispatcher_js_1 = require("../messaging/message-dispatcher.js");
|
|
148
150
|
const tokens_js_2 = require("../request-auth/tokens.js");
|
|
149
151
|
const mariadb_api_key_store_js_1 = require("../authentication/mariadb-api-key-store.js");
|
|
150
152
|
const core_1 = require("@astram/core");
|
|
@@ -741,10 +743,11 @@ const emailAddressChangerProvider = {
|
|
|
741
743
|
useFactory: (pool, config) => new mariadb_email_address_changer_js_1.MariaDbEmailAddressChanger(pool, undefined, (0, app_config_js_1.frameworkSchemasOf)(config)),
|
|
742
744
|
inject: [tokens_js_1.SHIELD_DB_POOL, config_module_js_1.APP_CONFIG],
|
|
743
745
|
};
|
|
744
|
-
|
|
745
|
-
|
|
746
|
-
|
|
747
|
-
|
|
746
|
+
exports.attemptLimiterFactoryProvider = {
|
|
747
|
+
provide: tokens_js_1.SHIELD_ATTEMPT_LIMITER_FACTORY,
|
|
748
|
+
useFactory: (redis) => (cfg) => new attempt_limiter_js_1.AttemptLimiter(redis, cfg),
|
|
749
|
+
inject: [tokens_js_1.SHIELD_REDIS],
|
|
750
|
+
};
|
|
748
751
|
const emailChangeLimiterProvider = {
|
|
749
752
|
provide: tokens_js_1.SHIELD_EMAIL_CHANGE_LIMITER,
|
|
750
753
|
useFactory: (redis) => new attempt_limiter_js_1.AttemptLimiter(redis, { maxAttempts: 3, windowMs: 60 * 60 * 1000 }),
|
|
@@ -818,6 +821,44 @@ function resolveDefaultEmailSender(rawNodeEnv) {
|
|
|
818
821
|
'to stdout, reset links included. Never run like this in production — supply an emailSender.');
|
|
819
822
|
return new log_email_sender_js_1.LogEmailSender();
|
|
820
823
|
}
|
|
824
|
+
/**
|
|
825
|
+
* The email delivery chain (G-010): `SHIELD_EMAIL_DELIVERY` (the bound provider and its per-send
|
|
826
|
+
* bound), `SHIELD_EMAIL_SENDER` (the port existing injectors know) and `SHIELD_MESSAGE_DISPATCHER`
|
|
827
|
+
* (bounded, audited, never throws). For `'env'` the sender is derived from the adapter; otherwise
|
|
828
|
+
* the sender binds exactly as before (AC-11) and the provider wraps it.
|
|
829
|
+
*/
|
|
830
|
+
function makeEmailDeliveryProviders(option) {
|
|
831
|
+
const dispatcher = {
|
|
832
|
+
provide: tokens_js_1.SHIELD_MESSAGE_DISPATCHER,
|
|
833
|
+
useFactory: (delivery, pool, config) => new message_dispatcher_js_1.GuardMessageDispatcher(delivery.provider, (0, email_delivery_js_1.messageAuditWriter)(pool, (0, app_config_js_1.frameworkSchemasOf)(config)), { timeoutMs: delivery.timeoutMs }),
|
|
834
|
+
inject: [tokens_js_1.SHIELD_EMAIL_DELIVERY, tokens_js_1.SHIELD_DB_POOL, config_module_js_1.APP_CONFIG],
|
|
835
|
+
};
|
|
836
|
+
if (option === 'env') {
|
|
837
|
+
return [
|
|
838
|
+
{
|
|
839
|
+
provide: tokens_js_1.SHIELD_EMAIL_DELIVERY,
|
|
840
|
+
useFactory: () => (0, email_delivery_js_1.buildEmailProvider)('env', null, {}),
|
|
841
|
+
},
|
|
842
|
+
{
|
|
843
|
+
provide: tokens_js_1.SHIELD_EMAIL_SENDER,
|
|
844
|
+
useFactory: (delivery) => delivery.provider
|
|
845
|
+
? (0, email_delivery_js_1.senderFromProvider)(delivery.provider, delivery.timeoutMs)
|
|
846
|
+
: new noop_email_sender_js_1.NoopEmailSender(),
|
|
847
|
+
inject: [tokens_js_1.SHIELD_EMAIL_DELIVERY],
|
|
848
|
+
},
|
|
849
|
+
dispatcher,
|
|
850
|
+
];
|
|
851
|
+
}
|
|
852
|
+
return [
|
|
853
|
+
makeEmailSenderProvider(option),
|
|
854
|
+
{
|
|
855
|
+
provide: tokens_js_1.SHIELD_EMAIL_DELIVERY,
|
|
856
|
+
useFactory: (sender) => (0, email_delivery_js_1.buildEmailProvider)(option, sender, {}),
|
|
857
|
+
inject: [tokens_js_1.SHIELD_EMAIL_SENDER],
|
|
858
|
+
},
|
|
859
|
+
dispatcher,
|
|
860
|
+
];
|
|
861
|
+
}
|
|
821
862
|
function makeRecoveryCodeStoreProvider(override) {
|
|
822
863
|
return override
|
|
823
864
|
? { provide: tokens_js_1.SHIELD_RECOVERY_CODE_STORE, useValue: override }
|
|
@@ -930,7 +971,8 @@ let AuthModule = AuthModule_1 = class AuthModule {
|
|
|
930
971
|
// The link-base boot rule (Phase 13 #1) applies only with a real sender: `'disabled'` delivers
|
|
931
972
|
// nothing, and an omitted sender outside development/test already fails the boot through
|
|
932
973
|
// `resolveDefaultEmailSender` (that clearer error is kept; in development/test the rule is off).
|
|
933
|
-
|
|
974
|
+
// G-010: `'env'` is a real sender unless `EMAIL_PROVIDER=disabled` (read after resolveBootSecrets).
|
|
975
|
+
const mailDisabled = (0, email_delivery_js_1.isMailDisabled)(options.emailSender, process.env);
|
|
934
976
|
return {
|
|
935
977
|
module: AuthModule_1,
|
|
936
978
|
imports: [persistence_module_js_1.PersistenceModule.forRoot()],
|
|
@@ -954,8 +996,9 @@ let AuthModule = AuthModule_1 = class AuthModule {
|
|
|
954
996
|
emailAddressChangerProvider,
|
|
955
997
|
emailChangeLimiterProvider,
|
|
956
998
|
confirmEmailLimiterProvider,
|
|
999
|
+
exports.attemptLimiterFactoryProvider,
|
|
957
1000
|
makeEmailChangeLinkBaseUrlProvider(options.emailChangeLinkBaseUrl, mailDisabled),
|
|
958
|
-
|
|
1001
|
+
...makeEmailDeliveryProviders(options.emailSender),
|
|
959
1002
|
makeRecoveryCodeStoreProvider(options.recoveryCodeStore),
|
|
960
1003
|
makeProfileWriterProvider(options.profileWriter),
|
|
961
1004
|
makeSessionSweeperProvider(options.sessionSweeper),
|
|
@@ -1065,6 +1108,10 @@ let AuthModule = AuthModule_1 = class AuthModule {
|
|
|
1065
1108
|
// Phase 12: identity's admin email change invalidates pending self-service tokens.
|
|
1066
1109
|
tokens_js_1.SHIELD_EMAIL_CHANGE_TOKEN_STORE,
|
|
1067
1110
|
tokens_js_1.SHIELD_EMAIL_SENDER,
|
|
1111
|
+
// G-010: the one exit for framework messages (identity's invite injects it).
|
|
1112
|
+
tokens_js_1.SHIELD_MESSAGE_DISPATCHER,
|
|
1113
|
+
// G-010: identity's invite rate limits (a limiter factory, never the raw Redis client).
|
|
1114
|
+
tokens_js_1.SHIELD_ATTEMPT_LIMITER_FACTORY,
|
|
1068
1115
|
tokens_js_1.SHIELD_RECOVERY_CODE_STORE,
|
|
1069
1116
|
tokens_js_1.SHIELD_PROFILE_WRITER,
|
|
1070
1117
|
tokens_js_1.SHIELD_SESSION_SWEEPER,
|
|
@@ -2,6 +2,7 @@ import type { AttemptLimiter } from './rate-limit/attempt-limiter.js';
|
|
|
2
2
|
import { TrustProxyBootCheck } from './rate-limit/trust-proxy-check.js';
|
|
3
3
|
import type { AuditSink } from './ports/audit-sink.js';
|
|
4
4
|
import type { EmailSender } from './ports/email-sender.js';
|
|
5
|
+
import type { MessageDispatcher } from '../messaging/message-dispatcher.js';
|
|
5
6
|
import type { EmailChangeTokenStore } from './ports/email-change-token-store.js';
|
|
6
7
|
import type { EmailAddressChanger } from './ports/email-address-changer.js';
|
|
7
8
|
import type { ResetTokenStore } from './ports/reset-token-store.js';
|
|
@@ -15,7 +16,8 @@ export declare class ConfirmEmailController {
|
|
|
15
16
|
private readonly auditSink?;
|
|
16
17
|
private readonly limiter?;
|
|
17
18
|
private readonly trustProxyCheck?;
|
|
18
|
-
|
|
19
|
+
private readonly messageDispatcher?;
|
|
20
|
+
constructor(tokens?: (EmailChangeTokenStore | null) | undefined, addresses?: (EmailAddressChanger | null) | undefined, sweeper?: (SessionSweeper | null) | undefined, resetTokens?: (ResetTokenStore | null) | undefined, emailSender?: (EmailSender | null) | undefined, auditSink?: (AuditSink | null) | undefined, limiter?: (AttemptLimiter | null) | undefined, trustProxyCheck?: (Pick<TrustProxyBootCheck, "perIpLimitingEnabled"> | null) | undefined, messageDispatcher?: (MessageDispatcher | null) | undefined);
|
|
19
21
|
confirmEmail(body: {
|
|
20
22
|
token?: unknown;
|
|
21
23
|
}, ip: string): Promise<{
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"confirm-email.controller.d.ts","sourceRoot":"","sources":["../../src/auth/confirm-email.controller.ts"],"names":[],"mappings":"
|
|
1
|
+
{"version":3,"file":"confirm-email.controller.d.ts","sourceRoot":"","sources":["../../src/auth/confirm-email.controller.ts"],"names":[],"mappings":"AA4CA,OAAO,KAAK,EAAE,cAAc,EAAE,MAAM,iCAAiC,CAAC;AACtE,OAAO,EAAE,mBAAmB,EAAE,MAAM,mCAAmC,CAAC;AACxE,OAAO,KAAK,EAAE,SAAS,EAAE,MAAM,uBAAuB,CAAC;AACvD,OAAO,KAAK,EAAE,WAAW,EAAE,MAAM,yBAAyB,CAAC;AAE3D,OAAO,KAAK,EAAE,iBAAiB,EAAE,MAAM,oCAAoC,CAAC;AAC5E,OAAO,KAAK,EAEV,qBAAqB,EACtB,MAAM,qCAAqC,CAAC;AAC7C,OAAO,KAAK,EAAE,mBAAmB,EAAsB,MAAM,kCAAkC,CAAC;AAChG,OAAO,KAAK,EAAE,eAAe,EAAE,MAAM,8BAA8B,CAAC;AACpE,OAAO,KAAK,EAAE,cAAc,EAAE,MAAM,4BAA4B,CAAC;AAcjE,qBACa,sBAAsB;IAI/B,OAAO,CAAC,QAAQ,CAAC,MAAM,CAAC;IAGxB,OAAO,CAAC,QAAQ,CAAC,SAAS,CAAC;IAG3B,OAAO,CAAC,QAAQ,CAAC,OAAO,CAAC;IAGzB,OAAO,CAAC,QAAQ,CAAC,WAAW,CAAC;IAG7B,OAAO,CAAC,QAAQ,CAAC,WAAW,CAAC;IAG7B,OAAO,CAAC,QAAQ,CAAC,SAAS,CAAC;IAG3B,OAAO,CAAC,QAAQ,CAAC,OAAO,CAAC;IAGzB,OAAO,CAAC,QAAQ,CAAC,eAAe,CAAC;IAKjC,OAAO,CAAC,QAAQ,CAAC,iBAAiB,CAAC;gBA1BlB,MAAM,CAAC,GAAE,qBAAqB,GAAG,IAAI,aAAA,EAGrC,SAAS,CAAC,GAAE,mBAAmB,GAAG,IAAI,aAAA,EAGtC,OAAO,CAAC,GAAE,cAAc,GAAG,IAAI,aAAA,EAG/B,WAAW,CAAC,GAAE,eAAe,GAAG,IAAI,aAAA,EAGpC,WAAW,CAAC,GAAE,WAAW,GAAG,IAAI,aAAA,EAGhC,SAAS,CAAC,GAAE,SAAS,GAAG,IAAI,aAAA,EAG5B,OAAO,CAAC,GAAE,cAAc,GAAG,IAAI,aAAA,EAG/B,eAAe,CAAC,GAAE,IAAI,CAAC,mBAAmB,EAAE,sBAAsB,CAAC,GAAG,IAAI,aAAA,EAK1E,iBAAiB,CAAC,GAAE,iBAAiB,GAAG,IAAI,aAAA;IAMzD,YAAY,CACR,IAAI,EAAE;QAAE,KAAK,CAAC,EAAE,OAAO,CAAA;KAAE,EAE3B,EAAE,EAAE,MAAM,GACf,OAAO,CAAC;QAAE,EAAE,EAAE,IAAI,CAAA;KAAE,CAAC;IAkFxB;;;;;;OAMG;IACH,OAAO,CAAC,KAAK;CAkBd"}
|
|
@@ -39,6 +39,7 @@ const node_crypto_1 = require("node:crypto");
|
|
|
39
39
|
const classification_decorator_js_1 = require("../enforcement/classification.decorator.js");
|
|
40
40
|
const tokens_js_1 = require("./tokens.js");
|
|
41
41
|
const trust_proxy_check_js_1 = require("./rate-limit/trust-proxy-check.js");
|
|
42
|
+
const deliver_email_js_1 = require("../messaging/deliver-email.js");
|
|
42
43
|
const email_address_js_1 = require("./email-address.js");
|
|
43
44
|
const email_change_messages_js_1 = require("./email-change-messages.js");
|
|
44
45
|
function fail(status, error) {
|
|
@@ -59,7 +60,8 @@ let ConfirmEmailController = class ConfirmEmailController {
|
|
|
59
60
|
auditSink;
|
|
60
61
|
limiter;
|
|
61
62
|
trustProxyCheck;
|
|
62
|
-
|
|
63
|
+
messageDispatcher;
|
|
64
|
+
constructor(tokens, addresses, sweeper, resetTokens, emailSender, auditSink, limiter, trustProxyCheck, messageDispatcher) {
|
|
63
65
|
this.tokens = tokens;
|
|
64
66
|
this.addresses = addresses;
|
|
65
67
|
this.sweeper = sweeper;
|
|
@@ -68,6 +70,7 @@ let ConfirmEmailController = class ConfirmEmailController {
|
|
|
68
70
|
this.auditSink = auditSink;
|
|
69
71
|
this.limiter = limiter;
|
|
70
72
|
this.trustProxyCheck = trustProxyCheck;
|
|
73
|
+
this.messageDispatcher = messageDispatcher;
|
|
71
74
|
}
|
|
72
75
|
async confirmEmail(body, ip) {
|
|
73
76
|
const tokens = this.tokens;
|
|
@@ -138,9 +141,8 @@ let ConfirmEmailController = class ConfirmEmailController {
|
|
|
138
141
|
});
|
|
139
142
|
}
|
|
140
143
|
if (outcome.oldEmail !== null && outcome.oldEmail !== '' && this.emailSender != null) {
|
|
141
|
-
|
|
142
|
-
|
|
143
|
-
.catch(() => undefined); // best-effort: the change is committed
|
|
144
|
+
// Best-effort (the change is committed); G-010: bounded and audited (`security_notice`).
|
|
145
|
+
await (0, deliver_email_js_1.deliverEmail)(this.messageDispatcher, this.emailSender, 'security_notice', (0, email_change_messages_js_1.emailChangedNoticeMessage)(outcome.oldEmail, maskedNew, Date.now()), { actorId: binding.principalId, tenantId: binding.tenantId });
|
|
144
146
|
}
|
|
145
147
|
this.audit(binding, 'account.email_changed', {
|
|
146
148
|
newEmail: maskedNew,
|
|
@@ -201,5 +203,7 @@ exports.ConfirmEmailController = ConfirmEmailController = __decorate([
|
|
|
201
203
|
__param(6, (0, common_1.Inject)(tokens_js_1.SHIELD_CONFIRM_EMAIL_LIMITER)),
|
|
202
204
|
__param(7, (0, common_1.Optional)()),
|
|
203
205
|
__param(7, (0, common_1.Inject)(trust_proxy_check_js_1.TrustProxyBootCheck)),
|
|
204
|
-
|
|
206
|
+
__param(8, (0, common_1.Optional)()),
|
|
207
|
+
__param(8, (0, common_1.Inject)(tokens_js_1.SHIELD_MESSAGE_DISPATCHER)),
|
|
208
|
+
__metadata("design:paramtypes", [Object, Object, Object, Object, Object, Object, Object, Object, Object])
|
|
205
209
|
], ConfirmEmailController);
|
|
@@ -19,6 +19,8 @@ export declare const DEFAULT_EMAIL_CHANGE_LINK_BASE_URL = "http://localhost:5173
|
|
|
19
19
|
* first, and the reset advice is qualified rather than given as the remedy.
|
|
20
20
|
*/
|
|
21
21
|
export declare const NOT_YOU_SENTENCE: string;
|
|
22
|
+
/** Escape a value for HTML text or a DOUBLE-quoted attribute (shared by framework messages). */
|
|
23
|
+
export declare function escapeHtml(value: string): string;
|
|
22
24
|
/** The confirm link: the token rides in the fragment, never the query (A4). */
|
|
23
25
|
export declare function emailChangeLink(base: string, rawToken: string): string;
|
|
24
26
|
export declare function confirmEmailChangeMessage(to: string, link: string): EmailMessage;
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"email-change-messages.d.ts","sourceRoot":"","sources":["../../src/auth/email-change-messages.ts"],"names":[],"mappings":"AAAA;;;;;;;;GAQG;AACH,OAAO,KAAK,EAAE,YAAY,EAAE,MAAM,yBAAyB,CAAC;AAE5D,8EAA8E;AAC9E,eAAO,MAAM,mBAAmB,QAAiB,CAAC;AAElD,sFAAsF;AACtF,eAAO,MAAM,kCAAkC,wCAAwC,CAAC;AAExF;;;;;GAKG;AACH,eAAO,MAAM,gBAAgB,QAE8C,CAAC;
|
|
1
|
+
{"version":3,"file":"email-change-messages.d.ts","sourceRoot":"","sources":["../../src/auth/email-change-messages.ts"],"names":[],"mappings":"AAAA;;;;;;;;GAQG;AACH,OAAO,KAAK,EAAE,YAAY,EAAE,MAAM,yBAAyB,CAAC;AAE5D,8EAA8E;AAC9E,eAAO,MAAM,mBAAmB,QAAiB,CAAC;AAElD,sFAAsF;AACtF,eAAO,MAAM,kCAAkC,wCAAwC,CAAC;AAExF;;;;;GAKG;AACH,eAAO,MAAM,gBAAgB,QAE8C,CAAC;AAE5E,gGAAgG;AAChG,wBAAgB,UAAU,CAAC,KAAK,EAAE,MAAM,GAAG,MAAM,CAMhD;AAED,+EAA+E;AAC/E,wBAAgB,eAAe,CAAC,IAAI,EAAE,MAAM,EAAE,QAAQ,EAAE,MAAM,GAAG,MAAM,CAEtE;AAED,wBAAgB,yBAAyB,CAAC,EAAE,EAAE,MAAM,EAAE,IAAI,EAAE,MAAM,GAAG,YAAY,CAehF;AAED,wBAAgB,yBAAyB,CACvC,EAAE,EAAE,MAAM,EACV,cAAc,EAAE,MAAM,EACtB,IAAI,EAAE,MAAM,GACX,YAAY,CAYd"}
|
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
"use strict";
|
|
2
2
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
3
|
exports.NOT_YOU_SENTENCE = exports.DEFAULT_EMAIL_CHANGE_LINK_BASE_URL = exports.EMAIL_CHANGE_TTL_MS = void 0;
|
|
4
|
+
exports.escapeHtml = escapeHtml;
|
|
4
5
|
exports.emailChangeLink = emailChangeLink;
|
|
5
6
|
exports.confirmEmailChangeMessage = confirmEmailChangeMessage;
|
|
6
7
|
exports.emailChangedNoticeMessage = emailChangedNoticeMessage;
|
|
@@ -16,6 +17,7 @@ exports.DEFAULT_EMAIL_CHANGE_LINK_BASE_URL = 'http://localhost:5173/confirm-emai
|
|
|
16
17
|
*/
|
|
17
18
|
exports.NOT_YOU_SENTENCE = "If this wasn't you, contact your administrator immediately. Your sign-in email may have " +
|
|
18
19
|
'changed too, so a password reset from the login page may not reach you.';
|
|
20
|
+
/** Escape a value for HTML text or a DOUBLE-quoted attribute (shared by framework messages). */
|
|
19
21
|
function escapeHtml(value) {
|
|
20
22
|
return value
|
|
21
23
|
.replace(/&/g, '&')
|
|
@@ -0,0 +1,7 @@
|
|
|
1
|
+
import type { EmailMessage } from './ports/email-sender.js';
|
|
2
|
+
/**
|
|
3
|
+
* The forgot-password email (G-010 R9: the link is HTML-escaped; before G-010 it was interpolated
|
|
4
|
+
* raw). The text part carries the plain link.
|
|
5
|
+
*/
|
|
6
|
+
export declare function passwordResetMessage(to: string, link: string): EmailMessage;
|
|
7
|
+
//# sourceMappingURL=password-reset-message.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"password-reset-message.d.ts","sourceRoot":"","sources":["../../src/auth/password-reset-message.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,YAAY,EAAE,MAAM,yBAAyB,CAAC;AAG5D;;;GAGG;AACH,wBAAgB,oBAAoB,CAAC,EAAE,EAAE,MAAM,EAAE,IAAI,EAAE,MAAM,GAAG,YAAY,CAQ3E"}
|
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.passwordResetMessage = passwordResetMessage;
|
|
4
|
+
const email_change_messages_js_1 = require("./email-change-messages.js");
|
|
5
|
+
/**
|
|
6
|
+
* The forgot-password email (G-010 R9: the link is HTML-escaped; before G-010 it was interpolated
|
|
7
|
+
* raw). The text part carries the plain link.
|
|
8
|
+
*/
|
|
9
|
+
function passwordResetMessage(to, link) {
|
|
10
|
+
const safe = (0, email_change_messages_js_1.escapeHtml)(link);
|
|
11
|
+
return {
|
|
12
|
+
to,
|
|
13
|
+
subject: 'Reset your password',
|
|
14
|
+
text: `Reset your password: ${link}`,
|
|
15
|
+
html: `<p>Reset your password: <a href="${safe}">${safe}</a></p>`,
|
|
16
|
+
};
|
|
17
|
+
}
|
|
@@ -1,13 +1,13 @@
|
|
|
1
1
|
/**
|
|
2
2
|
* EmailSender — the delivery seam. The framework builds the message; the consumer
|
|
3
|
-
* delivers it (SendGrid, SMTP, or a test capturer). Consumer-plugged
|
|
3
|
+
* delivers it (SendGrid, SMTP, or a test capturer). Consumer-plugged, or chosen by
|
|
4
|
+
* configuration with `ShieldModule.forRoot({ emailSender: 'env' })` (G-010).
|
|
5
|
+
*
|
|
6
|
+
* `EmailMessage` is core's channel type (G-010 R1); the name and shape are unchanged, so an app's
|
|
7
|
+
* existing sender keeps working.
|
|
4
8
|
*/
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
readonly subject: string;
|
|
8
|
-
readonly html: string;
|
|
9
|
-
readonly text: string;
|
|
10
|
-
}
|
|
9
|
+
import type { EmailMessage } from '@astram/core';
|
|
10
|
+
export type { EmailMessage };
|
|
11
11
|
export interface EmailSender {
|
|
12
12
|
send(message: EmailMessage): Promise<void>;
|
|
13
13
|
}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"email-sender.d.ts","sourceRoot":"","sources":["../../../src/auth/ports/email-sender.ts"],"names":[],"mappings":"AAAA
|
|
1
|
+
{"version":3,"file":"email-sender.d.ts","sourceRoot":"","sources":["../../../src/auth/ports/email-sender.ts"],"names":[],"mappings":"AAAA;;;;;;;GAOG;AACH,OAAO,KAAK,EAAE,YAAY,EAAE,MAAM,cAAc,CAAC;AAEjD,YAAY,EAAE,YAAY,EAAE,CAAC;AAE7B,MAAM,WAAW,WAAW;IAC1B,IAAI,CAAC,OAAO,EAAE,YAAY,GAAG,OAAO,CAAC,IAAI,CAAC,CAAC;CAC5C"}
|
package/dist/auth/tokens.d.ts
CHANGED
|
@@ -131,6 +131,20 @@ export declare const SHIELD_CONFIRM_EMAIL_LIMITER: unique symbol;
|
|
|
131
131
|
* consumer delivers it. Consumed by forgot-password.
|
|
132
132
|
*/
|
|
133
133
|
export declare const SHIELD_EMAIL_SENDER: unique symbol;
|
|
134
|
+
/**
|
|
135
|
+
* The {@link MessageDispatcher} (G-010, `../messaging/message-dispatcher.ts`): the one exit for
|
|
136
|
+
* framework messages. Bounds, audits (`message.sent` / `message.failed`) and never throws. Every
|
|
137
|
+
* framework send uses it; `@astram/identity`'s invite injects it too.
|
|
138
|
+
*/
|
|
139
|
+
export declare const SHIELD_MESSAGE_DISPATCHER: unique symbol;
|
|
140
|
+
/**
|
|
141
|
+
* A factory for guard's Redis-backed `AttemptLimiter` (G-010 P-5): `(cfg) => AttemptLimiter`. For
|
|
142
|
+
* `@astram/identity`'s invite rate limits; exported from `AuthModule` and `@astram/guard/internal`
|
|
143
|
+
* so identity builds limiters without ever holding the raw Redis client.
|
|
144
|
+
*/
|
|
145
|
+
export declare const SHIELD_ATTEMPT_LIMITER_FACTORY: unique symbol;
|
|
146
|
+
/** Internal: the bound email provider and its per-send bound (`EmailDelivery`). Not exported. */
|
|
147
|
+
export declare const SHIELD_EMAIL_DELIVERY: unique symbol;
|
|
134
148
|
/**
|
|
135
149
|
* The `RecoveryCodeStore` (guard port, `../auth/ports/recovery-code-store.ts`) —
|
|
136
150
|
* persists Argon2-hashed one-time MFA recovery codes. Consumed by MFA enrollment.
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"tokens.d.ts","sourceRoot":"","sources":["../../src/auth/tokens.ts"],"names":[],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"tokens.d.ts","sourceRoot":"","sources":["../../src/auth/tokens.ts"],"names":[],"mappings":"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"}
|