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

115 lines (114 loc) • 3.72 kB
import { CredoError } from "../error/CredoError.mjs"; import "../error/index.mjs"; import { TypedArrayEncoder } from "./TypedArrayEncoder.mjs"; import { Hasher } from "../crypto/hashes/Hasher.mjs"; //#region src/utils/IntegrityVerifier.ts /** * Verifies Subresource Integrity (SRI) metadata according to W3C specification. * * This class implements the verification logic for integrity metadata strings * as defined in the W3C Subresource Integrity specification. * * @see https://www.w3.org/TR/SRI/ */ var IntegrityVerifier = class IntegrityVerifier { /** * Verifies the integrity of raw data against provided integrity metadata. * * @param data - The data to verify * @param integrityMetadata - The integrity metadata string (e.g., "sha256-...") * @throws {CredoError} if verification fails */ static verifyIntegrity(data, integrityMetadata) { const parsedMetadata = IntegrityVerifier.parseIntegrityMetadata(integrityMetadata); if (parsedMetadata.length === 0) throw new CredoError(`Integrity check failed. Parsed integrity metadata is empty.`); const strongestMetadata = IntegrityVerifier.getStrongestMetadata(parsedMetadata); for (const metadata of strongestMetadata) if (IntegrityVerifier.applyAlgorithmToBytes(data, metadata.alg) === metadata.val) return; throw new CredoError(`Integrity check failed. None of the provided hashes match the computed hash for the response.`); } /** * Parses integrity metadata string into structured format. * * @param metadata - The integrity metadata string * @returns Array of parsed metadata objects */ static parseIntegrityMetadata(metadata) { const result = []; const validAlgorithms = [ "sha256", "sha384", "sha512" ]; const items = metadata.trim().split(/\s+/); for (const item of items) { if (!item) continue; const [algorithmExpression] = item.split("?"); const parts = algorithmExpression.split("-"); if (parts.length < 2) continue; const algorithm = parts[0].toLowerCase(); const base64Value = parts.slice(1).join("-"); if (validAlgorithms.includes(algorithm)) result.push({ alg: algorithm, val: base64Value }); } return result; } /** * Returns the metadata for the strongest algorithm(s) in the set. * * @param metadataSet - Array of parsed metadata * @returns Array containing only the strongest algorithm's metadata */ static getStrongestMetadata(metadataSet) { if (metadataSet.length === 0) return []; const algorithmPriority = { sha256: 0, sha384: 1, sha512: 2 }; let strongest = null; const result = []; for (const item of metadataSet) { if (!strongest) { strongest = item; result.push(item); continue; } const currentIndex = algorithmPriority[strongest.alg]; const newIndex = algorithmPriority[item.alg]; if (newIndex > currentIndex) { strongest = item; result.length = 0; result.push(item); } else if (newIndex === currentIndex) result.push(item); } return result; } /** * Applies the specified hash algorithm to the given bytes. * * @param bytes - The bytes to hash * @param algorithm - The hash algorithm name * @returns Base64-encoded hash value */ static applyAlgorithmToBytes(bytes, algorithm) { let hashResult; switch (algorithm) { case "sha256": hashResult = Hasher.hash(bytes, "sha-256"); break; case "sha384": hashResult = Hasher.hash(bytes, "sha-384"); break; case "sha512": hashResult = Hasher.hash(bytes, "sha-512"); break; default: throw new CredoError(`Unsupported hash algorithm: ${algorithm}`); } return TypedArrayEncoder.toBase64(hashResult); } }; //#endregion export { IntegrityVerifier }; //# sourceMappingURL=IntegrityVerifier.mjs.map