fix(s3): remove proxy, set objects acl to public-read, and serve files using their public urls
This commit is contained in:
parent
de099ac643
commit
6a77a9d2f2
|
@ -33,7 +33,6 @@ class Media extends BaseConfig
|
||||||
'debug' => false,
|
'debug' => false,
|
||||||
'pathStyleEndpoint' => false,
|
'pathStyleEndpoint' => false,
|
||||||
'keyPrefix' => '',
|
'keyPrefix' => '',
|
||||||
'serveWithRedirect' => false,
|
|
||||||
];
|
];
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|
|
@ -1,24 +0,0 @@
|
||||||
<?php
|
|
||||||
|
|
||||||
declare(strict_types=1);
|
|
||||||
|
|
||||||
use CodeIgniter\Router\RouteCollection;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @copyright 2023 Ad Aures
|
|
||||||
* @license https://www.gnu.org/licenses/agpl-3.0.en.html AGPL3
|
|
||||||
* @link https://castopod.org/
|
|
||||||
*/
|
|
||||||
|
|
||||||
/** @var RouteCollection $routes */
|
|
||||||
|
|
||||||
$routes->head('static/(:any)', 'MediaController::serve/$1', [
|
|
||||||
'as' => 'media-serve',
|
|
||||||
'namespace' => 'Modules\Media\Controllers',
|
|
||||||
'filter' => 'allow-cors',
|
|
||||||
]);
|
|
||||||
$routes->get('static/(:any)', 'MediaController::serve/$1', [
|
|
||||||
'as' => 'media-serve',
|
|
||||||
'namespace' => 'Modules\Media\Controllers',
|
|
||||||
'filter' => 'allow-cors',
|
|
||||||
]);
|
|
|
@ -1,26 +0,0 @@
|
||||||
<?php
|
|
||||||
|
|
||||||
declare(strict_types=1);
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @copyright 2020 Ad Aures
|
|
||||||
* @license https://www.gnu.org/licenses/agpl-3.0.en.html AGPL3
|
|
||||||
* @link https://castopod.org/
|
|
||||||
*/
|
|
||||||
|
|
||||||
namespace Modules\Media\Controllers;
|
|
||||||
|
|
||||||
use CodeIgniter\Controller;
|
|
||||||
use CodeIgniter\HTTP\Response;
|
|
||||||
use Modules\Media\FileManagers\FileManagerInterface;
|
|
||||||
|
|
||||||
class MediaController extends Controller
|
|
||||||
{
|
|
||||||
public function serve(string ...$key): Response
|
|
||||||
{
|
|
||||||
/** @var FileManagerInterface $fileManager */
|
|
||||||
$fileManager = service('file_manager');
|
|
||||||
|
|
||||||
return $fileManager->serve(implode('/', $key));
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -5,7 +5,6 @@ declare(strict_types=1);
|
||||||
namespace Modules\Media\FileManagers;
|
namespace Modules\Media\FileManagers;
|
||||||
|
|
||||||
use CodeIgniter\Files\File;
|
use CodeIgniter\Files\File;
|
||||||
use CodeIgniter\HTTP\Response;
|
|
||||||
use Exception;
|
use Exception;
|
||||||
use Modules\Media\Config\Media as MediaConfig;
|
use Modules\Media\Config\Media as MediaConfig;
|
||||||
|
|
||||||
|
@ -131,11 +130,6 @@ class FS implements FileManagerInterface
|
||||||
return is_really_writable($this->media_path_absolute());
|
return is_really_writable($this->media_path_absolute());
|
||||||
}
|
}
|
||||||
|
|
||||||
public function serve(string $key): Response
|
|
||||||
{
|
|
||||||
return redirect()->to($this->getUrl($key));
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Prefixes the absolute storage directory to the media path of a given uri
|
* Prefixes the absolute storage directory to the media path of a given uri
|
||||||
*
|
*
|
||||||
|
|
|
@ -5,7 +5,6 @@ declare(strict_types=1);
|
||||||
namespace Modules\Media\FileManagers;
|
namespace Modules\Media\FileManagers;
|
||||||
|
|
||||||
use CodeIgniter\Files\File;
|
use CodeIgniter\Files\File;
|
||||||
use CodeIgniter\HTTP\Response;
|
|
||||||
|
|
||||||
interface FileManagerInterface
|
interface FileManagerInterface
|
||||||
{
|
{
|
||||||
|
@ -28,6 +27,4 @@ interface FileManagerInterface
|
||||||
public function deleteAll(string $prefix, string $pattern = '*'): bool;
|
public function deleteAll(string $prefix, string $pattern = '*'): bool;
|
||||||
|
|
||||||
public function isHealthy(): bool;
|
public function isHealthy(): bool;
|
||||||
|
|
||||||
public function serve(string $key): Response;
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -6,11 +6,7 @@ namespace Modules\Media\FileManagers;
|
||||||
|
|
||||||
use Aws\Credentials\Credentials;
|
use Aws\Credentials\Credentials;
|
||||||
use Aws\S3\S3Client;
|
use Aws\S3\S3Client;
|
||||||
use CodeIgniter\Exceptions\PageNotFoundException;
|
|
||||||
use CodeIgniter\Files\File;
|
use CodeIgniter\Files\File;
|
||||||
use CodeIgniter\HTTP\IncomingRequest;
|
|
||||||
use CodeIgniter\HTTP\Response;
|
|
||||||
use DateTime;
|
|
||||||
use Exception;
|
use Exception;
|
||||||
use Modules\Media\Config\Media as MediaConfig;
|
use Modules\Media\Config\Media as MediaConfig;
|
||||||
|
|
||||||
|
@ -39,6 +35,7 @@ class S3 implements FileManagerInterface
|
||||||
'SourceFile' => $file,
|
'SourceFile' => $file,
|
||||||
'ContentType' => $file->getMimeType(),
|
'ContentType' => $file->getMimeType(),
|
||||||
'CacheControl' => 'max-age=' . YEAR,
|
'CacheControl' => 'max-age=' . YEAR,
|
||||||
|
'ACL' => 'public-read',
|
||||||
]);
|
]);
|
||||||
|
|
||||||
// delete file after storage in s3
|
// delete file after storage in s3
|
||||||
|
@ -63,7 +60,7 @@ class S3 implements FileManagerInterface
|
||||||
|
|
||||||
public function getUrl(string $key): string
|
public function getUrl(string $key): string
|
||||||
{
|
{
|
||||||
return media_url((string) route_to('media-serve', $key));
|
return media_url($this->prefixKey($key));
|
||||||
}
|
}
|
||||||
|
|
||||||
public function rename(string $oldKey, string $newKey): bool
|
public function rename(string $oldKey, string $newKey): bool
|
||||||
|
@ -74,6 +71,7 @@ class S3 implements FileManagerInterface
|
||||||
'Bucket' => $this->config->s3['bucket'],
|
'Bucket' => $this->config->s3['bucket'],
|
||||||
'CopySource' => $this->config->s3['bucket'] . '/' . $this->prefixKey($oldKey),
|
'CopySource' => $this->config->s3['bucket'] . '/' . $this->prefixKey($oldKey),
|
||||||
'Key' => $this->prefixKey($newKey),
|
'Key' => $this->prefixKey($newKey),
|
||||||
|
'ACL' => 'public-read',
|
||||||
]);
|
]);
|
||||||
} catch (Exception) {
|
} catch (Exception) {
|
||||||
return false;
|
return false;
|
||||||
|
@ -182,92 +180,6 @@ class S3 implements FileManagerInterface
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
public function serve(string $key): Response
|
|
||||||
{
|
|
||||||
if ($this->config->s3['serveWithRedirect']) {
|
|
||||||
return $this->servePresignedRequest($key);
|
|
||||||
}
|
|
||||||
|
|
||||||
return $this->serveProxy($key);
|
|
||||||
}
|
|
||||||
|
|
||||||
private function serveProxy(string $key): Response
|
|
||||||
{
|
|
||||||
/** @var IncomingRequest $incomingRequest */
|
|
||||||
$incomingRequest = service('request');
|
|
||||||
|
|
||||||
/** @var Response $response */
|
|
||||||
$response = service('response');
|
|
||||||
|
|
||||||
$s3Request = [
|
|
||||||
'Bucket' => $this->config->s3['bucket'],
|
|
||||||
'Key' => $this->prefixKey($key),
|
|
||||||
];
|
|
||||||
|
|
||||||
foreach ($incomingRequest->headers() as $header) {
|
|
||||||
$s3Request[$header->getName()] = $header->getValue();
|
|
||||||
}
|
|
||||||
|
|
||||||
try {
|
|
||||||
$result = $this->s3->getObject($s3Request);
|
|
||||||
} catch (Exception) {
|
|
||||||
throw new PageNotFoundException();
|
|
||||||
}
|
|
||||||
|
|
||||||
// Remove Cache-Control header before redefining it
|
|
||||||
header_remove('Cache-Control');
|
|
||||||
|
|
||||||
$response->setStatusCode($result['@metadata']['statusCode']);
|
|
||||||
|
|
||||||
// set same headers as response from s3
|
|
||||||
foreach ($result['@metadata']['headers'] as $headerName => $headerValue) {
|
|
||||||
$response->setHeader($headerName, $headerValue);
|
|
||||||
}
|
|
||||||
|
|
||||||
return $response->setBody((string) $result->get('Body')->getContents());
|
|
||||||
}
|
|
||||||
|
|
||||||
private function servePresignedRequest(string $key): Response
|
|
||||||
{
|
|
||||||
$cacheName = 'object_presigned_uri_' . str_replace('/', '-', $key) . '_' . $this->config->s3['bucket'];
|
|
||||||
if (! $found = cache($cacheName)) {
|
|
||||||
$cmd = $this->s3->getCommand('GetObject', [
|
|
||||||
'Bucket' => $this->config->s3['bucket'],
|
|
||||||
'Key' => $this->prefixKey($key),
|
|
||||||
]);
|
|
||||||
|
|
||||||
$request = $this->s3->createPresignedRequest($cmd, '+1 day');
|
|
||||||
|
|
||||||
$found = (string) $request->getUri();
|
|
||||||
|
|
||||||
cache()
|
|
||||||
->save($cacheName, $found, DAY);
|
|
||||||
}
|
|
||||||
|
|
||||||
$cacheOptions = [
|
|
||||||
'max-age' => DAY,
|
|
||||||
'etag' => md5($found),
|
|
||||||
'public' => true,
|
|
||||||
];
|
|
||||||
|
|
||||||
if (cache()->getMetaData($cacheName)) {
|
|
||||||
$lastModifiedTimestamp = cache()
|
|
||||||
->getMetaData($cacheName)['mtime'];
|
|
||||||
$lastModified = new DateTime();
|
|
||||||
$lastModified->setTimestamp($lastModifiedTimestamp);
|
|
||||||
$cacheOptions['last-modified'] = $lastModified->format(DATE_RFC7231);
|
|
||||||
}
|
|
||||||
|
|
||||||
/** @var Response $response */
|
|
||||||
$response = service('response');
|
|
||||||
|
|
||||||
// Remove Cache-Control header before redefining it
|
|
||||||
header_remove('Cache-Control');
|
|
||||||
|
|
||||||
return $response->setCache($cacheOptions)
|
|
||||||
->redirect($found);
|
|
||||||
}
|
|
||||||
|
|
||||||
private function prefixKey(string $key): string
|
private function prefixKey(string $key): string
|
||||||
{
|
{
|
||||||
if ($this->config->s3['keyPrefix'] === '') {
|
if ($this->config->s3['keyPrefix'] === '') {
|
||||||
|
|
Loading…
Reference in New Issue