@spinajs/authn-keys 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 (342) hide show
  1. package/README.md +165 -2
  2. package/lib/cjs/bootstrap.d.ts +6 -0
  3. package/lib/cjs/bootstrap.d.ts.map +1 -0
  4. package/lib/cjs/bootstrap.js +23 -0
  5. package/lib/cjs/bootstrap.js.map +1 -0
  6. package/lib/cjs/challenge/challenge.d.ts +27 -0
  7. package/lib/cjs/challenge/challenge.d.ts.map +1 -0
  8. package/lib/cjs/challenge/challenge.js +56 -0
  9. package/lib/cjs/challenge/challenge.js.map +1 -0
  10. package/lib/cjs/challenge/index.d.ts +2 -0
  11. package/lib/cjs/challenge/index.d.ts.map +1 -0
  12. package/lib/cjs/challenge/index.js +18 -0
  13. package/lib/cjs/challenge/index.js.map +1 -0
  14. package/lib/cjs/cli/AddKey.d.ts +18 -0
  15. package/lib/cjs/cli/AddKey.d.ts.map +1 -0
  16. package/lib/cjs/cli/AddKey.js +65 -0
  17. package/lib/cjs/cli/AddKey.js.map +1 -0
  18. package/lib/cjs/cli/ListKeys.d.ts +11 -0
  19. package/lib/cjs/cli/ListKeys.d.ts.map +1 -0
  20. package/lib/cjs/cli/ListKeys.js +48 -0
  21. package/lib/cjs/cli/ListKeys.js.map +1 -0
  22. package/lib/cjs/cli/RevokeKey.d.ts +9 -0
  23. package/lib/cjs/cli/RevokeKey.d.ts.map +1 -0
  24. package/lib/cjs/cli/RevokeKey.js +42 -0
  25. package/lib/cjs/cli/RevokeKey.js.map +1 -0
  26. package/lib/cjs/cli/common.d.ts +9 -0
  27. package/lib/cjs/cli/common.d.ts.map +1 -0
  28. package/lib/cjs/cli/common.js +35 -0
  29. package/lib/cjs/cli/common.js.map +1 -0
  30. package/lib/cjs/cli/index.d.ts +5 -0
  31. package/lib/cjs/cli/index.d.ts.map +1 -0
  32. package/lib/cjs/cli/index.js +21 -0
  33. package/lib/cjs/cli/index.js.map +1 -0
  34. package/lib/cjs/config/authn-keys.d.ts +9 -0
  35. package/lib/cjs/config/authn-keys.d.ts.map +1 -0
  36. package/lib/cjs/config/authn-keys.js +23 -0
  37. package/lib/cjs/config/authn-keys.js.map +1 -0
  38. package/lib/cjs/httpsig/base.d.ts +8 -0
  39. package/lib/cjs/httpsig/base.d.ts.map +1 -0
  40. package/lib/cjs/httpsig/base.js +73 -0
  41. package/lib/cjs/httpsig/base.js.map +1 -0
  42. package/lib/cjs/httpsig/fields.d.ts +17 -0
  43. package/lib/cjs/httpsig/fields.d.ts.map +1 -0
  44. package/lib/cjs/httpsig/fields.js +137 -0
  45. package/lib/cjs/httpsig/fields.js.map +1 -0
  46. package/lib/cjs/httpsig/index.d.ts +3 -0
  47. package/lib/cjs/httpsig/index.d.ts.map +1 -0
  48. package/lib/cjs/httpsig/index.js +19 -0
  49. package/lib/cjs/httpsig/index.js.map +1 -0
  50. package/lib/cjs/index.d.ts +13 -0
  51. package/lib/cjs/index.d.ts.map +1 -0
  52. package/lib/cjs/index.js +29 -0
  53. package/lib/cjs/index.js.map +1 -0
  54. package/lib/cjs/jwk/base64url.d.ts +7 -0
  55. package/lib/cjs/jwk/base64url.d.ts.map +1 -0
  56. package/lib/cjs/jwk/base64url.js +22 -0
  57. package/lib/cjs/jwk/base64url.js.map +1 -0
  58. package/lib/cjs/jwk/ed25519.d.ts +9 -0
  59. package/lib/cjs/jwk/ed25519.d.ts.map +1 -0
  60. package/lib/cjs/jwk/ed25519.js +47 -0
  61. package/lib/cjs/jwk/ed25519.js.map +1 -0
  62. package/lib/cjs/jwk/index.d.ts +5 -0
  63. package/lib/cjs/jwk/index.d.ts.map +1 -0
  64. package/lib/cjs/jwk/index.js +21 -0
  65. package/lib/cjs/jwk/index.js.map +1 -0
  66. package/lib/cjs/jwk/keys.d.ts +18 -0
  67. package/lib/cjs/jwk/keys.d.ts.map +1 -0
  68. package/lib/cjs/jwk/keys.js +102 -0
  69. package/lib/cjs/jwk/keys.js.map +1 -0
  70. package/lib/cjs/jwk/signature.d.ts +11 -0
  71. package/lib/cjs/jwk/signature.d.ts.map +1 -0
  72. package/lib/cjs/jwk/signature.js +45 -0
  73. package/lib/cjs/jwk/signature.js.map +1 -0
  74. package/lib/cjs/jws/index.d.ts +4 -0
  75. package/lib/cjs/jws/index.d.ts.map +1 -0
  76. package/lib/cjs/jws/index.js +20 -0
  77. package/lib/cjs/jws/index.js.map +1 -0
  78. package/lib/cjs/jws/json.d.ts +11 -0
  79. package/lib/cjs/jws/json.d.ts.map +1 -0
  80. package/lib/cjs/jws/json.js +76 -0
  81. package/lib/cjs/jws/json.js.map +1 -0
  82. package/lib/cjs/jws/signer.d.ts +25 -0
  83. package/lib/cjs/jws/signer.d.ts.map +1 -0
  84. package/lib/cjs/jws/signer.js +83 -0
  85. package/lib/cjs/jws/signer.js.map +1 -0
  86. package/lib/cjs/jws/verifier.d.ts +10 -0
  87. package/lib/cjs/jws/verifier.d.ts.map +1 -0
  88. package/lib/cjs/jws/verifier.js +86 -0
  89. package/lib/cjs/jws/verifier.js.map +1 -0
  90. package/lib/cjs/migrations/AuthnKeys_2026_10_02_00_00_00.d.ts +7 -0
  91. package/lib/cjs/migrations/AuthnKeys_2026_10_02_00_00_00.d.ts.map +1 -0
  92. package/lib/cjs/migrations/AuthnKeys_2026_10_02_00_00_00.js +40 -0
  93. package/lib/cjs/migrations/AuthnKeys_2026_10_02_00_00_00.js.map +1 -0
  94. package/lib/cjs/migrations/index.d.ts +2 -0
  95. package/lib/cjs/migrations/index.d.ts.map +1 -0
  96. package/lib/cjs/migrations/index.js +18 -0
  97. package/lib/cjs/migrations/index.js.map +1 -0
  98. package/lib/cjs/models/AuthnKey.d.ts +22 -0
  99. package/lib/cjs/models/AuthnKey.d.ts.map +1 -0
  100. package/lib/cjs/models/AuthnKey.js +43 -0
  101. package/lib/cjs/models/AuthnKey.js.map +1 -0
  102. package/lib/cjs/models/AuthnNonce.d.ts +8 -0
  103. package/lib/cjs/models/AuthnNonce.d.ts.map +1 -0
  104. package/lib/cjs/models/AuthnNonce.js +31 -0
  105. package/lib/cjs/models/AuthnNonce.js.map +1 -0
  106. package/lib/cjs/models/index.d.ts +3 -0
  107. package/lib/cjs/models/index.d.ts.map +1 -0
  108. package/lib/cjs/models/index.js +19 -0
  109. package/lib/cjs/models/index.js.map +1 -0
  110. package/lib/cjs/nonce/index.d.ts +2 -0
  111. package/lib/cjs/nonce/index.d.ts.map +1 -0
  112. package/lib/cjs/nonce/index.js +18 -0
  113. package/lib/cjs/nonce/index.js.map +1 -0
  114. package/lib/cjs/nonce/store.d.ts +22 -0
  115. package/lib/cjs/nonce/store.d.ts.map +1 -0
  116. package/lib/cjs/nonce/store.js +98 -0
  117. package/lib/cjs/nonce/store.js.map +1 -0
  118. package/lib/cjs/options/index.d.ts +2 -0
  119. package/lib/cjs/options/index.d.ts.map +1 -0
  120. package/lib/cjs/options/index.js +18 -0
  121. package/lib/cjs/options/index.js.map +1 -0
  122. package/lib/cjs/options/options.d.ts +47 -0
  123. package/lib/cjs/options/options.d.ts.map +1 -0
  124. package/lib/cjs/options/options.js +42 -0
  125. package/lib/cjs/options/options.js.map +1 -0
  126. package/lib/cjs/package.json +1 -0
  127. package/lib/cjs/register-schema.d.ts +2 -0
  128. package/lib/cjs/register-schema.d.ts.map +1 -0
  129. package/lib/cjs/register-schema.js +9 -0
  130. package/lib/cjs/register-schema.js.map +1 -0
  131. package/lib/cjs/registry/index.d.ts +4 -0
  132. package/lib/cjs/registry/index.d.ts.map +1 -0
  133. package/lib/cjs/registry/index.js +20 -0
  134. package/lib/cjs/registry/index.js.map +1 -0
  135. package/lib/cjs/registry/orm-store.d.ts +15 -0
  136. package/lib/cjs/registry/orm-store.d.ts.map +1 -0
  137. package/lib/cjs/registry/orm-store.js +109 -0
  138. package/lib/cjs/registry/orm-store.js.map +1 -0
  139. package/lib/cjs/registry/registry.d.ts +54 -0
  140. package/lib/cjs/registry/registry.d.ts.map +1 -0
  141. package/lib/cjs/registry/registry.js +244 -0
  142. package/lib/cjs/registry/registry.js.map +1 -0
  143. package/lib/cjs/registry/store.d.ts +25 -0
  144. package/lib/cjs/registry/store.d.ts.map +1 -0
  145. package/lib/cjs/registry/store.js +66 -0
  146. package/lib/cjs/registry/store.js.map +1 -0
  147. package/lib/cjs/schema.d.ts +88 -0
  148. package/lib/cjs/schema.d.ts.map +1 -0
  149. package/lib/cjs/schema.js +41 -0
  150. package/lib/cjs/schema.js.map +1 -0
  151. package/lib/cjs/strategies/assertion.d.ts +29 -0
  152. package/lib/cjs/strategies/assertion.d.ts.map +1 -0
  153. package/lib/cjs/strategies/assertion.js +118 -0
  154. package/lib/cjs/strategies/assertion.js.map +1 -0
  155. package/lib/cjs/strategies/challenge.d.ts +25 -0
  156. package/lib/cjs/strategies/challenge.d.ts.map +1 -0
  157. package/lib/cjs/strategies/challenge.js +81 -0
  158. package/lib/cjs/strategies/challenge.js.map +1 -0
  159. package/lib/cjs/strategies/httpsig.d.ts +34 -0
  160. package/lib/cjs/strategies/httpsig.d.ts.map +1 -0
  161. package/lib/cjs/strategies/httpsig.js +127 -0
  162. package/lib/cjs/strategies/httpsig.js.map +1 -0
  163. package/lib/cjs/strategies/index.d.ts +5 -0
  164. package/lib/cjs/strategies/index.d.ts.map +1 -0
  165. package/lib/cjs/strategies/index.js +21 -0
  166. package/lib/cjs/strategies/index.js.map +1 -0
  167. package/lib/cjs/strategies/keys.d.ts +43 -0
  168. package/lib/cjs/strategies/keys.d.ts.map +1 -0
  169. package/lib/cjs/strategies/keys.js +93 -0
  170. package/lib/cjs/strategies/keys.js.map +1 -0
  171. package/lib/mjs/bootstrap.d.ts +6 -0
  172. package/lib/mjs/bootstrap.d.ts.map +1 -0
  173. package/lib/mjs/bootstrap.js +20 -0
  174. package/lib/mjs/bootstrap.js.map +1 -0
  175. package/lib/mjs/challenge/challenge.d.ts +27 -0
  176. package/lib/mjs/challenge/challenge.d.ts.map +1 -0
  177. package/lib/mjs/challenge/challenge.js +45 -0
  178. package/lib/mjs/challenge/challenge.js.map +1 -0
  179. package/lib/mjs/challenge/index.d.ts +2 -0
  180. package/lib/mjs/challenge/index.d.ts.map +1 -0
  181. package/lib/mjs/challenge/index.js +2 -0
  182. package/lib/mjs/challenge/index.js.map +1 -0
  183. package/lib/mjs/cli/AddKey.d.ts +18 -0
  184. package/lib/mjs/cli/AddKey.d.ts.map +1 -0
  185. package/lib/mjs/cli/AddKey.js +62 -0
  186. package/lib/mjs/cli/AddKey.js.map +1 -0
  187. package/lib/mjs/cli/ListKeys.d.ts +11 -0
  188. package/lib/mjs/cli/ListKeys.d.ts.map +1 -0
  189. package/lib/mjs/cli/ListKeys.js +44 -0
  190. package/lib/mjs/cli/ListKeys.js.map +1 -0
  191. package/lib/mjs/cli/RevokeKey.d.ts +9 -0
  192. package/lib/mjs/cli/RevokeKey.d.ts.map +1 -0
  193. package/lib/mjs/cli/RevokeKey.js +39 -0
  194. package/lib/mjs/cli/RevokeKey.js.map +1 -0
  195. package/lib/mjs/cli/common.d.ts +9 -0
  196. package/lib/mjs/cli/common.d.ts.map +1 -0
  197. package/lib/mjs/cli/common.js +30 -0
  198. package/lib/mjs/cli/common.js.map +1 -0
  199. package/lib/mjs/cli/index.d.ts +5 -0
  200. package/lib/mjs/cli/index.d.ts.map +1 -0
  201. package/lib/mjs/cli/index.js +5 -0
  202. package/lib/mjs/cli/index.js.map +1 -0
  203. package/lib/mjs/config/authn-keys.d.ts +9 -0
  204. package/lib/mjs/config/authn-keys.d.ts.map +1 -0
  205. package/lib/mjs/config/authn-keys.js +21 -0
  206. package/lib/mjs/config/authn-keys.js.map +1 -0
  207. package/lib/mjs/httpsig/base.d.ts +8 -0
  208. package/lib/mjs/httpsig/base.d.ts.map +1 -0
  209. package/lib/mjs/httpsig/base.js +67 -0
  210. package/lib/mjs/httpsig/base.js.map +1 -0
  211. package/lib/mjs/httpsig/fields.d.ts +17 -0
  212. package/lib/mjs/httpsig/fields.d.ts.map +1 -0
  213. package/lib/mjs/httpsig/fields.js +133 -0
  214. package/lib/mjs/httpsig/fields.js.map +1 -0
  215. package/lib/mjs/httpsig/index.d.ts +3 -0
  216. package/lib/mjs/httpsig/index.d.ts.map +1 -0
  217. package/lib/mjs/httpsig/index.js +3 -0
  218. package/lib/mjs/httpsig/index.js.map +1 -0
  219. package/lib/mjs/index.d.ts +13 -0
  220. package/lib/mjs/index.d.ts.map +1 -0
  221. package/lib/mjs/index.js +13 -0
  222. package/lib/mjs/index.js.map +1 -0
  223. package/lib/mjs/jwk/base64url.d.ts +7 -0
  224. package/lib/mjs/jwk/base64url.d.ts.map +1 -0
  225. package/lib/mjs/jwk/base64url.js +18 -0
  226. package/lib/mjs/jwk/base64url.js.map +1 -0
  227. package/lib/mjs/jwk/ed25519.d.ts +9 -0
  228. package/lib/mjs/jwk/ed25519.d.ts.map +1 -0
  229. package/lib/mjs/jwk/ed25519.js +42 -0
  230. package/lib/mjs/jwk/ed25519.js.map +1 -0
  231. package/lib/mjs/jwk/index.d.ts +5 -0
  232. package/lib/mjs/jwk/index.d.ts.map +1 -0
  233. package/lib/mjs/jwk/index.js +5 -0
  234. package/lib/mjs/jwk/index.js.map +1 -0
  235. package/lib/mjs/jwk/keys.d.ts +18 -0
  236. package/lib/mjs/jwk/keys.d.ts.map +1 -0
  237. package/lib/mjs/jwk/keys.js +95 -0
  238. package/lib/mjs/jwk/keys.js.map +1 -0
  239. package/lib/mjs/jwk/signature.d.ts +11 -0
  240. package/lib/mjs/jwk/signature.d.ts.map +1 -0
  241. package/lib/mjs/jwk/signature.js +39 -0
  242. package/lib/mjs/jwk/signature.js.map +1 -0
  243. package/lib/mjs/jws/index.d.ts +4 -0
  244. package/lib/mjs/jws/index.d.ts.map +1 -0
  245. package/lib/mjs/jws/index.js +4 -0
  246. package/lib/mjs/jws/index.js.map +1 -0
  247. package/lib/mjs/jws/json.d.ts +11 -0
  248. package/lib/mjs/jws/json.d.ts.map +1 -0
  249. package/lib/mjs/jws/json.js +72 -0
  250. package/lib/mjs/jws/json.js.map +1 -0
  251. package/lib/mjs/jws/signer.d.ts +25 -0
  252. package/lib/mjs/jws/signer.d.ts.map +1 -0
  253. package/lib/mjs/jws/signer.js +79 -0
  254. package/lib/mjs/jws/signer.js.map +1 -0
  255. package/lib/mjs/jws/verifier.d.ts +10 -0
  256. package/lib/mjs/jws/verifier.d.ts.map +1 -0
  257. package/lib/mjs/jws/verifier.js +83 -0
  258. package/lib/mjs/jws/verifier.js.map +1 -0
  259. package/lib/mjs/migrations/AuthnKeys_2026_10_02_00_00_00.d.ts +7 -0
  260. package/lib/mjs/migrations/AuthnKeys_2026_10_02_00_00_00.d.ts.map +1 -0
  261. package/lib/mjs/migrations/AuthnKeys_2026_10_02_00_00_00.js +37 -0
  262. package/lib/mjs/migrations/AuthnKeys_2026_10_02_00_00_00.js.map +1 -0
  263. package/lib/mjs/migrations/index.d.ts +2 -0
  264. package/lib/mjs/migrations/index.d.ts.map +1 -0
  265. package/lib/mjs/migrations/index.js +2 -0
  266. package/lib/mjs/migrations/index.js.map +1 -0
  267. package/lib/mjs/models/AuthnKey.d.ts +22 -0
  268. package/lib/mjs/models/AuthnKey.d.ts.map +1 -0
  269. package/lib/mjs/models/AuthnKey.js +40 -0
  270. package/lib/mjs/models/AuthnKey.js.map +1 -0
  271. package/lib/mjs/models/AuthnNonce.d.ts +8 -0
  272. package/lib/mjs/models/AuthnNonce.d.ts.map +1 -0
  273. package/lib/mjs/models/AuthnNonce.js +28 -0
  274. package/lib/mjs/models/AuthnNonce.js.map +1 -0
  275. package/lib/mjs/models/index.d.ts +3 -0
  276. package/lib/mjs/models/index.d.ts.map +1 -0
  277. package/lib/mjs/models/index.js +3 -0
  278. package/lib/mjs/models/index.js.map +1 -0
  279. package/lib/mjs/nonce/index.d.ts +2 -0
  280. package/lib/mjs/nonce/index.d.ts.map +1 -0
  281. package/lib/mjs/nonce/index.js +2 -0
  282. package/lib/mjs/nonce/index.js.map +1 -0
  283. package/lib/mjs/nonce/store.d.ts +22 -0
  284. package/lib/mjs/nonce/store.d.ts.map +1 -0
  285. package/lib/mjs/nonce/store.js +92 -0
  286. package/lib/mjs/nonce/store.js.map +1 -0
  287. package/lib/mjs/options/index.d.ts +2 -0
  288. package/lib/mjs/options/index.d.ts.map +1 -0
  289. package/lib/mjs/options/index.js +2 -0
  290. package/lib/mjs/options/index.js.map +1 -0
  291. package/lib/mjs/options/options.d.ts +47 -0
  292. package/lib/mjs/options/options.d.ts.map +1 -0
  293. package/lib/mjs/options/options.js +39 -0
  294. package/lib/mjs/options/options.js.map +1 -0
  295. package/lib/mjs/package.json +1 -0
  296. package/lib/mjs/register-schema.d.ts +2 -0
  297. package/lib/mjs/register-schema.d.ts.map +1 -0
  298. package/lib/mjs/register-schema.js +7 -0
  299. package/lib/mjs/register-schema.js.map +1 -0
  300. package/lib/mjs/registry/index.d.ts +4 -0
  301. package/lib/mjs/registry/index.d.ts.map +1 -0
  302. package/lib/mjs/registry/index.js +4 -0
  303. package/lib/mjs/registry/index.js.map +1 -0
  304. package/lib/mjs/registry/orm-store.d.ts +15 -0
  305. package/lib/mjs/registry/orm-store.d.ts.map +1 -0
  306. package/lib/mjs/registry/orm-store.js +106 -0
  307. package/lib/mjs/registry/orm-store.js.map +1 -0
  308. package/lib/mjs/registry/registry.d.ts +54 -0
  309. package/lib/mjs/registry/registry.d.ts.map +1 -0
  310. package/lib/mjs/registry/registry.js +239 -0
  311. package/lib/mjs/registry/registry.js.map +1 -0
  312. package/lib/mjs/registry/store.d.ts +25 -0
  313. package/lib/mjs/registry/store.d.ts.map +1 -0
  314. package/lib/mjs/registry/store.js +57 -0
  315. package/lib/mjs/registry/store.js.map +1 -0
  316. package/lib/mjs/schema.d.ts +88 -0
  317. package/lib/mjs/schema.d.ts.map +1 -0
  318. package/lib/mjs/schema.js +38 -0
  319. package/lib/mjs/schema.js.map +1 -0
  320. package/lib/mjs/strategies/assertion.d.ts +29 -0
  321. package/lib/mjs/strategies/assertion.d.ts.map +1 -0
  322. package/lib/mjs/strategies/assertion.js +115 -0
  323. package/lib/mjs/strategies/assertion.js.map +1 -0
  324. package/lib/mjs/strategies/challenge.d.ts +25 -0
  325. package/lib/mjs/strategies/challenge.d.ts.map +1 -0
  326. package/lib/mjs/strategies/challenge.js +78 -0
  327. package/lib/mjs/strategies/challenge.js.map +1 -0
  328. package/lib/mjs/strategies/httpsig.d.ts +34 -0
  329. package/lib/mjs/strategies/httpsig.d.ts.map +1 -0
  330. package/lib/mjs/strategies/httpsig.js +124 -0
  331. package/lib/mjs/strategies/httpsig.js.map +1 -0
  332. package/lib/mjs/strategies/index.d.ts +5 -0
  333. package/lib/mjs/strategies/index.d.ts.map +1 -0
  334. package/lib/mjs/strategies/index.js +5 -0
  335. package/lib/mjs/strategies/index.js.map +1 -0
  336. package/lib/mjs/strategies/keys.d.ts +43 -0
  337. package/lib/mjs/strategies/keys.d.ts.map +1 -0
  338. package/lib/mjs/strategies/keys.js +85 -0
  339. package/lib/mjs/strategies/keys.js.map +1 -0
  340. package/lib/tsconfig.cjs.tsbuildinfo +1 -0
  341. package/lib/tsconfig.mjs.tsbuildinfo +1 -0
  342. package/package.json +79 -4
package/README.md CHANGED
@@ -1,3 +1,166 @@
1
- # Temporary Holding Version
1
+ # `@spinajs/authn-keys`
2
+
3
+ Public-key authentication for SpinaJS: a key registry, strict JWS (the
4
+ canvas C8 rules), JWS client assertions, RFC 9421 HTTP signatures and a
5
+ challenge-response login.
6
+
7
+ ## Keys
8
+
9
+ - Ed25519 (`{ "kty": "OKP", "crv": "Ed25519", "x" }`, RFC 8037) and P-256
10
+ (`{ "kty": "EC", "crv": "P-256", "x", "y" }`) public JWKs only. The
11
+ algorithm comes from the key type (`EdDSA`, `ES256`), never from a token.
12
+ - Refused: private parts (`d`), other key types and curves, values that are
13
+ not strict unpadded base64url of 32 bytes, Ed25519 points that are not
14
+ canonical or have small order, P-256 points off the curve.
15
+ - `kid`: 1–64 of `[A-Za-z0-9._-]`; default: the RFC 7638 thumbprint.
16
+ - Owners: a user, a service or an agent. A user's key needs a proof of
17
+ possession (below); services and agents are registered by an admin route
18
+ or the CLI.
19
+ - Table `authn_key` (migration `AuthnKeys_2026_10_02_00_00_00`).
20
+
21
+ `DefaultKeyRegistry` implements `KeyRegistry` over a `KeyStore`
22
+ (`OrmKeyStore` by default, `MemoryKeyStore` for tests) and a `SecretStore`.
23
+ The registry and the strategies get their dependencies through DI. Tests
24
+ build them with `new`, passing the dependencies in one object, e.g.
25
+ `new DefaultKeyRegistry({ store, secrets, throttle, options })` or
26
+ `new HttpSignatureStrategy({ registry, nonces, options })`. `OrmKeyStore`
27
+ and `DbKeyNonceStore` inject the `Orm`, so the `authn:key-*` commands bring
28
+ the database up on their own.
29
+
30
+ ## Challenges
31
+
32
+ `KeyRegistry.challenge` answers `{ id, nonce, expiresAt }`. The client signs
33
+ the UTF-8 bytes of
34
+
35
+ ```
36
+ spinajs-key-<purpose>:<nonce>:<audience>
37
+ ```
38
+
39
+ where `<purpose>` is `register` (proof of possession when a user adds a
40
+ key) or `login` (challenge-response login), `<nonce>` is the `nonce`
41
+ exactly as received (base64url, so it holds no `:`), and `<audience>` is
42
+ the service's `authn.keys.challenge.audience` (default: its
43
+ `authn.keys.assertion.audience`). The client knows the audience from its
44
+ own configuration of the service, never from the challenge answer: a
45
+ service that relays another one's challenge then gets a signature the
46
+ other one refuses. It sends the raw signature as unpadded base64url:
47
+ 64 bytes for Ed25519, and for P-256 an ECDSA SHA-256 signature as
48
+ IEEE P1363 `r || s` (64 bytes, not DER). It names the challenge by its
49
+ `id`, unchanged: the id carries the nonce back to the server, so treat it
50
+ as opaque.
51
+
52
+ - Registration: `{ owner, jwk, proof: { challengeId: id, signature } }`.
53
+ - Login: credentials `{ kind: 'key-challenge', keyId, challengeId: id, signature }`.
54
+
55
+ A challenge is single use, lives `authn.keys.challenge.ttlSeconds` (default
56
+ 120 s), and is redeemed only after the signature holds. A login challenge
57
+ counts against the `login` flow's IP throttle key.
58
+
59
+ With OpenSSL 3, for an Ed25519 key in `key.pem`:
60
+
61
+ ```sh
62
+ printf 'spinajs-key-login:%s:%s' "$NONCE" "$AUDIENCE" > input.bin
63
+ openssl pkeyutl -sign -inkey key.pem -rawin -in input.bin | basenc --base64url | tr -d '=\n'
64
+ ```
65
+
66
+ From Node: `signChallenge(challenge, 'login', audience, privateKey, 'EdDSA')`.
67
+
68
+ ## JWS
69
+
70
+ `StrictJwsVerifier` implements `JwsVerifier` under the C8 D4 rules. Checks
71
+ run in this order and the first failure gives the code: `malformed`,
72
+ `bad_header` (exactly `{ alg, kid, typ }`), `unknown_key`, `bad_signature`
73
+ (with the key's own algorithm), `invalid_claims` (JSON read as serde_json
74
+ reads it; integer `iat < exp`, lifetime within the limit), `wrong_issuer`,
75
+ `wrong_audience`, `expired` (`now ≥ exp + skew`), `not_yet_valid`
76
+ (`iat > now + skew`).
77
+
78
+ `LocalJwsSigner` implements `JwsSigner` over private JWKs the app loads:
79
+ `new LocalJwsSigner(privateJwks, { current: kid })`. It writes the header
80
+ as `{"alg","kid","typ"}` and the claims in the caller's order, so the canvas
81
+ C8 golden tickets come out byte for byte.
82
+
83
+ ## JWS client assertions (`keys-jws`)
84
+
85
+ `Authorization: Bearer <jws>` → credentials `{ kind: 'jws-assertion', jws }`.
86
+
87
+ - Header: `{ "alg": "EdDSA" | "ES256", "kid": "<kid>", "typ": "spinajs-client+jwt" }`.
88
+ - Claims: `iss` is the key owner as `<type>:<id>` (`user:<uuid>`,
89
+ `service:runner-1`), `aud` is `authn.keys.assertion.audience` (required),
90
+ integer `iat` and `exp` with `exp − iat ≤ 300` (or the configured
91
+ `maxLifetimeSeconds`), and a `jti` of 1–128 characters.
92
+ - A `jti` is accepted once per key until `exp` plus the skew (`authn_nonce`
93
+ or memory).
94
+
95
+ ## HTTP signatures (`keys-httpsig`)
96
+
97
+ An RFC 9421 subset with exactly one signature:
98
+
99
+ ```
100
+ Signature-Input: sig1=("@method" "@target-uri" "content-digest");created=1790000000;expires=1790000300;nonce="<random>";keyid="<kid>"
101
+ Signature: sig1=:<standard base64 of the raw signature>:
102
+ Content-Digest: sha-256=:<standard base64 of SHA-256(body)>:
103
+ ```
104
+
105
+ - Any label; the `Signature-Input` member must be in canonical RFC 8941
106
+ form (single spaces, no parameters on components).
107
+ - Covered: `@method` and `@target-uri` always; `content-digest` whenever
108
+ the request has a body (RFC 9530, `sha-256` or `sha-512`, checked against
109
+ the body); also each name in `authn.keys.httpSignature.requiredComponents`.
110
+ `@authority`, `@path`, `@query` and present request headers may be
111
+ covered too.
112
+ - Parameters: `created`, `expires`, `nonce`, `keyid` required; `alg`
113
+ optional (`ed25519` or `ecdsa-p256-sha256`, and then it must name the
114
+ key's algorithm); nothing else.
115
+ - `expires − created ≤ maxAgeSeconds` (300), `created` not ahead of now by
116
+ more than the skew, `now < expires`; the nonce is accepted once per key.
117
+ - The signature base is RFC 9421 §2.5; its `@signature-params` line is the
118
+ `Signature-Input` member value as sent.
119
+
120
+ ## Strategies
121
+
122
+ | Name | Credentials kind | Session |
123
+ |---|---|---|
124
+ | `keys-jws` (`JwsAssertionStrategy`) | `jws-assertion` | no |
125
+ | `keys-httpsig` (`HttpSignatureStrategy`) | `http-signature` | no |
126
+ | `keys-challenge` (`KeyChallengeStrategy`) | `key-challenge` | yes |
127
+
128
+ Each refuses credentials over 8 KiB before parsing them, verifies only
129
+ usable keys (not revoked, not expired), answers an
130
+ unknown key with the same work and result as a bad signature, throttles by
131
+ `key:<kid>`, and returns the key owner as the identity with the key's
132
+ `scope` as the ceiling.
133
+
134
+ ## Configuration (`authn.keys`)
135
+
136
+ | Key | Default |
137
+ |---|---|
138
+ | `algorithms` | `['EdDSA', 'ES256']` |
139
+ | `challenge.ttlSeconds` | `120` |
140
+ | `challenge.audience` | `null` (then `assertion.audience`; challenges need one) |
141
+ | `assertion.typ` | `'spinajs-client+jwt'` |
142
+ | `assertion.audience` | `null` (required for `keys-jws`) |
143
+ | `assertion.maxLifetimeSeconds` | `300` (at most 300) |
144
+ | `assertion.skewSeconds` | `30` |
145
+ | `httpSignature.maxAgeSeconds` | `300` (at most 300) |
146
+ | `httpSignature.skewSeconds` | `30` |
147
+ | `httpSignature.requiredComponents` | `['@method', '@target-uri', 'content-digest']` |
148
+
149
+ `authn_nonce` comes with `@spinajs/authn-orm`'s `AuthnInitial` migration.
150
+
151
+ List the strategies an app uses in `authn.strategies`; `service` is the
152
+ class name:
153
+
154
+ ```ts
155
+ authn: {
156
+ strategies: [
157
+ { name: 'keys-jws', service: 'JwsAssertionStrategy' },
158
+ { name: 'keys-httpsig', service: 'HttpSignatureStrategy' },
159
+ { name: 'keys-challenge', service: 'KeyChallengeStrategy' },
160
+ ],
161
+ keys: { assertion: { audience: 'https://api.example.com' } },
162
+ }
163
+ ```
164
+
165
+ Dates in `authn_key` and `authn_nonce` are UTC instants; the process time zone does not matter.
2
166
 
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.
@@ -0,0 +1,6 @@
1
+ import { Bootstrapper } from '@spinajs/di';
2
+ /** Registers the authn.keys schema, so the configuration validates that subtree and fills its defaults. */
3
+ export declare class AuthnKeysConfigBootstrapper extends Bootstrapper {
4
+ bootstrap(): void;
5
+ }
6
+ //# sourceMappingURL=bootstrap.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"bootstrap.d.ts","sourceRoot":"","sources":["../../src/bootstrap.ts"],"names":[],"mappings":"AACA,OAAO,EAAE,YAAY,EAAc,MAAM,aAAa,CAAC;AAIvD,2GAA2G;AAC3G,qBACa,2BAA4B,SAAQ,YAAY;IACpD,SAAS,IAAI,IAAI,CAEvB;CACF"}
@@ -0,0 +1,23 @@
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.AuthnKeysConfigBootstrapper = void 0;
10
+ const configuration_1 = require("@spinajs/configuration");
11
+ const di_1 = require("@spinajs/di");
12
+ const schema_js_1 = require("./schema.js");
13
+ /** Registers the authn.keys schema, so the configuration validates that subtree and fills its defaults. */
14
+ let AuthnKeysConfigBootstrapper = class AuthnKeysConfigBootstrapper extends di_1.Bootstrapper {
15
+ bootstrap() {
16
+ (0, configuration_1.registerConfigurationSchema)(schema_js_1.AUTHN_KEYS_CONFIGURATION_SCHEMA);
17
+ }
18
+ };
19
+ exports.AuthnKeysConfigBootstrapper = AuthnKeysConfigBootstrapper;
20
+ exports.AuthnKeysConfigBootstrapper = AuthnKeysConfigBootstrapper = __decorate([
21
+ (0, di_1.Injectable)(di_1.Bootstrapper)
22
+ ], AuthnKeysConfigBootstrapper);
23
+ //# sourceMappingURL=bootstrap.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"bootstrap.js","sourceRoot":"","sources":["../../src/bootstrap.ts"],"names":[],"mappings":";;;;;;;;;AAAA,0DAAqE;AACrE,oCAAuD;AAEvD,2CAA8D;AAE9D,2GAA2G;AAEpG,IAAM,2BAA2B,GAAjC,MAAM,2BAA4B,SAAQ,iBAAY;IACpD,SAAS;QACd,IAAA,2CAA2B,EAAC,2CAA+B,CAAC,CAAC;IAC/D,CAAC;CACF,CAAA;;sCAJY,2BAA2B;IADvC,IAAA,eAAU,EAAC,iBAAY,CAAC;GACZ,2BAA2B,CAIvC"}
@@ -0,0 +1,27 @@
1
+ import type { KeyObject } from 'node:crypto';
2
+ import type { KeyAlgorithm, KeyChallenge, KeyMaterial } from '@spinajs/authn/contracts';
3
+ export type ChallengePurpose = 'register' | 'login';
4
+ /** The SecretStore purpose of one challenge; `rid` keeps it within authn_secret.purpose (varchar 32). */
5
+ export declare const challengeSecretPurpose: (rid: string) => string;
6
+ export declare const newChallengeRid: () => string;
7
+ /**
8
+ * `<rid>.<nonce>`. SecretStore keeps only a hash of the nonce and redeems by the raw value, and the credentials carry
9
+ * only the challenge id and a signature, so the id has to bring the nonce back.
10
+ */
11
+ export declare const challengeId: (rid: string, nonce: string) => string;
12
+ export declare function parseChallengeId(id: unknown): {
13
+ rid: string;
14
+ nonce: string;
15
+ } | null;
16
+ /** Nonces are base64url, so the first ':' after one ends it and the signing input has exactly one reading. */
17
+ export declare const isChallengeNonce: (nonce: unknown) => nonce is string;
18
+ /**
19
+ * The bytes a key signs to answer a challenge: UTF-8 of `spinajs-key-<purpose>:<nonce>:<audience>`. The purpose keeps
20
+ * a login signature from proving a registration; the audience is the service as the client knows it (never taken from
21
+ * the challenge answer), so a service that relays another one's challenge gets a signature the other one refuses.
22
+ */
23
+ export declare function challengeSigningInput(challenge: Pick<KeyChallenge, 'nonce'>, purpose: ChallengePurpose, audience: string): Buffer;
24
+ /** The answer a client sends: the raw signature (64 bytes; ES256 as IEEE P1363) as unpadded base64url. */
25
+ export declare function signChallenge(challenge: Pick<KeyChallenge, 'nonce'>, purpose: ChallengePurpose, audience: string, privateKey: KeyObject, alg: KeyAlgorithm): string;
26
+ export declare function verifyChallengeSignature(key: KeyMaterial, nonce: string, purpose: ChallengePurpose, audience: string, signature: unknown): boolean;
27
+ //# sourceMappingURL=challenge.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"challenge.d.ts","sourceRoot":"","sources":["../../../src/challenge/challenge.ts"],"names":[],"mappings":"AACA,OAAO,KAAK,EAAE,SAAS,EAAE,MAAM,aAAa,CAAC;AAC7C,OAAO,KAAK,EAAE,YAAY,EAAE,YAAY,EAAE,WAAW,EAAE,MAAM,0BAA0B,CAAC;AAKxF,MAAM,MAAM,gBAAgB,GAAG,UAAU,GAAG,OAAO,CAAC;AAEpD,yGAAyG;AACzG,eAAO,MAAM,sBAAsB,QAAS,MAAM,KAAG,MAAgC,CAAC;AAQtF,eAAO,MAAM,eAAe,QAAO,MAAsD,CAAC;AAE1F;;;GAGG;AACH,eAAO,MAAM,WAAW,QAAS,MAAM,SAAS,MAAM,KAAG,MAA2B,CAAC;AAErF,wBAAgB,gBAAgB,CAAC,EAAE,EAAE,OAAO,GAAG;IAAE,GAAG,EAAE,MAAM,CAAC;IAAC,KAAK,EAAE,MAAM,CAAA;CAAE,GAAG,IAAI,CAQnF;AAED,8GAA8G;AAC9G,eAAO,MAAM,gBAAgB,UAAW,OAAO,KAAG,KAAK,IAAI,MAAwD,CAAC;AAEpH;;;;GAIG;AACH,wBAAgB,qBAAqB,CAAC,SAAS,EAAE,IAAI,CAAC,YAAY,EAAE,OAAO,CAAC,EAAE,OAAO,EAAE,gBAAgB,EAAE,QAAQ,EAAE,MAAM,GAAG,MAAM,CAEjI;AAED,0GAA0G;AAC1G,wBAAgB,aAAa,CAAC,SAAS,EAAE,IAAI,CAAC,YAAY,EAAE,OAAO,CAAC,EAAE,OAAO,EAAE,gBAAgB,EAAE,QAAQ,EAAE,MAAM,EAAE,UAAU,EAAE,SAAS,EAAE,GAAG,EAAE,YAAY,GAAG,MAAM,CAEnK;AAED,wBAAgB,wBAAwB,CAAC,GAAG,EAAE,WAAW,EAAE,KAAK,EAAE,MAAM,EAAE,OAAO,EAAE,gBAAgB,EAAE,QAAQ,EAAE,MAAM,EAAE,SAAS,EAAE,OAAO,GAAG,OAAO,CAGlJ"}
@@ -0,0 +1,56 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.isChallengeNonce = exports.challengeId = exports.newChallengeRid = exports.challengeSecretPurpose = void 0;
4
+ exports.parseChallengeId = parseChallengeId;
5
+ exports.challengeSigningInput = challengeSigningInput;
6
+ exports.signChallenge = signChallenge;
7
+ exports.verifyChallengeSignature = verifyChallengeSignature;
8
+ const node_crypto_1 = require("node:crypto");
9
+ const util_1 = require("@spinajs/util");
10
+ const base64url_js_1 = require("../jwk/base64url.js");
11
+ const signature_js_1 = require("../jwk/signature.js");
12
+ /** The SecretStore purpose of one challenge; `rid` keeps it within authn_secret.purpose (varchar 32). */
13
+ const challengeSecretPurpose = (rid) => `key-challenge:${rid}`;
14
+ exports.challengeSecretPurpose = challengeSecretPurpose;
15
+ const RID_BYTES = 12;
16
+ const RID_LENGTH = 16;
17
+ const RID = /^[A-Za-z0-9_-]{16}$/;
18
+ const MAX_NONCE_LENGTH = 512;
19
+ const NONCE = /^[A-Za-z0-9_-]{22,512}$/;
20
+ const newChallengeRid = () => (0, node_crypto_1.randomBytes)(RID_BYTES).toString('base64url');
21
+ exports.newChallengeRid = newChallengeRid;
22
+ /**
23
+ * `<rid>.<nonce>`. SecretStore keeps only a hash of the nonce and redeems by the raw value, and the credentials carry
24
+ * only the challenge id and a signature, so the id has to bring the nonce back.
25
+ */
26
+ const challengeId = (rid, nonce) => `${rid}.${nonce}`;
27
+ exports.challengeId = challengeId;
28
+ function parseChallengeId(id) {
29
+ const [ok, text] = (0, util_1._try_check_arg)((0, util_1._is_string)((0, util_1._between)(RID_LENGTH + 2, RID_LENGTH + 1 + MAX_NONCE_LENGTH), (0, util_1._custom)((s) => s[RID_LENGTH] === '.')))(id, 'id');
30
+ if (!ok) {
31
+ return null;
32
+ }
33
+ const rid = text.slice(0, RID_LENGTH);
34
+ const nonce = text.slice(RID_LENGTH + 1);
35
+ return RID.test(rid) && (0, exports.isChallengeNonce)(nonce) ? { rid, nonce } : null;
36
+ }
37
+ /** Nonces are base64url, so the first ':' after one ends it and the signing input has exactly one reading. */
38
+ const isChallengeNonce = (nonce) => typeof nonce === 'string' && NONCE.test(nonce);
39
+ exports.isChallengeNonce = isChallengeNonce;
40
+ /**
41
+ * The bytes a key signs to answer a challenge: UTF-8 of `spinajs-key-<purpose>:<nonce>:<audience>`. The purpose keeps
42
+ * a login signature from proving a registration; the audience is the service as the client knows it (never taken from
43
+ * the challenge answer), so a service that relays another one's challenge gets a signature the other one refuses.
44
+ */
45
+ function challengeSigningInput(challenge, purpose, audience) {
46
+ return Buffer.from(`spinajs-key-${purpose}:${challenge.nonce}:${audience}`, 'utf8');
47
+ }
48
+ /** The answer a client sends: the raw signature (64 bytes; ES256 as IEEE P1363) as unpadded base64url. */
49
+ function signChallenge(challenge, purpose, audience, privateKey, alg) {
50
+ return (0, base64url_js_1.encodeB64url)((0, signature_js_1.signRaw)(alg, privateKey, challengeSigningInput(challenge, purpose, audience)));
51
+ }
52
+ function verifyChallengeSignature(key, nonce, purpose, audience, signature) {
53
+ const raw = (0, base64url_js_1.decodeB64url)(signature);
54
+ return raw !== null && (0, exports.isChallengeNonce)(nonce) && (0, signature_js_1.verifySignature)(key, challengeSigningInput({ nonce }, purpose, audience), raw);
55
+ }
56
+ //# sourceMappingURL=challenge.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"challenge.js","sourceRoot":"","sources":["../../../src/challenge/challenge.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,2 @@
1
+ export * from './challenge.js';
2
+ //# sourceMappingURL=index.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../src/challenge/index.ts"],"names":[],"mappings":"AAAA,cAAc,gBAAgB,CAAC"}
@@ -0,0 +1,18 @@
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("./challenge.js"), exports);
18
+ //# sourceMappingURL=index.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.js","sourceRoot":"","sources":["../../../src/challenge/index.ts"],"names":[],"mappings":";;;;;;;;;;;;;;;;AAAA,iDAA+B"}
@@ -0,0 +1,18 @@
1
+ import { CliCommand } from '@spinajs/cli';
2
+ import { Log } from '@spinajs/log';
3
+ import { KeyRegistry } from '@spinajs/authn/contracts';
4
+ interface AddKeyOptions {
5
+ jwk?: string;
6
+ file?: string;
7
+ kid?: string;
8
+ name?: string;
9
+ expires?: string;
10
+ }
11
+ /** Services and agents only: a user registers a key with a proof of possession, which the CLI cannot give. */
12
+ export declare class AddKey extends CliCommand {
13
+ protected Log: Log;
14
+ protected Registry: KeyRegistry;
15
+ execute(ownerType: string, ownerId: string, options: AddKeyOptions): Promise<void>;
16
+ }
17
+ export {};
18
+ //# sourceMappingURL=AddKey.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"AddKey.d.ts","sourceRoot":"","sources":["../../../src/cli/AddKey.ts"],"names":[],"mappings":"AACA,OAAO,EAAY,UAAU,EAAmB,MAAM,cAAc,CAAC;AACrE,OAAO,EAAE,GAAG,EAAU,MAAM,cAAc,CAAC;AAC3C,OAAO,EAAa,WAAW,EAAc,MAAM,0BAA0B,CAAC;AAK9E,UAAU,aAAa;IACrB,GAAG,CAAC,EAAE,MAAM,CAAC;IACb,IAAI,CAAC,EAAE,MAAM,CAAC;IACd,GAAG,CAAC,EAAE,MAAM,CAAC;IACb,IAAI,CAAC,EAAE,MAAM,CAAC;IACd,OAAO,CAAC,EAAE,MAAM,CAAC;CAClB;AAED,8GAA8G;AAC9G,qBAQa,MAAO,SAAQ,UAAU;IAEpC,SAAS,CAAC,GAAG,EAAE,GAAG,CAAC;IAGnB,SAAS,CAAC,QAAQ,EAAE,WAAW,CAAC;IAEnB,OAAO,CAAC,SAAS,EAAE,MAAM,EAAE,OAAO,EAAE,MAAM,EAAE,OAAO,EAAE,aAAa,GAAG,OAAO,CAAC,IAAI,CAAC,CAuB9F;CACF"}
@@ -0,0 +1,65 @@
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.AddKey = void 0;
13
+ const di_1 = require("@spinajs/di");
14
+ const cli_1 = require("@spinajs/cli");
15
+ const log_1 = require("@spinajs/log");
16
+ const contracts_1 = require("@spinajs/authn/contracts");
17
+ const exceptions_1 = require("@spinajs/exceptions");
18
+ const common_js_1 = require("./common.js");
19
+ /** Services and agents only: a user registers a key with a proof of possession, which the CLI cannot give. */
20
+ let AddKey = class AddKey extends cli_1.CliCommand {
21
+ async execute(ownerType, ownerId, options) {
22
+ const owner = (0, common_js_1.ownerArg)(ownerType, ownerId);
23
+ if (owner.type === 'user') {
24
+ throw new exceptions_1.InvalidArgument('a user registers a key with a proof of possession, through POST /user/keys');
25
+ }
26
+ const expiresAt = options.expires === undefined ? undefined : new Date(options.expires);
27
+ // Without a zone, Date reads the time as local, which differs per host.
28
+ if (expiresAt !== undefined && (Number.isNaN(expiresAt.getTime()) || !/T.*(Z|[+-]\d{2}:?\d{2})$/i.test(options.expires))) {
29
+ throw new exceptions_1.InvalidArgument(`--expires is not an ISO 8601 instant with Z or an offset: ${options.expires}`);
30
+ }
31
+ const reg = {
32
+ owner,
33
+ actor: contracts_1.CLI_ACTOR,
34
+ jwk: (0, common_js_1.readPublicJwk)(options),
35
+ ...(options.kid !== undefined ? { kid: options.kid } : {}),
36
+ ...(options.name !== undefined ? { name: options.name } : {}),
37
+ ...(expiresAt ? { expiresAt } : {}),
38
+ };
39
+ const r = await this.Registry.register(reg, (0, contracts_1.cliContext)());
40
+ if (!r.ok) {
41
+ throw new exceptions_1.InvalidArgument(`key not registered: ${r.code}`);
42
+ }
43
+ this.Log.success({ kid: r.key.kid, alg: r.key.alg, thumbprint: r.key.thumbprint }, 'Key registered: kid ${kid}, ${alg}, thumbprint ${thumbprint}');
44
+ }
45
+ };
46
+ exports.AddKey = AddKey;
47
+ __decorate([
48
+ (0, log_1.Logger)('authn-keys'),
49
+ __metadata("design:type", log_1.Log)
50
+ ], AddKey.prototype, "Log", void 0);
51
+ __decorate([
52
+ (0, di_1.Autoinject)(contracts_1.KeyRegistry),
53
+ __metadata("design:type", contracts_1.KeyRegistry)
54
+ ], AddKey.prototype, "Registry", void 0);
55
+ exports.AddKey = AddKey = __decorate([
56
+ (0, cli_1.Command)('authn:key-add', 'Registers an Ed25519 or P-256 public key for a service or an agent'),
57
+ (0, cli_1.Argument)({ name: 'ownerType', required: true, description: 'service or agent', choices: ['service', 'agent'] }),
58
+ (0, cli_1.Argument)('ownerId', true, 'id of the service or agent'),
59
+ (0, cli_1.Option)('--jwk <json>', false, 'the public JWK as JSON'),
60
+ (0, cli_1.Option)('--file <path>', false, 'a file with the public JWK (JSON) or a PEM public key'),
61
+ (0, cli_1.Option)('--kid <kid>', false, 'key id, 1-64 of [A-Za-z0-9._-]; default: the RFC 7638 thumbprint'),
62
+ (0, cli_1.Option)('--name <name>', false, 'label, up to 128 characters'),
63
+ (0, cli_1.Option)('--expires <iso>', false, 'ISO 8601 expiry instant with Z or an offset')
64
+ ], AddKey);
65
+ //# sourceMappingURL=AddKey.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"AddKey.js","sourceRoot":"","sources":["../../../src/cli/AddKey.ts"],"names":[],"mappings":";;;;;;;;;;;;AAAA,oCAAyC;AACzC,sCAAqE;AACrE,sCAA2C;AAC3C,wDAA8E;AAE9E,oDAAsD;AACtD,2CAAsD;AAUtD,8GAA8G;AASvG,IAAM,MAAM,GAAZ,MAAM,MAAO,SAAQ,gBAAU;IAO7B,KAAK,CAAC,OAAO,CAAC,SAAiB,EAAE,OAAe,EAAE,OAAsB;QAC7E,MAAM,KAAK,GAAG,IAAA,oBAAQ,EAAC,SAAS,EAAE,OAAO,CAAC,CAAC;QAC3C,IAAI,KAAK,CAAC,IAAI,KAAK,MAAM,EAAE,CAAC;YAC1B,MAAM,IAAI,4BAAe,CAAC,4EAA4E,CAAC,CAAC;QAC1G,CAAC;QACD,MAAM,SAAS,GAAG,OAAO,CAAC,OAAO,KAAK,SAAS,CAAC,CAAC,CAAC,SAAS,CAAC,CAAC,CAAC,IAAI,IAAI,CAAC,OAAO,CAAC,OAAO,CAAC,CAAC;QACxF,wEAAwE;QACxE,IAAI,SAAS,KAAK,SAAS,IAAI,CAAC,MAAM,CAAC,KAAK,CAAC,SAAS,CAAC,OAAO,EAAE,CAAC,IAAI,CAAC,2BAA2B,CAAC,IAAI,CAAC,OAAO,CAAC,OAAQ,CAAC,CAAC,EAAE,CAAC;YAC1H,MAAM,IAAI,4BAAe,CAAC,6DAA6D,OAAO,CAAC,OAAO,EAAE,CAAC,CAAC;QAC5G,CAAC;QACD,MAAM,GAAG,GAAG;YACV,KAAK;YACL,KAAK,EAAE,qBAAS;YAChB,GAAG,EAAE,IAAA,yBAAa,EAAC,OAAO,CAAC;YAC3B,GAAG,CAAC,OAAO,CAAC,GAAG,KAAK,SAAS,CAAC,CAAC,CAAC,EAAE,GAAG,EAAE,OAAO,CAAC,GAAG,EAAE,CAAC,CAAC,CAAC,EAAE,CAAC;YAC1D,GAAG,CAAC,OAAO,CAAC,IAAI,KAAK,SAAS,CAAC,CAAC,CAAC,EAAE,IAAI,EAAE,OAAO,CAAC,IAAI,EAAE,CAAC,CAAC,CAAC,EAAE,CAAC;YAC7D,GAAG,CAAC,SAAS,CAAC,CAAC,CAAC,EAAE,SAAS,EAAE,CAAC,CAAC,CAAC,EAAE,CAAC;SACjB,CAAC;QACrB,MAAM,CAAC,GAAG,MAAM,IAAI,CAAC,QAAQ,CAAC,QAAQ,CAAC,GAAG,EAAE,IAAA,sBAAU,GAAE,CAAC,CAAC;QAC1D,IAAI,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC;YACV,MAAM,IAAI,4BAAe,CAAC,uBAAuB,CAAC,CAAC,IAAI,EAAE,CAAC,CAAC;QAC7D,CAAC;QACD,IAAI,CAAC,GAAG,CAAC,OAAO,CAAC,EAAE,GAAG,EAAE,CAAC,CAAC,GAAG,CAAC,GAAG,EAAE,GAAG,EAAE,CAAC,CAAC,GAAG,CAAC,GAAG,EAAE,UAAU,EAAE,CAAC,CAAC,GAAG,CAAC,UAAU,EAAE,EAAE,8DAA8D,CAAC,CAAC;IACrJ,CAAC;CACF,CAAA;;AA7BW;IADT,IAAA,YAAM,EAAC,YAAY,CAAC;8BACN,SAAG;mCAAC;AAGT;IADT,IAAA,eAAU,EAAC,uBAAW,CAAC;8BACJ,uBAAW;wCAAC;iBALrB,MAAM;IARlB,IAAA,aAAO,EAAC,eAAe,EAAE,oEAAoE,CAAC;IAC9F,IAAA,cAAQ,EAAC,EAAE,IAAI,EAAE,WAAW,EAAE,QAAQ,EAAE,IAAI,EAAE,WAAW,EAAE,kBAAkB,EAAE,OAAO,EAAE,CAAC,SAAS,EAAE,OAAO,CAAC,EAAE,CAAC;IAC/G,IAAA,cAAQ,EAAC,SAAS,EAAE,IAAI,EAAE,4BAA4B,CAAC;IACvD,IAAA,YAAM,EAAC,cAAc,EAAE,KAAK,EAAE,wBAAwB,CAAC;IACvD,IAAA,YAAM,EAAC,eAAe,EAAE,KAAK,EAAE,uDAAuD,CAAC;IACvF,IAAA,YAAM,EAAC,aAAa,EAAE,KAAK,EAAE,kEAAkE,CAAC;IAChG,IAAA,YAAM,EAAC,eAAe,EAAE,KAAK,EAAE,6BAA6B,CAAC;IAC7D,IAAA,YAAM,EAAC,iBAAiB,EAAE,KAAK,EAAE,6CAA6C,CAAC;GACnE,MAAM,CA+BlB"}
@@ -0,0 +1,11 @@
1
+ import { CliCommand } from '@spinajs/cli';
2
+ import { Log } from '@spinajs/log';
3
+ import { KeyRegistry } from '@spinajs/authn/contracts';
4
+ import type { KeyRecord } from '@spinajs/authn/contracts';
5
+ export declare function keyLine(k: KeyRecord): string;
6
+ export declare class ListKeys extends CliCommand {
7
+ protected Log: Log;
8
+ protected Registry: KeyRegistry;
9
+ execute(ownerType: string, ownerId: string): Promise<void>;
10
+ }
11
+ //# sourceMappingURL=ListKeys.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"ListKeys.d.ts","sourceRoot":"","sources":["../../../src/cli/ListKeys.ts"],"names":[],"mappings":"AACA,OAAO,EAAY,UAAU,EAAW,MAAM,cAAc,CAAC;AAC7D,OAAO,EAAE,GAAG,EAAU,MAAM,cAAc,CAAC;AAC3C,OAAO,EAAE,WAAW,EAAE,MAAM,0BAA0B,CAAC;AACvD,OAAO,KAAK,EAAE,SAAS,EAAE,MAAM,0BAA0B,CAAC;AAK1D,wBAAgB,OAAO,CAAC,CAAC,EAAE,SAAS,GAAG,MAAM,CAE5C;AAED,qBAGa,QAAS,SAAQ,UAAU;IAEtC,SAAS,CAAC,GAAG,EAAE,GAAG,CAAC;IAGnB,SAAS,CAAC,QAAQ,EAAE,WAAW,CAAC;IAEnB,OAAO,CAAC,SAAS,EAAE,MAAM,EAAE,OAAO,EAAE,MAAM,GAAG,OAAO,CAAC,IAAI,CAAC,CAQtE;CACF"}
@@ -0,0 +1,48 @@
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.ListKeys = void 0;
13
+ exports.keyLine = keyLine;
14
+ const di_1 = require("@spinajs/di");
15
+ const cli_1 = require("@spinajs/cli");
16
+ const log_1 = require("@spinajs/log");
17
+ const contracts_1 = require("@spinajs/authn/contracts");
18
+ const common_js_1 = require("./common.js");
19
+ const iso = (d) => (d ? d.toISOString() : '-');
20
+ function keyLine(k) {
21
+ return [k.kid, k.alg, k.name ?? '-', `created ${iso(k.createdAt)}`, `expires ${iso(k.expiresAt)}`, `revoked ${iso(k.revokedAt)}`, `last used ${iso(k.lastUsedAt)}`].join(' ');
22
+ }
23
+ let ListKeys = class ListKeys extends cli_1.CliCommand {
24
+ async execute(ownerType, ownerId) {
25
+ const keys = await this.Registry.list((0, common_js_1.ownerArg)(ownerType, ownerId));
26
+ if (keys.length === 0) {
27
+ this.Log.info('No keys');
28
+ }
29
+ for (const k of keys) {
30
+ this.Log.info(keyLine(k));
31
+ }
32
+ }
33
+ };
34
+ exports.ListKeys = ListKeys;
35
+ __decorate([
36
+ (0, log_1.Logger)('authn-keys'),
37
+ __metadata("design:type", log_1.Log)
38
+ ], ListKeys.prototype, "Log", void 0);
39
+ __decorate([
40
+ (0, di_1.Autoinject)(contracts_1.KeyRegistry),
41
+ __metadata("design:type", contracts_1.KeyRegistry)
42
+ ], ListKeys.prototype, "Registry", void 0);
43
+ exports.ListKeys = ListKeys = __decorate([
44
+ (0, cli_1.Command)('authn:key-list', 'Lists the public keys of a user, a service or an agent, revoked and expired ones included'),
45
+ (0, cli_1.Argument)({ name: 'ownerType', required: true, description: common_js_1.OWNER_TYPES.join(', '), choices: common_js_1.OWNER_TYPES }),
46
+ (0, cli_1.Argument)('ownerId', true, 'id of the owner (users.Uuid for users)')
47
+ ], ListKeys);
48
+ //# sourceMappingURL=ListKeys.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"ListKeys.js","sourceRoot":"","sources":["../../../src/cli/ListKeys.ts"],"names":[],"mappings":";;;;;;;;;;;;;AAAA,oCAAyC;AACzC,sCAA6D;AAC7D,sCAA2C;AAC3C,wDAAuD;AAEvD,2CAAoD;AAEpD,MAAM,GAAG,GAAG,CAAC,CAAQ,EAAU,EAAE,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,WAAW,EAAE,CAAC,CAAC,CAAC,GAAG,CAAC,CAAC;AAE9D,iBAAwB,CAAY;IAClC,OAAO,CAAC,CAAC,CAAC,GAAG,EAAE,CAAC,CAAC,GAAG,EAAE,CAAC,CAAC,IAAI,IAAI,GAAG,EAAE,WAAW,GAAG,CAAC,CAAC,CAAC,SAAS,CAAC,EAAE,EAAE,WAAW,GAAG,CAAC,CAAC,CAAC,SAAS,CAAC,EAAE,EAAE,WAAW,GAAG,CAAC,CAAC,CAAC,SAAS,CAAC,EAAE,EAAE,aAAa,GAAG,CAAC,CAAC,CAAC,UAAU,CAAC,EAAE,CAAC,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC;AACjL,CAAC;AAKM,IAAM,QAAQ,GAAd,MAAM,QAAS,SAAQ,gBAAU;IAO/B,KAAK,CAAC,OAAO,CAAC,SAAiB,EAAE,OAAe;QACrD,MAAM,IAAI,GAAG,MAAM,IAAI,CAAC,QAAQ,CAAC,IAAI,CAAC,IAAA,oBAAQ,EAAC,SAAS,EAAE,OAAO,CAAC,CAAC,CAAC;QACpE,IAAI,IAAI,CAAC,MAAM,KAAK,CAAC,EAAE,CAAC;YACtB,IAAI,CAAC,GAAG,CAAC,IAAI,CAAC,SAAS,CAAC,CAAC;QAC3B,CAAC;QACD,KAAK,MAAM,CAAC,IAAI,IAAI,EAAE,CAAC;YACrB,IAAI,CAAC,GAAG,CAAC,IAAI,CAAC,OAAO,CAAC,CAAC,CAAC,CAAC,CAAC;QAC5B,CAAC;IACH,CAAC;CACF,CAAA;;AAdW;IADT,IAAA,YAAM,EAAC,YAAY,CAAC;8BACN,SAAG;qCAAC;AAGT;IADT,IAAA,eAAU,EAAC,uBAAW,CAAC;8BACJ,uBAAW;0CAAC;mBALrB,QAAQ;IAHpB,IAAA,aAAO,EAAC,gBAAgB,EAAE,2FAA2F,CAAC;IACtH,IAAA,cAAQ,EAAC,EAAE,IAAI,EAAE,WAAW,EAAE,QAAQ,EAAE,IAAI,EAAE,WAAW,EAAE,uBAAW,CAAC,IAAI,CAAC,IAAI,CAAC,EAAE,OAAO,EAAE,uBAAW,EAAE,CAAC;IAC1G,IAAA,cAAQ,EAAC,SAAS,EAAE,IAAI,EAAE,wCAAwC,CAAC;GACvD,QAAQ,CAgBpB"}
@@ -0,0 +1,9 @@
1
+ import { CliCommand } from '@spinajs/cli';
2
+ import { Log } from '@spinajs/log';
3
+ import { KeyRegistry } from '@spinajs/authn/contracts';
4
+ export declare class RevokeKey extends CliCommand {
5
+ protected Log: Log;
6
+ protected Registry: KeyRegistry;
7
+ execute(ownerType: string, ownerId: string, kid: string): Promise<void>;
8
+ }
9
+ //# sourceMappingURL=RevokeKey.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"RevokeKey.d.ts","sourceRoot":"","sources":["../../../src/cli/RevokeKey.ts"],"names":[],"mappings":"AACA,OAAO,EAAY,UAAU,EAAW,MAAM,cAAc,CAAC;AAC7D,OAAO,EAAE,GAAG,EAAU,MAAM,cAAc,CAAC;AAC3C,OAAO,EAAa,WAAW,EAAc,MAAM,0BAA0B,CAAC;AAI9E,qBAIa,SAAU,SAAQ,UAAU;IAEvC,SAAS,CAAC,GAAG,EAAE,GAAG,CAAC;IAGnB,SAAS,CAAC,QAAQ,EAAE,WAAW,CAAC;IAEnB,OAAO,CAAC,SAAS,EAAE,MAAM,EAAE,OAAO,EAAE,MAAM,EAAE,GAAG,EAAE,MAAM,GAAG,OAAO,CAAC,IAAI,CAAC,CAKnF;CACF"}
@@ -0,0 +1,42 @@
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.RevokeKey = void 0;
13
+ const di_1 = require("@spinajs/di");
14
+ const cli_1 = require("@spinajs/cli");
15
+ const log_1 = require("@spinajs/log");
16
+ const contracts_1 = require("@spinajs/authn/contracts");
17
+ const exceptions_1 = require("@spinajs/exceptions");
18
+ const common_js_1 = require("./common.js");
19
+ let RevokeKey = class RevokeKey extends cli_1.CliCommand {
20
+ async execute(ownerType, ownerId, kid) {
21
+ if (!(await this.Registry.revoke((0, common_js_1.ownerArg)(ownerType, ownerId), kid, (0, contracts_1.cliContext)(), { actor: contracts_1.CLI_ACTOR }))) {
22
+ throw new exceptions_1.InvalidArgument(`no key ${kid} of ${ownerType} ${ownerId}`);
23
+ }
24
+ this.Log.success({ kid }, 'Key ${kid} revoked');
25
+ }
26
+ };
27
+ exports.RevokeKey = RevokeKey;
28
+ __decorate([
29
+ (0, log_1.Logger)('authn-keys'),
30
+ __metadata("design:type", log_1.Log)
31
+ ], RevokeKey.prototype, "Log", void 0);
32
+ __decorate([
33
+ (0, di_1.Autoinject)(contracts_1.KeyRegistry),
34
+ __metadata("design:type", contracts_1.KeyRegistry)
35
+ ], RevokeKey.prototype, "Registry", void 0);
36
+ exports.RevokeKey = RevokeKey = __decorate([
37
+ (0, cli_1.Command)('authn:key-revoke', 'Revokes a public key; it fails on the next request'),
38
+ (0, cli_1.Argument)({ name: 'ownerType', required: true, description: common_js_1.OWNER_TYPES.join(', '), choices: common_js_1.OWNER_TYPES }),
39
+ (0, cli_1.Argument)('ownerId', true, 'id of the owner (users.Uuid for users)'),
40
+ (0, cli_1.Argument)('kid', true, 'key id')
41
+ ], RevokeKey);
42
+ //# sourceMappingURL=RevokeKey.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"RevokeKey.js","sourceRoot":"","sources":["../../../src/cli/RevokeKey.ts"],"names":[],"mappings":";;;;;;;;;;;;AAAA,oCAAyC;AACzC,sCAA6D;AAC7D,sCAA2C;AAC3C,wDAA8E;AAC9E,oDAAsD;AACtD,2CAAoD;AAM7C,IAAM,SAAS,GAAf,MAAM,SAAU,SAAQ,gBAAU;IAOhC,KAAK,CAAC,OAAO,CAAC,SAAiB,EAAE,OAAe,EAAE,GAAW;QAClE,IAAI,CAAC,CAAC,MAAM,IAAI,CAAC,QAAQ,CAAC,MAAM,CAAC,IAAA,oBAAQ,EAAC,SAAS,EAAE,OAAO,CAAC,EAAE,GAAG,EAAE,IAAA,sBAAU,GAAE,EAAE,EAAE,KAAK,EAAE,qBAAS,EAAE,CAAC,CAAC,EAAE,CAAC;YACzG,MAAM,IAAI,4BAAe,CAAC,UAAU,GAAG,OAAO,SAAS,IAAI,OAAO,EAAE,CAAC,CAAC;QACxE,CAAC;QACD,IAAI,CAAC,GAAG,CAAC,OAAO,CAAC,EAAE,GAAG,EAAE,EAAE,oBAAoB,CAAC,CAAC;IAClD,CAAC;CACF,CAAA;;AAXW;IADT,IAAA,YAAM,EAAC,YAAY,CAAC;8BACN,SAAG;sCAAC;AAGT;IADT,IAAA,eAAU,EAAC,uBAAW,CAAC;8BACJ,uBAAW;2CAAC;oBALrB,SAAS;IAJrB,IAAA,aAAO,EAAC,kBAAkB,EAAE,oDAAoD,CAAC;IACjF,IAAA,cAAQ,EAAC,EAAE,IAAI,EAAE,WAAW,EAAE,QAAQ,EAAE,IAAI,EAAE,WAAW,EAAE,uBAAW,CAAC,IAAI,CAAC,IAAI,CAAC,EAAE,OAAO,EAAE,uBAAW,EAAE,CAAC;IAC1G,IAAA,cAAQ,EAAC,SAAS,EAAE,IAAI,EAAE,wCAAwC,CAAC;IACnE,IAAA,cAAQ,EAAC,KAAK,EAAE,IAAI,EAAE,QAAQ,CAAC;GACnB,SAAS,CAarB"}
@@ -0,0 +1,9 @@
1
+ import type { IdentityRef } from '@spinajs/authn/contracts';
2
+ export declare const OWNER_TYPES: string[];
3
+ export declare function ownerArg(type: string, id: string): IdentityRef;
4
+ /** A public JWK given inline as JSON, or a file holding JSON or a PEM public key; private keys are refused. */
5
+ export declare function readPublicJwk(opts: {
6
+ jwk?: string;
7
+ file?: string;
8
+ }): unknown;
9
+ //# sourceMappingURL=common.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"common.d.ts","sourceRoot":"","sources":["../../../src/cli/common.ts"],"names":[],"mappings":"AAEA,OAAO,KAAK,EAAE,WAAW,EAAE,MAAM,0BAA0B,CAAC;AAG5D,eAAO,MAAM,WAAW,UAA+B,CAAC;AAExD,wBAAgB,QAAQ,CAAC,IAAI,EAAE,MAAM,EAAE,EAAE,EAAE,MAAM,GAAG,WAAW,CAK9D;AAED,+GAA+G;AAC/G,wBAAgB,aAAa,CAAC,IAAI,EAAE;IAAE,GAAG,CAAC,EAAE,MAAM,CAAC;IAAC,IAAI,CAAC,EAAE,MAAM,CAAA;CAAE,GAAG,OAAO,CAgB5E"}
@@ -0,0 +1,35 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.OWNER_TYPES = void 0;
4
+ exports.ownerArg = ownerArg;
5
+ exports.readPublicJwk = readPublicJwk;
6
+ const node_fs_1 = require("node:fs");
7
+ const node_crypto_1 = require("node:crypto");
8
+ const exceptions_1 = require("@spinajs/exceptions");
9
+ exports.OWNER_TYPES = ['user', 'service', 'agent'];
10
+ function ownerArg(type, id) {
11
+ if (!exports.OWNER_TYPES.includes(type)) {
12
+ throw new exceptions_1.InvalidArgument(`owner type must be one of ${exports.OWNER_TYPES.join(', ')}, not ${JSON.stringify(type)}`);
13
+ }
14
+ return { type, id };
15
+ }
16
+ /** A public JWK given inline as JSON, or a file holding JSON or a PEM public key; private keys are refused. */
17
+ function readPublicJwk(opts) {
18
+ if ((opts.jwk === undefined) === (opts.file === undefined)) {
19
+ throw new exceptions_1.InvalidArgument('give the key with exactly one of --jwk or --file');
20
+ }
21
+ const text = opts.jwk ?? (0, node_fs_1.readFileSync)(opts.file, 'utf8');
22
+ if (text.includes('-----BEGIN')) {
23
+ if (!text.includes('-----BEGIN PUBLIC KEY-----') || text.includes('PRIVATE KEY')) {
24
+ throw new exceptions_1.InvalidArgument('the PEM file must hold a public key (SPKI), never a private key');
25
+ }
26
+ return (0, node_crypto_1.createPublicKey)(text).export({ format: 'jwk' });
27
+ }
28
+ try {
29
+ return JSON.parse(text);
30
+ }
31
+ catch {
32
+ throw new exceptions_1.InvalidArgument('the key is neither JSON nor a PEM public key');
33
+ }
34
+ }
35
+ //# sourceMappingURL=common.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"common.js","sourceRoot":"","sources":["../../../src/cli/common.ts"],"names":[],"mappings":";;;;;AAAA,qCAAuC;AACvC,6CAA8C;AAE9C,oDAAsD;AAEzC,QAAA,WAAW,GAAG,CAAC,MAAM,EAAE,SAAS,EAAE,OAAO,CAAC,CAAC;AAExD,kBAAyB,IAAY,EAAE,EAAU;IAC/C,IAAI,CAAC,QAAA,WAAW,CAAC,QAAQ,CAAC,IAAI,CAAC,EAAE,CAAC;QAChC,MAAM,IAAI,4BAAe,CAAC,6BAA6B,QAAA,WAAW,CAAC,IAAI,CAAC,IAAI,CAAC,SAAS,IAAI,CAAC,SAAS,CAAC,IAAI,CAAC,EAAE,CAAC,CAAC;IAChH,CAAC;IACD,OAAO,EAAE,IAAI,EAAE,EAAE,EAAE,CAAC;AACtB,CAAC;AAED,+GAA+G;AAC/G,uBAA8B,IAAqC;IACjE,IAAI,CAAC,IAAI,CAAC,GAAG,KAAK,SAAS,CAAC,KAAK,CAAC,IAAI,CAAC,IAAI,KAAK,SAAS,CAAC,EAAE,CAAC;QAC3D,MAAM,IAAI,4BAAe,CAAC,kDAAkD,CAAC,CAAC;IAChF,CAAC;IACD,MAAM,IAAI,GAAG,IAAI,CAAC,GAAG,IAAI,IAAA,sBAAY,EAAC,IAAI,CAAC,IAAK,EAAE,MAAM,CAAC,CAAC;IAC1D,IAAI,IAAI,CAAC,QAAQ,CAAC,YAAY,CAAC,EAAE,CAAC;QAChC,IAAI,CAAC,IAAI,CAAC,QAAQ,CAAC,4BAA4B,CAAC,IAAI,IAAI,CAAC,QAAQ,CAAC,aAAa,CAAC,EAAE,CAAC;YACjF,MAAM,IAAI,4BAAe,CAAC,iEAAiE,CAAC,CAAC;QAC/F,CAAC;QACD,OAAO,IAAA,6BAAe,EAAC,IAAI,CAAC,CAAC,MAAM,CAAC,EAAE,MAAM,EAAE,KAAK,EAAE,CAAC,CAAC;IACzD,CAAC;IACD,IAAI,CAAC;QACH,OAAO,IAAI,CAAC,KAAK,CAAC,IAAI,CAAY,CAAC;IACrC,CAAC;IAAC,MAAM,CAAC;QACP,MAAM,IAAI,4BAAe,CAAC,8CAA8C,CAAC,CAAC;IAC5E,CAAC;AACH,CAAC"}
@@ -0,0 +1,5 @@
1
+ export * from './common.js';
2
+ export * from './AddKey.js';
3
+ export * from './ListKeys.js';
4
+ export * from './RevokeKey.js';
5
+ //# sourceMappingURL=index.d.ts.map