Skip to content

Commit

Permalink
Merge pull request #16 from sigee/master
Browse files Browse the repository at this point in the history
Cleanup and unhandled exception fix
  • Loading branch information
potato committed Sep 7, 2021
2 parents c8cdfcb + 470a758 commit 7c63574
Show file tree
Hide file tree
Showing 7 changed files with 67 additions and 56 deletions.
10 changes: 6 additions & 4 deletions src/Escher/AuthElements.php
Expand Up @@ -2,6 +2,8 @@

namespace Escher;

use DateTime;
use DateTimeZone;

class AuthElements
{
Expand All @@ -13,7 +15,7 @@ class AuthElements
private $host;
private $isFromHeaders;

public function __construct(array $elementParts, $accessKeyId, $shortDate, $credentialScope, \DateTime $dateTime, $host, $isFromHeaders)
public function __construct(array $elementParts, $accessKeyId, $shortDate, $credentialScope, DateTime $dateTime, $host, $isFromHeaders)
{
$this->elementParts = $elementParts;
$this->accessKeyId = $accessKeyId;
Expand Down Expand Up @@ -47,8 +49,8 @@ public static function parseFromHeaders(array $headerList, $authHeaderKey, $date
$dateTime = Utils::parseLongDate($headerList[strtolower($dateHeaderKey)]);
} else {
try {
$dateTime = new \DateTime($headerList[strtolower($dateHeaderKey)], new \DateTimeZone('GMT'));
} catch (Exception $ex) {
$dateTime = new DateTime($headerList[strtolower($dateHeaderKey)], new DateTimeZone('GMT'));
} catch (\Exception $ex) {
throw new Exception('Date header is invalid, the expected format is Wed, 04 Nov 2015 09:20:22 GMT', Exception::CODE_FORMAT_INVALID_DATE_HEADER_GMT);
}
}
Expand Down Expand Up @@ -176,7 +178,7 @@ public function validateSignature(RequestHelper $helper, Escher $escher, $keyDB,

$provided = $this->getSignature();
if ($calculated !== $provided) {
throw new Exception("The signatures do not match", Exception::CODE_SIGNATURE_NOT_MATCH);
throw new Exception('The signatures do not match', Exception::CODE_SIGNATURE_NOT_MATCH);
}
}

Expand Down
36 changes: 19 additions & 17 deletions src/Escher/Escher.php
Expand Up @@ -2,6 +2,8 @@

namespace Escher;

use DateTime;
use DateTimeZone;

class Escher
{
Expand All @@ -14,7 +16,7 @@ class Escher
const DEFAULT_EXPIRES = 86400;
const ISO8601 = 'Ymd\THis\Z';
const LONG_DATE = self::ISO8601;
const SHORT_DATE = "Ymd";
const SHORT_DATE = 'Ymd';
const UNSIGNED_PAYLOAD = 'UNSIGNED-PAYLOAD';

private $credentialScope;
Expand All @@ -36,11 +38,12 @@ public static function create($credentialScope)
}

/**
* @return \DateTime
* @return DateTime
* @throws \Exception
*/
private static function now()
{
return new \DateTime('now', new \DateTimeZone('GMT'));
return new DateTime('now', new DateTimeZone('GMT'));
}

/**
Expand Down Expand Up @@ -68,9 +71,9 @@ public function authenticate($keyDB, array $serverVars = null, $requestBody = nu
return $authElements->getAccessKeyId();
}

public function presignUrl($accessKeyId, $secretKey, $url, $expires = Escher::DEFAULT_EXPIRES, \DateTime $date = null)
public function presignUrl($accessKeyId, $secretKey, $url, $expires = Escher::DEFAULT_EXPIRES, DateTime $date = null)
{
$date = $date ? $date : self::now();
$date = $date ?: self::now();
$url = $this->appendSigningParams($accessKeyId, $url, $date, $expires);

list($host, $path, $query) = $this->parseUrl($url);
Expand All @@ -81,7 +84,7 @@ public function presignUrl($accessKeyId, $secretKey, $url, $expires = Escher::DE
'GET',
$path,
$query,
Escher::UNSIGNED_PAYLOAD,
self::UNSIGNED_PAYLOAD,
array('host' => $host),
(array('host'))
);
Expand All @@ -90,9 +93,9 @@ public function presignUrl($accessKeyId, $secretKey, $url, $expires = Escher::DE
return $url;
}

public function signRequest($accessKeyId, $secretKey, $method, $url, $requestBody, $headerList = array(), $headersToSign = array(), \DateTime $date = null)
public function signRequest($accessKeyId, $secretKey, $method, $url, $requestBody, $headerList = array(), $headersToSign = array(), DateTime $date = null)
{
$date = $date ? $date : self::now();
$date = $date ?: self::now();
list($host, $path, $query) = $this->parseUrl($url);
list($headerList, $headersToSign) = $this->addMandatoryHeaders(
$headerList, $headersToSign, $this->dateHeaderKey, $date, $host
Expand Down Expand Up @@ -133,7 +136,7 @@ private function generateParamName($param)
return 'X-' . $this->vendorKey . '-' . $param;
}

public function getSignature($secretKey, \DateTime $date, $method, $url, $requestBody, $headerList, $signedHeaders)
public function getSignature($secretKey, DateTime $date, $method, $url, $requestBody, $headerList, $signedHeaders)
{
list(, $path, $query) = $this->parseUrl($url);
return $this->calculateSignature($secretKey, $date, $method, $path, $query, $requestBody, $headerList, $signedHeaders);
Expand All @@ -149,9 +152,9 @@ private function parseUrl($url)
return array($host, $path, $query);
}

private function toLongDate(\DateTime $date)
private function toLongDate(DateTime $date)
{
return $date->format(Escher::LONG_DATE);
return $date->format(self::LONG_DATE);
}

private function addGetParameter($url, $key, $value)
Expand All @@ -165,18 +168,17 @@ private function addGetParameter($url, $key, $value)
if ($fragmentPosition === false) {
return $url . $glue . $key . '=' . urlencode($value);
}
else {
return substr_replace($url, ($glue . $key . '=' . urlencode($value)), $fragmentPosition, 0);
}

return substr_replace($url, ($glue . $key . '=' . urlencode($value)), $fragmentPosition, 0);
}

/**
* @param $date
* @return string
*/
private function fullCredentialScope(\DateTime $date)
private function fullCredentialScope(DateTime $date)
{
return $date->format(Escher::SHORT_DATE) . "/" . $this->credentialScope;
return $date->format(self::SHORT_DATE) . '/' . $this->credentialScope;
}

private function generateAuthHeader($secretKey, $accessKeyId, $authHeaderKey, $date, $method, $path, $query, $requestBody, array $headerList, array $headersToSign)
Expand All @@ -185,7 +187,7 @@ private function generateAuthHeader($secretKey, $accessKeyId, $authHeaderKey, $d
$authHeaderValue = Signer::createAuthHeader(
$signature,
$this->fullCredentialScope($date),
implode(";", $headersToSign),
implode(';', $headersToSign),
$this->hashAlgo,
$this->algoPrefix,
$accessKeyId
Expand Down
3 changes: 2 additions & 1 deletion src/Escher/Provider.php
Expand Up @@ -2,6 +2,7 @@

namespace Escher;

use ArrayAccess;

class Provider
{
Expand Down Expand Up @@ -49,7 +50,7 @@ public function getEscherSecret()
}

/**
* @return \ArrayAccess|array
* @return ArrayAccess|array
*/
public function getKeyDB()
{
Expand Down
28 changes: 15 additions & 13 deletions src/Escher/RequestCanonicalizer.php
Expand Up @@ -17,7 +17,7 @@ public static function canonicalize($method, $requestUri, $payload, $rawHeaders,
$lines = array_merge($lines, self::canonicalizeHeaders($rawHeaders, $headersToSign));

$lines[] = '';
$lines[] = implode(";", $headersToSign);
$lines[] = implode(';', $headersToSign);

$lines[] = hash($hashAlgo, $payload);

Expand All @@ -26,24 +26,26 @@ public static function canonicalize($method, $requestUri, $payload, $rawHeaders,

public static function urlEncodeQueryString($query)
{
if (empty($query)) return "";
$pairs = explode("&", $query);
if (empty($query)) {
return '';
}
$pairs = explode('&', $query);
$encodedParts = array();
foreach ($pairs as $pair) {
$keyValues = array_pad(explode("=", $pair), 2, '');
if (strpos($keyValues[0], " ") !== false) {
$keyValues[0] = substr($keyValues[0], 0, strpos($keyValues[0], " "));
$keyValues[1] = "";
$keyValues = array_pad(explode('=', $pair), 2, '');
if (strpos($keyValues[0], ' ') !== false) {
$keyValues[0] = substr($keyValues[0], 0, strpos($keyValues[0], ' '));
$keyValues[1] = '';
}
$keyValues[0] = urldecode($keyValues[0]);
$keyValues[1] = urldecode($keyValues[1]);
$encodedParts[] = implode("=", array(
$encodedParts[] = implode('=', array(
self::rawUrlEncode(str_replace('+', ' ', $keyValues[0])),
self::rawUrlEncode(str_replace('+', ' ', $keyValues[1])),
));
}
sort($encodedParts);
return implode("&", $encodedParts);
return implode('&', $encodedParts);
}

private static function normalizePath($path)
Expand All @@ -57,11 +59,11 @@ private static function normalizePath($path)
}

$path = implode('/', $path);
$path = str_replace('./', '', $path);

$path = str_replace("//", "/", $path);
$path = str_replace(array('./', '//'), array('', '/'), $path);

if (empty($path)) return "/";
if (empty($path)) {
return '/';
}
return $path;
}

Expand Down
18 changes: 9 additions & 9 deletions src/Escher/RequestHelper.php
Expand Up @@ -34,7 +34,8 @@ public function getAuthElements($vendorKey, $algoPrefix)
$queryParams = $this->getQueryParams();
if (isset($headerList[strtolower($this->authHeaderKey)])) {
return AuthElements::parseFromHeaders($headerList, $this->authHeaderKey, $this->dateHeaderKey, $algoPrefix);
} else if($this->getRequestMethod() === 'GET' && isset($queryParams[$this->paramKey($vendorKey, 'Signature')])) {
}
if($this->getRequestMethod() === 'GET' && isset($queryParams[$this->paramKey($vendorKey, 'Signature')])) {
return AuthElements::parseFromQuery($headerList, $queryParams, $vendorKey, $algoPrefix);
}
throw new Exception('Escher authentication is missing', Exception::CODE_MISSING_AUTH);
Expand Down Expand Up @@ -66,17 +67,16 @@ public function getHeaderList()

public function getCurrentUrl()
{
$scheme = (array_key_exists('HTTPS', $this->serverVars) && $this->serverVars["HTTPS"] == "on") ? 'https' : 'http';
$scheme = (array_key_exists('HTTPS', $this->serverVars) && $this->serverVars['HTTPS'] == 'on') ? 'https' : 'http';
$host = $this->getServerHost();
$res = "$scheme://$host" . $this->serverVars["REQUEST_URI"];
return $res;
return "$scheme://$host" . $this->serverVars['REQUEST_URI'];
}

private function process(array $serverVars)
{
$headerList = array();
foreach ($serverVars as $key => $value) {
if (substr($key, 0, 5) === 'HTTP_') {
if (strpos($key, 'HTTP_') === 0) {
$headerList[strtolower(str_replace('_', '-', substr($key, 5)))] = $value;
}
}
Expand All @@ -90,7 +90,7 @@ private function getContentType()

public function getServerHost()
{
return $this->normalizeHost($this->serverVars['SERVER_NAME'], $this->serverVars["SERVER_PORT"]);
return $this->normalizeHost($this->serverVars['SERVER_NAME'], $this->serverVars['SERVER_PORT']);
}

/**
Expand All @@ -114,14 +114,14 @@ private function normalizeHost($host, $port)
{
if (is_null($port) || $this->isDefaultPort($port)) {
return $host;
} else {
return $host . ":" . $port;
}

return $host . ':' . $port;
}

private function isDefaultPort($port)
{
$defaultPort = isset($this->serverVars["HTTPS"]) && $this->serverVars["HTTPS"] === "on" ? '443' : '80';
$defaultPort = isset($this->serverVars['HTTPS']) && $this->serverVars['HTTPS'] === 'on' ? '443' : '80';
return $port == $defaultPort;
}
}
22 changes: 12 additions & 10 deletions src/Escher/Signer.php
Expand Up @@ -2,17 +2,19 @@

namespace Escher;

use DateTime;
use DateTimeZone;

class Signer
{
public static function createStringToSign($credentialScope, $canonicalRequestString, \DateTime $date, $hashAlgo, $algoPrefix)
public static function createStringToSign($credentialScope, $canonicalRequestString, DateTime $date, $hashAlgo, $algoPrefix)
{
$date = clone $date;
$date->setTimezone(new \DateTimeZone("GMT"));
$date->setTimezone(new DateTimeZone('GMT'));
$formattedDate = $date->format(Escher::LONG_DATE);
$scope = substr($formattedDate,0, 8) . "/" . $credentialScope;
$scope = substr($formattedDate,0, 8) . '/' . $credentialScope;
$lines = array();
$lines[] = $algoPrefix . "-HMAC-" . strtoupper($hashAlgo);
$lines[] = $algoPrefix . '-HMAC-' . strtoupper($hashAlgo);
$lines[] = $formattedDate;
$lines[] = $scope;
$lines[] = hash($hashAlgo, $canonicalRequestString);
Expand All @@ -22,7 +24,7 @@ public static function createStringToSign($credentialScope, $canonicalRequestStr
public static function calculateSigningKey($secret, $credentialScope, $hashAlgo, $algoPrefix)
{
$key = $algoPrefix . $secret;
$credentials = explode("/", $credentialScope);
$credentials = explode('/', $credentialScope);
foreach ($credentials as $data) {
$key = hash_hmac($hashAlgo, $data, $key, true);
}
Expand All @@ -31,12 +33,12 @@ public static function calculateSigningKey($secret, $credentialScope, $hashAlgo,

public static function createAuthHeader($signature, $credentialScope, $signedHeaders, $hashAlgo, $algoPrefix, $accessKey)
{
return $algoPrefix . "-HMAC-" . strtoupper($hashAlgo)
. " Credential="
. $accessKey . "/"
return $algoPrefix . '-HMAC-' . strtoupper($hashAlgo)
. ' Credential='
. $accessKey . '/'
. $credentialScope
. ", SignedHeaders=" . $signedHeaders
. ", Signature=" . $signature;
. ', SignedHeaders=' . $signedHeaders
. ', Signature=' . $signature;
}

public static function createSignature($stringToSign, $signerKey, $hashAlgo)
Expand Down
6 changes: 4 additions & 2 deletions src/Escher/Utils.php
Expand Up @@ -2,6 +2,8 @@

namespace Escher;

use DateTime;
use DateTimeZone;

class Utils
{
Expand All @@ -11,9 +13,9 @@ public static function parseLongDate($dateString)
throw new Exception('Date header is invalid, the expected format is 20151104T092022Z', Exception::CODE_FORMAT_INVALID_DATE_HEADER);
}
if (!self::advancedDateTimeFunctionsAvailable()) {
return new \DateTime($dateString, new \DateTimeZone('GMT'));
return new DateTime($dateString, new DateTimeZone('GMT'));
}
return \DateTime::createFromFormat('Ymd\THisT', $dateString, new \DateTimeZone('GMT'));
return DateTime::createFromFormat('Ymd\THisT', $dateString, new DateTimeZone('GMT'));
}

public static function keysToLower($array)
Expand Down

0 comments on commit 7c63574

Please sign in to comment.