mirror of
https://github.com/SociallyDev/Spaces-API.git
synced 2025-08-14 02:27:23 -07:00
v2: Updates
* Simplifies & beautifies everything * Introduces a new Class system. * Errors are defaulted to AWS's handler. * New function names & more efficient handling. * Should fix a majority of the errors. Please read the README for more!
This commit is contained in:
parent
ad0726e41e
commit
e6d7753dc8
1095 changed files with 45088 additions and 2911 deletions
|
@ -19,7 +19,8 @@ class AnonymousSignature implements SignatureInterface
|
|||
public function presign(
|
||||
RequestInterface $request,
|
||||
CredentialsInterface $credentials,
|
||||
$expires
|
||||
$expires,
|
||||
array $options = []
|
||||
) {
|
||||
return $request;
|
||||
}
|
||||
|
|
|
@ -59,6 +59,10 @@ class S3SignatureV4 extends SignatureV4
|
|||
*/
|
||||
protected function createCanonicalizedPath($path)
|
||||
{
|
||||
return '/' . ltrim($path, '/');
|
||||
// Only remove one slash in case of keys that have a preceding slash
|
||||
if (substr($path, 0, 1) === '/') {
|
||||
$path = substr($path, 1);
|
||||
}
|
||||
return '/' . $path;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -39,6 +39,7 @@ interface SignatureInterface
|
|||
public function presign(
|
||||
RequestInterface $request,
|
||||
CredentialsInterface $credentials,
|
||||
$expires
|
||||
$expires,
|
||||
array $options = []
|
||||
);
|
||||
}
|
||||
|
|
|
@ -40,6 +40,11 @@ use Aws\Exception\UnresolvedSignatureException;
|
|||
*/
|
||||
class SignatureProvider
|
||||
{
|
||||
private static $s3v4SignedServices = [
|
||||
's3' => true,
|
||||
's3control' => true,
|
||||
];
|
||||
|
||||
/**
|
||||
* Resolves and signature provider and ensures a non-null return value.
|
||||
*
|
||||
|
@ -111,7 +116,7 @@ class SignatureProvider
|
|||
switch ($version) {
|
||||
case 's3v4':
|
||||
case 'v4':
|
||||
return $service === 's3'
|
||||
return !empty(self::$s3v4SignedServices[$service])
|
||||
? new S3SignatureV4($service, $region)
|
||||
: new SignatureV4($service, $region);
|
||||
case 'v4-unsigned-body':
|
||||
|
|
|
@ -15,6 +15,7 @@ class SignatureV4 implements SignatureInterface
|
|||
use SignatureTrait;
|
||||
const ISO8601_BASIC = 'Ymd\THis\Z';
|
||||
const UNSIGNED_PAYLOAD = 'UNSIGNED-PAYLOAD';
|
||||
const AMZ_CONTENT_SHA256_HEADER = 'X-Amz-Content-Sha256';
|
||||
|
||||
/** @var string */
|
||||
private $service;
|
||||
|
@ -25,6 +26,41 @@ class SignatureV4 implements SignatureInterface
|
|||
/** @var bool */
|
||||
private $unsigned;
|
||||
|
||||
/**
|
||||
* The following headers are not signed because signing these headers
|
||||
* would potentially cause a signature mismatch when sending a request
|
||||
* through a proxy or if modified at the HTTP client level.
|
||||
*
|
||||
* @return array
|
||||
*/
|
||||
private function getHeaderBlacklist()
|
||||
{
|
||||
return [
|
||||
'cache-control' => true,
|
||||
'content-type' => true,
|
||||
'content-length' => true,
|
||||
'expect' => true,
|
||||
'max-forwards' => true,
|
||||
'pragma' => true,
|
||||
'range' => true,
|
||||
'te' => true,
|
||||
'if-match' => true,
|
||||
'if-none-match' => true,
|
||||
'if-modified-since' => true,
|
||||
'if-unmodified-since' => true,
|
||||
'if-range' => true,
|
||||
'accept' => true,
|
||||
'authorization' => true,
|
||||
'proxy-authorization' => true,
|
||||
'from' => true,
|
||||
'referer' => true,
|
||||
'user-agent' => true,
|
||||
'x-amzn-trace-id' => true,
|
||||
'aws-sdk-invocation-id' => true,
|
||||
'aws-sdk-retry' => true,
|
||||
];
|
||||
}
|
||||
|
||||
/**
|
||||
* @param string $service Service name to use when signing
|
||||
* @param string $region Region name to use when signing
|
||||
|
@ -55,7 +91,7 @@ class SignatureV4 implements SignatureInterface
|
|||
$payload = $this->getPayload($request);
|
||||
|
||||
if ($payload == self::UNSIGNED_PAYLOAD) {
|
||||
$parsed['headers']['X-Amz-Content-Sha256'] = [$payload];
|
||||
$parsed['headers'][self::AMZ_CONTENT_SHA256_HEADER] = [$payload];
|
||||
}
|
||||
|
||||
$context = $this->createContext($parsed, $payload);
|
||||
|
@ -76,6 +112,28 @@ class SignatureV4 implements SignatureInterface
|
|||
return $this->buildRequest($parsed);
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the headers that were used to pre-sign the request.
|
||||
* Used for the X-Amz-SignedHeaders header.
|
||||
*
|
||||
* @param array $headers
|
||||
* @return array
|
||||
*/
|
||||
private function getPresignHeaders(array $headers)
|
||||
{
|
||||
$presignHeaders = [];
|
||||
$blacklist = $this->getHeaderBlacklist();
|
||||
foreach ($headers as $name => $value) {
|
||||
$lName = strtolower($name);
|
||||
if (!isset($blacklist[$lName])
|
||||
&& $name !== self::AMZ_CONTENT_SHA256_HEADER
|
||||
) {
|
||||
$presignHeaders[] = $lName;
|
||||
}
|
||||
}
|
||||
return $presignHeaders;
|
||||
}
|
||||
|
||||
public function presign(
|
||||
RequestInterface $request,
|
||||
CredentialsInterface $credentials,
|
||||
|
@ -86,7 +144,7 @@ class SignatureV4 implements SignatureInterface
|
|||
$startTimestamp = isset($options['start_time'])
|
||||
? $this->convertToTimestamp($options['start_time'], null)
|
||||
: time();
|
||||
|
||||
|
||||
$expiresTimestamp = $this->convertToTimestamp($expires, $startTimestamp);
|
||||
|
||||
$parsed = $this->createPresignedRequest($request, $credentials);
|
||||
|
@ -95,10 +153,13 @@ class SignatureV4 implements SignatureInterface
|
|||
$shortDate = substr($httpDate, 0, 8);
|
||||
$scope = $this->createScope($shortDate, $this->region, $this->service);
|
||||
$credential = $credentials->getAccessKeyId() . '/' . $scope;
|
||||
if ($credentials->getSecurityToken()) {
|
||||
unset($parsed['headers']['X-Amz-Security-Token']);
|
||||
}
|
||||
$parsed['query']['X-Amz-Algorithm'] = 'AWS4-HMAC-SHA256';
|
||||
$parsed['query']['X-Amz-Credential'] = $credential;
|
||||
$parsed['query']['X-Amz-Date'] = gmdate('Ymd\THis\Z', $startTimestamp);
|
||||
$parsed['query']['X-Amz-SignedHeaders'] = 'host';
|
||||
$parsed['query']['X-Amz-SignedHeaders'] = implode(';', $this->getPresignHeaders($parsed['headers']));
|
||||
$parsed['query']['X-Amz-Expires'] = $this->convertExpires($expiresTimestamp, $startTimestamp);
|
||||
$context = $this->createContext($parsed, $payload);
|
||||
$stringToSign = $this->createStringToSign($httpDate, $scope, $context['creq']);
|
||||
|
@ -151,9 +212,9 @@ class SignatureV4 implements SignatureInterface
|
|||
return self::UNSIGNED_PAYLOAD;
|
||||
}
|
||||
// Calculate the request signature payload
|
||||
if ($request->hasHeader('X-Amz-Content-Sha256')) {
|
||||
if ($request->hasHeader(self::AMZ_CONTENT_SHA256_HEADER)) {
|
||||
// Handle streaming operations (e.g. Glacier.UploadArchive)
|
||||
return $request->getHeaderLine('X-Amz-Content-Sha256');
|
||||
return $request->getHeaderLine(self::AMZ_CONTENT_SHA256_HEADER);
|
||||
}
|
||||
|
||||
if (!$request->getBody()->isSeekable()) {
|
||||
|
@ -207,31 +268,7 @@ class SignatureV4 implements SignatureInterface
|
|||
*/
|
||||
private function createContext(array $parsedRequest, $payload)
|
||||
{
|
||||
// The following headers are not signed because signing these headers
|
||||
// would potentially cause a signature mismatch when sending a request
|
||||
// through a proxy or if modified at the HTTP client level.
|
||||
static $blacklist = [
|
||||
'cache-control' => true,
|
||||
'content-type' => true,
|
||||
'content-length' => true,
|
||||
'expect' => true,
|
||||
'max-forwards' => true,
|
||||
'pragma' => true,
|
||||
'range' => true,
|
||||
'te' => true,
|
||||
'if-match' => true,
|
||||
'if-none-match' => true,
|
||||
'if-modified-since' => true,
|
||||
'if-unmodified-since' => true,
|
||||
'if-range' => true,
|
||||
'accept' => true,
|
||||
'authorization' => true,
|
||||
'proxy-authorization' => true,
|
||||
'from' => true,
|
||||
'referer' => true,
|
||||
'user-agent' => true,
|
||||
'x-amzn-trace-id' => true
|
||||
];
|
||||
$blacklist = $this->getHeaderBlacklist();
|
||||
|
||||
// Normalize the path as required by SigV4
|
||||
$canon = $parsedRequest['method'] . "\n"
|
||||
|
@ -292,7 +329,7 @@ class SignatureV4 implements SignatureInterface
|
|||
|
||||
private function convertToTimestamp($dateValue, $relativeTimeBase = null)
|
||||
{
|
||||
if ($dateValue instanceof \DateTime) {
|
||||
if ($dateValue instanceof \DateTimeInterface) {
|
||||
$timestamp = $dateValue->getTimestamp();
|
||||
} elseif (!is_numeric($dateValue)) {
|
||||
$timestamp = strtotime($dateValue,
|
||||
|
@ -326,7 +363,10 @@ class SignatureV4 implements SignatureInterface
|
|||
if (substr($lname, 0, 5) == 'x-amz') {
|
||||
$parsedRequest['query'][$name] = $header;
|
||||
}
|
||||
if ($lname !== 'host') {
|
||||
$blacklist = $this->getHeaderBlacklist();
|
||||
if (isset($blacklist[$lname])
|
||||
|| $lname === strtolower(self::AMZ_CONTENT_SHA256_HEADER)
|
||||
) {
|
||||
unset($parsedRequest['headers'][$name]);
|
||||
}
|
||||
}
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue