@credo-ts/core
Version:
<p align="center"> <br /> <img alt="Credo Logo" src="https://github.com/openwallet-foundation/credo-ts/blob/c7886cb8377ceb8ee4efe8d264211e561a75072d/images/credo-logo.png" height="250px" /> </p> <h1 align="center"><b>Credo - Core</b></h1
1 lines • 10 kB
Source Map (JSON)
{"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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"}