everything-dev
Version:
A consolidated product package for building Module Federation apps with oRPC APIs.
104 lines (102 loc) • 3.88 kB
JavaScript
Object.defineProperty(exports, Symbol.toStringTag, { value: 'Module' });
const require_runtime = require('./_virtual/_rolldown/runtime.cjs');
const require_fastkv = require('./fastkv.cjs');
let node_crypto = require("node:crypto");
//#region src/integrity.ts
function computeSriHash(content) {
return `sha384-${(0, node_crypto.createHash)("sha384").update(content).digest("base64")}`;
}
async function computeSriHashForUrl(url) {
try {
const entryUrl = resolveEntryUrl(url);
const response = await fetch(entryUrl);
if (!response.ok) {
console.warn(`[SRI] Failed to fetch ${entryUrl}: ${response.status} ${response.statusText}`);
return null;
}
return computeSriHash(Buffer.from(await response.arrayBuffer()));
} catch (error) {
console.warn(`[SRI] Error computing integrity for ${url}:`, error instanceof Error ? error.message : error);
return null;
}
}
function resolveEntryUrl(url) {
if (url.endsWith("/remoteEntry.js")) return url;
if (url.endsWith("/mf-manifest.json")) return `${url.replace(/\/mf-manifest\.json$/, "")}/remoteEntry.js`;
return `${url.replace(/\/$/, "")}/remoteEntry.js`;
}
async function verifySriForUrl(url, expectedIntegrity) {
const entryUrl = resolveEntryUrl(url);
const response = await fetch(entryUrl);
if (!response.ok) {
console.warn(`[SRI] Failed to fetch ${entryUrl} for verification: ${response.status}`);
return;
}
const computed = computeSriHash(Buffer.from(await response.arrayBuffer()));
if (computed !== expectedIntegrity) throw new Error(`[SRI] Integrity check failed for ${entryUrl}\n Expected: ${expectedIntegrity}\n Computed: ${computed}`);
}
var IntegrityRegistry = class {
hashes = /* @__PURE__ */ new Map();
register(url, integrity) {
this.hashes.set(url, integrity);
}
registerEntry(baseUrl, integrity) {
this.hashes.set(resolveEntryUrl(baseUrl), integrity);
}
get(url) {
return this.hashes.get(url);
}
has(url) {
return this.hashes.has(url);
}
entries() {
return this.hashes.entries();
}
};
function extractIntegrityHashes(config) {
const hashes = /* @__PURE__ */ new Map();
const app = config.app;
const plugins = config.plugins;
if (app) {
for (const [, entry] of Object.entries(app)) if (entry?.integrity && entry?.production) hashes.set(resolveEntryUrl(entry.production), entry.integrity);
}
if (plugins) {
for (const [, entry] of Object.entries(plugins)) if (entry?.integrity && entry?.production) hashes.set(resolveEntryUrl(entry.production), entry.integrity);
}
return hashes;
}
async function verifyConfigAgainstChain(localConfig, bosUrl) {
const mismatches = [];
let chainConfig;
try {
chainConfig = await require_fastkv.fetchBosConfigFromFastKv(bosUrl);
} catch (error) {
console.warn(`[Attestation] Failed to fetch on-chain config: ${error instanceof Error ? error.message : String(error)}`);
return {
verified: false,
mismatches: ["chain-fetch-failed"]
};
}
const localHashes = extractIntegrityHashes(localConfig);
const chainHashes = extractIntegrityHashes(chainConfig);
for (const [url, chainHash] of chainHashes) {
const localHash = localHashes.get(url);
if (localHash && localHash !== chainHash) {
mismatches.push(url);
console.error(`[Attestation] Integrity mismatch for ${url}\n Local: ${localHash}\n Chain: ${chainHash}`);
}
}
if (mismatches.length === 0 && localHashes.size > 0) console.log(`[Attestation] Local config verified against on-chain anchor (${localHashes.size} entries checked)`);
return {
verified: mismatches.length === 0,
mismatches
};
}
//#endregion
exports.IntegrityRegistry = IntegrityRegistry;
exports.computeSriHash = computeSriHash;
exports.computeSriHashForUrl = computeSriHashForUrl;
exports.resolveEntryUrl = resolveEntryUrl;
exports.verifyConfigAgainstChain = verifyConfigAgainstChain;
exports.verifySriForUrl = verifySriForUrl;
//# sourceMappingURL=integrity.cjs.map