@peac/protocol 0.12.1 → 0.12.3

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/dist/index.mjs CHANGED
@@ -2,9 +2,9 @@ import { uuidv7 } from 'uuidv7';
2
2
  import { sign, signWire02, decode, verify, jcsHash, sha256Hex, computeJwkThumbprint, jwkToPublicKeyBytes, base64urlDecode } from '@peac/crypto';
3
3
  export { base64urlDecode, base64urlEncode, computeJwkThumbprint, generateKeypair, jwkToPublicKeyBytes, sha256Bytes, sha256Hex, verify } from '@peac/crypto';
4
4
  import { ZodError } from 'zod';
5
- import { isValidPurposeToken, isCanonicalPurpose, isValidPurposeReason, isValidWorkflowContext, createWorkflowContextInvalidError, hasValidDagSemantics, createWorkflowDagInvalidError, WORKFLOW_EXTENSION_KEY, validateKernelConstraints, createConstraintViolationError, ReceiptClaims, createEvidenceNotJsonError, validateSubjectSnapshot, isCanonicalIss, Wire02ClaimsSchema, PEAC_ISSUER_CONFIG_MAX_BYTES, validateRevokedKeys, PEAC_ISSUER_CONFIG_PATH, PEAC_POLICY_MAX_BYTES, PEAC_POLICY_PATH, PEAC_POLICY_FALLBACK_PATH, WARNING_TYP_MISSING, parseReceiptClaims, checkOccurredAtSkew, REGISTERED_RECEIPT_TYPES, WARNING_TYPE_UNREGISTERED, REGISTERED_EXTENSION_GROUP_KEYS, isValidExtensionKey, WARNING_UNKNOWN_EXTENSION, verifyPolicyBinding, sortWarnings, PEAC_RECEIPT_HEADER, PEAC_PURPOSE_HEADER, parsePurposeHeader, PEAC_PURPOSE_APPLIED_HEADER, PEAC_PURPOSE_REASON_HEADER } from '@peac/schema';
5
+ import { isValidPurposeToken, isCanonicalPurpose, isValidPurposeReason, isValidWorkflowContext, createWorkflowContextInvalidError, hasValidDagSemantics, createWorkflowDagInvalidError, WORKFLOW_EXTENSION_KEY, validateKernelConstraints, createConstraintViolationError, ReceiptClaims, createEvidenceNotJsonError, validateSubjectSnapshot, isCanonicalIss, Wire02ClaimsSchema, PEAC_ISSUER_CONFIG_MAX_BYTES, validateRevokedKeys, PEAC_ISSUER_CONFIG_PATH, PEAC_POLICY_MAX_BYTES, PEAC_POLICY_PATH, PEAC_POLICY_FALLBACK_PATH, WARNING_TYP_MISSING, parseReceiptClaims, checkOccurredAtSkew, REGISTERED_RECEIPT_TYPES, WARNING_TYPE_UNREGISTERED, REGISTERED_EXTENSION_GROUP_KEYS, isValidExtensionKey, WARNING_UNKNOWN_EXTENSION, WARNING_EXTENSION_GROUP_MISSING, WARNING_EXTENSION_GROUP_MISMATCH, verifyPolicyBinding, sortWarnings, PEAC_RECEIPT_HEADER, PEAC_PURPOSE_HEADER, parsePurposeHeader, PEAC_PURPOSE_APPLIED_HEADER, PEAC_PURPOSE_REASON_HEADER } from '@peac/schema';
6
6
  import { createHash } from 'crypto';
7
- import { VERIFIER_LIMITS, VERIFIER_NETWORK, HASH, VERIFIER_POLICY_VERSION, VERIFICATION_REPORT_VERSION, WIRE_TYPE } from '@peac/kernel';
7
+ import { VERIFIER_LIMITS, VERIFIER_NETWORK, TYPE_TO_EXTENSION_MAP, HASH, VERIFIER_POLICY_VERSION, VERIFICATION_REPORT_VERSION, WIRE_TYPE } from '@peac/kernel';
8
8
 
9
9
  // src/issue.ts
10
10
  function fireTelemetryHook(fn, input) {
@@ -1392,6 +1392,35 @@ async function verifyReceipt(optionsOrJws) {
1392
1392
  };
1393
1393
  }
1394
1394
  }
1395
+
1396
+ // src/type-extension-check.ts
1397
+ function checkTypeExtensionMapping(kind, type, extensions, typeToExtensionMap, registeredExtensionGroupKeys) {
1398
+ if (kind === "challenge") {
1399
+ return { status: "skip" };
1400
+ }
1401
+ const expectedGroup = typeToExtensionMap.get(type);
1402
+ if (expectedGroup === void 0) {
1403
+ return { status: "skip" };
1404
+ }
1405
+ if (extensions !== void 0 && Object.prototype.hasOwnProperty.call(extensions, expectedGroup)) {
1406
+ return { status: "ok" };
1407
+ }
1408
+ const presentRegistered = [];
1409
+ if (extensions !== void 0) {
1410
+ for (const key of Object.keys(extensions)) {
1411
+ if (key !== expectedGroup && registeredExtensionGroupKeys.has(key)) {
1412
+ presentRegistered.push(key);
1413
+ }
1414
+ }
1415
+ }
1416
+ return {
1417
+ status: presentRegistered.length > 0 ? "mismatch" : "missing",
1418
+ expected_extension_group: expectedGroup,
1419
+ present_registered_extension_groups: presentRegistered
1420
+ };
1421
+ }
1422
+
1423
+ // src/verify-local.ts
1395
1424
  function isCryptoError(err) {
1396
1425
  return err !== null && typeof err === "object" && "name" in err && err.name === "CryptoError" && "code" in err && typeof err.code === "string" && err.code.startsWith("CRYPTO_") && "message" in err && typeof err.message === "string";
1397
1426
  }
@@ -1518,6 +1547,34 @@ async function verifyLocal(jws, publicKey, options = {}) {
1518
1547
  }
1519
1548
  }
1520
1549
  }
1550
+ const typeExtCheck = checkTypeExtensionMapping(
1551
+ claims.kind,
1552
+ claims.type,
1553
+ claims.extensions,
1554
+ TYPE_TO_EXTENSION_MAP,
1555
+ REGISTERED_EXTENSION_GROUP_KEYS
1556
+ );
1557
+ if (typeExtCheck.status === "missing" || typeExtCheck.status === "mismatch") {
1558
+ const warningCode = typeExtCheck.status === "missing" ? WARNING_EXTENSION_GROUP_MISSING : WARNING_EXTENSION_GROUP_MISMATCH;
1559
+ const errorCode = typeExtCheck.status === "missing" ? "E_EXTENSION_GROUP_REQUIRED" : "E_EXTENSION_GROUP_MISMATCH";
1560
+ if (strictness === "strict") {
1561
+ return {
1562
+ valid: false,
1563
+ code: errorCode,
1564
+ message: `Type "${claims.type}" expects extension group "${typeExtCheck.expected_extension_group}" but it is ${typeExtCheck.status === "mismatch" ? "replaced by a different registered group" : "absent"}`,
1565
+ details: {
1566
+ type: claims.type,
1567
+ expected_extension_group: typeExtCheck.expected_extension_group,
1568
+ present_registered_extension_groups: typeExtCheck.present_registered_extension_groups
1569
+ }
1570
+ };
1571
+ }
1572
+ accumulatedWarnings.push({
1573
+ code: warningCode,
1574
+ message: `Type "${claims.type}" expects extension group "${typeExtCheck.expected_extension_group}"`,
1575
+ pointer: "/type"
1576
+ });
1577
+ }
1521
1578
  if (policyDigest !== void 0 && !HASH.pattern.test(policyDigest)) {
1522
1579
  return {
1523
1580
  valid: false,
@@ -1854,7 +1911,7 @@ var VerificationReportBuilder = class {
1854
1911
  reason,
1855
1912
  severity: reasonCodeToSeverity(reason),
1856
1913
  receipt_type: options?.receiptType ?? WIRE_TYPE,
1857
- // Wire 0.1: always 'unavailable' (DD-49). Wire 0.2 will set this via options.
1914
+ // Wire 0.1: always 'unavailable'. Wire 0.2 will set this via options.
1858
1915
  policy_binding: "unavailable",
1859
1916
  ...options?.issuer && { issuer: options.issuer },
1860
1917
  ...options?.kid && { kid: options.kid }