test-signature-verification.js 4.2 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161
  1. #!/usr/bin/env node
  2. /**
  3. * Test script for webhook signature verification
  4. * Tests both valid and invalid signatures to ensure security is working
  5. */
  6. import crypto from 'crypto';
  7. import http from 'http';
  8. const TEST_PORT = 3099;
  9. const TEST_SECRET = 'test-secret-12345';
  10. // Test payload
  11. const payload = JSON.stringify({
  12. ref: 'refs/heads/main',
  13. repository: {
  14. name: 'test-repo',
  15. full_name: 'user/test-repo'
  16. },
  17. pusher: {
  18. username: 'testuser'
  19. }
  20. });
  21. // Generate valid signature
  22. function generateSignature(payload, secret) {
  23. const hmac = crypto.createHmac('sha256', secret);
  24. hmac.update(payload, 'utf8');
  25. return hmac.digest('hex');
  26. }
  27. // Send webhook request
  28. async function sendWebhook(port, payload, signature, description) {
  29. return new Promise((resolve, reject) => {
  30. const options = {
  31. hostname: '127.0.0.1',
  32. port: port,
  33. path: '/webhook',
  34. method: 'POST',
  35. headers: {
  36. 'Content-Type': 'application/json',
  37. 'Content-Length': Buffer.byteLength(payload),
  38. 'X-Gogs-Event': 'push',
  39. 'X-Gogs-Delivery': '12345'
  40. }
  41. };
  42. if (signature) {
  43. options.headers['X-Gogs-Signature'] = signature;
  44. }
  45. const req = http.request(options, (res) => {
  46. let data = '';
  47. res.on('data', chunk => data += chunk);
  48. res.on('end', () => {
  49. resolve({
  50. statusCode: res.statusCode,
  51. body: data,
  52. description
  53. });
  54. });
  55. });
  56. req.on('error', reject);
  57. req.write(payload);
  58. req.end();
  59. });
  60. }
  61. // Start test server
  62. async function startTestServer() {
  63. const { WebhookServer } = await import('./src/server.js');
  64. const server = new WebhookServer({
  65. host: '127.0.0.1',
  66. port: TEST_PORT,
  67. secret: TEST_SECRET
  68. });
  69. return new Promise((resolve) => {
  70. server.start();
  71. // Give server time to start
  72. setTimeout(() => resolve(server), 500);
  73. });
  74. }
  75. // Run tests
  76. async function runTests() {
  77. console.log('🧪 Starting signature verification tests...\n');
  78. const server = await startTestServer();
  79. try {
  80. // Test 1: Valid signature
  81. const validSignature = generateSignature(payload, TEST_SECRET);
  82. const test1 = await sendWebhook(
  83. TEST_PORT,
  84. payload,
  85. validSignature,
  86. 'Valid signature'
  87. );
  88. console.log(`✓ Test 1: ${test1.description}`);
  89. console.log(` Status: ${test1.statusCode} ${test1.statusCode === 200 ? '✓ PASS' : '✗ FAIL'}`);
  90. console.log(` Response: ${test1.body}\n`);
  91. // Test 2: Invalid signature
  92. const test2 = await sendWebhook(
  93. TEST_PORT,
  94. payload,
  95. 'invalid-signature-123',
  96. 'Invalid signature'
  97. );
  98. console.log(`✓ Test 2: ${test2.description}`);
  99. console.log(` Status: ${test2.statusCode} ${test2.statusCode === 401 ? '✓ PASS' : '✗ FAIL'}`);
  100. console.log(` Response: ${test2.body}\n`);
  101. // Test 3: Missing signature
  102. const test3 = await sendWebhook(
  103. TEST_PORT,
  104. payload,
  105. null,
  106. 'Missing signature'
  107. );
  108. console.log(`✓ Test 3: ${test3.description}`);
  109. console.log(` Status: ${test3.statusCode} ${test3.statusCode === 401 ? '✓ PASS' : '✗ FAIL'}`);
  110. console.log(` Response: ${test3.body}\n`);
  111. // Summary
  112. const results = [test1, test2, test3];
  113. const passed = results.filter((r, i) => {
  114. if (i === 0) return r.statusCode === 200;
  115. return r.statusCode === 401;
  116. }).length;
  117. console.log('═══════════════════════════════════════');
  118. console.log(`Results: ${passed}/3 tests passed`);
  119. console.log('═══════════════════════════════════════\n');
  120. if (passed === 3) {
  121. console.log('✅ All signature verification tests passed!');
  122. console.log(' - Valid signatures are accepted (200)');
  123. console.log(' - Invalid signatures are rejected (401)');
  124. console.log(' - Missing signatures are rejected (401)');
  125. } else {
  126. console.log('❌ Some tests failed!');
  127. process.exitCode = 1;
  128. }
  129. } finally {
  130. await server.stop();
  131. console.log('\n🛑 Test server stopped');
  132. }
  133. }
  134. runTests().catch(err => {
  135. console.error('❌ Test error:', err);
  136. process.exit(1);
  137. });