Implemented a new option for S3 sources to allow signed URLs and private buckets to be used. #141
This commit is contained in:
parent
93c6f5da10
commit
f773b10244
@ -42,6 +42,11 @@ abstract class AlbumSourceBase
|
|||||||
return self::$albumSourceCache[$fullClassName];
|
return self::$albumSourceCache[$fullClassName];
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public function getConfiguration()
|
||||||
|
{
|
||||||
|
return $this->configuration;
|
||||||
|
}
|
||||||
|
|
||||||
public function setAlbum(Album $album)
|
public function setAlbum(Album $album)
|
||||||
{
|
{
|
||||||
$this->album = $album;
|
$this->album = $album;
|
||||||
|
@ -130,7 +130,19 @@ class AmazonS3Source extends AlbumSourceBase implements IAlbumSource, IAnalysisQ
|
|||||||
*/
|
*/
|
||||||
public function getUrlToPhoto(Photo $photo, $thumbnail = null)
|
public function getUrlToPhoto(Photo $photo, $thumbnail = null)
|
||||||
{
|
{
|
||||||
return $this->getClient()->getObjectUrl($this->configuration->container_name, $this->getPathToPhoto($photo, $thumbnail));
|
$client = $this->getClient();
|
||||||
|
|
||||||
|
if ($this->configuration->s3_signed_urls)
|
||||||
|
{
|
||||||
|
$cmd = $client->getCommand('GetObject', [
|
||||||
|
'Bucket' => $this->configuration->container_name,
|
||||||
|
'Key' => $this->getPathToPhoto($photo, $thumbnail)
|
||||||
|
]);
|
||||||
|
|
||||||
|
return $client->createPresignedRequest($cmd, '+5 minutes')->getUri();
|
||||||
|
}
|
||||||
|
|
||||||
|
return $client->getObjectUrl($this->configuration->container_name, $this->getPathToPhoto($photo, $thumbnail));
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -144,7 +156,11 @@ class AmazonS3Source extends AlbumSourceBase implements IAlbumSource, IAnalysisQ
|
|||||||
{
|
{
|
||||||
$photoPath = $this->getPathToPhoto($photo, $thumbnail);
|
$photoPath = $this->getPathToPhoto($photo, $thumbnail);
|
||||||
|
|
||||||
$this->getClient()->upload($this->configuration->container_name, $photoPath, fopen($tempFilename, 'r+'), 'public-read');
|
$uploadAcl = $this->configuration->s3_signed_urls
|
||||||
|
? 'private'
|
||||||
|
: 'public-read';
|
||||||
|
|
||||||
|
$this->getClient()->upload($this->configuration->container_name, $photoPath, fopen($tempFilename, 'r+'), $uploadAcl);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -6,7 +6,6 @@ use App\Album;
|
|||||||
use App\Photo;
|
use App\Photo;
|
||||||
use App\Storage;
|
use App\Storage;
|
||||||
use Guzzle\Http\EntityBody;
|
use Guzzle\Http\EntityBody;
|
||||||
use Symfony\Component\HttpFoundation\File\File;
|
|
||||||
|
|
||||||
interface IAlbumSource
|
interface IAlbumSource
|
||||||
{
|
{
|
||||||
@ -32,6 +31,12 @@ interface IAlbumSource
|
|||||||
*/
|
*/
|
||||||
function fetchPhotoContent(Photo $photo, $thumbnail = null);
|
function fetchPhotoContent(Photo $photo, $thumbnail = null);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Gets the configuration of the source.
|
||||||
|
* @return mixed
|
||||||
|
*/
|
||||||
|
function getConfiguration();
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Gets the name of this album source.
|
* Gets the name of this album source.
|
||||||
* @return string
|
* @return string
|
||||||
|
@ -55,12 +55,14 @@ class StorageController extends Controller
|
|||||||
$this->authorizeAccessToAdminPanel('admin:manage-storage');
|
$this->authorizeAccessToAdminPanel('admin:manage-storage');
|
||||||
|
|
||||||
$filesystemDefaultLocation = sprintf('%s/storage/app/albums', dirname(dirname(dirname(dirname(__DIR__)))));
|
$filesystemDefaultLocation = sprintf('%s/storage/app/albums', dirname(dirname(dirname(dirname(__DIR__)))));
|
||||||
|
$storage = new Storage();
|
||||||
|
$storage->s3_signed_urls = true;
|
||||||
|
|
||||||
return Theme::render('admin.create_storage', [
|
return Theme::render('admin.create_storage', [
|
||||||
'album_sources' => UserConfig::albumSources(),
|
'album_sources' => UserConfig::albumSources(),
|
||||||
'filesystem_default_location' => $filesystemDefaultLocation,
|
'filesystem_default_location' => $filesystemDefaultLocation,
|
||||||
'info' => $request->session()->get('info'),
|
'info' => $request->session()->get('info'),
|
||||||
'storage' => new Storage()
|
'storage' => $storage
|
||||||
]);
|
]);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -94,6 +96,7 @@ class StorageController extends Controller
|
|||||||
$storage->is_active = true;
|
$storage->is_active = true;
|
||||||
$storage->is_default = (strtolower($request->get('is_default')) == 'on');
|
$storage->is_default = (strtolower($request->get('is_default')) == 'on');
|
||||||
$storage->is_internal = false;
|
$storage->is_internal = false;
|
||||||
|
$storage->s3_signed_urls = (strtolower($request->get('s3_signed_urls')) == 'on');
|
||||||
|
|
||||||
if ($storage->source != 'LocalFilesystemSource' && isset($storage->location))
|
if ($storage->source != 'LocalFilesystemSource' && isset($storage->location))
|
||||||
{
|
{
|
||||||
@ -219,10 +222,12 @@ class StorageController extends Controller
|
|||||||
'cdn_url',
|
'cdn_url',
|
||||||
'access_key',
|
'access_key',
|
||||||
'secret_key',
|
'secret_key',
|
||||||
'b2_bucket_type'
|
'b2_bucket_type',
|
||||||
|
's3_signed_urls'
|
||||||
]));
|
]));
|
||||||
$storage->is_active = (strtolower($request->get('is_active')) == 'on');
|
$storage->is_active = (strtolower($request->get('is_active')) == 'on');
|
||||||
$storage->is_default = (strtolower($request->get('is_default')) == 'on');
|
$storage->is_default = (strtolower($request->get('is_default')) == 'on');
|
||||||
|
$storage->s3_signed_urls = (strtolower($request->get('s3_signed_urls')) == 'on');
|
||||||
|
|
||||||
if ($storage->is_default && !$storage->is_active)
|
if ($storage->is_default && !$storage->is_active)
|
||||||
{
|
{
|
||||||
|
@ -2,6 +2,7 @@
|
|||||||
|
|
||||||
namespace App;
|
namespace App;
|
||||||
|
|
||||||
|
use App\AlbumSources\IAlbumSource;
|
||||||
use Illuminate\Database\Eloquent\Model;
|
use Illuminate\Database\Eloquent\Model;
|
||||||
use Illuminate\Notifications\Notifiable;
|
use Illuminate\Notifications\Notifiable;
|
||||||
|
|
||||||
@ -110,9 +111,14 @@ class Photo extends Model
|
|||||||
|
|
||||||
public function thumbnailUrl($thumbnailName = null, $cacheBust = true)
|
public function thumbnailUrl($thumbnailName = null, $cacheBust = true)
|
||||||
{
|
{
|
||||||
$url = $this->album->getAlbumSource()->getUrlToPhoto($this, $thumbnailName);
|
/** @var IAlbumSource $source */
|
||||||
|
$source = $this->album->getAlbumSource();
|
||||||
|
$sourceConfiguration = $source->getConfiguration();
|
||||||
|
|
||||||
if ($cacheBust)
|
$url = $source->getUrlToPhoto($this, $thumbnailName);
|
||||||
|
|
||||||
|
// Cache busting doesn't work with S3 signed URLs
|
||||||
|
if ($cacheBust && !$sourceConfiguration->s3_signed_urls)
|
||||||
{
|
{
|
||||||
// Append the timestamp of the last update to avoid browser caching
|
// Append the timestamp of the last update to avoid browser caching
|
||||||
$theDate = is_null($this->updated_at) ? $this->created_at : $this->updated_at;
|
$theDate = is_null($this->updated_at) ? $this->created_at : $this->updated_at;
|
||||||
|
@ -0,0 +1,32 @@
|
|||||||
|
<?php
|
||||||
|
|
||||||
|
use Illuminate\Database\Migrations\Migration;
|
||||||
|
use Illuminate\Database\Schema\Blueprint;
|
||||||
|
use Illuminate\Support\Facades\Schema;
|
||||||
|
|
||||||
|
class AddS3SignedUrlsColumnToStoragesTable extends Migration
|
||||||
|
{
|
||||||
|
/**
|
||||||
|
* Run the migrations.
|
||||||
|
*
|
||||||
|
* @return void
|
||||||
|
*/
|
||||||
|
public function up()
|
||||||
|
{
|
||||||
|
Schema::table('storages', function (Blueprint $table) {
|
||||||
|
$table->boolean('s3_signed_urls');
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Reverse the migrations.
|
||||||
|
*
|
||||||
|
* @return void
|
||||||
|
*/
|
||||||
|
public function down()
|
||||||
|
{
|
||||||
|
Schema::table('storages', function (Blueprint $table) {
|
||||||
|
$table->dropColumn('s3_signed_urls');
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
@ -323,7 +323,10 @@ return [
|
|||||||
'photos' => 'photo|photos',
|
'photos' => 'photo|photos',
|
||||||
'users' => 'user|users',
|
'users' => 'user|users',
|
||||||
],
|
],
|
||||||
|
'storage_auth_url_label_help' => 'Leave blank to authenticate with Amazon S3. For an S3-compatible provider, enter your provider\'s authentication URL here.',
|
||||||
'storage_backblaze_access_key_id_help' => 'To use your account\'s master key, enter your account ID here.',
|
'storage_backblaze_access_key_id_help' => 'To use your account\'s master key, enter your account ID here.',
|
||||||
|
'storage_s3_signed_urls_help' => 'When enabled, Blue Twilight will upload your photos with a private ACL and will use signed URLs to display the photos to your visitors.',
|
||||||
|
'storage_s3_signed_urls_tooltip' => 'This location is set to use private images with signed URLs.',
|
||||||
'storage_title' => 'Storage Locations',
|
'storage_title' => 'Storage Locations',
|
||||||
'sysinfo_panel' => 'System information',
|
'sysinfo_panel' => 'System information',
|
||||||
'sysinfo_widget' => [
|
'sysinfo_widget' => [
|
||||||
|
@ -113,6 +113,7 @@ return [
|
|||||||
'storage_driver_label' => 'Storage driver:',
|
'storage_driver_label' => 'Storage driver:',
|
||||||
'storage_endpoint_url_label' => 'Endpoint URL (leave blank if using Amazon):',
|
'storage_endpoint_url_label' => 'Endpoint URL (leave blank if using Amazon):',
|
||||||
'storage_location_label' => 'Physical location:',
|
'storage_location_label' => 'Physical location:',
|
||||||
|
'storage_s3_signed_urls' => 'Upload files privately and use signed URLs',
|
||||||
'storage_secret_key_label' => 'Secret key:',
|
'storage_secret_key_label' => 'Secret key:',
|
||||||
'storage_service_name_label' => 'Service name:',
|
'storage_service_name_label' => 'Service name:',
|
||||||
'storage_service_region_label' => 'Region:',
|
'storage_service_region_label' => 'Region:',
|
||||||
|
@ -61,13 +61,13 @@
|
|||||||
@include(Theme::viewName('partials.admin_storages_rackspace_options'))
|
@include(Theme::viewName('partials.admin_storages_rackspace_options'))
|
||||||
@endif
|
@endif
|
||||||
|
|
||||||
<div v-if="storage_driver == 'BackblazeB2Source'">
|
@if ($storage->source == 'BackblazeB2Source')
|
||||||
<hr/>
|
<hr/>
|
||||||
@include(Theme::viewName('partials.admin_storages_backblaze_b2_options'))
|
@include(Theme::viewName('partials.admin_storages_backblaze_b2_options'))
|
||||||
</div>
|
@endif
|
||||||
|
|
||||||
<div class="text-right">
|
<div class="text-right">
|
||||||
<a href="{{ route('storage.index') }}" class="btn btn-default">@lang('forms.cancel_action')</a>
|
<a href="{{ route('storage.index') }}" class="btn btn-link">@lang('forms.cancel_action')</a>
|
||||||
<button type="submit" class="btn btn-success"><i class="fa fa-fw fa-check"></i> @lang('forms.save_action')</button>
|
<button type="submit" class="btn btn-success"><i class="fa fa-fw fa-check"></i> @lang('forms.save_action')</button>
|
||||||
</div>
|
</div>
|
||||||
</form>
|
</form>
|
||||||
|
@ -39,7 +39,12 @@
|
|||||||
<span style="color: #888; font-style: italic;">
|
<span style="color: #888; font-style: italic;">
|
||||||
@if ($storage->source == 'LocalFilesystemSource'){{ $storage->location }}@endif
|
@if ($storage->source == 'LocalFilesystemSource'){{ $storage->location }}@endif
|
||||||
@if ($storage->source == 'OpenStackSource'){{ $storage->container_name }} - {{ $storage->service_name }}, {{ $storage->service_region }}@endif
|
@if ($storage->source == 'OpenStackSource'){{ $storage->container_name }} - {{ $storage->service_name }}, {{ $storage->service_region }}@endif
|
||||||
@if ($storage->source == 'AmazonS3Source'){{ $storage->container_name }} - {{ $storage->service_region }}@endif
|
@if ($storage->source == 'AmazonS3Source')
|
||||||
|
{{ $storage->container_name }} - {{ $storage->service_region }}
|
||||||
|
@if ($storage->s3_signed_urls)
|
||||||
|
<i class="fa fa-key ml-2" data-toggle="tooltip" title="@lang('admin.storage_s3_signed_urls_tooltip')"></i>
|
||||||
|
@endif
|
||||||
|
@endif
|
||||||
@if ($storage->source == 'RackspaceSource'){{ $storage->container_name }} - {{ $storage->service_region }}@endif
|
@if ($storage->source == 'RackspaceSource'){{ $storage->container_name }} - {{ $storage->service_region }}@endif
|
||||||
</span>
|
</span>
|
||||||
</td>
|
</td>
|
||||||
@ -81,3 +86,11 @@
|
|||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
@endsection
|
@endsection
|
||||||
|
|
||||||
|
@push('scripts')
|
||||||
|
<script type="text/javascript">
|
||||||
|
$(function () {
|
||||||
|
$('[data-toggle="tooltip"]').tooltip()
|
||||||
|
});
|
||||||
|
</script>
|
||||||
|
@endpush
|
@ -55,6 +55,7 @@
|
|||||||
<div class="form-group">
|
<div class="form-group">
|
||||||
<label class="form-control-label" for="auth-url">@lang('forms.storage_auth_url_label')</label>
|
<label class="form-control-label" for="auth-url">@lang('forms.storage_auth_url_label')</label>
|
||||||
<input type="text" class="form-control{{ $errors->has('auth_url') ? ' is-invalid' : '' }}" id="auth-url" name="auth_url" value="{{ old('auth_url', $storage->auth_url) }}">
|
<input type="text" class="form-control{{ $errors->has('auth_url') ? ' is-invalid' : '' }}" id="auth-url" name="auth_url" value="{{ old('auth_url', $storage->auth_url) }}">
|
||||||
|
<small class="form-text text-muted">@lang('admin.storage_auth_url_label_help')</small>
|
||||||
|
|
||||||
@if ($errors->has('auth_url'))
|
@if ($errors->has('auth_url'))
|
||||||
<div class="invalid-feedback">
|
<div class="invalid-feedback">
|
||||||
@ -62,3 +63,11 @@
|
|||||||
</div>
|
</div>
|
||||||
@endif
|
@endif
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
|
<div class="form-check form-group">
|
||||||
|
<input type="checkbox" class="form-check-input" id="s3-signed-urls" name="s3_signed_urls"@if (old('s3_signed_urls', $storage->s3_signed_urls)) checked="checked"@endif>
|
||||||
|
<label for="s3-signed-urls" class="form-check-label">
|
||||||
|
<strong>@lang('forms.storage_s3_signed_urls')</strong><br>
|
||||||
|
@lang('admin.storage_s3_signed_urls_help')
|
||||||
|
</label>
|
||||||
|
</div>
|
Loading…
Reference in New Issue
Block a user