Files
portal/tools/judge-card-guard.mjs
T

37 lines
1.9 KiB
JavaScript

#!/usr/bin/env node
/**
* judge-card-guard (§11 #5 — страж карточки) — прежде чем опереться на карточку
* навыка, проверь: она ЕСТЬ + (для чужих карточек) хеш сходится. Иначе судья громко
* помечает «сужу вслепую» (не падает, но фиксирует, что опора ненадёжна). Свои
* карточки доверенны без хеша; чужие — только при совпадении ожидаемого хеша.
*/
import { createHash } from 'node:crypto';
import { canonicalJson } from './receipt-sign.mjs';
export function cardHash(card) {
return createHash('sha256').update(canonicalJson(card)).digest('hex');
}
/** Страж одной карточки. expectedHash задаётся для ЧУЖИХ карточек (хеш-сверка). */
export function guardCard(card, { expectedHash } = {}) {
if (!card || typeof card !== 'object') {
return { ok: false, blind: true, reason: 'карточка отсутствует — сужу вслепую' };
}
if (expectedHash && cardHash(card) !== expectedHash) {
return { ok: false, blind: true, reason: 'хеш карточки не сошёлся — сужу вслепую' };
}
return { ok: true, blind: false };
}
/** Страж набора карточек. expectedHashes: { [skill]: hash } для чужих. */
export function guardCards(cards = [], { expectedHashes = {} } = {}) {
const blindOn = [];
(cards || []).forEach((card, i) => {
const skill = card && card.skill;
const expectedHash = skill ? expectedHashes[skill] : undefined;
const r = guardCard(card, { expectedHash });
if (r.blind) blindOn.push({ index: i, skill: skill ?? null, reason: r.reason });
});
return { ok: blindOn.length === 0, blindOn };
}