@cogenta/auth 0.3.0 → 0.5.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.
Files changed (61) hide show
  1. package/dist/api-keys.d.ts +93 -4
  2. package/dist/api-keys.d.ts.map +1 -1
  3. package/dist/api-keys.js +260 -27
  4. package/dist/api-keys.js.map +1 -1
  5. package/dist/audit-integrity.d.ts +61 -0
  6. package/dist/audit-integrity.d.ts.map +1 -0
  7. package/dist/audit-integrity.js +130 -0
  8. package/dist/audit-integrity.js.map +1 -0
  9. package/dist/audit.d.ts +78 -2
  10. package/dist/audit.d.ts.map +1 -1
  11. package/dist/audit.js +168 -24
  12. package/dist/audit.js.map +1 -1
  13. package/dist/credentials.d.ts +27 -0
  14. package/dist/credentials.d.ts.map +1 -1
  15. package/dist/credentials.js +61 -0
  16. package/dist/credentials.js.map +1 -1
  17. package/dist/index.d.ts +11 -6
  18. package/dist/index.d.ts.map +1 -1
  19. package/dist/index.js +5 -2
  20. package/dist/index.js.map +1 -1
  21. package/dist/login.d.ts +63 -6
  22. package/dist/login.d.ts.map +1 -1
  23. package/dist/login.js +90 -10
  24. package/dist/login.js.map +1 -1
  25. package/dist/mfa.d.ts +1 -1
  26. package/dist/mfa.d.ts.map +1 -1
  27. package/dist/mfa.js +3 -1
  28. package/dist/mfa.js.map +1 -1
  29. package/dist/recovery-codes.d.ts +25 -0
  30. package/dist/recovery-codes.d.ts.map +1 -0
  31. package/dist/recovery-codes.js +56 -0
  32. package/dist/recovery-codes.js.map +1 -0
  33. package/dist/resets.d.ts +15 -1
  34. package/dist/resets.d.ts.map +1 -1
  35. package/dist/resets.js +10 -0
  36. package/dist/resets.js.map +1 -1
  37. package/dist/sessions.d.ts +24 -0
  38. package/dist/sessions.d.ts.map +1 -1
  39. package/dist/sessions.js +25 -4
  40. package/dist/sessions.js.map +1 -1
  41. package/dist/store.d.ts +3 -0
  42. package/dist/store.d.ts.map +1 -1
  43. package/dist/store.js +4 -1
  44. package/dist/store.js.map +1 -1
  45. package/dist/tables.d.ts +17 -0
  46. package/dist/tables.d.ts.map +1 -1
  47. package/dist/tables.js +129 -1
  48. package/dist/tables.js.map +1 -1
  49. package/dist/types.d.ts +89 -2
  50. package/dist/types.d.ts.map +1 -1
  51. package/dist/types.js +10 -1
  52. package/dist/types.js.map +1 -1
  53. package/dist/user-agent.d.ts +18 -0
  54. package/dist/user-agent.d.ts.map +1 -0
  55. package/dist/user-agent.js +39 -0
  56. package/dist/user-agent.js.map +1 -0
  57. package/dist/users.d.ts +24 -1
  58. package/dist/users.d.ts.map +1 -1
  59. package/dist/users.js +72 -3
  60. package/dist/users.js.map +1 -1
  61. package/package.json +3 -3
@@ -0,0 +1,130 @@
1
+ import { identifier, isCogentaError, sql } from '@cogenta/core';
2
+ import { TABLES } from './tables.js';
3
+ const DEFAULT_FULL_CHECK_INTERVAL_MS = 7 * 24 * 60 * 60 * 1000;
4
+ function checkpointOf(row) {
5
+ if (row.checkpoint_id === null || row.checkpoint_at === null || row.checkpoint_hash === null) {
6
+ return null;
7
+ }
8
+ return { id: row.checkpoint_id, at: row.checkpoint_at, hash: row.checkpoint_hash };
9
+ }
10
+ function statusOf(row) {
11
+ if (row === null) {
12
+ return {
13
+ state: 'never-run',
14
+ checkpoint: null,
15
+ entriesChecked: 0,
16
+ lastCheckedAt: null,
17
+ lastMode: null,
18
+ lastFullCheckedAt: null,
19
+ brokenAt: null,
20
+ brokenEntryId: null,
21
+ brokenMessage: null,
22
+ };
23
+ }
24
+ return {
25
+ state: row.state,
26
+ checkpoint: checkpointOf(row),
27
+ entriesChecked: row.entries_checked === null ? 0 : Number(row.entries_checked),
28
+ lastCheckedAt: row.last_checked_at,
29
+ lastMode: row.last_mode,
30
+ lastFullCheckedAt: row.last_full_checked_at,
31
+ brokenAt: row.broken_at,
32
+ brokenEntryId: row.broken_entry_id,
33
+ brokenMessage: row.broken_message,
34
+ };
35
+ }
36
+ function entryIdOf(details) {
37
+ const value = details?.entryId;
38
+ return typeof value === 'string' ? value : null;
39
+ }
40
+ export function createAuditIntegrityStore(db, audit, options = {}) {
41
+ const table = identifier(TABLES.auditIntegrity, db.dialect);
42
+ const now = options.now ?? Date.now;
43
+ const fullCheckIntervalMs = options.fullCheckIntervalMs ?? DEFAULT_FULL_CHECK_INTERVAL_MS;
44
+ async function readRow() {
45
+ const result = await db.query(sql `select * from ${table} where id = ${'singleton'}`);
46
+ return result.rows[0] ?? null;
47
+ }
48
+ async function writeRow(row) {
49
+ await db.transaction(async (tx) => {
50
+ await tx.query(sql `delete from ${table} where id = ${'singleton'}`);
51
+ await tx.query(sql `
52
+ insert into ${table} (
53
+ id, state, checkpoint_id, checkpoint_at, checkpoint_hash, entries_checked,
54
+ last_checked_at, last_mode, last_full_checked_at, broken_at, broken_entry_id, broken_message
55
+ ) values (
56
+ ${'singleton'}, ${row.state}, ${row.checkpoint_id}, ${row.checkpoint_at}, ${row.checkpoint_hash},
57
+ ${row.entries_checked}, ${row.last_checked_at}, ${row.last_mode}, ${row.last_full_checked_at},
58
+ ${row.broken_at}, ${row.broken_entry_id}, ${row.broken_message}
59
+ )`);
60
+ });
61
+ }
62
+ function dueForFullCheck(row) {
63
+ if (row === null || row.last_full_checked_at === null)
64
+ return true;
65
+ return now() - Date.parse(row.last_full_checked_at) >= fullCheckIntervalMs;
66
+ }
67
+ return {
68
+ status: async () => statusOf(await readRow()),
69
+ check: async (checkOptions = {}) => {
70
+ const row = await readRow();
71
+ const nowIso = new Date(now()).toISOString();
72
+ // Once broken, a plain (unforced) tick only re-stamps that it looked —
73
+ // it does not retry, because nothing about retrying a full or
74
+ // incremental verify would change the outcome until a human has acted
75
+ // (typically `prune()`ing the bad prefix, or restoring from a backup).
76
+ if (row !== null && row.state === 'broken' && checkOptions.full !== true) {
77
+ const { id: _id, ...rest } = row;
78
+ const restamped = { ...rest, last_checked_at: nowIso };
79
+ await writeRow(restamped);
80
+ return { status: statusOf({ ...restamped, id: 'singleton' }), newlyBroken: false };
81
+ }
82
+ const wasBroken = row?.state === 'broken';
83
+ const forceFull = checkOptions.full === true || row === null || dueForFullCheck(row);
84
+ const mode = forceFull ? 'full' : 'incremental';
85
+ const since = forceFull
86
+ ? null
87
+ : checkpointOf(row ?? { checkpoint_id: null, checkpoint_at: null, checkpoint_hash: null });
88
+ try {
89
+ const result = await audit.verifyRange(since);
90
+ const checkpoint = result.checkpoint ?? since;
91
+ const nextRow = {
92
+ state: 'ok',
93
+ checkpoint_id: checkpoint?.id ?? null,
94
+ checkpoint_at: checkpoint?.at ?? null,
95
+ checkpoint_hash: checkpoint?.hash ?? null,
96
+ entries_checked: String(result.entriesChecked),
97
+ last_checked_at: nowIso,
98
+ last_mode: mode,
99
+ last_full_checked_at: mode === 'full' ? nowIso : (row?.last_full_checked_at ?? null),
100
+ broken_at: null,
101
+ broken_entry_id: null,
102
+ broken_message: null,
103
+ };
104
+ await writeRow(nextRow);
105
+ return { status: statusOf({ ...nextRow, id: 'singleton' }), newlyBroken: false };
106
+ }
107
+ catch (error) {
108
+ if (!isCogentaError(error) || error.code !== 'AUDIT_CHAIN_BROKEN')
109
+ throw error;
110
+ const nextRow = {
111
+ state: 'broken',
112
+ // Frozen at the last point known good — never advanced past a break.
113
+ checkpoint_id: row?.checkpoint_id ?? null,
114
+ checkpoint_at: row?.checkpoint_at ?? null,
115
+ checkpoint_hash: row?.checkpoint_hash ?? null,
116
+ entries_checked: row?.entries_checked ?? '0',
117
+ last_checked_at: nowIso,
118
+ last_mode: mode,
119
+ last_full_checked_at: row?.last_full_checked_at ?? null,
120
+ broken_at: nowIso,
121
+ broken_entry_id: entryIdOf(error.details),
122
+ broken_message: error.message,
123
+ };
124
+ await writeRow(nextRow);
125
+ return { status: statusOf({ ...nextRow, id: 'singleton' }), newlyBroken: !wasBroken };
126
+ }
127
+ },
128
+ };
129
+ }
130
+ //# sourceMappingURL=audit-integrity.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"audit-integrity.js","sourceRoot":"","sources":["../src/audit-integrity.ts"],"names":[],"mappings":"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"}
package/dist/audit.d.ts CHANGED
@@ -1,17 +1,93 @@
1
1
  import { type DatabaseHandle } from '@cogenta/core';
2
- import type { AuditEntry, RecordAuditInput } from './types.js';
2
+ import type { AuditActorKind, AuditEntry, RecordAuditInput } from './types.js';
3
3
  export interface AuditFilter {
4
4
  readonly actorId?: string;
5
5
  readonly action?: string;
6
6
  readonly collection?: string;
7
+ /** Lower bound on `at`, inclusive. */
7
8
  readonly since?: string;
9
+ /** Upper bound on `at`, inclusive — the other half of task 2's date-range filter. */
10
+ readonly until?: string;
11
+ /** Task 4: narrows to one origin. See `classifyAuditActor`. */
12
+ readonly actorKind?: AuditActorKind;
8
13
  readonly limit?: number;
14
+ /**
15
+ * Cursor pagination (fiche 67 task 1): strictly older than this
16
+ * `(at, id)` position in the `order by at desc, id desc` listing — the
17
+ * exact position the previous page's last row sat at. Same shape as the
18
+ * chain-verification checkpoint (`AuditChainPoint`) on purpose, but this
19
+ * is a *listing* cursor, never confused with a verified chain position:
20
+ * an unknown or stale `before` (the row it named was pruned since) simply
21
+ * yields an earlier page, the same "not a security boundary" behaviour
22
+ * `users-router.ts`'s cursor already documents.
23
+ */
24
+ readonly before?: {
25
+ readonly at: string;
26
+ readonly id: string;
27
+ };
28
+ }
29
+ /**
30
+ * A point in the chain a caller has already verified up to — everything
31
+ * `verifyRange` needs to resume from it instead of the start.
32
+ */
33
+ export interface AuditChainPoint {
34
+ readonly id: string;
35
+ readonly at: string;
36
+ readonly hash: string;
37
+ }
38
+ export interface AuditVerifyRangeResult {
39
+ /**
40
+ * The newest point now verified. `since` unchanged when nothing new was
41
+ * found; `null` only when the whole chain (or the whole range) is empty.
42
+ */
43
+ readonly checkpoint: AuditChainPoint | null;
44
+ readonly entriesChecked: number;
45
+ }
46
+ export interface AuditPruneResult {
47
+ readonly prunedCount: number;
48
+ /** The new genesis anchor — `null` only when nothing matched `olderThan`. */
49
+ readonly genesis: AuditChainPoint | null;
9
50
  }
10
51
  export interface AuditLog {
11
52
  record(input: RecordAuditInput): Promise<AuditEntry>;
12
53
  list(filter?: AuditFilter): Promise<readonly AuditEntry[]>;
13
- /** Recomputes every hash and compares. Throws `AUDIT_CHAIN_BROKEN` naming the first mismatch. */
54
+ /** One entry by id, or `null` the detail view's lookup (fiche 21 task 1). */
55
+ get(id: string): Promise<AuditEntry | null>;
56
+ /** Recomputes every hash and compares, from the oldest surviving entry. Throws `AUDIT_CHAIN_BROKEN` naming the first mismatch. */
14
57
  verify(): Promise<void>;
58
+ /**
59
+ * The bounded form `verify()` is built on: recomputes only entries at or
60
+ * after `since` (the whole surviving chain when `since` is `null`), after
61
+ * first confirming `since` itself still matches what is stored — an
62
+ * altered or vanished checkpoint is exactly as much a break as an altered
63
+ * row in the middle ever was, unless it vanished because of a recorded
64
+ * `prune()`, which is not tampering and must not be reported as some.
65
+ */
66
+ verifyRange(since: AuditChainPoint | null): Promise<AuditVerifyRangeResult>;
67
+ /**
68
+ * Deletes every entry strictly older than `olderThan` (ISO-8601), for
69
+ * real — fiche 21 task 5's GDPR exit. Refuses (throwing
70
+ * `AUDIT_CHAIN_BROKEN`) if the segment about to be removed does not
71
+ * itself verify first: purging into an already-broken chain would erase
72
+ * the evidence of the break, not just old rows.
73
+ */
74
+ prune(olderThan: string): Promise<AuditPruneResult>;
15
75
  }
76
+ /**
77
+ * Who or what an entry names, read from signals the log already carries —
78
+ * no schema change needed to answer "human or agent or key or system"
79
+ * (fiche 21 task 4, "vérifier ce que le modèle porte déjà avant d'ajouter un
80
+ * champ"):
81
+ * - `actorId === null` → `'system'` (nobody was signed in — a migration, a
82
+ * scheduled job).
83
+ * - `actorId` starts with `apikey:` → `'api_key'`. `resolveActor`
84
+ * (`packages/api/src/rest/auth-router.ts`) has prefixed every API-key
85
+ * actor's id this way since L13 task 8; nothing else produces that shape.
86
+ * - `action` starts with `agent.tool.` → `'agent'`. `withAudit`
87
+ * (`packages/agents/src/audit/with-audit.ts`, L4 task 6) is the only
88
+ * writer that names an action this way.
89
+ * - anything else → `'human'`.
90
+ */
91
+ export declare function classifyAuditActor(entry: Pick<AuditEntry, 'actorId' | 'action'>): AuditActorKind;
16
92
  export declare function createAuditLog(db: DatabaseHandle, now?: () => number): AuditLog;
17
93
  //# sourceMappingURL=audit.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"audit.d.ts","sourceRoot":"","sources":["../src/audit.ts"],"names":[],"mappings":"AACA,OAAO,EAAgB,KAAK,cAAc,EAA0B,MAAM,eAAe,CAAA;AAEzF,OAAO,KAAK,EAAE,UAAU,EAAE,gBAAgB,EAAE,MAAM,YAAY,CAAA;AA0D9D,MAAM,WAAW,WAAW;IAC1B,QAAQ,CAAC,OAAO,CAAC,EAAE,MAAM,CAAA;IACzB,QAAQ,CAAC,MAAM,CAAC,EAAE,MAAM,CAAA;IACxB,QAAQ,CAAC,UAAU,CAAC,EAAE,MAAM,CAAA;IAC5B,QAAQ,CAAC,KAAK,CAAC,EAAE,MAAM,CAAA;IACvB,QAAQ,CAAC,KAAK,CAAC,EAAE,MAAM,CAAA;CACxB;AAED,MAAM,WAAW,QAAQ;IACvB,MAAM,CAAC,KAAK,EAAE,gBAAgB,GAAG,OAAO,CAAC,UAAU,CAAC,CAAA;IACpD,IAAI,CAAC,MAAM,CAAC,EAAE,WAAW,GAAG,OAAO,CAAC,SAAS,UAAU,EAAE,CAAC,CAAA;IAC1D,iGAAiG;IACjG,MAAM,IAAI,OAAO,CAAC,IAAI,CAAC,CAAA;CACxB;AAED,wBAAgB,cAAc,CAAC,EAAE,EAAE,cAAc,EAAE,GAAG,GAAE,MAAM,MAAiB,GAAG,QAAQ,CA2FzF"}
1
+ {"version":3,"file":"audit.d.ts","sourceRoot":"","sources":["../src/audit.ts"],"names":[],"mappings":"AACA,OAAO,EAAgB,KAAK,cAAc,EAA0B,MAAM,eAAe,CAAA;AAEzF,OAAO,KAAK,EAAE,cAAc,EAAE,UAAU,EAAE,gBAAgB,EAAE,MAAM,YAAY,CAAA;AAuF9E,MAAM,WAAW,WAAW;IAC1B,QAAQ,CAAC,OAAO,CAAC,EAAE,MAAM,CAAA;IACzB,QAAQ,CAAC,MAAM,CAAC,EAAE,MAAM,CAAA;IACxB,QAAQ,CAAC,UAAU,CAAC,EAAE,MAAM,CAAA;IAC5B,sCAAsC;IACtC,QAAQ,CAAC,KAAK,CAAC,EAAE,MAAM,CAAA;IACvB,qFAAqF;IACrF,QAAQ,CAAC,KAAK,CAAC,EAAE,MAAM,CAAA;IACvB,+DAA+D;IAC/D,QAAQ,CAAC,SAAS,CAAC,EAAE,cAAc,CAAA;IACnC,QAAQ,CAAC,KAAK,CAAC,EAAE,MAAM,CAAA;IACvB;;;;;;;;;OASG;IACH,QAAQ,CAAC,MAAM,CAAC,EAAE;QAAE,QAAQ,CAAC,EAAE,EAAE,MAAM,CAAC;QAAC,QAAQ,CAAC,EAAE,EAAE,MAAM,CAAA;KAAE,CAAA;CAC/D;AAED;;;GAGG;AACH,MAAM,WAAW,eAAe;IAC9B,QAAQ,CAAC,EAAE,EAAE,MAAM,CAAA;IACnB,QAAQ,CAAC,EAAE,EAAE,MAAM,CAAA;IACnB,QAAQ,CAAC,IAAI,EAAE,MAAM,CAAA;CACtB;AAED,MAAM,WAAW,sBAAsB;IACrC;;;OAGG;IACH,QAAQ,CAAC,UAAU,EAAE,eAAe,GAAG,IAAI,CAAA;IAC3C,QAAQ,CAAC,cAAc,EAAE,MAAM,CAAA;CAChC;AAED,MAAM,WAAW,gBAAgB;IAC/B,QAAQ,CAAC,WAAW,EAAE,MAAM,CAAA;IAC5B,6EAA6E;IAC7E,QAAQ,CAAC,OAAO,EAAE,eAAe,GAAG,IAAI,CAAA;CACzC;AAED,MAAM,WAAW,QAAQ;IACvB,MAAM,CAAC,KAAK,EAAE,gBAAgB,GAAG,OAAO,CAAC,UAAU,CAAC,CAAA;IACpD,IAAI,CAAC,MAAM,CAAC,EAAE,WAAW,GAAG,OAAO,CAAC,SAAS,UAAU,EAAE,CAAC,CAAA;IAC1D,+EAA+E;IAC/E,GAAG,CAAC,EAAE,EAAE,MAAM,GAAG,OAAO,CAAC,UAAU,GAAG,IAAI,CAAC,CAAA;IAC3C,kIAAkI;IAClI,MAAM,IAAI,OAAO,CAAC,IAAI,CAAC,CAAA;IACvB;;;;;;;OAOG;IACH,WAAW,CAAC,KAAK,EAAE,eAAe,GAAG,IAAI,GAAG,OAAO,CAAC,sBAAsB,CAAC,CAAA;IAC3E;;;;;;OAMG;IACH,KAAK,CAAC,SAAS,EAAE,MAAM,GAAG,OAAO,CAAC,gBAAgB,CAAC,CAAA;CACpD;AAED;;;;;;;;;;;;;;GAcG;AACH,wBAAgB,kBAAkB,CAAC,KAAK,EAAE,IAAI,CAAC,UAAU,EAAE,SAAS,GAAG,QAAQ,CAAC,GAAG,cAAc,CAKhG;AA+BD,wBAAgB,cAAc,CAAC,EAAE,EAAE,cAAc,EAAE,GAAG,GAAE,MAAM,MAAiB,GAAG,QAAQ,CAsMzF"}
package/dist/audit.js CHANGED
@@ -2,6 +2,7 @@ import { createHash } from 'node:crypto';
2
2
  import { CogentaError, identifier, newId, sql } from '@cogenta/core';
3
3
  import { TABLES } from './tables.js';
4
4
  function fromRow(row) {
5
+ const version = row.version;
5
6
  return {
6
7
  id: row.id,
7
8
  at: row.at,
@@ -11,10 +12,18 @@ function fromRow(row) {
11
12
  collection: row.collection_name,
12
13
  entryId: row.entry_id,
13
14
  diff: row.diff === null ? null : JSON.parse(row.diff),
15
+ version: version === undefined || version === null ? null : Number(version),
14
16
  hash: row.hash,
15
17
  previousHash: row.previous_hash,
16
18
  };
17
19
  }
20
+ /**
21
+ * Deliberately reads only the fields this format has hashed since the very
22
+ * first entry any site has ever recorded: `id`, `at`, `actor_id`,
23
+ * `actor_roles`, `action`, `collection_name`, `entry_id`, `diff`, chained to
24
+ * `previousHash`. Adding a field here changes what every already-recorded
25
+ * hash means — do not, without a migration plan for every existing chain.
26
+ */
18
27
  function computeHash(previousHash, fields) {
19
28
  const canonical = JSON.stringify([
20
29
  previousHash,
@@ -29,19 +38,132 @@ function computeHash(previousHash, fields) {
29
38
  ]);
30
39
  return createHash('sha256').update(canonical).digest('hex');
31
40
  }
41
+ /**
42
+ * Who or what an entry names, read from signals the log already carries —
43
+ * no schema change needed to answer "human or agent or key or system"
44
+ * (fiche 21 task 4, "vérifier ce que le modèle porte déjà avant d'ajouter un
45
+ * champ"):
46
+ * - `actorId === null` → `'system'` (nobody was signed in — a migration, a
47
+ * scheduled job).
48
+ * - `actorId` starts with `apikey:` → `'api_key'`. `resolveActor`
49
+ * (`packages/api/src/rest/auth-router.ts`) has prefixed every API-key
50
+ * actor's id this way since L13 task 8; nothing else produces that shape.
51
+ * - `action` starts with `agent.tool.` → `'agent'`. `withAudit`
52
+ * (`packages/agents/src/audit/with-audit.ts`, L4 task 6) is the only
53
+ * writer that names an action this way.
54
+ * - anything else → `'human'`.
55
+ */
56
+ export function classifyAuditActor(entry) {
57
+ if (entry.actorId === null)
58
+ return 'system';
59
+ if (entry.actorId.startsWith('apikey:'))
60
+ return 'api_key';
61
+ if (entry.action.startsWith('agent.tool.'))
62
+ return 'agent';
63
+ return 'human';
64
+ }
65
+ function actorKindCondition(kind) {
66
+ switch (kind) {
67
+ case 'system':
68
+ return sql `actor_id is null`;
69
+ case 'api_key':
70
+ return sql `actor_id like ${'apikey:%'}`;
71
+ case 'agent':
72
+ return sql `action like ${'agent.tool.%'}`;
73
+ case 'human':
74
+ return sql `(actor_id is not null and actor_id not like ${'apikey:%'} and action not like ${'agent.tool.%'})`;
75
+ }
76
+ }
77
+ function chainBroken(entryId, reason) {
78
+ return reason === 'discontinuous'
79
+ ? new CogentaError({
80
+ code: 'AUDIT_CHAIN_BROKEN',
81
+ message: `Audit entry ${entryId} does not chain from the entry before it.`,
82
+ hint: 'The audit log has been edited or reordered outside of record(). Treat every entry from this point on as untrusted.',
83
+ details: { entryId },
84
+ })
85
+ : new CogentaError({
86
+ code: 'AUDIT_CHAIN_BROKEN',
87
+ message: `Audit entry ${entryId} has been modified since it was recorded.`,
88
+ hint: 'Its stored hash no longer matches its content. Treat every entry from this point on as untrusted.',
89
+ details: { entryId },
90
+ });
91
+ }
32
92
  export function createAuditLog(db, now = Date.now) {
33
93
  const table = identifier(TABLES.auditLog, db.dialect);
94
+ const genesisTable = identifier(TABLES.auditGenesis, db.dialect);
34
95
  // Serialises appends within this process. Two concurrent writers computing
35
96
  // "the current last hash" from a read that has not committed yet would
36
97
  // both chain to the same previous hash and fork the chain — a database
37
98
  // transaction alone does not stop that on every dialect's default isolation
38
99
  // level, so the invariant is enforced here, once, rather than trusted to
39
- // whichever caller remembers to lock.
100
+ // whichever caller remembers to lock. `prune()` joins the same queue: a
101
+ // purge running concurrently with an append is exactly the same class of
102
+ // race, just over a delete instead of an insert.
40
103
  let appendQueue = Promise.resolve();
41
104
  async function lastHash() {
42
105
  const result = await db.query(sql `select hash from ${table} order by at desc, id desc limit ${1}`);
43
106
  return result.rows[0]?.hash ?? null;
44
107
  }
108
+ async function currentGenesis() {
109
+ const result = await db.query(sql `select entry_id, entry_at, entry_hash from ${genesisTable} where id = ${'singleton'}`);
110
+ const row = result.rows[0];
111
+ return row === undefined ? null : { id: row.entry_id, at: row.entry_at, hash: row.entry_hash };
112
+ }
113
+ /** `rows` must already be in `(at, id)` ascending order. */
114
+ function verifyRows(rows, expectedPreviousStart) {
115
+ let expectedPrevious = expectedPreviousStart;
116
+ let last = null;
117
+ for (const row of rows) {
118
+ if (row.previous_hash !== expectedPrevious)
119
+ throw chainBroken(row.id, 'discontinuous');
120
+ const { hash, version: _version, ...rest } = row;
121
+ if (computeHash(row.previous_hash, rest) !== hash)
122
+ throw chainBroken(row.id, 'edited');
123
+ expectedPrevious = hash;
124
+ last = { id: row.id, at: row.at, hash: row.hash };
125
+ }
126
+ return last;
127
+ }
128
+ async function verifyRangeImpl(since) {
129
+ const genesis = await currentGenesis();
130
+ if (since === null) {
131
+ const rows = await db.query(sql `select * from ${table} order by at asc, id asc`);
132
+ const last = verifyRows(rows.rows, genesis?.hash ?? null);
133
+ return { checkpoint: last, entriesChecked: rows.rows.length };
134
+ }
135
+ const found = await db.query(sql `select * from ${table} where id = ${since.id}`);
136
+ const checkpointRow = found.rows[0];
137
+ if (checkpointRow === undefined) {
138
+ // Missing is only innocent when it is exactly what a recorded prune()
139
+ // would leave behind: `since` at or before the current genesis. Newer
140
+ // than the genesis (or no genesis at all) and still missing means
141
+ // something else deleted it — tampering, not retention.
142
+ const explainedByPrune = genesis !== null &&
143
+ (since.at < genesis.at || (since.at === genesis.at && since.id <= genesis.id));
144
+ if (!explainedByPrune)
145
+ throw chainBroken(since.id, 'discontinuous');
146
+ // Resume as if starting fresh from the genesis: everything between the
147
+ // old checkpoint and the genesis is gone by design, and the caller's
148
+ // next checkpoint should be the genesis or later.
149
+ const rows = await db.query(sql `select * from ${table} order by at asc, id asc`);
150
+ const last = verifyRows(rows.rows, genesis?.hash ?? null);
151
+ return { checkpoint: last ?? genesis, entriesChecked: rows.rows.length };
152
+ }
153
+ if (checkpointRow.hash !== since.hash)
154
+ throw chainBroken(since.id, 'edited');
155
+ // Defence in depth: the checkpoint row's own stored hash must still
156
+ // match its own content, not only match what the caller remembered.
157
+ const { hash, version: _version, ...rest } = checkpointRow;
158
+ if (computeHash(checkpointRow.previous_hash, rest) !== hash) {
159
+ throw chainBroken(since.id, 'edited');
160
+ }
161
+ const rows = await db.query(sql `select * from ${table}
162
+ where (at > ${since.at}) or (at = ${since.at} and id > ${since.id})
163
+ order by at asc, id asc`);
164
+ const last = verifyRows(rows.rows, since.hash);
165
+ return { checkpoint: last ?? since, entriesChecked: rows.rows.length };
166
+ }
45
167
  return {
46
168
  record: (input) => {
47
169
  const task = appendQueue.then(async () => {
@@ -58,11 +180,12 @@ export function createAuditLog(db, now = Date.now) {
58
180
  previous_hash: previousHash,
59
181
  };
60
182
  const hash = computeHash(previousHash, base);
183
+ const version = input.version === undefined ? null : String(input.version);
61
184
  await db.query(sql `
62
- insert into ${table} (id, at, actor_id, actor_roles, action, collection_name, entry_id, diff, hash, previous_hash)
185
+ insert into ${table} (id, at, actor_id, actor_roles, action, collection_name, entry_id, diff, hash, previous_hash, version)
63
186
  values (${base.id}, ${base.at}, ${base.actor_id}, ${base.actor_roles}, ${base.action},
64
- ${base.collection_name}, ${base.entry_id}, ${base.diff}, ${hash}, ${base.previous_hash})`);
65
- return fromRow({ ...base, hash });
187
+ ${base.collection_name}, ${base.entry_id}, ${base.diff}, ${hash}, ${base.previous_hash}, ${version})`);
188
+ return fromRow({ ...base, hash, version });
66
189
  });
67
190
  // The queue must advance even if this append fails, or every append
68
191
  // after a failure would wait on a promise that never resolves.
@@ -79,34 +202,55 @@ export function createAuditLog(db, now = Date.now) {
79
202
  conditions.push(sql `collection_name = ${filter.collection}`);
80
203
  if (filter.since !== undefined)
81
204
  conditions.push(sql `at >= ${filter.since}`);
205
+ if (filter.until !== undefined)
206
+ conditions.push(sql `at <= ${filter.until}`);
207
+ if (filter.actorKind !== undefined)
208
+ conditions.push(actorKindCondition(filter.actorKind));
209
+ if (filter.before !== undefined) {
210
+ conditions.push(sql `(at < ${filter.before.at} or (at = ${filter.before.at} and id < ${filter.before.id}))`);
211
+ }
82
212
  const where = conditions.reduce((left, right) => sql `${left} and ${right}`);
83
213
  const result = await db.query(sql `
84
214
  select * from ${table} where ${where} order by at desc, id desc limit ${filter.limit ?? 200}`);
85
215
  return result.rows.map(fromRow);
86
216
  },
217
+ get: async (id) => {
218
+ const result = await db.query(sql `select * from ${table} where id = ${id}`);
219
+ const row = result.rows[0];
220
+ return row === undefined ? null : fromRow(row);
221
+ },
87
222
  verify: async () => {
88
- const result = await db.query(sql `select * from ${table} order by at asc, id asc`);
89
- let expectedPrevious = null;
90
- for (const row of result.rows) {
91
- if (row.previous_hash !== expectedPrevious) {
92
- throw new CogentaError({
93
- code: 'AUDIT_CHAIN_BROKEN',
94
- message: `Audit entry ${row.id} does not chain from the entry before it.`,
95
- hint: 'The audit log has been edited or reordered outside of record(). Treat every entry from this point on as untrusted.',
96
- details: { entryId: row.id },
97
- });
223
+ await verifyRangeImpl(null);
224
+ },
225
+ verifyRange: (since) => verifyRangeImpl(since),
226
+ prune: (olderThan) => {
227
+ const task = appendQueue.then(async () => {
228
+ const candidates = await db.query(sql `select * from ${table} where at < ${olderThan} order by at asc, id asc`);
229
+ if (candidates.rows.length === 0) {
230
+ return { prunedCount: 0, genesis: await currentGenesis() };
98
231
  }
99
- const { hash, ...rest } = row;
100
- if (computeHash(row.previous_hash, rest) !== hash) {
101
- throw new CogentaError({
102
- code: 'AUDIT_CHAIN_BROKEN',
103
- message: `Audit entry ${row.id} has been modified since it was recorded.`,
104
- hint: 'Its stored hash no longer matches its content. Treat every entry from this point on as untrusted.',
105
- details: { entryId: row.id },
106
- });
232
+ const genesis = await currentGenesis();
233
+ // Throws `AUDIT_CHAIN_BROKEN` when the segment about to be removed
234
+ // is already discontinuous or edited — refusing to purge over
235
+ // evidence of tampering, rather than quietly making it unrecoverable.
236
+ const anchor = verifyRows(candidates.rows, genesis?.hash ?? null);
237
+ if (anchor === null) {
238
+ // Unreachable: `candidates.rows.length > 0` guarantees `verifyRows`
239
+ // returns the last row it processed. Narrows the type for below.
240
+ throw chainBroken('unknown', 'discontinuous');
107
241
  }
108
- expectedPrevious = hash;
109
- }
242
+ await db.transaction(async (tx) => {
243
+ await tx.query(sql `delete from ${table} where at < ${olderThan}`);
244
+ await tx.query(sql `delete from ${genesisTable} where id = ${'singleton'}`);
245
+ await tx.query(sql `
246
+ insert into ${genesisTable} (id, entry_id, entry_at, entry_hash, pruned_count, pruned_at)
247
+ values (${'singleton'}, ${anchor.id}, ${anchor.at}, ${anchor.hash},
248
+ ${String(candidates.rows.length)}, ${new Date(now()).toISOString()})`);
249
+ });
250
+ return { prunedCount: candidates.rows.length, genesis: anchor };
251
+ });
252
+ appendQueue = task.catch(() => undefined);
253
+ return task;
110
254
  },
111
255
  };
112
256
  }
package/dist/audit.js.map CHANGED
@@ -1 +1 @@
1
- {"version":3,"file":"audit.js","sourceRoot":"","sources":["../src/audit.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"audit.js","sourceRoot":"","sources":["../src/audit.ts"],"names":[],"mappings":"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"}
@@ -26,6 +26,33 @@ export interface CredentialStore {
26
26
  data: WebAuthnCredentialData;
27
27
  } | null>;
28
28
  updateWebAuthnCounter(credentialId: string, counter: number): Promise<void>;
29
+ /**
30
+ * Replaces this account's recovery codes wholesale with `hashes` — already
31
+ * hashed by the caller (`recovery-codes.ts`), never a plaintext code. Used
32
+ * both for the first batch (TOTP confirmation) and for regeneration, which
33
+ * is exactly what makes regeneration invalidate the old ones: there is
34
+ * nothing left to consume the previous batch against.
35
+ */
36
+ setRecoveryCodes(userId: string, hashes: readonly string[]): Promise<void>;
37
+ /** How many codes exist and how many are still unused. `null` when none were ever issued. */
38
+ recoveryCodesStatus(userId: string): Promise<{
39
+ readonly total: number;
40
+ readonly remaining: number;
41
+ } | null>;
42
+ /**
43
+ * Checks `code` against every unused code for this account and, on a
44
+ * match, marks that one used. Single use is enforced with a
45
+ * compare-and-set on the write (`resets.ts`'s `markUsed` idiom): the
46
+ * `update` is conditioned on the row still holding the exact bytes this
47
+ * call read, so a concurrent redemption that wrote first makes this one's
48
+ * `update` affect zero rows, which is retried against the fresher row
49
+ * rather than blindly overwriting it. Two simultaneous calls with the same
50
+ * code can therefore never both return `true`. Returns `false` for no
51
+ * account, no codes, or no match at all.
52
+ */
53
+ consumeRecoveryCode(userId: string, code: string): Promise<boolean>;
54
+ /** Deletes every recovery code for this account — there is nothing left to be a spare key for once TOTP itself is off. */
55
+ removeRecoveryCodes(userId: string): Promise<void>;
29
56
  /** What second factors, if any, this user has set up. */
30
57
  kinds(userId: string): Promise<readonly CredentialKind[]>;
31
58
  }
@@ -1 +1 @@
1
- {"version":3,"file":"credentials.d.ts","sourceRoot":"","sources":["../src/credentials.ts"],"names":[],"mappings":"AAAA,OAAO,EAAgB,KAAK,cAAc,EAA0B,MAAM,eAAe,CAAA;AAGzF,OAAO,KAAK,EAAE,cAAc,EAAE,MAAM,YAAY,CAAA;AAUhD,MAAM,WAAW,sBAAsB;IACrC,QAAQ,CAAC,YAAY,EAAE,MAAM,CAAA;IAC7B,QAAQ,CAAC,SAAS,EAAE,MAAM,CAAA;IAC1B,QAAQ,CAAC,OAAO,EAAE,MAAM,CAAA;IACxB,QAAQ,CAAC,UAAU,EAAE,SAAS,MAAM,EAAE,CAAA;IACtC,QAAQ,CAAC,KAAK,EAAE,MAAM,GAAG,SAAS,CAAA;CACnC;AAED,MAAM,WAAW,eAAe;IAC9B,WAAW,CAAC,MAAM,EAAE,MAAM,EAAE,QAAQ,EAAE,MAAM,GAAG,OAAO,CAAC,IAAI,CAAC,CAAA;IAC5D,cAAc,CAAC,MAAM,EAAE,MAAM,EAAE,QAAQ,EAAE,MAAM,GAAG,OAAO,CAAC,OAAO,CAAC,CAAA;IAClE,WAAW,CAAC,MAAM,EAAE,MAAM,GAAG,OAAO,CAAC,OAAO,CAAC,CAAA;IAE7C,aAAa,CAAC,MAAM,EAAE,MAAM,EAAE,MAAM,EAAE,MAAM,GAAG,OAAO,CAAC,IAAI,CAAC,CAAA;IAC5D,kFAAkF;IAClF,UAAU,CAAC,MAAM,EAAE,MAAM,GAAG,OAAO,CAAC;QAAE,MAAM,EAAE,MAAM,CAAC;QAAC,QAAQ,EAAE,OAAO,CAAA;KAAE,GAAG,IAAI,CAAC,CAAA;IACjF,WAAW,CAAC,MAAM,EAAE,MAAM,GAAG,OAAO,CAAC,IAAI,CAAC,CAAA;IAC1C,UAAU,CAAC,MAAM,EAAE,MAAM,GAAG,OAAO,CAAC,IAAI,CAAC,CAAA;IAEzC,qBAAqB,CAAC,MAAM,EAAE,MAAM,EAAE,IAAI,EAAE,sBAAsB,GAAG,OAAO,CAAC,IAAI,CAAC,CAAA;IAClF,mBAAmB,CAAC,MAAM,EAAE,MAAM,GAAG,OAAO,CAAC,SAAS,sBAAsB,EAAE,CAAC,CAAA;IAC/E,8BAA8B,CAC5B,YAAY,EAAE,MAAM,GACnB,OAAO,CAAC;QAAE,MAAM,EAAE,MAAM,CAAC;QAAC,IAAI,EAAE,sBAAsB,CAAA;KAAE,GAAG,IAAI,CAAC,CAAA;IACnE,qBAAqB,CAAC,YAAY,EAAE,MAAM,EAAE,OAAO,EAAE,MAAM,GAAG,OAAO,CAAC,IAAI,CAAC,CAAA;IAE3E,yDAAyD;IACzD,KAAK,CAAC,MAAM,EAAE,MAAM,GAAG,OAAO,CAAC,SAAS,cAAc,EAAE,CAAC,CAAA;CAC1D;AAED,wBAAgB,qBAAqB,CACnC,EAAE,EAAE,cAAc,EAClB,GAAG,GAAE,MAAM,MAAiB,GAC3B,eAAe,CAkHjB"}
1
+ {"version":3,"file":"credentials.d.ts","sourceRoot":"","sources":["../src/credentials.ts"],"names":[],"mappings":"AAAA,OAAO,EAAgB,KAAK,cAAc,EAA0B,MAAM,eAAe,CAAA;AAIzF,OAAO,KAAK,EAAE,cAAc,EAAE,MAAM,YAAY,CAAA;AAUhD,MAAM,WAAW,sBAAsB;IACrC,QAAQ,CAAC,YAAY,EAAE,MAAM,CAAA;IAC7B,QAAQ,CAAC,SAAS,EAAE,MAAM,CAAA;IAC1B,QAAQ,CAAC,OAAO,EAAE,MAAM,CAAA;IACxB,QAAQ,CAAC,UAAU,EAAE,SAAS,MAAM,EAAE,CAAA;IACtC,QAAQ,CAAC,KAAK,EAAE,MAAM,GAAG,SAAS,CAAA;CACnC;AAED,MAAM,WAAW,eAAe;IAC9B,WAAW,CAAC,MAAM,EAAE,MAAM,EAAE,QAAQ,EAAE,MAAM,GAAG,OAAO,CAAC,IAAI,CAAC,CAAA;IAC5D,cAAc,CAAC,MAAM,EAAE,MAAM,EAAE,QAAQ,EAAE,MAAM,GAAG,OAAO,CAAC,OAAO,CAAC,CAAA;IAClE,WAAW,CAAC,MAAM,EAAE,MAAM,GAAG,OAAO,CAAC,OAAO,CAAC,CAAA;IAE7C,aAAa,CAAC,MAAM,EAAE,MAAM,EAAE,MAAM,EAAE,MAAM,GAAG,OAAO,CAAC,IAAI,CAAC,CAAA;IAC5D,kFAAkF;IAClF,UAAU,CAAC,MAAM,EAAE,MAAM,GAAG,OAAO,CAAC;QAAE,MAAM,EAAE,MAAM,CAAC;QAAC,QAAQ,EAAE,OAAO,CAAA;KAAE,GAAG,IAAI,CAAC,CAAA;IACjF,WAAW,CAAC,MAAM,EAAE,MAAM,GAAG,OAAO,CAAC,IAAI,CAAC,CAAA;IAC1C,UAAU,CAAC,MAAM,EAAE,MAAM,GAAG,OAAO,CAAC,IAAI,CAAC,CAAA;IAEzC,qBAAqB,CAAC,MAAM,EAAE,MAAM,EAAE,IAAI,EAAE,sBAAsB,GAAG,OAAO,CAAC,IAAI,CAAC,CAAA;IAClF,mBAAmB,CAAC,MAAM,EAAE,MAAM,GAAG,OAAO,CAAC,SAAS,sBAAsB,EAAE,CAAC,CAAA;IAC/E,8BAA8B,CAC5B,YAAY,EAAE,MAAM,GACnB,OAAO,CAAC;QAAE,MAAM,EAAE,MAAM,CAAC;QAAC,IAAI,EAAE,sBAAsB,CAAA;KAAE,GAAG,IAAI,CAAC,CAAA;IACnE,qBAAqB,CAAC,YAAY,EAAE,MAAM,EAAE,OAAO,EAAE,MAAM,GAAG,OAAO,CAAC,IAAI,CAAC,CAAA;IAE3E;;;;;;OAMG;IACH,gBAAgB,CAAC,MAAM,EAAE,MAAM,EAAE,MAAM,EAAE,SAAS,MAAM,EAAE,GAAG,OAAO,CAAC,IAAI,CAAC,CAAA;IAC1E,6FAA6F;IAC7F,mBAAmB,CACjB,MAAM,EAAE,MAAM,GACb,OAAO,CAAC;QAAE,QAAQ,CAAC,KAAK,EAAE,MAAM,CAAC;QAAC,QAAQ,CAAC,SAAS,EAAE,MAAM,CAAA;KAAE,GAAG,IAAI,CAAC,CAAA;IACzE;;;;;;;;;;OAUG;IACH,mBAAmB,CAAC,MAAM,EAAE,MAAM,EAAE,IAAI,EAAE,MAAM,GAAG,OAAO,CAAC,OAAO,CAAC,CAAA;IACnE,0HAA0H;IAC1H,mBAAmB,CAAC,MAAM,EAAE,MAAM,GAAG,OAAO,CAAC,IAAI,CAAC,CAAA;IAElD,yDAAyD;IACzD,KAAK,CAAC,MAAM,EAAE,MAAM,GAAG,OAAO,CAAC,SAAS,cAAc,EAAE,CAAC,CAAA;CAC1D;AAUD,wBAAgB,qBAAqB,CACnC,EAAE,EAAE,cAAc,EAClB,GAAG,GAAE,MAAM,MAAiB,GAC3B,eAAe,CAoLjB"}