#!/usr/bin/env node /** * Test script for webhook signature verification * Tests both valid and invalid signatures to ensure security is working */ import crypto from 'crypto'; import http from 'http'; const TEST_PORT = 3099; const TEST_SECRET = 'test-secret-12345'; // Test payload const payload = JSON.stringify({ ref: 'refs/heads/main', repository: { name: 'test-repo', full_name: 'user/test-repo' }, pusher: { username: 'testuser' } }); // Generate valid signature function generateSignature(payload, secret) { const hmac = crypto.createHmac('sha256', secret); hmac.update(payload, 'utf8'); return hmac.digest('hex'); } // Send webhook request async function sendWebhook(port, payload, signature, description) { return new Promise((resolve, reject) => { const options = { hostname: '127.0.0.1', port: port, path: '/webhook', method: 'POST', headers: { 'Content-Type': 'application/json', 'Content-Length': Buffer.byteLength(payload), 'X-Gogs-Event': 'push', 'X-Gogs-Delivery': '12345' } }; if (signature) { options.headers['X-Gogs-Signature'] = signature; } const req = http.request(options, (res) => { let data = ''; res.on('data', chunk => data += chunk); res.on('end', () => { resolve({ statusCode: res.statusCode, body: data, description }); }); }); req.on('error', reject); req.write(payload); req.end(); }); } // Start test server async function startTestServer() { const { WebhookServer } = await import('./src/server.js'); const server = new WebhookServer({ host: '127.0.0.1', port: TEST_PORT, secret: TEST_SECRET }); return new Promise((resolve) => { server.start(); // Give server time to start setTimeout(() => resolve(server), 500); }); } // Run tests async function runTests() { console.log('๐Ÿงช Starting signature verification tests...\n'); const server = await startTestServer(); try { // Test 1: Valid signature const validSignature = generateSignature(payload, TEST_SECRET); const test1 = await sendWebhook( TEST_PORT, payload, validSignature, 'Valid signature' ); console.log(`โœ“ Test 1: ${test1.description}`); console.log(` Status: ${test1.statusCode} ${test1.statusCode === 200 ? 'โœ“ PASS' : 'โœ— FAIL'}`); console.log(` Response: ${test1.body}\n`); // Test 2: Invalid signature const test2 = await sendWebhook( TEST_PORT, payload, 'invalid-signature-123', 'Invalid signature' ); console.log(`โœ“ Test 2: ${test2.description}`); console.log(` Status: ${test2.statusCode} ${test2.statusCode === 401 ? 'โœ“ PASS' : 'โœ— FAIL'}`); console.log(` Response: ${test2.body}\n`); // Test 3: Missing signature const test3 = await sendWebhook( TEST_PORT, payload, null, 'Missing signature' ); console.log(`โœ“ Test 3: ${test3.description}`); console.log(` Status: ${test3.statusCode} ${test3.statusCode === 401 ? 'โœ“ PASS' : 'โœ— FAIL'}`); console.log(` Response: ${test3.body}\n`); // Summary const results = [test1, test2, test3]; const passed = results.filter((r, i) => { if (i === 0) return r.statusCode === 200; return r.statusCode === 401; }).length; console.log('โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•'); console.log(`Results: ${passed}/3 tests passed`); console.log('โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•\n'); if (passed === 3) { console.log('โœ… All signature verification tests passed!'); console.log(' - Valid signatures are accepted (200)'); console.log(' - Invalid signatures are rejected (401)'); console.log(' - Missing signatures are rejected (401)'); } else { console.log('โŒ Some tests failed!'); process.exitCode = 1; } } finally { await server.stop(); console.log('\n๐Ÿ›‘ Test server stopped'); } } runTests().catch(err => { console.error('โŒ Test error:', err); process.exit(1); });