Completed
Push — master ( 271df1...366eb9 )
by
unknown
46:24 queued 25:12
created
lib/private/Files/ObjectStore/S3ConnectionTrait.php 1 patch
Indentation   +228 added lines, -228 removed lines patch added patch discarded remove patch
@@ -19,232 +19,232 @@
 block discarded – undo
19 19
 use Psr\Log\LoggerInterface;
20 20
 
21 21
 trait S3ConnectionTrait {
22
-	use S3ConfigTrait;
23
-
24
-	protected string $id;
25
-
26
-	protected bool $test;
27
-
28
-	protected ?S3Client $connection = null;
29
-
30
-	protected function parseParams($params) {
31
-		if (empty($params['bucket'])) {
32
-			throw new \Exception('Bucket has to be configured.');
33
-		}
34
-
35
-		$this->id = 'amazon::' . $params['bucket'];
36
-
37
-		$this->test = isset($params['test']);
38
-		$this->bucket = $params['bucket'];
39
-		// Default to 5 like the S3 SDK does
40
-		$this->concurrency = $params['concurrency'] ?? 5;
41
-		$this->proxy = $params['proxy'] ?? false;
42
-		$this->timeout = $params['timeout'] ?? 15;
43
-		$this->storageClass = !empty($params['storageClass']) ? $params['storageClass'] : 'STANDARD';
44
-		$this->uploadPartSize = $params['uploadPartSize'] ?? 524288000;
45
-		$this->putSizeLimit = $params['putSizeLimit'] ?? 104857600;
46
-		$this->copySizeLimit = $params['copySizeLimit'] ?? 5242880000;
47
-		$this->useMultipartCopy = (bool)($params['useMultipartCopy'] ?? true);
48
-		$params['region'] = empty($params['region']) ? 'eu-west-1' : $params['region'];
49
-		$params['hostname'] = empty($params['hostname']) ? 's3.' . $params['region'] . '.amazonaws.com' : $params['hostname'];
50
-		$params['s3-accelerate'] = $params['hostname'] === 's3-accelerate.amazonaws.com' || $params['hostname'] === 's3-accelerate.dualstack.amazonaws.com';
51
-		if (!isset($params['port']) || $params['port'] === '') {
52
-			$params['port'] = (isset($params['use_ssl']) && $params['use_ssl'] === false) ? 80 : 443;
53
-		}
54
-		$params['verify_bucket_exists'] = $params['verify_bucket_exists'] ?? true;
55
-
56
-		if ($params['s3-accelerate']) {
57
-			$params['verify_bucket_exists'] = false;
58
-		}
59
-
60
-		$this->params = $params;
61
-	}
62
-
63
-	public function getBucket() {
64
-		return $this->bucket;
65
-	}
66
-
67
-	public function getProxy() {
68
-		return $this->proxy;
69
-	}
70
-
71
-	/**
72
-	 * Returns the connection
73
-	 *
74
-	 * @return S3Client connected client
75
-	 * @throws \Exception if connection could not be made
76
-	 */
77
-	public function getConnection() {
78
-		if ($this->connection !== null) {
79
-			return $this->connection;
80
-		}
81
-
82
-		$scheme = (isset($this->params['use_ssl']) && $this->params['use_ssl'] === false) ? 'http' : 'https';
83
-		$base_url = $scheme . '://' . $this->params['hostname'] . ':' . $this->params['port'] . '/';
84
-
85
-		// Adding explicit credential provider to the beginning chain.
86
-		// Including default credential provider (skipping AWS shared config files).
87
-		$provider = CredentialProvider::memoize(
88
-			CredentialProvider::chain(
89
-				$this->paramCredentialProvider(),
90
-				CredentialProvider::defaultProvider(['use_aws_shared_config_files' => false])
91
-			)
92
-		);
93
-
94
-		$options = [
95
-			'version' => $this->params['version'] ?? 'latest',
96
-			'credentials' => $provider,
97
-			'endpoint' => $base_url,
98
-			'region' => $this->params['region'],
99
-			'use_path_style_endpoint' => isset($this->params['use_path_style']) ? $this->params['use_path_style'] : false,
100
-			'signature_provider' => \Aws\or_chain([self::class, 'legacySignatureProvider'], ClientResolver::_default_signature_provider()),
101
-			'csm' => false,
102
-			'use_arn_region' => false,
103
-			'http' => [
104
-				'verify' => $this->getCertificateBundlePath(),
105
-				// Timeout for the connection to S3 server, not for the request.
106
-				'connect_timeout' => 5
107
-			],
108
-			'use_aws_shared_config_files' => false,
109
-			'retries' => [
110
-				'mode' => 'standard',
111
-				'max_attempts' => 5,
112
-			],
113
-		];
114
-
115
-		if ($this->params['s3-accelerate']) {
116
-			$options['use_accelerate_endpoint'] = true;
117
-		} else {
118
-			$options['endpoint'] = $base_url;
119
-		}
120
-
121
-		if ($this->getProxy()) {
122
-			$options['http']['proxy'] = $this->getProxy();
123
-		}
124
-		if (isset($this->params['legacy_auth']) && $this->params['legacy_auth']) {
125
-			$options['signature_version'] = 'v2';
126
-		}
127
-		$this->connection = new S3Client($options);
128
-
129
-		try {
130
-			$logger = Server::get(LoggerInterface::class);
131
-			if (!$this->connection::isBucketDnsCompatible($this->bucket)) {
132
-				$logger->debug('Bucket "' . $this->bucket . '" This bucket name is not dns compatible, it may contain invalid characters.',
133
-					['app' => 'objectstore']);
134
-			}
135
-
136
-			if ($this->params['verify_bucket_exists'] && !$this->connection->doesBucketExist($this->bucket)) {
137
-				try {
138
-					$logger->info('Bucket "' . $this->bucket . '" does not exist - creating it.', ['app' => 'objectstore']);
139
-					if (!$this->connection::isBucketDnsCompatible($this->bucket)) {
140
-						throw new StorageNotAvailableException('The bucket will not be created because the name is not dns compatible, please correct it: ' . $this->bucket);
141
-					}
142
-					$this->connection->createBucket(['Bucket' => $this->bucket]);
143
-					$this->testTimeout();
144
-				} catch (S3Exception $e) {
145
-					$logger->debug('Invalid remote storage.', [
146
-						'exception' => $e,
147
-						'app' => 'objectstore',
148
-					]);
149
-					if ($e->getAwsErrorCode() !== 'BucketAlreadyOwnedByYou') {
150
-						throw new StorageNotAvailableException('Creation of bucket "' . $this->bucket . '" failed. ' . $e->getMessage());
151
-					}
152
-				}
153
-			}
154
-
155
-			// google cloud's s3 compatibility doesn't like the EncodingType parameter
156
-			if (strpos($base_url, 'storage.googleapis.com')) {
157
-				$this->connection->getHandlerList()->remove('s3.auto_encode');
158
-			}
159
-		} catch (S3Exception $e) {
160
-			throw new StorageNotAvailableException('S3 service is unable to handle request: ' . $e->getMessage());
161
-		}
162
-
163
-		return $this->connection;
164
-	}
165
-
166
-	/**
167
-	 * when running the tests wait to let the buckets catch up
168
-	 */
169
-	private function testTimeout() {
170
-		if ($this->test) {
171
-			sleep($this->timeout);
172
-		}
173
-	}
174
-
175
-	public static function legacySignatureProvider($version, $service, $region) {
176
-		switch ($version) {
177
-			case 'v2':
178
-			case 's3':
179
-				return new S3Signature();
180
-			default:
181
-				return null;
182
-		}
183
-	}
184
-
185
-	/**
186
-	 * This function creates a credential provider based on user parameter file
187
-	 */
188
-	protected function paramCredentialProvider(): callable {
189
-		return function () {
190
-			$key = empty($this->params['key']) ? null : $this->params['key'];
191
-			$secret = empty($this->params['secret']) ? null : $this->params['secret'];
192
-			$sessionToken = empty($this->params['session_token']) ? null : $this->params['session_token'];
193
-
194
-			if ($key && $secret) {
195
-				return Create::promiseFor(
196
-					// a null sessionToken match the default signature of the constructor
197
-					new Credentials($key, $secret, $sessionToken)
198
-				);
199
-			}
200
-
201
-			$msg = 'Could not find parameters set for credentials in config file.';
202
-			return new RejectedPromise(new CredentialsException($msg));
203
-		};
204
-	}
205
-
206
-	protected function getCertificateBundlePath(): ?string {
207
-		if ((int)($this->params['use_nextcloud_bundle'] ?? '0')) {
208
-			// since we store the certificate bundles on the primary storage, we can't get the bundle while setting up the primary storage
209
-			if (!isset($this->params['primary_storage'])) {
210
-				/** @var ICertificateManager $certManager */
211
-				$certManager = Server::get(ICertificateManager::class);
212
-				return $certManager->getAbsoluteBundlePath();
213
-			} else {
214
-				return \OC::$SERVERROOT . '/resources/config/ca-bundle.crt';
215
-			}
216
-		} else {
217
-			return null;
218
-		}
219
-	}
220
-
221
-	protected function getSSECKey(): ?string {
222
-		if (isset($this->params['sse_c_key']) && !empty($this->params['sse_c_key'])) {
223
-			return $this->params['sse_c_key'];
224
-		}
225
-
226
-		return null;
227
-	}
228
-
229
-	protected function getSSECParameters(bool $copy = false): array {
230
-		$key = $this->getSSECKey();
231
-
232
-		if ($key === null) {
233
-			return [];
234
-		}
235
-
236
-		$rawKey = base64_decode($key);
237
-		if ($copy) {
238
-			return [
239
-				'CopySourceSSECustomerAlgorithm' => 'AES256',
240
-				'CopySourceSSECustomerKey' => $rawKey,
241
-				'CopySourceSSECustomerKeyMD5' => md5($rawKey, true)
242
-			];
243
-		}
244
-		return [
245
-			'SSECustomerAlgorithm' => 'AES256',
246
-			'SSECustomerKey' => $rawKey,
247
-			'SSECustomerKeyMD5' => md5($rawKey, true)
248
-		];
249
-	}
22
+    use S3ConfigTrait;
23
+
24
+    protected string $id;
25
+
26
+    protected bool $test;
27
+
28
+    protected ?S3Client $connection = null;
29
+
30
+    protected function parseParams($params) {
31
+        if (empty($params['bucket'])) {
32
+            throw new \Exception('Bucket has to be configured.');
33
+        }
34
+
35
+        $this->id = 'amazon::' . $params['bucket'];
36
+
37
+        $this->test = isset($params['test']);
38
+        $this->bucket = $params['bucket'];
39
+        // Default to 5 like the S3 SDK does
40
+        $this->concurrency = $params['concurrency'] ?? 5;
41
+        $this->proxy = $params['proxy'] ?? false;
42
+        $this->timeout = $params['timeout'] ?? 15;
43
+        $this->storageClass = !empty($params['storageClass']) ? $params['storageClass'] : 'STANDARD';
44
+        $this->uploadPartSize = $params['uploadPartSize'] ?? 524288000;
45
+        $this->putSizeLimit = $params['putSizeLimit'] ?? 104857600;
46
+        $this->copySizeLimit = $params['copySizeLimit'] ?? 5242880000;
47
+        $this->useMultipartCopy = (bool)($params['useMultipartCopy'] ?? true);
48
+        $params['region'] = empty($params['region']) ? 'eu-west-1' : $params['region'];
49
+        $params['hostname'] = empty($params['hostname']) ? 's3.' . $params['region'] . '.amazonaws.com' : $params['hostname'];
50
+        $params['s3-accelerate'] = $params['hostname'] === 's3-accelerate.amazonaws.com' || $params['hostname'] === 's3-accelerate.dualstack.amazonaws.com';
51
+        if (!isset($params['port']) || $params['port'] === '') {
52
+            $params['port'] = (isset($params['use_ssl']) && $params['use_ssl'] === false) ? 80 : 443;
53
+        }
54
+        $params['verify_bucket_exists'] = $params['verify_bucket_exists'] ?? true;
55
+
56
+        if ($params['s3-accelerate']) {
57
+            $params['verify_bucket_exists'] = false;
58
+        }
59
+
60
+        $this->params = $params;
61
+    }
62
+
63
+    public function getBucket() {
64
+        return $this->bucket;
65
+    }
66
+
67
+    public function getProxy() {
68
+        return $this->proxy;
69
+    }
70
+
71
+    /**
72
+     * Returns the connection
73
+     *
74
+     * @return S3Client connected client
75
+     * @throws \Exception if connection could not be made
76
+     */
77
+    public function getConnection() {
78
+        if ($this->connection !== null) {
79
+            return $this->connection;
80
+        }
81
+
82
+        $scheme = (isset($this->params['use_ssl']) && $this->params['use_ssl'] === false) ? 'http' : 'https';
83
+        $base_url = $scheme . '://' . $this->params['hostname'] . ':' . $this->params['port'] . '/';
84
+
85
+        // Adding explicit credential provider to the beginning chain.
86
+        // Including default credential provider (skipping AWS shared config files).
87
+        $provider = CredentialProvider::memoize(
88
+            CredentialProvider::chain(
89
+                $this->paramCredentialProvider(),
90
+                CredentialProvider::defaultProvider(['use_aws_shared_config_files' => false])
91
+            )
92
+        );
93
+
94
+        $options = [
95
+            'version' => $this->params['version'] ?? 'latest',
96
+            'credentials' => $provider,
97
+            'endpoint' => $base_url,
98
+            'region' => $this->params['region'],
99
+            'use_path_style_endpoint' => isset($this->params['use_path_style']) ? $this->params['use_path_style'] : false,
100
+            'signature_provider' => \Aws\or_chain([self::class, 'legacySignatureProvider'], ClientResolver::_default_signature_provider()),
101
+            'csm' => false,
102
+            'use_arn_region' => false,
103
+            'http' => [
104
+                'verify' => $this->getCertificateBundlePath(),
105
+                // Timeout for the connection to S3 server, not for the request.
106
+                'connect_timeout' => 5
107
+            ],
108
+            'use_aws_shared_config_files' => false,
109
+            'retries' => [
110
+                'mode' => 'standard',
111
+                'max_attempts' => 5,
112
+            ],
113
+        ];
114
+
115
+        if ($this->params['s3-accelerate']) {
116
+            $options['use_accelerate_endpoint'] = true;
117
+        } else {
118
+            $options['endpoint'] = $base_url;
119
+        }
120
+
121
+        if ($this->getProxy()) {
122
+            $options['http']['proxy'] = $this->getProxy();
123
+        }
124
+        if (isset($this->params['legacy_auth']) && $this->params['legacy_auth']) {
125
+            $options['signature_version'] = 'v2';
126
+        }
127
+        $this->connection = new S3Client($options);
128
+
129
+        try {
130
+            $logger = Server::get(LoggerInterface::class);
131
+            if (!$this->connection::isBucketDnsCompatible($this->bucket)) {
132
+                $logger->debug('Bucket "' . $this->bucket . '" This bucket name is not dns compatible, it may contain invalid characters.',
133
+                    ['app' => 'objectstore']);
134
+            }
135
+
136
+            if ($this->params['verify_bucket_exists'] && !$this->connection->doesBucketExist($this->bucket)) {
137
+                try {
138
+                    $logger->info('Bucket "' . $this->bucket . '" does not exist - creating it.', ['app' => 'objectstore']);
139
+                    if (!$this->connection::isBucketDnsCompatible($this->bucket)) {
140
+                        throw new StorageNotAvailableException('The bucket will not be created because the name is not dns compatible, please correct it: ' . $this->bucket);
141
+                    }
142
+                    $this->connection->createBucket(['Bucket' => $this->bucket]);
143
+                    $this->testTimeout();
144
+                } catch (S3Exception $e) {
145
+                    $logger->debug('Invalid remote storage.', [
146
+                        'exception' => $e,
147
+                        'app' => 'objectstore',
148
+                    ]);
149
+                    if ($e->getAwsErrorCode() !== 'BucketAlreadyOwnedByYou') {
150
+                        throw new StorageNotAvailableException('Creation of bucket "' . $this->bucket . '" failed. ' . $e->getMessage());
151
+                    }
152
+                }
153
+            }
154
+
155
+            // google cloud's s3 compatibility doesn't like the EncodingType parameter
156
+            if (strpos($base_url, 'storage.googleapis.com')) {
157
+                $this->connection->getHandlerList()->remove('s3.auto_encode');
158
+            }
159
+        } catch (S3Exception $e) {
160
+            throw new StorageNotAvailableException('S3 service is unable to handle request: ' . $e->getMessage());
161
+        }
162
+
163
+        return $this->connection;
164
+    }
165
+
166
+    /**
167
+     * when running the tests wait to let the buckets catch up
168
+     */
169
+    private function testTimeout() {
170
+        if ($this->test) {
171
+            sleep($this->timeout);
172
+        }
173
+    }
174
+
175
+    public static function legacySignatureProvider($version, $service, $region) {
176
+        switch ($version) {
177
+            case 'v2':
178
+            case 's3':
179
+                return new S3Signature();
180
+            default:
181
+                return null;
182
+        }
183
+    }
184
+
185
+    /**
186
+     * This function creates a credential provider based on user parameter file
187
+     */
188
+    protected function paramCredentialProvider(): callable {
189
+        return function () {
190
+            $key = empty($this->params['key']) ? null : $this->params['key'];
191
+            $secret = empty($this->params['secret']) ? null : $this->params['secret'];
192
+            $sessionToken = empty($this->params['session_token']) ? null : $this->params['session_token'];
193
+
194
+            if ($key && $secret) {
195
+                return Create::promiseFor(
196
+                    // a null sessionToken match the default signature of the constructor
197
+                    new Credentials($key, $secret, $sessionToken)
198
+                );
199
+            }
200
+
201
+            $msg = 'Could not find parameters set for credentials in config file.';
202
+            return new RejectedPromise(new CredentialsException($msg));
203
+        };
204
+    }
205
+
206
+    protected function getCertificateBundlePath(): ?string {
207
+        if ((int)($this->params['use_nextcloud_bundle'] ?? '0')) {
208
+            // since we store the certificate bundles on the primary storage, we can't get the bundle while setting up the primary storage
209
+            if (!isset($this->params['primary_storage'])) {
210
+                /** @var ICertificateManager $certManager */
211
+                $certManager = Server::get(ICertificateManager::class);
212
+                return $certManager->getAbsoluteBundlePath();
213
+            } else {
214
+                return \OC::$SERVERROOT . '/resources/config/ca-bundle.crt';
215
+            }
216
+        } else {
217
+            return null;
218
+        }
219
+    }
220
+
221
+    protected function getSSECKey(): ?string {
222
+        if (isset($this->params['sse_c_key']) && !empty($this->params['sse_c_key'])) {
223
+            return $this->params['sse_c_key'];
224
+        }
225
+
226
+        return null;
227
+    }
228
+
229
+    protected function getSSECParameters(bool $copy = false): array {
230
+        $key = $this->getSSECKey();
231
+
232
+        if ($key === null) {
233
+            return [];
234
+        }
235
+
236
+        $rawKey = base64_decode($key);
237
+        if ($copy) {
238
+            return [
239
+                'CopySourceSSECustomerAlgorithm' => 'AES256',
240
+                'CopySourceSSECustomerKey' => $rawKey,
241
+                'CopySourceSSECustomerKeyMD5' => md5($rawKey, true)
242
+            ];
243
+        }
244
+        return [
245
+            'SSECustomerAlgorithm' => 'AES256',
246
+            'SSECustomerKey' => $rawKey,
247
+            'SSECustomerKeyMD5' => md5($rawKey, true)
248
+        ];
249
+    }
250 250
 }
Please login to merge, or discard this patch.