Browse Source

adding webhook tool

Co-authored-by: Copilot <copilot@github.com>
Medowar 1 month ago
parent
commit
3e7f126b83
4 changed files with 419 additions and 0 deletions
  1. 4 0
      .gitignore
  2. 139 0
      webhook-debug/index.php
  3. 198 0
      webhook-debug/view.php
  4. 78 0
      webhook-debug/webhook.php

+ 4 - 0
.gitignore

@@ -0,0 +1,4 @@
+fw-hook/data/*.json
+click/data/*.json
+click/data/*.jsonl
+webhook-debug/data/*.json

+ 139 - 0
webhook-debug/index.php

@@ -0,0 +1,139 @@
+<?php
+declare(strict_types=1);
+
+$baseUrl = (isset($_SERVER['HTTPS']) ? 'https' : 'http') . '://' . $_SERVER['HTTP_HOST'] . dirname($_SERVER['SCRIPT_NAME']);
+$dataPath = __DIR__ . '/data/webhooks.json';
+$maxWebhooks = 100;
+
+// Handle webhook creation
+if ($_SERVER['REQUEST_METHOD'] === 'POST' && isset($_POST['action']) && $_POST['action'] === 'create') {
+    $raw = file_get_contents($dataPath);
+    $data = json_decode($raw, true);
+    
+    if (count($data['webhooks']) >= $maxWebhooks) {
+        $error = 'Maximum number of webhooks (' . $maxWebhooks . ') reached.';
+    } else {
+        $key = bin2hex(random_bytes(8));
+        $webhook = [
+            'key' => $key,
+            'created' => date('c'),
+            'requests' => []
+        ];
+        $data['webhooks'][] = $webhook;
+        file_put_contents($dataPath, json_encode($data, JSON_PRETTY_PRINT), LOCK_EX);
+        header('Location: ' . $_SERVER['REQUEST_URI']);
+        exit;
+    }
+}
+
+// Load webhooks
+$raw = file_get_contents($dataPath);
+$data = json_decode($raw, true);
+$webhooks = $data['webhooks'];
+?>
+<!DOCTYPE html>
+<html lang="en">
+<head>
+    <meta charset="UTF-8">
+    <meta name="viewport" content="width=device-width, initial-scale=1.0">
+    <title>Webhook Debug Tool</title>
+    <style>
+        body {
+            font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, sans-serif;
+            max-width: 1200px;
+            margin: 40px auto;
+            padding: 0 20px;
+            background: #f5f5f5;
+        }
+        h1 { color: #333; }
+        .info { background: #e3f2fd; padding: 15px; border-radius: 5px; margin-bottom: 20px; }
+        table { width: 100%; border-collapse: collapse; background: white; box-shadow: 0 1px 3px rgba(0,0,0,0.1); }
+        th, td { padding: 12px; text-align: left; border-bottom: 1px solid #ddd; }
+        th { background: #2196F3; color: white; }
+        tr:hover { background: #f5f5f5; }
+        .btn {
+            display: inline-block;
+            padding: 10px 20px;
+            background: #2196F3;
+            color: white;
+            text-decoration: none;
+            border-radius: 5px;
+            border: none;
+            cursor: pointer;
+            font-size: 14px;
+        }
+        .btn:hover { background: #1976D2; }
+        .btn-danger { background: #f44336; }
+        .btn-danger:hover { background: #d32f2f; }
+        .url-box {
+            background: #f5f5f5;
+            padding: 8px;
+            border-radius: 3px;
+            font-family: monospace;
+            font-size: 12px;
+            word-break: break-all;
+        }
+        .empty { text-align: center; color: #999; padding: 40px; }
+        .error { background: #ffebee; color: #c62828; padding: 10px; border-radius: 5px; margin: 10px 0; }
+        form { display: inline; }
+    </style>
+</head>
+<body>
+    <h1>🔗 Webhook Debug Tool</h1>
+    
+    <div class="info">
+        <strong>How to use:</strong>
+        <ol>
+            <li>Click "Create New Webhook" to generate a unique webhook URL</li>
+            <li>Copy the webhook URL and configure it as the webhook endpoint in your service</li>
+            <li>Send requests to the webhook URL - all data will be captured</li>
+            <li>Click "View Requests" to see all captured requests with headers and body</li>
+        </ol>
+    </div>
+
+    <?php if (isset($error)): ?>
+        <div class="error"><?= htmlspecialchars($error) ?></div>
+    <?php endif; ?>
+
+    <div style="margin-bottom: 20px;">
+        <form method="POST" style="display: inline;">
+            <input type="hidden" name="action" value="create">
+            <button type="submit" class="btn">➕ Create New Webhook</button>
+        </form>
+        <span style="margin-left: 10px; color: #666;">(<?= count($webhooks) ?>/<?= $maxWebhooks ?> webhooks)</span>
+    </div>
+
+    <?php if (empty($webhooks)): ?>
+        <div class="empty">No webhooks created yet. Click "Create New Webhook" to get started.</div>
+    <?php else: ?>
+        <table>
+            <thead>
+                <tr>
+                    <th>Key</th>
+                    <th>Created</th>
+                    <th>Requests</th>
+                    <th>Webhook URL</th>
+                    <th>Actions</th>
+                </tr>
+            </thead>
+            <tbody>
+                <?php foreach (array_reverse($webhooks) as $webhook): ?>
+                    <tr>
+                        <td><code><?= htmlspecialchars($webhook['key']) ?></code></td>
+                        <td><?= htmlspecialchars(date('Y-m-d H:i:s', strtotime($webhook['created']))) ?></td>
+                        <td><?= count($webhook['requests']) ?></td>
+                        <td>
+                            <div class="url-box">
+                                <?= htmlspecialchars($baseUrl . '/webhook.php?key=' . $webhook['key']) ?>
+                            </div>
+                        </td>
+                        <td>
+                            <a href="view.php?key=<?= urlencode($webhook['key']) ?>" class="btn">View Requests</a>
+                        </td>
+                    </tr>
+                <?php endforeach; ?>
+            </tbody>
+        </table>
+    <?php endif; ?>
+</body>
+</html>

+ 198 - 0
webhook-debug/view.php

@@ -0,0 +1,198 @@
+<?php
+declare(strict_types=1);
+
+$baseUrl = (isset($_SERVER['HTTPS']) ? 'https' : 'http') . '://' . $_SERVER['HTTP_HOST'] . dirname($_SERVER['SCRIPT_NAME']);
+$dataPath = __DIR__ . '/data/webhooks.json';
+
+// Validate key parameter
+if (!isset($_GET['key']) || empty($_GET['key'])) {
+    http_response_code(400);
+    die('<h1>Error: Missing key parameter</h1>');
+}
+
+$key = $_GET['key'];
+
+// Load webhooks
+$raw = file_get_contents($dataPath);
+$data = json_decode($raw, true);
+
+// Find the webhook
+$webhook = null;
+foreach ($data['webhooks'] as $w) {
+    if ($w['key'] === $key) {
+        $webhook = $w;
+        break;
+    }
+}
+
+if ($webhook === null) {
+    http_response_code(404);
+    die('<h1>Error: Webhook not found</h1>');
+}
+
+// Reverse requests to show newest first
+$requests = array_reverse($webhook['requests']);
+
+// Helper function to format JSON
+function formatJson($string) {
+    $decoded = json_decode($string, true);
+    if (json_last_error() === JSON_ERROR_NONE) {
+        return json_encode($decoded, JSON_PRETTY_PRINT | JSON_UNESCAPED_SLASHES);
+    }
+    return $string;
+}
+
+// Helper function to format headers
+function formatHeaders($headers) {
+    $output = '';
+    foreach ($headers as $name => $value) {
+        $output .= htmlspecialchars($name) . ': ' . htmlspecialchars($value) . "\n";
+    }
+    return rtrim($output);
+}
+?>
+<!DOCTYPE html>
+<html lang="en">
+<head>
+    <meta charset="UTF-8">
+    <meta name="viewport" content="width=device-width, initial-scale=1.0">
+    <title>Webhook: <?= htmlspecialchars($webhook['key']) ?></title>
+    <style>
+        body {
+            font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, sans-serif;
+            max-width: 1400px;
+            margin: 40px auto;
+            padding: 0 20px;
+            background: #f5f5f5;
+        }
+        h1 { color: #333; }
+        .info { background: #e3f2fd; padding: 15px; border-radius: 5px; margin-bottom: 20px; }
+        .url-box {
+            background: #fff;
+            padding: 10px;
+            border-radius: 3px;
+            font-family: monospace;
+            font-size: 13px;
+            word-break: break-all;
+            border: 1px solid #ddd;
+        }
+        .btn {
+            display: inline-block;
+            padding: 8px 16px;
+            background: #2196F3;
+            color: white;
+            text-decoration: none;
+            border-radius: 5px;
+            border: none;
+            cursor: pointer;
+            font-size: 14px;
+        }
+        .btn:hover { background: #1976D2; }
+        .btn-secondary { background: #757575; }
+        .btn-secondary:hover { background: #616161; }
+        .request {
+            background: white;
+            border-radius: 5px;
+            margin-bottom: 20px;
+            box-shadow: 0 1px 3px rgba(0,0,0,0.1);
+            overflow: hidden;
+        }
+        .request-header {
+            background: #2196F3;
+            color: white;
+            padding: 12px 15px;
+            font-weight: bold;
+            display: flex;
+            justify-content: space-between;
+            align-items: center;
+        }
+        .request-method {
+            background: rgba(255,255,255,0.2);
+            padding: 3px 8px;
+            border-radius: 3px;
+            font-size: 12px;
+            margin-right: 10px;
+        }
+        .request-body {
+            padding: 15px;
+        }
+        .section {
+            margin-bottom: 15px;
+        }
+        .section-title {
+            font-weight: bold;
+            color: #666;
+            margin-bottom: 5px;
+            font-size: 13px;
+            text-transform: uppercase;
+        }
+        .code-box {
+            background: #f5f5f5;
+            border: 1px solid #ddd;
+            border-radius: 3px;
+            padding: 10px;
+            font-family: 'Courier New', monospace;
+            font-size: 12px;
+            white-space: pre-wrap;
+            word-break: break-all;
+            max-height: 400px;
+            overflow-y: auto;
+        }
+        .empty { text-align: center; color: #999; padding: 40px; }
+        .back-link { margin-bottom: 20px; display: inline-block; }
+    </style>
+</head>
+<body>
+    <a href="index.php" class="back-link btn btn-secondary">← Back to Webhooks</a>
+    
+    <h1>🔗 Webhook Details</h1>
+    
+    <div class="info">
+        <div><strong>Key:</strong> <code><?= htmlspecialchars($webhook['key']) ?></code></div>
+        <div style="margin-top: 10px;"><strong>Created:</strong> <?= htmlspecialchars(date('Y-m-d H:i:s', strtotime($webhook['created']))) ?></div>
+        <div style="margin-top: 10px;"><strong>Webhook URL:</strong></div>
+        <div class="url-box" style="margin-top: 5px;">
+            <?= htmlspecialchars($baseUrl . '/webhook.php?key=' . $webhook['key']) ?>
+        </div>
+        <div style="margin-top: 10px;"><strong>Total Requests:</strong> <?= count($webhook['requests']) ?></div>
+    </div>
+
+    <h2>Received Requests</h2>
+
+    <?php if (empty($requests)): ?>
+        <div class="empty">No requests received yet. Send a POST request to the webhook URL above.</div>
+    <?php else: ?>
+        <?php foreach ($requests as $index => $request): ?>
+            <div class="request">
+                <div class="request-header">
+                    <span>
+                        <span class="request-method"><?= htmlspecialchars($request['method']) ?></span>
+                        Request #<?= count($webhook['requests']) - $index ?>
+                    </span>
+                    <span style="font-size: 12px; font-weight: normal;">
+                        <?= htmlspecialchars(date('Y-m-d H:i:s', strtotime($request['timestamp']))) ?>
+                    </span>
+                </div>
+                <div class="request-body">
+                    <div class="section">
+                        <div class="section-title">Headers</div>
+                        <div class="code-box"><?= formatHeaders($request['headers']) ?></div>
+                    </div>
+                    
+                    <div class="section">
+                        <div class="section-title">Body</div>
+                        <?php 
+                        $isJson = false;
+                        if (isset($request['headers']['Content-Type']) && 
+                            strpos($request['headers']['Content-Type'], 'application/json') !== false) {
+                            $isJson = true;
+                        }
+                        ?>
+                        <div class="code-box"><?= htmlspecialchars($isJson ? formatJson($request['body']) : $request['body']) ?></div>
+                    </div>
+                </div>
+            </div>
+        <?php endforeach; ?>
+    <?php endif; ?>
+</body>
+</html>

+ 78 - 0
webhook-debug/webhook.php

@@ -0,0 +1,78 @@
+<?php
+declare(strict_types=1);
+
+header('Content-Type: application/json; charset=utf-8');
+
+// Only accept POST requests
+if ($_SERVER['REQUEST_METHOD'] !== 'POST') {
+    http_response_code(405);
+    echo json_encode(['error' => 'Method Not Allowed', 'allowed' => ['POST']]);
+    exit;
+}
+
+// Validate key parameter
+if (!isset($_GET['key']) || empty($_GET['key'])) {
+    http_response_code(400);
+    echo json_encode(['error' => 'Missing key parameter']);
+    exit;
+}
+
+$key = $_GET['key'];
+$dataPath = __DIR__ . '/data/webhooks.json';
+$maxRequestsPerWebhook = 100;
+
+// Read and validate webhook
+$fp = fopen($dataPath, 'c+');
+if (!$fp) {
+    http_response_code(500);
+    echo json_encode(['error' => 'Internal server error']);
+    exit;
+}
+
+flock($fp, LOCK_EX);
+$raw = stream_get_contents($fp);
+$data = json_decode($raw, true);
+
+// Find the webhook
+$webhookIndex = null;
+foreach ($data['webhooks'] as $index => $webhook) {
+    if ($webhook['key'] === $key) {
+        $webhookIndex = $index;
+        break;
+    }
+}
+
+if ($webhookIndex === null) {
+    flock($fp, LOCK_UN);
+    fclose($fp);
+    http_response_code(404);
+    echo json_encode(['error' => 'Webhook not found']);
+    exit;
+}
+
+// Capture request data
+$request = [
+    'timestamp' => date('c'),
+    'method' => $_SERVER['REQUEST_METHOD'],
+    'headers' => getallheaders() ?: [],
+    'body' => file_get_contents('php://input')
+];
+
+// Add request to webhook
+$data['webhooks'][$webhookIndex]['requests'][] = $request;
+
+// Enforce max requests limit (FIFO - remove oldest)
+if (count($data['webhooks'][$webhookIndex]['requests']) > $maxRequestsPerWebhook) {
+    array_shift($data['webhooks'][$webhookIndex]['requests']);
+}
+
+// Write back to file
+ftruncate($fp, 0);
+rewind($fp);
+fwrite($fp, json_encode($data, JSON_PRETTY_PRINT));
+flock($fp, LOCK_UN);
+fclose($fp);
+
+// Return success response
+http_response_code(200);
+echo json_encode(['success' => true, 'message' => 'Request logged']);