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,159 @@
1
+ import { v4 as uuidv4 } from 'uuid';
2
+ import { isRootInvocation, verifyZcap } from '../zcap.js';
3
+ import { invalidateSpaceDescription } from './spaceContext.js';
4
+ import { verifyBodyControllerConsent } from './controllerConsent.js';
5
+ import { invokerDid } from '../auth-header-hooks.js';
6
+ import { assertValidId } from '../lib/validateId.js';
7
+ import { spacePath, spacesPath } from '../lib/paths.js';
8
+ import { assertValidController } from '../lib/validateDid.js';
9
+ import { SpaceControllerMismatchError, InvalidRequestBodyError, IdConflictError } from '../errors.js';
10
+ export class SpacesRepositoryRequest {
11
+ /**
12
+ * GET /spaces/
13
+ * Request handler for "List Spaces" (spec "List Spaces Operation"): returns
14
+ * `{ url, totalItems, items }` with only the Spaces the caller is authorized
15
+ * to see. An anonymous or unauthorized request is NOT an error -- it gets the
16
+ * empty-items 200, the spec's explicit exception to 404 masking -- so nothing
17
+ * is revealed about which Spaces exist.
18
+ *
19
+ * Authorization is per Space controller: the root capability for `/spaces/`
20
+ * is synthesized with the candidate Space's controller (see `verifyZcap`), so
21
+ * one verification decides visibility for every Space sharing that
22
+ * controller. A bare-root invocation can only verify where the signer *is*
23
+ * the controller, so those candidates are filtered before any signature
24
+ * work; a delegated invocation reveals the Spaces of whichever controller
25
+ * roots its capability chain.
26
+ *
27
+ * @param request {import('fastify').FastifyRequest}
28
+ * @param reply {import('fastify').FastifyReply}
29
+ * @returns {Promise<FastifyReply>}
30
+ */
31
+ static async get(request, reply) {
32
+ const { url, method, headers } = request;
33
+ const { serverUrl, storage } = request.server;
34
+ const items = [];
35
+ const listing = { url: spacesPath(), totalItems: 0, items };
36
+ // No (complete) authorization presented: authorized to see no Spaces,
37
+ // which is the empty 200, not an error.
38
+ if (!request.zcap?.invocation) {
39
+ return reply.send(listing);
40
+ }
41
+ const { keyId, invocation } = request.zcap;
42
+ const [zcapSigningDid] = keyId.split('#');
43
+ const rootInvocation = isRootInvocation({ invocation });
44
+ const allowedTarget = new URL(spacesPath(), serverUrl).toString();
45
+ // Visibility is identical across Spaces sharing a controller (the
46
+ // verification depends only on the controller), so verify once per
47
+ // distinct controller. A failed verification just excludes that
48
+ // controller's Spaces -- never an error response.
49
+ const verifiedByController = new Map();
50
+ for (const space of await storage.listSpaces()) {
51
+ const { controller } = space;
52
+ if (rootInvocation && controller !== zcapSigningDid) {
53
+ continue; // a bare-root invocation cannot verify for another controller
54
+ }
55
+ let authorized = verifiedByController.get(controller);
56
+ if (authorized === undefined) {
57
+ try {
58
+ const result = await verifyZcap({
59
+ url,
60
+ allowedTarget,
61
+ allowedAction: 'GET',
62
+ method,
63
+ headers,
64
+ serverUrl,
65
+ spaceController: controller
66
+ });
67
+ authorized = result.verified === true;
68
+ }
69
+ catch (err) {
70
+ request.log.debug({ err }, 'List Spaces: invocation did not verify for a candidate controller');
71
+ authorized = false;
72
+ }
73
+ verifiedByController.set(controller, authorized);
74
+ }
75
+ if (authorized) {
76
+ const item = {
77
+ id: space.id,
78
+ url: spacePath({ spaceId: space.id })
79
+ };
80
+ if (space.name !== undefined) {
81
+ item.name = space.name;
82
+ }
83
+ items.push(item);
84
+ }
85
+ }
86
+ listing.totalItems = items.length;
87
+ return reply.send(listing);
88
+ }
89
+ /**
90
+ * POST /spaces/
91
+ * Request handler for "Create Space" request
92
+ * Before this, `parseAuthHeaders()` hook executed, resulting in:
93
+ * request.zcap: {
94
+ * keyId, headers, signature, created, expires, invocation, digest
95
+ * }
96
+ *
97
+ * @param request {import('fastify').FastifyRequest}
98
+ * @param reply {import('fastify').FastifyReply}
99
+ * @returns {Promise<FastifyReply>}
100
+ */
101
+ static async post(request, reply) {
102
+ const { body } = request;
103
+ const { serverUrl, storage } = request.server;
104
+ // The Space Description body must carry a controller DID. The `name`
105
+ // property is optional (see spec: Space Description object).
106
+ if (!body?.controller) {
107
+ throw new InvalidRequestBodyError({
108
+ requestName: 'Create Space',
109
+ detail: 'Space Description body requires a "controller" property.',
110
+ pointer: '#/controller'
111
+ });
112
+ }
113
+ // Reject a malformed / non-`did:key` controller before it is stored.
114
+ assertValidController(body.controller, { requestName: 'Create Space' });
115
+ // Reject a path-traversal / non-URL-safe client-supplied space id.
116
+ if (body.id !== undefined) {
117
+ assertValidId(body.id, { kind: 'space', requestName: 'Create Space' });
118
+ // POST must never replace an existing Space: the signature below is
119
+ // verified against the *body's* controller, so without this check any
120
+ // caller could overwrite a Space (controller included) by POSTing its
121
+ // id. Spec: `id-conflict` (409); create-or-replace by id is PUT's job.
122
+ if (await storage.getSpaceDescription({ spaceId: body.id })) {
123
+ throw new IdConflictError({ kind: 'Space' });
124
+ }
125
+ }
126
+ const spaceId = body.id || uuidv4();
127
+ const spaceDescription = { ...body, id: spaceId, type: ['Space'] };
128
+ // The invocation must be *authorized by* the body's controller (spec:
129
+ // Create Space): signed directly by it, or via a delegation chain rooted
130
+ // in it (see `verifyBodyControllerConsent`). Skipped when the provisioning
131
+ // policy already vouched for the request (e.g. a valid onboarding token).
132
+ if (!request.provisioningAuthorized) {
133
+ await verifyBodyControllerConsent({
134
+ request,
135
+ controller: body.controller,
136
+ allowedTarget: new URL(spacesPath(), serverUrl).toString(),
137
+ allowedAction: 'POST',
138
+ MismatchError: SpaceControllerMismatchError,
139
+ requestName: 'Create Space'
140
+ });
141
+ }
142
+ // zCap checks out, continue. A token-provisioned create carries no
143
+ // invocation, so it records no `createdBy`.
144
+ const createdBy = invokerDid(request);
145
+ await storage.writeSpace({ spaceId, spaceDescription, createdBy });
146
+ // Bust any cached (e.g. negatively cached) description for this id so the
147
+ // next read sees the freshly created Space.
148
+ invalidateSpaceDescription({ storage, spaceId });
149
+ const createdSpaceUrl = new URL(spacesPath({ spaceId }), serverUrl).toString();
150
+ reply.header('Location', createdSpaceUrl);
151
+ // Echo what was persisted, `createdBy` included, so the create response and
152
+ // a subsequent Get Space agree. An id already in use was rejected as a 409
153
+ // above, so this write created the Space and its creator is this invoker.
154
+ return reply
155
+ .status(201)
156
+ .send({ ...spaceDescription, ...(createdBy && { createdBy }) });
157
+ }
158
+ }
159
+ //# sourceMappingURL=SpacesRepositoryRequest.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"SpacesRepositoryRequest.js","sourceRoot":"","sources":["../../src/requests/SpacesRepositoryRequest.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,21 @@
1
+ import type { CollectionDescription, StorageBackend } from '../types.js';
2
+ /**
3
+ * Fetches a Collection Description or throws CollectionNotFoundError (404)
4
+ * when absent.
5
+ * @param options {object}
6
+ * @param options.storage {StorageBackend} the request's storage backend
7
+ * @param options.spaceId {string}
8
+ * @param options.collectionId {string}
9
+ * @param options.requestName {string} human-readable request name, used in
10
+ * error titles
11
+ * @returns {Promise<CollectionDescription & { descriptionVersion?: number }>}
12
+ */
13
+ export declare function getCollectionOrThrow({ storage, spaceId, collectionId, requestName }: {
14
+ storage: StorageBackend;
15
+ spaceId: string;
16
+ collectionId: string;
17
+ requestName: string;
18
+ }): Promise<CollectionDescription & {
19
+ descriptionVersion?: number;
20
+ }>;
21
+ //# sourceMappingURL=collectionContext.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"collectionContext.d.ts","sourceRoot":"","sources":["../../src/requests/collectionContext.ts"],"names":[],"mappings":"AAQA,OAAO,KAAK,EAAE,qBAAqB,EAAE,cAAc,EAAE,MAAM,aAAa,CAAA;AAExE;;;;;;;;;;GAUG;AACH,wBAAsB,oBAAoB,CAAC,EACzC,OAAO,EACP,OAAO,EACP,YAAY,EACZ,WAAW,EACZ,EAAE;IACD,OAAO,EAAE,cAAc,CAAA;IACvB,OAAO,EAAE,MAAM,CAAA;IACf,YAAY,EAAE,MAAM,CAAA;IACpB,WAAW,EAAE,MAAM,CAAA;CACpB,GAAG,OAAO,CAAC,qBAAqB,GAAG;IAAE,kBAAkB,CAAC,EAAE,MAAM,CAAA;CAAE,CAAC,CASnE"}
@@ -0,0 +1,30 @@
1
+ /**
2
+ * Shared handler prelude: fetch a Collection Description or 404 (paralleling
3
+ * spaceContext.ts / keystoreContext.ts). Nearly every Collection- and
4
+ * Resource-level handler repeats the same shape after authorization -- load
5
+ * the Collection Description for context, throw `CollectionNotFoundError`
6
+ * when absent -- so it lives here.
7
+ */
8
+ import { CollectionNotFoundError } from '../errors.js';
9
+ /**
10
+ * Fetches a Collection Description or throws CollectionNotFoundError (404)
11
+ * when absent.
12
+ * @param options {object}
13
+ * @param options.storage {StorageBackend} the request's storage backend
14
+ * @param options.spaceId {string}
15
+ * @param options.collectionId {string}
16
+ * @param options.requestName {string} human-readable request name, used in
17
+ * error titles
18
+ * @returns {Promise<CollectionDescription & { descriptionVersion?: number }>}
19
+ */
20
+ export async function getCollectionOrThrow({ storage, spaceId, collectionId, requestName }) {
21
+ const collectionDescription = await storage.getCollectionDescription({
22
+ spaceId,
23
+ collectionId
24
+ });
25
+ if (!collectionDescription) {
26
+ throw new CollectionNotFoundError({ requestName });
27
+ }
28
+ return collectionDescription;
29
+ }
30
+ //# sourceMappingURL=collectionContext.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"collectionContext.js","sourceRoot":"","sources":["../../src/requests/collectionContext.ts"],"names":[],"mappings":"AAAA;;;;;;GAMG;AACH,OAAO,EAAE,uBAAuB,EAAE,MAAM,cAAc,CAAA;AAGtD;;;;;;;;;;GAUG;AACH,MAAM,CAAC,KAAK,UAAU,oBAAoB,CAAC,EACzC,OAAO,EACP,OAAO,EACP,YAAY,EACZ,WAAW,EAMZ;IACC,MAAM,qBAAqB,GAAG,MAAM,OAAO,CAAC,wBAAwB,CAAC;QACnE,OAAO;QACP,YAAY;KACb,CAAC,CAAA;IACF,IAAI,CAAC,qBAAqB,EAAE,CAAC;QAC3B,MAAM,IAAI,uBAAuB,CAAC,EAAE,WAAW,EAAE,CAAC,CAAA;IACpD,CAAC;IACD,OAAO,qBAAqB,CAAA;AAC9B,CAAC"}
@@ -0,0 +1,58 @@
1
+ /**
2
+ * Shared handler prelude for the create-by-consent bootstrap (paralleling
3
+ * spaceContext.ts / keystoreContext.ts): the operations that create a
4
+ * top-level resource owned by a DID named in the request *body* (Create
5
+ * Space, the create form of Update Space, Create Keystore) have no stored
6
+ * controller to verify against yet, so the invocation must be *authorized by*
7
+ * the body's controller -- signed directly by it, or via a delegation chain
8
+ * rooted in it. Verifying against the signer instead would let anyone install
9
+ * an unrelated, non-consenting DID as controller.
10
+ */
11
+ import type { FastifyRequest } from 'fastify';
12
+ import type { ProblemError } from '../errors.js';
13
+ import type { IDID } from '../types.js';
14
+ /**
15
+ * Verifies that the invocation is authorized by `controller` (the DID named
16
+ * in the request body). For the bare-root invocation form the signer *is* the
17
+ * invoker, so a mismatch is rejected up front, before any signature work. The
18
+ * delegated form instead carries a capability chain, judged by the
19
+ * verification (which synthesizes the root capability with `controller` as
20
+ * its controller): a delegated invocation that fails to verify is a chain not
21
+ * rooted in the body's controller, wrapped in `MismatchError` (spec
22
+ * `controller-mismatch`, 400). Root-form verification failures keep their
23
+ * generic errors -- the signer already matched the controller.
24
+ *
25
+ * @param options {object}
26
+ * @param options.request {FastifyRequest} supplies url, method, headers,
27
+ * logger, `request.zcap`, and `request.server` for serverUrl
28
+ * @param options.controller {IDID} the controller DID named in the request
29
+ * body, which must authorize the invocation
30
+ * @param options.allowedTarget {string} the capability's expected
31
+ * invocationTarget (full URL, including host and port)
32
+ * @param options.allowedAction {string} expected action, e.g. an HTTP verb
33
+ * @param options.MismatchError {new (options) => ProblemError} the
34
+ * operation's `controller-mismatch` error class (constructed with
35
+ * `{ zcapSigningDid, controller, cause? }`)
36
+ * @param [options.requestName] {string} human-readable request name, used
37
+ * in error titles
38
+ * @param [options.maxChainLength] {number} max delegation chain length,
39
+ * root included (see `verifyZcap`)
40
+ * @param [options.maxDelegationTtl] {number} max delegated-zcap TTL in
41
+ * milliseconds (see `verifyZcap`)
42
+ * @returns {Promise<void>}
43
+ */
44
+ export declare function verifyBodyControllerConsent({ request, controller, allowedTarget, allowedAction, MismatchError, requestName, maxChainLength, maxDelegationTtl }: {
45
+ request: FastifyRequest;
46
+ controller: IDID;
47
+ allowedTarget: string;
48
+ allowedAction: string;
49
+ MismatchError: new (options: {
50
+ zcapSigningDid: string;
51
+ controller: string;
52
+ cause?: Error;
53
+ }) => ProblemError;
54
+ requestName?: string;
55
+ maxChainLength?: number;
56
+ maxDelegationTtl?: number;
57
+ }): Promise<void>;
58
+ //# sourceMappingURL=controllerConsent.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"controllerConsent.d.ts","sourceRoot":"","sources":["../../src/requests/controllerConsent.ts"],"names":[],"mappings":"AAAA;;;;;;;;;GASG;AACH,OAAO,KAAK,EAAE,cAAc,EAAE,MAAM,SAAS,CAAA;AAE7C,OAAO,KAAK,EAAE,YAAY,EAAE,MAAM,cAAc,CAAA;AAChD,OAAO,KAAK,EAAE,IAAI,EAAE,MAAM,aAAa,CAAA;AAEvC;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GA6BG;AACH,wBAAsB,2BAA2B,CAAC,EAChD,OAAO,EACP,UAAU,EACV,aAAa,EACb,aAAa,EACb,aAAa,EACb,WAAW,EACX,cAAc,EACd,gBAAgB,EACjB,EAAE;IACD,OAAO,EAAE,cAAc,CAAA;IACvB,UAAU,EAAE,IAAI,CAAA;IAChB,aAAa,EAAE,MAAM,CAAA;IACrB,aAAa,EAAE,MAAM,CAAA;IACrB,aAAa,EAAE,KAAK,OAAO,EAAE;QAC3B,cAAc,EAAE,MAAM,CAAA;QACtB,UAAU,EAAE,MAAM,CAAA;QAClB,KAAK,CAAC,EAAE,KAAK,CAAA;KACd,KAAK,YAAY,CAAA;IAClB,WAAW,CAAC,EAAE,MAAM,CAAA;IACpB,cAAc,CAAC,EAAE,MAAM,CAAA;IACvB,gBAAgB,CAAC,EAAE,MAAM,CAAA;CAC1B,GAAG,OAAO,CAAC,IAAI,CAAC,CAwChB"}
@@ -0,0 +1,73 @@
1
+ import { handleZcapVerify, isRootInvocation } from '../zcap.js';
2
+ /**
3
+ * Verifies that the invocation is authorized by `controller` (the DID named
4
+ * in the request body). For the bare-root invocation form the signer *is* the
5
+ * invoker, so a mismatch is rejected up front, before any signature work. The
6
+ * delegated form instead carries a capability chain, judged by the
7
+ * verification (which synthesizes the root capability with `controller` as
8
+ * its controller): a delegated invocation that fails to verify is a chain not
9
+ * rooted in the body's controller, wrapped in `MismatchError` (spec
10
+ * `controller-mismatch`, 400). Root-form verification failures keep their
11
+ * generic errors -- the signer already matched the controller.
12
+ *
13
+ * @param options {object}
14
+ * @param options.request {FastifyRequest} supplies url, method, headers,
15
+ * logger, `request.zcap`, and `request.server` for serverUrl
16
+ * @param options.controller {IDID} the controller DID named in the request
17
+ * body, which must authorize the invocation
18
+ * @param options.allowedTarget {string} the capability's expected
19
+ * invocationTarget (full URL, including host and port)
20
+ * @param options.allowedAction {string} expected action, e.g. an HTTP verb
21
+ * @param options.MismatchError {new (options) => ProblemError} the
22
+ * operation's `controller-mismatch` error class (constructed with
23
+ * `{ zcapSigningDid, controller, cause? }`)
24
+ * @param [options.requestName] {string} human-readable request name, used
25
+ * in error titles
26
+ * @param [options.maxChainLength] {number} max delegation chain length,
27
+ * root included (see `verifyZcap`)
28
+ * @param [options.maxDelegationTtl] {number} max delegated-zcap TTL in
29
+ * milliseconds (see `verifyZcap`)
30
+ * @returns {Promise<void>}
31
+ */
32
+ export async function verifyBodyControllerConsent({ request, controller, allowedTarget, allowedAction, MismatchError, requestName, maxChainLength, maxDelegationTtl }) {
33
+ const { url, method, headers } = request;
34
+ const { serverUrl } = request.server;
35
+ // The strict `requireAuthHeaders` hook guarantees auth headers were present
36
+ // and `parseAuthHeaders` set `request.zcap` before any calling handler.
37
+ const { keyId, invocation } = request.zcap;
38
+ const [zcapSigningDid] = keyId.split('#');
39
+ const rootInvocation = isRootInvocation({ invocation });
40
+ if (rootInvocation && zcapSigningDid !== controller) {
41
+ throw new MismatchError({ zcapSigningDid: zcapSigningDid, controller });
42
+ }
43
+ try {
44
+ await handleZcapVerify({
45
+ url,
46
+ allowedTarget,
47
+ allowedAction,
48
+ method,
49
+ headers,
50
+ serverUrl,
51
+ spaceController: controller,
52
+ requestName,
53
+ logger: request.log,
54
+ // Consent verifies a chain rooted in the BODY's controller for a
55
+ // resource that does not exist yet, so there is no keystore or Space
56
+ // scope a revocation could have been stored under.
57
+ revocation: 'no-revocation-scope',
58
+ maxChainLength,
59
+ maxDelegationTtl
60
+ });
61
+ }
62
+ catch (err) {
63
+ if (!rootInvocation) {
64
+ throw new MismatchError({
65
+ zcapSigningDid: zcapSigningDid,
66
+ controller,
67
+ cause: err
68
+ });
69
+ }
70
+ throw err;
71
+ }
72
+ }
73
+ //# sourceMappingURL=controllerConsent.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"controllerConsent.js","sourceRoot":"","sources":["../../src/requests/controllerConsent.ts"],"names":[],"mappings":"AAWA,OAAO,EAAE,gBAAgB,EAAE,gBAAgB,EAAE,MAAM,YAAY,CAAA;AAI/D;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GA6BG;AACH,MAAM,CAAC,KAAK,UAAU,2BAA2B,CAAC,EAChD,OAAO,EACP,UAAU,EACV,aAAa,EACb,aAAa,EACb,aAAa,EACb,WAAW,EACX,cAAc,EACd,gBAAgB,EAcjB;IACC,MAAM,EAAE,GAAG,EAAE,MAAM,EAAE,OAAO,EAAE,GAAG,OAAO,CAAA;IACxC,MAAM,EAAE,SAAS,EAAE,GAAG,OAAO,CAAC,MAAM,CAAA;IACpC,4EAA4E;IAC5E,wEAAwE;IACxE,MAAM,EAAE,KAAK,EAAE,UAAU,EAAE,GAAG,OAAO,CAAC,IAAK,CAAA;IAC3C,MAAM,CAAC,cAAc,CAAC,GAAG,KAAK,CAAC,KAAK,CAAC,GAAG,CAAC,CAAA;IACzC,MAAM,cAAc,GAAG,gBAAgB,CAAC,EAAE,UAAU,EAAE,CAAC,CAAA;IACvD,IAAI,cAAc,IAAI,cAAc,KAAK,UAAU,EAAE,CAAC;QACpD,MAAM,IAAI,aAAa,CAAC,EAAE,cAAc,EAAE,cAAe,EAAE,UAAU,EAAE,CAAC,CAAA;IAC1E,CAAC;IAED,IAAI,CAAC;QACH,MAAM,gBAAgB,CAAC;YACrB,GAAG;YACH,aAAa;YACb,aAAa;YACb,MAAM;YACN,OAAO;YACP,SAAS;YACT,eAAe,EAAE,UAAU;YAC3B,WAAW;YACX,MAAM,EAAE,OAAO,CAAC,GAAG;YACnB,iEAAiE;YACjE,qEAAqE;YACrE,mDAAmD;YACnD,UAAU,EAAE,qBAAqB;YACjC,cAAc;YACd,gBAAgB;SACjB,CAAC,CAAA;IACJ,CAAC;IAAC,OAAO,GAAG,EAAE,CAAC;QACb,IAAI,CAAC,cAAc,EAAE,CAAC;YACpB,MAAM,IAAI,aAAa,CAAC;gBACtB,cAAc,EAAE,cAAe;gBAC/B,UAAU;gBACV,KAAK,EAAE,GAAY;aACpB,CAAC,CAAA;QACJ,CAAC;QACD,MAAM,GAAG,CAAA;IACX,CAAC;AACH,CAAC"}
@@ -0,0 +1,68 @@
1
+ /**
2
+ * Shared WebKMS keystore context helper (the `/kms` facet): the keystore
3
+ * analogue of `fetchSpaceAndVerify`
4
+ * (spaceContext.ts), used by the keystore-lifecycle, key-operation, and
5
+ * revocation request handlers.
6
+ */
7
+ import type { FastifyRequest } from 'fastify';
8
+ import type { KeystoreConfig } from '../types.js';
9
+ /**
10
+ * Loads a keystore config by its URL param, masking an unknown (or
11
+ * non-URL-safe) id as the 404 `KeystoreNotFoundError` -- the WAS
12
+ * existence-masking convention. The verification-free half of
13
+ * `fetchKeystoreAndVerify`, for handlers that need the config before they can
14
+ * build their expected values (the revocation route).
15
+ *
16
+ * @param options {object}
17
+ * @param options.request {FastifyRequest} supplies `request.server.storage`
18
+ * @param options.keystoreId {string} the keystore's local id (URL param)
19
+ * @param options.requestName {string} request name used in error titles
20
+ * @returns {Promise<KeystoreConfig>} the stored config
21
+ */
22
+ export declare function fetchKeystore({ request, keystoreId, requestName }: {
23
+ request: FastifyRequest;
24
+ keystoreId: string;
25
+ requestName: string;
26
+ }): Promise<KeystoreConfig>;
27
+ /**
28
+ * Loads the keystore config (404 `KeystoreNotFoundError` when absent -- the
29
+ * WAS existence-masking convention) and verifies the capability invocation
30
+ * against the *stored* config's controller, with the keystore URL as the root
31
+ * invocation target. `allowedAction` is the webkms action (`read` / `write` /
32
+ * an operation name), not the HTTP verb. The verification carries the unified
33
+ * `/kms` delegation policy (`KMS_MAX_CHAIN_LENGTH`, `KMS_MAX_DELEGATION_TTL`;
34
+ * the zcap library itself already requires `expires` on every delegated
35
+ * capability) and the keystore's revocation-store chain inspector, so a
36
+ * revoked delegation fails on every keystore-rooted route.
37
+ *
38
+ * @param options {object}
39
+ * @param options.request {FastifyRequest} supplies url, method, headers,
40
+ * logger, and `request.server` for serverUrl + storage
41
+ * @param options.keystoreId {string} the keystore's local id (URL param)
42
+ * @param options.allowedAction {string} expected zcap action
43
+ * @param options.requestName {string} request name used in error titles
44
+ * @param [options.allowTargetAttenuation] {boolean} accept a request URL
45
+ * under the keystore URL (the key routes: every key operation roots in the
46
+ * keystore's capability, with the key URL as an attenuated target -- see
47
+ * `verifyZcap`)
48
+ * @param [options.allowTargetQuery] {boolean} tolerate query parameters on
49
+ * the request URL that are absent from the capability target (the List Keys
50
+ * route's `?limit` / `?cursor` pagination parameters select a page within an
51
+ * already-authorized target; the same treatment as List Keystores)
52
+ * @returns {Promise<{ config: KeystoreConfig, dereferencedChainLength: number }>}
53
+ * the stored config and the verified invocation's chain length, root
54
+ * included (a root invocation is 1) -- the input to the per-key
55
+ * `maxCapabilityChainLength` gate at operation time
56
+ */
57
+ export declare function fetchKeystoreAndVerify({ request, keystoreId, allowedAction, requestName, allowTargetAttenuation, allowTargetQuery }: {
58
+ request: FastifyRequest;
59
+ keystoreId: string;
60
+ allowedAction: string;
61
+ requestName: string;
62
+ allowTargetAttenuation?: boolean;
63
+ allowTargetQuery?: boolean;
64
+ }): Promise<{
65
+ config: KeystoreConfig;
66
+ dereferencedChainLength: number;
67
+ }>;
68
+ //# sourceMappingURL=keystoreContext.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"keystoreContext.d.ts","sourceRoot":"","sources":["../../src/requests/keystoreContext.ts"],"names":[],"mappings":"AAAA;;;;;GAKG;AACH,OAAO,KAAK,EAAE,cAAc,EAAE,MAAM,SAAS,CAAA;AAS7C,OAAO,KAAK,EAAE,cAAc,EAAE,MAAM,aAAa,CAAA;AAEjD;;;;;;;;;;;;GAYG;AACH,wBAAsB,aAAa,CAAC,EAClC,OAAO,EACP,UAAU,EACV,WAAW,EACZ,EAAE;IACD,OAAO,EAAE,cAAc,CAAA;IACvB,UAAU,EAAE,MAAM,CAAA;IAClB,WAAW,EAAE,MAAM,CAAA;CACpB,GAAG,OAAO,CAAC,cAAc,CAAC,CAW1B;AAED;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GA6BG;AACH,wBAAsB,sBAAsB,CAAC,EAC3C,OAAO,EACP,UAAU,EACV,aAAa,EACb,WAAW,EACX,sBAA8B,EAC9B,gBAAwB,EACzB,EAAE;IACD,OAAO,EAAE,cAAc,CAAA;IACvB,UAAU,EAAE,MAAM,CAAA;IAClB,aAAa,EAAE,MAAM,CAAA;IACrB,WAAW,EAAE,MAAM,CAAA;IACnB,sBAAsB,CAAC,EAAE,OAAO,CAAA;IAChC,gBAAgB,CAAC,EAAE,OAAO,CAAA;CAC3B,GAAG,OAAO,CAAC;IAAE,MAAM,EAAE,cAAc,CAAC;IAAC,uBAAuB,EAAE,MAAM,CAAA;CAAE,CAAC,CA4BvE"}
@@ -0,0 +1,87 @@
1
+ import { handleZcapVerify } from '../zcap.js';
2
+ import { isUrlSafeSegment } from '../lib/validateId.js';
3
+ import { kmsKeystoresPath } from '../lib/paths.js';
4
+ import { KMS_MAX_CHAIN_LENGTH, KMS_MAX_DELEGATION_TTL } from '../config.default.js';
5
+ import { KeystoreNotFoundError } from '../errors.js';
6
+ /**
7
+ * Loads a keystore config by its URL param, masking an unknown (or
8
+ * non-URL-safe) id as the 404 `KeystoreNotFoundError` -- the WAS
9
+ * existence-masking convention. The verification-free half of
10
+ * `fetchKeystoreAndVerify`, for handlers that need the config before they can
11
+ * build their expected values (the revocation route).
12
+ *
13
+ * @param options {object}
14
+ * @param options.request {FastifyRequest} supplies `request.server.storage`
15
+ * @param options.keystoreId {string} the keystore's local id (URL param)
16
+ * @param options.requestName {string} request name used in error titles
17
+ * @returns {Promise<KeystoreConfig>} the stored config
18
+ */
19
+ export async function fetchKeystore({ request, keystoreId, requestName }) {
20
+ // A non-URL-safe id cannot name a stored keystore (ids are server-generated
21
+ // base58 values) and must not reach the filesystem layer: same 404 masking.
22
+ if (!isUrlSafeSegment(keystoreId)) {
23
+ throw new KeystoreNotFoundError({ requestName });
24
+ }
25
+ const config = await request.server.storage.getKeystore({ keystoreId });
26
+ if (!config) {
27
+ throw new KeystoreNotFoundError({ requestName });
28
+ }
29
+ return config;
30
+ }
31
+ /**
32
+ * Loads the keystore config (404 `KeystoreNotFoundError` when absent -- the
33
+ * WAS existence-masking convention) and verifies the capability invocation
34
+ * against the *stored* config's controller, with the keystore URL as the root
35
+ * invocation target. `allowedAction` is the webkms action (`read` / `write` /
36
+ * an operation name), not the HTTP verb. The verification carries the unified
37
+ * `/kms` delegation policy (`KMS_MAX_CHAIN_LENGTH`, `KMS_MAX_DELEGATION_TTL`;
38
+ * the zcap library itself already requires `expires` on every delegated
39
+ * capability) and the keystore's revocation-store chain inspector, so a
40
+ * revoked delegation fails on every keystore-rooted route.
41
+ *
42
+ * @param options {object}
43
+ * @param options.request {FastifyRequest} supplies url, method, headers,
44
+ * logger, and `request.server` for serverUrl + storage
45
+ * @param options.keystoreId {string} the keystore's local id (URL param)
46
+ * @param options.allowedAction {string} expected zcap action
47
+ * @param options.requestName {string} request name used in error titles
48
+ * @param [options.allowTargetAttenuation] {boolean} accept a request URL
49
+ * under the keystore URL (the key routes: every key operation roots in the
50
+ * keystore's capability, with the key URL as an attenuated target -- see
51
+ * `verifyZcap`)
52
+ * @param [options.allowTargetQuery] {boolean} tolerate query parameters on
53
+ * the request URL that are absent from the capability target (the List Keys
54
+ * route's `?limit` / `?cursor` pagination parameters select a page within an
55
+ * already-authorized target; the same treatment as List Keystores)
56
+ * @returns {Promise<{ config: KeystoreConfig, dereferencedChainLength: number }>}
57
+ * the stored config and the verified invocation's chain length, root
58
+ * included (a root invocation is 1) -- the input to the per-key
59
+ * `maxCapabilityChainLength` gate at operation time
60
+ */
61
+ export async function fetchKeystoreAndVerify({ request, keystoreId, allowedAction, requestName, allowTargetAttenuation = false, allowTargetQuery = false }) {
62
+ const { serverUrl, storage } = request.server;
63
+ const config = await fetchKeystore({ request, keystoreId, requestName });
64
+ const { url, method, headers } = request;
65
+ const allowedTarget = new URL(kmsKeystoresPath({ keystoreId }), serverUrl).toString();
66
+ const zcapVerifyResult = await handleZcapVerify({
67
+ url,
68
+ allowedTarget,
69
+ allowedAction,
70
+ method,
71
+ headers,
72
+ serverUrl,
73
+ spaceController: config.controller,
74
+ requestName,
75
+ logger: request.log,
76
+ allowTargetAttenuation,
77
+ allowTargetQuery,
78
+ revocation: { storage, scope: { keystoreId } },
79
+ maxChainLength: KMS_MAX_CHAIN_LENGTH,
80
+ maxDelegationTtl: KMS_MAX_DELEGATION_TTL
81
+ });
82
+ return {
83
+ config,
84
+ dereferencedChainLength: zcapVerifyResult.dereferencedChain?.length ?? 1
85
+ };
86
+ }
87
+ //# sourceMappingURL=keystoreContext.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"keystoreContext.js","sourceRoot":"","sources":["../../src/requests/keystoreContext.ts"],"names":[],"mappings":"AAOA,OAAO,EAAE,gBAAgB,EAAE,MAAM,YAAY,CAAA;AAC7C,OAAO,EAAE,gBAAgB,EAAE,MAAM,sBAAsB,CAAA;AACvD,OAAO,EAAE,gBAAgB,EAAE,MAAM,iBAAiB,CAAA;AAClD,OAAO,EACL,oBAAoB,EACpB,sBAAsB,EACvB,MAAM,sBAAsB,CAAA;AAC7B,OAAO,EAAE,qBAAqB,EAAE,MAAM,cAAc,CAAA;AAGpD;;;;;;;;;;;;GAYG;AACH,MAAM,CAAC,KAAK,UAAU,aAAa,CAAC,EAClC,OAAO,EACP,UAAU,EACV,WAAW,EAKZ;IACC,4EAA4E;IAC5E,4EAA4E;IAC5E,IAAI,CAAC,gBAAgB,CAAC,UAAU,CAAC,EAAE,CAAC;QAClC,MAAM,IAAI,qBAAqB,CAAC,EAAE,WAAW,EAAE,CAAC,CAAA;IAClD,CAAC;IACD,MAAM,MAAM,GAAG,MAAM,OAAO,CAAC,MAAM,CAAC,OAAO,CAAC,WAAW,CAAC,EAAE,UAAU,EAAE,CAAC,CAAA;IACvE,IAAI,CAAC,MAAM,EAAE,CAAC;QACZ,MAAM,IAAI,qBAAqB,CAAC,EAAE,WAAW,EAAE,CAAC,CAAA;IAClD,CAAC;IACD,OAAO,MAAM,CAAA;AACf,CAAC;AAED;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GA6BG;AACH,MAAM,CAAC,KAAK,UAAU,sBAAsB,CAAC,EAC3C,OAAO,EACP,UAAU,EACV,aAAa,EACb,WAAW,EACX,sBAAsB,GAAG,KAAK,EAC9B,gBAAgB,GAAG,KAAK,EAQzB;IACC,MAAM,EAAE,SAAS,EAAE,OAAO,EAAE,GAAG,OAAO,CAAC,MAAM,CAAA;IAC7C,MAAM,MAAM,GAAG,MAAM,aAAa,CAAC,EAAE,OAAO,EAAE,UAAU,EAAE,WAAW,EAAE,CAAC,CAAA;IACxE,MAAM,EAAE,GAAG,EAAE,MAAM,EAAE,OAAO,EAAE,GAAG,OAAO,CAAA;IACxC,MAAM,aAAa,GAAG,IAAI,GAAG,CAC3B,gBAAgB,CAAC,EAAE,UAAU,EAAE,CAAC,EAChC,SAAS,CACV,CAAC,QAAQ,EAAE,CAAA;IACZ,MAAM,gBAAgB,GAAG,MAAM,gBAAgB,CAAC;QAC9C,GAAG;QACH,aAAa;QACb,aAAa;QACb,MAAM;QACN,OAAO;QACP,SAAS;QACT,eAAe,EAAE,MAAM,CAAC,UAAU;QAClC,WAAW;QACX,MAAM,EAAE,OAAO,CAAC,GAAG;QACnB,sBAAsB;QACtB,gBAAgB;QAChB,UAAU,EAAE,EAAE,OAAO,EAAE,KAAK,EAAE,EAAE,UAAU,EAAE,EAAE;QAC9C,cAAc,EAAE,oBAAoB;QACpC,gBAAgB,EAAE,sBAAsB;KACzC,CAAC,CAAA;IACF,OAAO;QACL,MAAM;QACN,uBAAuB,EAAE,gBAAgB,CAAC,iBAAiB,EAAE,MAAM,IAAI,CAAC;KACzE,CAAA;AACH,CAAC"}
@@ -0,0 +1,19 @@
1
+ /**
2
+ * Request-layer adapter: resolves a Fastify request into a transport-neutral
3
+ * `ResourceInput` value object, so that storage backends never depend on
4
+ * Fastify. JSON bodies pass through as parsed values; raw blob bodies and
5
+ * multipart uploads are normalized to a readable byte stream.
6
+ */
7
+ import type { FastifyRequest } from 'fastify';
8
+ import type { ResourceInput, StorageBackend } from '../types.js';
9
+ /**
10
+ * @param request {import('fastify').FastifyRequest}
11
+ * @param [dataBackend] {StorageBackend} the resolved data-plane backend the
12
+ * write targets (the Collection's selected backend); its `maxUploadBytes` and
13
+ * `describe().id` size and label the `payload-too-large` (413) for a multipart
14
+ * upload. Defaults to the server `storage` backend, read lazily only on the
15
+ * multipart path so non-multipart callers need not supply it.
16
+ * @returns {Promise<ResourceInput>}
17
+ */
18
+ export declare function resolveResourceInput(request: FastifyRequest, dataBackend?: StorageBackend): Promise<ResourceInput>;
19
+ //# sourceMappingURL=resourceInput.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"resourceInput.d.ts","sourceRoot":"","sources":["../../src/requests/resourceInput.ts"],"names":[],"mappings":"AAAA;;;;;GAKG;AACH,OAAO,KAAK,EAAE,cAAc,EAAE,MAAM,SAAS,CAAA;AAQ7C,OAAO,KAAK,EAAE,aAAa,EAAE,cAAc,EAAE,MAAM,aAAa,CAAA;AAEhE;;;;;;;;GAQG;AACH,wBAAsB,oBAAoB,CACxC,OAAO,EAAE,cAAc,EACvB,WAAW,CAAC,EAAE,cAAc,GAC3B,OAAO,CAAC,aAAa,CAAC,CAyFxB"}