@spinajs/authn-orm 0.0.0-stage → 3.0.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 (246) hide show
  1. package/README.md +84 -2
  2. package/lib/cjs/audit/db-audit-sink.d.ts +11 -0
  3. package/lib/cjs/audit/db-audit-sink.d.ts.map +1 -0
  4. package/lib/cjs/audit/db-audit-sink.js +73 -0
  5. package/lib/cjs/audit/db-audit-sink.js.map +1 -0
  6. package/lib/cjs/audit/index.d.ts +2 -0
  7. package/lib/cjs/audit/index.d.ts.map +1 -0
  8. package/lib/cjs/audit/index.js +6 -0
  9. package/lib/cjs/audit/index.js.map +1 -0
  10. package/lib/cjs/identity.d.ts +6 -0
  11. package/lib/cjs/identity.d.ts.map +1 -0
  12. package/lib/cjs/identity.js +27 -0
  13. package/lib/cjs/identity.js.map +1 -0
  14. package/lib/cjs/index.d.ts +10 -0
  15. package/lib/cjs/index.d.ts.map +1 -0
  16. package/lib/cjs/index.js +26 -0
  17. package/lib/cjs/index.js.map +1 -0
  18. package/lib/cjs/links/db-link-store.d.ts +13 -0
  19. package/lib/cjs/links/db-link-store.d.ts.map +1 -0
  20. package/lib/cjs/links/db-link-store.js +88 -0
  21. package/lib/cjs/links/db-link-store.js.map +1 -0
  22. package/lib/cjs/links/index.d.ts +2 -0
  23. package/lib/cjs/links/index.d.ts.map +1 -0
  24. package/lib/cjs/links/index.js +6 -0
  25. package/lib/cjs/links/index.js.map +1 -0
  26. package/lib/cjs/mfa/cipher.d.ts +18 -0
  27. package/lib/cjs/mfa/cipher.d.ts.map +1 -0
  28. package/lib/cjs/mfa/cipher.js +81 -0
  29. package/lib/cjs/mfa/cipher.js.map +1 -0
  30. package/lib/cjs/mfa/db-mfa-enrolments.d.ts +14 -0
  31. package/lib/cjs/mfa/db-mfa-enrolments.d.ts.map +1 -0
  32. package/lib/cjs/mfa/db-mfa-enrolments.js +43 -0
  33. package/lib/cjs/mfa/db-mfa-enrolments.js.map +1 -0
  34. package/lib/cjs/mfa/db-mfa-store.d.ts +51 -0
  35. package/lib/cjs/mfa/db-mfa-store.d.ts.map +1 -0
  36. package/lib/cjs/mfa/db-mfa-store.js +190 -0
  37. package/lib/cjs/mfa/db-mfa-store.js.map +1 -0
  38. package/lib/cjs/mfa/index.d.ts +4 -0
  39. package/lib/cjs/mfa/index.d.ts.map +1 -0
  40. package/lib/cjs/mfa/index.js +20 -0
  41. package/lib/cjs/mfa/index.js.map +1 -0
  42. package/lib/cjs/migrations/AuthnInitial_2026_10_02_00_00_00.d.ts +10 -0
  43. package/lib/cjs/migrations/AuthnInitial_2026_10_02_00_00_00.d.ts.map +1 -0
  44. package/lib/cjs/migrations/AuthnInitial_2026_10_02_00_00_00.js +98 -0
  45. package/lib/cjs/migrations/AuthnInitial_2026_10_02_00_00_00.js.map +1 -0
  46. package/lib/cjs/migrations/index.d.ts +2 -0
  47. package/lib/cjs/migrations/index.d.ts.map +1 -0
  48. package/lib/cjs/migrations/index.js +18 -0
  49. package/lib/cjs/migrations/index.js.map +1 -0
  50. package/lib/cjs/models/AuthnAudit.d.ts +18 -0
  51. package/lib/cjs/models/AuthnAudit.d.ts.map +1 -0
  52. package/lib/cjs/models/AuthnAudit.js +30 -0
  53. package/lib/cjs/models/AuthnAudit.js.map +1 -0
  54. package/lib/cjs/models/AuthnIdentity.d.ts +16 -0
  55. package/lib/cjs/models/AuthnIdentity.d.ts.map +1 -0
  56. package/lib/cjs/models/AuthnIdentity.js +39 -0
  57. package/lib/cjs/models/AuthnIdentity.js.map +1 -0
  58. package/lib/cjs/models/AuthnMfa.d.ts +16 -0
  59. package/lib/cjs/models/AuthnMfa.d.ts.map +1 -0
  60. package/lib/cjs/models/AuthnMfa.js +39 -0
  61. package/lib/cjs/models/AuthnMfa.js.map +1 -0
  62. package/lib/cjs/models/AuthnNonce.d.ts +7 -0
  63. package/lib/cjs/models/AuthnNonce.d.ts.map +1 -0
  64. package/lib/cjs/models/AuthnNonce.js +30 -0
  65. package/lib/cjs/models/AuthnNonce.js.map +1 -0
  66. package/lib/cjs/models/AuthnRecoveryCode.d.ts +10 -0
  67. package/lib/cjs/models/AuthnRecoveryCode.d.ts.map +1 -0
  68. package/lib/cjs/models/AuthnRecoveryCode.js +30 -0
  69. package/lib/cjs/models/AuthnRecoveryCode.js.map +1 -0
  70. package/lib/cjs/models/AuthnSecret.d.ts +13 -0
  71. package/lib/cjs/models/AuthnSecret.d.ts.map +1 -0
  72. package/lib/cjs/models/AuthnSecret.js +38 -0
  73. package/lib/cjs/models/AuthnSecret.js.map +1 -0
  74. package/lib/cjs/models/AuthnThrottle.d.ts +10 -0
  75. package/lib/cjs/models/AuthnThrottle.d.ts.map +1 -0
  76. package/lib/cjs/models/AuthnThrottle.js +38 -0
  77. package/lib/cjs/models/AuthnThrottle.js.map +1 -0
  78. package/lib/cjs/models/index.d.ts +9 -0
  79. package/lib/cjs/models/index.d.ts.map +1 -0
  80. package/lib/cjs/models/index.js +25 -0
  81. package/lib/cjs/models/index.js.map +1 -0
  82. package/lib/cjs/models/time.d.ts +4 -0
  83. package/lib/cjs/models/time.d.ts.map +1 -0
  84. package/lib/cjs/models/time.js +19 -0
  85. package/lib/cjs/models/time.js.map +1 -0
  86. package/lib/cjs/nonces/index.d.ts +2 -0
  87. package/lib/cjs/nonces/index.d.ts.map +1 -0
  88. package/lib/cjs/nonces/index.js +18 -0
  89. package/lib/cjs/nonces/index.js.map +1 -0
  90. package/lib/cjs/nonces/nonce-store.d.ts +11 -0
  91. package/lib/cjs/nonces/nonce-store.d.ts.map +1 -0
  92. package/lib/cjs/nonces/nonce-store.js +77 -0
  93. package/lib/cjs/nonces/nonce-store.js.map +1 -0
  94. package/lib/cjs/package.json +1 -0
  95. package/lib/cjs/secrets/db-secret-store.d.ts +25 -0
  96. package/lib/cjs/secrets/db-secret-store.d.ts.map +1 -0
  97. package/lib/cjs/secrets/db-secret-store.js +99 -0
  98. package/lib/cjs/secrets/db-secret-store.js.map +1 -0
  99. package/lib/cjs/secrets/index.d.ts +2 -0
  100. package/lib/cjs/secrets/index.d.ts.map +1 -0
  101. package/lib/cjs/secrets/index.js +6 -0
  102. package/lib/cjs/secrets/index.js.map +1 -0
  103. package/lib/cjs/support/sql.d.ts +16 -0
  104. package/lib/cjs/support/sql.d.ts.map +1 -0
  105. package/lib/cjs/support/sql.js +50 -0
  106. package/lib/cjs/support/sql.js.map +1 -0
  107. package/lib/cjs/support/values.d.ts +7 -0
  108. package/lib/cjs/support/values.d.ts.map +1 -0
  109. package/lib/cjs/support/values.js +8 -0
  110. package/lib/cjs/support/values.js.map +1 -0
  111. package/lib/cjs/throttle/db-throttle-store.d.ts +79 -0
  112. package/lib/cjs/throttle/db-throttle-store.d.ts.map +1 -0
  113. package/lib/cjs/throttle/db-throttle-store.js +231 -0
  114. package/lib/cjs/throttle/db-throttle-store.js.map +1 -0
  115. package/lib/cjs/throttle/db-throttle.d.ts +77 -0
  116. package/lib/cjs/throttle/db-throttle.d.ts.map +1 -0
  117. package/lib/cjs/throttle/db-throttle.js +192 -0
  118. package/lib/cjs/throttle/db-throttle.js.map +1 -0
  119. package/lib/cjs/throttle/index.d.ts +6 -0
  120. package/lib/cjs/throttle/index.d.ts.map +1 -0
  121. package/lib/cjs/throttle/index.js +8 -0
  122. package/lib/cjs/throttle/index.js.map +1 -0
  123. package/lib/mjs/audit/db-audit-sink.d.ts +11 -0
  124. package/lib/mjs/audit/db-audit-sink.d.ts.map +1 -0
  125. package/lib/mjs/audit/db-audit-sink.js +70 -0
  126. package/lib/mjs/audit/db-audit-sink.js.map +1 -0
  127. package/lib/mjs/audit/index.d.ts +2 -0
  128. package/lib/mjs/audit/index.d.ts.map +1 -0
  129. package/lib/mjs/audit/index.js +2 -0
  130. package/lib/mjs/audit/index.js.map +1 -0
  131. package/lib/mjs/identity.d.ts +6 -0
  132. package/lib/mjs/identity.d.ts.map +1 -0
  133. package/lib/mjs/identity.js +23 -0
  134. package/lib/mjs/identity.js.map +1 -0
  135. package/lib/mjs/index.d.ts +10 -0
  136. package/lib/mjs/index.d.ts.map +1 -0
  137. package/lib/mjs/index.js +10 -0
  138. package/lib/mjs/index.js.map +1 -0
  139. package/lib/mjs/links/db-link-store.d.ts +13 -0
  140. package/lib/mjs/links/db-link-store.d.ts.map +1 -0
  141. package/lib/mjs/links/db-link-store.js +85 -0
  142. package/lib/mjs/links/db-link-store.js.map +1 -0
  143. package/lib/mjs/links/index.d.ts +2 -0
  144. package/lib/mjs/links/index.d.ts.map +1 -0
  145. package/lib/mjs/links/index.js +2 -0
  146. package/lib/mjs/links/index.js.map +1 -0
  147. package/lib/mjs/mfa/cipher.d.ts +18 -0
  148. package/lib/mjs/mfa/cipher.d.ts.map +1 -0
  149. package/lib/mjs/mfa/cipher.js +76 -0
  150. package/lib/mjs/mfa/cipher.js.map +1 -0
  151. package/lib/mjs/mfa/db-mfa-enrolments.d.ts +14 -0
  152. package/lib/mjs/mfa/db-mfa-enrolments.d.ts.map +1 -0
  153. package/lib/mjs/mfa/db-mfa-enrolments.js +40 -0
  154. package/lib/mjs/mfa/db-mfa-enrolments.js.map +1 -0
  155. package/lib/mjs/mfa/db-mfa-store.d.ts +51 -0
  156. package/lib/mjs/mfa/db-mfa-store.d.ts.map +1 -0
  157. package/lib/mjs/mfa/db-mfa-store.js +187 -0
  158. package/lib/mjs/mfa/db-mfa-store.js.map +1 -0
  159. package/lib/mjs/mfa/index.d.ts +4 -0
  160. package/lib/mjs/mfa/index.d.ts.map +1 -0
  161. package/lib/mjs/mfa/index.js +4 -0
  162. package/lib/mjs/mfa/index.js.map +1 -0
  163. package/lib/mjs/migrations/AuthnInitial_2026_10_02_00_00_00.d.ts +10 -0
  164. package/lib/mjs/migrations/AuthnInitial_2026_10_02_00_00_00.d.ts.map +1 -0
  165. package/lib/mjs/migrations/AuthnInitial_2026_10_02_00_00_00.js +95 -0
  166. package/lib/mjs/migrations/AuthnInitial_2026_10_02_00_00_00.js.map +1 -0
  167. package/lib/mjs/migrations/index.d.ts +2 -0
  168. package/lib/mjs/migrations/index.d.ts.map +1 -0
  169. package/lib/mjs/migrations/index.js +2 -0
  170. package/lib/mjs/migrations/index.js.map +1 -0
  171. package/lib/mjs/models/AuthnAudit.d.ts +18 -0
  172. package/lib/mjs/models/AuthnAudit.d.ts.map +1 -0
  173. package/lib/mjs/models/AuthnAudit.js +27 -0
  174. package/lib/mjs/models/AuthnAudit.js.map +1 -0
  175. package/lib/mjs/models/AuthnIdentity.d.ts +16 -0
  176. package/lib/mjs/models/AuthnIdentity.d.ts.map +1 -0
  177. package/lib/mjs/models/AuthnIdentity.js +36 -0
  178. package/lib/mjs/models/AuthnIdentity.js.map +1 -0
  179. package/lib/mjs/models/AuthnMfa.d.ts +16 -0
  180. package/lib/mjs/models/AuthnMfa.d.ts.map +1 -0
  181. package/lib/mjs/models/AuthnMfa.js +36 -0
  182. package/lib/mjs/models/AuthnMfa.js.map +1 -0
  183. package/lib/mjs/models/AuthnNonce.d.ts +7 -0
  184. package/lib/mjs/models/AuthnNonce.d.ts.map +1 -0
  185. package/lib/mjs/models/AuthnNonce.js +27 -0
  186. package/lib/mjs/models/AuthnNonce.js.map +1 -0
  187. package/lib/mjs/models/AuthnRecoveryCode.d.ts +10 -0
  188. package/lib/mjs/models/AuthnRecoveryCode.d.ts.map +1 -0
  189. package/lib/mjs/models/AuthnRecoveryCode.js +27 -0
  190. package/lib/mjs/models/AuthnRecoveryCode.js.map +1 -0
  191. package/lib/mjs/models/AuthnSecret.d.ts +13 -0
  192. package/lib/mjs/models/AuthnSecret.d.ts.map +1 -0
  193. package/lib/mjs/models/AuthnSecret.js +35 -0
  194. package/lib/mjs/models/AuthnSecret.js.map +1 -0
  195. package/lib/mjs/models/AuthnThrottle.d.ts +10 -0
  196. package/lib/mjs/models/AuthnThrottle.d.ts.map +1 -0
  197. package/lib/mjs/models/AuthnThrottle.js +35 -0
  198. package/lib/mjs/models/AuthnThrottle.js.map +1 -0
  199. package/lib/mjs/models/index.d.ts +9 -0
  200. package/lib/mjs/models/index.d.ts.map +1 -0
  201. package/lib/mjs/models/index.js +9 -0
  202. package/lib/mjs/models/index.js.map +1 -0
  203. package/lib/mjs/models/time.d.ts +4 -0
  204. package/lib/mjs/models/time.d.ts.map +1 -0
  205. package/lib/mjs/models/time.js +16 -0
  206. package/lib/mjs/models/time.js.map +1 -0
  207. package/lib/mjs/nonces/index.d.ts +2 -0
  208. package/lib/mjs/nonces/index.d.ts.map +1 -0
  209. package/lib/mjs/nonces/index.js +2 -0
  210. package/lib/mjs/nonces/index.js.map +1 -0
  211. package/lib/mjs/nonces/nonce-store.d.ts +11 -0
  212. package/lib/mjs/nonces/nonce-store.d.ts.map +1 -0
  213. package/lib/mjs/nonces/nonce-store.js +72 -0
  214. package/lib/mjs/nonces/nonce-store.js.map +1 -0
  215. package/lib/mjs/package.json +1 -0
  216. package/lib/mjs/secrets/db-secret-store.d.ts +25 -0
  217. package/lib/mjs/secrets/db-secret-store.d.ts.map +1 -0
  218. package/lib/mjs/secrets/db-secret-store.js +96 -0
  219. package/lib/mjs/secrets/db-secret-store.js.map +1 -0
  220. package/lib/mjs/secrets/index.d.ts +2 -0
  221. package/lib/mjs/secrets/index.d.ts.map +1 -0
  222. package/lib/mjs/secrets/index.js +2 -0
  223. package/lib/mjs/secrets/index.js.map +1 -0
  224. package/lib/mjs/support/sql.d.ts +16 -0
  225. package/lib/mjs/support/sql.d.ts.map +1 -0
  226. package/lib/mjs/support/sql.js +41 -0
  227. package/lib/mjs/support/sql.js.map +1 -0
  228. package/lib/mjs/support/values.d.ts +7 -0
  229. package/lib/mjs/support/values.d.ts.map +1 -0
  230. package/lib/mjs/support/values.js +5 -0
  231. package/lib/mjs/support/values.js.map +1 -0
  232. package/lib/mjs/throttle/db-throttle-store.d.ts +79 -0
  233. package/lib/mjs/throttle/db-throttle-store.d.ts.map +1 -0
  234. package/lib/mjs/throttle/db-throttle-store.js +227 -0
  235. package/lib/mjs/throttle/db-throttle-store.js.map +1 -0
  236. package/lib/mjs/throttle/db-throttle.d.ts +77 -0
  237. package/lib/mjs/throttle/db-throttle.d.ts.map +1 -0
  238. package/lib/mjs/throttle/db-throttle.js +189 -0
  239. package/lib/mjs/throttle/db-throttle.js.map +1 -0
  240. package/lib/mjs/throttle/index.d.ts +6 -0
  241. package/lib/mjs/throttle/index.d.ts.map +1 -0
  242. package/lib/mjs/throttle/index.js +3 -0
  243. package/lib/mjs/throttle/index.js.map +1 -0
  244. package/lib/tsconfig.cjs.tsbuildinfo +1 -0
  245. package/lib/tsconfig.mjs.tsbuildinfo +1 -0
  246. package/package.json +89 -4
@@ -0,0 +1,192 @@
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.DbAuthnThrottle = void 0;
13
+ const node_crypto_1 = require("node:crypto");
14
+ const contracts_1 = require("@spinajs/authn/contracts");
15
+ const env_1 = require("@spinajs/authn/env");
16
+ const store_throttle_1 = require("@spinajs/authn/store-throttle");
17
+ const configuration_1 = require("@spinajs/configuration");
18
+ require("@spinajs/authn/register-schema");
19
+ const di_1 = require("@spinajs/di");
20
+ const exceptions_1 = require("@spinajs/exceptions");
21
+ const log_1 = require("@spinajs/log");
22
+ const util_1 = require("@spinajs/util");
23
+ const sql_js_1 = require("../support/sql.js");
24
+ const db_throttle_store_js_1 = require("./db-throttle-store.js");
25
+ // The hash key without authn.audit.hashKey.secret, which checkConfiguration accepts in development and test only.
26
+ let processKey;
27
+ /**
28
+ * Backoff per key, never a lock (A05, A06, H31), in `authn_throttle`, shared by every app instance. The rows, their
29
+ * compare-and-set claims and the purge are a `DbThrottleStore`.
30
+ *
31
+ * Every time decision compares in SQL against values computed in Node (`ctx.now`, or the clock in `succeed`),
32
+ * never SQL `now()`, and never against a datetime read back (lane note D10).
33
+ *
34
+ * Tested on sqlite and postgres. On MySQL and MSSQL the migration's `datetime` keeps whole seconds (MySQL) or
35
+ * about 3 ms (MSSQL): undo may then miss, which keeps the extra count (more throttling), and a `baseDelayMs`
36
+ * below one second is not supported there.
37
+ *
38
+ * `last_attempt_at` takes the caller's now, not the later of the two: with clocks skewed across instances, an
39
+ * account-ip row can outlive the ip run it counted in by that skew, and a later success subtracts it from the new run.
40
+ *
41
+ * The hash key check (`checkConfiguration`) runs when AuthnService resolves. A process that resolves this throttle
42
+ * without it (a worker, a CLI command) keys rows with a random key of the process when the key is unset.
43
+ */
44
+ let DbAuthnThrottle = class DbAuthnThrottle extends store_throttle_1.StoreAuthnThrottle {
45
+ /**
46
+ * DI passes nothing: `authn.throttle` and `authn.audit.hashKey.secret` come from the configuration of the resolving
47
+ * container on first use (`init`). With `params` nothing is read from the configuration: the hash key is
48
+ * `options.hashKey`. The rows live on the connection of the `AuthnThrottle` model.
49
+ */
50
+ constructor(params, options = {}) {
51
+ super();
52
+ this.options = options;
53
+ if (params)
54
+ (0, env_1.checkThrottleParams)(params);
55
+ this.fromConfiguration = params === undefined;
56
+ this.fixedParams = params;
57
+ if (!this.fromConfiguration) {
58
+ this.loadedParams = this.fixedParams;
59
+ this.hmacKey = hashKeyOf(this.options.hashKey);
60
+ }
61
+ }
62
+ get params() {
63
+ if (!this.loadedParams)
64
+ throw new exceptions_1.InvalidOption('DbAuthnThrottle: params are read from the configuration; await init() first');
65
+ return this.loadedParams;
66
+ }
67
+ get throttleName() {
68
+ return 'DbAuthnThrottle';
69
+ }
70
+ /**
71
+ * The authn service calls it at boot with its Configuration. Without the hash key this throttle uses (`options.hashKey`
72
+ * or the `authn.audit.hashKey.secret` it reads) the rows are keyed with a random key of this process, which only a
73
+ * development or test env of the booting configuration accepts.
74
+ */
75
+ async checkConfiguration(booting) {
76
+ // A @Config read needs the container's Configuration resolved.
77
+ if (this.fromConfiguration)
78
+ await this.configurationContainer().resolve(configuration_1.Configuration);
79
+ if ((0, util_1.isNonEmptyString)(this.hashSecret()))
80
+ return;
81
+ const env = (0, env_1.authnAppEnv)(booting);
82
+ if (!(0, env_1.isLenientAuthnEnv)(env)) {
83
+ throw new exceptions_1.InvalidOption(`DbAuthnThrottle: authn.audit.hashKey.secret is not set; outside development and test (env ${JSON.stringify(env ?? 'unset')}) the throttle rows must be keyed with a secret of the app`);
84
+ }
85
+ }
86
+ /** Resolves the configuration; the first `attempt`, `peek` or `succeed` and every `purge` call it. */
87
+ async init() {
88
+ this.loading ??= this.load().catch((err) => {
89
+ this.loading = undefined;
90
+ throw err;
91
+ });
92
+ await this.loading;
93
+ }
94
+ /** The row key: base64url(HMAC-SHA256(hash key, `flow|kind|value`)); logins and addresses are personal data (SR-19). */
95
+ rowKey(flow, key) {
96
+ checkKey(key);
97
+ if (!this.hmacKey)
98
+ throw new exceptions_1.InvalidOption('DbAuthnThrottle: the hash key is read from the configuration; await init() first');
99
+ return (0, node_crypto_1.createHmac)('sha256', this.hmacKey)
100
+ .update(`${flow}|${String(key.kind)}|${key.value}`, 'utf8')
101
+ .digest('base64url');
102
+ }
103
+ /** Deletes up to one batch of stale rows (idle for resetAfterSeconds and delaying nobody); returns how many went. */
104
+ async purge(now = new Date()) {
105
+ const nowMs = (0, sql_js_1.checkedMs)(now, 'DbAuthnThrottle.purge: now');
106
+ return (await this.dbStore()).purge(nowMs);
107
+ }
108
+ store() {
109
+ return this.dbStore();
110
+ }
111
+ keyId(flow, key) {
112
+ return this.rowKey(flow, key);
113
+ }
114
+ // The Throttle checks only the keys a flow uses; here a bad key fails attempt and succeed even when the flow ignores its kind, and in a reset.
115
+ checkKeys(keys) {
116
+ for (const key of keys)
117
+ checkKey(key);
118
+ }
119
+ // checkedMs also bounds the date to what the datetime columns hold.
120
+ nowMs(ctx, method) {
121
+ return (0, sql_js_1.checkedMs)(ctx?.now, `DbAuthnThrottle.${method}: ctx.now`);
122
+ }
123
+ /** Protected seam: override to wrap or replace the store (tests use it to interleave or fail statements). */
124
+ createStore(options) {
125
+ return new db_throttle_store_js_1.DbThrottleStore(options);
126
+ }
127
+ async dbStore() {
128
+ await this.init();
129
+ this.rows ??= this.createStore({ resetAfterMs: this.params.resetAfterSeconds * 1000 });
130
+ return this.rows;
131
+ }
132
+ // Read once and frozen: Configuration hands out live objects, and the rows assume fixed limits.
133
+ snapshotConfigured() {
134
+ if (!this.ConfiguredParams)
135
+ throw new exceptions_1.InvalidOperation('authn.throttle is unset: AUTHN_CONFIGURATION_SCHEMA is not registered');
136
+ const { service: _service, maxRows: _maxRows, memory: _memory, ...params } = structuredClone(this.ConfiguredParams);
137
+ (0, env_1.checkThrottleParams)(params);
138
+ return (0, util_1.deepFreeze)(params);
139
+ }
140
+ /** The key `init` uses: `options.hashKey` when given, else the configured one when there is a configuration. */
141
+ hashSecret() {
142
+ return this.options.hashKey !== undefined || !this.fromConfiguration ? this.options.hashKey : this.ConfiguredHashSecret;
143
+ }
144
+ configurationContainer() {
145
+ if (!this.Container)
146
+ throw new exceptions_1.InvalidOperation('DbAuthnThrottle: built without params and not by DI, so it has no configuration');
147
+ return this.Container;
148
+ }
149
+ async load() {
150
+ if (this.fromConfiguration) {
151
+ // A @Config read needs the container's Configuration resolved.
152
+ await this.configurationContainer().resolve(configuration_1.Configuration);
153
+ this.loadedParams = this.fixedParams ?? this.snapshotConfigured();
154
+ const secret = this.hashSecret();
155
+ this.hmacKey = hashKeyOf(secret);
156
+ if (!(0, util_1.isNonEmptyString)(secret)) {
157
+ this.Log.warnOnce('random-hash-key', 'DbAuthnThrottle: authn.audit.hashKey.secret is not set, so throttle rows are keyed with a random key of this process: their counts end with the process and are not shared with other instances');
158
+ }
159
+ }
160
+ }
161
+ };
162
+ exports.DbAuthnThrottle = DbAuthnThrottle;
163
+ __decorate([
164
+ (0, configuration_1.Config)('authn.throttle'),
165
+ __metadata("design:type", Object)
166
+ ], DbAuthnThrottle.prototype, "ConfiguredParams", void 0);
167
+ __decorate([
168
+ (0, configuration_1.Config)('authn.audit.hashKey.secret'),
169
+ __metadata("design:type", Object)
170
+ ], DbAuthnThrottle.prototype, "ConfiguredHashSecret", void 0);
171
+ __decorate([
172
+ (0, log_1.Logger)('authn-orm'),
173
+ __metadata("design:type", log_1.Log)
174
+ ], DbAuthnThrottle.prototype, "Log", void 0);
175
+ __decorate([
176
+ (0, di_1.Autoinject)(di_1.Container),
177
+ __metadata("design:type", Object)
178
+ ], DbAuthnThrottle.prototype, "Container", void 0);
179
+ exports.DbAuthnThrottle = DbAuthnThrottle = __decorate([
180
+ (0, di_1.PerChildInstance)(),
181
+ (0, di_1.Injectable)(contracts_1.AuthnThrottle),
182
+ __metadata("design:paramtypes", [Object, Object])
183
+ ], DbAuthnThrottle);
184
+ function checkKey(key) {
185
+ if (typeof key?.value !== 'string') {
186
+ throw new exceptions_1.InvalidArgument(`DbAuthnThrottle: the value of a ${JSON.stringify(String(key?.kind))} key must be a string`);
187
+ }
188
+ }
189
+ function hashKeyOf(secret) {
190
+ return (0, util_1.isNonEmptyString)(secret) ? Buffer.from(secret, 'utf8') : (processKey ??= (0, node_crypto_1.randomBytes)(32));
191
+ }
192
+ //# sourceMappingURL=db-throttle.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"db-throttle.js","sourceRoot":"","sources":["../../../src/throttle/db-throttle.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,6 @@
1
+ export type { BackoffParams, ThrottleFlowParams, ThrottleParams } from '@spinajs/authn/contracts';
2
+ export { DbAuthnThrottle } from './db-throttle.js';
3
+ export type { DbThrottleOptions } from './db-throttle.js';
4
+ export { DbThrottleStore } from './db-throttle-store.js';
5
+ export type { DbThrottleStoreOptions } from './db-throttle-store.js';
6
+ //# sourceMappingURL=index.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../src/throttle/index.ts"],"names":[],"mappings":"AAAA,YAAY,EAAE,aAAa,EAAE,kBAAkB,EAAE,cAAc,EAAE,MAAM,0BAA0B,CAAC;AAClG,OAAO,EAAE,eAAe,EAAE,MAAM,kBAAkB,CAAC;AACnD,YAAY,EAAE,iBAAiB,EAAE,MAAM,kBAAkB,CAAC;AAC1D,OAAO,EAAE,eAAe,EAAE,MAAM,wBAAwB,CAAC;AACzD,YAAY,EAAE,sBAAsB,EAAE,MAAM,wBAAwB,CAAC"}
@@ -0,0 +1,8 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.DbThrottleStore = exports.DbAuthnThrottle = void 0;
4
+ var db_throttle_js_1 = require("./db-throttle.js");
5
+ Object.defineProperty(exports, "DbAuthnThrottle", { enumerable: true, get: function () { return db_throttle_js_1.DbAuthnThrottle; } });
6
+ var db_throttle_store_js_1 = require("./db-throttle-store.js");
7
+ Object.defineProperty(exports, "DbThrottleStore", { enumerable: true, get: function () { return db_throttle_store_js_1.DbThrottleStore; } });
8
+ //# sourceMappingURL=index.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.js","sourceRoot":"","sources":["../../../src/throttle/index.ts"],"names":[],"mappings":";;;AACA,mDAAmD;AAA1C,iHAAA,eAAe,OAAA;AAExB,+DAAyD;AAAhD,uHAAA,eAAe,OAAA"}
@@ -0,0 +1,11 @@
1
+ import { AuthnEventSink } from '@spinajs/authn/contracts';
2
+ import type { AuthnEvent } from '@spinajs/authn/contracts';
3
+ /**
4
+ * One `authn_audit` row per event (SR-11). Nothing in an event makes the write fail, so a sink never fails a call
5
+ * whose work is already done (D4 over D1): free text longer than its column is cut, and an identity or actor that
6
+ * does not fit its column leaves the column null and goes whole into `data` (`identityRef`, `actorRef`).
7
+ */
8
+ export declare class DbAuthnAuditSink extends AuthnEventSink {
9
+ publish(e: AuthnEvent): Promise<void>;
10
+ }
11
+ //# sourceMappingURL=db-audit-sink.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"db-audit-sink.d.ts","sourceRoot":"","sources":["../../../src/audit/db-audit-sink.ts"],"names":[],"mappings":"AAEA,OAAO,EAAE,cAAc,EAAE,MAAM,0BAA0B,CAAC;AAC1D,OAAO,KAAK,EAAE,UAAU,EAA6B,MAAM,0BAA0B,CAAC;AA0BtF;;;;GAIG;AACH,qBAEa,gBAAiB,SAAQ,cAAc;IACrC,OAAO,CAAC,CAAC,EAAE,UAAU,GAAG,OAAO,CAAC,IAAI,CAAC,CA0BjD;CACF"}
@@ -0,0 +1,70 @@
1
+ var __decorate = (this && this.__decorate) || function (decorators, target, key, desc) {
2
+ var c = arguments.length, r = c < 3 ? target : desc === null ? desc = Object.getOwnPropertyDescriptor(target, key) : desc, d;
3
+ if (typeof Reflect === "object" && typeof Reflect.decorate === "function") r = Reflect.decorate(decorators, target, key, desc);
4
+ 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;
5
+ return c > 3 && r && Object.defineProperty(target, key, r), r;
6
+ };
7
+ import { randomUUID } from 'node:crypto';
8
+ import { AuthnEventSink } from '@spinajs/authn/contracts';
9
+ import { Injectable, PerChildInstance } from '@spinajs/di';
10
+ import { ormReady } from '@spinajs/orm';
11
+ import { identityKey } from '../identity.js';
12
+ import { AuthnAudit } from '../models/AuthnAudit.js';
13
+ import { checkedMs, cutText, instant } from '../support/sql.js';
14
+ import { columnValues } from '../support/values.js';
15
+ function keyOrNull(ref) {
16
+ if (!ref)
17
+ return null;
18
+ try {
19
+ return identityKey(ref);
20
+ }
21
+ catch {
22
+ return null;
23
+ }
24
+ }
25
+ function json(value) {
26
+ try {
27
+ return JSON.stringify(value, (_k, v) => (typeof v === 'bigint' ? v.toString() : v));
28
+ }
29
+ catch {
30
+ return JSON.stringify({ unserialisable: true });
31
+ }
32
+ }
33
+ /**
34
+ * One `authn_audit` row per event (SR-11). Nothing in an event makes the write fail, so a sink never fails a call
35
+ * whose work is already done (D4 over D1): free text longer than its column is cut, and an identity or actor that
36
+ * does not fit its column leaves the column null and goes whole into `data` (`identityRef`, `actorRef`).
37
+ */
38
+ let DbAuthnAuditSink = class DbAuthnAuditSink extends AuthnEventSink {
39
+ async publish(e) {
40
+ const identity = keyOrNull(e.identity);
41
+ const actor = keyOrNull(e.actor);
42
+ const extra = {
43
+ ...(e.identity && identity === null ? { identityRef: { type: e.identity.type, id: e.identity.id } } : {}),
44
+ ...(e.actor && actor === null ? { actorRef: { type: e.actor.type, id: e.actor.id } } : {}),
45
+ };
46
+ const data = e.data === undefined && Object.keys(extra).length === 0 ? undefined : { ...(e.data ?? {}), ...extra };
47
+ const at = instant(checkedMs(e.at, 'DbAuthnAuditSink.publish: e.at'));
48
+ await ormReady();
49
+ await AuthnAudit.insert(columnValues({
50
+ id: randomUUID(),
51
+ at,
52
+ type: cutText(e.type, 32),
53
+ outcome: cutText(e.outcome, 8),
54
+ identity,
55
+ actor,
56
+ strategy: cutText(e.strategy, 64),
57
+ reason: cutText(e.reason, 64),
58
+ ip: cutText(e.ip, 64),
59
+ user_agent: cutText(e.userAgent, 255),
60
+ session: cutText(e.session, 64),
61
+ data: data === undefined ? null : json(data),
62
+ }));
63
+ }
64
+ };
65
+ DbAuthnAuditSink = __decorate([
66
+ PerChildInstance(),
67
+ Injectable(AuthnEventSink)
68
+ ], DbAuthnAuditSink);
69
+ export { DbAuthnAuditSink };
70
+ //# sourceMappingURL=db-audit-sink.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"db-audit-sink.js","sourceRoot":"","sources":["../../../src/audit/db-audit-sink.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,2 @@
1
+ export { DbAuthnAuditSink } from './db-audit-sink.js';
2
+ //# sourceMappingURL=index.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../src/audit/index.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,gBAAgB,EAAE,MAAM,oBAAoB,CAAC"}
@@ -0,0 +1,2 @@
1
+ export { DbAuthnAuditSink } from './db-audit-sink.js';
2
+ //# sourceMappingURL=index.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.js","sourceRoot":"","sources":["../../../src/audit/index.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,gBAAgB,EAAE,MAAM,oBAAoB,CAAC"}
@@ -0,0 +1,6 @@
1
+ import type { IdentityRef } from '@spinajs/authn/contracts';
2
+ /** `${type}:${id}`, the form `identity` and `actor` columns hold (D1). Never truncates: too long throws. */
3
+ export declare function identityKey(ref: IdentityRef, maxLength?: number): string;
4
+ /** Splits at the first `:`; the id may contain more. */
5
+ export declare function parseIdentityKey(key: string): IdentityRef;
6
+ //# sourceMappingURL=identity.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"identity.d.ts","sourceRoot":"","sources":["../../src/identity.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,WAAW,EAAE,MAAM,0BAA0B,CAAC;AAI5D,4GAA4G;AAC5G,wBAAgB,WAAW,CAAC,GAAG,EAAE,WAAW,EAAE,SAAS,SAAM,GAAG,MAAM,CAWrE;AAED,wDAAwD;AACxD,wBAAgB,gBAAgB,CAAC,GAAG,EAAE,MAAM,GAAG,WAAW,CAMzD"}
@@ -0,0 +1,23 @@
1
+ import { InvalidArgument } from '@spinajs/exceptions';
2
+ import { _check_arg, _is_string, _non_empty } from '@spinajs/util';
3
+ /** `${type}:${id}`, the form `identity` and `actor` columns hold (D1). Never truncates: too long throws. */
4
+ export function identityKey(ref, maxLength = 100) {
5
+ _check_arg(_is_string(_non_empty()))(ref?.type, 'identity type');
6
+ if (ref.type.includes(':')) {
7
+ throw new InvalidArgument(`identity type "${ref.type}" contains ":"`);
8
+ }
9
+ const key = `${ref.type}:${ref.id}`;
10
+ if (key.length > maxLength) {
11
+ throw new InvalidArgument(`identity key of type "${ref.type}" is ${key.length} characters long, the column holds ${maxLength}`);
12
+ }
13
+ return key;
14
+ }
15
+ /** Splits at the first `:`; the id may contain more. */
16
+ export function parseIdentityKey(key) {
17
+ const at = key.indexOf(':');
18
+ if (at <= 0) {
19
+ throw new InvalidArgument('identity key is not of the form <type>:<id>');
20
+ }
21
+ return { type: key.slice(0, at), id: key.slice(at + 1) };
22
+ }
23
+ //# sourceMappingURL=identity.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"identity.js","sourceRoot":"","sources":["../../src/identity.ts"],"names":[],"mappings":"AACA,OAAO,EAAE,eAAe,EAAE,MAAM,qBAAqB,CAAC;AACtD,OAAO,EAAE,UAAU,EAAE,UAAU,EAAE,UAAU,EAAE,MAAM,eAAe,CAAC;AAEnE,4GAA4G;AAC5G,MAAM,UAAU,WAAW,CAAC,GAAgB,EAAE,SAAS,GAAG,GAAG;IAC3D,UAAU,CAAC,UAAU,CAAC,UAAU,EAAE,CAAC,CAAC,CAAC,GAAG,EAAE,IAAI,EAAE,eAAe,CAAC,CAAC;IACjE,IAAI,GAAG,CAAC,IAAI,CAAC,QAAQ,CAAC,GAAG,CAAC,EAAE,CAAC;QAC3B,MAAM,IAAI,eAAe,CAAC,kBAAkB,GAAG,CAAC,IAAI,gBAAgB,CAAC,CAAC;IACxE,CAAC;IAED,MAAM,GAAG,GAAG,GAAG,GAAG,CAAC,IAAI,IAAI,GAAG,CAAC,EAAE,EAAE,CAAC;IACpC,IAAI,GAAG,CAAC,MAAM,GAAG,SAAS,EAAE,CAAC;QAC3B,MAAM,IAAI,eAAe,CAAC,yBAAyB,GAAG,CAAC,IAAI,QAAQ,GAAG,CAAC,MAAM,sCAAsC,SAAS,EAAE,CAAC,CAAC;IAClI,CAAC;IACD,OAAO,GAAG,CAAC;AACb,CAAC;AAED,wDAAwD;AACxD,MAAM,UAAU,gBAAgB,CAAC,GAAW;IAC1C,MAAM,EAAE,GAAG,GAAG,CAAC,OAAO,CAAC,GAAG,CAAC,CAAC;IAC5B,IAAI,EAAE,IAAI,CAAC,EAAE,CAAC;QACZ,MAAM,IAAI,eAAe,CAAC,6CAA6C,CAAC,CAAC;IAC3E,CAAC;IACD,OAAO,EAAE,IAAI,EAAE,GAAG,CAAC,KAAK,CAAC,CAAC,EAAE,EAAE,CAAC,EAAE,EAAE,EAAE,GAAG,CAAC,KAAK,CAAC,EAAE,GAAG,CAAC,CAAC,EAAE,CAAC;AAC3D,CAAC"}
@@ -0,0 +1,10 @@
1
+ export * from './migrations/index.js';
2
+ export * from './models/index.js';
3
+ export * from './identity.js';
4
+ export * from './throttle/index.js';
5
+ export * from './secrets/index.js';
6
+ export * from './links/index.js';
7
+ export * from './nonces/index.js';
8
+ export * from './mfa/index.js';
9
+ export * from './audit/index.js';
10
+ //# sourceMappingURL=index.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/index.ts"],"names":[],"mappings":"AAAA,cAAc,uBAAuB,CAAC;AACtC,cAAc,mBAAmB,CAAC;AAClC,cAAc,eAAe,CAAC;AAC9B,cAAc,qBAAqB,CAAC;AACpC,cAAc,oBAAoB,CAAC;AACnC,cAAc,kBAAkB,CAAC;AACjC,cAAc,mBAAmB,CAAC;AAClC,cAAc,gBAAgB,CAAC;AAC/B,cAAc,kBAAkB,CAAC"}
@@ -0,0 +1,10 @@
1
+ export * from './migrations/index.js';
2
+ export * from './models/index.js';
3
+ export * from './identity.js';
4
+ export * from './throttle/index.js';
5
+ export * from './secrets/index.js';
6
+ export * from './links/index.js';
7
+ export * from './nonces/index.js';
8
+ export * from './mfa/index.js';
9
+ export * from './audit/index.js';
10
+ //# sourceMappingURL=index.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.js","sourceRoot":"","sources":["../../src/index.ts"],"names":[],"mappings":"AAAA,cAAc,uBAAuB,CAAC;AACtC,cAAc,mBAAmB,CAAC;AAClC,cAAc,eAAe,CAAC;AAC9B,cAAc,qBAAqB,CAAC;AACpC,cAAc,oBAAoB,CAAC;AACnC,cAAc,kBAAkB,CAAC;AACjC,cAAc,mBAAmB,CAAC;AAClC,cAAc,gBAAgB,CAAC;AAC/B,cAAc,kBAAkB,CAAC"}
@@ -0,0 +1,13 @@
1
+ import { IdentityLinkStore } from '@spinajs/authn/contracts';
2
+ import type { ExternalSubject, IdentityLink, IdentityRef } from '@spinajs/authn/contracts';
3
+ /** `authn_identity`: external subjects linked to identities (A19). Values longer than their columns throw (D1). */
4
+ export declare class DbIdentityLinkStore extends IdentityLinkStore {
5
+ find(provider: string, subject: string): Promise<IdentityLink | null>;
6
+ list(identity: IdentityRef): Promise<readonly IdentityLink[]>;
7
+ /** A duplicate (provider, subject) rejects with `ResourceDuplicated` (the unique index decides). */
8
+ link(identity: IdentityRef, external: ExternalSubject): Promise<IdentityLink>;
9
+ unlink(id: string): Promise<void>;
10
+ /** Sets `last_used_at` (default now); true when the link exists. */
11
+ touch(id: string, at?: Date): Promise<boolean>;
12
+ }
13
+ //# sourceMappingURL=db-link-store.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"db-link-store.d.ts","sourceRoot":"","sources":["../../../src/links/db-link-store.ts"],"names":[],"mappings":"AAEA,OAAO,EAAE,iBAAiB,EAAE,MAAM,0BAA0B,CAAC;AAC7D,OAAO,KAAK,EAAE,eAAe,EAAE,YAAY,EAAE,WAAW,EAAE,MAAM,0BAA0B,CAAC;AAiB3F,mHAAmH;AACnH,qBAEa,mBAAoB,SAAQ,iBAAiB;IAC3C,IAAI,CAAC,QAAQ,EAAE,MAAM,EAAE,OAAO,EAAE,MAAM,GAAG,OAAO,CAAC,YAAY,GAAG,IAAI,CAAC,CAOjF;IAEY,IAAI,CAAC,QAAQ,EAAE,WAAW,GAAG,OAAO,CAAC,SAAS,YAAY,EAAE,CAAC,CAKzE;IAED,oGAAoG;IACvF,IAAI,CAAC,QAAQ,EAAE,WAAW,EAAE,QAAQ,EAAE,eAAe,GAAG,OAAO,CAAC,YAAY,CAAC,CAgBzF;IAEY,MAAM,CAAC,EAAE,EAAE,MAAM,GAAG,OAAO,CAAC,IAAI,CAAC,CAG7C;IAED,oEAAoE;IACvD,KAAK,CAAC,EAAE,EAAE,MAAM,EAAE,EAAE,GAAE,IAAiB,GAAG,OAAO,CAAC,OAAO,CAAC,CAKtE;CACF"}
@@ -0,0 +1,85 @@
1
+ var __decorate = (this && this.__decorate) || function (decorators, target, key, desc) {
2
+ var c = arguments.length, r = c < 3 ? target : desc === null ? desc = Object.getOwnPropertyDescriptor(target, key) : desc, d;
3
+ if (typeof Reflect === "object" && typeof Reflect.decorate === "function") r = Reflect.decorate(decorators, target, key, desc);
4
+ 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;
5
+ return c > 3 && r && Object.defineProperty(target, key, r), r;
6
+ };
7
+ import { randomUUID } from 'node:crypto';
8
+ import { IdentityLinkStore } from '@spinajs/authn/contracts';
9
+ import { Injectable, PerChildInstance } from '@spinajs/di';
10
+ import { InvalidArgument, ResourceDuplicated } from '@spinajs/exceptions';
11
+ import { UniqueViolation, ormReady } from '@spinajs/orm';
12
+ import { AuthnIdentity } from '../models/AuthnIdentity.js';
13
+ import { checkedMs, checkedText, dateOf, instant } from '../support/sql.js';
14
+ import { columnValues } from '../support/values.js';
15
+ const LINK_COLUMNS = ['id', 'identity_type', 'identity_id', 'provider', 'subject', 'email', 'linked_at', 'last_used_at'];
16
+ function identityParts(ref) {
17
+ const type = checkedText(ref?.type, 16, 'DbIdentityLinkStore: identity type');
18
+ if (type.includes(':'))
19
+ throw new InvalidArgument(`DbIdentityLinkStore: identity type "${type}" contains ":"`);
20
+ return { type, id: checkedText(ref.id, 64, 'DbIdentityLinkStore: identity id') };
21
+ }
22
+ /** `authn_identity`: external subjects linked to identities (A19). Values longer than their columns throw (D1). */
23
+ let DbIdentityLinkStore = class DbIdentityLinkStore extends IdentityLinkStore {
24
+ async find(provider, subject) {
25
+ await ormReady();
26
+ const rows = await AuthnIdentity.query().columns(LINK_COLUMNS).where('provider', provider).where('subject', subject);
27
+ // MySQL and MSSQL default collations ignore case (and accents or trailing spaces): a subject differing only that
28
+ // way must not sign in as another account.
29
+ const exact = rows.find((r) => r.provider === provider && r.subject === subject);
30
+ return exact ? toLink(exact) : null;
31
+ }
32
+ async list(identity) {
33
+ const { type, id } = identityParts(identity);
34
+ await ormReady();
35
+ const rows = await AuthnIdentity.query().columns(LINK_COLUMNS).where('identity_type', type).where('identity_id', id).orderBy('linked_at');
36
+ return rows.filter((r) => r.identity_type === type && r.identity_id === id).map(toLink);
37
+ }
38
+ /** A duplicate (provider, subject) rejects with `ResourceDuplicated` (the unique index decides). */
39
+ async link(identity, external) {
40
+ const { type, id } = identityParts(identity);
41
+ const provider = checkedText(external?.provider, 128, 'DbIdentityLinkStore: provider');
42
+ const subject = checkedText(external.subject, 255, 'DbIdentityLinkStore: subject');
43
+ const email = external.email === undefined || external.email === null ? undefined : checkedText(external.email, 255, 'DbIdentityLinkStore: email', true);
44
+ const nowMs = checkedMs(new Date(), 'DbIdentityLinkStore.link: the clock');
45
+ await ormReady();
46
+ const linkId = randomUUID();
47
+ try {
48
+ await AuthnIdentity.insert(columnValues({ id: linkId, identity_type: type, identity_id: id, provider, subject, email: email ?? null, email_verified: external.emailVerified === true, attributes: null, linked_at: instant(nowMs), last_used_at: null }));
49
+ }
50
+ catch (err) {
51
+ if (err instanceof UniqueViolation)
52
+ throw new ResourceDuplicated(`DbIdentityLinkStore: (${provider}, subject) is already linked`, err);
53
+ throw err;
54
+ }
55
+ return { id: linkId, identity: { type, id }, provider, subject, ...(email !== undefined ? { email } : {}), linkedAt: new Date(nowMs) };
56
+ }
57
+ async unlink(id) {
58
+ await ormReady();
59
+ await AuthnIdentity.destroy().where('id', id);
60
+ }
61
+ /** Sets `last_used_at` (default now); true when the link exists. */
62
+ async touch(id, at = new Date()) {
63
+ const ms = checkedMs(at, 'DbIdentityLinkStore.touch: at');
64
+ await ormReady();
65
+ const { RowsAffected } = await AuthnIdentity.update({ last_used_at: instant(ms) }).where('id', id);
66
+ return RowsAffected === 1;
67
+ }
68
+ };
69
+ DbIdentityLinkStore = __decorate([
70
+ PerChildInstance(),
71
+ Injectable(IdentityLinkStore)
72
+ ], DbIdentityLinkStore);
73
+ export { DbIdentityLinkStore };
74
+ function toLink(r) {
75
+ return {
76
+ id: r.id,
77
+ identity: { type: r.identity_type, id: r.identity_id },
78
+ provider: r.provider,
79
+ subject: r.subject,
80
+ ...(r.email !== null && r.email !== undefined ? { email: r.email } : {}),
81
+ linkedAt: dateOf(r.linked_at),
82
+ ...(r.last_used_at ? { lastUsedAt: dateOf(r.last_used_at) } : {}),
83
+ };
84
+ }
85
+ //# sourceMappingURL=db-link-store.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"db-link-store.js","sourceRoot":"","sources":["../../../src/links/db-link-store.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,2 @@
1
+ export { DbIdentityLinkStore } from './db-link-store.js';
2
+ //# sourceMappingURL=index.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../src/links/index.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,mBAAmB,EAAE,MAAM,oBAAoB,CAAC"}
@@ -0,0 +1,2 @@
1
+ export { DbIdentityLinkStore } from './db-link-store.js';
2
+ //# sourceMappingURL=index.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.js","sourceRoot":"","sources":["../../../src/links/index.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,mBAAmB,EAAE,MAAM,oBAAoB,CAAC"}
@@ -0,0 +1,18 @@
1
+ import type { IdentityRef } from '@spinajs/authn/contracts';
2
+ /** The MFA encryption key (`authn.mfa.encryptionKey.secret`) and its id, which `authn_mfa.key_id` stores. */
3
+ export interface MfaKey {
4
+ /** Not enumerable, so it stays out of logs and JSON. */
5
+ readonly key: Buffer;
6
+ /** The first 16 characters of base64url(SHA-256(key)). */
7
+ readonly keyId: string;
8
+ }
9
+ /**
10
+ * Reads a 32-byte key given as 64 hex characters, base64 (44, or 43 unpadded) or base64url (43). Anything else
11
+ * throws `InvalidOption`; the message never contains the value.
12
+ */
13
+ export declare function mfaKeyFrom(secret: string): MfaKey;
14
+ /** AES-256-GCM under `key` with AAD `${identity}|${step}`; returns `v1.<iv>.<tag>.<ct>`, each part base64url. */
15
+ export declare function encryptMfaSecret(key: MfaKey, identity: IdentityRef | string, step: string, plain: string): string;
16
+ /** Throws `InvalidArgument` on a malformed text, another key, a changed text or another row's identity or step. */
17
+ export declare function decryptMfaSecret(key: MfaKey, identity: IdentityRef | string, step: string, enc: string): string;
18
+ //# sourceMappingURL=cipher.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"cipher.d.ts","sourceRoot":"","sources":["../../../src/mfa/cipher.ts"],"names":[],"mappings":"AAEA,OAAO,KAAK,EAAE,WAAW,EAAE,MAAM,0BAA0B,CAAC;AAY5D,6GAA6G;AAC7G,MAAM,WAAW,MAAM;IACrB,wDAAwD;IACxD,QAAQ,CAAC,GAAG,EAAE,MAAM,CAAC;IACrB,0DAA0D;IAC1D,QAAQ,CAAC,KAAK,EAAE,MAAM,CAAC;CACxB;AAMD;;;GAGG;AACH,wBAAgB,UAAU,CAAC,MAAM,EAAE,MAAM,GAAG,MAAM,CAkBjD;AAUD,iHAAiH;AACjH,wBAAgB,gBAAgB,CAAC,GAAG,EAAE,MAAM,EAAE,QAAQ,EAAE,WAAW,GAAG,MAAM,EAAE,IAAI,EAAE,MAAM,EAAE,KAAK,EAAE,MAAM,GAAG,MAAM,CAQjH;AAID,mHAAmH;AACnH,wBAAgB,gBAAgB,CAAC,GAAG,EAAE,MAAM,EAAE,QAAQ,EAAE,WAAW,GAAG,MAAM,EAAE,IAAI,EAAE,MAAM,EAAE,GAAG,EAAE,MAAM,GAAG,MAAM,CAmB/G"}