diff --git a/cdn/README.md b/cdn/README.md new file mode 100644 index 0000000000..a747807efe --- /dev/null +++ b/cdn/README.md @@ -0,0 +1,15 @@ +# Google Cloud CDN Sign URL + +PHP implementation of [`gcloud compute sign-url`](https://cloud.google.com/sdk/gcloud/reference/compute/sign-url) based on [Google Cloud CDN Documentation](https://cloud.google.com/cdn/docs/using-signed-urls#signing_urls). +The provided file includes implementation of base64url encode and decode functions based on [RFC4648 Section 5](https://tools.ietf.org/html/rfc4648#section-5). + +## Usage + +``` + +``` diff --git a/cdn/phpunit.xml.dist b/cdn/phpunit.xml.dist new file mode 100644 index 0000000000..8227a75be8 --- /dev/null +++ b/cdn/phpunit.xml.dist @@ -0,0 +1,31 @@ + + + + + + test + + + + + + + + signUrl.php + + + diff --git a/cdn/signUrl.php b/cdn/signUrl.php new file mode 100644 index 0000000000..b7b6753b71 --- /dev/null +++ b/cdn/signUrl.php @@ -0,0 +1,84 @@ + + * + * @param string $url URL of the endpoint served by Cloud CDN + * @param string $keyName Name of the signing key added to the Google Cloud Storage bucket or service + * @param string $base64UrlKey Signing key as base64url (RFC4648 Section 5) encoded string + * @param int $expirationTime Expiration time as a UNIX timestamp (GMT, e.g. time()) + * + * @return string + */ +function sign_url(https://github.com/$url,%20$keyName,%20$base64UrlKey,%20$expirationTime) +{ + // Decode the key + $decodedKey = base64url_decode($base64UrlKey, true); + + // Determine which separator makes sense given a URL + $separator = (strpos($url, '?') === false) ? '?' : '&'; + + // Concatenate url with expected query parameters Expires and KeyName + $url = "{$url}{$separator}Expires={$expirationTime}&KeyName={$keyName}"; + + // Sign the url using the key and encode the signature using base64url + $signature = hash_hmac('sha1', $url, $decodedKey, true); + $encodedSignature = base64url_encode($signature); + + // Concatenate the URL and encoded signature + return "{$url}&Signature={$encodedSignature}"; +} +// [END signed_url] diff --git a/cdn/test/signUrlTest.php b/cdn/test/signUrlTest.php new file mode 100644 index 0000000000..e8c0abb04f --- /dev/null +++ b/cdn/test/signUrlTest.php @@ -0,0 +1,62 @@ +assertEquals(base64url_encode(hex2bin("9d9b51a2174d17d9b770a336e0870ae3")), "nZtRohdNF9m3cKM24IcK4w=="); + } + + public function testBase64UrlEncodeWithoutPadding() + { + $this->assertEquals(base64url_encode(hex2bin("9d9b51a2174d17d9b770a336e0870ae3"), false), "nZtRohdNF9m3cKM24IcK4w"); + } + + public function testBase64UrlDecode() + { + $this->assertEquals(hex2bin("9d9b51a2174d17d9b770a336e0870ae3"), base64url_decode("nZtRohdNF9m3cKM24IcK4w==")); + } + + public function testBase64UrlDecodeWithoutPadding() + { + $this->assertEquals(hex2bin("9d9b51a2174d17d9b770a336e0870ae3"), base64url_decode("nZtRohdNF9m3cKM24IcK4w")); + } + + public function testSignUrl() + { + $encoded_key="nZtRohdNF9m3cKM24IcK4w=="; // base64url encoded key + + $cases = array( + array("http://35.186.234.33/index.html", "my-key", 1558131350, + "http://35.186.234.33/index.html?Expires=1558131350&KeyName=my-key&Signature=fm6JZSmKNsB5sys8VGr-JE4LiiE="), + array("https://www.google.com/", "my-key", 1549751401, + "https://www.google.com/?Expires=1549751401&KeyName=my-key&Signature=M_QO7BGHi2sGqrJO-MDr0uhDFuc="), + array("https://www.example.com/some/path?some=query&another=param", "my-key", 1549751461, + "https://www.example.com/some/path?some=query&another=param&Expires=1549751461&KeyName=my-key&Signature=sTqqGX5hUJmlRJ84koAIhWW_c3M="), + ); + + foreach($cases as $c) + { + $this->assertEquals(sign_url(https://github.com/$c[0],%20$c[1],%20$encoded_key,%20$c[2]), $c[3]); + } + } +}