Sdlweb: Added github-webhook

From 0fb242fee3f596c8131a5102b75c8d0958e39c5a Mon Sep 17 00:00:00 2001
From: "Ryan C. Gordon" <[EMAIL REDACTED]>
Date: Sun, 14 Feb 2021 06:39:35 +0000
Subject: [PATCH] Added github-webhook.

---
 github-webhook/index.php | 103 +++++++++++++++++++++++++++++++++++++++
 1 file changed, 103 insertions(+)
 create mode 100644 github-webhook/index.php

diff --git a/github-webhook/index.php b/github-webhook/index.php
new file mode 100644
index 0000000..adde94a
--- /dev/null
+++ b/github-webhook/index.php
@@ -0,0 +1,103 @@
+<?php
+// GitHub POSTs to this script whenever any repository in the libsdl-org
+//  Organization is pushed to. This lets us do several things:
+//  - Tweet new commits via @sdl_commits.
+//  - Post commit notifications to Discourse.
+//  - Fire up the buildbot (EDIT: this is handled in a different webhook).
+//  - Update the website by pulling from the sdlweb repo.
+//  - etc.
+
+header('Content-Type: text/plain; charset=utf-8');
+
+// Stole some of this from https://github.com/dintel/php-github-webhook/blob/master/src/Handler.php
+function validateSignature($gitHubSignatureHeader, $payload)
+{
+    $secret = rtrim(file_get_contents('/webspace/github-webhook-secret.txt'));
+    list ($algo, $gitHubSignature) = explode("=", $gitHubSignatureHeader);
+
+    if (($algo !== 'sha256') && ($algo !== 'sha1')) {
+        // see https://developer.github.com/webhooks/securing/
+        return false;
+    }
+
+    $payloadHash = hash_hmac($algo, $payload, $secret);
+    return ($payloadHash === $gitHubSignature);
+}
+
+$signature = isset($_SERVER['HTTP_X_HUB_SIGNATURE_256']) ? $_SERVER['HTTP_X_HUB_SIGNATURE_256'] : NULL;
+$event = isset($_SERVER['HTTP_X_GITHUB_EVENT']) ? $_SERVER['HTTP_X_GITHUB_EVENT'] : NULL;
+$delivery = isset($_SERVER['HTTP_X_GITHUB_DELIVERY']) ? $_SERVER['HTTP_X_GITHUB_DELIVERY'] : NULL;
+
+if (!isset($signature, $event, $delivery)) {
+    print("BAD SIGNATURE\n");
+    exit(0);
+}
+
+$payload = file_get_contents('php://input');
+
+// Check if the payload is json or urlencoded.
+if (strpos($payload, 'payload=') === 0) {
+    $payload = substr(urldecode($payload), 8);
+}
+
+if (!validateSignature($signature, $payload)) {
+    print("BAD SIGNATURE\n");
+    exit(0);
+}
+
+print("SIGNATURE OK\n");
+print("GITHUB EVENT: $event\n");
+
+if ($event == 'push') {
+    $basedir = '/webspace/sdl_commit_events';
+    $dirs = scandir($basedir, SCANDIR_SORT_NONE);
+    if ($dirs === false) {
+        print("FAILED TO SCANDIR BASE DIRECTORY.\n");
+        exit(0);
+    }
+
+    foreach ($dirs as $d) {
+        if (substr($d, 0, 1) == '.') { continue; }  // skip "." and ".." and other magic files.
+
+        // Use an advisory lock to make sure we don't race against other webhook handlers
+        //  or the consumers of this data.
+        $lockfname = "$basedir/$d/.github_webhook_lock";
+        $lockfp = fopen($lockfname, 'c+');
+        if ($lockfp === false) {
+            print("LOCKFILE '$lockfname' DID NOT OPEN.  :O\n");  // going on and praying to avoid race by sheer luck  :/
+        } else if (flock($lockfp, LOCK_EX) === false) {
+            print("LOCKFILE '$lockfname' DID NOT LOCK.  :O\n");  // going on and praying to avoid race by sheer luck  :/
+        }
+
+        // Tell the cronjobs there's work to do. Dump the json payload where they can find it.
+        $fnameid = time();
+        $fp = false;
+        $fname = '';
+        do {
+            $fname = "$basedir/$d/$fnameid";
+            $fnameid++;
+        } while (($fp = @fopen($fname, 'x')) === false);  // 'x' so we make sure other hook handlers don't compete for the file name.
+
+        fwrite($fp, $payload);
+        fclose($fp);
+
+        if ($lockfp !== false) {
+            flock($lockfp, LOCK_UN);
+            fclose($lockfp);
+        }
+
+        print("PUSH INFO SAVED TO: $fname\n");
+    }
+
+    if ($repo == 'sdlweb') {
+        // !!! FIXME: update the website.
+    }
+}
+
+// handle other events we care about here.
+
+print("OK\n\n");
+exit(0);
+
+?>
+