import { describe, it, expect } from 'vitest'; import { UtilsV1 as UtilsV1Pb } from '@superblocksteam/types'; import { AnyPageDSL, ApplicationConfiguration, ApplicationSettings } from '../types/index.js'; import { ApplicationSignatureTreeV1, ApplicationSignatureTreeV2, createApplicationSignatureTree, getAlgorithmName, verifyApplicationHashTree } from './index'; const pageDsl = { version: 8, widgetId: '0', children: [] } as unknown as AnyPageDSL; const appSettings = {} as ApplicationSettings; const appConfiguration = { routes: {} } as ApplicationConfiguration; const hashTreeV1: ApplicationSignatureTreeV1 = { v: 1, page: { hash: 'ZMpaDRZaIl1QxyEwrjoPUQJbkcCtTsNXbVySIGlcgVg=', version: 8 }, settings: { components: 'RBNvo1WzZ4oRRq0W9+hknpT7T8If536DEMBg9hyq/4o=', rest: 'RBNvo1WzZ4oRRq0W9+hknpT7T8If536DEMBg9hyq/4o=' } }; const hashTreeV2: ApplicationSignatureTreeV2 = { v: 2, pages: { 'fake-page-id': { hash: 'ZMpaDRZaIl1QxyEwrjoPUQJbkcCtTsNXbVySIGlcgVg=', version: 8 } }, settings: { components: 'RBNvo1WzZ4oRRq0W9+hknpT7T8If536DEMBg9hyq/4o=', rest: 'RBNvo1WzZ4oRRq0W9+hknpT7T8If536DEMBg9hyq/4o=' }, configuration: { version: 1, hash: 'boT9TuU6iU3HiVIO8vh8YU+SgXAozIHLSuhRcux09F8=' } }; describe('createApplicationSignatureTree', () => { it('returns a v2 signature tree', async () => { const calculatedHashTree = await createApplicationSignatureTree({ pages: { 'fake-page-id': pageDsl }, appSettings, configuration: appConfiguration }); expect(calculatedHashTree).toEqual(hashTreeV2); }); }); describe('verifyApplicationHashTree', () => { describe('v1', () => { it('verifies a v1 signature tree', async () => { const result = await verifyApplicationHashTree({ hashTree: hashTreeV1, pages: { 'fake-page-id': pageDsl }, appSettings }); expect(result).toBe(true); }); it('returns false if the page hash does not match', async () => { const badHashTree = { ...hashTreeV1, page: { ...hashTreeV1.page, hash: 'bad-hash' } }; const result = await verifyApplicationHashTree({ hashTree: badHashTree, pages: { 'fake-page-id': pageDsl }, appSettings }); expect(result).toBe(false); }); it('returns false if the settings hash does not match', async () => { const badHashTree = { ...hashTreeV1, settings: { ...hashTreeV1.settings, components: 'bad-hash' } }; const result = await verifyApplicationHashTree({ hashTree: badHashTree, pages: { 'fake-page-id': pageDsl }, appSettings }); expect(result).toBe(false); }); }); describe('v2', () => { it('verifies a v2 signature tree', async () => { const result = await verifyApplicationHashTree({ hashTree: hashTreeV2, pages: { 'fake-page-id': pageDsl }, appSettings }); expect(result).toBe(true); }); it('returns false if the page hash does not match', async () => { const badHashTree = { ...hashTreeV2, pages: { 'fake-page-id': { ...hashTreeV2.pages['fake-page-id'], hash: 'bad-hash' } } }; const result = await verifyApplicationHashTree({ hashTree: badHashTree, pages: { 'fake-page-id': pageDsl }, appSettings }); expect(result).toBe(false); }); it('returns false if the settings hash does not match', async () => { const badHashTree = { ...hashTreeV2, settings: { ...hashTreeV2.settings, components: 'bad-hash' } }; const result = await verifyApplicationHashTree({ hashTree: badHashTree, pages: { 'fake-page-id': pageDsl }, appSettings }); expect(result).toBe(false); }); }); }); describe('get algorithm name', () => { it.each([ { name: 'unspecified algorithm', algorithm: UtilsV1Pb.Signature_Algorithm.UNSPECIFIED, expected: 'ALGORITHM_UNSPECIFIED' }, { name: 'ED25519 algorithm', algorithm: UtilsV1Pb.Signature_Algorithm.ED25519, expected: 'ALGORITHM_ED25519' } ])('should return $expected for $name', ({ algorithm, expected }) => { const actual = getAlgorithmName(algorithm); expect(actual).toEqual(expected); }); });