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,311 @@
1
+ /**
2
+ * Shared handler prelude: fetch a Space (for its controller) and authorize the
3
+ * request against a target. Nearly every handler repeats the same shape -- load
4
+ * the Space Description to get the controller key, build the capability's
5
+ * `invocationTarget` URL, then check authorization -- so it lives here.
6
+ *
7
+ * Two entry points, one per authorization model, so the call site names which it
8
+ * uses (rather than passing a flag):
9
+ *
10
+ * - `fetchSpaceAndAuthorize` -- **capability-or-policy**: capability invocation
11
+ * first, then the target's effective access-control policy as a fallback. For
12
+ * read/list endpoints that may be public-readable.
13
+ * - `fetchSpaceAndVerify` -- **capability-only**: capability invocation, no
14
+ * policy fallback. For write/privileged endpoints and the controller-managed
15
+ * policy resource.
16
+ */
17
+ import type { FastifyRequest } from 'fastify'
18
+ import { LruCache } from '@interop/lru-memoize'
19
+ import { handleZcapVerify } from '../zcap.js'
20
+ import { authorize } from '../authorize.js'
21
+ import { spacePath } from '../lib/paths.js'
22
+ import { isUrlSafeSegment } from '../lib/validateId.js'
23
+ import { SpaceNotFoundError } from '../errors.js'
24
+ import {
25
+ SPACE_DESCRIPTION_CACHE_MAX,
26
+ SPACE_DESCRIPTION_CACHE_TTL
27
+ } from '../config.default.js'
28
+ import type { IDID, SpaceDescription, StorageBackend } from '../types.js'
29
+
30
+ /**
31
+ * One short-TTL memoization cache per storage backend, keyed by `spaceId`. The
32
+ * cache is scoped to the backend instance (rather than module-global) via a
33
+ * WeakMap so two backends in one process -- e.g. parallel test suites -- never
34
+ * serve each other's descriptions, and a cache is discarded with its backend.
35
+ */
36
+ const descriptionCaches = new WeakMap<StorageBackend, LruCache>()
37
+
38
+ /**
39
+ * Returns the (lazily created) Space Description cache for a backend.
40
+ * @param storage {StorageBackend}
41
+ * @returns {LruCache}
42
+ */
43
+ function descriptionCacheFor(storage: StorageBackend): LruCache {
44
+ let cache = descriptionCaches.get(storage)
45
+ if (!cache) {
46
+ cache = new LruCache({
47
+ max: SPACE_DESCRIPTION_CACHE_MAX,
48
+ ttl: SPACE_DESCRIPTION_CACHE_TTL
49
+ })
50
+ descriptionCaches.set(storage, cache)
51
+ }
52
+ return cache
53
+ }
54
+
55
+ /**
56
+ * Drops the cached Space Description for a Space. Call after any write that
57
+ * changes (or removes) it -- create/update/delete -- so the next read reflects
58
+ * the new state rather than a stale cached one.
59
+ * @param options {object}
60
+ * @param options.storage {StorageBackend} the request's storage backend
61
+ * @param options.spaceId {string}
62
+ * @returns {void}
63
+ */
64
+ export function invalidateSpaceDescription({
65
+ storage,
66
+ spaceId
67
+ }: {
68
+ storage: StorageBackend
69
+ spaceId: string
70
+ }): void {
71
+ // Only touch a cache that already exists for this backend.
72
+ descriptionCaches.get(storage)?.delete(spaceId)
73
+ }
74
+
75
+ /**
76
+ * Fetches a Space Description or throws SpaceNotFoundError (404) when absent.
77
+ * Memoized per storage backend (short TTL) because this is read on every
78
+ * authorized handler; writes invalidate via `invalidateSpaceDescription`.
79
+ * @param options {object}
80
+ * @param options.storage {StorageBackend} the request's storage backend
81
+ * @param options.spaceId {string}
82
+ * @param options.requestName {string} human-readable request name, used in
83
+ * error titles
84
+ * @returns {Promise<SpaceDescription>}
85
+ */
86
+ async function getSpaceDescriptionOrThrow({
87
+ storage,
88
+ spaceId,
89
+ requestName
90
+ }: {
91
+ storage: StorageBackend
92
+ spaceId: string
93
+ requestName: string
94
+ }): Promise<SpaceDescription> {
95
+ const spaceDescription = await descriptionCacheFor(storage).memoize<
96
+ SpaceDescription | undefined
97
+ >({
98
+ key: spaceId,
99
+ fn: () => storage.getSpaceDescription({ spaceId })
100
+ })
101
+ if (!spaceDescription) {
102
+ throw new SpaceNotFoundError({ requestName })
103
+ }
104
+ return spaceDescription
105
+ }
106
+
107
+ /**
108
+ * Loads a Space Description by its URL param, masking an unknown (or
109
+ * non-URL-safe) id as the 404 `SpaceNotFoundError` -- the WAS
110
+ * existence-masking convention. The verification-free half of
111
+ * `fetchSpaceAndVerify`, for handlers that need the controller before they can
112
+ * build their expected values (the revocation route, whose invocation verifies
113
+ * under the dual-root rule rather than the usual single root). The Space
114
+ * analogue of `fetchKeystore` (keystoreContext.ts).
115
+ *
116
+ * @param options {object}
117
+ * @param options.request {FastifyRequest} supplies `request.server.storage`
118
+ * @param options.spaceId {string}
119
+ * @param options.requestName {string} human-readable request name, used in
120
+ * error titles
121
+ * @returns {Promise<SpaceDescription>}
122
+ */
123
+ export async function fetchSpace({
124
+ request,
125
+ spaceId,
126
+ requestName
127
+ }: {
128
+ request: FastifyRequest
129
+ spaceId: string
130
+ requestName: string
131
+ }): Promise<SpaceDescription> {
132
+ // A non-URL-safe id cannot name a stored Space and must not reach the
133
+ // filesystem layer: same 404 masking.
134
+ if (!isUrlSafeSegment(spaceId)) {
135
+ throw new SpaceNotFoundError({ requestName })
136
+ }
137
+ return await getSpaceDescriptionOrThrow({
138
+ storage: request.server.storage,
139
+ spaceId,
140
+ requestName
141
+ })
142
+ }
143
+
144
+ /** The verified context every handler builds before touching storage. */
145
+ export interface VerifiedSpaceContext {
146
+ /** the fetched Space Description (its controller authorized the request) */
147
+ spaceDescription: SpaceDescription
148
+ /** the did:key that controls the Space */
149
+ spaceController: IDID
150
+ /** the resolved invocationTarget URL the request was authorized against */
151
+ allowedTarget: string
152
+ /**
153
+ * the Space's own URL -- the ancestor root target every space-family route
154
+ * also accepts for a delegated chain that attenuates down to the request
155
+ * URL (a Space- or Collection-scoped capability delegated by the controller)
156
+ */
157
+ spaceRootTarget: string
158
+ }
159
+
160
+ /**
161
+ * Loads the Space and builds the capability's invocationTarget URL -- the part
162
+ * shared by both authorization models below. Does not check authorization.
163
+ *
164
+ * @param options {object}
165
+ * @param options.request {FastifyRequest} supplies `request.server` for
166
+ * serverUrl + storage
167
+ * @param options.spaceId {string}
168
+ * @param options.targetPath {string} the relative path of the capability's
169
+ * invocationTarget, resolved against serverUrl (e.g. `/space/${spaceId}`)
170
+ * @param options.requestName {string} human-readable request name, used in
171
+ * error titles
172
+ * @returns {Promise<VerifiedSpaceContext>}
173
+ */
174
+ async function fetchSpaceContext({
175
+ request,
176
+ spaceId,
177
+ targetPath,
178
+ requestName
179
+ }: {
180
+ request: FastifyRequest
181
+ spaceId: string
182
+ targetPath: string
183
+ requestName: string
184
+ }): Promise<VerifiedSpaceContext> {
185
+ const { serverUrl, storage } = request.server
186
+ const spaceDescription = await getSpaceDescriptionOrThrow({
187
+ storage,
188
+ spaceId,
189
+ requestName
190
+ })
191
+ const spaceController = spaceDescription.controller
192
+ const allowedTarget = new URL(targetPath, serverUrl).toString()
193
+ const spaceRootTarget = new URL(spacePath({ spaceId }), serverUrl).toString()
194
+ return { spaceDescription, spaceController, allowedTarget, spaceRootTarget }
195
+ }
196
+
197
+ /**
198
+ * Fetches the Space and AUTHORIZES the request **capability-or-policy**:
199
+ * capability invocation first, then the target's effective access-control policy
200
+ * as a fallback (see authorize.ts). Use for read/list endpoints that may be
201
+ * public-readable. The action checked is the request's HTTP method. Returns the
202
+ * fetched Space Description so callers that also serve it (e.g. "Read Space")
203
+ * need not fetch it twice.
204
+ *
205
+ * @param options {object}
206
+ * @param options.request {FastifyRequest} supplies url, method, headers,
207
+ * logger, and `request.server` for serverUrl + storage
208
+ * @param options.spaceId {string}
209
+ * @param [options.collectionId] {string} policy-resolution level
210
+ * @param [options.resourceId] {string} policy-resolution level
211
+ * @param options.targetPath {string} the relative path of the capability's
212
+ * invocationTarget, resolved against serverUrl (e.g. `/space/${spaceId}`)
213
+ * @param options.requestName {string} human-readable request name, used in
214
+ * error titles
215
+ * @returns {Promise<VerifiedSpaceContext>}
216
+ */
217
+ export async function fetchSpaceAndAuthorize({
218
+ request,
219
+ spaceId,
220
+ collectionId,
221
+ resourceId,
222
+ targetPath,
223
+ requestName,
224
+ allowTargetQuery = false
225
+ }: {
226
+ request: FastifyRequest
227
+ spaceId: string
228
+ collectionId?: string
229
+ resourceId?: string
230
+ targetPath: string
231
+ requestName: string
232
+ /**
233
+ * When set, the capability-invocation path tolerates query parameters on
234
+ * the request URL that extend `targetPath` (e.g. List Collection's
235
+ * `?limit`/`cursor`), treating them as a RESTful attenuation of the same
236
+ * target rather than a different one. See `verifyZcap`.
237
+ */
238
+ allowTargetQuery?: boolean
239
+ }): Promise<VerifiedSpaceContext> {
240
+ const context = await fetchSpaceContext({
241
+ request,
242
+ spaceId,
243
+ targetPath,
244
+ requestName
245
+ })
246
+ await authorize({
247
+ request,
248
+ allowedTarget: context.allowedTarget,
249
+ spaceId,
250
+ collectionId,
251
+ resourceId,
252
+ spaceController: context.spaceController,
253
+ requestName,
254
+ allowTargetQuery,
255
+ attenuatedRootTarget: context.spaceRootTarget
256
+ })
257
+ return context
258
+ }
259
+
260
+ /**
261
+ * Fetches the Space and VERIFIES the request **capability-only**: a valid
262
+ * capability invocation is required, with no access-control-policy fallback (see
263
+ * zcap.ts). Use for write/privileged endpoints and the controller-managed policy
264
+ * resource. The action checked is the request's HTTP method. The Space's
265
+ * revocation store is consulted on every delegated chain, so a revoked
266
+ * capability fails here as it does on the `/kms` routes.
267
+ *
268
+ * @param options {object}
269
+ * @param options.request {FastifyRequest} supplies url, method, headers,
270
+ * logger, and `request.server` for serverUrl + storage
271
+ * @param options.spaceId {string}
272
+ * @param options.targetPath {string} the relative path of the capability's
273
+ * invocationTarget, resolved against serverUrl (e.g. `/space/${spaceId}`)
274
+ * @param options.requestName {string} human-readable request name, used in
275
+ * error titles
276
+ * @returns {Promise<VerifiedSpaceContext>}
277
+ */
278
+ export async function fetchSpaceAndVerify({
279
+ request,
280
+ spaceId,
281
+ targetPath,
282
+ requestName
283
+ }: {
284
+ request: FastifyRequest
285
+ spaceId: string
286
+ targetPath: string
287
+ requestName: string
288
+ }): Promise<VerifiedSpaceContext> {
289
+ const context = await fetchSpaceContext({
290
+ request,
291
+ spaceId,
292
+ targetPath,
293
+ requestName
294
+ })
295
+ const { url, method, headers } = request
296
+ const { serverUrl, storage } = request.server
297
+ await handleZcapVerify({
298
+ url,
299
+ allowedTarget: context.allowedTarget,
300
+ allowedAction: method,
301
+ method,
302
+ headers,
303
+ serverUrl,
304
+ spaceController: context.spaceController,
305
+ requestName,
306
+ logger: request.log,
307
+ attenuatedRootTarget: context.spaceRootTarget,
308
+ revocation: { storage, scope: { spaceId } }
309
+ })
310
+ return context
311
+ }