@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 • 6.55 kB
Source Map (JSON)
{"version":3,"file":"IntegrityVerifier.mjs","names":[],"sources":["../../src/utils/IntegrityVerifier.ts"],"sourcesContent":["import { Hasher } from '../crypto/hashes/Hasher'\nimport { CredoError } from '../error'\nimport { TypedArrayEncoder } from './TypedArrayEncoder'\n\n/**\n * Verifies Subresource Integrity (SRI) metadata according to W3C specification.\n *\n * This class implements the verification logic for integrity metadata strings\n * as defined in the W3C Subresource Integrity specification.\n *\n * @see https://www.w3.org/TR/SRI/\n */\n// biome-ignore lint/complexity/noStaticOnlyClass: no explanation\nexport class IntegrityVerifier {\n /**\n * Verifies the integrity of raw data against provided integrity metadata.\n *\n * @param data - The data to verify\n * @param integrityMetadata - The integrity metadata string (e.g., \"sha256-...\")\n * @throws {CredoError} if verification fails\n */\n public static verifyIntegrity(data: Uint8Array, integrityMetadata: string): void {\n const parsedMetadata = IntegrityVerifier.parseIntegrityMetadata(integrityMetadata)\n\n // If metadata is empty, no verification is required\n if (parsedMetadata.length === 0) {\n throw new CredoError(`Integrity check failed. Parsed integrity metadata is empty.`)\n }\n\n // Get the strongest algorithm's metadata\n const strongestMetadata = IntegrityVerifier.getStrongestMetadata(parsedMetadata)\n\n // Try to match any of the strongest hashes\n for (const metadata of strongestMetadata) {\n const actualValue = IntegrityVerifier.applyAlgorithmToBytes(data, metadata.alg)\n if (actualValue === metadata.val) {\n return\n }\n }\n\n throw new CredoError(\n `Integrity check failed. None of the provided hashes match the computed hash for the response.`\n )\n }\n\n /**\n * Parses integrity metadata string into structured format.\n *\n * @param metadata - The integrity metadata string\n * @returns Array of parsed metadata objects\n */\n private static parseIntegrityMetadata(metadata: string): Array<{ alg: string; val: string }> {\n const result: Array<{ alg: string; val: string }> = []\n const validAlgorithms = ['sha256', 'sha384', 'sha512']\n\n // Split by whitespace\n const items = metadata.trim().split(/\\s+/)\n\n for (const item of items) {\n if (!item) continue\n\n // Remove options (anything after '?')\n const [algorithmExpression] = item.split('?')\n\n // Split algorithm and base64 value\n const parts = algorithmExpression.split('-')\n if (parts.length < 2) continue\n\n const algorithm = parts[0].toLowerCase()\n const base64Value = parts.slice(1).join('-') // Rejoin in case base64 contains hyphens\n\n // Only include supported algorithms\n if (validAlgorithms.includes(algorithm)) {\n result.push({ alg: algorithm, val: base64Value })\n }\n }\n\n return result\n }\n\n /**\n * Returns the metadata for the strongest algorithm(s) in the set.\n *\n * @param metadataSet - Array of parsed metadata\n * @returns Array containing only the strongest algorithm's metadata\n */\n private static getStrongestMetadata(\n metadataSet: Array<{ alg: string; val: string }>\n ): Array<{ alg: string; val: string }> {\n if (metadataSet.length === 0) {\n return []\n }\n\n // Algorithm priority (higher = stronger)\n const algorithmPriority: Record<string, number> = {\n sha256: 0,\n sha384: 1,\n sha512: 2,\n }\n\n let strongest: { alg: string; val: string } | null = null\n const result: Array<{ alg: string; val: string }> = []\n\n for (const item of metadataSet) {\n if (!strongest) {\n strongest = item\n result.push(item)\n continue\n }\n\n const currentIndex = algorithmPriority[strongest.alg]\n const newIndex = algorithmPriority[item.alg]\n\n if (newIndex > currentIndex) {\n // Found a stronger algorithm, replace all\n strongest = item\n result.length = 0\n result.push(item)\n } else if (newIndex === currentIndex) {\n // Same strength, add to results\n result.push(item)\n }\n // If newIndex < currentIndex, ignore (weaker algorithm)\n }\n\n return result\n }\n\n /**\n * Applies the specified hash algorithm to the given bytes.\n *\n * @param bytes - The bytes to hash\n * @param algorithm - The hash algorithm name\n * @returns Base64-encoded hash value\n */\n private static applyAlgorithmToBytes(bytes: Uint8Array, algorithm: string): string {\n let hashResult: Uint8Array\n\n switch (algorithm) {\n case 'sha256':\n hashResult = Hasher.hash(bytes, 'sha-256')\n break\n case 'sha384':\n hashResult = Hasher.hash(bytes, 'sha-384')\n break\n case 'sha512':\n hashResult = Hasher.hash(bytes, 'sha-512')\n break\n default:\n throw new CredoError(`Unsupported hash algorithm: ${algorithm}`)\n }\n\n return TypedArrayEncoder.toBase64(hashResult)\n }\n}\n"],"mappings":";;;;;;;;;;;;;;;;AAaA,IAAa,oBAAb,MAAa,kBAAkB;;;;;;;;CAQ7B,OAAc,gBAAgB,MAAkB,mBAAiC;EAC/E,MAAM,iBAAiB,kBAAkB,uBAAuB,kBAAkB;AAGlF,MAAI,eAAe,WAAW,EAC5B,OAAM,IAAI,WAAW,8DAA8D;EAIrF,MAAM,oBAAoB,kBAAkB,qBAAqB,eAAe;AAGhF,OAAK,MAAM,YAAY,kBAErB,KADoB,kBAAkB,sBAAsB,MAAM,SAAS,IAAI,KAC3D,SAAS,IAC3B;AAIJ,QAAM,IAAI,WACR,gGACD;;;;;;;;CASH,OAAe,uBAAuB,UAAuD;EAC3F,MAAM,SAA8C,EAAE;EACtD,MAAM,kBAAkB;GAAC;GAAU;GAAU;GAAS;EAGtD,MAAM,QAAQ,SAAS,MAAM,CAAC,MAAM,MAAM;AAE1C,OAAK,MAAM,QAAQ,OAAO;AACxB,OAAI,CAAC,KAAM;GAGX,MAAM,CAAC,uBAAuB,KAAK,MAAM,IAAI;GAG7C,MAAM,QAAQ,oBAAoB,MAAM,IAAI;AAC5C,OAAI,MAAM,SAAS,EAAG;GAEtB,MAAM,YAAY,MAAM,GAAG,aAAa;GACxC,MAAM,cAAc,MAAM,MAAM,EAAE,CAAC,KAAK,IAAI;AAG5C,OAAI,gBAAgB,SAAS,UAAU,CACrC,QAAO,KAAK;IAAE,KAAK;IAAW,KAAK;IAAa,CAAC;;AAIrD,SAAO;;;;;;;;CAST,OAAe,qBACb,aACqC;AACrC,MAAI,YAAY,WAAW,EACzB,QAAO,EAAE;EAIX,MAAM,oBAA4C;GAChD,QAAQ;GACR,QAAQ;GACR,QAAQ;GACT;EAED,IAAI,YAAiD;EACrD,MAAM,SAA8C,EAAE;AAEtD,OAAK,MAAM,QAAQ,aAAa;AAC9B,OAAI,CAAC,WAAW;AACd,gBAAY;AACZ,WAAO,KAAK,KAAK;AACjB;;GAGF,MAAM,eAAe,kBAAkB,UAAU;GACjD,MAAM,WAAW,kBAAkB,KAAK;AAExC,OAAI,WAAW,cAAc;AAE3B,gBAAY;AACZ,WAAO,SAAS;AAChB,WAAO,KAAK,KAAK;cACR,aAAa,aAEtB,QAAO,KAAK,KAAK;;AAKrB,SAAO;;;;;;;;;CAUT,OAAe,sBAAsB,OAAmB,WAA2B;EACjF,IAAI;AAEJ,UAAQ,WAAR;GACE,KAAK;AACH,iBAAa,OAAO,KAAK,OAAO,UAAU;AAC1C;GACF,KAAK;AACH,iBAAa,OAAO,KAAK,OAAO,UAAU;AAC1C;GACF,KAAK;AACH,iBAAa,OAAO,KAAK,OAAO,UAAU;AAC1C;GACF,QACE,OAAM,IAAI,WAAW,+BAA+B,YAAY;;AAGpE,SAAO,kBAAkB,SAAS,WAAW"}