fix(s3): remove proxy, set objects acl to public-read, and serve files using their public urls

This commit is contained in:
Yassine Doghri 2024-01-30 15:26:22 +00:00
parent de099ac643
commit 6a77a9d2f2
6 changed files with 3 additions and 151 deletions

View File

@ -33,7 +33,6 @@ class Media extends BaseConfig
'debug' => false,
'pathStyleEndpoint' => false,
'keyPrefix' => '',
'serveWithRedirect' => false,
];
/**

View File

@ -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',
]);

View File

@ -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));
}
}

View File

@ -5,7 +5,6 @@ declare(strict_types=1);
namespace Modules\Media\FileManagers;
use CodeIgniter\Files\File;
use CodeIgniter\HTTP\Response;
use Exception;
use Modules\Media\Config\Media as MediaConfig;
@ -131,11 +130,6 @@ class FS implements FileManagerInterface
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
*

View File

@ -5,7 +5,6 @@ declare(strict_types=1);
namespace Modules\Media\FileManagers;
use CodeIgniter\Files\File;
use CodeIgniter\HTTP\Response;
interface FileManagerInterface
{
@ -28,6 +27,4 @@ interface FileManagerInterface
public function deleteAll(string $prefix, string $pattern = '*'): bool;
public function isHealthy(): bool;
public function serve(string $key): Response;
}

View File

@ -6,11 +6,7 @@ namespace Modules\Media\FileManagers;
use Aws\Credentials\Credentials;
use Aws\S3\S3Client;
use CodeIgniter\Exceptions\PageNotFoundException;
use CodeIgniter\Files\File;
use CodeIgniter\HTTP\IncomingRequest;
use CodeIgniter\HTTP\Response;
use DateTime;
use Exception;
use Modules\Media\Config\Media as MediaConfig;
@ -39,6 +35,7 @@ class S3 implements FileManagerInterface
'SourceFile' => $file,
'ContentType' => $file->getMimeType(),
'CacheControl' => 'max-age=' . YEAR,
'ACL' => 'public-read',
]);
// delete file after storage in s3
@ -63,7 +60,7 @@ class S3 implements FileManagerInterface
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
@ -74,6 +71,7 @@ class S3 implements FileManagerInterface
'Bucket' => $this->config->s3['bucket'],
'CopySource' => $this->config->s3['bucket'] . '/' . $this->prefixKey($oldKey),
'Key' => $this->prefixKey($newKey),
'ACL' => 'public-read',
]);
} catch (Exception) {
return false;
@ -182,92 +180,6 @@ class S3 implements FileManagerInterface
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
{
if ($this->config->s3['keyPrefix'] === '') {