@metalabel/dfos-protocol 0.51.0 → 0.52.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.
@@ -1,5 +1,5 @@
1
- import { I as IdentityOperation, v as Signer, x as VerifiedIdentity, S as ServiceEntry, c as ContentOperation, R as ResolvedIdentity, r as RevocationChecker, d as CountersignPayload, a as ArtifactPayload } from '../dfos-credential-CtG0_n4P.js';
2
- export { A as ARTIFACT_CID_ANCHOR_RE, C as CONTENT_ID_ANCHOR_RE, f as CreditClaimPayload, g as DeclaredKeyState, h as Iso8601, M as MAX_ARTIFACT_PAYLOAD_SIZE, j as MAX_CREDIT_CLAIM_SIZE, k as MAX_KEY_PROOFS, l as MAX_OPERATION_SIZE, m as MAX_SERVICES_ENTRIES, n as MAX_SERVICES_PAYLOAD_SIZE, o as MAX_SIGN_REQUEST_PAYLOAD_SIZE, p as MAX_SIGN_REQUEST_SIZE, q as MultikeyPublicKey, s as RevocationPayload, t as ServicesArray, u as SignRequestPayload, y as VoidKeyMembership, G as parseProtocolTimestampUnix } from '../dfos-credential-CtG0_n4P.js';
1
+ import { I as IdentityOperation, v as Signer, x as VerifiedIdentity, S as ServiceEntry, c as ContentOperation, R as ResolvedIdentity, r as RevocationChecker, d as CountersignPayload, a as ArtifactPayload } from '../dfos-credential-j-kHtFvG.js';
2
+ export { A as ARTIFACT_CID_ANCHOR_RE, C as CONTENT_ID_ANCHOR_RE, f as CreditClaimPayload, g as DeclaredKeyState, h as Iso8601, M as MAX_ARTIFACT_PAYLOAD_SIZE, j as MAX_CREDIT_CLAIM_SIZE, k as MAX_KEY_PROOFS, l as MAX_OPERATION_SIZE, m as MAX_SERVICES_ENTRIES, n as MAX_SERVICES_PAYLOAD_SIZE, o as MAX_SIGN_REQUEST_PAYLOAD_SIZE, p as MAX_SIGN_REQUEST_SIZE, q as MultikeyPublicKey, s as RevocationPayload, t as ServicesArray, u as SignRequestPayload, y as VoidKeyMembership, G as parseProtocolTimestampUnix } from '../dfos-credential-j-kHtFvG.js';
3
3
  import 'zod';
4
4
 
5
5
  /** Ed25519 public key multicodec value */
@@ -22,6 +22,17 @@ declare const decodeMultikey: (multibase: string) => {
22
22
  keyBytes: Uint8Array;
23
23
  codec: number;
24
24
  };
25
+ /**
26
+ * Decode a Multikey multibase string that MUST carry an Ed25519 PUBLIC key
27
+ *
28
+ * `decodeMultikey` also accepts the `ed25519-priv` prefix and reports it in
29
+ * `codec`, which a caller that destructures only `{ keyBytes }` silently
30
+ * discards — so a private-key-tagged multibase string would verify as if it were
31
+ * a public key, where the Go reference (DecodeMultikey) accepts the 0xed01
32
+ * prefix and nothing else. This is the decode every signature path takes, so the
33
+ * codec assertion cannot be forgotten at the next call site.
34
+ */
35
+ declare const decodeEd25519PublicMultikey: (multibase: string) => Uint8Array;
25
36
 
26
37
  /**
27
38
  * Derive a prefixed chain identifier from CID bytes
@@ -529,7 +540,8 @@ declare const buildSignRequest: (input: {
529
540
  requestCID: string;
530
541
  }>;
531
542
  /**
532
- * Verify a sign-request envelope in SIGNING.md's exact 1–9 order.
543
+ * Verify a sign-request envelope in RELAY.md, Envelope verification's exact 1–9
544
+ * order.
533
545
  *
534
546
  * `resolveIdentity` supplies CURRENT identity state. A missing identity or
535
547
  * resolver failure is `unverifiable`; a deleted identity, missing current key,
@@ -548,4 +560,4 @@ declare const assertCanonicalSignRequestPayload: (payloadTyp: string, payloadByt
548
560
  subject: string;
549
561
  }) => void;
550
562
 
551
- export { type AnchorKind, ArtifactPayload, ContentOperation, CountersignPayload, type CreditClaimFailureReason, CreditClaimVerifyError, type CreditEntry, type CreditEntryState, ED25519_PRIV_MULTICODEC, ED25519_PUB_MULTICODEC, IdentityOperation, RECOGNIZED_SERVICE_TYPES, ServiceEntry, type SignRequestFailureReason, SignRequestVerifyError, Signer, type VerifiedArtifact, type VerifiedContentChain, type VerifiedCountersignature, type VerifiedCreditClaim, type VerifiedCreditEntry, VerifiedIdentity, type VerifiedRevocation, type VerifiedSignRequest, anchorsByLabel, assertCanonicalSignRequestPayload, assertServicesWithinCap, buildSignRequest, classifyAnchor, decodeMultikey, deriveChainIdentifier, deriveContentId, encodeEd25519Multikey, isRecognizedServiceType, relayEndpoints, signArtifact, signContentOperation, signCountersignature, signCreditClaim, signIdentityOperation, signRevocation, verifyArtifact, verifyContentChain, verifyContentExtensionFromTrustedState, verifyCountersignature, verifyCreditClaim, verifyCreditEntry, verifyIdentityChain, verifyIdentityExtensionFromTrustedState, verifyRevocation, verifySignRequest };
563
+ export { type AnchorKind, ArtifactPayload, ContentOperation, CountersignPayload, type CreditClaimFailureReason, CreditClaimVerifyError, type CreditEntry, type CreditEntryState, ED25519_PRIV_MULTICODEC, ED25519_PUB_MULTICODEC, IdentityOperation, RECOGNIZED_SERVICE_TYPES, ServiceEntry, type SignRequestFailureReason, SignRequestVerifyError, Signer, type VerifiedArtifact, type VerifiedContentChain, type VerifiedCountersignature, type VerifiedCreditClaim, type VerifiedCreditEntry, VerifiedIdentity, type VerifiedRevocation, type VerifiedSignRequest, anchorsByLabel, assertCanonicalSignRequestPayload, assertServicesWithinCap, buildSignRequest, classifyAnchor, decodeEd25519PublicMultikey, decodeMultikey, deriveChainIdentifier, deriveContentId, encodeEd25519Multikey, isRecognizedServiceType, relayEndpoints, signArtifact, signContentOperation, signCountersignature, signCreditClaim, signIdentityOperation, signRevocation, verifyArtifact, verifyContentChain, verifyContentExtensionFromTrustedState, verifyCountersignature, verifyCreditClaim, verifyCreditEntry, verifyIdentityChain, verifyIdentityExtensionFromTrustedState, verifyRevocation, verifySignRequest };
@@ -52,16 +52,17 @@ import {
52
52
  verifyIdentityExtensionFromTrustedState,
53
53
  verifyRevocation,
54
54
  verifySignRequest
55
- } from "../chunk-LMAPBTDW.js";
56
- import "../chunk-T2YR5KWQ.js";
57
- import "../chunk-JVSC67DC.js";
55
+ } from "../chunk-OU2DPHCN.js";
56
+ import "../chunk-IV3TIYKP.js";
57
+ import "../chunk-QRCOMLAP.js";
58
58
  import {
59
59
  ED25519_PRIV_MULTICODEC,
60
60
  ED25519_PUB_MULTICODEC,
61
+ decodeEd25519PublicMultikey,
61
62
  decodeMultikey,
62
63
  encodeEd25519Multikey
63
- } from "../chunk-IDVYITX7.js";
64
- import "../chunk-4LG2GEB2.js";
64
+ } from "../chunk-F7RHI2CK.js";
65
+ import "../chunk-QTJZGXMH.js";
65
66
  export {
66
67
  ARTIFACT_CID_ANCHOR_RE,
67
68
  ArtifactPayload,
@@ -97,6 +98,7 @@ export {
97
98
  assertServicesWithinCap,
98
99
  buildSignRequest,
99
100
  classifyAnchor,
101
+ decodeEd25519PublicMultikey,
100
102
  decodeMultikey,
101
103
  deriveChainIdentifier,
102
104
  deriveContentId,
@@ -36,10 +36,18 @@ var decodeMultikey = (multibase) => {
36
36
  `unsupported multikey codec: [0x${bytes[0]?.toString(16)}, 0x${bytes[1]?.toString(16)}]`
37
37
  );
38
38
  };
39
+ var decodeEd25519PublicMultikey = (multibase) => {
40
+ const { keyBytes, codec } = decodeMultikey(multibase);
41
+ if (codec !== ED25519_PUB_MULTICODEC) {
42
+ throw new Error("publicKeyMultibase is not an Ed25519 public key");
43
+ }
44
+ return keyBytes;
45
+ };
39
46
 
40
47
  export {
41
48
  ED25519_PUB_MULTICODEC,
42
49
  ED25519_PRIV_MULTICODEC,
43
50
  encodeEd25519Multikey,
44
- decodeMultikey
51
+ decodeMultikey,
52
+ decodeEd25519PublicMultikey
45
53
  };
@@ -1,6 +1,6 @@
1
1
  import {
2
- decodeMultikey
3
- } from "./chunk-IDVYITX7.js";
2
+ decodeEd25519PublicMultikey
3
+ } from "./chunk-F7RHI2CK.js";
4
4
  import {
5
5
  assertJwsProfile,
6
6
  base64urlDecode,
@@ -10,7 +10,7 @@ import {
10
10
  decodeJwsUnsafe,
11
11
  sha256,
12
12
  verifyJws
13
- } from "./chunk-4LG2GEB2.js";
13
+ } from "./chunk-QTJZGXMH.js";
14
14
 
15
15
  // src/credentials/schemas.ts
16
16
  import { z } from "zod";
@@ -355,7 +355,10 @@ var verifyProofEnvelope = async (input, shape, resolvePresenter) => {
355
355
  const key = state.keys.find((candidate) => candidate.id === presenterKeyId);
356
356
  if (!key) throw invalidProof(`${shape.label} signing key is not a current key of the presenter`);
357
357
  try {
358
- verifyJws({ token: input.proof, publicKey: decodeMultikey(key.publicKeyMultibase).keyBytes });
358
+ verifyJws({
359
+ token: input.proof,
360
+ publicKey: decodeEd25519PublicMultikey(key.publicKeyMultibase)
361
+ });
359
362
  } catch (err) {
360
363
  throw invalidProof(err instanceof Error ? err.message : `invalid ${shape.label} signature`);
361
364
  }
@@ -382,7 +385,7 @@ var resolveKeyFromIdentity = (identity, kid, determinate) => {
382
385
  );
383
386
  throw determinate ? miss : markDependencyMissing(miss);
384
387
  }
385
- const { keyBytes } = decodeMultikey(key.publicKeyMultibase);
388
+ const keyBytes = decodeEd25519PublicMultikey(key.publicKeyMultibase);
386
389
  return keyBytes;
387
390
  };
388
391
  var basisUnixSeconds = (basis) => {
@@ -456,7 +459,7 @@ var verifyDFOSCredential = async (jwsToken, options) => {
456
459
  } catch {
457
460
  throw new CredentialVerificationError("invalid credential signature");
458
461
  }
459
- const encoded = await dagCborCanonicalEncode(payload);
462
+ const encoded = await dagCborCanonicalEncode(decoded.payload);
460
463
  const credentialCID = encoded.cid.toString();
461
464
  if (!decoded.header.cid) {
462
465
  throw new CredentialVerificationError("missing cid in credential header");
@@ -534,8 +537,9 @@ var parseResource = (resource) => {
534
537
  if (colonIdx < 0) return null;
535
538
  return { type: resource.substring(0, colonIdx), id: resource.substring(colonIdx + 1) };
536
539
  };
540
+ var ASCII_TRIM_RE = /^[\t\n\v\f\r ]+|[\t\n\v\f\r ]+$/g;
537
541
  var parseActions = (action) => new Set(
538
- action.split(",").map((a) => a.trim()).filter((a) => a !== "")
542
+ action.split(",").map((a) => a.replace(ASCII_TRIM_RE, "")).filter((a) => a !== "")
539
543
  );
540
544
  var isAttenuated = (parentAtt, childAtt) => {
541
545
  return childAtt.every((childEntry) => {
@@ -6,16 +6,16 @@ import {
6
6
  matchesResource,
7
7
  verifyDFOSCredential,
8
8
  verifyDelegationChain
9
- } from "./chunk-T2YR5KWQ.js";
9
+ } from "./chunk-IV3TIYKP.js";
10
10
  import {
11
11
  KEY_ADD_JWS_TYP,
12
12
  KEY_ROLES,
13
13
  unsafeKeyProofSubject,
14
14
  verifyChainKeyProof
15
- } from "./chunk-JVSC67DC.js";
15
+ } from "./chunk-QRCOMLAP.js";
16
16
  import {
17
- decodeMultikey
18
- } from "./chunk-IDVYITX7.js";
17
+ decodeEd25519PublicMultikey
18
+ } from "./chunk-F7RHI2CK.js";
19
19
  import {
20
20
  assertJwsProfile,
21
21
  base64urlDecode,
@@ -25,13 +25,13 @@ import {
25
25
  decodeJwsUnsafe,
26
26
  generateIdNoPrefix,
27
27
  verifyJws
28
- } from "./chunk-4LG2GEB2.js";
28
+ } from "./chunk-QTJZGXMH.js";
29
29
 
30
30
  // src/chain/schemas.ts
31
31
  import { z } from "zod";
32
32
  var MAX_KEYS_PER_ROLE = 256;
33
33
  var MAX_KEY_PROOFS = 256;
34
- var MAX_RELATION = 64;
34
+ var MAX_RELATION_BYTES = 64;
35
35
  var MAX_SERVICES_ENTRIES = 256;
36
36
  var MAX_SERVICES_PAYLOAD_SIZE = 32768;
37
37
  var MAX_OPERATION_SIZE = 65536;
@@ -78,7 +78,7 @@ var parseProtocolTimestampUnix = (value) => {
78
78
  const ms = Date.parse(value);
79
79
  return Number.isFinite(ms) ? Math.floor(ms / 1e3) : null;
80
80
  };
81
- var CIDString = z.string();
81
+ var CIDString = z.string().min(1, "CID must not be empty");
82
82
  var IdentityCreate = z.looseObject({
83
83
  version: z.literal(1),
84
84
  type: z.literal("create"),
@@ -261,7 +261,9 @@ var CountersignPayload = z.looseObject({
261
261
  type: z.literal("countersign"),
262
262
  did: z.string(),
263
263
  targetCID: CIDString,
264
- relation: z.string().min(1).max(MAX_RELATION).optional(),
264
+ relation: z.string().min(1).refine((value) => new TextEncoder().encode(value).length <= MAX_RELATION_BYTES, {
265
+ message: `relation exceeds ${MAX_RELATION_BYTES} bytes`
266
+ }).optional(),
265
267
  createdAt: Iso8601
266
268
  });
267
269
  var RevocationPayload = z.looseObject({
@@ -544,7 +546,7 @@ var verifyIdentityChain = async (input) => {
544
546
  }
545
547
  }
546
548
  }
547
- const encoded = await dagCborCanonicalEncode(op);
549
+ const encoded = await dagCborCanonicalEncode(decoded.payload);
548
550
  if (encoded.bytes.length > MAX_OPERATION_SIZE) {
549
551
  throw new Error(
550
552
  `log[${idx}]: operation exceeds max size: ${encoded.bytes.length} > ${MAX_OPERATION_SIZE}`
@@ -575,7 +577,7 @@ var verifyIdentityChain = async (input) => {
575
577
  if (!signingKey) {
576
578
  throw new Error(`log[${idx}]: kid references unknown key: ${signingKeyId}`);
577
579
  }
578
- const { keyBytes } = decodeMultikey(signingKey.publicKeyMultibase);
580
+ const keyBytes = decodeEd25519PublicMultikey(signingKey.publicKeyMultibase);
579
581
  try {
580
582
  verifyJws({ token: jwsToken, publicKey: keyBytes });
581
583
  } catch {
@@ -694,7 +696,7 @@ var verifyIdentityExtensionFromTrustedState = async (input) => {
694
696
  if (op.createdAt <= lastCreatedAt) {
695
697
  throw new Error("createdAt must be after last op");
696
698
  }
697
- const encoded = await dagCborCanonicalEncode(op);
699
+ const encoded = await dagCborCanonicalEncode(decoded.payload);
698
700
  if (encoded.bytes.length > MAX_OPERATION_SIZE) {
699
701
  throw new Error(`operation exceeds max size: ${encoded.bytes.length} > ${MAX_OPERATION_SIZE}`);
700
702
  }
@@ -715,7 +717,7 @@ var verifyIdentityExtensionFromTrustedState = async (input) => {
715
717
  if (!signingKey) {
716
718
  throw new Error(`kid references unknown key: ${signingKeyId}`);
717
719
  }
718
- const { keyBytes } = decodeMultikey(signingKey.publicKeyMultibase);
720
+ const keyBytes = decodeEd25519PublicMultikey(signingKey.publicKeyMultibase);
719
721
  try {
720
722
  verifyJws({ token: newOp, publicKey: keyBytes });
721
723
  } catch {
@@ -791,11 +793,13 @@ var verifyIdentityExtensionFromTrustedState = async (input) => {
791
793
 
792
794
  // src/chain/content-chain.ts
793
795
  var operationSizeForCap = async (op, fullByteLength) => {
796
+ if (op.type === "create") return fullByteLength;
794
797
  const auth = op.authorization;
795
798
  if (typeof auth !== "string") return fullByteLength;
796
- if (auth.length > MAX_CREDENTIAL_SIZE) {
799
+ const authByteLength = new TextEncoder().encode(auth).length;
800
+ if (authByteLength > MAX_CREDENTIAL_SIZE) {
797
801
  throw new Error(
798
- `authorization credential exceeds max size: ${auth.length} > ${MAX_CREDENTIAL_SIZE}`
802
+ `authorization credential exceeds max size: ${authByteLength} > ${MAX_CREDENTIAL_SIZE}`
799
803
  );
800
804
  }
801
805
  const { authorization: _omit, ...rest } = op;
@@ -927,8 +931,8 @@ var verifyContentChain = async (input) => {
927
931
  );
928
932
  }
929
933
  }
930
- const encoded = await dagCborCanonicalEncode(op);
931
- const opSize = await operationSizeForCap(op, encoded.bytes.length);
934
+ const encoded = await dagCborCanonicalEncode(decoded.payload);
935
+ const opSize = await operationSizeForCap(decoded.payload, encoded.bytes.length);
932
936
  if (opSize > MAX_OPERATION_SIZE) {
933
937
  throw new Error(`operation exceeds max size: ${opSize} > ${MAX_OPERATION_SIZE}`);
934
938
  }
@@ -1032,8 +1036,8 @@ var verifyContentExtensionFromTrustedState = async (input) => {
1032
1036
  throw carryDependencyMissing(err, new Error(`authorization verification failed: ${message}`));
1033
1037
  }
1034
1038
  }
1035
- const encoded = await dagCborCanonicalEncode(op);
1036
- const opSize = await operationSizeForCap(op, encoded.bytes.length);
1039
+ const encoded = await dagCborCanonicalEncode(decoded.payload);
1040
+ const opSize = await operationSizeForCap(decoded.payload, encoded.bytes.length);
1037
1041
  if (opSize > MAX_OPERATION_SIZE) {
1038
1042
  throw new Error(`operation exceeds max size: ${opSize} > ${MAX_OPERATION_SIZE}`);
1039
1043
  }
@@ -1198,7 +1202,7 @@ var verifyRevocation = async (input) => {
1198
1202
  } catch {
1199
1203
  throw new Error("invalid revocation signature");
1200
1204
  }
1201
- const encoded = await dagCborCanonicalEncode(payload);
1205
+ const encoded = await dagCborCanonicalEncode(decoded.payload);
1202
1206
  const revocationCID = encoded.cid.toString();
1203
1207
  if (!decoded.header.cid) throw new Error("missing cid in revocation header");
1204
1208
  if (decoded.header.cid !== revocationCID) throw new Error("revocation cid mismatch");
@@ -1231,7 +1235,7 @@ var resolveKeyFromIdentity = (identity, kid) => {
1231
1235
  if (!key) {
1232
1236
  throw markDependencyMissing(invalid(`key ${keyId} not found on identity ${identity.did}`));
1233
1237
  }
1234
- const { keyBytes } = decodeMultikey(key.publicKeyMultibase);
1238
+ const keyBytes = decodeEd25519PublicMultikey(key.publicKeyMultibase);
1235
1239
  return keyBytes;
1236
1240
  };
1237
1241
  var normalizeClaimCreatedAt = (createdAt) => {
@@ -1327,7 +1331,7 @@ var verifyCreditClaim = async (jwsToken, options) => {
1327
1331
  } catch {
1328
1332
  throw invalid("invalid credit claim signature");
1329
1333
  }
1330
- const encoded = await dagCborCanonicalEncode(payload);
1334
+ const encoded = await dagCborCanonicalEncode(decoded.payload);
1331
1335
  const claimCID = encoded.cid.toString();
1332
1336
  if (!decoded.header.cid) throw invalid("missing cid in credit claim header");
1333
1337
  if (decoded.header.cid !== claimCID) throw invalid("credit claim cid mismatch");
@@ -1454,7 +1458,7 @@ var resolveCurrentKey = (identity, kid) => {
1454
1458
  );
1455
1459
  if (!key) throw invalid2(`key ${keyId} not found on current identity ${identity.did}`);
1456
1460
  try {
1457
- return decodeMultikey(key.publicKeyMultibase).keyBytes;
1461
+ return decodeEd25519PublicMultikey(key.publicKeyMultibase);
1458
1462
  } catch {
1459
1463
  throw invalid2(`key ${keyId} on identity ${identity.did} is not a valid Ed25519 multikey`);
1460
1464
  }
@@ -1554,7 +1558,7 @@ var verifySignRequest = async (jwsToken, options) => {
1554
1558
  }
1555
1559
  let encoded;
1556
1560
  try {
1557
- encoded = await dagCborCanonicalEncode(payload);
1561
+ encoded = await dagCborCanonicalEncode(decoded.payload);
1558
1562
  } catch (error) {
1559
1563
  const detail = error instanceof Error ? error.message : String(error);
1560
1564
  throw invalid2(`failed to derive sign request CID: ${detail}`);
@@ -1,8 +1,7 @@
1
1
  import {
2
- ED25519_PUB_MULTICODEC,
3
- decodeMultikey,
2
+ decodeEd25519PublicMultikey,
4
3
  encodeEd25519Multikey
5
- } from "./chunk-IDVYITX7.js";
4
+ } from "./chunk-F7RHI2CK.js";
6
5
  import {
7
6
  base64urlDecode,
8
7
  base64urlEncode,
@@ -10,7 +9,7 @@ import {
10
9
  isValidEd25519Signature,
11
10
  sha256,
12
11
  signPayloadEd25519
13
- } from "./chunk-4LG2GEB2.js";
12
+ } from "./chunk-QTJZGXMH.js";
14
13
 
15
14
  // src/key-proof/role-set.ts
16
15
  var KEY_ROLES = ["auth", "assert", "controller"];
@@ -205,11 +204,7 @@ var decodeKeyProof = (jws, expectedTyp) => {
205
204
  var verifyKeyProofSignature = (decoded) => {
206
205
  let keyBytes;
207
206
  try {
208
- const key = decodeMultikey(decoded.payload.publicKeyMultibase);
209
- if (key.codec !== ED25519_PUB_MULTICODEC) {
210
- throw new Error("publicKeyMultibase is not an Ed25519 public key");
211
- }
212
- keyBytes = key.keyBytes;
207
+ keyBytes = decodeEd25519PublicMultikey(decoded.payload.publicKeyMultibase);
213
208
  } catch (err) {
214
209
  throw invalid(
215
210
  "signature",
@@ -79,6 +79,68 @@ var normalizedId = (prefix, id) => {
79
79
  return `${prefixLowered}_${idLowered}`;
80
80
  };
81
81
 
82
+ // src/crypto/json-scan.ts
83
+ var assertCanonicalJsonText = (text) => {
84
+ const frames = [];
85
+ let i = 0;
86
+ while (i < text.length) {
87
+ const ch = text[i];
88
+ if (ch === '"') {
89
+ const end = scanStringToken(text, i);
90
+ if (end < 0) return;
91
+ const value = decodeStringToken(text.slice(i, end));
92
+ if (value === null) return;
93
+ if (LONE_SURROGATE_RE.test(value)) {
94
+ throw new Error("string with an unpaired surrogate is not canonicalizable");
95
+ }
96
+ const frame = frames[frames.length - 1];
97
+ if (frame && frame.isObject && frame.awaitingKey) {
98
+ if (frame.keys.has(value)) {
99
+ throw new Error(`duplicate JSON key is malformed: ${JSON.stringify(value)}`);
100
+ }
101
+ frame.keys.add(value);
102
+ frame.awaitingKey = false;
103
+ }
104
+ i = end;
105
+ continue;
106
+ }
107
+ if (ch === "{") {
108
+ frames.push({ isObject: true, keys: /* @__PURE__ */ new Set(), awaitingKey: true });
109
+ } else if (ch === "[") {
110
+ frames.push({ isObject: false, keys: /* @__PURE__ */ new Set(), awaitingKey: false });
111
+ } else if (ch === "}" || ch === "]") {
112
+ frames.pop();
113
+ } else if (ch === ",") {
114
+ const frame = frames[frames.length - 1];
115
+ if (frame && frame.isObject) frame.awaitingKey = true;
116
+ }
117
+ i++;
118
+ }
119
+ };
120
+ var scanStringToken = (text, start) => {
121
+ let i = start + 1;
122
+ while (i < text.length) {
123
+ const ch = text[i];
124
+ if (ch === "\\") {
125
+ i += 2;
126
+ continue;
127
+ }
128
+ if (ch === '"') return i + 1;
129
+ i++;
130
+ }
131
+ return -1;
132
+ };
133
+ var decodeStringToken = (raw) => {
134
+ if (!raw.includes("\\")) return raw.slice(1, -1);
135
+ try {
136
+ const value = JSON.parse(raw);
137
+ return typeof value === "string" ? value : null;
138
+ } catch {
139
+ return null;
140
+ }
141
+ };
142
+ var LONE_SURROGATE_RE = /[\uD800-\uDBFF](?![\uDC00-\uDFFF])|(?<![\uD800-\uDBFF])[\uDC00-\uDFFF]/;
143
+
82
144
  // src/crypto/jws-profile.ts
83
145
  var assertJwsProfile = (header, makeError) => {
84
146
  if (header.alg !== "EdDSA") {
@@ -96,6 +158,30 @@ var assertJwsProfile = (header, makeError) => {
96
158
  };
97
159
 
98
160
  // src/crypto/jws.ts
161
+ var decodeJwsSegment = (segmentB64) => {
162
+ let text;
163
+ try {
164
+ text = new TextDecoder("utf-8", { fatal: true }).decode(base64urlDecode(segmentB64));
165
+ } catch {
166
+ return null;
167
+ }
168
+ assertCanonicalJsonText(text);
169
+ let value;
170
+ try {
171
+ value = JSON.parse(text);
172
+ } catch {
173
+ return null;
174
+ }
175
+ if (typeof value !== "object" || value === null || Array.isArray(value)) return null;
176
+ return value;
177
+ };
178
+ var asJwsHeader = (raw) => {
179
+ if (typeof raw["alg"] !== "string") return null;
180
+ if (typeof raw["typ"] !== "string") return null;
181
+ if (typeof raw["kid"] !== "string") return null;
182
+ if ("cid" in raw && typeof raw["cid"] !== "string") return null;
183
+ return raw;
184
+ };
99
185
  var createJws = async (options) => {
100
186
  const headerB64 = base64urlEncode(JSON.stringify(options.header));
101
187
  const payloadB64 = base64urlEncode(JSON.stringify(options.payload));
@@ -111,18 +197,22 @@ var verifyJws = (options) => {
111
197
  throw new JwsVerificationError("Invalid token format");
112
198
  }
113
199
  const [headerB64, payloadB64, signatureB64] = parts;
114
- let header;
200
+ let rawHeader;
115
201
  let payload;
116
202
  try {
117
- header = JSON.parse(new TextDecoder().decode(base64urlDecode(headerB64)));
118
- payload = JSON.parse(new TextDecoder().decode(base64urlDecode(payloadB64)));
119
- } catch {
203
+ rawHeader = decodeJwsSegment(headerB64);
204
+ payload = decodeJwsSegment(payloadB64);
205
+ } catch (e) {
206
+ throw new JwsVerificationError(e.message);
207
+ }
208
+ if (!rawHeader || !payload) {
120
209
  throw new JwsVerificationError("Failed to decode token");
121
210
  }
122
- assertJwsProfile(
123
- header,
124
- (m) => new JwsVerificationError(m)
125
- );
211
+ assertJwsProfile(rawHeader, (m) => new JwsVerificationError(m));
212
+ const header = asJwsHeader(rawHeader);
213
+ if (!header) {
214
+ throw new JwsVerificationError("Invalid protected header");
215
+ }
126
216
  const signingInput = `${headerB64}.${payloadB64}`;
127
217
  const signingInputBytes = new TextEncoder().encode(signingInput);
128
218
  const signatureBytes = base64urlDecode(signatureB64);
@@ -135,14 +225,19 @@ var verifyJws = (options) => {
135
225
  var decodeJwsUnsafe = (token) => {
136
226
  const parts = token.split(".");
137
227
  if (parts.length !== 3) return null;
228
+ const [headerB64, payloadB64] = parts;
229
+ let rawHeader;
230
+ let payload;
138
231
  try {
139
- const [headerB64, payloadB64] = parts;
140
- const header = JSON.parse(new TextDecoder().decode(base64urlDecode(headerB64)));
141
- const payload = JSON.parse(new TextDecoder().decode(base64urlDecode(payloadB64)));
142
- return { header, payload };
232
+ rawHeader = decodeJwsSegment(headerB64);
233
+ payload = decodeJwsSegment(payloadB64);
143
234
  } catch {
144
235
  return null;
145
236
  }
237
+ if (!rawHeader || !payload) return null;
238
+ const header = asJwsHeader(rawHeader);
239
+ if (!header) return null;
240
+ return { header, payload };
146
241
  };
147
242
  var JwsVerificationError = class extends Error {
148
243
  constructor(message) {
@@ -203,7 +298,7 @@ var verifyJwt = (options) => {
203
298
  const isValid = isValidEd25519Signature(signingInputBytes, signatureBytes, options.publicKey);
204
299
  if (!isValid) throw new JwtVerificationError("Invalid signature");
205
300
  const currentTime = options.currentTime ?? Math.floor(Date.now() / 1e3);
206
- if (payload.exp <= currentTime) {
301
+ if (!Number.isSafeInteger(payload.exp) || payload.exp <= currentTime) {
207
302
  throw new JwtVerificationError("Token expired");
208
303
  }
209
304
  if (options.issuer !== void 0 && payload.iss !== options.issuer) {
@@ -231,20 +326,25 @@ import * as Block from "multiformats/block";
231
326
  import { CID } from "multiformats/cid";
232
327
  import { sha256 as sha2562 } from "multiformats/hashes/sha2";
233
328
  var dagCborCanonicalEncode = async (value) => {
234
- assertCanonicalNumbers(value);
329
+ assertCanonicalValue(value);
235
330
  const serialized = JSON.parse(JSON.stringify(value));
236
- assertCanonicalNumbers(serialized);
237
- return await Block.encode({
238
- // removes any undefineds or other non-serializable values (and normalizes
239
- // -0 to 0)
240
- value: serialized,
241
- codec: dagCborCodec,
242
- hasher: sha2562
243
- });
331
+ assertCanonicalValue(serialized);
332
+ try {
333
+ return await Block.encode({
334
+ // removes any undefineds or other non-serializable values (and normalizes
335
+ // -0 to 0)
336
+ value: serialized,
337
+ codec: dagCborCodec,
338
+ hasher: sha2562
339
+ });
340
+ } catch (e) {
341
+ throw new Error(`value is not canonically encodable: ${e.message}`);
342
+ }
244
343
  };
245
344
  var MAX_SAFE_CANONICAL_INTEGER = 9007199254740991;
246
345
  var MAX_CANONICAL_DEPTH = 1024;
247
- var assertCanonicalNumbers = (value, depth = 0) => {
346
+ var LONE_SURROGATE_RE2 = /[\uD800-\uDBFF](?![\uDC00-\uDFFF])|(?<![\uD800-\uDBFF])[\uDC00-\uDFFF]/;
347
+ var assertCanonicalValue = (value, depth = 0) => {
248
348
  if (depth > MAX_CANONICAL_DEPTH) {
249
349
  throw new Error(`value nesting exceeds max depth ${MAX_CANONICAL_DEPTH}`);
250
350
  }
@@ -264,12 +364,26 @@ var assertCanonicalNumbers = (value, depth = 0) => {
264
364
  }
265
365
  return;
266
366
  }
367
+ if (typeof value === "string") {
368
+ if (LONE_SURROGATE_RE2.test(value)) {
369
+ throw new Error("string with an unpaired surrogate is not canonicalizable");
370
+ }
371
+ return;
372
+ }
267
373
  if (Array.isArray(value)) {
268
- for (const entry of value) assertCanonicalNumbers(entry, depth + 1);
374
+ for (const entry of value) assertCanonicalValue(entry, depth + 1);
269
375
  return;
270
376
  }
271
377
  if (value !== null && typeof value === "object") {
272
- for (const entry of Object.values(value)) assertCanonicalNumbers(entry, depth + 1);
378
+ if ("/" in value && "bytes" in value) {
379
+ throw new Error('object carrying both "/" and "bytes" members is not canonicalizable');
380
+ }
381
+ for (const [key, entry] of Object.entries(value)) {
382
+ if (LONE_SURROGATE_RE2.test(key)) {
383
+ throw new Error("string with an unpaired surrogate is not canonicalizable");
384
+ }
385
+ assertCanonicalValue(entry, depth + 1);
386
+ }
273
387
  }
274
388
  };
275
389
  var parseDagCborCID = (cid) => {
@@ -293,6 +407,7 @@ export {
293
407
  generateId,
294
408
  isValidId,
295
409
  normalizedId,
410
+ assertCanonicalJsonText,
296
411
  assertJwsProfile,
297
412
  createJws,
298
413
  verifyJws,
@@ -1,15 +1,16 @@
1
- export { b as Attenuation, e as CredentialVerificationError, D as DFOSCredentialPayload, i as MAX_CREDENTIAL_SIZE, R as ResolvedIdentity, r as RevocationChecker, V as VerifiedDFOSCredential, w as VerifiedDelegationChain, z as createDFOSCredential, B as decodeDFOSCredentialUnsafe, E as isAttenuated, F as matchesResource, H as verifyDFOSCredential, J as verifyDelegationChain } from '../dfos-credential-CtG0_n4P.js';
1
+ export { b as Attenuation, e as CredentialVerificationError, D as DFOSCredentialPayload, i as MAX_CREDENTIAL_SIZE, R as ResolvedIdentity, r as RevocationChecker, V as VerifiedDFOSCredential, w as VerifiedDelegationChain, z as createDFOSCredential, B as decodeDFOSCredentialUnsafe, E as isAttenuated, F as matchesResource, H as verifyDFOSCredential, J as verifyDelegationChain } from '../dfos-credential-j-kHtFvG.js';
2
2
  import 'zod';
3
3
 
4
4
  /**
5
- * The normative JWS header `typ` for a request proof (API-AUTH.md). Signers MUST
6
- * set it; the request-proof verifier rejects anything else — it is also what lets
7
- * typ-routing dispatchers tell a proof apart from credentials and chain ops.
5
+ * The normative JWS header `typ` for a request proof (INTEGRATIONS.md, The
6
+ * request proof). Signers MUST set it; the request-proof verifier rejects
7
+ * anything else — it is also what lets typ-routing dispatchers tell a proof
8
+ * apart from credentials and chain ops.
8
9
  */
9
10
  declare const REQUEST_PROOF_JWS_TYP = "did:dfos:request-proof";
10
11
  /**
11
- * The normative JWS header `typ` for an identity proof (API-AUTH.md) — the
12
- * request proof's credential-less sibling.
12
+ * The normative JWS header `typ` for an identity proof (INTEGRATIONS.md, The
13
+ * identity proof) — the request proof's credential-less sibling.
13
14
  *
14
15
  * THE TYP GATE IS ABSOLUTE, IN BOTH DIRECTIONS. "Possession of a grant's
15
16
  * audience key" and "possession of a bare identity's key" are different claims,
@@ -84,10 +85,10 @@ interface IdentityProofPayload {
84
85
  /**
85
86
  * ADDITIVE MEMBERS, appended AFTER the canonical order.
86
87
  *
87
- * API-AUTH.md's growth rule is additive members on this envelope, never a new
88
- * envelope: "additional members register additively, appended to the canonical
89
- * order". `jti` — the per-request uniqueness member a write-gating deployment
90
- * requires — is the named one.
88
+ * INTEGRATIONS.md, One envelope, optional credential's growth rule is additive
89
+ * members on this envelope, never a new envelope: "additional members register
90
+ * additively, appended to the canonical order". `jti` — the per-request
91
+ * uniqueness member a write-gating deployment requires — is the named one.
91
92
  *
92
93
  * TWO RULES MAKE THIS A BYTE-TWIN. (1) Extra members are emitted AFTER every
93
94
  * canonical member, so a verifier that ignores them still reconstructs the same
@@ -173,7 +174,7 @@ interface SignApiRequestInput {
173
174
  /**
174
175
  * ADDITIVE members, appended after the canonical order in lexicographic name
175
176
  * order. `{ jti }` is the registered one — required by a deployment that gates
176
- * WRITES with this envelope (API-AUTH.md, Security Considerations).
177
+ * WRITES with this envelope (INTEGRATIONS.md, API security notes).
177
178
  */
178
179
  extraMembers?: ProofExtraMembers;
179
180
  }
@@ -211,7 +212,7 @@ interface SignApiIdentityRequestInput {
211
212
  /**
212
213
  * ADDITIVE members, appended after the canonical order in lexicographic name
213
214
  * order. `{ jti }` is the registered one, and a WRITE-SHAPED surface — relay
214
- * ingestion, blob upload — REQUIRES it (WEB-RELAY.md, Authentication).
215
+ * ingestion, blob upload — REQUIRES it (INTEGRATIONS.md, API security notes).
215
216
  */
216
217
  extraMembers?: ProofExtraMembers;
217
218
  }
@@ -247,8 +248,8 @@ declare const buildApiAuthHeaders: (input: {
247
248
  * On an `api:<host>` surface an accompanying `X-Credential` is MALFORMED: the
248
249
  * two headers would assert two different claims at once. A relay content-plane
249
250
  * read is NOT that case — there the identity proof is the AuthN half and a DFOS
250
- * credential presentation is a separate authorization artifact (WEB-RELAY.md,
251
- * Authentication) — so that refusal belongs to the middleware of the surface
251
+ * credential presentation is a separate authorization artifact (RELAY.md,
252
+ * Access) — so that refusal belongs to the middleware of the surface
252
253
  * being served, never to this builder.
253
254
  */
254
255
  declare const buildApiIdentityHeaders: (input: {
@@ -317,7 +318,7 @@ interface ProofPresenterState {
317
318
  type ResolveProofPresenter = (did: string) => Promise<ProofPresenterState | null>;
318
319
  /**
319
320
  * What the PROOF PHASE reads — the subset of a verifier's inputs that
320
- * API-AUTH.md steps 1–7 touch.
321
+ * INTEGRATIONS.md, Verification algorithm steps 1–7 touch.
321
322
  */
322
323
  interface ProofEnvelopeInput {
323
324
  /** The proof JWS — the `Authorization: DFOS <token>` token, scheme stripped. */
@@ -346,8 +347,8 @@ interface ProofEnvelopeInput {
346
347
  now?: () => number;
347
348
  }
348
349
  /**
349
- * API-AUTH.md step 4's CONFIG half, hoisted so a caller can run it BEFORE any
350
- * request-dependent gate.
350
+ * INTEGRATIONS.md, Verification algorithm step 4's freshness configuration,
351
+ * hoisted so a caller can run it BEFORE any request-dependent gate.
351
352
  *
352
353
  * ORDER IS LOAD-BEARING. A deployment whose freshness span is out of bounds must
353
354
  * never verify anything, and its misconfiguration must never be REPORTED as a
@@ -399,9 +400,9 @@ interface VerifiedProofEnvelope {
399
400
  */
400
401
  declare const verifyIdentityProofEnvelope: (input: ProofEnvelopeInput, resolvePresenter: ResolveProofPresenter) => Promise<VerifiedProofEnvelope>;
401
402
  /**
402
- * Verify a REQUEST proof's envelope — API-AUTH.md steps 1–7 with the request
403
- * `typ`. The caller then performs steps 8–11 (the credential walk), for which a
404
- * verified proof signature is the gate.
403
+ * Verify a REQUEST proof's envelope — INTEGRATIONS.md, Verification algorithm
404
+ * steps 1–7 with the request `typ`. The caller then performs steps 8–11 (the
405
+ * credential walk), for which a verified proof signature is the gate.
405
406
  */
406
407
  declare const verifyRequestProofEnvelope: (input: ProofEnvelopeInput, resolvePresenter: ResolveProofPresenter) => Promise<VerifiedProofEnvelope>;
407
408
 
@@ -34,9 +34,9 @@ import {
34
34
  verifyDelegationChain,
35
35
  verifyIdentityProofEnvelope,
36
36
  verifyRequestProofEnvelope
37
- } from "../chunk-T2YR5KWQ.js";
38
- import "../chunk-IDVYITX7.js";
39
- import "../chunk-4LG2GEB2.js";
37
+ } from "../chunk-IV3TIYKP.js";
38
+ import "../chunk-F7RHI2CK.js";
39
+ import "../chunk-QTJZGXMH.js";
40
40
  export {
41
41
  ApiRequestVerifyError,
42
42
  Attenuation,
@@ -128,6 +128,28 @@ declare class JwsVerificationError extends Error {
128
128
  constructor(message: string);
129
129
  }
130
130
 
131
+ /**
132
+ * Reject a signed JSON document whose raw text carries something its decoded
133
+ * value can no longer show:
134
+ *
135
+ * 1. DUPLICATE KEYS — PROTOCOL: "A payload containing duplicate keys is
136
+ * malformed: the signature commits to the raw payload bytes while the CID
137
+ * derives from the decoded value." Every JSON parser silently resolves a
138
+ * duplicate (last wins), so the only place to see one is the text.
139
+ * 2. LONE SURROGATE ESCAPES — a `\uD800`-class escape with no pair. TypeScript
140
+ * keeps it; Go's decoder replaces it with U+FFFD. Two verifiers would derive
141
+ * two different CIDs from the same signed bytes, so refusing the escape is
142
+ * the one verdict both can reach.
143
+ *
144
+ * This is a tokenizer, not a parser: it does not validate the grammar — the
145
+ * caller's `JSON.parse` is the grammar judge, and this walk simply stops at the
146
+ * first thing it cannot read. It tracks only enough structure to know which
147
+ * strings are member names of which object.
148
+ *
149
+ * MUST match the Go reference (AssertCanonicalJSONText in json_scan.go).
150
+ */
151
+ declare const assertCanonicalJsonText: (text: string) => void;
152
+
131
153
  /**
132
154
  * Apply the DFOS signature verification profile to a decoded protected header.
133
155
  *
@@ -214,4 +236,4 @@ declare const parseDagCborCID: (cid: string) => CID<unknown, number, number, mul
214
236
  */
215
237
  declare const isCanonicallyEqual: (data1: unknown, data2: unknown) => Promise<boolean>;
216
238
 
217
- export { type JwsHeader, JwsVerificationError, type JwtClaims, type JwtCreateOptions, type JwtHeader, JwtVerificationError, type JwtVerifyOptions, type PrefixedID, assertJwsProfile, base64urlDecode, base64urlEncode, createJws, createJwt, createNewEd25519Keypair, dagCborCanonicalEncode, decodeJwsUnsafe, decodeJwtUnsafe, generateId, generateIdNoPrefix, importEd25519Keypair, isCanonicallyEqual, isValidEd25519Signature, isValidId, normalizedId, parseDagCborCID, sha256, signPayloadEd25519, verifyJws, verifyJwt };
239
+ export { type JwsHeader, JwsVerificationError, type JwtClaims, type JwtCreateOptions, type JwtHeader, JwtVerificationError, type JwtVerifyOptions, type PrefixedID, assertCanonicalJsonText, assertJwsProfile, base64urlDecode, base64urlEncode, createJws, createJwt, createNewEd25519Keypair, dagCborCanonicalEncode, decodeJwsUnsafe, decodeJwtUnsafe, generateId, generateIdNoPrefix, importEd25519Keypair, isCanonicallyEqual, isValidEd25519Signature, isValidId, normalizedId, parseDagCborCID, sha256, signPayloadEd25519, verifyJws, verifyJwt };
@@ -1,6 +1,7 @@
1
1
  import {
2
2
  JwsVerificationError,
3
3
  JwtVerificationError,
4
+ assertCanonicalJsonText,
4
5
  assertJwsProfile,
5
6
  base64urlDecode,
6
7
  base64urlEncode,
@@ -22,10 +23,11 @@ import {
22
23
  signPayloadEd25519,
23
24
  verifyJws,
24
25
  verifyJwt
25
- } from "../chunk-4LG2GEB2.js";
26
+ } from "../chunk-QTJZGXMH.js";
26
27
  export {
27
28
  JwsVerificationError,
28
29
  JwtVerificationError,
30
+ assertCanonicalJsonText,
29
31
  assertJwsProfile,
30
32
  base64urlDecode,
31
33
  base64urlEncode,
@@ -440,7 +440,8 @@ declare const MAX_SIGN_REQUEST_PAYLOAD_SIZE = 4096;
440
440
  *
441
441
  * Unknown envelope fields are preserved-and-ignored, matching every other wire
442
442
  * payload in this file. The signer-side target-payload check is deliberately
443
- * strict instead: a signer refuses fields it cannot render (see SIGNING.md).
443
+ * strict instead: a signer refuses fields it cannot render (see RELAY.md,
444
+ * Signer obligations).
444
445
  */
445
446
  declare const SignRequestPayload: z.ZodObject<{
446
447
  version: z.ZodLiteral<1>;
package/dist/index.d.ts CHANGED
@@ -1,6 +1,6 @@
1
- export { JwsHeader, JwsVerificationError, JwtClaims, JwtCreateOptions, JwtHeader, JwtVerificationError, JwtVerifyOptions, PrefixedID, assertJwsProfile, base64urlDecode, base64urlEncode, createJws, createJwt, createNewEd25519Keypair, dagCborCanonicalEncode, decodeJwsUnsafe, decodeJwtUnsafe, generateId, generateIdNoPrefix, importEd25519Keypair, isCanonicallyEqual, isValidEd25519Signature, isValidId, normalizedId, parseDagCborCID, sha256, signPayloadEd25519, verifyJws, verifyJwt } from './crypto/index.js';
2
- export { A as ARTIFACT_CID_ANCHOR_RE, a as ArtifactPayload, b as Attenuation, C as CONTENT_ID_ANCHOR_RE, c as ContentOperation, d as CountersignPayload, e as CredentialVerificationError, f as CreditClaimPayload, D as DFOSCredentialPayload, g as DeclaredKeyState, I as IdentityOperation, h as Iso8601, M as MAX_ARTIFACT_PAYLOAD_SIZE, i as MAX_CREDENTIAL_SIZE, j as MAX_CREDIT_CLAIM_SIZE, k as MAX_KEY_PROOFS, l as MAX_OPERATION_SIZE, m as MAX_SERVICES_ENTRIES, n as MAX_SERVICES_PAYLOAD_SIZE, o as MAX_SIGN_REQUEST_PAYLOAD_SIZE, p as MAX_SIGN_REQUEST_SIZE, q as MultikeyPublicKey, R as ResolvedIdentity, r as RevocationChecker, s as RevocationPayload, S as ServiceEntry, t as ServicesArray, u as SignRequestPayload, v as Signer, V as VerifiedDFOSCredential, w as VerifiedDelegationChain, x as VerifiedIdentity, y as VoidKeyMembership, z as createDFOSCredential, B as decodeDFOSCredentialUnsafe, E as isAttenuated, F as matchesResource, G as parseProtocolTimestampUnix, H as verifyDFOSCredential, J as verifyDelegationChain } from './dfos-credential-CtG0_n4P.js';
3
- export { AnchorKind, CreditClaimFailureReason, CreditClaimVerifyError, CreditEntry, CreditEntryState, ED25519_PRIV_MULTICODEC, ED25519_PUB_MULTICODEC, RECOGNIZED_SERVICE_TYPES, SignRequestFailureReason, SignRequestVerifyError, VerifiedArtifact, VerifiedContentChain, VerifiedCountersignature, VerifiedCreditClaim, VerifiedCreditEntry, VerifiedRevocation, VerifiedSignRequest, anchorsByLabel, assertCanonicalSignRequestPayload, assertServicesWithinCap, buildSignRequest, classifyAnchor, decodeMultikey, deriveChainIdentifier, deriveContentId, encodeEd25519Multikey, isRecognizedServiceType, relayEndpoints, signArtifact, signContentOperation, signCountersignature, signCreditClaim, signIdentityOperation, signRevocation, verifyArtifact, verifyContentChain, verifyContentExtensionFromTrustedState, verifyCountersignature, verifyCreditClaim, verifyCreditEntry, verifyIdentityChain, verifyIdentityExtensionFromTrustedState, verifyRevocation, verifySignRequest } from './chain/index.js';
1
+ export { JwsHeader, JwsVerificationError, JwtClaims, JwtCreateOptions, JwtHeader, JwtVerificationError, JwtVerifyOptions, PrefixedID, assertCanonicalJsonText, assertJwsProfile, base64urlDecode, base64urlEncode, createJws, createJwt, createNewEd25519Keypair, dagCborCanonicalEncode, decodeJwsUnsafe, decodeJwtUnsafe, generateId, generateIdNoPrefix, importEd25519Keypair, isCanonicallyEqual, isValidEd25519Signature, isValidId, normalizedId, parseDagCborCID, sha256, signPayloadEd25519, verifyJws, verifyJwt } from './crypto/index.js';
2
+ export { A as ARTIFACT_CID_ANCHOR_RE, a as ArtifactPayload, b as Attenuation, C as CONTENT_ID_ANCHOR_RE, c as ContentOperation, d as CountersignPayload, e as CredentialVerificationError, f as CreditClaimPayload, D as DFOSCredentialPayload, g as DeclaredKeyState, I as IdentityOperation, h as Iso8601, M as MAX_ARTIFACT_PAYLOAD_SIZE, i as MAX_CREDENTIAL_SIZE, j as MAX_CREDIT_CLAIM_SIZE, k as MAX_KEY_PROOFS, l as MAX_OPERATION_SIZE, m as MAX_SERVICES_ENTRIES, n as MAX_SERVICES_PAYLOAD_SIZE, o as MAX_SIGN_REQUEST_PAYLOAD_SIZE, p as MAX_SIGN_REQUEST_SIZE, q as MultikeyPublicKey, R as ResolvedIdentity, r as RevocationChecker, s as RevocationPayload, S as ServiceEntry, t as ServicesArray, u as SignRequestPayload, v as Signer, V as VerifiedDFOSCredential, w as VerifiedDelegationChain, x as VerifiedIdentity, y as VoidKeyMembership, z as createDFOSCredential, B as decodeDFOSCredentialUnsafe, E as isAttenuated, F as matchesResource, G as parseProtocolTimestampUnix, H as verifyDFOSCredential, J as verifyDelegationChain } from './dfos-credential-j-kHtFvG.js';
3
+ export { AnchorKind, CreditClaimFailureReason, CreditClaimVerifyError, CreditEntry, CreditEntryState, ED25519_PRIV_MULTICODEC, ED25519_PUB_MULTICODEC, RECOGNIZED_SERVICE_TYPES, SignRequestFailureReason, SignRequestVerifyError, VerifiedArtifact, VerifiedContentChain, VerifiedCountersignature, VerifiedCreditClaim, VerifiedCreditEntry, VerifiedRevocation, VerifiedSignRequest, anchorsByLabel, assertCanonicalSignRequestPayload, assertServicesWithinCap, buildSignRequest, classifyAnchor, decodeEd25519PublicMultikey, decodeMultikey, deriveChainIdentifier, deriveContentId, encodeEd25519Multikey, isRecognizedServiceType, relayEndpoints, signArtifact, signContentOperation, signCountersignature, signCreditClaim, signIdentityOperation, signRevocation, verifyArtifact, verifyContentChain, verifyContentExtensionFromTrustedState, verifyCountersignature, verifyCreditClaim, verifyCreditEntry, verifyIdentityChain, verifyIdentityExtensionFromTrustedState, verifyRevocation, verifySignRequest } from './chain/index.js';
4
4
  export { ApiRequestVerifyError, DEFAULT_PROOF_SKEW_SECONDS, DEFAULT_PROOF_WINDOW_SECONDS, DFOS_AUTH_SCHEME, EMPTY_BODY_SHA256, IDENTITY_PROOF_JWS_TYP, IdentityProofPayload, MAX_BODY_BYTES, MAX_PROOF_FRESHNESS_SPAN_SECONDS, MAX_REQUEST_PROOF_SIZE, ParsedProofPayload, ProofEnvelopeInput, ProofExtraMembers, ProofPresenterState, REQUEST_PROOF_JWS_TYP, RequestProofFailurePhase, RequestProofFailureReason, RequestProofPayload, ResolveProofPresenter, SignApiIdentityRequestInput, SignApiRequestInput, VerifiedProofEnvelope, apiIdentitySigningInput, apiRequestSigningInput, assertProofVerifierConfig, buildApiAuthHeaders, buildApiIdentityHeaders, canonicalExtraMembers, invalidProof, misconfiguredProof, parseDfosAuthorization, sha256BodyHash, signApiIdentityRequest, signApiRequest, unverifiableProof, verifyIdentityProofEnvelope, verifyRequestProofEnvelope } from './credentials/index.js';
5
5
  export { DEFAULT_KEY_PROOF_SKEW_SECONDS, KEY_ADD_JWS_TYP, KEY_ROLES, KeyProofFailureReason, KeyProofPayload, KeyProofVerifyError, KeyRole, MAX_KEY_PROOF_SIZE, SignKeyProofInput, VerifiedKeyProof, VerifyChainKeyProofOptions, VerifyKeyProofOptions, isCanonicalRoleSet, keyProofSigningInput, keyWordFingerprint, parseRoleSet, roleSetCovers, serializeRoleSet, signKeyProof, unsafeKeyProofSubject, verifyChainKeyProof, verifyKeyProof } from './key-proof/index.js';
6
6
  export { FoldOperation, INDEX_V1_SCHEMA, IndexDelta, IndexDocument, IndexEntry, LwwDelta, OrderKey, byteCompare, compareHeadPreference, compareLinear, foldIndexV1, foldLwwMap, linearize } from './fold/index.js';
package/dist/index.js CHANGED
@@ -52,7 +52,7 @@ import {
52
52
  verifyIdentityExtensionFromTrustedState,
53
53
  verifyRevocation,
54
54
  verifySignRequest
55
- } from "./chunk-LMAPBTDW.js";
55
+ } from "./chunk-OU2DPHCN.js";
56
56
  import {
57
57
  ApiRequestVerifyError,
58
58
  Attenuation,
@@ -92,7 +92,7 @@ import {
92
92
  verifyDelegationChain,
93
93
  verifyIdentityProofEnvelope,
94
94
  verifyRequestProofEnvelope
95
- } from "./chunk-T2YR5KWQ.js";
95
+ } from "./chunk-IV3TIYKP.js";
96
96
  import {
97
97
  DEFAULT_KEY_PROOF_SKEW_SECONDS,
98
98
  KEY_ADD_JWS_TYP,
@@ -109,16 +109,18 @@ import {
109
109
  unsafeKeyProofSubject,
110
110
  verifyChainKeyProof,
111
111
  verifyKeyProof
112
- } from "./chunk-JVSC67DC.js";
112
+ } from "./chunk-QRCOMLAP.js";
113
113
  import {
114
114
  ED25519_PRIV_MULTICODEC,
115
115
  ED25519_PUB_MULTICODEC,
116
+ decodeEd25519PublicMultikey,
116
117
  decodeMultikey,
117
118
  encodeEd25519Multikey
118
- } from "./chunk-IDVYITX7.js";
119
+ } from "./chunk-F7RHI2CK.js";
119
120
  import {
120
121
  JwsVerificationError,
121
122
  JwtVerificationError,
123
+ assertCanonicalJsonText,
122
124
  assertJwsProfile,
123
125
  base64urlDecode,
124
126
  base64urlEncode,
@@ -140,7 +142,7 @@ import {
140
142
  signPayloadEd25519,
141
143
  verifyJws,
142
144
  verifyJwt
143
- } from "./chunk-4LG2GEB2.js";
145
+ } from "./chunk-QTJZGXMH.js";
144
146
  import {
145
147
  INDEX_V1_SCHEMA,
146
148
  byteCompare,
@@ -205,6 +207,7 @@ export {
205
207
  anchorsByLabel,
206
208
  apiIdentitySigningInput,
207
209
  apiRequestSigningInput,
210
+ assertCanonicalJsonText,
208
211
  assertCanonicalSignRequestPayload,
209
212
  assertJwsProfile,
210
213
  assertProofVerifierConfig,
@@ -226,6 +229,7 @@ export {
226
229
  createNewEd25519Keypair,
227
230
  dagCborCanonicalEncode,
228
231
  decodeDFOSCredentialUnsafe,
232
+ decodeEd25519PublicMultikey,
229
233
  decodeJwsUnsafe,
230
234
  decodeJwtUnsafe,
231
235
  decodeMultikey,
@@ -43,7 +43,7 @@ declare const isCanonicalRoleSet: (value: string) => boolean;
43
43
  declare const roleSetCovers: (value: string, role: KeyRole) => boolean;
44
44
 
45
45
  /**
46
- * The first registered purpose in KEY-PROOF.md's purpose registry: the candidate
46
+ * The registered key-proof purpose in PROTOCOL.md, The envelope: the candidate
47
47
  * key presents for addition to a ceremony-named identity's `authKeys`/
48
48
  * `assertKeys` sets.
49
49
  *
@@ -57,7 +57,7 @@ declare const KEY_ADD_JWS_TYP = "did:dfos:key-add";
57
57
  declare const MAX_KEY_PROOF_SIZE = 4096;
58
58
  /**
59
59
  * RECOMMENDED acceptance window, in seconds, EITHER SIDE of the verifier's clock
60
- * — matching a ceremony's own lifetime (KEY-PROOF.md, Verification step 5).
60
+ * — matching a ceremony's own lifetime (INTEGRATIONS.md, Presentation verification).
61
61
  */
62
62
  declare const DEFAULT_KEY_PROOF_SKEW_SECONDS = 300;
63
63
  /**
@@ -146,8 +146,8 @@ interface SignKeyProofInput {
146
146
  * through `createJws`, whose `JwsHeader` requires a `kid` this envelope must not
147
147
  * carry.
148
148
  *
149
- * HOLDER OBLIGATIONS THIS FUNCTION CANNOT DISCHARGE (KEY-PROOF.md, Holder
150
- * Obligations). A holder MUST show its human — before calling this — the
149
+ * HOLDER OBLIGATIONS THIS FUNCTION CANNOT DISCHARGE (INTEGRATIONS.md, Holder
150
+ * obligations). A holder MUST show its human — before calling this — the
151
151
  * audience, the purpose, the adopting identity, and the roles. A proof is
152
152
  * consent, and consent that was never displayed was never given.
153
153
  *
@@ -210,10 +210,10 @@ interface VerifyKeyProofOptions {
210
210
  /** What a verified key proof hands back. */
211
211
  interface VerifiedKeyProof {
212
212
  /**
213
- * The validated payload. THE CALLER MUST NOW RUN STEP 6 against `payload.nonce`:
214
- * check that it is a nonce this verifier minted, for this ceremony, not yet
215
- * consumed, and consume it ATOMICALLY (check-and-delete) so two racing
216
- * completions cannot both pass.
213
+ * The validated payload. THE CALLER MUST NOW RUN THE NONCE CHECK against
214
+ * `payload.nonce`: check that it is a nonce this verifier minted, for this
215
+ * ceremony, not yet consumed, and consume it ATOMICALLY (check-and-delete) so
216
+ * two racing completions cannot both pass.
217
217
  */
218
218
  payload: KeyProofPayload;
219
219
  /** The header `typ` — equal to `expectedTyp`, since anything else rejected. */
@@ -222,17 +222,18 @@ interface VerifiedKeyProof {
222
222
  now: number;
223
223
  }
224
224
  /**
225
- * Verify a key proof AT PRESENTATION TIME — KEY-PROOF.md's verification algorithm
226
- * steps 1–5 and 7: size cap, header gates, the closed payload schema over
227
- * CANONICAL bytes, the four expectation arms (audience, did, roleSet, prevCID),
228
- * freshness, and the signature against the payload's OWN `publicKeyMultibase`.
225
+ * Verify a key proof AT PRESENTATION TIME — INTEGRATIONS.md, Presentation
226
+ * verification except its nonce check: size cap, header gates, the closed
227
+ * payload schema over CANONICAL bytes, the four expectation arms (audience,
228
+ * did, roleSet, prevCID), freshness, and the signature against the payload's
229
+ * OWN `publicKeyMultibase`.
229
230
  *
230
231
  * EVERY EXPECTATION IS THE DEPLOYMENT'S OWN VALUE. There is no arm here that
231
232
  * compares the envelope to itself. `expectedDid`, `expectedRoleSet` and
232
233
  * `expectedPrevCID` are the position the completing authority is about to WRITE;
233
234
  * if the envelope names a different one, the holder consented to something else.
234
235
  *
235
- * STEP 6 (NONCE) IS THE CALLER'S, and this function cannot stand in for it. The
236
+ * THE NONCE CHECK IS THE CALLER'S, and this function cannot stand in for it. The
236
237
  * nonce MUST be one this verifier minted, for this ceremony, not yet consumed,
237
238
  * checked and consumed ATOMICALLY — a check-and-delete against the verifier's
238
239
  * own store, which is state this pure function does not hold. It is returned on
@@ -14,9 +14,9 @@ import {
14
14
  unsafeKeyProofSubject,
15
15
  verifyChainKeyProof,
16
16
  verifyKeyProof
17
- } from "../chunk-JVSC67DC.js";
18
- import "../chunk-IDVYITX7.js";
19
- import "../chunk-4LG2GEB2.js";
17
+ } from "../chunk-QRCOMLAP.js";
18
+ import "../chunk-F7RHI2CK.js";
19
+ import "../chunk-QTJZGXMH.js";
20
20
  export {
21
21
  DEFAULT_KEY_PROOF_SKEW_SECONDS,
22
22
  KEY_ADD_JWS_TYP,
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@metalabel/dfos-protocol",
3
- "version": "0.51.0",
3
+ "version": "0.52.0",
4
4
  "type": "module",
5
5
  "description": "DFOS Protocol — Ed25519 signed chain primitives, services, credentials, and verification",
6
6
  "license": "MIT",