Files
brain/tools/verify-receipt.test.mjs
T

42 lines
2.1 KiB
JavaScript

import { describe, it, expect } from 'vitest';
import { signVerifyReceipt, verifyReceiptSig, acceptVerifyReceipt } from './verify-receipt.mjs';
const KEY = 'signer-key';
const FP = 'a'.repeat(64);
describe('signVerifyReceipt', () => {
it('подписывает {code_fingerprint, occurrence}; без ключа → null', () => {
expect(signVerifyReceipt({ code_fingerprint: FP, occurrence: 1 }, '')).toBe(null);
const r = signVerifyReceipt({ code_fingerprint: FP, occurrence: 1 }, KEY);
expect(r.code_fingerprint).toBe(FP);
expect(r.occurrence).toBe(1);
expect(typeof r.sig).toBe('string');
expect(verifyReceiptSig(r, KEY)).toBe(true);
});
});
describe('acceptVerifyReceipt', () => {
const good = () => signVerifyReceipt({ code_fingerprint: FP, occurrence: 1 }, KEY);
it('валидная подпись + occurrence>0 + fingerprint совпал → accepted', () => {
expect(acceptVerifyReceipt(good(), KEY, { currentFingerprint: FP })).toEqual({ accepted: true, reason: 'ok' });
});
it('подмена fingerprint после подписи → bad-signature', () => {
const r = { ...good(), code_fingerprint: 'b'.repeat(64) };
expect(acceptVerifyReceipt(r, KEY, { currentFingerprint: 'b'.repeat(64) }).accepted).toBe(false);
});
it('staged-diff изменился (current ≠ receipt) → stale-fingerprint', () => {
expect(acceptVerifyReceipt(good(), KEY, { currentFingerprint: 'c'.repeat(64) }))
.toEqual({ accepted: false, reason: 'stale-fingerprint' });
});
it('occurrence не целое/≤0 → bad-occurrence', () => {
const r = signVerifyReceipt({ code_fingerprint: FP, occurrence: 0 }, KEY);
expect(acceptVerifyReceipt(r, KEY, { currentFingerprint: FP }).reason).toBe('bad-occurrence');
});
it('без ключа → bad-signature (fail-closed)', () => {
expect(acceptVerifyReceipt(good(), '', { currentFingerprint: FP }).accepted).toBe(false);
});
it('currentFingerprint не задан (null) → проверка свежести пропущена', () => {
expect(acceptVerifyReceipt(good(), KEY).accepted).toBe(true);
});
});