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,267 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Request handlers for zcap revocation, one per route family:
|
|
3
|
+
* - POST /kms/keystores/:keystoreId/zcaps/revocations/:revocationId
|
|
4
|
+
* - POST /space/:spaceId/zcaps/revocations/:revocationId
|
|
5
|
+
*
|
|
6
|
+
* Both share one submission flow (`submitRevocation`), differing only in the
|
|
7
|
+
* scope the revocation aggregates under -- a keystore or a Space -- the action
|
|
8
|
+
* the invocation must carry (the webkms `write` vs the WAS route families'
|
|
9
|
+
* HTTP verb), and the `/kms` delegation policy the WAS families do not impose.
|
|
10
|
+
*
|
|
11
|
+
* The wire contract is protocol-fixed by ezcap-express's
|
|
12
|
+
* `authorizeZcapRevocation` / `@interop/webkms-client` (the conformance
|
|
13
|
+
* suite): `:revocationId` is the to-be-revoked capability's id, URL-encoded;
|
|
14
|
+
* the body is that capability, verbatim; success is 204 with no body. The
|
|
15
|
+
* submission is authorized under the dual-root rule -- an invocation rooted
|
|
16
|
+
* in the scope, or in the revocation URL itself, whose synthesized root is
|
|
17
|
+
* controlled by every controller in the to-be-revoked capability's (fully
|
|
18
|
+
* verified) chain -- so a delegee can revoke its own zcap without holding a
|
|
19
|
+
* separate capability. Root zcaps cannot be revoked. The stored revocation is
|
|
20
|
+
* consulted by the chain-inspection hook on every subsequent verification
|
|
21
|
+
* rooted in that scope (`lib/revocations.ts`).
|
|
22
|
+
*/
|
|
23
|
+
import type { FastifyReply, FastifyRequest } from 'fastify'
|
|
24
|
+
import {
|
|
25
|
+
handleRevocationInvocationVerify,
|
|
26
|
+
verifyRevocationChain
|
|
27
|
+
} from '../zcap.js'
|
|
28
|
+
import { revocationChainInspector } from '../lib/revocations.js'
|
|
29
|
+
import { spacePath } from '../lib/paths.js'
|
|
30
|
+
import {
|
|
31
|
+
KMS_MAX_CHAIN_LENGTH,
|
|
32
|
+
KMS_MAX_DELEGATION_TTL
|
|
33
|
+
} from '../config.default.js'
|
|
34
|
+
import { InvalidRevocationError } from '../errors.js'
|
|
35
|
+
import type { IDID, RevocationRecord, RevocationScope } from '../types.js'
|
|
36
|
+
import { fetchKeystore } from './keystoreContext.js'
|
|
37
|
+
import { fetchSpace } from './spaceContext.js'
|
|
38
|
+
|
|
39
|
+
/** One day in milliseconds -- the revocation record's GC margin. */
|
|
40
|
+
const ONE_DAY = 24 * 60 * 60 * 1000
|
|
41
|
+
|
|
42
|
+
/**
|
|
43
|
+
* The scope-agnostic revocation submission: validate the body capability,
|
|
44
|
+
* verify its delegation chain (it must root in `rootTarget`), which yields
|
|
45
|
+
* the chain's controllers for the dual-root invocation check, then -- only
|
|
46
|
+
* once the invocation is authorized -- reject a chain containing an
|
|
47
|
+
* already-revoked link (resubmissions included) with the 400
|
|
48
|
+
* `InvalidRevocationError`, per ezcap-express, and store the record. The
|
|
49
|
+
* store check runs strictly AFTER the 404-masking authorization so an
|
|
50
|
+
* unauthorized caller cannot probe whether a capability is revoked (a
|
|
51
|
+
* 400-vs-404 oracle otherwise). The record expires one day after the
|
|
52
|
+
* capability itself does (from then on the capability is rejected on expiry
|
|
53
|
+
* alone; the margin covers clock-skew grace periods).
|
|
54
|
+
*
|
|
55
|
+
* @param options {object}
|
|
56
|
+
* @param options.request {FastifyRequest} supplies url, method, headers,
|
|
57
|
+
* logger, and `request.server` for serverUrl + storage
|
|
58
|
+
* @param options.revocationId {string} the URL's revocation id (the
|
|
59
|
+
* to-be-revoked capability's id, already URL-decoded by the router)
|
|
60
|
+
* @param options.scope {RevocationScope} the keystore or Space the record is
|
|
61
|
+
* stored under
|
|
62
|
+
* @param options.rootTarget {string} the scope's full URL (the required root
|
|
63
|
+
* of the revoked capability's chain, and one of the two accepted invocation
|
|
64
|
+
* roots)
|
|
65
|
+
* @param options.rootController {IDID} the scope's controller
|
|
66
|
+
* @param options.expectedAction {string} the action the invocation must
|
|
67
|
+
* carry (`write` on `/kms`, `POST` on the WAS route families)
|
|
68
|
+
* @param options.requestName {string} human-readable request name, used in
|
|
69
|
+
* error titles
|
|
70
|
+
* @param [options.maxChainLength] {number} max chain length, root included
|
|
71
|
+
* @param [options.maxDelegationTtl] {number} max delegated-zcap TTL (ms)
|
|
72
|
+
* @returns {Promise<void>}
|
|
73
|
+
*/
|
|
74
|
+
async function submitRevocation({
|
|
75
|
+
request,
|
|
76
|
+
revocationId,
|
|
77
|
+
scope,
|
|
78
|
+
rootTarget,
|
|
79
|
+
rootController,
|
|
80
|
+
expectedAction,
|
|
81
|
+
requestName,
|
|
82
|
+
maxChainLength,
|
|
83
|
+
maxDelegationTtl
|
|
84
|
+
}: {
|
|
85
|
+
request: FastifyRequest
|
|
86
|
+
revocationId: string
|
|
87
|
+
scope: RevocationScope
|
|
88
|
+
rootTarget: string
|
|
89
|
+
rootController: IDID
|
|
90
|
+
expectedAction: string
|
|
91
|
+
requestName: string
|
|
92
|
+
maxChainLength?: number
|
|
93
|
+
maxDelegationTtl?: number
|
|
94
|
+
}): Promise<void> {
|
|
95
|
+
const { url, method, headers, body } = request
|
|
96
|
+
const { serverUrl, storage } = request.server
|
|
97
|
+
|
|
98
|
+
if (
|
|
99
|
+
typeof body !== 'object' ||
|
|
100
|
+
body === null ||
|
|
101
|
+
Array.isArray(body) ||
|
|
102
|
+
typeof (body as Record<string, unknown>).id !== 'string'
|
|
103
|
+
) {
|
|
104
|
+
throw new InvalidRevocationError({
|
|
105
|
+
detail: 'The revocation body must be a capability with a string "id".'
|
|
106
|
+
})
|
|
107
|
+
}
|
|
108
|
+
const capabilityBody = body as Record<string, unknown> & { id: string }
|
|
109
|
+
if (capabilityBody.id.startsWith('urn:zcap:root:')) {
|
|
110
|
+
throw new InvalidRevocationError({
|
|
111
|
+
detail: 'A root capability cannot be revoked.'
|
|
112
|
+
})
|
|
113
|
+
}
|
|
114
|
+
// The submitted capability must be the one the URL names (the client
|
|
115
|
+
// frames the id with `encodeURIComponent` into the final path segment).
|
|
116
|
+
if (capabilityBody.id !== revocationId) {
|
|
117
|
+
throw new InvalidRevocationError({
|
|
118
|
+
detail: 'The capability "id" does not match the revocation URL.'
|
|
119
|
+
})
|
|
120
|
+
}
|
|
121
|
+
|
|
122
|
+
// Verify the to-be-revoked capability's own delegation chain (400 when
|
|
123
|
+
// invalid); its controllers feed the dual-root invocation check below.
|
|
124
|
+
// Structural only -- the revocation store is not consulted until after
|
|
125
|
+
// authorization (see below).
|
|
126
|
+
const { delegator, chainControllers, capabilities } =
|
|
127
|
+
await verifyRevocationChain({
|
|
128
|
+
capability: capabilityBody,
|
|
129
|
+
rootTarget,
|
|
130
|
+
rootController,
|
|
131
|
+
maxChainLength,
|
|
132
|
+
maxDelegationTtl
|
|
133
|
+
})
|
|
134
|
+
|
|
135
|
+
await handleRevocationInvocationVerify({
|
|
136
|
+
url,
|
|
137
|
+
method,
|
|
138
|
+
headers,
|
|
139
|
+
serverUrl,
|
|
140
|
+
rootTarget,
|
|
141
|
+
rootController,
|
|
142
|
+
chainControllers,
|
|
143
|
+
expectedAction,
|
|
144
|
+
// The *invoking* chain is checked against the store as on every other
|
|
145
|
+
// route: a revoked capability cannot authorize a revocation.
|
|
146
|
+
inspectCapabilityChain: revocationChainInspector({ storage, scope }),
|
|
147
|
+
maxChainLength,
|
|
148
|
+
maxDelegationTtl,
|
|
149
|
+
requestName,
|
|
150
|
+
logger: request.log
|
|
151
|
+
})
|
|
152
|
+
|
|
153
|
+
// The caller is authorized; NOW consult the store for the to-be-revoked
|
|
154
|
+
// chain. A chain containing an already-revoked link (resubmissions
|
|
155
|
+
// included) is the 400, per ezcap-express; the 409 duplicate stays
|
|
156
|
+
// reserved for a write race at the store. Running this after the masked
|
|
157
|
+
// authorization keeps revocation state undisclosed to unauthorized callers.
|
|
158
|
+
if (await storage.isRevoked({ scope, capabilities })) {
|
|
159
|
+
throw new InvalidRevocationError({
|
|
160
|
+
detail:
|
|
161
|
+
'The capability (or a capability in its chain) is already revoked.'
|
|
162
|
+
})
|
|
163
|
+
}
|
|
164
|
+
|
|
165
|
+
const capability = capabilityBody as RevocationRecord['capability']
|
|
166
|
+
// Compute the record's GC expiry only from a parseable `expires`; an
|
|
167
|
+
// unparseable one yields `NaN`, and `new Date(NaN).toISOString()` would
|
|
168
|
+
// throw a `RangeError` (500). Omitting `expires` here just drops the GC
|
|
169
|
+
// margin -- the capability is still rejected on its own expiry.
|
|
170
|
+
const expiresMs = capability.expires ? Date.parse(capability.expires) : NaN
|
|
171
|
+
const record: RevocationRecord = {
|
|
172
|
+
capability,
|
|
173
|
+
meta: {
|
|
174
|
+
delegator,
|
|
175
|
+
rootTarget,
|
|
176
|
+
created: new Date().toISOString(),
|
|
177
|
+
...(Number.isFinite(expiresMs) && {
|
|
178
|
+
expires: new Date(expiresMs + ONE_DAY).toISOString()
|
|
179
|
+
})
|
|
180
|
+
}
|
|
181
|
+
}
|
|
182
|
+
await storage.insertRevocation({ scope, record })
|
|
183
|
+
}
|
|
184
|
+
|
|
185
|
+
export class RevocationRequest {
|
|
186
|
+
/**
|
|
187
|
+
* POST /kms/keystores/:keystoreId/zcaps/revocations/:revocationId
|
|
188
|
+
* Revoke a capability delegated from a keystore. Carries the unified `/kms`
|
|
189
|
+
* delegation policy, and the webkms `write` action. Responds 204, no body; a
|
|
190
|
+
* concurrent duplicate insert is the 409 `DuplicateRevocationError`.
|
|
191
|
+
*
|
|
192
|
+
* @param request {import('fastify').FastifyRequest}
|
|
193
|
+
* @param reply {import('fastify').FastifyReply}
|
|
194
|
+
* @returns {Promise<FastifyReply>}
|
|
195
|
+
*/
|
|
196
|
+
static async post(
|
|
197
|
+
request: FastifyRequest<{
|
|
198
|
+
Params: { keystoreId: string; revocationId: string }
|
|
199
|
+
Body: Record<string, unknown>
|
|
200
|
+
}>,
|
|
201
|
+
reply: FastifyReply
|
|
202
|
+
): Promise<FastifyReply> {
|
|
203
|
+
const requestName = 'Revoke Capability'
|
|
204
|
+
const { keystoreId, revocationId } = request.params
|
|
205
|
+
|
|
206
|
+
// 404-masks an unknown keystore before any verification work.
|
|
207
|
+
const config = await fetchKeystore({ request, keystoreId, requestName })
|
|
208
|
+
|
|
209
|
+
await submitRevocation({
|
|
210
|
+
request,
|
|
211
|
+
revocationId,
|
|
212
|
+
scope: { keystoreId },
|
|
213
|
+
rootTarget: config.id,
|
|
214
|
+
rootController: config.controller,
|
|
215
|
+
expectedAction: 'write',
|
|
216
|
+
requestName,
|
|
217
|
+
maxChainLength: KMS_MAX_CHAIN_LENGTH,
|
|
218
|
+
maxDelegationTtl: KMS_MAX_DELEGATION_TTL
|
|
219
|
+
})
|
|
220
|
+
|
|
221
|
+
return reply.status(204).send()
|
|
222
|
+
}
|
|
223
|
+
|
|
224
|
+
/**
|
|
225
|
+
* POST /space/:spaceId/zcaps/revocations/:revocationId
|
|
226
|
+
* Revoke a capability delegated from a Space -- the WAS-route sibling of
|
|
227
|
+
* `post`, scoped to the Space rather than a keystore. The revoked capability
|
|
228
|
+
* is rejected from then on wherever a Space-rooted chain is verified: the
|
|
229
|
+
* write/privileged routes (`fetchSpaceAndVerify`) and the capability leg of
|
|
230
|
+
* the read routes (`authorize`). The invoked action is the HTTP verb, since
|
|
231
|
+
* WAS capabilities are scoped by HTTP method. No delegation-policy caps
|
|
232
|
+
* apply, matching the rest of the WAS route families.
|
|
233
|
+
*
|
|
234
|
+
* Responds 204, no body; a concurrent duplicate insert is the 409
|
|
235
|
+
* `DuplicateRevocationError`.
|
|
236
|
+
*
|
|
237
|
+
* @param request {import('fastify').FastifyRequest}
|
|
238
|
+
* @param reply {import('fastify').FastifyReply}
|
|
239
|
+
* @returns {Promise<FastifyReply>}
|
|
240
|
+
*/
|
|
241
|
+
static async postSpace(
|
|
242
|
+
request: FastifyRequest<{
|
|
243
|
+
Params: { spaceId: string; revocationId: string }
|
|
244
|
+
Body: Record<string, unknown>
|
|
245
|
+
}>,
|
|
246
|
+
reply: FastifyReply
|
|
247
|
+
): Promise<FastifyReply> {
|
|
248
|
+
const requestName = 'Revoke Capability'
|
|
249
|
+
const { spaceId, revocationId } = request.params
|
|
250
|
+
const { serverUrl } = request.server
|
|
251
|
+
|
|
252
|
+
// 404-masks an unknown Space before any verification work.
|
|
253
|
+
const spaceDescription = await fetchSpace({ request, spaceId, requestName })
|
|
254
|
+
|
|
255
|
+
await submitRevocation({
|
|
256
|
+
request,
|
|
257
|
+
revocationId,
|
|
258
|
+
scope: { spaceId },
|
|
259
|
+
rootTarget: new URL(spacePath({ spaceId }), serverUrl).toString(),
|
|
260
|
+
rootController: spaceDescription.controller,
|
|
261
|
+
expectedAction: request.method,
|
|
262
|
+
requestName
|
|
263
|
+
})
|
|
264
|
+
|
|
265
|
+
return reply.status(204).send()
|
|
266
|
+
}
|
|
267
|
+
}
|