@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
JavaScript
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