{"version":3,"file":"proofValidation.mjs","names":[],"sources":["../../../../src/modules/w3c-di/proof-processing/proofValidation.ts"],"sourcesContent":["import { asArray, equalsIgnoreOrder } from '../../../utils'\nimport { MultiBaseEncoder } from '../../../utils/MultiBaseEncoder'\nimport type { W3cDataIntegrityVerifyFailure } from '../W3cDataIntegrityError'\nimport {\n  createInvalidResult,\n  createIssue,\n  W3cDataIntegrityProcessingError,\n  W3cDataIntegrityProcessingErrorCode,\n} from '../W3cDataIntegrityError'\nimport type { W3cDataIntegrityCryptosuiteProof } from '../W3cDataIntegrityProof'\nimport { isXsdDateTimeStamp } from './iso8601Datetime'\n\n// ─── Exported validators ──────────────────────────────────────────────────────\n\n/**\n * Implements VC Data Integrity v1.0 §4.4 step 4 required-member validation.\n * MANDATORY GATE: all downstream validation and cryptosuite verification assume this passed.\n */\nexport function validateProofRequiredMembers(proof: unknown): string | undefined {\n  if (!proof || typeof proof !== 'object') {\n    return 'Proof must be a non-null object'\n  }\n\n  const dataIntegrityProof = proof as Record<string, unknown>\n\n  if (dataIntegrityProof.type !== 'DataIntegrityProof') {\n    return \"Proof type must be 'DataIntegrityProof'\"\n  }\n\n  if (typeof dataIntegrityProof.cryptosuite !== 'string') {\n    return 'Proof cryptosuite is required'\n  }\n\n  if (typeof dataIntegrityProof.proofPurpose !== 'string') {\n    return 'Proof proofPurpose is required'\n  }\n\n  if (typeof dataIntegrityProof.verificationMethod !== 'string') {\n    return 'Proof verificationMethod is required'\n  }\n\n  if (typeof dataIntegrityProof.proofValue !== 'string') {\n    return 'Proof proofValue is required'\n  }\n\n  return undefined\n}\n\n/**\n * Implements VC Data Integrity v1.0 §4.4 step 8 semantic field-format validation.\n *\n * Prerequisite: validateProofRequiredMembers() has already passed for this proof.\n */\nexport function validateProofFieldFormats(\n  proof: W3cDataIntegrityCryptosuiteProof\n): W3cDataIntegrityVerifyFailure | undefined {\n  // Assumes validateProofRequiredMembers() has already validated proof structure.\n  // This function validates only semantic/format constraints on required members.\n\n  if (!isValidAbsoluteUrl(proof.verificationMethod)) {\n    return createInvalidResult(\n      createIssue(\n        W3cDataIntegrityProcessingErrorCode.ProofVerificationError,\n        'Proof verificationMethod must be a valid URL',\n        `Received '${proof.verificationMethod}'`\n      )\n    )\n  }\n\n  if (typeof proof.id === 'string') {\n    if (!isValidAbsoluteUrl(proof.id)) {\n      return createInvalidResult(\n        createIssue(\n          W3cDataIntegrityProcessingErrorCode.ProofVerificationError,\n          'Proof id must be a valid URL',\n          `Received '${proof.id}'`\n        )\n      )\n    }\n  }\n\n  if (typeof proof.created === 'string' && !isXsdDateTimeStamp(proof.created)) {\n    return createInvalidResult(\n      createIssue(\n        W3cDataIntegrityProcessingErrorCode.ProofVerificationError,\n        'Proof created must be a valid dateTimeStamp',\n        `Received '${proof.created}'`\n      )\n    )\n  }\n\n  if (typeof proof.expires === 'string' && !isXsdDateTimeStamp(proof.expires)) {\n    return createInvalidResult(\n      createIssue(\n        W3cDataIntegrityProcessingErrorCode.ProofVerificationError,\n        'Proof expires must be a valid dateTimeStamp',\n        `Received '${proof.expires}'`\n      )\n    )\n  }\n\n  // Validate proofValue using the shared multibase decoder so prefix and alphabet checks stay consistent.\n  if (!MultiBaseEncoder.isValid(proof.proofValue)) {\n    return createInvalidResult(\n      createIssue(\n        W3cDataIntegrityProcessingErrorCode.ProofVerificationError,\n        'Proof proofValue must be a valid multibase-encoded value'\n      )\n    )\n  }\n\n  return undefined\n}\n\n// ─── Proof option postcondition assertions ────────────────────────────────────\n\nexport function assertCreatedProofPostconditions(\n  proof: W3cDataIntegrityCryptosuiteProof,\n  options: {\n    verificationMethod: string\n    proofPurpose: string\n    challenge?: string\n    nonce?: string\n    created?: string\n    expires?: string\n    domain?: string | string[]\n    previousProof?: string | string[]\n  },\n  expectedCryptosuite: string\n): void {\n  const throwPostconditionError = (detail: string) => {\n    throw new W3cDataIntegrityProcessingError(\n      W3cDataIntegrityProcessingErrorCode.ProofGenerationError,\n      'Error creating Data Integrity proof',\n      detail\n    )\n  }\n\n  const proofValidationError = validateProofRequiredMembers(proof)\n  if (proofValidationError) {\n    throwPostconditionError(proofValidationError)\n  }\n\n  if (proof.cryptosuite !== expectedCryptosuite) {\n    throwPostconditionError(\n      `Created proof cryptosuite '${proof.cryptosuite}' does not match requested cryptosuite '${expectedCryptosuite}'`\n    )\n  }\n\n  if (proof.verificationMethod !== options.verificationMethod) {\n    throwPostconditionError(\n      `Created proof verificationMethod '${proof.verificationMethod}' does not match requested '${options.verificationMethod}'`\n    )\n  }\n\n  if (proof.proofPurpose !== options.proofPurpose) {\n    throwPostconditionError(\n      `Created proof proofPurpose '${proof.proofPurpose}' does not match requested '${options.proofPurpose}'`\n    )\n  }\n\n  if (options.challenge !== undefined && proof.challenge !== options.challenge) {\n    throwPostconditionError(\n      `Created proof challenge '${proof.challenge ?? 'undefined'}' does not match requested '${options.challenge}'`\n    )\n  }\n\n  if (options.nonce !== undefined && proof.nonce !== options.nonce) {\n    throwPostconditionError(\n      `Created proof nonce '${proof.nonce ?? 'undefined'}' does not match requested '${options.nonce}'`\n    )\n  }\n\n  if (options.created !== undefined && proof.created !== options.created) {\n    throwPostconditionError(\n      `Created proof created '${proof.created ?? 'undefined'}' does not match requested '${options.created}'`\n    )\n  }\n\n  if (options.expires !== undefined && proof.expires !== options.expires) {\n    throwPostconditionError(\n      `Created proof expires '${proof.expires ?? 'undefined'}' does not match requested '${options.expires}'`\n    )\n  }\n\n  if (options.domain !== undefined) {\n    const expectedDomain = [...new Set(asArray(options.domain))]\n    const actualDomain = [...new Set(asArray(proof.domain))]\n    if (!equalsIgnoreOrder(expectedDomain, actualDomain)) {\n      throwPostconditionError('Created proof domain does not match requested domain')\n    }\n  }\n\n  if (options.previousProof !== undefined) {\n    const expectedPreviousProof = [...new Set(asArray(options.previousProof))]\n    const actualPreviousProof = [...new Set(asArray(proof.previousProof))]\n    if (!equalsIgnoreOrder(expectedPreviousProof, actualPreviousProof)) {\n      throwPostconditionError('Created proof previousProof does not match requested previousProof')\n    }\n  }\n}\n\n// ─── Private helpers ──────────────────────────────────────────────────────────\n\nfunction isValidAbsoluteUrl(value: string): boolean {\n  try {\n    // WHATWG URL accepts DID URLs, URNs, and HTTPS URLs used by Data Integrity proofs.\n    const parsedUrl = new URL(value)\n    return parsedUrl.protocol.length > 0\n  } catch {\n    return false\n  }\n}\n"],"mappings":"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"}