@metalabel/dfos-protocol 0.9.0 → 0.11.0
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/README.md +7 -11
- package/dist/chain/index.d.ts +37 -33
- package/dist/chain/index.js +27 -9
- package/dist/{chunk-ZXXP5W5N.js → chunk-GQOZJKKO.js} +58 -10
- package/dist/{chunk-24VGJGUM.js → chunk-LQFOBE6X.js} +25 -27
- package/dist/{chunk-UEJ364OG.js → chunk-SDUOUFTF.js} +110 -75
- package/dist/credentials/index.d.ts +3 -12
- package/dist/credentials/index.js +2 -2
- package/dist/crypto/index.d.ts +16 -7
- package/dist/crypto/index.js +3 -1
- package/dist/index.d.ts +3 -4
- package/dist/index.js +29 -21
- package/dist/{schemas-BEl38wrI.d.ts → schemas-Myod8ES9.d.ts} +58 -14
- package/examples/content-delegated.json +11 -11
- package/examples/content-delete.json +5 -5
- package/examples/content-lifecycle.json +9 -9
- package/examples/credential-read.json +3 -3
- package/examples/credential-write.json +5 -5
- package/examples/identity-delete.json +4 -4
- package/examples/identity-genesis.json +3 -3
- package/examples/identity-rotation.json +4 -4
- package/examples/identity-services.json +38 -0
- package/package.json +10 -14
- package/dist/chunk-E5CFQG2B.js +0 -99
- package/dist/merkle/index.d.ts +0 -45
- package/dist/merkle/index.js +0 -14
- package/examples/beacon.json +0 -14
- package/examples/merkle-tree.json +0 -28
- package/schemas/manifest.v1.json +0 -29
package/README.md
CHANGED
|
@@ -17,18 +17,15 @@ import { verifyContentChain, verifyIdentityChain } from '@metalabel/dfos-protoco
|
|
|
17
17
|
import { createAuthToken, createDFOSCredential } from '@metalabel/dfos-protocol/credentials';
|
|
18
18
|
// Crypto primitives
|
|
19
19
|
import { createJws, dagCborCanonicalEncode, verifyJws } from '@metalabel/dfos-protocol/crypto';
|
|
20
|
-
// Merkle trees
|
|
21
|
-
import { buildMerkleTree, verifyMerkleProof } from '@metalabel/dfos-protocol/merkle';
|
|
22
20
|
```
|
|
23
21
|
|
|
24
22
|
## Subpath Exports
|
|
25
23
|
|
|
26
|
-
| Export | Description
|
|
27
|
-
| -------------------------------------- |
|
|
28
|
-
| `@metalabel/dfos-protocol/chain` | Identity
|
|
29
|
-
| `@metalabel/dfos-protocol/credentials` | Auth tokens (DID-signed JWT) and DFOS credentials for authorization
|
|
30
|
-
| `@metalabel/dfos-protocol/crypto` | Ed25519, JWS, JWT, dag-cbor, base64url, ID generation
|
|
31
|
-
| `@metalabel/dfos-protocol/merkle` | SHA-256 binary merkle tree, inclusion proofs |
|
|
24
|
+
| Export | Description |
|
|
25
|
+
| -------------------------------------- | ------------------------------------------------------------------------- |
|
|
26
|
+
| `@metalabel/dfos-protocol/chain` | Identity & content chains, services, artifacts, countersigns, revocations |
|
|
27
|
+
| `@metalabel/dfos-protocol/credentials` | Auth tokens (DID-signed JWT) and DFOS credentials for authorization |
|
|
28
|
+
| `@metalabel/dfos-protocol/crypto` | Ed25519, JWS, JWT, dag-cbor, base64url, ID generation |
|
|
32
29
|
|
|
33
30
|
## Specifications
|
|
34
31
|
|
|
@@ -36,7 +33,7 @@ import { buildMerkleTree, verifyMerkleProof } from '@metalabel/dfos-protocol/mer
|
|
|
36
33
|
| ------------------------------------------------ | -------------------------------------------------------------- |
|
|
37
34
|
| [PROTOCOL.md](../../specs/PROTOCOL.md) | Core protocol — chains, signatures, verification, test vectors |
|
|
38
35
|
| [DID-METHOD.md](../../specs/DID-METHOD.md) | W3C DID method specification for `did:dfos` |
|
|
39
|
-
| [CONTENT-MODEL.md](../../specs/CONTENT-MODEL.md) | Standard content schemas (post, profile
|
|
36
|
+
| [CONTENT-MODEL.md](../../specs/CONTENT-MODEL.md) | Standard content schemas (post, profile) |
|
|
40
37
|
|
|
41
38
|
## Examples
|
|
42
39
|
|
|
@@ -50,8 +47,7 @@ The `examples/` directory contains deterministic reference fixtures that can be
|
|
|
50
47
|
- `content-delegated.json` — creator genesis + delegated update with DFOS write credential
|
|
51
48
|
- `credential-write.json` — DFOS write credential (broad + content-narrowed)
|
|
52
49
|
- `credential-read.json` — DFOS read credential
|
|
53
|
-
- `
|
|
54
|
-
- `beacon.json` — signed manifest pointer announcement with witness countersignature
|
|
50
|
+
- `identity-services.json` — genesis publishing a services set (relay locator + content/artifact anchors)
|
|
55
51
|
|
|
56
52
|
## License
|
|
57
53
|
|
package/dist/chain/index.d.ts
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
|
-
import { I as IdentityOperation,
|
|
2
|
-
export { M as MAX_ARTIFACT_PAYLOAD_SIZE,
|
|
1
|
+
import { I as IdentityOperation, h as Signer, V as VerifiedIdentity, S as ServiceEntry, b as ContentOperation, c as CountersignPayload, a as ArtifactPayload } from '../schemas-Myod8ES9.js';
|
|
2
|
+
export { A as ARTIFACT_CID_ANCHOR_RE, C as CONTENT_ID_ANCHOR_RE, M as MAX_ARTIFACT_PAYLOAD_SIZE, d as MAX_SERVICES_ENTRIES, e as MAX_SERVICES_PAYLOAD_SIZE, f as MultikeyPublicKey, R as RevocationPayload, g as ServicesArray } from '../schemas-Myod8ES9.js';
|
|
3
3
|
import 'zod';
|
|
4
4
|
|
|
5
5
|
/** Ed25519 public key multicodec value */
|
|
@@ -32,7 +32,7 @@ declare const deriveChainIdentifier: (cidBytes: Uint8Array, prefix: string) => s
|
|
|
32
32
|
/**
|
|
33
33
|
* Derive a bare content identifier from CID bytes
|
|
34
34
|
*
|
|
35
|
-
* Returns the raw
|
|
35
|
+
* Returns the raw 31-char hash with no prefix. Applications may add
|
|
36
36
|
* their own prefix for routing (e.g., post_xxxx) — that's semantic sugar.
|
|
37
37
|
*/
|
|
38
38
|
declare const deriveContentId: (cidBytes: Uint8Array) => string;
|
|
@@ -88,8 +88,31 @@ declare const verifyIdentityExtensionFromTrustedState: (input: {
|
|
|
88
88
|
createdAt: string;
|
|
89
89
|
}>;
|
|
90
90
|
|
|
91
|
+
type AnchorKind = 'chain' | 'artifact' | 'invalid';
|
|
92
|
+
/**
|
|
93
|
+
* Enforce the services byte cap on the CBOR-encoded array — same encoding the
|
|
94
|
+
* wire uses, so the bound is identical across implementations. Mirrors the
|
|
95
|
+
* artifact payload size check.
|
|
96
|
+
*/
|
|
97
|
+
declare const assertServicesWithinCap: (services: ServiceEntry[]) => Promise<void>;
|
|
98
|
+
/**
|
|
99
|
+
* Classify a ContentAnchor target by structural form. Resolvers dispatch on the
|
|
100
|
+
* result: 'chain' → resolve a content chain by contentId; 'artifact' → fetch by
|
|
101
|
+
* CID and require type:"artifact"; 'invalid' → reject (e.g. a bare head CID is
|
|
102
|
+
* 'artifact'-shaped but fails the resolution-time type check).
|
|
103
|
+
*/
|
|
104
|
+
declare const classifyAnchor: (anchor: string) => AnchorKind;
|
|
105
|
+
/** Recognized (core-blessed) service types. All other types are valid but opaque. */
|
|
106
|
+
declare const RECOGNIZED_SERVICE_TYPES: readonly ["DfosRelay", "ContentAnchor"];
|
|
107
|
+
/** Whether the core assigns structural semantics to this service type. */
|
|
108
|
+
declare const isRecognizedServiceType: (type: string) => boolean;
|
|
109
|
+
/** Select the DfosRelay transport endpoints from a services set, in entry order. */
|
|
110
|
+
declare const relayEndpoints: (services: ServiceEntry[]) => string[];
|
|
111
|
+
/** Select ContentAnchor entries matching a client label (e.g. "profile"). */
|
|
112
|
+
declare const anchorsByLabel: (services: ServiceEntry[], label: string) => ServiceEntry[];
|
|
113
|
+
|
|
91
114
|
interface VerifiedContentChain {
|
|
92
|
-
/** Content identifier — bare
|
|
115
|
+
/** Content identifier — bare 31-char hash derived from genesis CID */
|
|
93
116
|
contentId: string;
|
|
94
117
|
/** CID of the genesis operation */
|
|
95
118
|
genesisCID: string;
|
|
@@ -144,6 +167,11 @@ declare const verifyContentChain: (input: {
|
|
|
144
167
|
* is true, as credential verification needs identity resolution.
|
|
145
168
|
*/
|
|
146
169
|
resolveIdentity?: (did: string) => Promise<VerifiedIdentity | undefined>;
|
|
170
|
+
/**
|
|
171
|
+
* Check whether a credential (leaf or parent) has been revoked. Threaded onto
|
|
172
|
+
* the WRITE path so revoked credentials no longer authorize writes.
|
|
173
|
+
*/
|
|
174
|
+
isRevoked?: (issuerDID: string, credentialCID: string) => Promise<boolean>;
|
|
147
175
|
}) => Promise<VerifiedContentChain>;
|
|
148
176
|
/**
|
|
149
177
|
* Verify a single new content operation against already-verified chain state
|
|
@@ -165,40 +193,14 @@ declare const verifyContentExtensionFromTrustedState: (input: {
|
|
|
165
193
|
enforceAuthorization?: boolean;
|
|
166
194
|
/** Resolve a DID to a VerifiedIdentity. Required when enforceAuthorization is true. */
|
|
167
195
|
resolveIdentity?: (did: string) => Promise<VerifiedIdentity | undefined>;
|
|
196
|
+
/** Check whether a credential (leaf or parent) has been revoked. */
|
|
197
|
+
isRevoked?: (issuerDID: string, credentialCID: string) => Promise<boolean>;
|
|
168
198
|
}) => Promise<{
|
|
169
199
|
state: VerifiedContentChain;
|
|
170
200
|
operationCID: string;
|
|
171
201
|
createdAt: string;
|
|
172
202
|
}>;
|
|
173
203
|
|
|
174
|
-
interface VerifiedBeacon {
|
|
175
|
-
did: string;
|
|
176
|
-
manifestContentId: string;
|
|
177
|
-
createdAt: string;
|
|
178
|
-
signerKeyId: string;
|
|
179
|
-
beaconCID: string;
|
|
180
|
-
}
|
|
181
|
-
/**
|
|
182
|
-
* Sign a beacon announcement as a JWS
|
|
183
|
-
*/
|
|
184
|
-
declare const signBeacon: (input: {
|
|
185
|
-
payload: BeaconPayload;
|
|
186
|
-
signer: Signer;
|
|
187
|
-
kid: string;
|
|
188
|
-
}) => Promise<{
|
|
189
|
-
jwsToken: string;
|
|
190
|
-
beaconCID: string;
|
|
191
|
-
}>;
|
|
192
|
-
/**
|
|
193
|
-
* Verify a beacon JWS — signature, CID, payload schema, clock skew
|
|
194
|
-
*/
|
|
195
|
-
declare const verifyBeacon: (input: {
|
|
196
|
-
jwsToken: string;
|
|
197
|
-
resolveKey: (kid: string) => Promise<Uint8Array>;
|
|
198
|
-
/** Current time for clock skew check (defaults to Date.now()) */
|
|
199
|
-
now?: number;
|
|
200
|
-
}) => Promise<VerifiedBeacon>;
|
|
201
|
-
|
|
202
204
|
interface VerifiedCountersignature {
|
|
203
205
|
/** CID of this countersign operation (distinct from the target) */
|
|
204
206
|
countersignCID: string;
|
|
@@ -206,6 +208,8 @@ interface VerifiedCountersignature {
|
|
|
206
208
|
witnessDID: string;
|
|
207
209
|
/** The CID being attested to */
|
|
208
210
|
targetCID: string;
|
|
211
|
+
/** Open-namespace relation tag, if present (e.g. "endorses", "coauthors") */
|
|
212
|
+
relation?: string;
|
|
209
213
|
}
|
|
210
214
|
/**
|
|
211
215
|
* Sign a countersignature attesting to a target operation by CID
|
|
@@ -287,4 +291,4 @@ declare const verifyRevocation: (input: {
|
|
|
287
291
|
resolveKey: (kid: string) => Promise<Uint8Array>;
|
|
288
292
|
}) => Promise<VerifiedRevocation>;
|
|
289
293
|
|
|
290
|
-
export {
|
|
294
|
+
export { type AnchorKind, ArtifactPayload, ContentOperation, CountersignPayload, ED25519_PRIV_MULTICODEC, ED25519_PUB_MULTICODEC, IdentityOperation, RECOGNIZED_SERVICE_TYPES, ServiceEntry, Signer, type VerifiedArtifact, type VerifiedContentChain, type VerifiedCountersignature, VerifiedIdentity, type VerifiedRevocation, anchorsByLabel, assertServicesWithinCap, classifyAnchor, decodeMultikey, deriveChainIdentifier, deriveContentId, encodeEd25519Multikey, isRecognizedServiceType, relayEndpoints, signArtifact, signContentOperation, signCountersignature, signIdentityOperation, signRevocation, verifyArtifact, verifyContentChain, verifyContentExtensionFromTrustedState, verifyCountersignature, verifyIdentityChain, verifyIdentityExtensionFromTrustedState, verifyRevocation };
|
package/dist/chain/index.js
CHANGED
|
@@ -1,61 +1,79 @@
|
|
|
1
1
|
import {
|
|
2
|
+
ARTIFACT_CID_ANCHOR_RE,
|
|
2
3
|
ArtifactPayload,
|
|
3
|
-
|
|
4
|
+
CONTENT_ID_ANCHOR_RE,
|
|
4
5
|
ContentOperation,
|
|
5
6
|
CountersignPayload,
|
|
6
7
|
IdentityOperation,
|
|
7
8
|
MAX_ARTIFACT_PAYLOAD_SIZE,
|
|
9
|
+
MAX_SERVICES_ENTRIES,
|
|
10
|
+
MAX_SERVICES_PAYLOAD_SIZE,
|
|
8
11
|
MultikeyPublicKey,
|
|
12
|
+
RECOGNIZED_SERVICE_TYPES,
|
|
9
13
|
RevocationPayload,
|
|
14
|
+
ServiceEntry,
|
|
15
|
+
ServicesArray,
|
|
10
16
|
VerifiedIdentity,
|
|
17
|
+
anchorsByLabel,
|
|
18
|
+
assertServicesWithinCap,
|
|
19
|
+
classifyAnchor,
|
|
11
20
|
deriveChainIdentifier,
|
|
12
21
|
deriveContentId,
|
|
22
|
+
isRecognizedServiceType,
|
|
23
|
+
relayEndpoints,
|
|
13
24
|
signArtifact,
|
|
14
|
-
signBeacon,
|
|
15
25
|
signContentOperation,
|
|
16
26
|
signCountersignature,
|
|
17
27
|
signIdentityOperation,
|
|
18
28
|
signRevocation,
|
|
19
29
|
verifyArtifact,
|
|
20
|
-
verifyBeacon,
|
|
21
30
|
verifyContentChain,
|
|
22
31
|
verifyContentExtensionFromTrustedState,
|
|
23
32
|
verifyCountersignature,
|
|
24
33
|
verifyIdentityChain,
|
|
25
34
|
verifyIdentityExtensionFromTrustedState,
|
|
26
35
|
verifyRevocation
|
|
27
|
-
} from "../chunk-
|
|
36
|
+
} from "../chunk-SDUOUFTF.js";
|
|
28
37
|
import {
|
|
29
38
|
ED25519_PRIV_MULTICODEC,
|
|
30
39
|
ED25519_PUB_MULTICODEC,
|
|
31
40
|
decodeMultikey,
|
|
32
41
|
encodeEd25519Multikey
|
|
33
|
-
} from "../chunk-
|
|
34
|
-
import "../chunk-
|
|
42
|
+
} from "../chunk-LQFOBE6X.js";
|
|
43
|
+
import "../chunk-GQOZJKKO.js";
|
|
35
44
|
export {
|
|
45
|
+
ARTIFACT_CID_ANCHOR_RE,
|
|
36
46
|
ArtifactPayload,
|
|
37
|
-
|
|
47
|
+
CONTENT_ID_ANCHOR_RE,
|
|
38
48
|
ContentOperation,
|
|
39
49
|
CountersignPayload,
|
|
40
50
|
ED25519_PRIV_MULTICODEC,
|
|
41
51
|
ED25519_PUB_MULTICODEC,
|
|
42
52
|
IdentityOperation,
|
|
43
53
|
MAX_ARTIFACT_PAYLOAD_SIZE,
|
|
54
|
+
MAX_SERVICES_ENTRIES,
|
|
55
|
+
MAX_SERVICES_PAYLOAD_SIZE,
|
|
44
56
|
MultikeyPublicKey,
|
|
57
|
+
RECOGNIZED_SERVICE_TYPES,
|
|
45
58
|
RevocationPayload,
|
|
59
|
+
ServiceEntry,
|
|
60
|
+
ServicesArray,
|
|
46
61
|
VerifiedIdentity,
|
|
62
|
+
anchorsByLabel,
|
|
63
|
+
assertServicesWithinCap,
|
|
64
|
+
classifyAnchor,
|
|
47
65
|
decodeMultikey,
|
|
48
66
|
deriveChainIdentifier,
|
|
49
67
|
deriveContentId,
|
|
50
68
|
encodeEd25519Multikey,
|
|
69
|
+
isRecognizedServiceType,
|
|
70
|
+
relayEndpoints,
|
|
51
71
|
signArtifact,
|
|
52
|
-
signBeacon,
|
|
53
72
|
signContentOperation,
|
|
54
73
|
signCountersignature,
|
|
55
74
|
signIdentityOperation,
|
|
56
75
|
signRevocation,
|
|
57
76
|
verifyArtifact,
|
|
58
|
-
verifyBeacon,
|
|
59
77
|
verifyContentChain,
|
|
60
78
|
verifyContentExtensionFromTrustedState,
|
|
61
79
|
verifyCountersignature,
|
|
@@ -40,7 +40,7 @@ var isValidEd25519Signature = (payload, signature, publicKey) => {
|
|
|
40
40
|
// src/crypto/id.ts
|
|
41
41
|
import { sha256 as sha256Hash } from "@noble/hashes/sha2.js";
|
|
42
42
|
var alphabet = "2346789acdefhknrtvz";
|
|
43
|
-
var idLength =
|
|
43
|
+
var idLength = 31;
|
|
44
44
|
var getRandomBytes = (length) => {
|
|
45
45
|
const bytes = new Uint8Array(length);
|
|
46
46
|
globalThis.crypto.getRandomValues(bytes);
|
|
@@ -75,6 +75,22 @@ var normalizedId = (prefix, id) => {
|
|
|
75
75
|
return `${prefixLowered}_${idLowered}`;
|
|
76
76
|
};
|
|
77
77
|
|
|
78
|
+
// src/crypto/jws-profile.ts
|
|
79
|
+
var assertJwsProfile = (header, makeError) => {
|
|
80
|
+
if (header.alg !== "EdDSA") {
|
|
81
|
+
throw makeError(`Unsupported algorithm: ${String(header.alg)}`);
|
|
82
|
+
}
|
|
83
|
+
if ("crit" in header) {
|
|
84
|
+
throw makeError("crit header is not supported");
|
|
85
|
+
}
|
|
86
|
+
if ("jwk" in header) {
|
|
87
|
+
throw makeError("jwk header is not allowed (key is resolved from kid)");
|
|
88
|
+
}
|
|
89
|
+
if ("x5c" in header) {
|
|
90
|
+
throw makeError("x5c header is not allowed (key is resolved from kid)");
|
|
91
|
+
}
|
|
92
|
+
};
|
|
93
|
+
|
|
78
94
|
// src/crypto/jws.ts
|
|
79
95
|
var createJws = async (options) => {
|
|
80
96
|
const headerB64 = base64urlEncode(JSON.stringify(options.header));
|
|
@@ -99,9 +115,10 @@ var verifyJws = (options) => {
|
|
|
99
115
|
} catch {
|
|
100
116
|
throw new JwsVerificationError("Failed to decode token");
|
|
101
117
|
}
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
|
|
118
|
+
assertJwsProfile(
|
|
119
|
+
header,
|
|
120
|
+
(m) => new JwsVerificationError(m)
|
|
121
|
+
);
|
|
105
122
|
const signingInput = `${headerB64}.${payloadB64}`;
|
|
106
123
|
const signingInputBytes = new TextEncoder().encode(signingInput);
|
|
107
124
|
const signatureBytes = base64urlDecode(signatureB64);
|
|
@@ -172,12 +189,13 @@ var verifyJwt = (options) => {
|
|
|
172
189
|
} catch {
|
|
173
190
|
throw new JwtVerificationError("Failed to decode token");
|
|
174
191
|
}
|
|
192
|
+
assertJwsProfile(
|
|
193
|
+
header,
|
|
194
|
+
(m) => new JwtVerificationError(m)
|
|
195
|
+
);
|
|
175
196
|
const signingInput = `${headerB64}.${payloadB64}`;
|
|
176
197
|
const signingInputBytes = new TextEncoder().encode(signingInput);
|
|
177
198
|
const signatureBytes = base64urlDecode(signatureB64);
|
|
178
|
-
if (header.alg !== "EdDSA") {
|
|
179
|
-
throw new JwtVerificationError(`Unsupported algorithm: ${header.alg}`);
|
|
180
|
-
}
|
|
181
199
|
const isValid = isValidEd25519Signature(signingInputBytes, signatureBytes, options.publicKey);
|
|
182
200
|
if (!isValid) throw new JwtVerificationError("Invalid signature");
|
|
183
201
|
const currentTime = options.currentTime ?? Math.floor(Date.now() / 1e3);
|
|
@@ -209,14 +227,43 @@ import * as Block from "multiformats/block";
|
|
|
209
227
|
import { CID } from "multiformats/cid";
|
|
210
228
|
import { sha256 } from "multiformats/hashes/sha2";
|
|
211
229
|
var dagCborCanonicalEncode = async (value) => {
|
|
230
|
+
assertCanonicalNumbers(value);
|
|
231
|
+
const serialized = JSON.parse(JSON.stringify(value));
|
|
232
|
+
assertCanonicalNumbers(serialized);
|
|
212
233
|
return await Block.encode({
|
|
213
|
-
// removes any undefineds or other non-serializable values
|
|
214
|
-
//
|
|
215
|
-
value:
|
|
234
|
+
// removes any undefineds or other non-serializable values (and normalizes
|
|
235
|
+
// -0 to 0)
|
|
236
|
+
value: serialized,
|
|
216
237
|
codec: dagCborCodec,
|
|
217
238
|
hasher: sha256
|
|
218
239
|
});
|
|
219
240
|
};
|
|
241
|
+
var MAX_SAFE_CANONICAL_INTEGER = 9007199254740991;
|
|
242
|
+
var assertCanonicalNumbers = (value) => {
|
|
243
|
+
if (typeof value === "number") {
|
|
244
|
+
if (!Number.isFinite(value)) {
|
|
245
|
+
throw new Error(`non-finite number is not canonicalizable: ${value}`);
|
|
246
|
+
}
|
|
247
|
+
if (!Number.isInteger(value)) {
|
|
248
|
+
throw new Error(
|
|
249
|
+
`non-integer number is not canonicalizable: ${value} (encode it as a string)`
|
|
250
|
+
);
|
|
251
|
+
}
|
|
252
|
+
if (value > MAX_SAFE_CANONICAL_INTEGER || value < -MAX_SAFE_CANONICAL_INTEGER) {
|
|
253
|
+
throw new Error(
|
|
254
|
+
`integer out of safe range is not canonicalizable: ${value} (encode it as a string)`
|
|
255
|
+
);
|
|
256
|
+
}
|
|
257
|
+
return;
|
|
258
|
+
}
|
|
259
|
+
if (Array.isArray(value)) {
|
|
260
|
+
for (const entry of value) assertCanonicalNumbers(entry);
|
|
261
|
+
return;
|
|
262
|
+
}
|
|
263
|
+
if (value !== null && typeof value === "object") {
|
|
264
|
+
for (const entry of Object.values(value)) assertCanonicalNumbers(entry);
|
|
265
|
+
}
|
|
266
|
+
};
|
|
220
267
|
var parseDagCborCID = (cid) => {
|
|
221
268
|
return CID.parse(cid);
|
|
222
269
|
};
|
|
@@ -237,6 +284,7 @@ export {
|
|
|
237
284
|
generateId,
|
|
238
285
|
isValidId,
|
|
239
286
|
normalizedId,
|
|
287
|
+
assertJwsProfile,
|
|
240
288
|
createJws,
|
|
241
289
|
verifyJws,
|
|
242
290
|
decodeJwsUnsafe,
|
|
@@ -5,7 +5,7 @@ import {
|
|
|
5
5
|
decodeJwsUnsafe,
|
|
6
6
|
verifyJws,
|
|
7
7
|
verifyJwt
|
|
8
|
-
} from "./chunk-
|
|
8
|
+
} from "./chunk-GQOZJKKO.js";
|
|
9
9
|
|
|
10
10
|
// src/credentials/schemas.ts
|
|
11
11
|
import { z } from "zod";
|
|
@@ -14,7 +14,7 @@ var MAX_AUD = 512;
|
|
|
14
14
|
var MAX_RESOURCE = 512;
|
|
15
15
|
var MAX_ACTION = 64;
|
|
16
16
|
var MAX_ATT = 32;
|
|
17
|
-
var MAX_PRF =
|
|
17
|
+
var MAX_PRF = 1;
|
|
18
18
|
var Attenuation = z.strictObject({
|
|
19
19
|
resource: z.string().min(1).max(MAX_RESOURCE),
|
|
20
20
|
action: z.string().min(1).max(MAX_ACTION)
|
|
@@ -96,6 +96,7 @@ var verifyAuthToken = (options) => {
|
|
|
96
96
|
iss: result.data.iss,
|
|
97
97
|
aud: result.data.aud,
|
|
98
98
|
exp: result.data.exp,
|
|
99
|
+
iat: result.data.iat,
|
|
99
100
|
kid
|
|
100
101
|
};
|
|
101
102
|
};
|
|
@@ -256,41 +257,38 @@ var verifyDelegationChain = async (credential, options) => {
|
|
|
256
257
|
}
|
|
257
258
|
return { credential, chain, rootDID: options.rootDID };
|
|
258
259
|
}
|
|
259
|
-
|
|
260
|
-
|
|
261
|
-
|
|
262
|
-
|
|
263
|
-
|
|
264
|
-
|
|
265
|
-
|
|
266
|
-
|
|
267
|
-
|
|
268
|
-
|
|
269
|
-
|
|
260
|
+
if (current.prf.length > 1) {
|
|
261
|
+
throw new CredentialVerificationError(
|
|
262
|
+
"delegation chain: multi-parent credentials are not supported (prf must have at most one entry)"
|
|
263
|
+
);
|
|
264
|
+
}
|
|
265
|
+
const parent = await verifyDFOSCredential(current.prf[0], {
|
|
266
|
+
resolveIdentity: options.resolveIdentity,
|
|
267
|
+
...options.now !== void 0 ? { now: options.now } : {}
|
|
268
|
+
});
|
|
269
|
+
if (options.isRevoked) {
|
|
270
|
+
const revoked = await options.isRevoked(parent.iss, parent.credentialCID);
|
|
271
|
+
if (revoked) {
|
|
272
|
+
throw new CredentialVerificationError("parent credential in delegation chain is revoked");
|
|
270
273
|
}
|
|
271
|
-
parents.push(parent);
|
|
272
274
|
}
|
|
273
|
-
|
|
274
|
-
if (!matchingParent) {
|
|
275
|
+
if (parent.aud !== "*" && parent.aud !== current.iss) {
|
|
275
276
|
throw new CredentialVerificationError(
|
|
276
|
-
`delegation gap:
|
|
277
|
+
`delegation gap: parent credential audience ${parent.aud} does not match child issuer ${current.iss}`
|
|
277
278
|
);
|
|
278
279
|
}
|
|
279
|
-
|
|
280
|
-
|
|
281
|
-
|
|
282
|
-
|
|
283
|
-
);
|
|
284
|
-
}
|
|
280
|
+
if (current.exp > parent.exp) {
|
|
281
|
+
throw new CredentialVerificationError(
|
|
282
|
+
"delegation chain: child credential expiry exceeds parent expiry"
|
|
283
|
+
);
|
|
285
284
|
}
|
|
286
|
-
|
|
287
|
-
if (!isAttenuated(parentAttUnion, current.att)) {
|
|
285
|
+
if (!isAttenuated(parent.att, current.att)) {
|
|
288
286
|
throw new CredentialVerificationError(
|
|
289
287
|
"delegation chain: child credential scope exceeds parent scope"
|
|
290
288
|
);
|
|
291
289
|
}
|
|
292
|
-
chain.push(
|
|
293
|
-
current =
|
|
290
|
+
chain.push(parent);
|
|
291
|
+
current = parent;
|
|
294
292
|
}
|
|
295
293
|
throw new CredentialVerificationError("delegation chain too deep (max 16 hops)");
|
|
296
294
|
};
|