/** * Security test suite * Run with: npm test -- security.test.ts */ import { validateAddress, validateTransactionData, validateTransactionValue, validateGasLimit, validateNetworkId, validateRpcUrl, generateSecureId, validateTransactionRequest, } from "../utils/security"; import { TEST_ADDRESSES } from "./test-constants"; describe("Security Validation Tests", () => { describe("Address Validation", () => { it("should validate correct addresses", () => { const valid = validateAddress(TEST_ADDRESSES.ADDRESS_1); expect(valid.valid).toBe(true); expect(valid.checksummed).toBeDefined(); }); it("should reject invalid addresses", () => { const invalid = validateAddress("not-an-address"); expect(invalid.valid).toBe(false); expect(invalid.error).toBeDefined(); }); it("should reject addresses that are too long", () => { const long = validateAddress("0x" + "a".repeat(100)); expect(long.valid).toBe(false); }); it("should reject empty addresses", () => { const empty = validateAddress(""); expect(empty.valid).toBe(false); }); it("should reject non-string addresses", () => { const nonString = validateAddress(null as any); expect(nonString.valid).toBe(false); }); }); describe("Transaction Data Validation", () => { it("should accept valid hex data", () => { const valid = validateTransactionData("0x1234abcd"); expect(valid.valid).toBe(true); }); it("should accept empty data", () => { const empty = validateTransactionData(""); expect(empty.valid).toBe(true); }); it("should reject data without 0x prefix", () => { const invalid = validateTransactionData("1234abcd"); expect(invalid.valid).toBe(false); }); it("should reject data that is too long", () => { const long = validateTransactionData("0x" + "a".repeat(10001)); expect(long.valid).toBe(false); }); it("should reject non-hex characters", () => { const invalid = validateTransactionData("0xghijklmn"); expect(invalid.valid).toBe(false); }); }); describe("Transaction Value Validation", () => { it("should accept valid values", () => { const valid = validateTransactionValue("1000000000000000000"); // 1 ETH expect(valid.valid).toBe(true); expect(valid.parsed).toBeDefined(); }); it("should accept zero value", () => { const zero = validateTransactionValue("0"); expect(zero.valid).toBe(true); }); it("should reject negative values", () => { // Note: BigNumber doesn't support negative, but test the check const negative = validateTransactionValue("-1"); // Will fail at BigNumber.from, but test structure expect(negative.valid).toBe(false); }); it("should reject values exceeding maximum", () => { const tooLarge = validateTransactionValue( "1000000000000000000000001" // > 1M ETH ); expect(tooLarge.valid).toBe(false); }); }); describe("Gas Limit Validation", () => { it("should accept valid gas limits", () => { const valid = validateGasLimit("21000"); expect(valid.valid).toBe(true); }); it("should reject gas limits that are too low", () => { const tooLow = validateGasLimit("20000"); expect(tooLow.valid).toBe(false); }); it("should reject gas limits that are too high", () => { const tooHigh = validateGasLimit("20000000"); expect(tooHigh.valid).toBe(false); }); }); describe("Network ID Validation", () => { it("should accept supported networks", () => { const valid = validateNetworkId(1); // Mainnet expect(valid.valid).toBe(true); }); it("should reject unsupported networks", () => { const invalid = validateNetworkId(99999); expect(invalid.valid).toBe(false); }); it("should reject invalid network IDs", () => { const invalid = validateNetworkId(-1); expect(invalid.valid).toBe(false); }); }); describe("RPC URL Validation", () => { it("should accept valid HTTPS URLs", () => { const valid = validateRpcUrl("https://mainnet.infura.io/v3/abc123"); expect(valid.valid).toBe(true); }); it("should reject invalid URLs", () => { const invalid = validateRpcUrl("not-a-url"); expect(invalid.valid).toBe(false); }); it("should reject HTTP URLs in production", () => { const http = validateRpcUrl("http://localhost:8545"); expect(http.valid).toBe(false); }); }); describe("Secure ID Generation", () => { it("should generate unique IDs", () => { const id1 = generateSecureId(); const id2 = generateSecureId(); expect(id1).not.toBe(id2); }); it("should generate IDs of correct length", () => { const id = generateSecureId(); expect(id.length).toBeGreaterThan(0); }); }); describe("Transaction Request Validation", () => { it("should validate complete transaction requests", () => { const tx = { from: TEST_ADDRESSES.ADDRESS_1, to: TEST_ADDRESSES.ADDRESS_2, value: "1000000000000000000", data: "0x", }; const result = validateTransactionRequest(tx); expect(result.valid).toBe(true); expect(result.errors.length).toBe(0); }); it("should catch missing required fields", () => { const tx = { from: TEST_ADDRESSES.ADDRESS_1, // Missing 'to' }; const result = validateTransactionRequest(tx); expect(result.valid).toBe(false); expect(result.errors.length).toBeGreaterThan(0); }); it("should catch invalid addresses", () => { const tx = { from: "invalid-address", to: TEST_ADDRESSES.ADDRESS_1, }; const result = validateTransactionRequest(tx); expect(result.valid).toBe(false); expect(result.errors.some((e) => e.includes("from"))).toBe(true); }); }); }); describe("Attack Vector Tests", () => { describe("XSS Prevention", () => { it("should sanitize script tags", () => { // Test sanitization in components const malicious = ""; // Should be sanitized before rendering }); }); describe("Replay Attack Prevention", () => { it("should prevent duplicate transaction execution", () => { // Test nonce management // Test transaction deduplication }); }); describe("Race Condition Tests", () => { it("should handle concurrent approvals", async () => { // Test multiple simultaneous approvals // Should not allow threshold bypass }); }); describe("Integer Overflow Tests", () => { it("should handle large values correctly", () => { const largeValue = "115792089237316195423570985008687907853269984665640564039457584007913129639935"; // Max uint256 const result = validateTransactionValue(largeValue); // Should use BigNumber, not parseInt }); }); });