Skip to content

Commit e69b3a0

Browse files
committed
Use ssh auth + replace allowed-ips by X-Hub-Signature github header
1 parent 641c698 commit e69b3a0

File tree

6 files changed

+80
-79
lines changed

6 files changed

+80
-79
lines changed

README.md

+25-35
Original file line numberDiff line numberDiff line change
@@ -10,8 +10,8 @@ The WebHook works in two parts, a web listener and a worker. The web listener
1010
adds requests to Redis and the worker processes the requests.
1111

1212
The worker will interact with the system's git as the user running the worker.
13-
This means that the user running the worker should have its key added to
14-
the appropriate GitHub accounts.
13+
**This means that the user running the worker should have its key added to
14+
the appropriate GitHub accounts.**
1515

1616
During testing it would make sense to run the worker manually. For production
1717
deployments it would probably make more sense to runt he worker using something
@@ -27,19 +27,21 @@ Ensure that [git-subsplit][2] is installed correctly. If is not available
2727
in your version of git (likely true for versions older than 1.7.11)
2828
please install it manually from [here][5].
2929

30+
You should initialize subsplit with a git repository:
3031

31-
### Installation
32-
33-
#### If You Already Have Composer
32+
cd /home/myuser
33+
git subsplit init [email protected]:orga/repo.git
3434

35-
composer create-project dflydev/git-subsplit-github-webhook:1.0.x-dev -n webhook
36-
cd webhook
35+
It will create a `.subsplit` working directory that you will use later.
3736

38-
#### If You Need Composer
37+
### Installation
3938

40-
curl -s https://getcomposer.org/installer | php
41-
php composer.phar create-project dflydev/git-subsplit-github-webhook:1.0.x-dev -n webhook
39+
git clone [email protected]:dflydev/dflydev-git-subsplit-github-webhook.git
40+
mv dflydev-git-subsplit-github-webhook/ webhook/
4241
cd webhook
42+
composer install
43+
44+
N.B. If you need composer : [https://getcomposer.org/download/][8]
4345

4446
### Redis
4547

@@ -49,6 +51,7 @@ Ensure that the Redis server is running.
4951

5052
Copy `config.json.dist` to `config.json` and edit it accordingly. Please make sure
5153
to pay special attention to setting `working-directory` correctly.
54+
Don't forget to change the `webhook-secret` to secure your webhook.
5255

5356
### Web Server
5457

@@ -63,7 +66,7 @@ Start the worker by running `php bin/subsplit-worker.php`.
6366
### GitHub
6467

6568
From your repository go to **Settings** / **Service Hooks** / **WebHook URLs**.
66-
Enter the URL to your WebHook and click **Update Settings**.
69+
Enter the URL to your WebHook and your secret. Then click **Update Settings**.
6770

6871
Click **WebHook URLs** again and click **Test Hook**.
6972

@@ -77,26 +80,13 @@ Configuration
7780

7881
```
7982
{
80-
"working-directory": "/home/myuser/.git-subsplit-working",
81-
"allowed-ips": ["127.0.0.1"],
83+
"working-directory": "/home/myuser/.subsplit",
84+
"webhook-secret": "ThisTokenIsNotSoSecretChangeIt",
8285
"projects": {
83-
"sculpin": {
84-
"url": "https://github.com/sculpin/sculpin",
85-
"repository-url": "[email protected]:sculpin/sculpin.git",
86-
"splits": [
87-
"src/Sculpin/Core:[email protected]:sculpin/core.git"
88-
]
89-
},
90-
"react": {
91-
"url": "https://github.com/reactphp/react",
86+
"project-1": {
87+
"url": "[email protected]:orga/private-repo.git",
9288
"splits": [
93-
"src/React/EventLoop:[email protected]:reactphp/event-loop.git",
94-
"src/React/Stream:[email protected]:reactphp/stream.git",
95-
"src/React/Cache:[email protected]:reactphp/cache.git",
96-
"src/React/Socket:[email protected]:reactphp/socket.git",
97-
"src/React/Http:[email protected]:reactphp/http.git",
98-
"src/React/HttpClient:[email protected]:reactphp/http-client.git",
99-
"src/React/Dns:[email protected]:reactphp/dns.git"
89+
"src/public:[email protected]:orga/public-repo.git"
10090
]
10191
}
10292
}
@@ -112,12 +102,12 @@ Configuration
112102
The directory in which the subsplits will be processed. This is more or less
113103
a temporary directory in which all projects will have their subsplit initialized.
114104

115-
#### allowed-ips
105+
#### webhook-secret
116106

117-
*Array. Default: ['207.97.227.253', '50.57.128.197', '108.171.174.178']*
107+
*String. Default: "ThisTokenIsNotSoSecretChangeIt". **Required.***
118108

119-
The IP addresses that are allowed to call the WebHook. The default values are
120-
GitHub's IP addresses published here.
109+
This is a secret string that should be unique to your webhook. It's used to secure communication between the webhook and github.
110+
You can use a *secret generator* if you want a strong string.
121111

122112
#### projects
123113

@@ -135,9 +125,8 @@ Each project description object can have the following properties:
135125
`url` property against each project's listed `url` property to determine
136126
which project the request is for.
137127

138-
This URL will look like: **https://github.com/sculpin/sculpin**
128+
This URL should be like: **git@github.com:orga/repo.git**
139129

140-
Note: The URL is secure (http**s**) and does not contain `.git` extension.
141130
* **repository-url**:
142131
The URL that `git` will use to check out the project. This setting is
143132
optional. If it is not defined the repository URL will be read from the
@@ -174,3 +163,4 @@ Thanks Igor. :)
174163
[5]: https://github.com/apenwarr/git-subtree
175164
[6]: http://upstart.ubuntu.com
176165
[7]: http://supervisord.org
166+
[8]: https://getcomposer.org/download/

bin/subsplit-worker.php

+3-3
Original file line numberDiff line numberDiff line change
@@ -21,15 +21,15 @@
2121
);
2222

2323
foreach ($config['projects'] as $testName => $testProject) {
24-
if ($testProject['url'] === $data['repository']['url']) {
24+
if ($testProject['url'] === $data['repository']['ssh_url']) {
2525
$name = $testName;
2626
$project = $testProject;
2727
break;
2828
}
2929
}
3030

3131
if (null === $name) {
32-
print(sprintf('Skipping request for URL %s (not configured)', $data['repository']['url'])."\n");
32+
print(sprintf('Skipping request for URL %s (not configured)', $data['repository']['ssh_url'])."\n");
3333

3434
$redis->lrem('dflydev-git-subsplit:processing', 1, $body);
3535
$redis->lpush('dflydev-git-subspilt:failures', json_encode($data));
@@ -54,7 +54,7 @@
5454
$publishCommand[] = escapeshellarg('--no-tags');
5555
$publishCommand[] = escapeshellarg(sprintf('--heads=%s', $matches[1]));
5656
} else {
57-
print sprintf('Skipping request for URL %s (unexpected reference detected: %s)', $data['repository']['url'], $ref)."\n";
57+
print sprintf('Skipping request for URL %s (unexpected reference detected: %s)', $data['repository']['ssh_url'], $ref)."\n";
5858

5959
$redis->lrem('dflydev-git-subsplit:processing', 1, $body);
6060
$redis->lpush('dflydev-git-subspilt:failures', json_encode($data));

composer.lock

+29-20
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

config.json.dist

+5-16
Original file line numberDiff line numberDiff line change
@@ -1,22 +1,11 @@
11
{
2-
"working-directory": "/tmp/dflydev-git-subsplit-github-webhook-working",
2+
"working-directory": "/home/myuser/.subsplit",
3+
"webhook-secret": "ThisTokenIsNotSoSecretChangeIt",
34
"projects": {
4-
"sculpin": {
5-
"url": "https://github.com/sculpin/sculpin",
5+
"project-1": {
6+
"url": "git@github.com:orga/private-repo.git",
67
"splits": [
7-
"src/Sculpin/Core:[email protected]:sculpin/core.git"
8-
]
9-
},
10-
"react": {
11-
"url": "https://github.com/reactphp/react",
12-
"splits": [
13-
"src/React/EventLoop:[email protected]:reactphp/event-loop.git",
14-
"src/React/Stream:[email protected]:reactphp/stream.git",
15-
"src/React/Cache:[email protected]:reactphp/cache.git",
16-
"src/React/Socket:[email protected]:reactphp/socket.git",
17-
"src/React/Http:[email protected]:reactphp/http.git",
18-
"src/React/HttpClient:[email protected]:reactphp/http-client.git",
19-
"src/React/Dns:[email protected]:reactphp/dns.git"
8+
"src/public:[email protected]:orga/public-repo.git"
209
]
2110
}
2211
}

web/index.html

100644100755
File mode changed.

web/subsplit-webhook.php

100644100755
+18-5
Original file line numberDiff line numberDiff line change
@@ -8,13 +8,26 @@
88

99
$config = json_decode(file_get_contents($configFilename), true);
1010

11-
$allowedIps = isset($config['allowed-ips'])
12-
? $config['allowed-ips']
13-
: array('207.97.227.253', '50.57.128.197', '108.171.174.178');
11+
if (!array_key_exists('webhook-secret', $config)) {
12+
header('HTTP/1.1 403 Forbidden');
13+
echo '"webhook-secret" key is missing in your configuration.';
14+
exit;
15+
}
16+
17+
if (!isset($_SERVER['HTTP_X_HUB_SIGNATURE'])) {
18+
header('HTTP/1.1 403 Forbidden');
19+
echo 'HTTP header "X-Hub-Signature" is missing. Please provide a secret token to secure your webhook.';
20+
exit;
21+
}
22+
23+
list($algo, $hash) = explode('=', $_SERVER['HTTP_X_HUB_SIGNATURE']);
24+
25+
$rawPost = file_get_contents('php://input');
26+
$signature = trim(hash_hmac($algo, $rawPost, $config['webhook-secret']));
1427

15-
if (!in_array($_SERVER['REMOTE_ADDR'], $allowedIps)) {
28+
if (!hash_equals($signature, $hash)) {
1629
header('HTTP/1.1 403 Forbidden');
17-
echo sprintf("Host %s is not allowed to connect.\n", $_SERVER['REMOTE_ADDR']);
30+
echo 'Hook secret does not match.';
1831
exit;
1932
}
2033

0 commit comments

Comments
 (0)