First commit
This commit is contained in:
commit
bcd7365f76
|
@ -0,0 +1 @@
|
|||
.*.sw*
|
|
@ -0,0 +1,3 @@
|
|||
# forge-endpoints.php
|
||||
|
||||
PHP implementation of the forgehook endpoints. The server script should never be used in production, it's only here to run tests.
|
|
@ -0,0 +1,171 @@
|
|||
<?php
|
||||
|
||||
function error($message, $code = 500) {
|
||||
http_response_code($code);
|
||||
error_log($message);
|
||||
exit();
|
||||
}
|
||||
|
||||
// extract_payload()
|
||||
// Find the JSON payload from the POST request
|
||||
function extract_payload() {
|
||||
// check for POST request
|
||||
if ($_SERVER['REQUEST_METHOD'] != 'POST') {
|
||||
error('FAILED - not POST - '. $_SERVER['REQUEST_METHOD']);
|
||||
}
|
||||
// get content type
|
||||
$content_type = isset($_SERVER['CONTENT_TYPE']) ? strtolower(trim($_SERVER['CONTENT_TYPE'])) : '';
|
||||
if ($content_type != 'application/json') {
|
||||
error('FAILED - not application/json - '. $content_type);
|
||||
}
|
||||
// get payload
|
||||
$payload = trim(file_get_contents("php://input"));
|
||||
// TODO: trim or not?
|
||||
//$payload = file_get_contents("php://input");
|
||||
if (empty($payload)) {
|
||||
error('FAILED - no payload');
|
||||
}
|
||||
return $payload;
|
||||
|
||||
}
|
||||
|
||||
// json_to_array(payload)
|
||||
// payload: JSON string
|
||||
function json_to_array($payload) {
|
||||
// convert json to array
|
||||
$json = json_decode($payload, true);
|
||||
// check for json decode errors
|
||||
if (json_last_error() !== JSON_ERROR_NONE) {
|
||||
error('FAILED - json decode - '. json_last_error());
|
||||
}
|
||||
return $json;
|
||||
}
|
||||
|
||||
// Find header value or die
|
||||
function extract_header($header) {
|
||||
// PHP embedded server prepends HTTP_ to the header name. WTF?
|
||||
$value = isset($_SERVER[$header]) ? $_SERVER[$header]
|
||||
: (isset($_SERVER['HTTP_'.$header]) ? $_SERVER['HTTP_'.$header]
|
||||
: '');
|
||||
//error_log("extracted header: ".$value);
|
||||
|
||||
if (empty($value)) {
|
||||
error('FAILED - header signature missing');
|
||||
}
|
||||
|
||||
return $value;
|
||||
}
|
||||
|
||||
function verify_signature($payload, $secret, $claimed_signature) {
|
||||
$payload_signature = hash_hmac('sha256', $payload, $secret, false);
|
||||
|
||||
// check payload signature against header signature
|
||||
if ($claimed_signature != $payload_signature) {
|
||||
error_log("payload:".$payload."EOF");
|
||||
error_log("sig: ".$payload_signature);
|
||||
error('FAILED - payload signature mismatch', 403);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
function verify_token($secret, $claimed_secret) {
|
||||
error_log($secret." vs ".$claimed_secret);
|
||||
if ($secret !== $claimed_secret) {
|
||||
error('FAILED - secret token mismatch', 403);
|
||||
}
|
||||
}
|
||||
|
||||
// find_secret($repo_url)
|
||||
// Find the secret corresponding to the repo_url, if any. Returns empty string otherwise
|
||||
function find_secret($repo_url) {
|
||||
$forgehook = getenv('FORGEHOOK') ? : 'forgehook';
|
||||
|
||||
// Please no Remote Code Execution
|
||||
$repo = escapeshellarg($repo_url);
|
||||
$secret = shell_exec($forgehook." secret ".$repo);
|
||||
|
||||
// Error returns NULL
|
||||
if ($secret == NULL) {
|
||||
error("Secret not found for ".$repo);
|
||||
}
|
||||
|
||||
$secret = trim($secret);
|
||||
if (empty($secret)) {
|
||||
error("Secret empty for ".$repo);
|
||||
}
|
||||
//error_log('secret: '.$secret);
|
||||
return $secret;
|
||||
}
|
||||
|
||||
function find_url_gitea($array) {
|
||||
$repo_url = isset($array["repository"]["html_url"]) ?
|
||||
$array["repository"]["html_url"] : "";
|
||||
if (empty($repo_url)) {
|
||||
error('Could not find Gitea repository URL');
|
||||
}
|
||||
return $repo_url;
|
||||
}
|
||||
|
||||
function find_url_gitlab($array) {
|
||||
$repo_url = isset($array["project"]["git_http_url"]) ?
|
||||
$array["project"]["git_http_url"] : "";
|
||||
if (empty($repo_url)) {
|
||||
error('Could not find Gitlab repository URL');
|
||||
}
|
||||
return $repo_url;
|
||||
}
|
||||
|
||||
function notify($repo) {
|
||||
$notify = getenv('FORGEHOOKNOTIFY') ? : 'forgehook-notify';
|
||||
|
||||
$output=shell_exec($notify." ".$repo);
|
||||
|
||||
if ($output != NULL) {
|
||||
error_log("Notify failed (".$notify.") with:\n".$output);
|
||||
}
|
||||
}
|
||||
|
||||
function action() {
|
||||
if (!isset($_GET['action'])) {
|
||||
error("You need to specify an action (gitea, gitlab) like this: ?action=gitea", 404);
|
||||
}
|
||||
switch($_GET['action']) {
|
||||
case 'github':
|
||||
$claimed_secret = extract_header("HTTP_X_HUB_SIGNATURE");
|
||||
$payload = extract_payload();
|
||||
$payload_array = json_to_array($payload);
|
||||
// Gitea URL is same as Github, for the moment
|
||||
$repo_url = find_url_gitea($payload_array);
|
||||
$secret = find_secret($repo_url);
|
||||
verify_signature($payload, $secret, $claimed_secret);
|
||||
notify($repo_url);
|
||||
break;
|
||||
case 'gitea':
|
||||
$claimed_secret = extract_header("HTTP_X_GITEA_SIGNATURE");
|
||||
$payload = extract_payload();
|
||||
$payload_array = json_to_array($payload);
|
||||
$repo_url = find_url_gitea($payload_array);
|
||||
$secret = find_secret($repo_url);
|
||||
verify_signature($payload, $secret, $claimed_secret);
|
||||
notify($repo_url);
|
||||
break;
|
||||
case 'gitlab':
|
||||
//error_log(print_r(getallheaders(), true));
|
||||
//error_log(print_r($_SERVER, true));
|
||||
$claimed_secret = extract_header("HTTP_X_GITLAB_TOKEN");
|
||||
$payload = extract_payload();
|
||||
$payload_array = json_to_array($payload);
|
||||
$repo_url = find_url_gitlab($payload_array);
|
||||
$secret = find_secret($repo_url);
|
||||
verify_token($secret, $claimed_secret);
|
||||
notify($repo_url);
|
||||
break;
|
||||
default:
|
||||
error("Unrecognized action: ".$_GET['action'], 400);
|
||||
}
|
||||
}
|
||||
|
||||
action();
|
||||
error_log("OK");
|
||||
|
||||
?>
|
|
@ -0,0 +1,14 @@
|
|||
#! /bin/bash
|
||||
# This script should be used by the test suite, don't useit manually
|
||||
# or you may end up with zombie processes lying around
|
||||
|
||||
if [ -z "$FORGEHOOKPORT" ]; then
|
||||
[ -z "$1" ] && exit 1
|
||||
FORGEHOOKPORT="$1"
|
||||
fi
|
||||
[ -z "$FORGEHOOK" ] && FORGEHOOK="forgehook"
|
||||
|
||||
php -S localhost:$FORGEHOOKPORT
|
||||
if [[ $? != 0 ]]; then
|
||||
exit 2
|
||||
fi
|
Loading…
Reference in New Issue