Page MenuHomeDevCentral

No OneTemporary

diff --git a/github/.gitignore b/github/.gitignore
new file mode 100644
index 0000000..3a9875b
--- /dev/null
+++ b/github/.gitignore
@@ -0,0 +1,2 @@
+/vendor/
+composer.lock
diff --git a/github/XHubSignature.php b/github/XHubSignature.php
new file mode 100644
index 0000000..ad2e645
--- /dev/null
+++ b/github/XHubSignature.php
@@ -0,0 +1,151 @@
+<?php
+
+namespace Keruald\GitHub;
+
+class XHubSignature {
+
+ ///
+ /// Properties
+ ///
+
+ /**
+ * The secret token to secure messages
+ *
+ * @var string
+ */
+ private $secret;
+
+ /**
+ * The hash algorithm
+ *
+ * @var string
+ */
+ private $hashAlgo;
+
+ /**
+ * The payload
+ *
+ * @var string
+ */
+ public $payload;
+
+ /**
+ * The signature delivered with the payload, to validate it
+ *
+ * @var string
+ */
+ public $signature;
+
+ ///
+ /// Constants
+ ///
+
+ /**
+ * The default hash algorithm to use if none is offered
+ */
+ const DEFAULT_HASH_ALGO = 'sha1';
+
+ ///
+ /// Constructor
+ ///
+
+ /**
+ * Initializes a new instance of the XHubSignature class
+ *
+ * @param string $secret the secret token
+ * @param string $algo the algorithm to use to compute hashs [facultative]
+ */
+ public function __construct ($secret, $algo = self::DEFAULT_HASH_ALGO) {
+ $this->secret = $secret;
+ $this->hashAlgo = $algo;
+ }
+
+ ///
+ /// Signature methods
+ ///
+
+ /**
+ * Computes the signature for the current payload
+ *
+ * @return string the payload signature
+ */
+ public function compute () {
+ return hash_hmac($this->hashAlgo, $this->payload, $this->secret);
+ }
+
+ /**
+ * Validates the signature
+ *
+ * @return bool true if the signature is correct; otherwise, false.
+ */
+ public function validate () {
+ // Comparison with hash_equals allows to mitigate timing attacks.
+ return hash_equals($this->compute(), $this->signature);
+ }
+
+ ///
+ /// Static helper methods
+ ///
+
+ /**
+ * Computes a signature for the specified secret and payload
+ *
+ * @param string $secret the secret token to secure messages
+ * @param string $payload the payload
+ * @param string $algo the hash algorithm [facultative]
+ *
+ * @return string the payload signature
+ */
+ public static function hashPayload(
+ $secret,
+ $payload,
+ $algo = self::DEFAULT_HASH_ALGO
+ ) {
+ $instance = new static($secret, $algo);
+ $instance->payload = $payload;
+
+ return $instance->compute();
+ }
+
+ /**
+ * Validates a payload against specified secret
+ *
+ * @param string $secret the secret token to secure messages
+ * @param string $payload the payload
+ * @param string $signature the signature delivered with the payload
+ * @param string $algo the hash algorithm [facultative]
+ *
+ * @return bool true if the signature is correct; otherwise, false.
+ */
+ public static function validatePayload (
+ $secret,
+ $payload,
+ $signature,
+ $algo = self::DEFAULT_HASH_ALGO
+ ) {
+ $instance = new static($secret, $algo);
+ $instance->payload = $payload;
+ $instance->signature = $signature;
+
+ return $instance->validate();
+ }
+
+ /**
+ * Parses a X-Hub-Signature field from headers and gets the signature part
+ *
+ * @param string $header the header value
+ * @return string the signature
+ */
+ public static function parseSignature ($header) {
+ if ($header === null) {
+ return "";
+ }
+
+ if (strpos($header, '=') === false) {
+ return $header;
+ }
+
+ $data = explode('=', $header, 2);
+ return $data[1];
+ }
+}
diff --git a/github/composer.json b/github/composer.json
new file mode 100644
index 0000000..ed256f9
--- /dev/null
+++ b/github/composer.json
@@ -0,0 +1,39 @@
+{
+ "name": "keruald/github",
+ "description": "X-Hub-Signature generator and validator",
+ "license": "BSD-2-Clause",
+ "repositories": [
+ {
+ "type": "vcs",
+ "url": "https://github.com/keruald/github"
+ }
+ ],
+ "authors": [
+ {
+ "name": "Sébastien Santoro",
+ "email": "dereckson@espace-win.org"
+ }
+ ],
+ "keywords": [
+ "keruald",
+ "GitHub"
+ ],
+ "support": {
+ "irc": "irc://irc.freenode.net/wolfplex",
+ "issues": "http://devcentral.nasqueron.org"
+ },
+ "require": {
+ "php": ">=5.6.0"
+ },
+ "require-dev": {
+ "phpunit/phpunit": "5.0.*"
+ },
+ "autoload": {
+ "psr-4": {
+ "Keruald\\GitHub\\": ""
+ }
+ },
+ "scripts": {
+ "test": "phpunit tests"
+ }
+}
diff --git a/github/tests/XHubSignatureConstants.php b/github/tests/XHubSignatureConstants.php
new file mode 100644
index 0000000..e7da00d
--- /dev/null
+++ b/github/tests/XHubSignatureConstants.php
@@ -0,0 +1,13 @@
+<?php
+
+define('SECRET', 'secret123');
+
+define('TIGER_ALGO', 'tiger192,4');
+define('TIGER_PAYLOAD', 'lorem ipsum dolor');
+define('TIGER_SIGNATURE', '7081ac97e50ad97e13b2fb9364b9df376c26b920080245ce');
+
+// Current default algo is sha-1.
+define('DEFAULT_PAYLOAD', file_get_contents(__DIR__ . '/payload.json'));
+define('DEFAULT_SIGNATURE', 'ab05a3aef13696b60a60a8064b9fda31a8c77582');
+
+define('EMPTY_DEFAULT_HASH_ALGO_SIGNATURE', 'fbdb1d1b18aa6c08324b7d64b71fb76370690e1d');
diff --git a/github/tests/XHubSignatureTest.php b/github/tests/XHubSignatureTest.php
new file mode 100644
index 0000000..e2add85
--- /dev/null
+++ b/github/tests/XHubSignatureTest.php
@@ -0,0 +1,84 @@
+<?php
+
+use Keruald\GitHub\XHubSignature;
+
+require 'XHubSignatureConstants.php';
+
+class XHubSignatureTest extends PHPUnit_Framework_TestCase {
+ protected $defaultInstance;
+ protected $tigerInstance;
+
+ protected function setUp() {
+ $this->defaultInstance = new XHubSignature(SECRET);
+ $this->tigerInstance = new XHubSignature(SECRET, TIGER_ALGO);
+
+ $this->defaultInstance->payload = DEFAULT_PAYLOAD;
+ $this->tigerInstance->payload = TIGER_PAYLOAD;
+ }
+
+ public function testValidate () {
+ $this->defaultInstance->signature = "";
+ $this->assertFalse($this->defaultInstance->validate());
+
+ $this->defaultInstance->signature = "bad signature";
+ $this->assertFalse($this->defaultInstance->validate());
+
+ $this->defaultInstance->signature = DEFAULT_SIGNATURE;
+ $this->assertTrue($this->defaultInstance->validate());
+ }
+
+ public function testCompute () {
+ $this->assertSame(
+ DEFAULT_SIGNATURE,
+ $this->defaultInstance->compute()
+ );
+
+ $this->assertSame(
+ TIGER_SIGNATURE,
+ $this->tigerInstance->compute()
+ );
+ }
+
+ ///
+ /// Test static helper methods
+ ///
+
+ /**
+ * @covers XHubSignature::validatePayload
+ */
+ public function testhashPayload () {
+ $this->assertSame(
+ EMPTY_DEFAULT_HASH_ALGO_SIGNATURE,
+ XHubSignature::hashPayload("", "")
+ );
+ $this->assertSame(
+ TIGER_SIGNATURE,
+ XHubSignature::hashPayload(SECRET, TIGER_PAYLOAD, TIGER_ALGO)
+ );
+ }
+
+ /**
+ * @covers XHubSignature::validatePayload
+ */
+ public function testValidatePayload () {
+ $this->assertFalse(XHubSignature::validatePayload("", "", ""));
+
+ $this->assertTrue(XHubSignature::validatePayload(
+ SECRET,
+ TIGER_PAYLOAD,
+ TIGER_SIGNATURE,
+ TIGER_ALGO
+ ));
+ }
+
+ public function testParseSignature () {
+ $this->assertSame(
+ TIGER_SIGNATURE,
+ XHubSignature::parseSignature(TIGER_SIGNATURE)
+ );
+ $this->assertSame(
+ TIGER_SIGNATURE,
+ XHubSignature::parseSignature(TIGER_ALGO . '=' . TIGER_SIGNATURE)
+ );
+ }
+}
diff --git a/github/tests/payload.json b/github/tests/payload.json
new file mode 100644
index 0000000..0849621
--- /dev/null
+++ b/github/tests/payload.json
@@ -0,0 +1 @@
+{"zen":"Practicality beats purity.","hook_id":6474950,"hook":{"url":"https://api.github.com/orgs/nasqueron/hooks/6474950","ping_url":"https://api.github.com/orgs/nasqueron/hooks/6474950/pings","id":6474950,"name":"web","active":true,"events":["*"],"config":{"url":"https://notifications-dereckson.c9users.io/gate/GitHub","content_type":"json","insecure_ssl":"0","secret":"********"},"updated_at":"2015-11-22T06:25:12Z","created_at":"2015-11-22T06:25:12Z"},"organization":{"login":"nasqueron","id":5605546,"url":"https://api.github.com/orgs/nasqueron","repos_url":"https://api.github.com/orgs/nasqueron/repos","events_url":"https://api.github.com/orgs/nasqueron/events","members_url":"https://api.github.com/orgs/nasqueron/members{/member}","public_members_url":"https://api.github.com/orgs/nasqueron/public_members{/member}","avatar_url":"https://avatars.githubusercontent.com/u/5605546?v=3","description":"Central hub of a budding community of creative people, writers, developers and thinkers."},"sender":{"login":"dereckson","id":135563,"avatar_url":"https://avatars.githubusercontent.com/u/135563?v=3","gravatar_id":"","url":"https://api.github.com/users/dereckson","html_url":"https://github.com/dereckson","followers_url":"https://api.github.com/users/dereckson/followers","following_url":"https://api.github.com/users/dereckson/following{/other_user}","gists_url":"https://api.github.com/users/dereckson/gists{/gist_id}","starred_url":"https://api.github.com/users/dereckson/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/dereckson/subscriptions","organizations_url":"https://api.github.com/users/dereckson/orgs","repos_url":"https://api.github.com/users/dereckson/repos","events_url":"https://api.github.com/users/dereckson/events{/privacy}","received_events_url":"https://api.github.com/users/dereckson/received_events","type":"User","site_admin":false}}
\ No newline at end of file

File Metadata

Mime Type
text/x-diff
Expires
Mon, Nov 25, 10:26 (1 d, 17 h)
Storage Engine
blob
Storage Format
Raw Data
Storage Handle
2258344
Default Alt Text
(9 KB)

Event Timeline