/** * Run react/http server for incoming GitHub webhook events * * @param LoopInterface $loop * @param int $port * @param string $ip */ private function runServer(LoopInterface $loop, $port = 8080, $ip = '0.0.0.0') { // Set up react HTTP server to listen for github webhooks $socket = new \React\Socket\Server($loop); $http = new \React\Http\Server($socket, $loop); $http->on('request', function ($request, $response) { $headers = $request->getHeaders(); $path = $request->getPath(); $hook = substr($path, 1); // Basic check if we got event and signature headers if (empty($headers['X-GitHub-Event'])) { $response->writeHead(500, ['Content-Type' => 'text/plain']); $response->end("Missing event header\n"); $this->plugin->getLogger()->error("Received request with missing event header"); return; } if (empty($headers['X-Hub-Signature'])) { $response->writeHead(500, ['Content-Type' => 'text/plain']); $response->end("Missing signature\n"); $this->plugin->getLogger()->error("Received request with missing signature header"); return; } // Check if the hook actually exists if (empty($hook)) { $response->writeHead(500, ['Content-Type' => 'text/plain']); $response->end("Missing hook name\n"); $this->plugin->getLogger()->error("Received request with missing hook name, check out the plugin README"); return; } $hooks = $this->plugin->getHooks(); if (!isset($hooks[$hook])) { $response->writeHead(500, ['Content-Type' => 'text/plain']); $response->end("Missing hook name\n"); $this->plugin->getLogger()->error("{$hook} does not match any defined hooks in the plugin configuration, check out the plugin README"); return; } // Okay the request $response->writeHead(200, ['Content-Type' => 'text/plain']); $response->end("OK\n"); // Get incoming JSON payload $payload = ""; $request->on('data', function ($data) use(&$payload) { $payload .= $data; }); // Wait for the end of data burst $request->on('end', function () use(&$payload, $headers, $hook) { $raw_payload = $payload; // Parse json payload to PHP array $payload = json_decode($payload, TRUE); if (!$payload) { $this->plugin->getLogger()->error(sprintf("Unable to parse payload: %s", json_last_error_msg())); $this->plugin->getLogger()->debug('Payload: ' . var_export($payload, TRUE)); return; } // Verify signature $hooks = $this->plugin->getHooks(); if (!empty($hooks[$hook]['secret'])) { list($algo, $signature) = explode("=", $headers['X-Hub-Signature']); if (hash_hmac($algo, $raw_payload, $hooks[$hook]['secret']) != $signature) { $this->plugin->getLogger()->error("Invalid signature, void request"); return; } } else { $this->plugin->getLogger()->warning("No secret set for {$hook}, seriously consider setting one"); } $this->plugin->getEventEmitter()->emit("githubhooks.{$hook}.{$headers['X-GitHub-Event']}", [$payload]); }); }); $socket->listen($port, $ip); }
/** * Tests that getSubscribedEvents() returns an array. */ public function testGetSubscribedEvents() { $plugin = new Plugin(); $this->assertInternalType('array', $plugin->getSubscribedEvents()); }