UNPKG

ic-websocket-js

Version:
89 lines 3.5 kB
import { Cbor, Certificate, compare, lookup_path, lookupResultToBuffer, reconstruct, } from "@dfinity/agent"; import { logger } from "./logger"; const areBuffersEqual = (buf1, buf2) => { return compare(buf1, buf2) === 0; }; export const isMessageBodyValid = async (canisterId, path, body, certificate, tree, agent, maxCertificateAgeInMinutes) => { let cert; try { cert = await Certificate.create({ certificate, canisterId, rootKey: agent.rootKey, maxAgeInMinutes: maxCertificateAgeInMinutes, }); } catch (error) { logger.error("[certification] Error creating certificate:", error); return false; } const hashTree = Cbor.decode(tree); const reconstructed = await reconstruct(hashTree); const witnessLookupResult = cert.lookup([ "canister", canisterId.toUint8Array(), "certified_data" ]); const witness = lookupResultToBuffer(witnessLookupResult); if (!witness) { throw new Error("Could not find certified data for this canister in the certificate."); } // First validate that the Tree is as good as the certification. if (!areBuffersEqual(witness, reconstructed)) { logger.error("[certification] Witness != Tree passed in ic-certification"); return false; } // Next, calculate the SHA of the content. const sha = await crypto.subtle.digest("SHA-256", body); let treeShaLookupResult = lookup_path(["websocket", path], hashTree); let treeSha = lookupResultToBuffer(treeShaLookupResult); if (!treeSha) { // Allow fallback to index path. treeShaLookupResult = lookup_path(["websocket"], hashTree); treeSha = lookupResultToBuffer(treeShaLookupResult); } if (!treeSha) { // The tree returned in the certification header is wrong. Return false. // We don't throw here, just invalidate the request. logger.error(`[certification] Invalid Tree in the header. Does not contain path ${JSON.stringify(path)}`); return false; } return !!treeSha && areBuffersEqual(sha, treeSha); }; export const safeExecute = async (fn, warnMessage) => { try { return await Promise.resolve(fn()); } catch (error) { logger.warn(warnMessage, error); } }; /** * Generates a random unsigned 64-bit integer * @returns {bigint} a random bigint */ export const randomBigInt = () => { // determine whether browser crypto is available if (typeof window !== 'undefined' && window.crypto && window.crypto.getRandomValues) { const array = new BigUint64Array(1); window.crypto.getRandomValues(array); return array[0]; } // A second check for webcrypto, in case it is loaded under global instead of window if (typeof crypto !== 'undefined' && crypto.getRandomValues) { const array = new BigUint64Array(1); crypto.getRandomValues(array); return array[0]; } // determine whether node crypto is available // @ts-ignore if (typeof crypto !== 'undefined' && crypto.randomBytes) { // @ts-ignore const randomBuffer = crypto.randomBytes(8); const randomHexString = randomBuffer.toString('hex'); return BigInt('0x' + randomHexString); } // TODO: test these fallbacks in a node environment throw new Error('Random UInt64 generation not supported in this environment'); }; //# sourceMappingURL=utils.js.map