From 70e340be340d1e069f2971365511c260fd80578e Mon Sep 17 00:00:00 2001 From: flashwave Date: Fri, 30 Jul 2021 22:06:11 +0000 Subject: [PATCH] Moved webhook handler for changelog into Misuzu. --- .gitignore | 1 + config/github.example.ini | 9 ++ public/_github-callback.php | 146 ++++++++++++++++++++++++++++++++ templates/changelog/change.twig | 2 +- templates/changelog/macros.twig | 6 +- 5 files changed, 160 insertions(+), 4 deletions(-) create mode 100644 config/github.example.ini create mode 100644 public/_github-callback.php diff --git a/.gitignore b/.gitignore index a7a6ac98..d9e72dff 100644 --- a/.gitignore +++ b/.gitignore @@ -6,6 +6,7 @@ # Configuration /config/config.ini +/config/github.ini /.debug /.migrating diff --git a/config/github.example.ini b/config/github.example.ini new file mode 100644 index 00000000..0580278e --- /dev/null +++ b/config/github.example.ini @@ -0,0 +1,9 @@ +[tokens] +token[flashwave/misuzu] = token-here + +[addresses] +github@flash.moe = 1 + +[repo:flashwave/misuzu] +tags[] = 1 +tags[] = 3 diff --git a/public/_github-callback.php b/public/_github-callback.php new file mode 100644 index 00000000..4e73a0d7 --- /dev/null +++ b/public/_github-callback.php @@ -0,0 +1,146 @@ += 10 ? $line : mb_substr($line, $findColon + 1)); +} + +function ghcb_changelog_action(string &$line): int { + $original = trim($line); + $line = ghcb_strip_prefix($line); + + $firstSix = mb_strtolower(mb_substr($original, 0, 6)); + + if($firstSix === 'revert' + || $firstSix === 'restor') + return ChangelogChange::ACTION_REVERT; + if($firstSix === 'import') + return ChangelogChange::ACTION_IMPORT; + + $firstThree = mb_strtolower(mb_substr($original, 0, 3)); + + if($firstThree === 'add' + || $firstSix === 'create') + return ChangelogChange::ACTION_ADD; + if($firstThree === 'fix') + return ChangelogChange::ACTION_FIX; + + $firstFour = mb_strtolower(mb_substr($original, 0, 4)); + $firstEight = mb_strtolower(mb_substr($original, 0, 8)); + + if($firstSix === 'delete' + || $firstSix === 'remove' + || $firstFour === 'nuke' + || $firstEight === 'dropkick') + return ChangelogChange::ACTION_REMOVE; + + return ChangelogChange::ACTION_UPDATE; +} + +header('Content-Type: text/plain; charset=utf-8'); + +if($_SERVER['REQUEST_METHOD'] !== 'POST') + die('no'); + +$config = MSZ_ROOT . '/config/github.ini'; +if(!is_file($config)) + die('config missing'); + +$config = parse_ini_file(MSZ_ROOT . '/config/github.ini', true); +if(empty($config['tokens']['token'])) + die('config invalid'); + +$isGitea = isset($_SERVER['HTTP_X_GITEA_DELIVERY']) && isset($_SERVER['HTTP_X_GITEA_EVENT']); + +$rawData = file_get_contents('php://input'); +$sigParts = $isGitea + ? ['sha256', $_SERVER['HTTP_X_GITEA_SIGNATURE']] + : explode('=', $_SERVER['HTTP_X_HUB_SIGNATURE'] ?? '', 2); + +if(empty($sigParts[1])) + die('invalid signature'); + +$repoAuthenticated = false; +foreach($config['tokens']['token'] as $repoName => $repoToken) { + if(hash_equals(hash_hmac($sigParts[0], $rawData, $repoToken), $sigParts[1])) { + $repoAuthenticated = true; + break; + } +} + +if(!$repoAuthenticated) + die('signature check failed'); + +$data = json_decode($_SERVER['CONTENT_TYPE'] === 'application/x-www-form-urlencoded' + ? $_POST['payload'] + : $rawData); + +if(empty($data)) + die('body is corrupt'); + +if(empty($data->repository->full_name)) + die('body is corrupt'); + +if($data->repository->full_name !== $repoName) + die('invalid repository token'); + +if($_SERVER['HTTP_X_GITHUB_EVENT'] !== 'push') + die('only push event is supported'); + +$commitCount = count($data->commits); +if($commitCount < 1) + die('no commits received'); + +$repoInfo = $config['repo:' . $repoName] ?? []; + +$repoMaster = 'refs/heads/master'; +if(!empty($repoInfo['master'])) + $repoMaster = $repoInfo['master']; + +if($data->ref !== $repoMaster) + die('only the master branch is tracked'); + +// the actual changelog api sucks ass +$changeCreate = DB::prepare('INSERT INTO `msz_changelog_changes` (`change_log`, `change_text`, `change_action`, `user_id`, `change_created`) VALUES (:log, :text, :action, :user, FROM_UNIXTIME(:created))'); +$changeTag = DB::prepare('REPLACE INTO `msz_changelog_change_tags` VALUES (:change_id, :tag_id)'); + +$tags = $repoInfo['tags'] ?? []; +$addresses = $config['addresses'] ?? []; + +foreach($data->commits as $commit) { + $message = trim($commit->message); + + if(mb_strpos($message, $repoName) !== false + || mb_substr($message, 0, 2) === '//' + || mb_strpos(mb_strtolower($message), 'merge pull request') !== false) + continue; + + $index = mb_strpos($message, "\n"); + $line = $index === false ? $message : mb_substr($message, 0, $index); + $body = trim($index === false ? null : mb_substr($message, $index + 1)); + + $changeCreate->bind('user', $addresses[$commit->author->email] ?? null); + $changeCreate->bind('action', ghcb_changelog_action($line)); + $changeCreate->bind('log', $line); + $changeCreate->bind('text', empty($body) ? null : $body); + $changeCreate->bind('created', max(1, strtotime($commit->timestamp))); + $changeId = $changeCreate->executeGetId(); + + if(!empty($tags) && !empty($changeId)) { + $changeTag->bindValue('change_id', $changeId); + + foreach($tags as $tag) { + $changeTag->bindValue('tag_id', $tag); + $changeTag->execute(); + } + } + + unset($changeId, $tag); +} diff --git a/templates/changelog/change.twig b/templates/changelog/change.twig index cf42b1c9..0aa37bef 100644 --- a/templates/changelog/change.twig +++ b/templates/changelog/change.twig @@ -22,7 +22,7 @@