@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
package/README.md CHANGED
@@ -1,3 +1,85 @@
1
- # Temporary Holding Version
1
+ # `@spinajs/authn-orm`
2
2
 
3
- This version is a temporary placeholder for this package. An operational version to replace this has been submitted for review and is awaiting a staged release.
3
+ ORM stores and migrations for SpinaJS authentication (design §22.12, §22.13, §22.16,
4
+ §22.18).
5
+
6
+ ## Migrations
7
+
8
+ Importing the package registers `AuthnInitial_2026_10_02_00_00_00` on the `default` connection. It
9
+ creates `authn_identity`, `authn_throttle`, `authn_audit`, `authn_secret`, `authn_mfa`,
10
+ `authn_recovery_code` and `authn_nonce`. Nothing is carried over from 2.x `users_metadata`: 2.x TOTP
11
+ enrolments, pending resets and invites do not survive the upgrade.
12
+
13
+ ## Services
14
+
15
+ Each one is registered under its class name, so configuration can name it:
16
+
17
+ | Contract | Class | Config |
18
+ |---|---|---|
19
+ | `AuthnThrottle` | `DbAuthnThrottle` | used when `authn.throttle.service` is unset (or named) |
20
+ | `SecretStore` | `DbSecretStore` | — |
21
+ | `IdentityLinkStore` | `DbIdentityLinkStore` | — |
22
+ | `AuthnEventSink` | `DbAuthnAuditSink` | gets every event |
23
+ | — | `DbNonceStore` (`NonceStore`, `MemoryNonceStore`) | — |
24
+ | — | `DbMfaStore` | for MFA steps (authn-totp) |
25
+
26
+ Once this package is imported, the core uses `DbAuthnThrottle` when `authn.throttle.service` is unset:
27
+ it takes the only registered throttle besides `MemoryAuthnThrottle`. An app that wants the memory
28
+ throttle names it. The package ships no config file: config files load whether or not their package
29
+ is imported, so a shipped service name would break an app that has this package installed but unused
30
+ (authn-totp depends on it). `DbAuthnAuditSink` gets every event once registered.
31
+
32
+ The MFA cipher (`mfaKeyFrom`, `encryptMfaSecret`, `decryptMfaSecret`) uses AES-256-GCM.
33
+ The format is `v1.<iv>.<tag>.<ct>`, and the additional authenticated data is
34
+ `<identity>|<step>`. Callers must build the identity from `users.Uuid` exactly as it is
35
+ stored (`user:<Uuid>`), or the secret will not decrypt. Recovery codes are stored as
36
+ unsalted SHA-256, so steps must generate codes of at least 80 bits.
37
+ The cipher and `identityKey` are also exported from the side-effect-free subpaths
38
+ `@spinajs/authn-orm/cipher` and `@spinajs/authn-orm/identity`, which register nothing.
39
+
40
+ Every store reads and writes through the package's models (`AuthnIdentity`, `AuthnSecret`,
41
+ `AuthnNonce`, `AuthnMfa`, `AuthnRecoveryCode`, `AuthnThrottle`, `AuthnAudit`), which name the
42
+ table and the `default` connection. The stores take no driver: a store awaits `ormReady()` before
43
+ its first statement, and a test boots an Orm whose `default` connection is the database under test.
44
+ The stores, `DbAuthnThrottle` and `DbMfaEnrolments` are `@PerChildInstance`: each container that
45
+ resolves one gets its own instance, and the throttle reads that container's configuration.
46
+
47
+ ## Rules the stores keep
48
+
49
+ - **Time comes from Node.** "Now" is `ctx.now`, or `Date` at call time; SQL `now()` is
50
+ never used. Every claim, expiry or compare-and-set is decided in SQL against bound
51
+ values. Datetimes are written as UTC (ISO-8601 text on SQLite).
52
+ - **Secrets are never stored in clear:**
53
+ - single-use secrets and recovery codes are kept as SHA-256 only;
54
+ - TOTP secrets are kept as cipher text only;
55
+ - throttle keys are kept as an HMAC under `authn.audit.hashKey.secret`. Without that
56
+ secret the HMAC key is a public constant, so anyone who reads `authn_throttle` can
57
+ test guessed logins and IPs against it. The store warns once at start.
58
+ - **A login throttles, it never locks.** Attempts are counted before verification, one
59
+ compare-and-set per key, so a burst gets exactly `free` verifications (A05, A06).
60
+
61
+ ## Supported drivers and known gaps
62
+
63
+ - sqlite and postgres are tested against a real database. MySQL and MSSQL are checked only
64
+ as compiled SQL.
65
+ - **postgres:** node-postgres reads `timestamp` as local time. A value that falls in the
66
+ local spring DST gap therefore reads back one hour late. This needs a fix in
67
+ orm-postgres; no store depends on such a read for a decision.
68
+ - **MySQL and MSSQL:**
69
+ - `datetime` precision is lower, so the throttle's undo may miss, which errs towards
70
+ more throttling. A sub-second `baseDelayMs` is not supported there.
71
+ - Default collations ignore case. Every read therefore also checks identity, step,
72
+ purpose, provider and subject for exact equality in Node. Writes keyed by identity
73
+ still rely on the collation, so on these drivers the identity columns need a binary
74
+ collation.
75
+ - **Races:** two parallel `issue` calls, or two `replaceRecoveryCodes` calls, for the same
76
+ identity and purpose can leave two live rows. This is because the stores use no
77
+ transactions, since the sqlite driver shares one handle.
78
+
79
+ ## Throttle store
80
+
81
+ `DbAuthnThrottle` is a `StoreAuthnThrottle` (`@spinajs/authn`) over `DbThrottleStore`, a util `ThrottleStore` on
82
+ `authn_throttle`. The flow rules, keys and config are in `packages/authn/src/throttle/README.md`. `DbThrottleStore`
83
+ is exported for reuse and tests; `DbAuthnThrottle.createStore(options)` is the protected seam that builds it (override it to wrap or replace the store).
84
+ Writes are compare-and-set statements without a transaction (the sqlite driver shares one handle), so a lost race
85
+ only throttles more.
@@ -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,73 @@
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
+ Object.defineProperty(exports, "__esModule", { value: true });
9
+ exports.DbAuthnAuditSink = void 0;
10
+ const node_crypto_1 = require("node:crypto");
11
+ const contracts_1 = require("@spinajs/authn/contracts");
12
+ const di_1 = require("@spinajs/di");
13
+ const orm_1 = require("@spinajs/orm");
14
+ const identity_js_1 = require("../identity.js");
15
+ const AuthnAudit_js_1 = require("../models/AuthnAudit.js");
16
+ const sql_js_1 = require("../support/sql.js");
17
+ const values_js_1 = require("../support/values.js");
18
+ function keyOrNull(ref) {
19
+ if (!ref)
20
+ return null;
21
+ try {
22
+ return (0, identity_js_1.identityKey)(ref);
23
+ }
24
+ catch {
25
+ return null;
26
+ }
27
+ }
28
+ function json(value) {
29
+ try {
30
+ return JSON.stringify(value, (_k, v) => (typeof v === 'bigint' ? v.toString() : v));
31
+ }
32
+ catch {
33
+ return JSON.stringify({ unserialisable: true });
34
+ }
35
+ }
36
+ /**
37
+ * One `authn_audit` row per event (SR-11). Nothing in an event makes the write fail, so a sink never fails a call
38
+ * whose work is already done (D4 over D1): free text longer than its column is cut, and an identity or actor that
39
+ * does not fit its column leaves the column null and goes whole into `data` (`identityRef`, `actorRef`).
40
+ */
41
+ let DbAuthnAuditSink = class DbAuthnAuditSink extends contracts_1.AuthnEventSink {
42
+ async publish(e) {
43
+ const identity = keyOrNull(e.identity);
44
+ const actor = keyOrNull(e.actor);
45
+ const extra = {
46
+ ...(e.identity && identity === null ? { identityRef: { type: e.identity.type, id: e.identity.id } } : {}),
47
+ ...(e.actor && actor === null ? { actorRef: { type: e.actor.type, id: e.actor.id } } : {}),
48
+ };
49
+ const data = e.data === undefined && Object.keys(extra).length === 0 ? undefined : { ...(e.data ?? {}), ...extra };
50
+ const at = (0, sql_js_1.instant)((0, sql_js_1.checkedMs)(e.at, 'DbAuthnAuditSink.publish: e.at'));
51
+ await (0, orm_1.ormReady)();
52
+ await AuthnAudit_js_1.AuthnAudit.insert((0, values_js_1.columnValues)({
53
+ id: (0, node_crypto_1.randomUUID)(),
54
+ at,
55
+ type: (0, sql_js_1.cutText)(e.type, 32),
56
+ outcome: (0, sql_js_1.cutText)(e.outcome, 8),
57
+ identity,
58
+ actor,
59
+ strategy: (0, sql_js_1.cutText)(e.strategy, 64),
60
+ reason: (0, sql_js_1.cutText)(e.reason, 64),
61
+ ip: (0, sql_js_1.cutText)(e.ip, 64),
62
+ user_agent: (0, sql_js_1.cutText)(e.userAgent, 255),
63
+ session: (0, sql_js_1.cutText)(e.session, 64),
64
+ data: data === undefined ? null : json(data),
65
+ }));
66
+ }
67
+ };
68
+ exports.DbAuthnAuditSink = DbAuthnAuditSink;
69
+ exports.DbAuthnAuditSink = DbAuthnAuditSink = __decorate([
70
+ (0, di_1.PerChildInstance)(),
71
+ (0, di_1.Injectable)(contracts_1.AuthnEventSink)
72
+ ], DbAuthnAuditSink);
73
+ //# 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,6 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.DbAuthnAuditSink = void 0;
4
+ var db_audit_sink_js_1 = require("./db-audit-sink.js");
5
+ Object.defineProperty(exports, "DbAuthnAuditSink", { enumerable: true, get: function () { return db_audit_sink_js_1.DbAuthnAuditSink; } });
6
+ //# sourceMappingURL=index.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.js","sourceRoot":"","sources":["../../../src/audit/index.ts"],"names":[],"mappings":";;;AAAA,uDAAsD;AAA7C,oHAAA,gBAAgB,OAAA"}
@@ -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,27 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.identityKey = identityKey;
4
+ exports.parseIdentityKey = parseIdentityKey;
5
+ const exceptions_1 = require("@spinajs/exceptions");
6
+ const util_1 = require("@spinajs/util");
7
+ /** `${type}:${id}`, the form `identity` and `actor` columns hold (D1). Never truncates: too long throws. */
8
+ function identityKey(ref, maxLength = 100) {
9
+ (0, util_1._check_arg)((0, util_1._is_string)((0, util_1._non_empty)()))(ref?.type, 'identity type');
10
+ if (ref.type.includes(':')) {
11
+ throw new exceptions_1.InvalidArgument(`identity type "${ref.type}" contains ":"`);
12
+ }
13
+ const key = `${ref.type}:${ref.id}`;
14
+ if (key.length > maxLength) {
15
+ throw new exceptions_1.InvalidArgument(`identity key of type "${ref.type}" is ${key.length} characters long, the column holds ${maxLength}`);
16
+ }
17
+ return key;
18
+ }
19
+ /** Splits at the first `:`; the id may contain more. */
20
+ function parseIdentityKey(key) {
21
+ const at = key.indexOf(':');
22
+ if (at <= 0) {
23
+ throw new exceptions_1.InvalidArgument('identity key is not of the form <type>:<id>');
24
+ }
25
+ return { type: key.slice(0, at), id: key.slice(at + 1) };
26
+ }
27
+ //# sourceMappingURL=identity.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"identity.js","sourceRoot":"","sources":["../../src/identity.ts"],"names":[],"mappings":";;;;AACA,oDAAsD;AACtD,wCAAmE;AAEnE,4GAA4G;AAC5G,qBAA4B,GAAgB,EAAE,SAAS,GAAG,GAAG;IAC3D,IAAA,iBAAU,EAAC,IAAA,iBAAU,EAAC,IAAA,iBAAU,GAAE,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,4BAAe,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,4BAAe,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,0BAAiC,GAAW;IAC1C,MAAM,EAAE,GAAG,GAAG,CAAC,OAAO,CAAC,GAAG,CAAC,CAAC;IAC5B,IAAI,EAAE,IAAI,CAAC,EAAE,CAAC;QACZ,MAAM,IAAI,4BAAe,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,26 @@
1
+ "use strict";
2
+ var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
3
+ if (k2 === undefined) k2 = k;
4
+ var desc = Object.getOwnPropertyDescriptor(m, k);
5
+ if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
6
+ desc = { enumerable: true, get: function() { return m[k]; } };
7
+ }
8
+ Object.defineProperty(o, k2, desc);
9
+ }) : (function(o, m, k, k2) {
10
+ if (k2 === undefined) k2 = k;
11
+ o[k2] = m[k];
12
+ }));
13
+ var __exportStar = (this && this.__exportStar) || function(m, exports) {
14
+ for (var p in m) if (p !== "default" && !Object.prototype.hasOwnProperty.call(exports, p)) __createBinding(exports, m, p);
15
+ };
16
+ Object.defineProperty(exports, "__esModule", { value: true });
17
+ __exportStar(require("./migrations/index.js"), exports);
18
+ __exportStar(require("./models/index.js"), exports);
19
+ __exportStar(require("./identity.js"), exports);
20
+ __exportStar(require("./throttle/index.js"), exports);
21
+ __exportStar(require("./secrets/index.js"), exports);
22
+ __exportStar(require("./links/index.js"), exports);
23
+ __exportStar(require("./nonces/index.js"), exports);
24
+ __exportStar(require("./mfa/index.js"), exports);
25
+ __exportStar(require("./audit/index.js"), exports);
26
+ //# sourceMappingURL=index.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.js","sourceRoot":"","sources":["../../src/index.ts"],"names":[],"mappings":";;;;;;;;;;;;;;;;AAAA,wDAAsC;AACtC,oDAAkC;AAClC,gDAA8B;AAC9B,sDAAoC;AACpC,qDAAmC;AACnC,mDAAiC;AACjC,oDAAkC;AAClC,iDAA+B;AAC/B,mDAAiC"}
@@ -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,88 @@
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
+ Object.defineProperty(exports, "__esModule", { value: true });
9
+ exports.DbIdentityLinkStore = void 0;
10
+ const node_crypto_1 = require("node:crypto");
11
+ const contracts_1 = require("@spinajs/authn/contracts");
12
+ const di_1 = require("@spinajs/di");
13
+ const exceptions_1 = require("@spinajs/exceptions");
14
+ const orm_1 = require("@spinajs/orm");
15
+ const AuthnIdentity_js_1 = require("../models/AuthnIdentity.js");
16
+ const sql_js_1 = require("../support/sql.js");
17
+ const values_js_1 = require("../support/values.js");
18
+ const LINK_COLUMNS = ['id', 'identity_type', 'identity_id', 'provider', 'subject', 'email', 'linked_at', 'last_used_at'];
19
+ function identityParts(ref) {
20
+ const type = (0, sql_js_1.checkedText)(ref?.type, 16, 'DbIdentityLinkStore: identity type');
21
+ if (type.includes(':'))
22
+ throw new exceptions_1.InvalidArgument(`DbIdentityLinkStore: identity type "${type}" contains ":"`);
23
+ return { type, id: (0, sql_js_1.checkedText)(ref.id, 64, 'DbIdentityLinkStore: identity id') };
24
+ }
25
+ /** `authn_identity`: external subjects linked to identities (A19). Values longer than their columns throw (D1). */
26
+ let DbIdentityLinkStore = class DbIdentityLinkStore extends contracts_1.IdentityLinkStore {
27
+ async find(provider, subject) {
28
+ await (0, orm_1.ormReady)();
29
+ const rows = await AuthnIdentity_js_1.AuthnIdentity.query().columns(LINK_COLUMNS).where('provider', provider).where('subject', subject);
30
+ // MySQL and MSSQL default collations ignore case (and accents or trailing spaces): a subject differing only that
31
+ // way must not sign in as another account.
32
+ const exact = rows.find((r) => r.provider === provider && r.subject === subject);
33
+ return exact ? toLink(exact) : null;
34
+ }
35
+ async list(identity) {
36
+ const { type, id } = identityParts(identity);
37
+ await (0, orm_1.ormReady)();
38
+ const rows = await AuthnIdentity_js_1.AuthnIdentity.query().columns(LINK_COLUMNS).where('identity_type', type).where('identity_id', id).orderBy('linked_at');
39
+ return rows.filter((r) => r.identity_type === type && r.identity_id === id).map(toLink);
40
+ }
41
+ /** A duplicate (provider, subject) rejects with `ResourceDuplicated` (the unique index decides). */
42
+ async link(identity, external) {
43
+ const { type, id } = identityParts(identity);
44
+ const provider = (0, sql_js_1.checkedText)(external?.provider, 128, 'DbIdentityLinkStore: provider');
45
+ const subject = (0, sql_js_1.checkedText)(external.subject, 255, 'DbIdentityLinkStore: subject');
46
+ const email = external.email === undefined || external.email === null ? undefined : (0, sql_js_1.checkedText)(external.email, 255, 'DbIdentityLinkStore: email', true);
47
+ const nowMs = (0, sql_js_1.checkedMs)(new Date(), 'DbIdentityLinkStore.link: the clock');
48
+ await (0, orm_1.ormReady)();
49
+ const linkId = (0, node_crypto_1.randomUUID)();
50
+ try {
51
+ await AuthnIdentity_js_1.AuthnIdentity.insert((0, values_js_1.columnValues)({ id: linkId, identity_type: type, identity_id: id, provider, subject, email: email ?? null, email_verified: external.emailVerified === true, attributes: null, linked_at: (0, sql_js_1.instant)(nowMs), last_used_at: null }));
52
+ }
53
+ catch (err) {
54
+ if (err instanceof orm_1.UniqueViolation)
55
+ throw new exceptions_1.ResourceDuplicated(`DbIdentityLinkStore: (${provider}, subject) is already linked`, err);
56
+ throw err;
57
+ }
58
+ return { id: linkId, identity: { type, id }, provider, subject, ...(email !== undefined ? { email } : {}), linkedAt: new Date(nowMs) };
59
+ }
60
+ async unlink(id) {
61
+ await (0, orm_1.ormReady)();
62
+ await AuthnIdentity_js_1.AuthnIdentity.destroy().where('id', id);
63
+ }
64
+ /** Sets `last_used_at` (default now); true when the link exists. */
65
+ async touch(id, at = new Date()) {
66
+ const ms = (0, sql_js_1.checkedMs)(at, 'DbIdentityLinkStore.touch: at');
67
+ await (0, orm_1.ormReady)();
68
+ const { RowsAffected } = await AuthnIdentity_js_1.AuthnIdentity.update({ last_used_at: (0, sql_js_1.instant)(ms) }).where('id', id);
69
+ return RowsAffected === 1;
70
+ }
71
+ };
72
+ exports.DbIdentityLinkStore = DbIdentityLinkStore;
73
+ exports.DbIdentityLinkStore = DbIdentityLinkStore = __decorate([
74
+ (0, di_1.PerChildInstance)(),
75
+ (0, di_1.Injectable)(contracts_1.IdentityLinkStore)
76
+ ], DbIdentityLinkStore);
77
+ function toLink(r) {
78
+ return {
79
+ id: r.id,
80
+ identity: { type: r.identity_type, id: r.identity_id },
81
+ provider: r.provider,
82
+ subject: r.subject,
83
+ ...(r.email !== null && r.email !== undefined ? { email: r.email } : {}),
84
+ linkedAt: (0, sql_js_1.dateOf)(r.linked_at),
85
+ ...(r.last_used_at ? { lastUsedAt: (0, sql_js_1.dateOf)(r.last_used_at) } : {}),
86
+ };
87
+ }
88
+ //# 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,6 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.DbIdentityLinkStore = void 0;
4
+ var db_link_store_js_1 = require("./db-link-store.js");
5
+ Object.defineProperty(exports, "DbIdentityLinkStore", { enumerable: true, get: function () { return db_link_store_js_1.DbIdentityLinkStore; } });
6
+ //# sourceMappingURL=index.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.js","sourceRoot":"","sources":["../../../src/links/index.ts"],"names":[],"mappings":";;;AAAA,uDAAyD;AAAhD,uHAAA,mBAAmB,OAAA"}
@@ -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"}
@@ -0,0 +1,81 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.mfaKeyFrom = mfaKeyFrom;
4
+ exports.encryptMfaSecret = encryptMfaSecret;
5
+ exports.decryptMfaSecret = decryptMfaSecret;
6
+ const node_crypto_1 = require("node:crypto");
7
+ const exceptions_1 = require("@spinajs/exceptions");
8
+ const util_1 = require("@spinajs/util");
9
+ const identity_js_1 = require("../identity.js");
10
+ const ALGORITHM = 'aes-256-gcm';
11
+ const VERSION = 'v1';
12
+ const KEY_BYTES = 32;
13
+ const IV_BYTES = 12;
14
+ const TAG_BYTES = 16;
15
+ const HEX = /^[0-9a-fA-F]{64}$/;
16
+ const BASE64 = /^[A-Za-z0-9+/]{43}=?$/;
17
+ const BASE64URL = /^[A-Za-z0-9_-]{43}$/;
18
+ /**
19
+ * Reads a 32-byte key given as 64 hex characters, base64 (44, or 43 unpadded) or base64url (43). Anything else
20
+ * throws `InvalidOption`; the message never contains the value.
21
+ */
22
+ function mfaKeyFrom(secret) {
23
+ let key;
24
+ if (typeof secret === 'string') {
25
+ if (HEX.test(secret)) {
26
+ key = Buffer.from(secret, 'hex');
27
+ }
28
+ else if (BASE64.test(secret) || BASE64URL.test(secret)) {
29
+ key = Buffer.from(secret, 'base64');
30
+ // Unused low bits in the last character would let several texts name one key.
31
+ if (key.toString('base64url') !== secret.replace(/=$/, '').replace(/\+/g, '-').replace(/\//g, '_'))
32
+ key = undefined;
33
+ }
34
+ }
35
+ if (!key || key.length !== KEY_BYTES) {
36
+ throw new exceptions_1.InvalidOption('authn.mfa.encryptionKey.secret must be 32 bytes given as 64 hex characters, base64 or base64url');
37
+ }
38
+ const result = { keyId: (0, node_crypto_1.createHash)('sha256').update(key).digest('base64url').slice(0, 16) };
39
+ Object.defineProperty(result, 'key', { value: key, enumerable: false });
40
+ return Object.freeze(result);
41
+ }
42
+ function aad(identity, step) {
43
+ const id = typeof identity === 'string' ? identity : (0, identity_js_1.identityKey)(identity);
44
+ (0, util_1._check_arg)((0, util_1._is_string)((0, util_1._non_empty)()))(id, 'identity');
45
+ // With no "|" in the step, the last "|" splits the AAD into exactly one (identity, step) pair.
46
+ (0, util_1._check_arg)((0, util_1._is_string)((0, util_1._non_empty)(), (0, util_1._reg_match)(/^[^|]*$/)))(step, 'step');
47
+ return Buffer.from(`${id}|${step}`, 'utf8');
48
+ }
49
+ /** AES-256-GCM under `key` with AAD `${identity}|${step}`; returns `v1.<iv>.<tag>.<ct>`, each part base64url. */
50
+ function encryptMfaSecret(key, identity, step, plain) {
51
+ (0, util_1._check_arg)((0, util_1._is_string)((0, util_1._non_empty)()))(plain, 'plain');
52
+ const ad = aad(identity, step);
53
+ const iv = (0, node_crypto_1.randomBytes)(IV_BYTES);
54
+ const cipher = (0, node_crypto_1.createCipheriv)(ALGORITHM, key.key, iv, { authTagLength: TAG_BYTES });
55
+ cipher.setAAD(ad);
56
+ const ct = Buffer.concat([cipher.update(plain, 'utf8'), cipher.final()]);
57
+ return [VERSION, iv.toString('base64url'), cipher.getAuthTag().toString('base64url'), ct.toString('base64url')].join('.');
58
+ }
59
+ const PART = /^[A-Za-z0-9_-]+$/;
60
+ /** Throws `InvalidArgument` on a malformed text, another key, a changed text or another row's identity or step. */
61
+ function decryptMfaSecret(key, identity, step, enc) {
62
+ const ad = aad(identity, step);
63
+ const parts = typeof enc === 'string' ? enc.split('.') : [];
64
+ if (parts.length !== 4 || parts[0] !== VERSION || !parts.slice(1).every((p) => PART.test(p))) {
65
+ throw new exceptions_1.InvalidArgument('MFA cipher: the cipher text is not of the form v1.<iv>.<tag>.<ct>');
66
+ }
67
+ const [iv, tag, ct] = parts.slice(1).map((p) => Buffer.from(p, 'base64url'));
68
+ if (iv.length !== IV_BYTES || tag.length !== TAG_BYTES) {
69
+ throw new exceptions_1.InvalidArgument('MFA cipher: the cipher text has a wrong IV or tag length');
70
+ }
71
+ try {
72
+ const decipher = (0, node_crypto_1.createDecipheriv)(ALGORITHM, key.key, iv, { authTagLength: TAG_BYTES });
73
+ decipher.setAAD(ad);
74
+ decipher.setAuthTag(tag);
75
+ return Buffer.concat([decipher.update(ct), decipher.final()]).toString('utf8');
76
+ }
77
+ catch (err) {
78
+ throw new exceptions_1.InvalidArgument('MFA cipher: the cipher text does not decrypt under this key for this identity and step', undefined, undefined, err);
79
+ }
80
+ }
81
+ //# sourceMappingURL=cipher.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"cipher.js","sourceRoot":"","sources":["../../../src/mfa/cipher.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,14 @@
1
+ import type { IdentityRef } from '@spinajs/authn/contracts';
2
+ import { MfaEnrolments } from '@spinajs/authn/mfa-enrolments';
3
+ import { DbMfaStore } from './db-mfa-store.js';
4
+ /** The confirmed steps of `authn_mfa` for DefaultMfaPolicy and authn:check-config, whether authn.mfa.steps lists them or not. */
5
+ export declare class DbMfaEnrolments extends MfaEnrolments {
6
+ private readonly db?;
7
+ protected DbMfaStore: DbMfaStore;
8
+ /** DI passes nothing and injects `DbMfaStore`. */
9
+ constructor(db?: DbMfaStore | undefined);
10
+ private store;
11
+ stepsOf(id: IdentityRef): Promise<readonly string[]>;
12
+ stepNames(): Promise<readonly string[]>;
13
+ }
14
+ //# sourceMappingURL=db-mfa-enrolments.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"db-mfa-enrolments.d.ts","sourceRoot":"","sources":["../../../src/mfa/db-mfa-enrolments.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,WAAW,EAAE,MAAM,0BAA0B,CAAC;AAC5D,OAAO,EAAE,aAAa,EAAE,MAAM,+BAA+B,CAAC;AAG9D,OAAO,EAAE,UAAU,EAAE,MAAM,mBAAmB,CAAC;AAE/C,iIAAiI;AACjI,qBAEa,eAAgB,SAAQ,aAAa;IAKpC,OAAO,CAAC,QAAQ,CAAC,EAAE,CAAC;IAHhC,SAAS,CAAC,UAAU,EAAE,UAAU,CAAC;IAEjC,kDAAkD;IAClD,YAA6B,EAAE,CAAC,EAAE,UAAU,YAAA,EAE3C;IAED,OAAO,CAAC,KAAK;IAIN,OAAO,CAAC,EAAE,EAAE,WAAW,GAAG,OAAO,CAAC,SAAS,MAAM,EAAE,CAAC,CAE1D;IAEM,SAAS,IAAI,OAAO,CAAC,SAAS,MAAM,EAAE,CAAC,CAE7C;CACF"}
@@ -0,0 +1,43 @@
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.DbMfaEnrolments = void 0;
13
+ const mfa_enrolments_1 = require("@spinajs/authn/mfa-enrolments");
14
+ const di_1 = require("@spinajs/di");
15
+ const db_mfa_store_js_1 = require("./db-mfa-store.js");
16
+ /** The confirmed steps of `authn_mfa` for DefaultMfaPolicy and authn:check-config, whether authn.mfa.steps lists them or not. */
17
+ let DbMfaEnrolments = class DbMfaEnrolments extends mfa_enrolments_1.MfaEnrolments {
18
+ /** DI passes nothing and injects `DbMfaStore`. */
19
+ constructor(db) {
20
+ super();
21
+ this.db = db;
22
+ }
23
+ store() {
24
+ return this.db ?? this.DbMfaStore;
25
+ }
26
+ stepsOf(id) {
27
+ return this.store().confirmedSteps(id);
28
+ }
29
+ stepNames() {
30
+ return this.store().confirmedStepNames();
31
+ }
32
+ };
33
+ exports.DbMfaEnrolments = DbMfaEnrolments;
34
+ __decorate([
35
+ (0, di_1.Autoinject)(db_mfa_store_js_1.DbMfaStore),
36
+ __metadata("design:type", db_mfa_store_js_1.DbMfaStore)
37
+ ], DbMfaEnrolments.prototype, "DbMfaStore", void 0);
38
+ exports.DbMfaEnrolments = DbMfaEnrolments = __decorate([
39
+ (0, di_1.PerChildInstance)(),
40
+ (0, di_1.Injectable)(mfa_enrolments_1.MfaEnrolments),
41
+ __metadata("design:paramtypes", [db_mfa_store_js_1.DbMfaStore])
42
+ ], DbMfaEnrolments);
43
+ //# sourceMappingURL=db-mfa-enrolments.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"db-mfa-enrolments.js","sourceRoot":"","sources":["../../../src/mfa/db-mfa-enrolments.ts"],"names":[],"mappings":";;;;;;;;;;;;AACA,kEAA8D;AAC9D,oCAAuE;AAEvE,uDAA+C;AAE/C,iIAAiI;AAG1H,IAAM,eAAe,GAArB,MAAM,eAAgB,SAAQ,8BAAa;IAIhD,kDAAkD;IAClD,YAA6B,EAAe;QAC1C,KAAK,EAAE,CAAC;kBADmB,EAAE;IAE/B,CAAC;IAEO,KAAK;QACX,OAAO,IAAI,CAAC,EAAE,IAAI,IAAI,CAAC,UAAU,CAAC;IACpC,CAAC;IAEM,OAAO,CAAC,EAAe;QAC5B,OAAO,IAAI,CAAC,KAAK,EAAE,CAAC,cAAc,CAAC,EAAE,CAAC,CAAC;IACzC,CAAC;IAEM,SAAS;QACd,OAAO,IAAI,CAAC,KAAK,EAAE,CAAC,kBAAkB,EAAE,CAAC;IAC3C,CAAC;CACF,CAAA;;AAlBW;IADT,IAAA,eAAU,EAAC,4BAAU,CAAC;8BACD,4BAAU;mDAAC;0BAFtB,eAAe;IAF3B,IAAA,qBAAgB,GAAE;IAClB,IAAA,eAAU,EAAC,8BAAa,CAAC;qCAMU,4BAAU;GALjC,eAAe,CAoB3B"}