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.
- package/CHANGELOG.md +1432 -0
- package/LICENSE +661 -0
- package/README.md +305 -0
- package/common/css/materialize.1.0.0.min.css +13 -0
- package/dist/auth-header-hooks.d.ts +84 -0
- package/dist/auth-header-hooks.d.ts.map +1 -0
- package/dist/auth-header-hooks.js +136 -0
- package/dist/auth-header-hooks.js.map +1 -0
- package/dist/authorize.d.ts +45 -0
- package/dist/authorize.d.ts.map +1 -0
- package/dist/authorize.js +76 -0
- package/dist/authorize.js.map +1 -0
- package/dist/backends/filesystem.d.ts +1179 -0
- package/dist/backends/filesystem.d.ts.map +1 -0
- package/dist/backends/filesystem.js +2727 -0
- package/dist/backends/filesystem.js.map +1 -0
- package/dist/backends/postgres.d.ts +833 -0
- package/dist/backends/postgres.d.ts.map +1 -0
- package/dist/backends/postgres.js +2164 -0
- package/dist/backends/postgres.js.map +1 -0
- package/dist/backends/postgresSchema.d.ts +36 -0
- package/dist/backends/postgresSchema.d.ts.map +1 -0
- package/dist/backends/postgresSchema.js +203 -0
- package/dist/backends/postgresSchema.js.map +1 -0
- package/dist/config.default.d.ts +360 -0
- package/dist/config.default.d.ts.map +1 -0
- package/dist/config.default.js +493 -0
- package/dist/config.default.js.map +1 -0
- package/dist/corsProxy.d.ts +45 -0
- package/dist/corsProxy.d.ts.map +1 -0
- package/dist/corsProxy.js +278 -0
- package/dist/corsProxy.js.map +1 -0
- package/dist/digest.d.ts +45 -0
- package/dist/digest.d.ts.map +1 -0
- package/dist/digest.js +174 -0
- package/dist/digest.js.map +1 -0
- package/dist/errors.d.ts +654 -0
- package/dist/errors.d.ts.map +1 -0
- package/dist/errors.js +960 -0
- package/dist/errors.js.map +1 -0
- package/dist/index.d.ts +22 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +21 -0
- package/dist/index.js.map +1 -0
- package/dist/lib/atomicFile.d.ts +61 -0
- package/dist/lib/atomicFile.d.ts.map +1 -0
- package/dist/lib/atomicFile.js +150 -0
- package/dist/lib/atomicFile.js.map +1 -0
- package/dist/lib/backendRegistry.d.ts +59 -0
- package/dist/lib/backendRegistry.d.ts.map +1 -0
- package/dist/lib/backendRegistry.js +92 -0
- package/dist/lib/backendRegistry.js.map +1 -0
- package/dist/lib/backendUsage.d.ts +28 -0
- package/dist/lib/backendUsage.d.ts.map +1 -0
- package/dist/lib/backendUsage.js +55 -0
- package/dist/lib/backendUsage.js.map +1 -0
- package/dist/lib/backends.d.ts +142 -0
- package/dist/lib/backends.d.ts.map +1 -0
- package/dist/lib/backends.js +272 -0
- package/dist/lib/backends.js.map +1 -0
- package/dist/lib/blindedIndex.d.ts +156 -0
- package/dist/lib/blindedIndex.d.ts.map +1 -0
- package/dist/lib/blindedIndex.js +338 -0
- package/dist/lib/blindedIndex.js.map +1 -0
- package/dist/lib/collectionDescription.d.ts +33 -0
- package/dist/lib/collectionDescription.d.ts.map +1 -0
- package/dist/lib/collectionDescription.js +21 -0
- package/dist/lib/collectionDescription.js.map +1 -0
- package/dist/lib/cursor.d.ts +18 -0
- package/dist/lib/cursor.d.ts.map +1 -0
- package/dist/lib/cursor.js +50 -0
- package/dist/lib/cursor.js.map +1 -0
- package/dist/lib/edvEnvelope.d.ts +50 -0
- package/dist/lib/edvEnvelope.d.ts.map +1 -0
- package/dist/lib/edvEnvelope.js +106 -0
- package/dist/lib/edvEnvelope.js.map +1 -0
- package/dist/lib/encryption.d.ts +192 -0
- package/dist/lib/encryption.d.ts.map +1 -0
- package/dist/lib/encryption.js +383 -0
- package/dist/lib/encryption.js.map +1 -0
- package/dist/lib/etag.d.ts +33 -0
- package/dist/lib/etag.d.ts.map +1 -0
- package/dist/lib/etag.js +36 -0
- package/dist/lib/etag.js.map +1 -0
- package/dist/lib/exportManifest.d.ts +29 -0
- package/dist/lib/exportManifest.d.ts.map +1 -0
- package/dist/lib/exportManifest.js +77 -0
- package/dist/lib/exportManifest.js.map +1 -0
- package/dist/lib/importTar.d.ts +81 -0
- package/dist/lib/importTar.d.ts.map +1 -0
- package/dist/lib/importTar.js +301 -0
- package/dist/lib/importTar.js.map +1 -0
- package/dist/lib/isJson.d.ts +16 -0
- package/dist/lib/isJson.d.ts.map +1 -0
- package/dist/lib/isJson.js +17 -0
- package/dist/lib/isJson.js.map +1 -0
- package/dist/lib/keyEpoch.d.ts +38 -0
- package/dist/lib/keyEpoch.d.ts.map +1 -0
- package/dist/lib/keyEpoch.js +75 -0
- package/dist/lib/keyEpoch.js.map +1 -0
- package/dist/lib/keyedMutex.d.ts +28 -0
- package/dist/lib/keyedMutex.d.ts.map +1 -0
- package/dist/lib/keyedMutex.js +45 -0
- package/dist/lib/keyedMutex.js.map +1 -0
- package/dist/lib/kmsModule.d.ts +62 -0
- package/dist/lib/kmsModule.d.ts.map +1 -0
- package/dist/lib/kmsModule.js +327 -0
- package/dist/lib/kmsModule.js.map +1 -0
- package/dist/lib/kmsRecordCipher.d.ts +82 -0
- package/dist/lib/kmsRecordCipher.d.ts.map +1 -0
- package/dist/lib/kmsRecordCipher.js +226 -0
- package/dist/lib/kmsRecordCipher.js.map +1 -0
- package/dist/lib/pagination.d.ts +19 -0
- package/dist/lib/pagination.d.ts.map +1 -0
- package/dist/lib/pagination.js +21 -0
- package/dist/lib/pagination.js.map +1 -0
- package/dist/lib/paths.d.ts +273 -0
- package/dist/lib/paths.d.ts.map +1 -0
- package/dist/lib/paths.js +270 -0
- package/dist/lib/paths.js.map +1 -0
- package/dist/lib/preconditions.d.ts +65 -0
- package/dist/lib/preconditions.d.ts.map +1 -0
- package/dist/lib/preconditions.js +112 -0
- package/dist/lib/preconditions.js.map +1 -0
- package/dist/lib/resourceFileName.d.ts +41 -0
- package/dist/lib/resourceFileName.d.ts.map +1 -0
- package/dist/lib/resourceFileName.js +58 -0
- package/dist/lib/resourceFileName.js.map +1 -0
- package/dist/lib/revocations.d.ts +49 -0
- package/dist/lib/revocations.d.ts.map +1 -0
- package/dist/lib/revocations.js +86 -0
- package/dist/lib/revocations.js.map +1 -0
- package/dist/lib/validateDid.d.ts +19 -0
- package/dist/lib/validateDid.d.ts.map +1 -0
- package/dist/lib/validateDid.js +35 -0
- package/dist/lib/validateDid.js.map +1 -0
- package/dist/lib/validateId.d.ts +66 -0
- package/dist/lib/validateId.d.ts.map +1 -0
- package/dist/lib/validateId.js +126 -0
- package/dist/lib/validateId.js.map +1 -0
- package/dist/plugin.d.ts +115 -0
- package/dist/plugin.d.ts.map +1 -0
- package/dist/plugin.js +134 -0
- package/dist/plugin.js.map +1 -0
- package/dist/policy.d.ts +78 -0
- package/dist/policy.d.ts.map +1 -0
- package/dist/policy.js +115 -0
- package/dist/policy.js.map +1 -0
- package/dist/provisioning.d.ts +38 -0
- package/dist/provisioning.d.ts.map +1 -0
- package/dist/provisioning.js +72 -0
- package/dist/provisioning.js.map +1 -0
- package/dist/requests/BackendRequest.d.ts +61 -0
- package/dist/requests/BackendRequest.d.ts.map +1 -0
- package/dist/requests/BackendRequest.js +152 -0
- package/dist/requests/BackendRequest.js.map +1 -0
- package/dist/requests/CollectionRequest.d.ts +234 -0
- package/dist/requests/CollectionRequest.d.ts.map +1 -0
- package/dist/requests/CollectionRequest.js +705 -0
- package/dist/requests/CollectionRequest.js.map +1 -0
- package/dist/requests/KeyRequest.d.ts +115 -0
- package/dist/requests/KeyRequest.d.ts.map +1 -0
- package/dist/requests/KeyRequest.js +468 -0
- package/dist/requests/KeyRequest.js.map +1 -0
- package/dist/requests/KeystoreRequest.d.ts +99 -0
- package/dist/requests/KeystoreRequest.d.ts.map +1 -0
- package/dist/requests/KeystoreRequest.js +247 -0
- package/dist/requests/KeystoreRequest.js.map +1 -0
- package/dist/requests/PolicyRequest.d.ts +53 -0
- package/dist/requests/PolicyRequest.d.ts.map +1 -0
- package/dist/requests/PolicyRequest.js +124 -0
- package/dist/requests/PolicyRequest.js.map +1 -0
- package/dist/requests/ResourceRequest.d.ts +134 -0
- package/dist/requests/ResourceRequest.d.ts.map +1 -0
- package/dist/requests/ResourceRequest.js +548 -0
- package/dist/requests/ResourceRequest.js.map +1 -0
- package/dist/requests/RevocationRequest.d.ts +67 -0
- package/dist/requests/RevocationRequest.d.ts.map +1 -0
- package/dist/requests/RevocationRequest.js +187 -0
- package/dist/requests/RevocationRequest.js.map +1 -0
- package/dist/requests/SpaceRequest.d.ts +204 -0
- package/dist/requests/SpaceRequest.d.ts.map +1 -0
- package/dist/requests/SpaceRequest.js +520 -0
- package/dist/requests/SpaceRequest.js.map +1 -0
- package/dist/requests/SpacesRepositoryRequest.d.ts +50 -0
- package/dist/requests/SpacesRepositoryRequest.d.ts.map +1 -0
- package/dist/requests/SpacesRepositoryRequest.js +159 -0
- package/dist/requests/SpacesRepositoryRequest.js.map +1 -0
- package/dist/requests/collectionContext.d.ts +21 -0
- package/dist/requests/collectionContext.d.ts.map +1 -0
- package/dist/requests/collectionContext.js +30 -0
- package/dist/requests/collectionContext.js.map +1 -0
- package/dist/requests/controllerConsent.d.ts +58 -0
- package/dist/requests/controllerConsent.d.ts.map +1 -0
- package/dist/requests/controllerConsent.js +73 -0
- package/dist/requests/controllerConsent.js.map +1 -0
- package/dist/requests/keystoreContext.d.ts +68 -0
- package/dist/requests/keystoreContext.d.ts.map +1 -0
- package/dist/requests/keystoreContext.js +87 -0
- package/dist/requests/keystoreContext.js.map +1 -0
- package/dist/requests/resourceInput.d.ts +19 -0
- package/dist/requests/resourceInput.d.ts.map +1 -0
- package/dist/requests/resourceInput.js +102 -0
- package/dist/requests/resourceInput.js.map +1 -0
- package/dist/requests/spaceContext.d.ts +127 -0
- package/dist/requests/spaceContext.d.ts.map +1 -0
- package/dist/requests/spaceContext.js +201 -0
- package/dist/requests/spaceContext.js.map +1 -0
- package/dist/routes.d.ts +55 -0
- package/dist/routes.d.ts.map +1 -0
- package/dist/routes.js +306 -0
- package/dist/routes.js.map +1 -0
- package/dist/server.d.ts +20 -0
- package/dist/server.d.ts.map +1 -0
- package/dist/server.js +60 -0
- package/dist/server.js.map +1 -0
- package/dist/start.d.ts +7 -0
- package/dist/start.d.ts.map +1 -0
- package/dist/start.js +61 -0
- package/dist/start.js.map +1 -0
- package/dist/storage.d.ts +29 -0
- package/dist/storage.d.ts.map +1 -0
- package/dist/storage.js +47 -0
- package/dist/storage.js.map +1 -0
- package/dist/types.d.ts +915 -0
- package/dist/types.d.ts.map +1 -0
- package/dist/types.js +2 -0
- package/dist/types.js.map +1 -0
- package/dist/views/home.hbs +9 -0
- package/dist/views/templates/main.hbs +12 -0
- package/dist/zcap.d.ts +267 -0
- package/dist/zcap.d.ts.map +1 -0
- package/dist/zcap.js +478 -0
- package/dist/zcap.js.map +1 -0
- package/package.json +109 -0
- package/src/auth-header-hooks.ts +163 -0
- package/src/authorize.ts +117 -0
- package/src/backends/filesystem.ts +3626 -0
- package/src/backends/postgres.ts +3073 -0
- package/src/backends/postgresSchema.ts +231 -0
- package/src/config.default.ts +657 -0
- package/src/corsProxy.ts +326 -0
- package/src/declarations.d.ts +28 -0
- package/src/digest.ts +223 -0
- package/src/errors.ts +1122 -0
- package/src/index.ts +21 -0
- package/src/lib/atomicFile.ts +176 -0
- package/src/lib/backendRegistry.ts +139 -0
- package/src/lib/backendUsage.ts +79 -0
- package/src/lib/backends.ts +351 -0
- package/src/lib/blindedIndex.ts +466 -0
- package/src/lib/collectionDescription.ts +43 -0
- package/src/lib/cursor.ts +52 -0
- package/src/lib/edvEnvelope.ts +120 -0
- package/src/lib/encryption.ts +472 -0
- package/src/lib/etag.ts +40 -0
- package/src/lib/exportManifest.ts +115 -0
- package/src/lib/importTar.ts +381 -0
- package/src/lib/isJson.ts +18 -0
- package/src/lib/keyEpoch.ts +89 -0
- package/src/lib/keyedMutex.ts +45 -0
- package/src/lib/kmsModule.ts +451 -0
- package/src/lib/kmsRecordCipher.ts +292 -0
- package/src/lib/pagination.ts +22 -0
- package/src/lib/paths.ts +382 -0
- package/src/lib/preconditions.ts +145 -0
- package/src/lib/resourceFileName.ts +69 -0
- package/src/lib/revocations.ts +116 -0
- package/src/lib/validateDid.ts +41 -0
- package/src/lib/validateId.ts +148 -0
- package/src/plugin.ts +288 -0
- package/src/policy.ts +176 -0
- package/src/provisioning.ts +98 -0
- package/src/requests/BackendRequest.ts +219 -0
- package/src/requests/CollectionRequest.ts +899 -0
- package/src/requests/KeyRequest.ts +617 -0
- package/src/requests/KeystoreRequest.ts +325 -0
- package/src/requests/PolicyRequest.ts +169 -0
- package/src/requests/ResourceRequest.ts +649 -0
- package/src/requests/RevocationRequest.ts +267 -0
- package/src/requests/SpaceRequest.ts +686 -0
- package/src/requests/SpacesRepositoryRequest.ts +194 -0
- package/src/requests/collectionContext.ts +41 -0
- package/src/requests/controllerConsent.ts +108 -0
- package/src/requests/keystoreContext.ts +124 -0
- package/src/requests/resourceInput.ts +118 -0
- package/src/requests/spaceContext.ts +311 -0
- package/src/routes.ts +420 -0
- package/src/server.ts +69 -0
- package/src/start.ts +71 -0
- package/src/storage.ts +60 -0
- package/src/types.ts +1016 -0
- package/src/views/home.hbs +9 -0
- package/src/views/templates/main.hbs +12 -0
- 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
|
+
}
|