3b71ef0a70596314b07d58843498e80ad70ed5e4
[m6w6/gh-mirror] / mirror.php
1 <?php
2
3 use http\Env\Request;
4 use http\Env\Response;
5 use http\Params;
6
7 $request = new Request;
8 $response = new Response;
9 $response->setResponseCode(500);
10 ob_start($response);
11
12 $mirror = getenv("mirror") ?: "/var/github/mirror";
13 $secret = getenv("secret") ?: trim(file_get_contents("$mirror/.secret"));
14 $owners = explode(",", getenv("owners") ?: trim(file_get_contents("$mirror/.owners")));
15
16 $sig = $request->getHeader("X-Hub-Signature");
17 $evt = $request->getHeader("X-Github-Event");
18
19 if (!$sig || !$evt) {
20 $response->setResponseCode(400);
21 $response->setContentType("message/http");
22 $response->getBody()->append($request);
23 return $response->send();
24 }
25
26 foreach ((new Params($sig))->params as $algo => $mac) {
27 if ($mac["value"] !== hash_hmac($algo, $request->getBody(), $secret)) {
28 $response->setResponseCode(403);
29 $response->getBody()->append("Invalid signature");
30 return $response->send();
31 }
32 }
33
34 switch ($evt) {
35 default:
36 $response->setResponseCode(202);
37 $response->getBody()->append("Not a configured event");
38 break;
39 case "ping";
40 case "push":
41 if (!($json = json_decode($request->getBody()))) {
42 $response->setResponseCode(415);
43 $response->setContentType($request->getHeader("Content-Type"));
44 $response->getBody()->append($request->getBody());
45 } elseif (!isset($json->repository) && $evt === "ping") {
46 // ping on an org webhook
47 $response->setResponseCode(202);
48 $response->getBody()->append("PONG");
49 } elseif (!in_array(isset($json->repository->owner->name)?$json->repository->owner->name:$json->repository->owner->login, $owners, true)) {
50 $response->setResponseCode(403);
51 $response->getBody()->append("Invalid owner");
52 } else {
53 $repo = $json->repository->full_name;
54 $path = $mirror . "/" . $repo;
55 if (is_dir($path) && chdir($path)) {
56 passthru("git fetch -vp 2>&1", $rv);
57 if ($rv == 0) {
58 $response->setResponseCode(200);
59 }
60 } elseif (mkdir($path, 0755, true) && chdir($path)) {
61 $source = escapeshellarg($json->repository->clone_url);
62 $description = escapeshellarg($json->repository->description);
63 passthru("git clone --mirror $source . 2>&1", $rv);
64 passthru("git config gitweb.description $description 2>&1");
65 unlink("description");
66 if ($rv == 0) {
67 $response->setResponseCode(200);
68 }
69 }
70 }
71 break;
72 }
73
74 $response->send();