Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

feat: download and get storage files as private #5192

Merged
merged 32 commits into from
Jun 22, 2021
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
32 commits
Select commit Hold shift + click to select a range
cd6b332
feat: download and get storage file as private
asbiin May 15, 2021
3cc265f
Apply fixes from StyleCI
asbiin May 15, 2021
11a8b7f
fix
asbiin May 15, 2021
b3a73e3
Merge branch '20210515-private-avatar-documents' of github.com:monica…
asbiin May 15, 2021
b330232
add If* conditions
asbiin May 16, 2021
d25c74d
fix
asbiin May 16, 2021
a9cab1c
Apply fixes from StyleCI
asbiin May 16, 2021
5fcc11c
fix test
asbiin May 16, 2021
fe6d2a2
fix styleci
asbiin May 16, 2021
1080791
Apply fixes from StyleCI
asbiin May 16, 2021
5137865
add an option to deactivate secure filesystems
asbiin May 16, 2021
b0c3b28
Apply fixes from StyleCI
asbiin May 16, 2021
1578ba1
fix
asbiin May 17, 2021
d0e69b9
Apply fixes from StyleCI
asbiin May 17, 2021
f2b19a3
use etagconditionals
asbiin May 18, 2021
c8a0823
Apply fixes from StyleCI
asbiin May 18, 2021
dcaffe8
fix
asbiin May 19, 2021
49a37d1
Merge branch 'master' into 20210515-private-avatar-documents
asbiin Jun 19, 2021
13b4c11
create a test
asbiin Jun 20, 2021
1d5496b
Apply fixes from StyleCI
asbiin Jun 20, 2021
95b80b9
add more tests
asbiin Jun 20, 2021
73a645c
Merge branch '20210515-private-avatar-documents' of github.com:monica…
asbiin Jun 20, 2021
d26dfc8
Apply fixes from StyleCI
asbiin Jun 20, 2021
bc81c8c
add tests
asbiin Jun 20, 2021
105c7ae
fix tests
asbiin Jun 21, 2021
4082007
more tests
asbiin Jun 21, 2021
61bf6fa
Apply fixes from StyleCI
asbiin Jun 21, 2021
b527ad9
update deps
asbiin Jun 21, 2021
c702874
factorize visibility
asbiin Jun 21, 2021
91fa265
Apply fixes from StyleCI
asbiin Jun 21, 2021
b513fff
Make changes from review
asbiin Jun 22, 2021
e3d6b99
change if order
asbiin Jun 22, 2021
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion app/Console/Commands/OneTime/MoveAvatars.php
Original file line number Diff line number Diff line change
Expand Up @@ -96,7 +96,7 @@ private function moveContactAvatars($contact)
}
if (! $this->option('dryrun')) {
$avatarFile = $storage->get($avatarFileName);
$newStorage->put($avatarFileName, $avatarFile, 'public');
$newStorage->put($avatarFileName, $avatarFile, config('filesystems.default_visibility'));
}

$this->line(' File pushed: '.$avatarFileName, null, OutputInterface::VERBOSITY_VERBOSE);
Expand Down
5 changes: 4 additions & 1 deletion app/Http/Controllers/ContactsController.php
Original file line number Diff line number Diff line change
Expand Up @@ -462,7 +462,10 @@ public function update(Request $request, Contact $contact)
}
$contact->has_avatar = true;
$contact->avatar_location = config('filesystems.default');
$contact->avatar_file_name = $request->avatar->storePublicly('avatars', $contact->avatar_location);
$contact->avatar_file_name = $request->file('avatar')->store('avatars', [
'disk' => $contact->avatar_location,
'visibility' => config('filesystems.default_visibility'),
]);
$contact->save();
}

Expand Down
136 changes: 136 additions & 0 deletions app/Http/Controllers/StorageController.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,136 @@
<?php

namespace App\Http\Controllers;

use Illuminate\Support\Str;
use Illuminate\Http\Request;
use App\Models\Account\Photo;
use App\Helpers\StorageHelper;
use Illuminate\Support\Carbon;
use App\Models\Contact\Contact;
use App\Models\Contact\Document;
use Illuminate\Support\Facades\Response;
use League\Flysystem\FileNotFoundException;

class StorageController extends Controller
{
public function __construct()
{
$this->middleware(['setEtag', 'ifMatch', 'ifNoneMatch']);
}

/**
* Download file with authorization.
*
* @param Request $request
* @param string $file
* @return \Illuminate\Http\Response|\Symfony\Component\HttpFoundation\StreamedResponse|null
*/
public function show(Request $request, string $file)
{
$filename = $this->getFilename($request, $file);

try {
$disk = StorageHelper::disk(config('filesystems.default'));

$lastModified = Carbon::createFromTimestamp($disk->lastModified($file), 'UTC')->locale('en');

$headers = [
'Last-Modified' => $lastModified->isoFormat('ddd\, DD MMM YYYY HH\:mm\:ss \G\M\T'),
'Cache-Control' => config('filesystems.default_cache_control'),
];

if (! $this->checkConditions($request, $lastModified)) {
return Response::noContent(304, $headers)->setNotModified();
}

return $disk->response($file, $filename, $headers);
} catch (FileNotFoundException $e) {
abort(404);
}
}

/**
* Get the filename for this file.
*
* @param Request $request
* @param string $file
* @return string
*/
private function getFilename(Request $request, string $file): string
{
$accountId = $request->user()->account_id;
$folder = Str::before($file, '/');

switch ($folder) {
case 'avatars':
$obj = Contact::where([
'account_id' => $accountId,
['avatar_default_url', 'like', "$file%"],
])->first();
$filename = Str::after($file, '/');
break;

case 'photos':
$obj = Photo::where([
'account_id' => $accountId,
'new_filename' => $file,
])->first();
$filename = $obj ? $obj->original_filename : null;
break;

case 'documents':
$obj = Document::where([
'account_id' => $accountId,
'new_filename' => $file,
])->first();
$filename = $obj ? $obj->original_filename : null;
break;

default:
$obj = false;
$filename = null;
break;
}

if ($obj === false || $obj === null || ! $obj->exists) {
abort(404);
}

return $filename;
}

/**
* Check for If-Modified-Since and If-Unmodified-Since conditions.
* Return true if the condition does not match.
*
* @param Request $request
* @param Carbon $lastModified Last modified date
* @return bool
*/
private function checkConditions(Request $request, Carbon $lastModified): bool
{
if (! $request->header('If-None-Match') && ($ifModifiedSince = $request->header('If-Modified-Since'))) {
// The If-Modified-Since header contains a date. We will only
// return the entity if it has been changed since that date.
$date = Carbon::parse($ifModifiedSince);

if ($lastModified->lessThanOrEqualTo($date)) {
return false;
}
}

if ($ifUnmodifiedSince = $request->header('If-Unmodified-Since')) {
// The If-Unmodified-Since will allow the request if the
// entity has not changed since the specified date.
$date = Carbon::parse($ifUnmodifiedSince);

// We must only check the date if it's valid
if ($lastModified->greaterThan($date)) {
abort(412, 'An If-Unmodified-Since header was specified, but the entity has been changed since the specified date.');
}
}

return true;
}
}
2 changes: 1 addition & 1 deletion app/Jobs/Avatars/MoveContactAvatarToPhotosDirectory.php
Original file line number Diff line number Diff line change
Expand Up @@ -103,7 +103,7 @@ private function moveContactAvatars(): ?string

if (! $this->dryrun) {
$avatarFile = $this->storage->get($avatarFileName);
$newStorage->put($newAvatarFilename, $avatarFile, 'public');
$newStorage->put($newAvatarFilename, $avatarFile, config('filesystems.default_visibility'));

$this->contact->avatar_location = config('filesystems.default');
$this->contact->save();
Expand Down
2 changes: 1 addition & 1 deletion app/Jobs/ResizeAvatars.php
Original file line number Diff line number Diff line change
Expand Up @@ -63,6 +63,6 @@ private function resize($avatarFile, $filename, $extension, $storage, $size)
$avatar = Image::make($avatarFile);
$avatar->fit($size);

$storage->put($avatarFileName, (string) $avatar->stream(), 'public');
$storage->put($avatarFileName, (string) $avatar->stream(), config('filesystems.default_visibility'));
}
}
6 changes: 4 additions & 2 deletions app/Models/Account/Photo.php
Original file line number Diff line number Diff line change
Expand Up @@ -64,9 +64,11 @@ public function contact()
*/
public function url()
{
$url = $this->new_filename;
if (config('filesystems.default_visibility') === 'public') {
return asset(StorageHelper::disk(config('filesystems.default'))->url($this->new_filename));
}

return asset(StorageHelper::disk(config('filesystems.default'))->url($url));
return route('storage', ['file' => $this->new_filename]);
}

/**
Expand Down
12 changes: 6 additions & 6 deletions app/Models/Contact/Contact.php
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,6 @@
use App\Helpers\LocaleHelper;
use App\Models\Account\Photo;
use App\Models\Journal\Entry;
use function Safe\preg_split;
use App\Helpers\StorageHelper;
use App\Helpers\WeatherHelper;
use Illuminate\Support\Carbon;
Expand Down Expand Up @@ -1049,17 +1048,18 @@ public function getAvatarDefaultURL()
return '';
}

try {
$matches = preg_split('/\?/', $this->avatar_default_url);
if (config('filesystems.default_visibility') === 'public') {
$matches = Str::of($this->avatar_default_url)->split('/\?/');

$url = asset(StorageHelper::disk(config('filesystems.default'))->url($matches[0]));
if (count($matches) > 1) {
if ($matches->count() > 1) {
$url .= '?'.$matches[1];
}

return $url;
} catch (\Exception $e) {
return '';
}

return route('storage', ['file' => $this->avatar_default_url]);
}

/**
Expand Down
6 changes: 4 additions & 2 deletions app/Models/Contact/Document.php
Original file line number Diff line number Diff line change
Expand Up @@ -59,8 +59,10 @@ public function contact()
*/
public function getDownloadLink(): string
{
$url = $this->new_filename;
if (config('filesystems.default_visibility') === 'public') {
return asset(StorageHelper::disk(config('filesystems.default'))->url($this->new_filename));
}

return asset(StorageHelper::disk(config('filesystems.default'))->url($url));
return route('storage', ['file' => $this->new_filename]);
}
}
10 changes: 10 additions & 0 deletions app/Providers/AppServiceProvider.php
Original file line number Diff line number Diff line change
Expand Up @@ -10,11 +10,13 @@
use Illuminate\Pagination\Paginator;
use Illuminate\Support\Facades\View;
use App\Notifications\EmailMessaging;
use Illuminate\Support\Facades\Cache;
use Illuminate\Support\Facades\Schema;
use Illuminate\Support\ServiceProvider;
use Illuminate\Cache\RateLimiting\Limit;
use Illuminate\Support\Facades\RateLimiter;
use Illuminate\Auth\Notifications\VerifyEmail;
use Werk365\EtagConditionals\EtagConditionals;
use Illuminate\Auth\Notifications\ResetPassword;

class AppServiceProvider extends ServiceProvider
Expand Down Expand Up @@ -74,6 +76,14 @@ public function boot()
Limit::perDay(5000),
];
});

EtagConditionals::etagGenerateUsing(function (\Illuminate\Http\Request $request, \Symfony\Component\HttpFoundation\Response $response) {
$url = $request->getRequestUri();

return Cache::rememberForever('etag.'.$url, function () use ($url) {
return md5($url);
});
});
}

/**
Expand Down
7 changes: 5 additions & 2 deletions app/Services/Account/Photo/UploadPhoto.php
Original file line number Diff line number Diff line change
Expand Up @@ -84,7 +84,10 @@ private function importPhoto($data): array
'original_filename' => $photo->getClientOriginalName(),
'filesize' => $photo->getSize(),
'mime_type' => (new \Mimey\MimeTypes)->getMimeType($photo->guessClientExtension()),
'new_filename' => $photo->storePublicly('photos', config('filesystems.default')),
'new_filename' => $photo->store('photos', [
'disk' => config('filesystems.default'),
'visibility' => config('filesystems.default_visibility'),
]),
];
}

Expand Down Expand Up @@ -146,7 +149,7 @@ private function importFile(array $data): ?array
private function storeImage(string $disk, $image, string $filename): ?string
{
$result = Storage::disk($disk)
->put($path = $filename, (string) $image->stream(), 'public');
->put($path = $filename, (string) $image->stream(), config('filesystems.default_visibility'));

return $result ? $path : null;
}
Expand Down
5 changes: 4 additions & 1 deletion app/Services/Contact/Avatar/GenerateDefaultAvatar.php
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@
use Illuminate\Support\Str;
use App\Services\BaseService;
use App\Models\Contact\Contact;
use Illuminate\Support\Facades\Cache;
use Laravolt\Avatar\Facade as Avatar;
use Illuminate\Support\Facades\Storage;
use Illuminate\Contracts\Filesystem\FileNotFoundException;
Expand Down Expand Up @@ -47,6 +48,8 @@ public function execute(array $data)
$contact->avatar_default_url = $filename;
$contact->save();

Cache::forget('etag'.Str::before('?', $filename));

return $contact;
}

Expand Down Expand Up @@ -83,7 +86,7 @@ private function createNewAvatar(Contact $contact)

$filename = 'avatars/'.$contact->uuid.'.jpg';
Storage::disk(config('filesystems.default'))
->put($filename, $img, 'public');
->put($filename, $img, config('filesystems.default_visibility'));

// This will force the browser to reload the new avatar
return $filename.'?'.now()->format('U');
Expand Down
5 changes: 4 additions & 1 deletion app/Services/Contact/Document/UploadDocument.php
Original file line number Diff line number Diff line change
Expand Up @@ -65,7 +65,10 @@ private function populateData($data)
'mime_type' => (new \Mimey\MimeTypes)->getMimeType($document->guessClientExtension()),
];

$filename = $document->storePublicly('documents', config('filesystems.default'));
$filename = $document->store('documents', [
'disk' => config('filesystems.default'),
'visibility' => config('filesystems.default_visibility'),
]);

return array_merge($data, [
'new_filename' => $filename,
Expand Down
1 change: 1 addition & 0 deletions composer.json
Original file line number Diff line number Diff line change
Expand Up @@ -57,6 +57,7 @@
"web-token/jwt-signature-algorithm-ecdsa": "^2.1",
"web-token/jwt-signature-algorithm-eddsa": "^2.1",
"web-token/jwt-signature-algorithm-rsa": "^2.1",
"werk365/etagconditionals": "^1.2",
"xantios/mimey": "^2.0"
},
"require-dev": {
Expand Down
Loading