mirror of
https://git.quad4.io/RNS-Things/MeshChatX.git
synced 2026-05-11 18:14:51 +00:00
146 lines
5.7 KiB
JavaScript
146 lines
5.7 KiB
JavaScript
import { describe, it, expect } from "vitest";
|
|
import { readFileSync, existsSync } from "fs";
|
|
import { createHash } from "crypto";
|
|
import path from "path";
|
|
|
|
const REPO_ROOT = path.resolve(__dirname, "../..");
|
|
|
|
function computeSri384(filePath) {
|
|
const buf = readFileSync(filePath);
|
|
const hash = createHash("sha384").update(buf).digest("base64");
|
|
return `sha384-${hash}`;
|
|
}
|
|
|
|
describe("SRI (Subresource Integrity) Verification", () => {
|
|
describe("micron-parser-go WASM", () => {
|
|
it("has valid integrity.json with matching SRI hashes", () => {
|
|
const integrityPath = path.join(
|
|
REPO_ROOT,
|
|
"meshchatx/src/frontend/public/vendor/micron-parser-go/integrity.json"
|
|
);
|
|
const wasmPath = path.join(
|
|
REPO_ROOT,
|
|
"meshchatx/src/frontend/public/vendor/micron-parser-go/micron-parser-go.wasm"
|
|
);
|
|
const execPath = path.join(REPO_ROOT, "meshchatx/src/frontend/public/vendor/micron-parser-go/wasm_exec.js");
|
|
|
|
if (!existsSync(integrityPath)) {
|
|
return; // Skip if WASM not fetched
|
|
}
|
|
|
|
const integrity = JSON.parse(readFileSync(integrityPath, "utf-8"));
|
|
expect(integrity.version).toBeTruthy();
|
|
expect(integrity.wasm).toMatch(/^sha384-[A-Za-z0-9+/=]+$/);
|
|
expect(integrity.wasmExec).toMatch(/^sha384-[A-Za-z0-9+/=]+$/);
|
|
|
|
if (existsSync(wasmPath)) {
|
|
const actualWasmHash = computeSri384(wasmPath);
|
|
expect(actualWasmHash).toBe(integrity.wasm);
|
|
}
|
|
|
|
if (existsSync(execPath)) {
|
|
const actualExecHash = computeSri384(execPath);
|
|
expect(actualExecHash).toBe(integrity.wasmExec);
|
|
}
|
|
});
|
|
});
|
|
|
|
describe("Codec2 Emscripten", () => {
|
|
it("has valid integrity.json with all required files", () => {
|
|
const integrityPath = path.join(
|
|
REPO_ROOT,
|
|
"meshchatx/src/frontend/public/assets/js/codec2-emscripten/integrity.json"
|
|
);
|
|
const baseDir = path.join(REPO_ROOT, "meshchatx/src/frontend/public/assets/js/codec2-emscripten");
|
|
|
|
expect(existsSync(integrityPath)).toBe(true);
|
|
|
|
const integrity = JSON.parse(readFileSync(integrityPath, "utf-8"));
|
|
expect(integrity.version).toBeTruthy();
|
|
expect(integrity.files).toBeTruthy();
|
|
|
|
const requiredFiles = [
|
|
"c2dec.wasm",
|
|
"c2dec.js",
|
|
"c2enc.wasm",
|
|
"c2enc.js",
|
|
"sox.wasm",
|
|
"sox.js",
|
|
"codec2-lib.js",
|
|
"codec2-microphone-recorder.js",
|
|
"processor.js",
|
|
"wav-encoder.js",
|
|
];
|
|
|
|
for (const file of requiredFiles) {
|
|
expect(integrity.files[file]).toMatch(/^sha384-[A-Za-z0-9+/=]+$/);
|
|
|
|
const filePath = path.join(baseDir, file);
|
|
if (existsSync(filePath)) {
|
|
const actualHash = computeSri384(filePath);
|
|
expect(actualHash).toBe(integrity.files[file]);
|
|
}
|
|
}
|
|
});
|
|
});
|
|
|
|
describe("RNode Flasher", () => {
|
|
it("has valid integrity.json with all required vendor libraries", () => {
|
|
const integrityPath = path.join(REPO_ROOT, "meshchatx/src/frontend/public/rnode-flasher/js/integrity.json");
|
|
const baseDir = path.join(REPO_ROOT, "meshchatx/src/frontend/public/rnode-flasher/js");
|
|
|
|
expect(existsSync(integrityPath)).toBe(true);
|
|
|
|
const integrity = JSON.parse(readFileSync(integrityPath, "utf-8"));
|
|
expect(integrity.version).toBeTruthy();
|
|
expect(integrity.files).toBeTruthy();
|
|
|
|
const requiredFiles = [
|
|
"zip.min.js",
|
|
"crypto-js@3.9.1-1/core.js",
|
|
"crypto-js@3.9.1-1/md5.js",
|
|
"esptool-js@0.4.5/bundle.js",
|
|
"nrf52_dfu_flasher.js",
|
|
"rnode.js",
|
|
"web-serial-polyfill@1.0.15/dist/serial.js",
|
|
];
|
|
|
|
for (const file of requiredFiles) {
|
|
expect(integrity.files[file]).toMatch(/^sha384-[A-Za-z0-9+/=]+$/);
|
|
|
|
const filePath = path.join(baseDir, file);
|
|
if (existsSync(filePath)) {
|
|
const actualHash = computeSri384(filePath);
|
|
expect(actualHash).toBe(integrity.files[file]);
|
|
}
|
|
}
|
|
});
|
|
});
|
|
|
|
describe("SRI hash format validation", () => {
|
|
it("all SRI hashes use sha384- prefix and base64 format", async () => {
|
|
const integrityFiles = [
|
|
"meshchatx/src/frontend/public/vendor/micron-parser-go/integrity.json",
|
|
"meshchatx/src/frontend/public/assets/js/codec2-emscripten/integrity.json",
|
|
"meshchatx/src/frontend/public/rnode-flasher/js/integrity.json",
|
|
];
|
|
|
|
for (const relPath of integrityFiles) {
|
|
const fullPath = path.join(REPO_ROOT, relPath);
|
|
if (!existsSync(fullPath)) continue;
|
|
|
|
const data = JSON.parse(readFileSync(fullPath, "utf-8"));
|
|
const hashes =
|
|
data.wasm && data.wasmExec ? [data.wasm, data.wasmExec] : Object.values(data.files || {});
|
|
|
|
for (const hash of hashes) {
|
|
expect(hash).toMatch(/^sha384-[A-Za-z0-9+/=]+$/);
|
|
// SHA-384 in base64 should be exactly 64 characters
|
|
const b64Part = hash.replace("sha384-", "");
|
|
expect(b64Part.length).toBe(64);
|
|
}
|
|
}
|
|
});
|
|
});
|
|
});
|