UNPKG

@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

69 lines (68 loc) • 5.45 kB
import { asArray } from "../../../utils/array.mjs"; import { equalsIgnoreOrder } from "../../../utils/deepEquality.mjs"; import { MultiBaseEncoder } from "../../../utils/MultiBaseEncoder.mjs"; import "../../../utils/index.mjs"; import { isXsdDateTimeStamp } from "./iso8601Datetime.mjs"; import { W3cDataIntegrityProcessingError, createInvalidResult, createIssue } from "../W3cDataIntegrityError.mjs"; //#region src/modules/w3c-di/proof-processing/proofValidation.ts /** * Implements VC Data Integrity v1.0 §4.4 step 4 required-member validation. * MANDATORY GATE: all downstream validation and cryptosuite verification assume this passed. */ function validateProofRequiredMembers(proof) { if (!proof || typeof proof !== "object") return "Proof must be a non-null object"; const dataIntegrityProof = proof; if (dataIntegrityProof.type !== "DataIntegrityProof") return "Proof type must be 'DataIntegrityProof'"; if (typeof dataIntegrityProof.cryptosuite !== "string") return "Proof cryptosuite is required"; if (typeof dataIntegrityProof.proofPurpose !== "string") return "Proof proofPurpose is required"; if (typeof dataIntegrityProof.verificationMethod !== "string") return "Proof verificationMethod is required"; if (typeof dataIntegrityProof.proofValue !== "string") return "Proof proofValue is required"; } /** * Implements VC Data Integrity v1.0 §4.4 step 8 semantic field-format validation. * * Prerequisite: validateProofRequiredMembers() has already passed for this proof. */ function validateProofFieldFormats(proof) { if (!isValidAbsoluteUrl(proof.verificationMethod)) return createInvalidResult(createIssue("https://w3id.org/security#PROOF_VERIFICATION_ERROR", "Proof verificationMethod must be a valid URL", `Received '${proof.verificationMethod}'`)); if (typeof proof.id === "string") { if (!isValidAbsoluteUrl(proof.id)) return createInvalidResult(createIssue("https://w3id.org/security#PROOF_VERIFICATION_ERROR", "Proof id must be a valid URL", `Received '${proof.id}'`)); } if (typeof proof.created === "string" && !isXsdDateTimeStamp(proof.created)) return createInvalidResult(createIssue("https://w3id.org/security#PROOF_VERIFICATION_ERROR", "Proof created must be a valid dateTimeStamp", `Received '${proof.created}'`)); if (typeof proof.expires === "string" && !isXsdDateTimeStamp(proof.expires)) return createInvalidResult(createIssue("https://w3id.org/security#PROOF_VERIFICATION_ERROR", "Proof expires must be a valid dateTimeStamp", `Received '${proof.expires}'`)); if (!MultiBaseEncoder.isValid(proof.proofValue)) return createInvalidResult(createIssue("https://w3id.org/security#PROOF_VERIFICATION_ERROR", "Proof proofValue must be a valid multibase-encoded value")); } function assertCreatedProofPostconditions(proof, options, expectedCryptosuite) { const throwPostconditionError = (detail) => { throw new W3cDataIntegrityProcessingError("https://w3id.org/security#PROOF_GENERATION_ERROR", "Error creating Data Integrity proof", detail); }; const proofValidationError = validateProofRequiredMembers(proof); if (proofValidationError) throwPostconditionError(proofValidationError); if (proof.cryptosuite !== expectedCryptosuite) throwPostconditionError(`Created proof cryptosuite '${proof.cryptosuite}' does not match requested cryptosuite '${expectedCryptosuite}'`); if (proof.verificationMethod !== options.verificationMethod) throwPostconditionError(`Created proof verificationMethod '${proof.verificationMethod}' does not match requested '${options.verificationMethod}'`); if (proof.proofPurpose !== options.proofPurpose) throwPostconditionError(`Created proof proofPurpose '${proof.proofPurpose}' does not match requested '${options.proofPurpose}'`); if (options.challenge !== void 0 && proof.challenge !== options.challenge) throwPostconditionError(`Created proof challenge '${proof.challenge ?? "undefined"}' does not match requested '${options.challenge}'`); if (options.nonce !== void 0 && proof.nonce !== options.nonce) throwPostconditionError(`Created proof nonce '${proof.nonce ?? "undefined"}' does not match requested '${options.nonce}'`); if (options.created !== void 0 && proof.created !== options.created) throwPostconditionError(`Created proof created '${proof.created ?? "undefined"}' does not match requested '${options.created}'`); if (options.expires !== void 0 && proof.expires !== options.expires) throwPostconditionError(`Created proof expires '${proof.expires ?? "undefined"}' does not match requested '${options.expires}'`); if (options.domain !== void 0) { const expectedDomain = [...new Set(asArray(options.domain))]; const actualDomain = [...new Set(asArray(proof.domain))]; if (!equalsIgnoreOrder(expectedDomain, actualDomain)) throwPostconditionError("Created proof domain does not match requested domain"); } if (options.previousProof !== void 0) { const expectedPreviousProof = [...new Set(asArray(options.previousProof))]; const actualPreviousProof = [...new Set(asArray(proof.previousProof))]; if (!equalsIgnoreOrder(expectedPreviousProof, actualPreviousProof)) throwPostconditionError("Created proof previousProof does not match requested previousProof"); } } function isValidAbsoluteUrl(value) { try { return new URL(value).protocol.length > 0; } catch { return false; } } //#endregion export { assertCreatedProofPostconditions, validateProofFieldFormats, validateProofRequiredMembers }; //# sourceMappingURL=proofValidation.mjs.map