PluginProbe
Media Cloud Sync / 1.4.2
Media Cloud Sync v1.4.2
1.4.2 1.4.1 1.4.0 1.3.12 1.3.11 1.3.10 trunk 1.0.0 1.0.1 1.0.2 1.0.3 1.1.0 1.1.1 1.2.0 1.2.10 1.2.11 1.2.12 1.2.13 1.2.2 1.2.3 1.2.4 1.2.5 1.2.6 1.2.7 1.2.8 All 36 releases
← All changes | includes/sdk/s3/Aws/S3/Parser/ValidateResponseChecksumResultMutator.php +55 -28 1.2.13 → 1.4.2 View file →
@@ -15,16 +15,21 @@
15 15 */
16 16 final class ValidateResponseChecksumResultMutator implements S3ResultMutator
17 17 {
18 18 use CalculatesChecksumTrait;
19 + public const DEFAULT_VALIDATION_MODE = 'when_supported';
19 20 /** @var Service $api */
20 21 private $api;
22 + /** @var array $api */
23 + private $config;
21 24 /**
22 25 * @param Service $api
26 + * @param array $config
23 27 */
24 - public function __construct(Service $api)
28 + public function __construct(Service $api, array $config = [])
25 29 {
26 30 $this->api = $api;
31 + $this->config = $config;
27 32 }
28 33 /**
29 34 * @param ResultInterface $result
30 35 * @param CommandInterface|null $command
@@ -31,43 +36,32 @@
31 36 * @param ResponseInterface|null $response
32 37 *
33 38 * @return ResultInterface
34 39 */
35 - public function __invoke(ResultInterface $result, CommandInterface $command = null, ResponseInterface $response = null) : ResultInterface
40 + public function __invoke(ResultInterface $result, ?CommandInterface $command = null, ?ResponseInterface $response = null) : ResultInterface
36 41 {
37 42 $operation = $this->api->getOperation($command->getName());
38 43 // Skip this middleware if the operation doesn't have an httpChecksum
39 - $checksumInfo = empty($operation['httpChecksum']) ? null : $operation['httpChecksum'];
40 - if (null === $checksumInfo) {
44 + $checksumInfo = $operation['httpChecksum'] ?? null;
45 + if (\is_null($checksumInfo)) {
41 46 return $result;
42 47 }
43 - // Skip this middleware if the operation doesn't send back a checksum,
44 - // or the user doesn't opt in
48 + $mode = $this->config['response_checksum_validation'] ?? self::DEFAULT_VALIDATION_MODE;
45 49 $checksumModeEnabledMember = $checksumInfo['requestValidationModeMember'] ?? "";
46 - $checksumModeEnabled = $command[$checksumModeEnabledMember] ?? "";
50 + $checksumModeEnabled = \strtolower($command[$checksumModeEnabledMember] ?? "");
47 51 $responseAlgorithms = $checksumInfo['responseAlgorithms'] ?? [];
48 - if (empty($responseAlgorithms) || \strtolower($checksumModeEnabled) !== "enabled") {
52 + $shouldSkipValidation = $this->shouldSkipValidation($mode, $checksumModeEnabled, $responseAlgorithms);
53 + if ($shouldSkipValidation) {
49 54 return $result;
50 55 }
51 - if (\extension_loaded('awscrt')) {
52 - $checksumPriority = ['CRC32C', 'CRC32', 'SHA1', 'SHA256'];
53 - } else {
54 - $checksumPriority = ['CRC32', 'SHA1', 'SHA256'];
55 - }
56 - $checksumsToCheck = \array_intersect($responseAlgorithms, $checksumPriority);
56 + $checksumPriority = $this->getChecksumPriority();
57 + $checksumsToCheck = \array_intersect($responseAlgorithms, \array_map('strtoupper', \array_keys($checksumPriority)));
57 58 $checksumValidationInfo = $this->validateChecksum($checksumsToCheck, $response);
58 - if ($checksumValidationInfo['status'] == "SUCCEEDED") {
59 + if ($checksumValidationInfo['status'] === "SUCCEEDED") {
59 60 $result['ChecksumValidated'] = $checksumValidationInfo['checksum'];
60 - } elseif ($checksumValidationInfo['status'] == "FAILED") {
61 - // Ignore failed validations on GetObject if it's a multipart get
62 - // which returned a full multipart object
63 - if ($command->getName() === "GetObject" && !empty($checksumValidationInfo['checksumHeaderValue'])) {
64 - $headerValue = $checksumValidationInfo['checksumHeaderValue'];
65 - $lastDashPos = \strrpos($headerValue, '-');
66 - $endOfChecksum = \substr($headerValue, $lastDashPos + 1);
67 - if (\is_numeric($endOfChecksum) && \intval($endOfChecksum) > 1 && \intval($endOfChecksum) < 10000) {
68 - return $result;
69 - }
61 + } elseif ($checksumValidationInfo['status'] === "FAILED") {
62 + if ($this->isMultipartGetObject($command, $checksumValidationInfo)) {
63 + return $result;
70 64 }
71 65 throw new S3Exception("Calculated response checksum did not match the expected value", $command);
72 66 }
73 67 return $result;
@@ -83,11 +77,10 @@
83 77 $checksumToValidate = $this->chooseChecksumHeaderToValidate($checksumPriority, $response);
84 78 $validationStatus = "SKIPPED";
85 79 $checksumHeaderValue = null;
86 80 if (!empty($checksumToValidate)) {
87 - $checksumHeaderValue = $response->getHeader('x-amz-checksum-' . $checksumToValidate);
88 - if (isset($checksumHeaderValue)) {
89 - $checksumHeaderValue = $checksumHeaderValue[0];
81 + $checksumHeaderValue = $response->getHeaderLine('x-amz-checksum-' . $checksumToValidate);
82 + if (!empty($checksumHeaderValue)) {
90 83 $calculatedChecksumValue = $this->getEncodedValue($checksumToValidate, $response->getBody());
91 84 $validationStatus = $checksumHeaderValue == $calculatedChecksumValue ? "SUCCEEDED" : "FAILED";
92 85 }
93 86 }
@@ -107,6 +100,40 @@
107 100 return $checksum;
108 101 }
109 102 }
110 103 return null;
104 + }
105 + /**
106 + * @param string $mode
107 + * @param string $checksumModeEnabled
108 + * @param array $responseAlgorithms
109 + *
110 + * @return bool
111 + */
112 + private function shouldSkipValidation(string $mode, string $checksumModeEnabled, array $responseAlgorithms) : bool
113 + {
114 + return empty($responseAlgorithms) || $mode === 'when_required' && $checksumModeEnabled !== 'enabled';
115 + }
116 + /**
117 + * @return string[]
118 + */
119 + private function getChecksumPriority() : array
120 + {
121 + return \extension_loaded('awscrt') ? self::$supportedAlgorithms : \array_slice(self::$supportedAlgorithms, 1);
122 + }
123 + /**
124 + * @param CommandInterface $command
125 + * @param array $checksumValidationInfo
126 + *
127 + * @return bool
128 + */
129 + private function isMultipartGetObject(CommandInterface $command, array $checksumValidationInfo) : bool
130 + {
131 + if ($command->getName() !== "GetObject" || empty($checksumValidationInfo['checksumHeaderValue'])) {
132 + return \false;
133 + }
134 + $headerValue = $checksumValidationInfo['checksumHeaderValue'];
135 + $lastDashPos = \strrpos($headerValue, '-');
136 + $endOfChecksum = \substr($headerValue, $lastDashPos + 1);
137 + return \is_numeric($endOfChecksum) && (int) $endOfChecksum > 1 && (int) $endOfChecksum < 10000;
111 138 }
112 139 }