62 lines
4.0 KiB
JavaScript
62 lines
4.0 KiB
JavaScript
import { createHash } from "node:crypto";
|
|
import { existsSync, readFileSync, statSync, writeFileSync } from "node:fs";
|
|
import { homedir } from "node:os";
|
|
import { resolve } from "node:path";
|
|
|
|
const colorRoot = process.env.DADA_COLOR_ASSET_ROOT ?? resolve(homedir(), "Desktop", "sticker_colour", "单模板归档", "styles");
|
|
const dynamicRoot = process.env.DADA_DYNAMIC_ASSET_ROOT ?? resolve(homedir(), "Desktop", "sticker_interactive", "单模板归档", "templates");
|
|
const colorIds = ["COLOR001", "COLOR002", "COLOR008", "COLOR016"];
|
|
const dynamicIds = ["DYN001", "DYN002", "DYN003", "DYN004", "DYN007", "DYN008", "DYN011", "DYN012", "DYN015", "DYN016"];
|
|
const expectedColorStyles = { COLOR001: "style_01", COLOR002: "style_02", COLOR008: "style_08", COLOR016: "style_16" };
|
|
const expectedDynamicSources = {
|
|
DYN001: "l_POI01", DYN002: "l_POI02", DYN003: "l_POI03", DYN004: "l_POI04", DYN007: "diaoyu",
|
|
DYN008: "l_shijian2", DYN011: "l_shijian6", DYN012: "l_shijian7", DYN015: "0721userna", DYN016: "l_username00",
|
|
};
|
|
const requiredDynamicKeys = {
|
|
DYN001: ["title"], DYN002: ["city_en", "title"], DYN003: ["city", "title"], DYN004: ["city", "latitude", "longitude"],
|
|
DYN007: ["nickname"], DYN008: ["hour", "minute", "month"],
|
|
DYN011: ["day", "month", "year"], DYN012: ["hour", "minute"], DYN015: ["nickname"], DYN016: ["nickname"],
|
|
};
|
|
const paths = [
|
|
...colorIds.map((id) => resolve(colorRoot, id, "metadata.json")),
|
|
...dynamicIds.map((id) => resolve(dynamicRoot, id, "metadata.json")),
|
|
];
|
|
if (!paths.every(existsSync)) throw new Error("WP4-04 normative metadata is unavailable.");
|
|
const hash = (bytes) => createHash("sha256").update(bytes).digest("hex").toUpperCase();
|
|
const before = paths.map((path) => ({ bytes: readFileSync(path), mtime: statSync(path).mtimeMs }));
|
|
const metadata = before.map((entry) => JSON.parse(entry.bytes.toString("utf8")));
|
|
for (const id of colorIds) {
|
|
const item = metadata.find((entry) => entry.canonical_id === id);
|
|
if (!item || item.family !== "color_card" || item.resource_class !== "parameter_renderer"
|
|
|| item.runtime?.stable_style_id !== expectedColorStyles[id]) throw new Error(`Color metadata verification failed for ${id}.`);
|
|
}
|
|
for (const id of dynamicIds) {
|
|
const item = metadata.find((entry) => entry.canonical_id === id);
|
|
if (!item || item.family !== "interactive_sticker" || item.resource_class !== "dynamic_resource"
|
|
|| item.source_candidate_id !== expectedDynamicSources[id] || item.runtime?.has_dynamic_binding !== true
|
|
|| !requiredDynamicKeys[id].every((key) => item.dynamic_keys.includes(key))
|
|
|| ![...(item.files?.prefab ?? []), ...(item.files?.images ?? []), ...(item.files?.lua ?? [])]
|
|
.every((relativePath) => existsSync(resolve(dynamicRoot, id, relativePath)))) {
|
|
throw new Error(`Dynamic metadata verification failed for ${id}.`);
|
|
}
|
|
}
|
|
const dyn012 = metadata.find((entry) => entry.canonical_id === "DYN012");
|
|
const missingDin = dyn012.runtime.external_runtime_fonts?.some((entry) => entry.manifest_filename === "DIN_MediumAlternate.otf");
|
|
if (!missingDin) throw new Error("DYN012 missing-font evidence is unavailable.");
|
|
const unchanged = paths.every((path, index) => statSync(path).mtimeMs === before[index].mtime && hash(readFileSync(path)) === hash(before[index].bytes));
|
|
if (!unchanged) throw new Error("Normative source changed during read-only verification.");
|
|
const result = {
|
|
color_ids: colorIds,
|
|
color_metadata_sha256: hash(Buffer.concat(before.slice(0, colorIds.length).map((entry) => entry.bytes))),
|
|
dyn012_original_font: "DIN_MediumAlternate.otf",
|
|
dyn012_substitute_font: "FONT081 Lexend Deca",
|
|
dynamic_ids: dynamicIds,
|
|
dynamic_metadata_sha256: hash(Buffer.concat(before.slice(colorIds.length).map((entry) => entry.bytes))),
|
|
lua_prefab_execution: false,
|
|
source_access: "read_only_normative_metadata",
|
|
source_unchanged: unchanged,
|
|
status: "passed",
|
|
};
|
|
if (process.env.DADA_WP4_04_SOURCE_EVIDENCE) writeFileSync(process.env.DADA_WP4_04_SOURCE_EVIDENCE, `${JSON.stringify(result, null, 2)}\n`);
|
|
console.log(JSON.stringify(result, null, 2));
|