was-teaching-server 0.9.1

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 (295) hide show
  1. package/CHANGELOG.md +1432 -0
  2. package/LICENSE +661 -0
  3. package/README.md +305 -0
  4. package/common/css/materialize.1.0.0.min.css +13 -0
  5. package/dist/auth-header-hooks.d.ts +84 -0
  6. package/dist/auth-header-hooks.d.ts.map +1 -0
  7. package/dist/auth-header-hooks.js +136 -0
  8. package/dist/auth-header-hooks.js.map +1 -0
  9. package/dist/authorize.d.ts +45 -0
  10. package/dist/authorize.d.ts.map +1 -0
  11. package/dist/authorize.js +76 -0
  12. package/dist/authorize.js.map +1 -0
  13. package/dist/backends/filesystem.d.ts +1179 -0
  14. package/dist/backends/filesystem.d.ts.map +1 -0
  15. package/dist/backends/filesystem.js +2727 -0
  16. package/dist/backends/filesystem.js.map +1 -0
  17. package/dist/backends/postgres.d.ts +833 -0
  18. package/dist/backends/postgres.d.ts.map +1 -0
  19. package/dist/backends/postgres.js +2164 -0
  20. package/dist/backends/postgres.js.map +1 -0
  21. package/dist/backends/postgresSchema.d.ts +36 -0
  22. package/dist/backends/postgresSchema.d.ts.map +1 -0
  23. package/dist/backends/postgresSchema.js +203 -0
  24. package/dist/backends/postgresSchema.js.map +1 -0
  25. package/dist/config.default.d.ts +360 -0
  26. package/dist/config.default.d.ts.map +1 -0
  27. package/dist/config.default.js +493 -0
  28. package/dist/config.default.js.map +1 -0
  29. package/dist/corsProxy.d.ts +45 -0
  30. package/dist/corsProxy.d.ts.map +1 -0
  31. package/dist/corsProxy.js +278 -0
  32. package/dist/corsProxy.js.map +1 -0
  33. package/dist/digest.d.ts +45 -0
  34. package/dist/digest.d.ts.map +1 -0
  35. package/dist/digest.js +174 -0
  36. package/dist/digest.js.map +1 -0
  37. package/dist/errors.d.ts +654 -0
  38. package/dist/errors.d.ts.map +1 -0
  39. package/dist/errors.js +960 -0
  40. package/dist/errors.js.map +1 -0
  41. package/dist/index.d.ts +22 -0
  42. package/dist/index.d.ts.map +1 -0
  43. package/dist/index.js +21 -0
  44. package/dist/index.js.map +1 -0
  45. package/dist/lib/atomicFile.d.ts +61 -0
  46. package/dist/lib/atomicFile.d.ts.map +1 -0
  47. package/dist/lib/atomicFile.js +150 -0
  48. package/dist/lib/atomicFile.js.map +1 -0
  49. package/dist/lib/backendRegistry.d.ts +59 -0
  50. package/dist/lib/backendRegistry.d.ts.map +1 -0
  51. package/dist/lib/backendRegistry.js +92 -0
  52. package/dist/lib/backendRegistry.js.map +1 -0
  53. package/dist/lib/backendUsage.d.ts +28 -0
  54. package/dist/lib/backendUsage.d.ts.map +1 -0
  55. package/dist/lib/backendUsage.js +55 -0
  56. package/dist/lib/backendUsage.js.map +1 -0
  57. package/dist/lib/backends.d.ts +142 -0
  58. package/dist/lib/backends.d.ts.map +1 -0
  59. package/dist/lib/backends.js +272 -0
  60. package/dist/lib/backends.js.map +1 -0
  61. package/dist/lib/blindedIndex.d.ts +156 -0
  62. package/dist/lib/blindedIndex.d.ts.map +1 -0
  63. package/dist/lib/blindedIndex.js +338 -0
  64. package/dist/lib/blindedIndex.js.map +1 -0
  65. package/dist/lib/collectionDescription.d.ts +33 -0
  66. package/dist/lib/collectionDescription.d.ts.map +1 -0
  67. package/dist/lib/collectionDescription.js +21 -0
  68. package/dist/lib/collectionDescription.js.map +1 -0
  69. package/dist/lib/cursor.d.ts +18 -0
  70. package/dist/lib/cursor.d.ts.map +1 -0
  71. package/dist/lib/cursor.js +50 -0
  72. package/dist/lib/cursor.js.map +1 -0
  73. package/dist/lib/edvEnvelope.d.ts +50 -0
  74. package/dist/lib/edvEnvelope.d.ts.map +1 -0
  75. package/dist/lib/edvEnvelope.js +106 -0
  76. package/dist/lib/edvEnvelope.js.map +1 -0
  77. package/dist/lib/encryption.d.ts +192 -0
  78. package/dist/lib/encryption.d.ts.map +1 -0
  79. package/dist/lib/encryption.js +383 -0
  80. package/dist/lib/encryption.js.map +1 -0
  81. package/dist/lib/etag.d.ts +33 -0
  82. package/dist/lib/etag.d.ts.map +1 -0
  83. package/dist/lib/etag.js +36 -0
  84. package/dist/lib/etag.js.map +1 -0
  85. package/dist/lib/exportManifest.d.ts +29 -0
  86. package/dist/lib/exportManifest.d.ts.map +1 -0
  87. package/dist/lib/exportManifest.js +77 -0
  88. package/dist/lib/exportManifest.js.map +1 -0
  89. package/dist/lib/importTar.d.ts +81 -0
  90. package/dist/lib/importTar.d.ts.map +1 -0
  91. package/dist/lib/importTar.js +301 -0
  92. package/dist/lib/importTar.js.map +1 -0
  93. package/dist/lib/isJson.d.ts +16 -0
  94. package/dist/lib/isJson.d.ts.map +1 -0
  95. package/dist/lib/isJson.js +17 -0
  96. package/dist/lib/isJson.js.map +1 -0
  97. package/dist/lib/keyEpoch.d.ts +38 -0
  98. package/dist/lib/keyEpoch.d.ts.map +1 -0
  99. package/dist/lib/keyEpoch.js +75 -0
  100. package/dist/lib/keyEpoch.js.map +1 -0
  101. package/dist/lib/keyedMutex.d.ts +28 -0
  102. package/dist/lib/keyedMutex.d.ts.map +1 -0
  103. package/dist/lib/keyedMutex.js +45 -0
  104. package/dist/lib/keyedMutex.js.map +1 -0
  105. package/dist/lib/kmsModule.d.ts +62 -0
  106. package/dist/lib/kmsModule.d.ts.map +1 -0
  107. package/dist/lib/kmsModule.js +327 -0
  108. package/dist/lib/kmsModule.js.map +1 -0
  109. package/dist/lib/kmsRecordCipher.d.ts +82 -0
  110. package/dist/lib/kmsRecordCipher.d.ts.map +1 -0
  111. package/dist/lib/kmsRecordCipher.js +226 -0
  112. package/dist/lib/kmsRecordCipher.js.map +1 -0
  113. package/dist/lib/pagination.d.ts +19 -0
  114. package/dist/lib/pagination.d.ts.map +1 -0
  115. package/dist/lib/pagination.js +21 -0
  116. package/dist/lib/pagination.js.map +1 -0
  117. package/dist/lib/paths.d.ts +273 -0
  118. package/dist/lib/paths.d.ts.map +1 -0
  119. package/dist/lib/paths.js +270 -0
  120. package/dist/lib/paths.js.map +1 -0
  121. package/dist/lib/preconditions.d.ts +65 -0
  122. package/dist/lib/preconditions.d.ts.map +1 -0
  123. package/dist/lib/preconditions.js +112 -0
  124. package/dist/lib/preconditions.js.map +1 -0
  125. package/dist/lib/resourceFileName.d.ts +41 -0
  126. package/dist/lib/resourceFileName.d.ts.map +1 -0
  127. package/dist/lib/resourceFileName.js +58 -0
  128. package/dist/lib/resourceFileName.js.map +1 -0
  129. package/dist/lib/revocations.d.ts +49 -0
  130. package/dist/lib/revocations.d.ts.map +1 -0
  131. package/dist/lib/revocations.js +86 -0
  132. package/dist/lib/revocations.js.map +1 -0
  133. package/dist/lib/validateDid.d.ts +19 -0
  134. package/dist/lib/validateDid.d.ts.map +1 -0
  135. package/dist/lib/validateDid.js +35 -0
  136. package/dist/lib/validateDid.js.map +1 -0
  137. package/dist/lib/validateId.d.ts +66 -0
  138. package/dist/lib/validateId.d.ts.map +1 -0
  139. package/dist/lib/validateId.js +126 -0
  140. package/dist/lib/validateId.js.map +1 -0
  141. package/dist/plugin.d.ts +115 -0
  142. package/dist/plugin.d.ts.map +1 -0
  143. package/dist/plugin.js +134 -0
  144. package/dist/plugin.js.map +1 -0
  145. package/dist/policy.d.ts +78 -0
  146. package/dist/policy.d.ts.map +1 -0
  147. package/dist/policy.js +115 -0
  148. package/dist/policy.js.map +1 -0
  149. package/dist/provisioning.d.ts +38 -0
  150. package/dist/provisioning.d.ts.map +1 -0
  151. package/dist/provisioning.js +72 -0
  152. package/dist/provisioning.js.map +1 -0
  153. package/dist/requests/BackendRequest.d.ts +61 -0
  154. package/dist/requests/BackendRequest.d.ts.map +1 -0
  155. package/dist/requests/BackendRequest.js +152 -0
  156. package/dist/requests/BackendRequest.js.map +1 -0
  157. package/dist/requests/CollectionRequest.d.ts +234 -0
  158. package/dist/requests/CollectionRequest.d.ts.map +1 -0
  159. package/dist/requests/CollectionRequest.js +705 -0
  160. package/dist/requests/CollectionRequest.js.map +1 -0
  161. package/dist/requests/KeyRequest.d.ts +115 -0
  162. package/dist/requests/KeyRequest.d.ts.map +1 -0
  163. package/dist/requests/KeyRequest.js +468 -0
  164. package/dist/requests/KeyRequest.js.map +1 -0
  165. package/dist/requests/KeystoreRequest.d.ts +99 -0
  166. package/dist/requests/KeystoreRequest.d.ts.map +1 -0
  167. package/dist/requests/KeystoreRequest.js +247 -0
  168. package/dist/requests/KeystoreRequest.js.map +1 -0
  169. package/dist/requests/PolicyRequest.d.ts +53 -0
  170. package/dist/requests/PolicyRequest.d.ts.map +1 -0
  171. package/dist/requests/PolicyRequest.js +124 -0
  172. package/dist/requests/PolicyRequest.js.map +1 -0
  173. package/dist/requests/ResourceRequest.d.ts +134 -0
  174. package/dist/requests/ResourceRequest.d.ts.map +1 -0
  175. package/dist/requests/ResourceRequest.js +548 -0
  176. package/dist/requests/ResourceRequest.js.map +1 -0
  177. package/dist/requests/RevocationRequest.d.ts +67 -0
  178. package/dist/requests/RevocationRequest.d.ts.map +1 -0
  179. package/dist/requests/RevocationRequest.js +187 -0
  180. package/dist/requests/RevocationRequest.js.map +1 -0
  181. package/dist/requests/SpaceRequest.d.ts +204 -0
  182. package/dist/requests/SpaceRequest.d.ts.map +1 -0
  183. package/dist/requests/SpaceRequest.js +520 -0
  184. package/dist/requests/SpaceRequest.js.map +1 -0
  185. package/dist/requests/SpacesRepositoryRequest.d.ts +50 -0
  186. package/dist/requests/SpacesRepositoryRequest.d.ts.map +1 -0
  187. package/dist/requests/SpacesRepositoryRequest.js +159 -0
  188. package/dist/requests/SpacesRepositoryRequest.js.map +1 -0
  189. package/dist/requests/collectionContext.d.ts +21 -0
  190. package/dist/requests/collectionContext.d.ts.map +1 -0
  191. package/dist/requests/collectionContext.js +30 -0
  192. package/dist/requests/collectionContext.js.map +1 -0
  193. package/dist/requests/controllerConsent.d.ts +58 -0
  194. package/dist/requests/controllerConsent.d.ts.map +1 -0
  195. package/dist/requests/controllerConsent.js +73 -0
  196. package/dist/requests/controllerConsent.js.map +1 -0
  197. package/dist/requests/keystoreContext.d.ts +68 -0
  198. package/dist/requests/keystoreContext.d.ts.map +1 -0
  199. package/dist/requests/keystoreContext.js +87 -0
  200. package/dist/requests/keystoreContext.js.map +1 -0
  201. package/dist/requests/resourceInput.d.ts +19 -0
  202. package/dist/requests/resourceInput.d.ts.map +1 -0
  203. package/dist/requests/resourceInput.js +102 -0
  204. package/dist/requests/resourceInput.js.map +1 -0
  205. package/dist/requests/spaceContext.d.ts +127 -0
  206. package/dist/requests/spaceContext.d.ts.map +1 -0
  207. package/dist/requests/spaceContext.js +201 -0
  208. package/dist/requests/spaceContext.js.map +1 -0
  209. package/dist/routes.d.ts +55 -0
  210. package/dist/routes.d.ts.map +1 -0
  211. package/dist/routes.js +306 -0
  212. package/dist/routes.js.map +1 -0
  213. package/dist/server.d.ts +20 -0
  214. package/dist/server.d.ts.map +1 -0
  215. package/dist/server.js +60 -0
  216. package/dist/server.js.map +1 -0
  217. package/dist/start.d.ts +7 -0
  218. package/dist/start.d.ts.map +1 -0
  219. package/dist/start.js +61 -0
  220. package/dist/start.js.map +1 -0
  221. package/dist/storage.d.ts +29 -0
  222. package/dist/storage.d.ts.map +1 -0
  223. package/dist/storage.js +47 -0
  224. package/dist/storage.js.map +1 -0
  225. package/dist/types.d.ts +915 -0
  226. package/dist/types.d.ts.map +1 -0
  227. package/dist/types.js +2 -0
  228. package/dist/types.js.map +1 -0
  229. package/dist/views/home.hbs +9 -0
  230. package/dist/views/templates/main.hbs +12 -0
  231. package/dist/zcap.d.ts +267 -0
  232. package/dist/zcap.d.ts.map +1 -0
  233. package/dist/zcap.js +478 -0
  234. package/dist/zcap.js.map +1 -0
  235. package/package.json +109 -0
  236. package/src/auth-header-hooks.ts +163 -0
  237. package/src/authorize.ts +117 -0
  238. package/src/backends/filesystem.ts +3626 -0
  239. package/src/backends/postgres.ts +3073 -0
  240. package/src/backends/postgresSchema.ts +231 -0
  241. package/src/config.default.ts +657 -0
  242. package/src/corsProxy.ts +326 -0
  243. package/src/declarations.d.ts +28 -0
  244. package/src/digest.ts +223 -0
  245. package/src/errors.ts +1122 -0
  246. package/src/index.ts +21 -0
  247. package/src/lib/atomicFile.ts +176 -0
  248. package/src/lib/backendRegistry.ts +139 -0
  249. package/src/lib/backendUsage.ts +79 -0
  250. package/src/lib/backends.ts +351 -0
  251. package/src/lib/blindedIndex.ts +466 -0
  252. package/src/lib/collectionDescription.ts +43 -0
  253. package/src/lib/cursor.ts +52 -0
  254. package/src/lib/edvEnvelope.ts +120 -0
  255. package/src/lib/encryption.ts +472 -0
  256. package/src/lib/etag.ts +40 -0
  257. package/src/lib/exportManifest.ts +115 -0
  258. package/src/lib/importTar.ts +381 -0
  259. package/src/lib/isJson.ts +18 -0
  260. package/src/lib/keyEpoch.ts +89 -0
  261. package/src/lib/keyedMutex.ts +45 -0
  262. package/src/lib/kmsModule.ts +451 -0
  263. package/src/lib/kmsRecordCipher.ts +292 -0
  264. package/src/lib/pagination.ts +22 -0
  265. package/src/lib/paths.ts +382 -0
  266. package/src/lib/preconditions.ts +145 -0
  267. package/src/lib/resourceFileName.ts +69 -0
  268. package/src/lib/revocations.ts +116 -0
  269. package/src/lib/validateDid.ts +41 -0
  270. package/src/lib/validateId.ts +148 -0
  271. package/src/plugin.ts +288 -0
  272. package/src/policy.ts +176 -0
  273. package/src/provisioning.ts +98 -0
  274. package/src/requests/BackendRequest.ts +219 -0
  275. package/src/requests/CollectionRequest.ts +899 -0
  276. package/src/requests/KeyRequest.ts +617 -0
  277. package/src/requests/KeystoreRequest.ts +325 -0
  278. package/src/requests/PolicyRequest.ts +169 -0
  279. package/src/requests/ResourceRequest.ts +649 -0
  280. package/src/requests/RevocationRequest.ts +267 -0
  281. package/src/requests/SpaceRequest.ts +686 -0
  282. package/src/requests/SpacesRepositoryRequest.ts +194 -0
  283. package/src/requests/collectionContext.ts +41 -0
  284. package/src/requests/controllerConsent.ts +108 -0
  285. package/src/requests/keystoreContext.ts +124 -0
  286. package/src/requests/resourceInput.ts +118 -0
  287. package/src/requests/spaceContext.ts +311 -0
  288. package/src/routes.ts +420 -0
  289. package/src/server.ts +69 -0
  290. package/src/start.ts +71 -0
  291. package/src/storage.ts +60 -0
  292. package/src/types.ts +1016 -0
  293. package/src/views/home.hbs +9 -0
  294. package/src/views/templates/main.hbs +12 -0
  295. package/src/zcap.ts +657 -0
@@ -0,0 +1,99 @@
1
+ /**
2
+ * Request handlers for the WebKMS keystore lifecycle (the `/kms` facet):
3
+ * - POST /kms/keystores (Create Keystore)
4
+ * - GET /kms/keystores?controller=<did> (List Keystores by controller)
5
+ * - GET /kms/keystores/:keystoreId (Get Keystore config)
6
+ * - POST /kms/keystores/:keystoreId (Update Keystore config)
7
+ *
8
+ * The wire contract is protocol-fixed by `@interop/webkms-client` (which is
9
+ * also the conformance suite for it): all routes are zcap-invoked with
10
+ * `read` / `write` actions (not HTTP verbs), the create response is the bare
11
+ * config (201 + `Location`), list wraps in `{ results }`, and update wraps in
12
+ * `{ config }`. The `meterId` / `ipAllowList` fields are deliberately dropped;
13
+ * the body schemas remain `additionalProperties: false`, so supplying them is
14
+ * rejected.
15
+ */
16
+ import type { FastifyReply, FastifyRequest } from 'fastify';
17
+ import type { IDID } from '../types.js';
18
+ /** The keystore config fields a client may supply (create and update). */
19
+ interface KeystoreConfigBody {
20
+ id?: string;
21
+ controller: IDID;
22
+ sequence: number;
23
+ kmsModule?: string;
24
+ }
25
+ export declare class KeystoreRequest {
26
+ /**
27
+ * POST /kms/keystores
28
+ * Create Keystore. Authorization is the keystore-creation bootstrap rule,
29
+ * mirroring Create Space (`SpacesRepositoryRequest.post`): the invocation
30
+ * must be *authorized by* the `controller` DID in the request body -- signed
31
+ * directly by it, or via a delegation chain rooted in it -- so anyone can
32
+ * create their own keystore by proving control of the DID they name.
33
+ * Responds 201 with `Location` and the bare config -- the client asserts a
34
+ * string `id` on it.
35
+ *
36
+ * @param request {import('fastify').FastifyRequest}
37
+ * @param reply {import('fastify').FastifyReply}
38
+ * @returns {Promise<FastifyReply>}
39
+ */
40
+ static post(request: FastifyRequest<{
41
+ Body: KeystoreConfigBody;
42
+ }>, reply: FastifyReply): Promise<FastifyReply>;
43
+ /**
44
+ * GET /kms/keystores?controller=<did>
45
+ * List Keystores by controller. The root capability for `/kms/keystores` is
46
+ * synthesized with the `controller` *query parameter* as its controller, so
47
+ * a caller can only list their own keystores (a failed verification is the
48
+ * masked 404, per the server-wide convention). The query string rides the
49
+ * request URL, so verification runs in target-attenuation mode (the same
50
+ * `allowTargetQuery` treatment as List Collection pagination). Responds
51
+ * `{ results }`, capped at `KEYSTORE_LIST_LIMIT`.
52
+ *
53
+ * @param request {import('fastify').FastifyRequest}
54
+ * @param reply {import('fastify').FastifyReply}
55
+ * @returns {Promise<FastifyReply>}
56
+ */
57
+ static list(request: FastifyRequest<{
58
+ Querystring: {
59
+ controller?: string;
60
+ };
61
+ }>, reply: FastifyReply): Promise<FastifyReply>;
62
+ /**
63
+ * GET /kms/keystores/:keystoreId
64
+ * Get Keystore config: capability-verified against the stored config's
65
+ * controller (`read`), responding with the bare config.
66
+ *
67
+ * @param request {import('fastify').FastifyRequest}
68
+ * @param reply {import('fastify').FastifyReply}
69
+ * @returns {Promise<FastifyReply>}
70
+ */
71
+ static get(request: FastifyRequest<{
72
+ Params: {
73
+ keystoreId: string;
74
+ };
75
+ }>, reply: FastifyReply): Promise<FastifyReply>;
76
+ /**
77
+ * POST /kms/keystores/:keystoreId
78
+ * Update Keystore config. Verified against the *stored* config's controller
79
+ * (`write`) -- so a controller change is authorized by the current
80
+ * controller and takes effect immediately. The body's `id` must match the
81
+ * keystore URL (400); the storage layer applies the update atomically iff
82
+ * `sequence` is exactly previous+1 and `kmsModule` is unchanged (409
83
+ * `KeystoreStateConflictError` otherwise; an omitted `kmsModule` defaults to
84
+ * the stored one). Responds `{ config }` -- note the
85
+ * wrapper, unlike get/create.
86
+ *
87
+ * @param request {import('fastify').FastifyRequest}
88
+ * @param reply {import('fastify').FastifyReply}
89
+ * @returns {Promise<FastifyReply>}
90
+ */
91
+ static update(request: FastifyRequest<{
92
+ Params: {
93
+ keystoreId: string;
94
+ };
95
+ Body: KeystoreConfigBody;
96
+ }>, reply: FastifyReply): Promise<FastifyReply>;
97
+ }
98
+ export {};
99
+ //# sourceMappingURL=KeystoreRequest.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"KeystoreRequest.d.ts","sourceRoot":"","sources":["../../src/requests/KeystoreRequest.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;GAcG;AACH,OAAO,KAAK,EAAE,YAAY,EAAE,cAAc,EAAE,MAAM,SAAS,CAAA;AAiB3D,OAAO,KAAK,EAAE,IAAI,EAAkB,MAAM,aAAa,CAAA;AAEvD,0EAA0E;AAC1E,UAAU,kBAAkB;IAC1B,EAAE,CAAC,EAAE,MAAM,CAAA;IACX,UAAU,EAAE,IAAI,CAAA;IAChB,QAAQ,EAAE,MAAM,CAAA;IAChB,SAAS,CAAC,EAAE,MAAM,CAAA;CACnB;AAoFD,qBAAa,eAAe;IAC1B;;;;;;;;;;;;;OAaG;WACU,IAAI,CACf,OAAO,EAAE,cAAc,CAAC;QAAE,IAAI,EAAE,kBAAkB,CAAA;KAAE,CAAC,EACrD,KAAK,EAAE,YAAY,GAClB,OAAO,CAAC,YAAY,CAAC;IA0CxB;;;;;;;;;;;;;OAaG;WACU,IAAI,CACf,OAAO,EAAE,cAAc,CAAC;QAAE,WAAW,EAAE;YAAE,UAAU,CAAC,EAAE,MAAM,CAAA;SAAE,CAAA;KAAE,CAAC,EACjE,KAAK,EAAE,YAAY,GAClB,OAAO,CAAC,YAAY,CAAC;IA4CxB;;;;;;;;OAQG;WACU,GAAG,CACd,OAAO,EAAE,cAAc,CAAC;QAAE,MAAM,EAAE;YAAE,UAAU,EAAE,MAAM,CAAA;SAAE,CAAA;KAAE,CAAC,EAC3D,KAAK,EAAE,YAAY,GAClB,OAAO,CAAC,YAAY,CAAC;IAUxB;;;;;;;;;;;;;;OAcG;WACU,MAAM,CACjB,OAAO,EAAE,cAAc,CAAC;QACtB,MAAM,EAAE;YAAE,UAAU,EAAE,MAAM,CAAA;SAAE,CAAA;QAC9B,IAAI,EAAE,kBAAkB,CAAA;KACzB,CAAC,EACF,KAAK,EAAE,YAAY,GAClB,OAAO,CAAC,YAAY,CAAC;CAoCzB"}
@@ -0,0 +1,247 @@
1
+ import { generateId } from '@digitalcredentials/bnid';
2
+ import { handleZcapVerify } from '../zcap.js';
3
+ import { assertValidController } from '../lib/validateDid.js';
4
+ import { kmsKeystoresPath } from '../lib/paths.js';
5
+ import { fetchKeystoreAndVerify } from './keystoreContext.js';
6
+ import { verifyBodyControllerConsent } from './controllerConsent.js';
7
+ import { DEFAULT_KMS_MODULE, KEYSTORE_LIST_LIMIT, KMS_MAX_CHAIN_LENGTH, KMS_MAX_DELEGATION_TTL } from '../config.default.js';
8
+ import { InvalidRequestBodyError, KeystoreControllerMismatchError } from '../errors.js';
9
+ /**
10
+ * Validates a keystore config request body against the webkms schema shape
11
+ * (minus the dropped `meterId` / `ipAllowList`): required fields present, no
12
+ * unknown fields (`additionalProperties: false`), `controller` a valid
13
+ * did:key, `sequence` a non-negative integer -- exactly 0 on create; the
14
+ * update path's previous+1 gate is the storage layer's, where it is atomic.
15
+ * Throws `InvalidRequestBodyError` (400).
16
+ *
17
+ * @param options {object}
18
+ * @param options.body {unknown} the parsed request body
19
+ * @param options.requestName {string} request name used in error titles
20
+ * @param [options.isUpdate] {boolean} validate the update shape (requires
21
+ * `id`, allows any non-negative `sequence`)
22
+ * @returns {KeystoreConfigBody} the body, narrowed
23
+ */
24
+ function assertKeystoreConfigBody({ body, requestName, isUpdate = false }) {
25
+ if (typeof body !== 'object' || body === null || Array.isArray(body)) {
26
+ throw new InvalidRequestBodyError({
27
+ requestName,
28
+ detail: 'Keystore config body must be a JSON object.'
29
+ });
30
+ }
31
+ const allowedKeys = isUpdate
32
+ ? ['id', 'controller', 'sequence', 'kmsModule']
33
+ : ['controller', 'sequence', 'kmsModule'];
34
+ for (const key of Object.keys(body)) {
35
+ if (!allowedKeys.includes(key)) {
36
+ throw new InvalidRequestBodyError({
37
+ requestName,
38
+ detail: `Unexpected keystore config property "${key}".`,
39
+ pointer: `#/${key}`
40
+ });
41
+ }
42
+ }
43
+ const config = body;
44
+ assertValidController(config.controller, { requestName });
45
+ if (!Number.isInteger(config.sequence) ||
46
+ config.sequence < 0 ||
47
+ config.sequence > Number.MAX_SAFE_INTEGER - 1) {
48
+ throw new InvalidRequestBodyError({
49
+ requestName,
50
+ detail: 'Keystore config "sequence" must be a non-negative integer.',
51
+ pointer: '#/sequence'
52
+ });
53
+ }
54
+ if (!isUpdate && config.sequence !== 0) {
55
+ throw new InvalidRequestBodyError({
56
+ requestName,
57
+ detail: 'Keystore config sequence must be "0" on create.',
58
+ pointer: '#/sequence'
59
+ });
60
+ }
61
+ if (isUpdate && typeof config.id !== 'string') {
62
+ throw new InvalidRequestBodyError({
63
+ requestName,
64
+ detail: 'Keystore config "id" is required.',
65
+ pointer: '#/id'
66
+ });
67
+ }
68
+ if (config.kmsModule !== undefined &&
69
+ (typeof config.kmsModule !== 'string' || config.kmsModule.length === 0)) {
70
+ throw new InvalidRequestBodyError({
71
+ requestName,
72
+ detail: 'Keystore config "kmsModule" must be a non-empty string.',
73
+ pointer: '#/kmsModule'
74
+ });
75
+ }
76
+ return config;
77
+ }
78
+ export class KeystoreRequest {
79
+ /**
80
+ * POST /kms/keystores
81
+ * Create Keystore. Authorization is the keystore-creation bootstrap rule,
82
+ * mirroring Create Space (`SpacesRepositoryRequest.post`): the invocation
83
+ * must be *authorized by* the `controller` DID in the request body -- signed
84
+ * directly by it, or via a delegation chain rooted in it -- so anyone can
85
+ * create their own keystore by proving control of the DID they name.
86
+ * Responds 201 with `Location` and the bare config -- the client asserts a
87
+ * string `id` on it.
88
+ *
89
+ * @param request {import('fastify').FastifyRequest}
90
+ * @param reply {import('fastify').FastifyReply}
91
+ * @returns {Promise<FastifyReply>}
92
+ */
93
+ static async post(request, reply) {
94
+ const requestName = 'Create Keystore';
95
+ const { body } = request;
96
+ const { serverUrl, storage } = request.server;
97
+ assertKeystoreConfigBody({ body, requestName });
98
+ // The invocation must be *authorized by* the body's controller (see
99
+ // `verifyBodyControllerConsent`). Skipped when the provisioning policy
100
+ // already vouched for the request (e.g. a valid onboarding token).
101
+ if (!request.provisioningAuthorized) {
102
+ await verifyBodyControllerConsent({
103
+ request,
104
+ controller: body.controller,
105
+ allowedTarget: new URL(kmsKeystoresPath(), serverUrl).toString(),
106
+ allowedAction: 'write',
107
+ MismatchError: KeystoreControllerMismatchError,
108
+ requestName,
109
+ maxChainLength: KMS_MAX_CHAIN_LENGTH,
110
+ maxDelegationTtl: KMS_MAX_DELEGATION_TTL
111
+ });
112
+ }
113
+ // Server-generated local id, per webkms-switch `generateRandom`: multibase
114
+ // base58btc of a multihash-framed (identity, 16-byte) 128-bit random value.
115
+ const keystoreId = await generateId({ multihash: true });
116
+ const keystoreUrl = new URL(kmsKeystoresPath({ keystoreId }), serverUrl).toString();
117
+ const config = {
118
+ id: keystoreUrl,
119
+ controller: body.controller,
120
+ sequence: 0,
121
+ kmsModule: body.kmsModule ?? DEFAULT_KMS_MODULE
122
+ };
123
+ await storage.writeKeystore({ keystoreId, config });
124
+ reply.header('Location', keystoreUrl);
125
+ return reply.status(201).send(config);
126
+ }
127
+ /**
128
+ * GET /kms/keystores?controller=<did>
129
+ * List Keystores by controller. The root capability for `/kms/keystores` is
130
+ * synthesized with the `controller` *query parameter* as its controller, so
131
+ * a caller can only list their own keystores (a failed verification is the
132
+ * masked 404, per the server-wide convention). The query string rides the
133
+ * request URL, so verification runs in target-attenuation mode (the same
134
+ * `allowTargetQuery` treatment as List Collection pagination). Responds
135
+ * `{ results }`, capped at `KEYSTORE_LIST_LIMIT`.
136
+ *
137
+ * @param request {import('fastify').FastifyRequest}
138
+ * @param reply {import('fastify').FastifyReply}
139
+ * @returns {Promise<FastifyReply>}
140
+ */
141
+ static async list(request, reply) {
142
+ const requestName = 'List Keystores';
143
+ const { url, method, headers, query } = request;
144
+ const { serverUrl, storage } = request.server;
145
+ // The list query schema: `controller` required, no other parameters.
146
+ // The controller names whose keystores are being asked for
147
+ // (and thereby the root controller the invocation must verify against).
148
+ for (const key of Object.keys(query)) {
149
+ if (key !== 'controller') {
150
+ throw new InvalidRequestBodyError({
151
+ requestName,
152
+ detail: `Unexpected query parameter "${key}".`
153
+ });
154
+ }
155
+ }
156
+ assertValidController(query.controller, { requestName });
157
+ const controller = query.controller;
158
+ const allowedTarget = new URL(kmsKeystoresPath(), serverUrl).toString();
159
+ await handleZcapVerify({
160
+ url,
161
+ allowedTarget,
162
+ allowedAction: 'read',
163
+ method,
164
+ headers,
165
+ serverUrl,
166
+ spaceController: controller,
167
+ requestName,
168
+ logger: request.log,
169
+ allowTargetQuery: true,
170
+ // The chain roots at the keystores-collection URL (keyed by the query
171
+ // `controller`), not at any one keystore, so no RevocationScope exists
172
+ // for it -- collection-level capabilities are outside the per-scope
173
+ // revocation model.
174
+ revocation: 'no-revocation-scope',
175
+ maxChainLength: KMS_MAX_CHAIN_LENGTH,
176
+ maxDelegationTtl: KMS_MAX_DELEGATION_TTL
177
+ });
178
+ const configs = await storage.listKeystoresByController({ controller });
179
+ return reply.send({ results: configs.slice(0, KEYSTORE_LIST_LIMIT) });
180
+ }
181
+ /**
182
+ * GET /kms/keystores/:keystoreId
183
+ * Get Keystore config: capability-verified against the stored config's
184
+ * controller (`read`), responding with the bare config.
185
+ *
186
+ * @param request {import('fastify').FastifyRequest}
187
+ * @param reply {import('fastify').FastifyReply}
188
+ * @returns {Promise<FastifyReply>}
189
+ */
190
+ static async get(request, reply) {
191
+ const { config } = await fetchKeystoreAndVerify({
192
+ request,
193
+ keystoreId: request.params.keystoreId,
194
+ allowedAction: 'read',
195
+ requestName: 'Get Keystore'
196
+ });
197
+ return reply.send(config);
198
+ }
199
+ /**
200
+ * POST /kms/keystores/:keystoreId
201
+ * Update Keystore config. Verified against the *stored* config's controller
202
+ * (`write`) -- so a controller change is authorized by the current
203
+ * controller and takes effect immediately. The body's `id` must match the
204
+ * keystore URL (400); the storage layer applies the update atomically iff
205
+ * `sequence` is exactly previous+1 and `kmsModule` is unchanged (409
206
+ * `KeystoreStateConflictError` otherwise; an omitted `kmsModule` defaults to
207
+ * the stored one). Responds `{ config }` -- note the
208
+ * wrapper, unlike get/create.
209
+ *
210
+ * @param request {import('fastify').FastifyRequest}
211
+ * @param reply {import('fastify').FastifyReply}
212
+ * @returns {Promise<FastifyReply>}
213
+ */
214
+ static async update(request, reply) {
215
+ const requestName = 'Update Keystore';
216
+ const { body } = request;
217
+ const { storage } = request.server;
218
+ const { keystoreId } = request.params;
219
+ assertKeystoreConfigBody({ body, requestName, isUpdate: true });
220
+ const { config: existing } = await fetchKeystoreAndVerify({
221
+ request,
222
+ keystoreId,
223
+ allowedAction: 'write',
224
+ requestName
225
+ });
226
+ // The stored `id` is the keystore's full URL; the submitted config must
227
+ // name the same keystore it is posted to.
228
+ if (body.id !== existing.id) {
229
+ throw new InvalidRequestBodyError({
230
+ requestName,
231
+ detail: 'Configuration "id" does not match request URL.',
232
+ pointer: '#/id'
233
+ });
234
+ }
235
+ const config = {
236
+ id: existing.id,
237
+ controller: body.controller,
238
+ sequence: body.sequence,
239
+ kmsModule: body.kmsModule ?? existing.kmsModule
240
+ };
241
+ // Throws the merged 409 state conflict on a sequence / kmsModule mismatch,
242
+ // atomically with the write.
243
+ await storage.updateKeystore({ keystoreId, config });
244
+ return reply.send({ config });
245
+ }
246
+ }
247
+ //# sourceMappingURL=KeystoreRequest.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"KeystoreRequest.js","sourceRoot":"","sources":["../../src/requests/KeystoreRequest.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,53 @@
1
+ /**
2
+ * Request handlers for access-control policy operations: get/update/delete the
3
+ * `policy` auxiliary resource at the Space, Collection, or Resource level (the
4
+ * level is selected by which path params are present). Reading or modifying a
5
+ * policy is privileged: every operation verifies a capability invocation against
6
+ * the Space controller (the read-method relaxation in auth-header-hooks.ts does
7
+ * not apply here -- a policy is controller-managed metadata, not public data).
8
+ */
9
+ import type { FastifyReply, FastifyRequest } from 'fastify';
10
+ /** Path params shared by the three policy route shapes. */
11
+ interface PolicyParams {
12
+ spaceId: string;
13
+ collectionId?: string;
14
+ resourceId?: string;
15
+ }
16
+ export declare class PolicyRequest {
17
+ /**
18
+ * GET /space/:spaceId[/:collectionId[/:resourceId]]/policy
19
+ * Read the access-control policy document set at this level.
20
+ *
21
+ * @param request {import('fastify').FastifyRequest}
22
+ * @param reply {import('fastify').FastifyReply}
23
+ * @returns {Promise<FastifyReply>}
24
+ */
25
+ static get(request: FastifyRequest<{
26
+ Params: PolicyParams;
27
+ }>, reply: FastifyReply): Promise<FastifyReply>;
28
+ /**
29
+ * PUT /space/:spaceId[/:collectionId[/:resourceId]]/policy
30
+ * Create or replace the access-control policy document at this level.
31
+ *
32
+ * @param request {import('fastify').FastifyRequest}
33
+ * @param reply {import('fastify').FastifyReply}
34
+ * @returns {Promise<FastifyReply>}
35
+ */
36
+ static put(request: FastifyRequest<{
37
+ Params: PolicyParams;
38
+ Body: unknown;
39
+ }>, reply: FastifyReply): Promise<FastifyReply>;
40
+ /**
41
+ * DELETE /space/:spaceId[/:collectionId[/:resourceId]]/policy
42
+ * Remove the access-control policy document at this level (idempotent).
43
+ *
44
+ * @param request {import('fastify').FastifyRequest}
45
+ * @param reply {import('fastify').FastifyReply}
46
+ * @returns {Promise<FastifyReply>}
47
+ */
48
+ static delete(request: FastifyRequest<{
49
+ Params: PolicyParams;
50
+ }>, reply: FastifyReply): Promise<FastifyReply>;
51
+ }
52
+ export {};
53
+ //# sourceMappingURL=PolicyRequest.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"PolicyRequest.d.ts","sourceRoot":"","sources":["../../src/requests/PolicyRequest.ts"],"names":[],"mappings":"AAAA;;;;;;;GAOG;AACH,OAAO,KAAK,EAAE,YAAY,EAAE,cAAc,EAAE,MAAM,SAAS,CAAA;AAW3D,2DAA2D;AAC3D,UAAU,YAAY;IACpB,OAAO,EAAE,MAAM,CAAA;IACf,YAAY,CAAC,EAAE,MAAM,CAAA;IACrB,UAAU,CAAC,EAAE,MAAM,CAAA;CACpB;AAiBD,qBAAa,aAAa;IACxB;;;;;;;OAOG;WACU,GAAG,CACd,OAAO,EAAE,cAAc,CAAC;QAAE,MAAM,EAAE,YAAY,CAAA;KAAE,CAAC,EACjD,KAAK,EAAE,YAAY,GAClB,OAAO,CAAC,YAAY,CAAC;IA+BxB;;;;;;;OAOG;WACU,GAAG,CACd,OAAO,EAAE,cAAc,CAAC;QAAE,MAAM,EAAE,YAAY,CAAC;QAAC,IAAI,EAAE,OAAO,CAAA;KAAE,CAAC,EAChE,KAAK,EAAE,YAAY,GAClB,OAAO,CAAC,YAAY,CAAC;IA2CxB;;;;;;;OAOG;WACU,MAAM,CACjB,OAAO,EAAE,cAAc,CAAC;QAAE,MAAM,EAAE,YAAY,CAAA;KAAE,CAAC,EACjD,KAAK,EAAE,YAAY,GAClB,OAAO,CAAC,YAAY,CAAC;CAmBzB"}
@@ -0,0 +1,124 @@
1
+ import { fetchSpaceAndVerify } from './spaceContext.js';
2
+ import { assertValidIds } from '../lib/validateId.js';
3
+ import { policyPath } from '../lib/paths.js';
4
+ import { InvalidPolicyError, MissingAuthError, PolicyNotFoundError } from '../errors.js';
5
+ /**
6
+ * Asserts the request carries auth headers, throwing MissingAuthError (401)
7
+ * otherwise. Needed for the GET handler, which the `requireAuthHeaders` hook
8
+ * lets through unauthenticated (it is a safe method); PUT/DELETE are already
9
+ * gated by the hook.
10
+ * @param request {FastifyRequest}
11
+ * @returns {void}
12
+ */
13
+ function requireAuth(request) {
14
+ const { headers } = request;
15
+ if (!(headers.authorization && headers['capability-invocation'])) {
16
+ throw new MissingAuthError();
17
+ }
18
+ }
19
+ export class PolicyRequest {
20
+ /**
21
+ * GET /space/:spaceId[/:collectionId[/:resourceId]]/policy
22
+ * Read the access-control policy document set at this level.
23
+ *
24
+ * @param request {import('fastify').FastifyRequest}
25
+ * @param reply {import('fastify').FastifyReply}
26
+ * @returns {Promise<FastifyReply>}
27
+ */
28
+ static async get(request, reply) {
29
+ const { spaceId, collectionId, resourceId } = request.params;
30
+ const { storage } = request.server;
31
+ const requestName = 'Get Policy';
32
+ assertValidIds({ spaceId, collectionId, resourceId }, { requestName });
33
+ requireAuth(request);
34
+ // Verify (capability-only): a policy is controller-managed metadata, so
35
+ // reading it requires a valid capability invocation -- no policy fallback.
36
+ await fetchSpaceAndVerify({
37
+ request,
38
+ spaceId,
39
+ targetPath: policyPath({ spaceId, collectionId, resourceId }),
40
+ requestName
41
+ });
42
+ const policy = await storage.getPolicy({
43
+ spaceId,
44
+ collectionId,
45
+ resourceId
46
+ });
47
+ if (!policy) {
48
+ throw new PolicyNotFoundError({ requestName });
49
+ }
50
+ return reply
51
+ .status(200)
52
+ .type('application/json')
53
+ .send(JSON.stringify(policy));
54
+ }
55
+ /**
56
+ * PUT /space/:spaceId[/:collectionId[/:resourceId]]/policy
57
+ * Create or replace the access-control policy document at this level.
58
+ *
59
+ * @param request {import('fastify').FastifyRequest}
60
+ * @param reply {import('fastify').FastifyReply}
61
+ * @returns {Promise<FastifyReply>}
62
+ */
63
+ static async put(request, reply) {
64
+ const { spaceId, collectionId, resourceId } = request.params;
65
+ const { body } = request;
66
+ const { storage } = request.server;
67
+ const requestName = 'Update Policy';
68
+ assertValidIds({ spaceId, collectionId, resourceId }, { requestName });
69
+ // A policy document must be a JSON object carrying a non-empty string
70
+ // `type`. The set of recognized types is intentionally open (unknown types
71
+ // are stored and fail-closed at evaluation time, see policy.ts), so this is
72
+ // a shape check only -- it does not gate on a known-types allowlist.
73
+ const policyType = typeof body === 'object' && body !== null
74
+ ? body.type
75
+ : undefined;
76
+ if (typeof policyType !== 'string' || policyType.trim() === '') {
77
+ throw new InvalidPolicyError({ requestName });
78
+ }
79
+ const policy = body;
80
+ // Verify (capability-only): a policy is controller-managed metadata, so
81
+ // writing it requires a valid capability invocation -- no policy fallback.
82
+ const { allowedTarget: policyUrl } = await fetchSpaceAndVerify({
83
+ request,
84
+ spaceId,
85
+ targetPath: policyPath({ spaceId, collectionId, resourceId }),
86
+ requestName
87
+ });
88
+ const existing = await storage.getPolicy({
89
+ spaceId,
90
+ collectionId,
91
+ resourceId
92
+ });
93
+ await storage.writePolicy({ spaceId, collectionId, resourceId, policy });
94
+ reply.header('Location', policyUrl);
95
+ return existing
96
+ ? reply.status(204).send() // update
97
+ : reply.status(201).send(policy); // create
98
+ }
99
+ /**
100
+ * DELETE /space/:spaceId[/:collectionId[/:resourceId]]/policy
101
+ * Remove the access-control policy document at this level (idempotent).
102
+ *
103
+ * @param request {import('fastify').FastifyRequest}
104
+ * @param reply {import('fastify').FastifyReply}
105
+ * @returns {Promise<FastifyReply>}
106
+ */
107
+ static async delete(request, reply) {
108
+ const { spaceId, collectionId, resourceId } = request.params;
109
+ const { storage } = request.server;
110
+ const requestName = 'Delete Policy';
111
+ assertValidIds({ spaceId, collectionId, resourceId }, { requestName });
112
+ // Verify (capability-only): a policy is controller-managed metadata, so
113
+ // deleting it requires a valid capability invocation -- no policy fallback.
114
+ await fetchSpaceAndVerify({
115
+ request,
116
+ spaceId,
117
+ targetPath: policyPath({ spaceId, collectionId, resourceId }),
118
+ requestName
119
+ });
120
+ await storage.deletePolicy({ spaceId, collectionId, resourceId });
121
+ return reply.status(204).send();
122
+ }
123
+ }
124
+ //# sourceMappingURL=PolicyRequest.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"PolicyRequest.js","sourceRoot":"","sources":["../../src/requests/PolicyRequest.ts"],"names":[],"mappings":"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"}