diff --git a/packages/utils/package.json b/packages/utils/package.json index 66d64ff..4c37a9e 100644 --- a/packages/utils/package.json +++ b/packages/utils/package.json @@ -3,6 +3,10 @@ "version": "1.0.0", "private": true, "type": "module", + "scripts": { + "fix": "biome check --write", + "typecheck": "tsc --noEmit" + }, "imports": { "#*": "./src/*" }, diff --git a/packages/utils/src/fingerprint.test.ts b/packages/utils/src/fingerprint.test.ts new file mode 100644 index 0000000..f3c357d --- /dev/null +++ b/packages/utils/src/fingerprint.test.ts @@ -0,0 +1,157 @@ +import { beforeEach, describe, expect, it, mock } from 'bun:test' +import { getHardwareFingerprint } from './fingerprint' + +// Mock systeminformation module +const mockSystemInfo = { + uuid: mock(() => + Promise.resolve({ + os: 'test-os-uuid', + hardware: 'test-hardware-uuid', + }), + ), + baseboard: mock(() => + Promise.resolve({ + manufacturer: 'Test Manufacturer', + model: 'Test Model', + version: '1.0', + serial: 'TEST123', + }), + ), + bios: mock(() => + Promise.resolve({ + vendor: 'Test Vendor', + version: '1.0.0', + releaseDate: '2024-01-01', + }), + ), + system: mock(() => + Promise.resolve({ + manufacturer: 'Test System', + model: 'Test Model', + version: '1.0', + sku: 'TEST-SKU', + }), + ), + diskLayout: mock(() => + Promise.resolve([ + { + device: '/dev/sda', + type: 'SSD', + name: 'Test Disk', + size: 512000000000, + }, + ]), + ), + networkInterfaces: mock(() => + Promise.resolve([ + { + iface: 'eth0', + mac: '00:11:22:33:44:55', + ip4: '192.168.1.1', + }, + ]), + ), +} + +mock.module('systeminformation', () => ({ + default: mockSystemInfo, +})) + +describe('fingerprint', () => { + beforeEach(() => { + // Reset all mocks before each test + mockSystemInfo.uuid.mockClear() + mockSystemInfo.baseboard.mockClear() + mockSystemInfo.bios.mockClear() + mockSystemInfo.system.mockClear() + mockSystemInfo.diskLayout.mockClear() + mockSystemInfo.networkInterfaces.mockClear() + }) + + describe('getHardwareFingerprint', () => { + it('should return a fingerprint hash', async () => { + const fingerprint = await getHardwareFingerprint() + + expect(fingerprint).toBeDefined() + expect(typeof fingerprint).toBe('string') + expect(fingerprint.length).toBeGreaterThan(0) + }) + + it('should call all system information methods', async () => { + await getHardwareFingerprint() + + expect(mockSystemInfo.uuid).toHaveBeenCalledTimes(1) + expect(mockSystemInfo.baseboard).toHaveBeenCalledTimes(1) + expect(mockSystemInfo.bios).toHaveBeenCalledTimes(1) + expect(mockSystemInfo.system).toHaveBeenCalledTimes(1) + expect(mockSystemInfo.diskLayout).toHaveBeenCalledTimes(1) + expect(mockSystemInfo.networkInterfaces).toHaveBeenCalledTimes(1) + }) + + it('should return the same fingerprint for the same system info', async () => { + const fingerprint1 = await getHardwareFingerprint() + const fingerprint2 = await getHardwareFingerprint() + + expect(fingerprint1).toBe(fingerprint2) + }) + + it('should return different fingerprint when system info changes', async () => { + const fingerprint1 = await getHardwareFingerprint() + + // Change mock data + mockSystemInfo.uuid.mockImplementationOnce(() => + Promise.resolve({ + os: 'different-os-uuid', + hardware: 'different-hardware-uuid', + }), + ) + + const fingerprint2 = await getHardwareFingerprint() + + expect(fingerprint1).not.toBe(fingerprint2) + }) + + it('should handle empty system information gracefully', async () => { + // Mock empty responses + mockSystemInfo.uuid.mockImplementationOnce(() => Promise.resolve({})) + mockSystemInfo.baseboard.mockImplementationOnce(() => Promise.resolve({})) + mockSystemInfo.bios.mockImplementationOnce(() => Promise.resolve({})) + mockSystemInfo.system.mockImplementationOnce(() => Promise.resolve({})) + mockSystemInfo.diskLayout.mockImplementationOnce(() => + Promise.resolve([]), + ) + mockSystemInfo.networkInterfaces.mockImplementationOnce(() => + Promise.resolve([]), + ) + + const fingerprint = await getHardwareFingerprint() + + expect(fingerprint).toBeDefined() + expect(typeof fingerprint).toBe('string') + }) + + it('should handle partial system information', async () => { + mockSystemInfo.baseboard.mockImplementationOnce(() => + Promise.resolve({ + manufacturer: 'Only Manufacturer', + }), + ) + + const fingerprint = await getHardwareFingerprint() + + expect(fingerprint).toBeDefined() + expect(typeof fingerprint).toBe('string') + }) + + it('should be deterministic with the same input', async () => { + const results = await Promise.all([ + getHardwareFingerprint(), + getHardwareFingerprint(), + getHardwareFingerprint(), + ]) + + expect(results[0]).toBe(results[1]) + expect(results[1]).toBe(results[2]) + }) + }) +}) diff --git a/packages/utils/tsconfig.json b/packages/utils/tsconfig.json new file mode 100644 index 0000000..086fbdf --- /dev/null +++ b/packages/utils/tsconfig.json @@ -0,0 +1,3 @@ +{ + "extends": "@furtherverse/tsconfig/base.json" +}