@astram/guard 0.17.0 → 0.19.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/audit/audit-chain-sealer.d.ts +90 -0
- package/dist/audit/audit-chain-sealer.d.ts.map +1 -0
- package/dist/audit/audit-chain-sealer.js +520 -0
- package/dist/audit/audit-seal-config.d.ts +22 -0
- package/dist/audit/audit-seal-config.d.ts.map +1 -0
- package/dist/audit/audit-seal-config.js +35 -0
- package/dist/audit/audit-sealer.service.d.ts +62 -0
- package/dist/audit/audit-sealer.service.d.ts.map +1 -0
- package/dist/audit/audit-sealer.service.js +197 -0
- package/dist/audit/node-sha256-hash.d.ts +6 -0
- package/dist/audit/node-sha256-hash.d.ts.map +1 -0
- package/dist/audit/node-sha256-hash.js +16 -0
- package/dist/auth/account.controller.d.ts +3 -1
- package/dist/auth/account.controller.d.ts.map +1 -1
- package/dist/auth/account.controller.js +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/persistence.module.d.ts +2 -2
- package/dist/auth/persistence.module.d.ts.map +1 -1
- package/dist/auth/persistence.module.js +19 -3
- package/dist/auth/ports/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/credential-provisioner.d.ts +5 -0
- package/dist/authentication/credential-provisioner.d.ts.map +1 -1
- package/dist/authentication/mariadb-credential-provisioner.d.ts +1 -0
- package/dist/authentication/mariadb-credential-provisioner.d.ts.map +1 -1
- package/dist/authentication/mariadb-credential-provisioner.js +24 -1
- 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/index.d.ts +7 -1
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +17 -3
- package/dist/internal.d.ts +10 -0
- package/dist/internal.d.ts.map +1 -1
- package/dist/internal.js +13 -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/package.json +15 -5
|
@@ -0,0 +1,62 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* `AuditSealerService` — runs the deferred audit sealer in the app (audit-chain-store SPEC
|
|
3
|
+
* §5.H, §11, §12).
|
|
4
|
+
*
|
|
5
|
+
* Registered by `PersistenceModule.forRoot()`, so it exists exactly when `SHIELD_DB_POOL`
|
|
6
|
+
* does (`ShieldModule.forRoot({ auth: true })`); an enforcement-only app has neither. There
|
|
7
|
+
* is no switch to turn it off: only `AUDIT_SEAL_INTERVAL_MS` / `AUDIT_SEAL_BATCH` tune it.
|
|
8
|
+
*
|
|
9
|
+
* - Boot (`onApplicationBootstrap`): one bounded table probe on `information_schema.TABLES`;
|
|
10
|
+
* both `audit_log` and `audit_chain` present ⇒ tick every interval. `audit_log` absent
|
|
11
|
+
* (auth without identity), or the probe failing (DB down, a test's stub pool) ⇒ one warning,
|
|
12
|
+
* idle; `audit_chain` absent (migration 102 not applied) ⇒ one error per probe, idle. The
|
|
13
|
+
* probe repeats every sweep period (1 h) and starts or stops the ticks. Never throws.
|
|
14
|
+
* - Ticks never overlap: the next one is scheduled only after the previous settled. A
|
|
15
|
+
* rejected tick is logged by error class only and the loop continues.
|
|
16
|
+
* - Shutdown (`onModuleDestroy`, which runs before the pool is ended, and
|
|
17
|
+
* `onApplicationShutdown`): stops the timers and waits for an in-flight tick. Idempotent.
|
|
18
|
+
* - Every timer is `unref()`'d: the sealer never keeps a process alive. Nothing here touches
|
|
19
|
+
* the request path (Shield #12).
|
|
20
|
+
*/
|
|
21
|
+
import { type OnApplicationBootstrap, type OnApplicationShutdown, type OnModuleDestroy } from '@nestjs/common';
|
|
22
|
+
import type { Pool } from 'mariadb';
|
|
23
|
+
import type { FrameworkSchemas } from '@astram/core';
|
|
24
|
+
import { type AuditSealConfig } from './audit-seal-config.js';
|
|
25
|
+
import { type AuditSealerLogger } from './audit-chain-sealer.js';
|
|
26
|
+
export interface AuditSealerServiceOptions {
|
|
27
|
+
/** Default `loadAuditSealConfig(process.env)`. */
|
|
28
|
+
readonly config?: AuditSealConfig;
|
|
29
|
+
/** Default `new Logger('Shield')`. */
|
|
30
|
+
readonly logger?: AuditSealerLogger;
|
|
31
|
+
/** Test seam; default an {@link AuditChainSealer} over the pool with {@link NodeSha256Hash}. */
|
|
32
|
+
readonly sealer?: {
|
|
33
|
+
tick(): Promise<unknown>;
|
|
34
|
+
};
|
|
35
|
+
}
|
|
36
|
+
export declare class AuditSealerService implements OnApplicationBootstrap, OnModuleDestroy, OnApplicationShutdown {
|
|
37
|
+
private readonly pool;
|
|
38
|
+
private readonly schemas;
|
|
39
|
+
private readonly config;
|
|
40
|
+
private readonly logger;
|
|
41
|
+
private readonly sealer;
|
|
42
|
+
private stopped;
|
|
43
|
+
private active;
|
|
44
|
+
private lastOutcome;
|
|
45
|
+
private tickTimer;
|
|
46
|
+
private probeTimer;
|
|
47
|
+
private inFlightTick;
|
|
48
|
+
private inFlightProbe;
|
|
49
|
+
constructor(pool: Pool, schemas: FrameworkSchemas, options?: AuditSealerServiceOptions);
|
|
50
|
+
onApplicationBootstrap(): Promise<void>;
|
|
51
|
+
onModuleDestroy(): Promise<void>;
|
|
52
|
+
onApplicationShutdown(): Promise<void>;
|
|
53
|
+
private stop;
|
|
54
|
+
/** Probe once (never overlapping, never throwing) and start or stop the ticks. */
|
|
55
|
+
private runProbe;
|
|
56
|
+
private probe;
|
|
57
|
+
/** Warnings once per change of state; the missing-chain error on every probe (SPEC §12). */
|
|
58
|
+
private report;
|
|
59
|
+
private schedule;
|
|
60
|
+
private runTick;
|
|
61
|
+
}
|
|
62
|
+
//# sourceMappingURL=audit-sealer.service.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"audit-sealer.service.d.ts","sourceRoot":"","sources":["../../src/audit/audit-sealer.service.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;GAmBG;AACH,OAAO,EAGL,KAAK,sBAAsB,EAC3B,KAAK,qBAAqB,EAC1B,KAAK,eAAe,EACrB,MAAM,gBAAgB,CAAC;AACxB,OAAO,KAAK,EAAE,IAAI,EAAE,MAAM,SAAS,CAAC;AACpC,OAAO,KAAK,EAAE,gBAAgB,EAAE,MAAM,cAAc,CAAC;AACrD,OAAO,EAAuB,KAAK,eAAe,EAAE,MAAM,wBAAwB,CAAC;AACnF,OAAO,EAIL,KAAK,iBAAiB,EACvB,MAAM,yBAAyB,CAAC;AAMjC,MAAM,WAAW,yBAAyB;IACxC,kDAAkD;IAClD,QAAQ,CAAC,MAAM,CAAC,EAAE,eAAe,CAAC;IAClC,sCAAsC;IACtC,QAAQ,CAAC,MAAM,CAAC,EAAE,iBAAiB,CAAC;IACpC,gGAAgG;IAChG,QAAQ,CAAC,MAAM,CAAC,EAAE;QAAE,IAAI,IAAI,OAAO,CAAC,OAAO,CAAC,CAAA;KAAE,CAAC;CAChD;AAID,qBACa,kBACX,YAAW,sBAAsB,EAAE,eAAe,EAAE,qBAAqB;IAevE,OAAO,CAAC,QAAQ,CAAC,IAAI;IACrB,OAAO,CAAC,QAAQ,CAAC,OAAO;IAd1B,OAAO,CAAC,QAAQ,CAAC,MAAM,CAAkB;IACzC,OAAO,CAAC,QAAQ,CAAC,MAAM,CAAoB;IAC3C,OAAO,CAAC,QAAQ,CAAC,MAAM,CAA+B;IAEtD,OAAO,CAAC,OAAO,CAAS;IACxB,OAAO,CAAC,MAAM,CAAS;IACvB,OAAO,CAAC,WAAW,CAA2B;IAC9C,OAAO,CAAC,SAAS,CAA6B;IAC9C,OAAO,CAAC,UAAU,CAA6B;IAC/C,OAAO,CAAC,YAAY,CAA4B;IAChD,OAAO,CAAC,aAAa,CAA4B;gBAG9B,IAAI,EAAE,IAAI,EACV,OAAO,EAAE,gBAAgB,EAC1C,OAAO,GAAE,yBAA8B;IAenC,sBAAsB,IAAI,OAAO,CAAC,IAAI,CAAC;IAQvC,eAAe,IAAI,OAAO,CAAC,IAAI,CAAC;IAIhC,qBAAqB,IAAI,OAAO,CAAC,IAAI,CAAC;YAI9B,IAAI;IAWlB,kFAAkF;IAClF,OAAO,CAAC,QAAQ;YAwBF,KAAK;IA4BnB,4FAA4F;IAC5F,OAAO,CAAC,MAAM;IAsBd,OAAO,CAAC,QAAQ;IAShB,OAAO,CAAC,OAAO;CAehB"}
|
|
@@ -0,0 +1,197 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
var __decorate = (this && this.__decorate) || function (decorators, target, key, desc) {
|
|
3
|
+
var c = arguments.length, r = c < 3 ? target : desc === null ? desc = Object.getOwnPropertyDescriptor(target, key) : desc, d;
|
|
4
|
+
if (typeof Reflect === "object" && typeof Reflect.decorate === "function") r = Reflect.decorate(decorators, target, key, desc);
|
|
5
|
+
else for (var i = decorators.length - 1; i >= 0; i--) if (d = decorators[i]) r = (c < 3 ? d(r) : c > 3 ? d(target, key, r) : d(target, key)) || r;
|
|
6
|
+
return c > 3 && r && Object.defineProperty(target, key, r), r;
|
|
7
|
+
};
|
|
8
|
+
var __metadata = (this && this.__metadata) || function (k, v) {
|
|
9
|
+
if (typeof Reflect === "object" && typeof Reflect.metadata === "function") return Reflect.metadata(k, v);
|
|
10
|
+
};
|
|
11
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
12
|
+
exports.AuditSealerService = void 0;
|
|
13
|
+
/**
|
|
14
|
+
* `AuditSealerService` — runs the deferred audit sealer in the app (audit-chain-store SPEC
|
|
15
|
+
* §5.H, §11, §12).
|
|
16
|
+
*
|
|
17
|
+
* Registered by `PersistenceModule.forRoot()`, so it exists exactly when `SHIELD_DB_POOL`
|
|
18
|
+
* does (`ShieldModule.forRoot({ auth: true })`); an enforcement-only app has neither. There
|
|
19
|
+
* is no switch to turn it off: only `AUDIT_SEAL_INTERVAL_MS` / `AUDIT_SEAL_BATCH` tune it.
|
|
20
|
+
*
|
|
21
|
+
* - Boot (`onApplicationBootstrap`): one bounded table probe on `information_schema.TABLES`;
|
|
22
|
+
* both `audit_log` and `audit_chain` present ⇒ tick every interval. `audit_log` absent
|
|
23
|
+
* (auth without identity), or the probe failing (DB down, a test's stub pool) ⇒ one warning,
|
|
24
|
+
* idle; `audit_chain` absent (migration 102 not applied) ⇒ one error per probe, idle. The
|
|
25
|
+
* probe repeats every sweep period (1 h) and starts or stops the ticks. Never throws.
|
|
26
|
+
* - Ticks never overlap: the next one is scheduled only after the previous settled. A
|
|
27
|
+
* rejected tick is logged by error class only and the loop continues.
|
|
28
|
+
* - Shutdown (`onModuleDestroy`, which runs before the pool is ended, and
|
|
29
|
+
* `onApplicationShutdown`): stops the timers and waits for an in-flight tick. Idempotent.
|
|
30
|
+
* - Every timer is `unref()`'d: the sealer never keeps a process alive. Nothing here touches
|
|
31
|
+
* the request path (Shield #12).
|
|
32
|
+
*/
|
|
33
|
+
const common_1 = require("@nestjs/common");
|
|
34
|
+
const audit_seal_config_js_1 = require("./audit-seal-config.js");
|
|
35
|
+
const audit_chain_sealer_js_1 = require("./audit-chain-sealer.js");
|
|
36
|
+
const node_sha256_hash_js_1 = require("./node-sha256-hash.js");
|
|
37
|
+
/** Upper bound on the boot/re-probe query, so a hung pool cannot stall the boot hook. */
|
|
38
|
+
const PROBE_TIMEOUT_MS = 10_000;
|
|
39
|
+
let AuditSealerService = class AuditSealerService {
|
|
40
|
+
pool;
|
|
41
|
+
schemas;
|
|
42
|
+
config;
|
|
43
|
+
logger;
|
|
44
|
+
sealer;
|
|
45
|
+
stopped = false;
|
|
46
|
+
active = false;
|
|
47
|
+
lastOutcome;
|
|
48
|
+
tickTimer;
|
|
49
|
+
probeTimer;
|
|
50
|
+
inFlightTick;
|
|
51
|
+
inFlightProbe;
|
|
52
|
+
constructor(pool, schemas, options = {}) {
|
|
53
|
+
this.pool = pool;
|
|
54
|
+
this.schemas = schemas;
|
|
55
|
+
this.config = options.config ?? (0, audit_seal_config_js_1.loadAuditSealConfig)(process.env);
|
|
56
|
+
this.logger = options.logger ?? new common_1.Logger('Shield');
|
|
57
|
+
this.sealer =
|
|
58
|
+
options.sealer ??
|
|
59
|
+
new audit_chain_sealer_js_1.AuditChainSealer({
|
|
60
|
+
pool,
|
|
61
|
+
schemas,
|
|
62
|
+
hash: new node_sha256_hash_js_1.NodeSha256Hash(),
|
|
63
|
+
batch: this.config.batch,
|
|
64
|
+
logger: this.logger,
|
|
65
|
+
});
|
|
66
|
+
}
|
|
67
|
+
async onApplicationBootstrap() {
|
|
68
|
+
if (this.stopped)
|
|
69
|
+
return;
|
|
70
|
+
await this.runProbe();
|
|
71
|
+
if (this.stopped || this.probeTimer !== undefined)
|
|
72
|
+
return;
|
|
73
|
+
this.probeTimer = setInterval(() => void this.runProbe(), audit_chain_sealer_js_1.AUDIT_SEAL_SWEEP_MS);
|
|
74
|
+
this.probeTimer.unref();
|
|
75
|
+
}
|
|
76
|
+
async onModuleDestroy() {
|
|
77
|
+
await this.stop();
|
|
78
|
+
}
|
|
79
|
+
async onApplicationShutdown() {
|
|
80
|
+
await this.stop();
|
|
81
|
+
}
|
|
82
|
+
async stop() {
|
|
83
|
+
this.stopped = true;
|
|
84
|
+
this.active = false;
|
|
85
|
+
if (this.tickTimer !== undefined)
|
|
86
|
+
clearTimeout(this.tickTimer);
|
|
87
|
+
if (this.probeTimer !== undefined)
|
|
88
|
+
clearInterval(this.probeTimer);
|
|
89
|
+
this.tickTimer = undefined;
|
|
90
|
+
this.probeTimer = undefined;
|
|
91
|
+
await this.inFlightProbe;
|
|
92
|
+
await this.inFlightTick;
|
|
93
|
+
}
|
|
94
|
+
/** Probe once (never overlapping, never throwing) and start or stop the ticks. */
|
|
95
|
+
runProbe() {
|
|
96
|
+
if (this.inFlightProbe !== undefined)
|
|
97
|
+
return this.inFlightProbe;
|
|
98
|
+
const run = (async () => {
|
|
99
|
+
const outcome = await this.probe();
|
|
100
|
+
if (this.stopped)
|
|
101
|
+
return;
|
|
102
|
+
this.report(outcome);
|
|
103
|
+
this.lastOutcome = outcome;
|
|
104
|
+
if (outcome === 'ready') {
|
|
105
|
+
if (!this.active) {
|
|
106
|
+
this.active = true;
|
|
107
|
+
this.schedule();
|
|
108
|
+
}
|
|
109
|
+
}
|
|
110
|
+
else {
|
|
111
|
+
this.active = false;
|
|
112
|
+
if (this.tickTimer !== undefined)
|
|
113
|
+
clearTimeout(this.tickTimer);
|
|
114
|
+
this.tickTimer = undefined;
|
|
115
|
+
}
|
|
116
|
+
})().finally(() => {
|
|
117
|
+
this.inFlightProbe = undefined;
|
|
118
|
+
});
|
|
119
|
+
this.inFlightProbe = run;
|
|
120
|
+
return run;
|
|
121
|
+
}
|
|
122
|
+
async probe() {
|
|
123
|
+
let timer;
|
|
124
|
+
try {
|
|
125
|
+
const timeout = new Promise((_, reject) => {
|
|
126
|
+
timer = setTimeout(() => reject(new Error('probe_timeout')), PROBE_TIMEOUT_MS);
|
|
127
|
+
timer.unref();
|
|
128
|
+
});
|
|
129
|
+
const query = Promise.resolve().then(() => this.pool.query(`SELECT TABLE_NAME FROM information_schema.TABLES
|
|
130
|
+
WHERE TABLE_SCHEMA = ? AND TABLE_NAME IN ('audit_log', 'audit_chain')`, [this.schemas.audit]));
|
|
131
|
+
query.catch(() => undefined); // a late rejection after the timeout is not unhandled
|
|
132
|
+
const rows = await Promise.race([query, timeout]);
|
|
133
|
+
if (!Array.isArray(rows))
|
|
134
|
+
return 'probe_failed';
|
|
135
|
+
const names = new Set(rows.map((r) => r.TABLE_NAME));
|
|
136
|
+
if (!names.has('audit_log'))
|
|
137
|
+
return 'no_audit_log';
|
|
138
|
+
if (!names.has('audit_chain'))
|
|
139
|
+
return 'no_audit_chain';
|
|
140
|
+
return 'ready';
|
|
141
|
+
}
|
|
142
|
+
catch {
|
|
143
|
+
return 'probe_failed';
|
|
144
|
+
}
|
|
145
|
+
finally {
|
|
146
|
+
if (timer !== undefined)
|
|
147
|
+
clearTimeout(timer);
|
|
148
|
+
}
|
|
149
|
+
}
|
|
150
|
+
/** Warnings once per change of state; the missing-chain error on every probe (SPEC §12). */
|
|
151
|
+
report(outcome) {
|
|
152
|
+
const db = this.schemas.audit;
|
|
153
|
+
if (outcome === 'no_audit_chain') {
|
|
154
|
+
this.logger.error(`audit sealer idle: ${db}.audit_chain does not exist (apply framework migration ` +
|
|
155
|
+
'1710000000102); audit_log rows stay unsealed until it does');
|
|
156
|
+
return;
|
|
157
|
+
}
|
|
158
|
+
if (outcome === this.lastOutcome)
|
|
159
|
+
return;
|
|
160
|
+
if (outcome === 'no_audit_log') {
|
|
161
|
+
this.logger.warn(`audit sealer idle: ${db}.audit_log does not exist (no identity audit store); ` +
|
|
162
|
+
're-checked every hour');
|
|
163
|
+
}
|
|
164
|
+
else if (outcome === 'probe_failed') {
|
|
165
|
+
this.logger.warn('audit sealer idle: the audit table check could not run; re-checked every hour');
|
|
166
|
+
}
|
|
167
|
+
}
|
|
168
|
+
schedule() {
|
|
169
|
+
if (!this.active || this.stopped || this.tickTimer !== undefined)
|
|
170
|
+
return;
|
|
171
|
+
this.tickTimer = setTimeout(() => {
|
|
172
|
+
this.tickTimer = undefined;
|
|
173
|
+
this.runTick();
|
|
174
|
+
}, this.config.intervalMs);
|
|
175
|
+
this.tickTimer.unref();
|
|
176
|
+
}
|
|
177
|
+
runTick() {
|
|
178
|
+
if (!this.active || this.stopped || this.inFlightTick !== undefined)
|
|
179
|
+
return;
|
|
180
|
+
this.inFlightTick = (async () => {
|
|
181
|
+
try {
|
|
182
|
+
await this.sealer.tick();
|
|
183
|
+
}
|
|
184
|
+
catch (err) {
|
|
185
|
+
this.logger.error(`audit sealer: tick failed (${(0, audit_chain_sealer_js_1.auditSealErrorClass)(err)}); retried next interval`);
|
|
186
|
+
}
|
|
187
|
+
})().finally(() => {
|
|
188
|
+
this.inFlightTick = undefined;
|
|
189
|
+
this.schedule();
|
|
190
|
+
});
|
|
191
|
+
}
|
|
192
|
+
};
|
|
193
|
+
exports.AuditSealerService = AuditSealerService;
|
|
194
|
+
exports.AuditSealerService = AuditSealerService = __decorate([
|
|
195
|
+
(0, common_1.Injectable)(),
|
|
196
|
+
__metadata("design:paramtypes", [Object, Object, Object])
|
|
197
|
+
], AuditSealerService);
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"node-sha256-hash.d.ts","sourceRoot":"","sources":["../../src/audit/node-sha256-hash.ts"],"names":[],"mappings":"AAMA,OAAO,KAAK,EAAE,YAAY,EAAE,MAAM,cAAc,CAAC;AAEjD,qBAAa,cAAe,YAAW,YAAY;IACjD,4DAA4D;IAC5D,IAAI,CAAC,KAAK,EAAE,MAAM,GAAG,MAAM;CAG5B"}
|
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.NodeSha256Hash = void 0;
|
|
4
|
+
/**
|
|
5
|
+
* `HashFunction` adapter over `node:crypto` SHA-256 for the durable audit chain
|
|
6
|
+
* (audit-chain-store SPEC §5.F). Core is zero-dependency, so the hash is injected into
|
|
7
|
+
* `linkEntry` / `verifyChain`. Lower-case hex of the UTF-8 bytes; never logs its input.
|
|
8
|
+
*/
|
|
9
|
+
const node_crypto_1 = require("node:crypto");
|
|
10
|
+
class NodeSha256Hash {
|
|
11
|
+
/** Lower-case hex SHA-256 of the UTF-8 bytes of `input`. */
|
|
12
|
+
hash(input) {
|
|
13
|
+
return (0, node_crypto_1.createHash)('sha256').update(input, 'utf8').digest('hex');
|
|
14
|
+
}
|
|
15
|
+
}
|
|
16
|
+
exports.NodeSha256Hash = NodeSha256Hash;
|
|
@@ -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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"}
|