@astram/guard 0.14.0 → 0.15.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 (95) hide show
  1. package/dist/auth/auth.module.d.ts.map +1 -1
  2. package/dist/auth/auth.module.js +57 -30
  3. package/dist/authentication/mariadb-api-key-store.d.ts +10 -1
  4. package/dist/authentication/mariadb-api-key-store.d.ts.map +1 -1
  5. package/dist/authentication/mariadb-api-key-store.js +20 -10
  6. package/dist/authentication/mariadb-credential-resolver.d.ts +8 -1
  7. package/dist/authentication/mariadb-credential-resolver.d.ts.map +1 -1
  8. package/dist/authentication/mariadb-credential-resolver.js +15 -5
  9. package/dist/authentication/mariadb-credential-writer.d.ts +6 -1
  10. package/dist/authentication/mariadb-credential-writer.d.ts.map +1 -1
  11. package/dist/authentication/mariadb-credential-writer.js +9 -3
  12. package/dist/authentication/mariadb-email-address-changer.d.ts +10 -1
  13. package/dist/authentication/mariadb-email-address-changer.d.ts.map +1 -1
  14. package/dist/authentication/mariadb-email-address-changer.js +22 -9
  15. package/dist/authentication/mariadb-email-change-token-store.d.ts +8 -1
  16. package/dist/authentication/mariadb-email-change-token-store.d.ts.map +1 -1
  17. package/dist/authentication/mariadb-email-change-token-store.js +18 -9
  18. package/dist/authentication/mariadb-mfa-device-store.d.ts +6 -1
  19. package/dist/authentication/mariadb-mfa-device-store.d.ts.map +1 -1
  20. package/dist/authentication/mariadb-mfa-device-store.js +22 -13
  21. package/dist/authentication/mariadb-profile-resolver.d.ts +6 -1
  22. package/dist/authentication/mariadb-profile-resolver.d.ts.map +1 -1
  23. package/dist/authentication/mariadb-profile-resolver.js +12 -6
  24. package/dist/authentication/mariadb-profile-writer.d.ts +6 -1
  25. package/dist/authentication/mariadb-profile-writer.d.ts.map +1 -1
  26. package/dist/authentication/mariadb-profile-writer.js +11 -4
  27. package/dist/authentication/mariadb-recovery-code-store.d.ts +6 -1
  28. package/dist/authentication/mariadb-recovery-code-store.d.ts.map +1 -1
  29. package/dist/authentication/mariadb-recovery-code-store.js +11 -5
  30. package/dist/authentication/mariadb-reset-token-store.d.ts +6 -1
  31. package/dist/authentication/mariadb-reset-token-store.d.ts.map +1 -1
  32. package/dist/authentication/mariadb-reset-token-store.js +11 -5
  33. package/dist/authentication/mariadb-session-sweeper.d.ts +6 -1
  34. package/dist/authentication/mariadb-session-sweeper.d.ts.map +1 -1
  35. package/dist/authentication/mariadb-session-sweeper.js +11 -5
  36. package/dist/authz/cross-tenant-grant-writer.d.ts.map +1 -1
  37. package/dist/authz/cross-tenant-grant-writer.js +4 -3
  38. package/dist/authz/list-scope-sql.d.ts +10 -2
  39. package/dist/authz/list-scope-sql.d.ts.map +1 -1
  40. package/dist/authz/list-scope-sql.js +4 -4
  41. package/dist/authz/mariadb-cross-tenant-grant-adapter.d.ts.map +1 -1
  42. package/dist/authz/mariadb-cross-tenant-grant-adapter.js +4 -3
  43. package/dist/authz/mariadb-list-scope-adapter.d.ts.map +1 -1
  44. package/dist/authz/mariadb-list-scope-adapter.js +4 -3
  45. package/dist/authz/mariadb-policy-store.d.ts.map +1 -1
  46. package/dist/authz/mariadb-policy-store.js +4 -3
  47. package/dist/authz/mariadb-record-rule-adapter.d.ts.map +1 -1
  48. package/dist/authz/mariadb-record-rule-adapter.js +4 -3
  49. package/dist/authz/mariadb-record-share-adapter.d.ts.map +1 -1
  50. package/dist/authz/mariadb-record-share-adapter.js +4 -3
  51. package/dist/authz/record-share-cascade.d.ts.map +1 -1
  52. package/dist/authz/record-share-cascade.js +4 -3
  53. package/dist/authz/record-share-writer.d.ts.map +1 -1
  54. package/dist/authz/record-share-writer.js +4 -3
  55. package/dist/authz/wire-record-authorization.d.ts +8 -0
  56. package/dist/authz/wire-record-authorization.d.ts.map +1 -1
  57. package/dist/authz/wire-record-authorization.js +14 -6
  58. package/dist/boot/boot-sequence.d.ts +4 -0
  59. package/dist/boot/boot-sequence.d.ts.map +1 -1
  60. package/dist/boot/boot-sequence.js +13 -1
  61. package/dist/boot/migration-ledger-check.d.ts +94 -0
  62. package/dist/boot/migration-ledger-check.d.ts.map +1 -0
  63. package/dist/boot/migration-ledger-check.js +280 -0
  64. package/dist/config/app-config.d.ts +29 -3
  65. package/dist/config/app-config.d.ts.map +1 -1
  66. package/dist/config/app-config.js +37 -6
  67. package/dist/config/config.module.d.ts +7 -0
  68. package/dist/config/config.module.d.ts.map +1 -1
  69. package/dist/config/config.module.js +8 -1
  70. package/dist/config/framework-schema-names.d.ts +29 -0
  71. package/dist/config/framework-schema-names.d.ts.map +1 -0
  72. package/dist/config/framework-schema-names.js +41 -0
  73. package/dist/identity/permission-facts.adapter.d.ts +7 -1
  74. package/dist/identity/permission-facts.adapter.d.ts.map +1 -1
  75. package/dist/identity/permission-facts.adapter.js +15 -6
  76. package/dist/index.d.ts +5 -2
  77. package/dist/index.d.ts.map +1 -1
  78. package/dist/index.js +18 -2
  79. package/dist/module/shield.module.d.ts.map +1 -1
  80. package/dist/module/shield.module.js +43 -7
  81. package/dist/session/mariadb-session-record-store.d.ts +8 -1
  82. package/dist/session/mariadb-session-record-store.d.ts.map +1 -1
  83. package/dist/session/mariadb-session-record-store.js +23 -13
  84. package/dist/session/session-restriction-store.d.ts +8 -1
  85. package/dist/session/session-restriction-store.d.ts.map +1 -1
  86. package/dist/session/session-restriction-store.js +15 -5
  87. package/migrations/1710000000006-CreateAuthzSchema.cjs +15 -4
  88. package/migrations/1710000000007-ExtendPermissionAndRolePermission.cjs +11 -3
  89. package/migrations/1710000000008-CreateAccessBundleTables.cjs +14 -4
  90. package/migrations/1710000000009-CreateRecordPermissionRule.cjs +15 -4
  91. package/migrations/1710000000014-CreateRecordShare.cjs +15 -4
  92. package/migrations/1710000000015-CreateScopeClosure.cjs +14 -4
  93. package/migrations/1710000000016-AlterCompanyParentFkRestrict.cjs +20 -9
  94. package/migrations/1710000000017-CreateServiceAccountKey.cjs +14 -4
  95. package/package.json +3 -3
@@ -1,13 +1,22 @@
1
1
  "use strict";
2
2
  Object.defineProperty(exports, "__esModule", { value: true });
3
3
  exports.MariaDbEmailChangeTokenStore = void 0;
4
- const TABLE = '`shield_identity`.`email_change_token`';
4
+ const framework_schema_names_js_1 = require("../config/framework-schema-names.js");
5
5
  class MariaDbEmailChangeTokenStore {
6
6
  pool;
7
7
  now;
8
- constructor(pool, now = Date.now) {
8
+ /** `<identity>`.`email_change_token`. */
9
+ table;
10
+ /** `<app>`.`users`. */
11
+ usersTable;
12
+ constructor(pool, now = Date.now,
13
+ /** Framework database names; absent ⇒ resolved from `SHIELD_DB_NAMESPACE` here, once. */
14
+ schemas) {
9
15
  this.pool = pool;
10
16
  this.now = now;
17
+ const s = (0, framework_schema_names_js_1.schemaNamesAtConstruction)(schemas);
18
+ this.table = (0, framework_schema_names_js_1.qualifiedTableName)(s.identity, 'email_change_token');
19
+ this.usersTable = (0, framework_schema_names_js_1.qualifiedTableName)(s.app, 'users');
11
20
  }
12
21
  async issue(token) {
13
22
  const now = this.now();
@@ -15,13 +24,13 @@ class MariaDbEmailChangeTokenStore {
15
24
  try {
16
25
  await conn.beginTransaction();
17
26
  try {
18
- const user = (await conn.query('SELECT u_uuid FROM `shield_app`.`users` WHERE u_uuid = ? FOR UPDATE', [token.principalId]));
27
+ const user = (await conn.query(`SELECT u_uuid FROM ${this.usersTable} WHERE u_uuid = ? FOR UPDATE`, [token.principalId]));
19
28
  if (user.length === 0)
20
29
  throw new Error('email change: unknown user');
21
- await conn.query(`DELETE FROM ${TABLE} WHERE ect_expires_at_ms <= ?`, [now]);
22
- await conn.query(`UPDATE ${TABLE} SET ect_consumed_at_ms = ?
30
+ await conn.query(`DELETE FROM ${this.table} WHERE ect_expires_at_ms <= ?`, [now]);
31
+ await conn.query(`UPDATE ${this.table} SET ect_consumed_at_ms = ?
23
32
  WHERE ect_principal_id = ? AND ect_consumed_at_ms IS NULL`, [now, token.principalId]);
24
- await conn.query(`INSERT INTO ${TABLE}
33
+ await conn.query(`INSERT INTO ${this.table}
25
34
  (ect_token_hash, ect_principal_id, ect_new_email, ect_old_email, ect_session_id,
26
35
  ect_tenant_id, ect_expires_at_ms, ect_consumed_at_ms, ect_created_at_ms)
27
36
  VALUES (?, ?, ?, ?, ?, ?, ?, NULL, ?)`, [
@@ -47,12 +56,12 @@ class MariaDbEmailChangeTokenStore {
47
56
  }
48
57
  async consume(tokenHash) {
49
58
  const now = this.now();
50
- const res = (await this.pool.query(`UPDATE ${TABLE} SET ect_consumed_at_ms = ?
59
+ const res = (await this.pool.query(`UPDATE ${this.table} SET ect_consumed_at_ms = ?
51
60
  WHERE ect_token_hash = ? AND ect_consumed_at_ms IS NULL AND ect_expires_at_ms > ?`, [now, tokenHash, now]));
52
61
  if (res.affectedRows !== 1)
53
62
  return null;
54
63
  const rows = (await this.pool.query(`SELECT ect_principal_id, ect_new_email, ect_old_email, ect_session_id, ect_tenant_id
55
- FROM ${TABLE} WHERE ect_token_hash = ? LIMIT 1`, [tokenHash]));
64
+ FROM ${this.table} WHERE ect_token_hash = ? LIMIT 1`, [tokenHash]));
56
65
  const row = rows[0];
57
66
  if (row === undefined)
58
67
  return null; // the user was deleted in between (FK cascade)
@@ -65,7 +74,7 @@ class MariaDbEmailChangeTokenStore {
65
74
  };
66
75
  }
67
76
  async invalidateAllForPrincipal(principalId) {
68
- await this.pool.query(`UPDATE ${TABLE} SET ect_consumed_at_ms = ?
77
+ await this.pool.query(`UPDATE ${this.table} SET ect_consumed_at_ms = ?
69
78
  WHERE ect_principal_id = ? AND ect_consumed_at_ms IS NULL`, [this.now(), principalId]);
70
79
  }
71
80
  }
@@ -1,8 +1,13 @@
1
1
  import type { Pool } from 'mariadb';
2
2
  import type { MfaDevice, MfaDeviceStore } from '../auth/ports/mfa-device-store.js';
3
+ import { type FrameworkSchemaNames } from '../config/framework-schema-names.js';
3
4
  export declare class MariaDbMfaDeviceStore implements MfaDeviceStore {
4
5
  private readonly pool;
5
- constructor(pool: Pool);
6
+ /** `<identity>`.`mfa_device`, resolved at construction. */
7
+ private readonly table;
8
+ constructor(pool: Pool,
9
+ /** Framework database names; absent ⇒ resolved from `SHIELD_DB_NAMESPACE` here, once. */
10
+ schemas?: FrameworkSchemaNames);
6
11
  listAll(principalId: string): Promise<MfaDevice[]>;
7
12
  listConfirmedSecrets(principalId: string): Promise<string[]>;
8
13
  getSecret(principalId: string, deviceId: string): Promise<string | null>;
@@ -1 +1 @@
1
- {"version":3,"file":"mariadb-mfa-device-store.d.ts","sourceRoot":"","sources":["../../src/authentication/mariadb-mfa-device-store.ts"],"names":[],"mappings":"AAuBA,OAAO,KAAK,EAAE,IAAI,EAAE,MAAM,SAAS,CAAC;AACpC,OAAO,KAAK,EAAE,SAAS,EAAE,cAAc,EAAE,MAAM,mCAAmC,CAAC;AAuBnF,qBAAa,qBAAsB,YAAW,cAAc;IAC9C,OAAO,CAAC,QAAQ,CAAC,IAAI;gBAAJ,IAAI,EAAE,IAAI;IAEjC,OAAO,CAAC,WAAW,EAAE,MAAM,GAAG,OAAO,CAAC,SAAS,EAAE,CAAC;IASlD,oBAAoB,CAAC,WAAW,EAAE,MAAM,GAAG,OAAO,CAAC,MAAM,EAAE,CAAC;IAS5D,SAAS,CAAC,WAAW,EAAE,MAAM,EAAE,QAAQ,EAAE,MAAM,GAAG,OAAO,CAAC,MAAM,GAAG,IAAI,CAAC;IASxE,KAAK,CAAC,WAAW,EAAE,MAAM,EAAE,IAAI,EAAE,MAAM,EAAE,MAAM,EAAE,MAAM,GAAG,OAAO,CAAC,MAAM,CAAC;IAiBzE,OAAO,CAAC,WAAW,EAAE,MAAM,EAAE,QAAQ,EAAE,MAAM,GAAG,OAAO,CAAC,OAAO,CAAC;IAkBhE,MAAM,CAAC,WAAW,EAAE,MAAM,EAAE,QAAQ,EAAE,MAAM,EAAE,IAAI,EAAE,MAAM,GAAG,OAAO,CAAC,SAAS,GAAG,IAAI,CAAC;IAetF,MAAM,CAAC,WAAW,EAAE,MAAM,EAAE,QAAQ,EAAE,MAAM,GAAG,OAAO,CAAC,OAAO,CAAC;IAQ/D,cAAc,CAAC,WAAW,EAAE,MAAM,GAAG,OAAO,CAAC,MAAM,CAAC;IASpD,SAAS,CAAC,MAAM,EAAE,MAAM,GAAG,OAAO,CAAC,IAAI,CAAC;CAU/C"}
1
+ {"version":3,"file":"mariadb-mfa-device-store.d.ts","sourceRoot":"","sources":["../../src/authentication/mariadb-mfa-device-store.ts"],"names":[],"mappings":"AAuBA,OAAO,KAAK,EAAE,IAAI,EAAE,MAAM,SAAS,CAAC;AACpC,OAAO,KAAK,EAAE,SAAS,EAAE,cAAc,EAAE,MAAM,mCAAmC,CAAC;AACnF,OAAO,EAGL,KAAK,oBAAoB,EAC1B,MAAM,qCAAqC,CAAC;AAuB7C,qBAAa,qBAAsB,YAAW,cAAc;IAKxD,OAAO,CAAC,QAAQ,CAAC,IAAI;IAJvB,2DAA2D;IAC3D,OAAO,CAAC,QAAQ,CAAC,KAAK,CAAS;gBAGZ,IAAI,EAAE,IAAI;IAC3B,yFAAyF;IACzF,OAAO,CAAC,EAAE,oBAAoB;IAK1B,OAAO,CAAC,WAAW,EAAE,MAAM,GAAG,OAAO,CAAC,SAAS,EAAE,CAAC;IASlD,oBAAoB,CAAC,WAAW,EAAE,MAAM,GAAG,OAAO,CAAC,MAAM,EAAE,CAAC;IAS5D,SAAS,CAAC,WAAW,EAAE,MAAM,EAAE,QAAQ,EAAE,MAAM,GAAG,OAAO,CAAC,MAAM,GAAG,IAAI,CAAC;IASxE,KAAK,CAAC,WAAW,EAAE,MAAM,EAAE,IAAI,EAAE,MAAM,EAAE,MAAM,EAAE,MAAM,GAAG,OAAO,CAAC,MAAM,CAAC;IAiBzE,OAAO,CAAC,WAAW,EAAE,MAAM,EAAE,QAAQ,EAAE,MAAM,GAAG,OAAO,CAAC,OAAO,CAAC;IAkBhE,MAAM,CAAC,WAAW,EAAE,MAAM,EAAE,QAAQ,EAAE,MAAM,EAAE,IAAI,EAAE,MAAM,GAAG,OAAO,CAAC,SAAS,GAAG,IAAI,CAAC;IAetF,MAAM,CAAC,WAAW,EAAE,MAAM,EAAE,QAAQ,EAAE,MAAM,GAAG,OAAO,CAAC,OAAO,CAAC;IAQ/D,cAAc,CAAC,WAAW,EAAE,MAAM,GAAG,OAAO,CAAC,MAAM,CAAC;IASpD,SAAS,CAAC,MAAM,EAAE,MAAM,GAAG,OAAO,CAAC,IAAI,CAAC;CAU/C"}
@@ -24,6 +24,7 @@ exports.MariaDbMfaDeviceStore = void 0;
24
24
  * other method's genuine store outage propagates (fails loud), never swallowed.
25
25
  */
26
26
  const node_crypto_1 = require("node:crypto");
27
+ const framework_schema_names_js_1 = require("../config/framework-schema-names.js");
27
28
  /** Pending-device TTL — a `begin` never confirmed within this window is self-pruned. */
28
29
  const PENDING_TTL_MS = 15 * 60 * 1000;
29
30
  /** Map a DB row → the display shape (NO secret). BIGINT columns arrive as bigint → Number. */
@@ -36,67 +37,75 @@ const toDevice = (r) => ({
36
37
  });
37
38
  class MariaDbMfaDeviceStore {
38
39
  pool;
39
- constructor(pool) {
40
+ /** `<identity>`.`mfa_device`, resolved at construction. */
41
+ table;
42
+ constructor(pool,
43
+ /** Framework database names; absent ⇒ resolved from `SHIELD_DB_NAMESPACE` here, once. */
44
+ schemas) {
40
45
  this.pool = pool;
46
+ this.table = (0, framework_schema_names_js_1.qualifiedTableName)((0, framework_schema_names_js_1.schemaNamesAtConstruction)(schemas).identity, 'mfa_device');
41
47
  }
42
48
  async listAll(principalId) {
43
49
  const rows = (await this.pool.query(`SELECT md_id, md_name, md_secret, md_created_at_ms, md_last_used_at_ms, md_confirmed_at_ms
44
- FROM \`shield_identity\`.\`mfa_device\` WHERE md_principal_id = ? ORDER BY md_created_at_ms ASC`, [principalId]));
50
+ FROM ${this.table} WHERE md_principal_id = ? ORDER BY md_created_at_ms ASC`, [principalId]));
45
51
  return rows.map(toDevice);
46
52
  }
47
53
  async listConfirmedSecrets(principalId) {
48
- const rows = (await this.pool.query(`SELECT md_secret FROM \`shield_identity\`.\`mfa_device\`
54
+ const rows = (await this.pool.query(`SELECT md_secret FROM ${this.table}
49
55
  WHERE md_principal_id = ? AND md_confirmed_at_ms IS NOT NULL`, [principalId]));
50
56
  return rows.map((r) => r.md_secret);
51
57
  }
52
58
  async getSecret(principalId, deviceId) {
53
- const rows = (await this.pool.query(`SELECT md_secret FROM \`shield_identity\`.\`mfa_device\`
59
+ const rows = (await this.pool.query(`SELECT md_secret FROM ${this.table}
54
60
  WHERE md_id = ? AND md_principal_id = ? LIMIT 1`, [deviceId, principalId]));
55
61
  return rows[0]?.md_secret ?? null;
56
62
  }
57
63
  async begin(principalId, name, secret) {
58
64
  // Prune the caller's stale pending rows first (self-pruning; no cron).
59
- await this.pool.query(`DELETE FROM \`shield_identity\`.\`mfa_device\`
65
+ await this.pool.query(`DELETE FROM ${this.table}
60
66
  WHERE md_principal_id = ? AND md_confirmed_at_ms IS NULL AND md_created_at_ms < ?`, [principalId, Date.now() - PENDING_TTL_MS]);
61
67
  const id = (0, node_crypto_1.randomUUID)();
62
- await this.pool.query(`INSERT INTO \`shield_identity\`.\`mfa_device\`
68
+ await this.pool.query(`INSERT INTO ${this.table}
63
69
  (md_id, md_principal_id, md_name, md_secret, md_created_at_ms, md_last_used_at_ms, md_confirmed_at_ms)
64
70
  VALUES (?, ?, ?, ?, ?, NULL, NULL)`, [id, principalId, name, secret, Date.now()]);
65
71
  return id;
66
72
  }
67
73
  async confirm(principalId, deviceId) {
68
- const res = (await this.pool.query(`UPDATE \`shield_identity\`.\`mfa_device\` SET md_confirmed_at_ms = ?
74
+ const res = (await this.pool.query(`UPDATE ${this.table} SET md_confirmed_at_ms = ?
69
75
  WHERE md_id = ? AND md_principal_id = ? AND md_confirmed_at_ms IS NULL`, [Date.now(), deviceId, principalId]));
70
76
  if (res.affectedRows !== 1)
71
77
  return false;
72
78
  // KI #14 re-review: once a device is confirmed MFA is on, so every later begin needs a code.
73
79
  // Drop the principal's OTHER pending devices: one begun by a stolen session while MFA was
74
80
  // still off (between the user's own begin and confirm) must not stay confirmable.
75
- await this.pool.query(`DELETE FROM \`shield_identity\`.\`mfa_device\`
81
+ await this.pool.query(`DELETE FROM ${this.table}
76
82
  WHERE md_principal_id = ? AND md_confirmed_at_ms IS NULL AND md_id <> ?`, [principalId, deviceId]);
77
83
  return true;
78
84
  }
79
85
  async rename(principalId, deviceId, name) {
80
- const res = (await this.pool.query(`UPDATE \`shield_identity\`.\`mfa_device\` SET md_name = ?
86
+ const res = (await this.pool.query(`UPDATE ${this.table} SET md_name = ?
81
87
  WHERE md_id = ? AND md_principal_id = ?`, [name, deviceId, principalId]));
82
88
  if (res.affectedRows !== 1)
83
89
  return null;
84
90
  const rows = (await this.pool.query(`SELECT md_id, md_name, md_secret, md_created_at_ms, md_last_used_at_ms, md_confirmed_at_ms
85
- FROM \`shield_identity\`.\`mfa_device\` WHERE md_id = ? AND md_principal_id = ? LIMIT 1`, [deviceId, principalId]));
91
+ FROM ${this.table} WHERE md_id = ? AND md_principal_id = ? LIMIT 1`, [deviceId, principalId]));
86
92
  return rows[0] ? toDevice(rows[0]) : null;
87
93
  }
88
94
  async remove(principalId, deviceId) {
89
- const res = (await this.pool.query(`DELETE FROM \`shield_identity\`.\`mfa_device\` WHERE md_id = ? AND md_principal_id = ?`, [deviceId, principalId]));
95
+ const res = (await this.pool.query(`DELETE FROM ${this.table} WHERE md_id = ? AND md_principal_id = ?`, [deviceId, principalId]));
90
96
  return res.affectedRows === 1;
91
97
  }
92
98
  async countConfirmed(principalId) {
93
- const rows = (await this.pool.query(`SELECT COUNT(*) AS c FROM \`shield_identity\`.\`mfa_device\`
99
+ const rows = (await this.pool.query(`SELECT COUNT(*) AS c FROM ${this.table}
94
100
  WHERE md_principal_id = ? AND md_confirmed_at_ms IS NOT NULL`, [principalId]));
95
101
  return Number(rows[0]?.c ?? 0);
96
102
  }
97
103
  async stampUsed(secret) {
98
104
  try {
99
- await this.pool.query(`UPDATE \`shield_identity\`.\`mfa_device\` SET md_last_used_at_ms = ? WHERE md_secret = ?`, [Date.now(), secret]);
105
+ await this.pool.query(`UPDATE ${this.table} SET md_last_used_at_ms = ? WHERE md_secret = ?`, [
106
+ Date.now(),
107
+ secret,
108
+ ]);
100
109
  }
101
110
  catch {
102
111
  // best-effort; a stamp failure must never fail a login.
@@ -14,10 +14,15 @@
14
14
  import type { Pool } from 'mariadb';
15
15
  import type { Principal } from '@astram/core';
16
16
  import type { CurrentUserProfile, ProfileResolver } from '../auth/profile-resolver.js';
17
+ import { type FrameworkSchemaNames } from '../config/framework-schema-names.js';
17
18
  export declare class MariaDbProfileResolver implements ProfileResolver {
18
19
  private readonly pool;
19
20
  private readonly now;
20
- constructor(pool: Pool, now?: () => number);
21
+ /** The org database (`<app>`), resolved at construction. */
22
+ private readonly app;
23
+ constructor(pool: Pool, now?: () => number,
24
+ /** Framework database names; absent ⇒ resolved from `SHIELD_DB_NAMESPACE` here, once. */
25
+ schemas?: FrameworkSchemaNames);
21
26
  resolve(principal: Principal): Promise<CurrentUserProfile | null>;
22
27
  private resolveRoleNames;
23
28
  }
@@ -1 +1 @@
1
- {"version":3,"file":"mariadb-profile-resolver.d.ts","sourceRoot":"","sources":["../../src/authentication/mariadb-profile-resolver.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;GAYG;AAEH,OAAO,KAAK,EAAE,IAAI,EAAE,MAAM,SAAS,CAAC;AACpC,OAAO,KAAK,EAAE,SAAS,EAAE,MAAM,cAAc,CAAC;AAC9C,OAAO,KAAK,EAAE,kBAAkB,EAAE,eAAe,EAAe,MAAM,6BAA6B,CAAC;AAcpG,qBAAa,sBAAuB,YAAW,eAAe;IAE1D,OAAO,CAAC,QAAQ,CAAC,IAAI;IACrB,OAAO,CAAC,QAAQ,CAAC,GAAG;gBADH,IAAI,EAAE,IAAI,EACV,GAAG,GAAE,MAAM,MAAiB;IAGzC,OAAO,CAAC,SAAS,EAAE,SAAS,GAAG,OAAO,CAAC,kBAAkB,GAAG,IAAI,CAAC;YA4BzD,gBAAgB;CAc/B"}
1
+ {"version":3,"file":"mariadb-profile-resolver.d.ts","sourceRoot":"","sources":["../../src/authentication/mariadb-profile-resolver.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;GAYG;AAEH,OAAO,KAAK,EAAE,IAAI,EAAE,MAAM,SAAS,CAAC;AACpC,OAAO,KAAK,EAAE,SAAS,EAAE,MAAM,cAAc,CAAC;AAC9C,OAAO,KAAK,EAAE,kBAAkB,EAAE,eAAe,EAAe,MAAM,6BAA6B,CAAC;AACpG,OAAO,EAEL,KAAK,oBAAoB,EAC1B,MAAM,qCAAqC,CAAC;AAc7C,qBAAa,sBAAuB,YAAW,eAAe;IAK1D,OAAO,CAAC,QAAQ,CAAC,IAAI;IACrB,OAAO,CAAC,QAAQ,CAAC,GAAG;IALtB,4DAA4D;IAC5D,OAAO,CAAC,QAAQ,CAAC,GAAG,CAAS;gBAGV,IAAI,EAAE,IAAI,EACV,GAAG,GAAE,MAAM,MAAiB;IAC7C,yFAAyF;IACzF,OAAO,CAAC,EAAE,oBAAoB;IAK1B,OAAO,CAAC,SAAS,EAAE,SAAS,GAAG,OAAO,CAAC,kBAAkB,GAAG,IAAI,CAAC;YA4BzD,gBAAgB;CAc/B"}
@@ -14,21 +14,27 @@
14
14
  */
15
15
  Object.defineProperty(exports, "__esModule", { value: true });
16
16
  exports.MariaDbProfileResolver = void 0;
17
+ const framework_schema_names_js_1 = require("../config/framework-schema-names.js");
17
18
  class MariaDbProfileResolver {
18
19
  pool;
19
20
  now;
20
- constructor(pool, now = Date.now) {
21
+ /** The org database (`<app>`), resolved at construction. */
22
+ app;
23
+ constructor(pool, now = Date.now,
24
+ /** Framework database names; absent ⇒ resolved from `SHIELD_DB_NAMESPACE` here, once. */
25
+ schemas) {
21
26
  this.pool = pool;
22
27
  this.now = now;
28
+ this.app = (0, framework_schema_names_js_1.schemaNamesAtConstruction)(schemas).app;
23
29
  }
24
30
  async resolve(principal) {
25
31
  const userUuid = principal.id;
26
32
  const companyUuid = principal.tenantId;
27
- const users = (await this.pool.query('SELECT u_username, u_email FROM `shield_app`.`users` WHERE u_uuid = ? LIMIT 1', [userUuid]));
33
+ const users = (await this.pool.query(`SELECT u_username, u_email FROM \`${this.app}\`.\`users\` WHERE u_uuid = ? LIMIT 1`, [userUuid]));
28
34
  const user = users[0];
29
35
  if (!user)
30
36
  return null; // deleted user → no profile (never id-leak; endpoint 404s)
31
- const companies = (await this.pool.query('SELECT c_name FROM `shield_app`.`companies` WHERE c_uuid = ? LIMIT 1', [companyUuid]));
37
+ const companies = (await this.pool.query(`SELECT c_name FROM \`${this.app}\`.\`companies\` WHERE c_uuid = ? LIMIT 1`, [companyUuid]));
32
38
  const companyName = companies[0]?.c_name ?? '(unknown company)';
33
39
  const roles = await this.resolveRoleNames(userUuid, companyUuid);
34
40
  return {
@@ -42,9 +48,9 @@ class MariaDbProfileResolver {
42
48
  async resolveRoleNames(userUuid, companyUuid) {
43
49
  const nowMs = this.now();
44
50
  const rows = (await this.pool.query(`SELECT DISTINCT r.r_uuid, r.r_name
45
- FROM \`shield_app\`.\`membership_posting\` mp
46
- JOIN \`shield_app\`.\`company_membership\` cm ON cm.cm_uuid = mp.mp_membership_uuid
47
- JOIN \`shield_app\`.\`roles\` r ON r.r_uuid = mp.mp_role_uuid
51
+ FROM \`${this.app}\`.\`membership_posting\` mp
52
+ JOIN \`${this.app}\`.\`company_membership\` cm ON cm.cm_uuid = mp.mp_membership_uuid
53
+ JOIN \`${this.app}\`.\`roles\` r ON r.r_uuid = mp.mp_role_uuid
48
54
  WHERE cm.cm_user_uuid = ? AND cm.cm_company_uuid = ?
49
55
  AND (mp.mp_effective_from_ms IS NULL OR mp.mp_effective_from_ms <= ?)
50
56
  AND (mp.mp_effective_until_ms IS NULL OR mp.mp_effective_until_ms > ?)`, [userUuid, companyUuid, nowMs, nowMs]));
@@ -7,10 +7,15 @@
7
7
  import type { Pool } from 'mariadb';
8
8
  import { type ProfileWriter } from '../auth/ports/profile-writer.js';
9
9
  import type { CurrentUserProfile } from '../auth/profile-resolver.js';
10
+ import { type FrameworkSchemaNames } from '../config/framework-schema-names.js';
10
11
  export declare class MariaDbProfileWriter implements ProfileWriter {
11
12
  private readonly pool;
12
13
  private readonly resolver;
13
- constructor(pool: Pool);
14
+ /** The org database (`<app>`), resolved at construction; the re-read resolver uses the same. */
15
+ private readonly app;
16
+ constructor(pool: Pool,
17
+ /** Framework database names; absent ⇒ resolved from `SHIELD_DB_NAMESPACE` here, once. */
18
+ schemas?: FrameworkSchemaNames);
14
19
  update(principalId: string, changes: {
15
20
  name?: string;
16
21
  email?: string;
@@ -1 +1 @@
1
- {"version":3,"file":"mariadb-profile-writer.d.ts","sourceRoot":"","sources":["../../src/authentication/mariadb-profile-writer.ts"],"names":[],"mappings":"AAAA;;;;;GAKG;AACH,OAAO,KAAK,EAAE,IAAI,EAAE,MAAM,SAAS,CAAC;AACpC,OAAO,EAAyB,KAAK,aAAa,EAAE,MAAM,iCAAiC,CAAC;AAC5F,OAAO,KAAK,EAAE,kBAAkB,EAAE,MAAM,6BAA6B,CAAC;AAgBtE,qBAAa,oBAAqB,YAAW,aAAa;IAE5C,OAAO,CAAC,QAAQ,CAAC,IAAI;IADjC,OAAO,CAAC,QAAQ,CAAC,QAAQ,CAAyB;gBACrB,IAAI,EAAE,IAAI;IAIjC,MAAM,CACV,WAAW,EAAE,MAAM,EACnB,OAAO,EAAE;QAAE,IAAI,CAAC,EAAE,MAAM,CAAC;QAAC,KAAK,CAAC,EAAE,MAAM,CAAA;KAAE,GACzC,OAAO,CAAC,kBAAkB,CAAC;CAgD/B"}
1
+ {"version":3,"file":"mariadb-profile-writer.d.ts","sourceRoot":"","sources":["../../src/authentication/mariadb-profile-writer.ts"],"names":[],"mappings":"AAAA;;;;;GAKG;AACH,OAAO,KAAK,EAAE,IAAI,EAAE,MAAM,SAAS,CAAC;AACpC,OAAO,EAAyB,KAAK,aAAa,EAAE,MAAM,iCAAiC,CAAC;AAC5F,OAAO,KAAK,EAAE,kBAAkB,EAAE,MAAM,6BAA6B,CAAC;AAEtE,OAAO,EAEL,KAAK,oBAAoB,EAC1B,MAAM,qCAAqC,CAAC;AAe7C,qBAAa,oBAAqB,YAAW,aAAa;IAKtD,OAAO,CAAC,QAAQ,CAAC,IAAI;IAJvB,OAAO,CAAC,QAAQ,CAAC,QAAQ,CAAyB;IAClD,gGAAgG;IAChG,OAAO,CAAC,QAAQ,CAAC,GAAG,CAAS;gBAEV,IAAI,EAAE,IAAI;IAC3B,yFAAyF;IACzF,OAAO,CAAC,EAAE,oBAAoB;IAO1B,MAAM,CACV,WAAW,EAAE,MAAM,EACnB,OAAO,EAAE;QAAE,IAAI,CAAC,EAAE,MAAM,CAAC;QAAC,KAAK,CAAC,EAAE,MAAM,CAAA;KAAE,GACzC,OAAO,CAAC,kBAAkB,CAAC;CAgD/B"}
@@ -3,6 +3,7 @@ Object.defineProperty(exports, "__esModule", { value: true });
3
3
  exports.MariaDbProfileWriter = void 0;
4
4
  const profile_writer_js_1 = require("../auth/ports/profile-writer.js");
5
5
  const mariadb_profile_resolver_js_1 = require("./mariadb-profile-resolver.js");
6
+ const framework_schema_names_js_1 = require("../config/framework-schema-names.js");
6
7
  /** MariaDB `ER_DUP_ENTRY`: here `IDX_users_username` refused the name (KI #97). */
7
8
  const ER_DUP_ENTRY = 1062;
8
9
  function isDuplicateKey(err) {
@@ -14,9 +15,15 @@ function isDuplicateKey(err) {
14
15
  class MariaDbProfileWriter {
15
16
  pool;
16
17
  resolver;
17
- constructor(pool) {
18
+ /** The org database (`<app>`), resolved at construction; the re-read resolver uses the same. */
19
+ app;
20
+ constructor(pool,
21
+ /** Framework database names; absent ⇒ resolved from `SHIELD_DB_NAMESPACE` here, once. */
22
+ schemas) {
18
23
  this.pool = pool;
19
- this.resolver = new mariadb_profile_resolver_js_1.MariaDbProfileResolver(pool);
24
+ const s = (0, framework_schema_names_js_1.schemaNamesAtConstruction)(schemas);
25
+ this.app = s.app;
26
+ this.resolver = new mariadb_profile_resolver_js_1.MariaDbProfileResolver(pool, undefined, s);
20
27
  }
21
28
  async update(principalId, changes) {
22
29
  // Phase 12 / KI #87: the email is written ONLY by the verified email-change flow
@@ -34,7 +41,7 @@ class MariaDbProfileWriter {
34
41
  if (sets.length > 0) {
35
42
  params.push(principalId);
36
43
  try {
37
- await this.pool.query(`UPDATE \`shield_app\`.\`users\` SET ${sets.join(', ')} WHERE u_uuid = ?`, params);
44
+ await this.pool.query(`UPDATE \`${this.app}\`.\`users\` SET ${sets.join(', ')} WHERE u_uuid = ?`, params);
38
45
  }
39
46
  catch (err) {
40
47
  // KI #97: the driver message quotes the value; drop it and answer a typed conflict.
@@ -44,7 +51,7 @@ class MariaDbProfileWriter {
44
51
  }
45
52
  }
46
53
  // Resolve the caller's active company so the re-read profile is tenant-correct.
47
- const active = (await this.pool.query("SELECT cm_company_uuid FROM `shield_app`.`company_membership` WHERE cm_user_uuid = ? AND cm_is_active = 1 AND cm_status = 'active' LIMIT 1", [principalId]));
54
+ const active = (await this.pool.query(`SELECT cm_company_uuid FROM \`${this.app}\`.\`company_membership\` WHERE cm_user_uuid = ? AND cm_is_active = 1 AND cm_status = 'active' LIMIT 1`, [principalId]));
48
55
  const tenantId = active[0]?.cm_company_uuid ?? '';
49
56
  const profile = await this.resolver.resolve({
50
57
  kind: 'user',
@@ -21,14 +21,19 @@
21
21
  import type { Pool } from 'mariadb';
22
22
  import type { PasswordHasher } from '@astram/core';
23
23
  import type { RecoveryCodeStore } from '../auth/ports/recovery-code-store.js';
24
+ import { type FrameworkSchemaNames } from '../config/framework-schema-names.js';
24
25
  export declare class MariaDbRecoveryCodeStore implements RecoveryCodeStore {
25
26
  private readonly pool;
26
27
  /** The SAME Argon2id hasher the framework uses to hash the codes on enroll. */
27
28
  private readonly hasher;
28
29
  private readonly now;
30
+ /** `<identity>`.`mfa_recovery_code`, resolved at construction. */
31
+ private readonly table;
29
32
  constructor(pool: Pool,
30
33
  /** The SAME Argon2id hasher the framework uses to hash the codes on enroll. */
31
- hasher: PasswordHasher, now?: () => number);
34
+ hasher: PasswordHasher, now?: () => number,
35
+ /** Framework database names; absent ⇒ resolved from `SHIELD_DB_NAMESPACE` here, once. */
36
+ schemas?: FrameworkSchemaNames);
32
37
  /**
33
38
  * Replace the principal's entire recovery-code set with `codeHashes` (already
34
39
  * Argon2-hashed). Wipes any prior codes first, then inserts the new batch. Passing
@@ -1 +1 @@
1
- {"version":3,"file":"mariadb-recovery-code-store.d.ts","sourceRoot":"","sources":["../../src/authentication/mariadb-recovery-code-store.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;GAmBG;AACH,OAAO,KAAK,EAAE,IAAI,EAAE,MAAM,SAAS,CAAC;AACpC,OAAO,KAAK,EAAE,cAAc,EAAE,MAAM,cAAc,CAAC;AACnD,OAAO,KAAK,EAAE,iBAAiB,EAAE,MAAM,sCAAsC,CAAC;AAM9E,qBAAa,wBAAyB,YAAW,iBAAiB;IAE9D,OAAO,CAAC,QAAQ,CAAC,IAAI;IACrB,+EAA+E;IAC/E,OAAO,CAAC,QAAQ,CAAC,MAAM;IACvB,OAAO,CAAC,QAAQ,CAAC,GAAG;gBAHH,IAAI,EAAE,IAAI;IAC3B,+EAA+E;IAC9D,MAAM,EAAE,cAAc,EACtB,GAAG,GAAE,MAAM,MAAiB;IAG/C;;;;OAIG;IACG,UAAU,CAAC,WAAW,EAAE,MAAM,EAAE,UAAU,EAAE,SAAS,MAAM,EAAE,GAAG,OAAO,CAAC,IAAI,CAAC;IAgBnF;;;;;;OAMG;IACG,OAAO,CAAC,WAAW,EAAE,MAAM,EAAE,OAAO,EAAE,MAAM,GAAG,OAAO,CAAC,OAAO,CAAC;CAqBtE"}
1
+ {"version":3,"file":"mariadb-recovery-code-store.d.ts","sourceRoot":"","sources":["../../src/authentication/mariadb-recovery-code-store.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;GAmBG;AACH,OAAO,KAAK,EAAE,IAAI,EAAE,MAAM,SAAS,CAAC;AACpC,OAAO,KAAK,EAAE,cAAc,EAAE,MAAM,cAAc,CAAC;AACnD,OAAO,KAAK,EAAE,iBAAiB,EAAE,MAAM,sCAAsC,CAAC;AAC9E,OAAO,EAGL,KAAK,oBAAoB,EAC1B,MAAM,qCAAqC,CAAC;AAM7C,qBAAa,wBAAyB,YAAW,iBAAiB;IAK9D,OAAO,CAAC,QAAQ,CAAC,IAAI;IACrB,+EAA+E;IAC/E,OAAO,CAAC,QAAQ,CAAC,MAAM;IACvB,OAAO,CAAC,QAAQ,CAAC,GAAG;IAPtB,kEAAkE;IAClE,OAAO,CAAC,QAAQ,CAAC,KAAK,CAAS;gBAGZ,IAAI,EAAE,IAAI;IAC3B,+EAA+E;IAC9D,MAAM,EAAE,cAAc,EACtB,GAAG,GAAE,MAAM,MAAiB;IAC7C,yFAAyF;IACzF,OAAO,CAAC,EAAE,oBAAoB;IAQhC;;;;OAIG;IACG,UAAU,CAAC,WAAW,EAAE,MAAM,EAAE,UAAU,EAAE,SAAS,MAAM,EAAE,GAAG,OAAO,CAAC,IAAI,CAAC;IAanF;;;;;;OAMG;IACG,OAAO,CAAC,WAAW,EAAE,MAAM,EAAE,OAAO,EAAE,MAAM,GAAG,OAAO,CAAC,OAAO,CAAC;CAqBtE"}
@@ -1,16 +1,22 @@
1
1
  "use strict";
2
2
  Object.defineProperty(exports, "__esModule", { value: true });
3
3
  exports.MariaDbRecoveryCodeStore = void 0;
4
+ const framework_schema_names_js_1 = require("../config/framework-schema-names.js");
4
5
  class MariaDbRecoveryCodeStore {
5
6
  pool;
6
7
  hasher;
7
8
  now;
9
+ /** `<identity>`.`mfa_recovery_code`, resolved at construction. */
10
+ table;
8
11
  constructor(pool,
9
12
  /** The SAME Argon2id hasher the framework uses to hash the codes on enroll. */
10
- hasher, now = Date.now) {
13
+ hasher, now = Date.now,
14
+ /** Framework database names; absent ⇒ resolved from `SHIELD_DB_NAMESPACE` here, once. */
15
+ schemas) {
11
16
  this.pool = pool;
12
17
  this.hasher = hasher;
13
18
  this.now = now;
19
+ this.table = (0, framework_schema_names_js_1.qualifiedTableName)((0, framework_schema_names_js_1.schemaNamesAtConstruction)(schemas).identity, 'mfa_recovery_code');
14
20
  }
15
21
  /**
16
22
  * Replace the principal's entire recovery-code set with `codeHashes` (already
@@ -18,10 +24,10 @@ class MariaDbRecoveryCodeStore {
18
24
  * an empty array simply wipes (used when MFA is disabled).
19
25
  */
20
26
  async replaceAll(principalId, codeHashes) {
21
- await this.pool.query(`DELETE FROM \`shield_identity\`.\`mfa_recovery_code\` WHERE mrc_principal_id = ?`, [principalId]);
27
+ await this.pool.query(`DELETE FROM ${this.table} WHERE mrc_principal_id = ?`, [principalId]);
22
28
  const createdAt = this.now();
23
29
  for (const hash of codeHashes) {
24
- await this.pool.query(`INSERT INTO \`shield_identity\`.\`mfa_recovery_code\`
30
+ await this.pool.query(`INSERT INTO ${this.table}
25
31
  (mrc_principal_id, mrc_code_hash, mrc_consumed_at_ms, mrc_created_at_ms)
26
32
  VALUES (?, ?, NULL, ?)`, [principalId, hash, createdAt]);
27
33
  }
@@ -36,11 +42,11 @@ class MariaDbRecoveryCodeStore {
36
42
  async consume(principalId, rawCode) {
37
43
  if (typeof rawCode !== 'string' || rawCode.length === 0)
38
44
  return false;
39
- const rows = (await this.pool.query(`SELECT mrc_code_hash FROM \`shield_identity\`.\`mfa_recovery_code\`
45
+ const rows = (await this.pool.query(`SELECT mrc_code_hash FROM ${this.table}
40
46
  WHERE mrc_principal_id = ? AND mrc_consumed_at_ms IS NULL`, [principalId]));
41
47
  for (const row of rows) {
42
48
  if (await this.hasher.verify(row.mrc_code_hash, rawCode)) {
43
- const res = (await this.pool.query(`UPDATE \`shield_identity\`.\`mfa_recovery_code\`
49
+ const res = (await this.pool.query(`UPDATE ${this.table}
44
50
  SET mrc_consumed_at_ms = ?
45
51
  WHERE mrc_principal_id = ? AND mrc_code_hash = ? AND mrc_consumed_at_ms IS NULL`, [this.now(), principalId, row.mrc_code_hash]));
46
52
  // Single-use guard: only the UPDATE that flips NULL→consumed wins.
@@ -15,10 +15,15 @@
15
15
  */
16
16
  import type { Pool } from 'mariadb';
17
17
  import type { ResetTokenStore } from '../auth/ports/reset-token-store.js';
18
+ import { type FrameworkSchemaNames } from '../config/framework-schema-names.js';
18
19
  export declare class MariaDbResetTokenStore implements ResetTokenStore {
19
20
  private readonly pool;
20
21
  private readonly now;
21
- constructor(pool: Pool, now?: () => number);
22
+ /** `<identity>`.`password_reset_token`, resolved at construction. */
23
+ private readonly table;
24
+ constructor(pool: Pool, now?: () => number,
25
+ /** Framework database names; absent ⇒ resolved from `SHIELD_DB_NAMESPACE` here, once. */
26
+ schemas?: FrameworkSchemaNames);
22
27
  issue(principalId: string, tokenHash: string, expiresAtMs: number): Promise<void>;
23
28
  consume(tokenHash: string): Promise<string | null>;
24
29
  invalidateAllForPrincipal(principalId: string): Promise<void>;
@@ -1 +1 @@
1
- {"version":3,"file":"mariadb-reset-token-store.d.ts","sourceRoot":"","sources":["../../src/authentication/mariadb-reset-token-store.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;GAcG;AACH,OAAO,KAAK,EAAE,IAAI,EAAE,MAAM,SAAS,CAAC;AACpC,OAAO,KAAK,EAAE,eAAe,EAAE,MAAM,oCAAoC,CAAC;AAM1E,qBAAa,sBAAuB,YAAW,eAAe;IAE1D,OAAO,CAAC,QAAQ,CAAC,IAAI;IACrB,OAAO,CAAC,QAAQ,CAAC,GAAG;gBADH,IAAI,EAAE,IAAI,EACV,GAAG,GAAE,MAAM,MAAiB;IAGzC,KAAK,CAAC,WAAW,EAAE,MAAM,EAAE,SAAS,EAAE,MAAM,EAAE,WAAW,EAAE,MAAM,GAAG,OAAO,CAAC,IAAI,CAAC;IASjF,OAAO,CAAC,SAAS,EAAE,MAAM,GAAG,OAAO,CAAC,MAAM,GAAG,IAAI,CAAC;IA0BlD,yBAAyB,CAAC,WAAW,EAAE,MAAM,GAAG,OAAO,CAAC,IAAI,CAAC;CAUpE"}
1
+ {"version":3,"file":"mariadb-reset-token-store.d.ts","sourceRoot":"","sources":["../../src/authentication/mariadb-reset-token-store.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;GAcG;AACH,OAAO,KAAK,EAAE,IAAI,EAAE,MAAM,SAAS,CAAC;AACpC,OAAO,KAAK,EAAE,eAAe,EAAE,MAAM,oCAAoC,CAAC;AAC1E,OAAO,EAGL,KAAK,oBAAoB,EAC1B,MAAM,qCAAqC,CAAC;AAM7C,qBAAa,sBAAuB,YAAW,eAAe;IAK1D,OAAO,CAAC,QAAQ,CAAC,IAAI;IACrB,OAAO,CAAC,QAAQ,CAAC,GAAG;IALtB,qEAAqE;IACrE,OAAO,CAAC,QAAQ,CAAC,KAAK,CAAS;gBAGZ,IAAI,EAAE,IAAI,EACV,GAAG,GAAE,MAAM,MAAiB;IAC7C,yFAAyF;IACzF,OAAO,CAAC,EAAE,oBAAoB;IAQ1B,KAAK,CAAC,WAAW,EAAE,MAAM,EAAE,SAAS,EAAE,MAAM,EAAE,WAAW,EAAE,MAAM,GAAG,OAAO,CAAC,IAAI,CAAC;IASjF,OAAO,CAAC,SAAS,EAAE,MAAM,GAAG,OAAO,CAAC,MAAM,GAAG,IAAI,CAAC;IA0BlD,yBAAyB,CAAC,WAAW,EAAE,MAAM,GAAG,OAAO,CAAC,IAAI,CAAC;CAUpE"}
@@ -1,15 +1,21 @@
1
1
  "use strict";
2
2
  Object.defineProperty(exports, "__esModule", { value: true });
3
3
  exports.MariaDbResetTokenStore = void 0;
4
+ const framework_schema_names_js_1 = require("../config/framework-schema-names.js");
4
5
  class MariaDbResetTokenStore {
5
6
  pool;
6
7
  now;
7
- constructor(pool, now = Date.now) {
8
+ /** `<identity>`.`password_reset_token`, resolved at construction. */
9
+ table;
10
+ constructor(pool, now = Date.now,
11
+ /** Framework database names; absent ⇒ resolved from `SHIELD_DB_NAMESPACE` here, once. */
12
+ schemas) {
8
13
  this.pool = pool;
9
14
  this.now = now;
15
+ this.table = (0, framework_schema_names_js_1.qualifiedTableName)((0, framework_schema_names_js_1.schemaNamesAtConstruction)(schemas).identity, 'password_reset_token');
10
16
  }
11
17
  async issue(principalId, tokenHash, expiresAtMs) {
12
- await this.pool.query(`INSERT INTO \`shield_identity\`.\`password_reset_token\`
18
+ await this.pool.query(`INSERT INTO ${this.table}
13
19
  (prt_token_hash, prt_principal_id, prt_expires_at_ms, prt_consumed_at_ms, prt_created_at_ms)
14
20
  VALUES (?, ?, ?, NULL, ?)`, [tokenHash, principalId, expiresAtMs, this.now()]);
15
21
  }
@@ -17,7 +23,7 @@ class MariaDbResetTokenStore {
17
23
  const now = this.now();
18
24
  // 1) Find an unexpired, unconsumed token for this hash.
19
25
  const rows = (await this.pool.query(`SELECT prt_principal_id
20
- FROM \`shield_identity\`.\`password_reset_token\`
26
+ FROM ${this.table}
21
27
  WHERE prt_token_hash = ? AND prt_consumed_at_ms IS NULL AND prt_expires_at_ms > ?
22
28
  LIMIT 1`, [tokenHash, now]));
23
29
  const principalId = rows[0]?.prt_principal_id;
@@ -25,7 +31,7 @@ class MariaDbResetTokenStore {
25
31
  return null;
26
32
  // 2) Atomically claim it (single-use). The `IS NULL` guard + affectedRows check means a
27
33
  // concurrent consume can never both succeed — the loser sees 0 rows and returns null.
28
- const res = (await this.pool.query(`UPDATE \`shield_identity\`.\`password_reset_token\`
34
+ const res = (await this.pool.query(`UPDATE ${this.table}
29
35
  SET prt_consumed_at_ms = ?
30
36
  WHERE prt_token_hash = ? AND prt_consumed_at_ms IS NULL`, [now, tokenHash]));
31
37
  if (res.affectedRows !== 1)
@@ -35,7 +41,7 @@ class MariaDbResetTokenStore {
35
41
  async invalidateAllForPrincipal(principalId) {
36
42
  // Burn every outstanding (unconsumed) token for the principal after a successful reset, so a
37
43
  // second still-valid link cannot re-reset.
38
- await this.pool.query(`UPDATE \`shield_identity\`.\`password_reset_token\`
44
+ await this.pool.query(`UPDATE ${this.table}
39
45
  SET prt_consumed_at_ms = ?
40
46
  WHERE prt_principal_id = ? AND prt_consumed_at_ms IS NULL`, [this.now(), principalId]);
41
47
  }
@@ -23,6 +23,7 @@
23
23
  import type { Pool } from 'mariadb';
24
24
  import type { SessionSweeper } from '../auth/ports/session-sweeper.js';
25
25
  import type { SessionTokenBinder } from '../request-auth/session-token-binder.js';
26
+ import { type FrameworkSchemaNames } from '../config/framework-schema-names.js';
26
27
  /** The binder surface the sweeper needs; `unbindSessionStrict` (throws on a Redis error) is preferred. */
27
28
  type SweepBinder = Pick<SessionTokenBinder, 'unbindSession'> & Partial<Pick<SessionTokenBinder, 'unbindSessionStrict'>>;
28
29
  export declare class MariaDbSessionSweeper implements SessionSweeper {
@@ -30,9 +31,13 @@ export declare class MariaDbSessionSweeper implements SessionSweeper {
30
31
  private readonly binder;
31
32
  /** Clock for the "not yet expired" unbind window (epoch-ms). */
32
33
  private readonly now;
34
+ /** `<identity>`.`session`, resolved at construction (configurable-framework-db). */
35
+ private readonly sessionTable;
33
36
  constructor(pool: Pool, binder: SweepBinder,
34
37
  /** Clock for the "not yet expired" unbind window (epoch-ms). */
35
- now?: () => number);
38
+ now?: () => number,
39
+ /** Framework database names; absent ⇒ resolved from `SHIELD_DB_NAMESPACE` here, once. */
40
+ schemas?: FrameworkSchemaNames);
36
41
  /**
37
42
  * Unbind the given sessions in Redis. Every session is attempted; if any unbind failed, the
38
43
  * FIRST error is thrown afterwards (Phase 3 review P1), so an administrative revoke reports it
@@ -1 +1 @@
1
- {"version":3,"file":"mariadb-session-sweeper.d.ts","sourceRoot":"","sources":["../../src/authentication/mariadb-session-sweeper.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;GAqBG;AAEH,OAAO,KAAK,EAAE,IAAI,EAAE,MAAM,SAAS,CAAC;AACpC,OAAO,KAAK,EAAE,cAAc,EAAE,MAAM,kCAAkC,CAAC;AACvE,OAAO,KAAK,EAAE,kBAAkB,EAAE,MAAM,yCAAyC,CAAC;AAMlF,0GAA0G;AAC1G,KAAK,WAAW,GAAG,IAAI,CAAC,kBAAkB,EAAE,eAAe,CAAC,GAC1D,OAAO,CAAC,IAAI,CAAC,kBAAkB,EAAE,qBAAqB,CAAC,CAAC,CAAC;AAE3D,qBAAa,qBAAsB,YAAW,cAAc;IAExD,OAAO,CAAC,QAAQ,CAAC,IAAI;IACrB,OAAO,CAAC,QAAQ,CAAC,MAAM;IACvB,gEAAgE;IAChE,OAAO,CAAC,QAAQ,CAAC,GAAG;gBAHH,IAAI,EAAE,IAAI,EACV,MAAM,EAAE,WAAW;IACpC,gEAAgE;IAC/C,GAAG,GAAE,MAAM,MAAiB;IAG/C;;;;OAIG;YACW,SAAS;IAUjB,qBAAqB,CAAC,WAAW,EAAE,MAAM,GAAG,OAAO,CAAC,IAAI,CAAC;IAqBzD,wBAAwB,CAAC,WAAW,EAAE,MAAM,EAAE,aAAa,EAAE,MAAM,GAAG,OAAO,CAAC,IAAI,CAAC;CAkB1F"}
1
+ {"version":3,"file":"mariadb-session-sweeper.d.ts","sourceRoot":"","sources":["../../src/authentication/mariadb-session-sweeper.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;GAqBG;AAEH,OAAO,KAAK,EAAE,IAAI,EAAE,MAAM,SAAS,CAAC;AACpC,OAAO,KAAK,EAAE,cAAc,EAAE,MAAM,kCAAkC,CAAC;AACvE,OAAO,KAAK,EAAE,kBAAkB,EAAE,MAAM,yCAAyC,CAAC;AAClF,OAAO,EAGL,KAAK,oBAAoB,EAC1B,MAAM,qCAAqC,CAAC;AAM7C,0GAA0G;AAC1G,KAAK,WAAW,GAAG,IAAI,CAAC,kBAAkB,EAAE,eAAe,CAAC,GAC1D,OAAO,CAAC,IAAI,CAAC,kBAAkB,EAAE,qBAAqB,CAAC,CAAC,CAAC;AAE3D,qBAAa,qBAAsB,YAAW,cAAc;IAKxD,OAAO,CAAC,QAAQ,CAAC,IAAI;IACrB,OAAO,CAAC,QAAQ,CAAC,MAAM;IACvB,gEAAgE;IAChE,OAAO,CAAC,QAAQ,CAAC,GAAG;IAPtB,oFAAoF;IACpF,OAAO,CAAC,QAAQ,CAAC,YAAY,CAAS;gBAGnB,IAAI,EAAE,IAAI,EACV,MAAM,EAAE,WAAW;IACpC,gEAAgE;IAC/C,GAAG,GAAE,MAAM,MAAiB;IAC7C,yFAAyF;IACzF,OAAO,CAAC,EAAE,oBAAoB;IAKhC;;;;OAIG;YACW,SAAS;IAUjB,qBAAqB,CAAC,WAAW,EAAE,MAAM,GAAG,OAAO,CAAC,IAAI,CAAC;IAqBzD,wBAAwB,CAAC,WAAW,EAAE,MAAM,EAAE,aAAa,EAAE,MAAM,GAAG,OAAO,CAAC,IAAI,CAAC;CAkB1F"}
@@ -23,16 +23,22 @@
23
23
  */
24
24
  Object.defineProperty(exports, "__esModule", { value: true });
25
25
  exports.MariaDbSessionSweeper = void 0;
26
+ const framework_schema_names_js_1 = require("../config/framework-schema-names.js");
26
27
  class MariaDbSessionSweeper {
27
28
  pool;
28
29
  binder;
29
30
  now;
31
+ /** `<identity>`.`session`, resolved at construction (configurable-framework-db). */
32
+ sessionTable;
30
33
  constructor(pool, binder,
31
34
  /** Clock for the "not yet expired" unbind window (epoch-ms). */
32
- now = Date.now) {
35
+ now = Date.now,
36
+ /** Framework database names; absent ⇒ resolved from `SHIELD_DB_NAMESPACE` here, once. */
37
+ schemas) {
33
38
  this.pool = pool;
34
39
  this.binder = binder;
35
40
  this.now = now;
41
+ this.sessionTable = (0, framework_schema_names_js_1.qualifiedTableName)((0, framework_schema_names_js_1.schemaNamesAtConstruction)(schemas).identity, 'session');
36
42
  }
37
43
  /**
38
44
  * Unbind the given sessions in Redis. Every session is attempted; if any unbind failed, the
@@ -53,9 +59,9 @@ class MariaDbSessionSweeper {
53
59
  // absolute expiry, WHATEVER its status — so a retry after a failed unbind (the durable row is
54
60
  // already `revoked`) still drops the Redis keys. Read BEFORE the durable revoke.
55
61
  const rows = (await this.pool.query(`SELECT s_session_id
56
- FROM \`shield_identity\`.\`session\`
62
+ FROM ${this.sessionTable}
57
63
  WHERE s_principal_id = ? AND s_absolute_expires_at_ms > ?`, [principalId, this.now()]));
58
- await this.pool.query(`UPDATE \`shield_identity\`.\`session\`
64
+ await this.pool.query(`UPDATE ${this.sessionTable}
59
65
  SET s_status = 'revoked'
60
66
  WHERE s_principal_id = ? AND s_status = 'active'`, [principalId]);
61
67
  // Drop each session's Redis liveness key so outstanding access tokens die immediately, not
@@ -65,9 +71,9 @@ class MariaDbSessionSweeper {
65
71
  async revokeOthersForPrincipal(principalId, keepSessionId) {
66
72
  // Same unbind set as revokeAll (not-yet-expired, any status) minus the kept session.
67
73
  const rows = (await this.pool.query(`SELECT s_session_id
68
- FROM \`shield_identity\`.\`session\`
74
+ FROM ${this.sessionTable}
69
75
  WHERE s_principal_id = ? AND s_absolute_expires_at_ms > ? AND s_session_id <> ?`, [principalId, this.now(), keepSessionId]));
70
- await this.pool.query(`UPDATE \`shield_identity\`.\`session\`
76
+ await this.pool.query(`UPDATE ${this.sessionTable}
71
77
  SET s_status = 'revoked'
72
78
  WHERE s_principal_id = ? AND s_status = 'active' AND s_session_id <> ?`, [principalId, keepSessionId]);
73
79
  // Only the OTHER sessions are unbound — the kept (current) session's liveness key
@@ -1 +1 @@
1
- {"version":3,"file":"cross-tenant-grant-writer.d.ts","sourceRoot":"","sources":["../../src/authz/cross-tenant-grant-writer.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"cross-tenant-grant-writer.d.ts","sourceRoot":"","sources":["../../src/authz/cross-tenant-grant-writer.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GA4DG;AAGH,OAAO,KAAK,EAAE,cAAc,EAAE,MAAM,yCAAyC,CAAC;AAG9E,8CAA8C;AAC9C,eAAO,MAAM,gCAAgC,eAA6C,CAAC;AAE3F,0FAA0F;AAC1F,MAAM,MAAM,gBAAgB,GAAG,MAAM,GAAG,MAAM,CAAC;AAE/C,gFAAgF;AAChF,MAAM,MAAM,UAAU,GAAG,aAAa,GAAG,QAAQ,CAAC;AAElD;;;;;;;;;;;;;;;;;;;;;;GAsBG;AACH,MAAM,MAAM,gBAAgB,GAAG,CAC7B,WAAW,EAAE,MAAM,EACnB,QAAQ,EAAE,MAAM,EAChB,MAAM,EAAE,OAAO,GAAG,QAAQ,GAAG,QAAQ,KAClC,OAAO,CAAC,OAAO,CAAC,CAAC;AAEtB,+FAA+F;AAC/F,MAAM,WAAW,eAAe;IAC9B,qCAAqC;IACrC,QAAQ,CAAC,IAAI,EAAE,oBAAoB,CAAC;IACpC,oCAAoC;IACpC,QAAQ,CAAC,MAAM,EAAE,eAAe,GAAG,gBAAgB,GAAG,eAAe,CAAC;IACtE,mCAAmC;IACnC,QAAQ,CAAC,YAAY,EAAE,MAAM,CAAC;IAC9B,6EAA6E;IAC7E,QAAQ,CAAC,OAAO,EAAE,MAAM,CAAC;IACzB;;;OAGG;IACH,QAAQ,CAAC,cAAc,EAAE,MAAM,CAAC;IAChC,2FAA2F;IAC3F,QAAQ,CAAC,eAAe,EAAE,MAAM,CAAC;IACjC,yFAAyF;IACzF,QAAQ,CAAC,UAAU,EAAE;QACnB,QAAQ,CAAC,SAAS,EAAE,MAAM,CAAC;QAC3B,QAAQ,CAAC,OAAO,EAAE,MAAM,CAAC;QACzB,QAAQ,CAAC,KAAK,EAAE,UAAU,CAAC;QAC3B,QAAQ,CAAC,QAAQ,CAAC,EAAE,MAAM,CAAC;QAC3B,QAAQ,CAAC,WAAW,EAAE,gBAAgB,CAAC;QACvC,QAAQ,CAAC,WAAW,EAAE,MAAM,CAAC;QAC7B,QAAQ,CAAC,cAAc,EAAE,SAAS,MAAM,EAAE,CAAC;KAC5C,CAAC;CACH;AAED,4FAA4F;AAC5F,MAAM,WAAW,cAAc;IAC7B,MAAM,CAAC,KAAK,EAAE,eAAe,GAAG,OAAO,CAAC,IAAI,CAAC,CAAC;CAC/C;AAED,qDAAqD;AACrD,MAAM,WAAW,eAAe;IAC9B;;;;OAIG;IACH,QAAQ,CAAC,cAAc,EAAE,MAAM,CAAC;IAChC,mDAAmD;IACnD,QAAQ,CAAC,eAAe,EAAE,MAAM,CAAC;IACjC,4EAA4E;IAC5E,QAAQ,CAAC,WAAW,EAAE,gBAAgB,CAAC;IACvC,0DAA0D;IAC1D,QAAQ,CAAC,WAAW,EAAE,MAAM,CAAC;IAC7B,wCAAwC;IACxC,QAAQ,CAAC,OAAO,EAAE,MAAM,CAAC;IACzB,6CAA6C;IAC7C,QAAQ,CAAC,KAAK,EAAE,UAAU,CAAC;IAC3B,0EAA0E;IAC1E,QAAQ,CAAC,QAAQ,CAAC,EAAE,MAAM,CAAC;IAC3B,iFAAiF;IACjF,QAAQ,CAAC,cAAc,EAAE,SAAS,MAAM,EAAE,CAAC;IAC3C,+EAA+E;IAC/E,QAAQ,CAAC,WAAW,EAAE,MAAM,CAAC;IAC7B;;;OAGG;IACH,QAAQ,CAAC,SAAS,EAAE,MAAM,CAAC;CAC5B;AAED,sDAAsD;AACtD,MAAM,WAAW,gBAAgB;IAC/B,sCAAsC;IACtC,QAAQ,CAAC,SAAS,EAAE,MAAM,CAAC;IAC3B;;;OAGG;IACH,QAAQ,CAAC,UAAU,EAAE,MAAM,CAAC;CAC7B;AAED,sDAAsD;AACtD,MAAM,WAAW,gBAAgB;IAC/B,sCAAsC;IACtC,QAAQ,CAAC,SAAS,EAAE,MAAM,CAAC;IAC3B;;;OAGG;IACH,QAAQ,CAAC,SAAS,EAAE,MAAM,CAAC;CAC5B;AAED,wFAAwF;AACxF,qBAAa,sBAAuB,SAAQ,KAAK;gBACnC,OAAO,EAAE,MAAM;CAI5B;AAED,+EAA+E;AAC/E,qBAAa,iBAAkB,SAAQ,KAAK;gBAC9B,OAAO,EAAE,MAAM;CAI5B;AAED,6FAA6F;AAC7F,qBAAa,0BAA2B,SAAQ,KAAK;gBACvC,OAAO,EAAE,MAAM;CAI5B;AAqCD,qBAAa,sBAAsB;IACjC,OAAO,CAAC,QAAQ,CAAC,EAAE,CAAiB;IACpC,OAAO,CAAC,QAAQ,CAAC,SAAS,CAAmB;IAC7C,OAAO,CAAC,QAAQ,CAAC,KAAK,CAA6B;IACnD,OAAO,CAAC,QAAQ,CAAC,MAAM,CAAS;IAChC,OAAO,CAAC,QAAQ,CAAC,GAAG,CAAe;gBAEvB,IAAI,EAAE;QAChB,EAAE,EAAE,cAAc,CAAC;QACnB;;;;WAIG;QACH,SAAS,EAAE,gBAAgB,CAAC;QAC5B,oFAAoF;QACpF,KAAK,CAAC,EAAE,cAAc,CAAC;QACvB,MAAM,CAAC,EAAE,MAAM,CAAC;QAChB,+DAA+D;QAC/D,KAAK,CAAC,EAAE,MAAM,MAAM,CAAC;KACtB;IAUD;;;;;;;;;OASG;IACG,KAAK,CAAC,KAAK,EAAE,eAAe,GAAG,OAAO,CAAC,MAAM,CAAC;IAuEpD;;;;;;;;;OASG;IACG,MAAM,CAAC,KAAK,EAAE,gBAAgB,GAAG,OAAO,CAAC,IAAI,CAAC;IAiDpD;;;;;;;;;OASG;IACG,MAAM,CAAC,KAAK,EAAE,gBAAgB,GAAG,OAAO,CAAC,IAAI,CAAC;IAqDpD;;;;OAIG;IACH,OAAO,CAAC,gBAAgB;IAkDxB;;;;OAIG;YACW,gBAAgB;IAU9B,uGAAuG;YACzF,UAAU;IAqBxB,mEAAmE;YACrD,IAAI;IAalB,wFAAwF;YAC1E,WAAW;CA0B1B"}
@@ -63,8 +63,7 @@
63
63
  Object.defineProperty(exports, "__esModule", { value: true });
64
64
  exports.CrossTenantGrantWriter = exports.GrantStoreUnavailableError = exports.InvalidGrantError = exports.GrantNotPermittedError = exports.SHIELD_CROSS_TENANT_GRANT_WRITER = void 0;
65
65
  const node_crypto_1 = require("node:crypto");
66
- /** Schema the `cross_tenant_grant` table lives in (astram3 ships the migration). */
67
- const DEFAULT_SCHEMA = 'shield_authz';
66
+ const framework_schema_names_js_1 = require("../config/framework-schema-names.js");
68
67
  /** The DI token the writer is bound under. */
69
68
  exports.SHIELD_CROSS_TENANT_GRANT_WRITER = Symbol('SHIELD_CROSS_TENANT_GRANT_WRITER');
70
69
  /** Thrown when the who-may-grant bound rejects an offer/accept/revoke (fail-closed). */
@@ -122,7 +121,9 @@ class CrossTenantGrantWriter {
122
121
  this.db = deps.db;
123
122
  this.authorize = deps.authorize;
124
123
  this.audit = deps.audit;
125
- this.schema = deps.schema ?? DEFAULT_SCHEMA;
124
+ // The `cross_tenant_grant` database: `deps.schema` (checked), else the resolved authz name
125
+ // (configurable-framework-db), fixed at construction.
126
+ this.schema = (0, framework_schema_names_js_1.authzSchemaAtConstruction)(deps.schema);
126
127
  this.now = deps.nowMs ?? (() => Date.now());
127
128
  }
128
129
  /**