| 1 |
<?php |
| 2 |
|
| 3 |
namespace Dudlewebs\WPMCS\s3\Aws; |
| 4 |
|
| 5 |
use Dudlewebs\WPMCS\s3\Aws\Signature\SignatureV4; |
| 6 |
use Dudlewebs\WPMCS\s3\Aws\Endpoint\EndpointProvider; |
| 7 |
use Dudlewebs\WPMCS\s3\GuzzleHttp\Psr7\Uri; |
| 8 |
use Dudlewebs\WPMCS\s3\Psr\Http\Message\RequestInterface; |
| 9 |
/** |
| 10 |
* @internal Adds computed values to service operations that need presigned url. |
| 11 |
*/ |
| 12 |
class PresignUrlMiddleware |
| 13 |
{ |
| 14 |
private $client; |
| 15 |
private $endpointProvider; |
| 16 |
private $nextHandler; |
| 17 |
/** @var array names of operations that require presign url */ |
| 18 |
private $commandPool; |
| 19 |
/** @var array query params that are not on the operation's model to add before signing */ |
| 20 |
private $extraQueryParams; |
| 21 |
/** @var string */ |
| 22 |
private $serviceName; |
| 23 |
/** @var string */ |
| 24 |
private $presignParam; |
| 25 |
/** @var bool */ |
| 26 |
private $requireDifferentRegion; |
| 27 |
public function __construct(array $options, callable $endpointProvider, AwsClientInterface $client, callable $nextHandler) |
| 28 |
{ |
| 29 |
$this->endpointProvider = $endpointProvider; |
| 30 |
$this->client = $client; |
| 31 |
$this->nextHandler = $nextHandler; |
| 32 |
$this->commandPool = $options['operations']; |
| 33 |
$this->serviceName = $options['service']; |
| 34 |
$this->presignParam = !empty($options['presign_param']) ? $options['presign_param'] : 'PresignedUrl'; |
| 35 |
$this->extraQueryParams = !empty($options['extra_query_params']) ? $options['extra_query_params'] : []; |
| 36 |
$this->requireDifferentRegion = !empty($options['require_different_region']); |
| 37 |
} |
| 38 |
public static function wrap(AwsClientInterface $client, callable $endpointProvider, array $options = []) |
| 39 |
{ |
| 40 |
return function (callable $handler) use($endpointProvider, $client, $options) { |
| 41 |
$f = new PresignUrlMiddleware($options, $endpointProvider, $client, $handler); |
| 42 |
return $f; |
| 43 |
}; |
| 44 |
} |
| 45 |
public function __invoke(CommandInterface $cmd, RequestInterface $request = null) |
| 46 |
{ |
| 47 |
if (\in_array($cmd->getName(), $this->commandPool) && !isset($cmd->{'__skip' . $cmd->getName()})) { |
| 48 |
$cmd['DestinationRegion'] = $this->client->getRegion(); |
| 49 |
if (!empty($cmd['SourceRegion']) && !empty($cmd[$this->presignParam])) { |
| 50 |
goto nexthandler; |
| 51 |
} |
| 52 |
if (!$this->requireDifferentRegion || !empty($cmd['SourceRegion']) && $cmd['SourceRegion'] !== $cmd['DestinationRegion']) { |
| 53 |
$cmd[$this->presignParam] = $this->createPresignedUrl($this->client, $cmd); |
| 54 |
} |
| 55 |
} |
| 56 |
nexthandler: |
| 57 |
$nextHandler = $this->nextHandler; |
| 58 |
return $nextHandler($cmd, $request); |
| 59 |
} |
| 60 |
private function createPresignedUrl(AwsClientInterface $client, CommandInterface $cmd) |
| 61 |
{ |
| 62 |
$cmdName = $cmd->getName(); |
| 63 |
$newCmd = $client->getCommand($cmdName, $cmd->toArray()); |
| 64 |
// Avoid infinite recursion by flagging the new command. |
| 65 |
$newCmd->{'__skip' . $cmdName} = \true; |
| 66 |
// Serialize a request for the operation. |
| 67 |
$request = \Dudlewebs\WPMCS\s3\Aws\serialize($newCmd); |
| 68 |
// Create the new endpoint for the target endpoint. |
| 69 |
$endpoint = EndpointProvider::resolve($this->endpointProvider, ['region' => $cmd['SourceRegion'], 'service' => $this->serviceName])['endpoint']; |
| 70 |
// Set the request to hit the target endpoint. |
| 71 |
$uri = $request->getUri()->withHost((new Uri($endpoint))->getHost()); |
| 72 |
$request = $request->withUri($uri); |
| 73 |
// Create a presigned URL for our generated request. |
| 74 |
$signer = new SignatureV4($this->serviceName, $cmd['SourceRegion']); |
| 75 |
$currentQueryParams = (string) $request->getBody(); |
| 76 |
$paramsToAdd = \false; |
| 77 |
if (!empty($this->extraQueryParams[$cmdName])) { |
| 78 |
foreach ($this->extraQueryParams[$cmdName] as $param) { |
| 79 |
if (!\strpos($currentQueryParams, $param)) { |
| 80 |
$paramsToAdd = "&{$param}={$cmd[$param]}"; |
| 81 |
} |
| 82 |
} |
| 83 |
} |
| 84 |
return (string) $signer->presign(SignatureV4::convertPostToGet($request, $paramsToAdd ?: ""), $client->getCredentials()->wait(), '+1 hour')->getUri(); |
| 85 |
} |
| 86 |
} |
| 87 |
|