protected sharing update

This commit is contained in:
carodej
2020-04-24 12:50:11 +02:00
parent c4b26d70b5
commit 586f0bba68
22 changed files with 446 additions and 164 deletions

View File

@@ -59,7 +59,7 @@ class AuthController extends Controller
$data = json_decode($response->content(), true);
return response('Login Successfull!', 200)->cookie('token', $data['access_token'], 43200);
return response('Login Successfull!', 200)->cookie('access_token', $data['access_token'], 43200);
} else {
return $response;
@@ -118,7 +118,7 @@ class AuthController extends Controller
$token->delete();
});
return response('Logout successfull', 200)->cookie('token', '', -1);
return response('Logout successfull', 200)->cookie('access_token', '', -1);
}
/**

View File

@@ -2,52 +2,19 @@
namespace App\Http\Controllers;
use App\FileManagerFolder;
use App\Share;
use Illuminate\Support\Arr;
use Illuminate\Support\Facades\Auth;
use Illuminate\Support\Facades\DB;
use Illuminate\Support\Facades\File;
use Illuminate\Http\Request;
use App\FileManagerFile;
use Illuminate\Support\Str;
use Response;
class FileAccessController extends Controller
{
/**
* Get file
*
* @param $filename
* @return mixed
*/
public function get_file($filename)
{
// Get user id
$user_id = Auth::id();
// Get file record
$file = FileManagerFile::withTrashed()
->where('user_id', $user_id)
->where('basename', $filename)
->firstOrFail();
// Get file path
$path = storage_path() . '/app/file-manager/' . $file->basename;
// Check if file exist
if (!File::exists($path)) abort(404);
$file = File::get($path);
$type = File::mimeType($path);
$size = File::size($path);
// Create response
$response = Response::make($file, 200);
$response->header("Content-Type", $type);
$response->header("Content-Disposition", 'attachment; filename=' . $filename);
$response->header("Content-Length", $size);
$response->header("Accept-Ranges", "bytes");
$response->header("Content-Range", "bytes 0-" . $size . "/" . $size);
return $response;
}
/**
* Get avatar
*
@@ -73,12 +40,13 @@ class FileAccessController extends Controller
}
/**
* Get image thumbnail
* Get file
*
* @param Request $request
* @param $filename
* @return mixed
*/
public function get_thumbnail($filename)
public function get_file(Request $request, $filename)
{
// Get user id
$user_id = Auth::id();
@@ -86,26 +54,57 @@ class FileAccessController extends Controller
// Get file record
$file = FileManagerFile::withTrashed()
->where('user_id', $user_id)
->where('basename', $filename)
->firstOrFail();
// Check user permission
if ( ! $request->user()->tokenCan('master') ) {
$this->check_access($request, $file);
}
// Format pretty filename
$file_pretty_name = $file->name . '.' . $file->mimetype;
// Get file path
$path = storage_path() . '/app/file-manager/' . $file->basename;
// Check if file exist
if (!File::exists($path)) abort(404);
$file = File::get($path);
$type = File::mimeType($path);
$size = File::size($path);
// Create response
$response = Response::make($file, 200);
$response->header("Content-Type", $type);
$response->header("Content-Disposition", 'attachment; filename=' . $file_pretty_name);
$response->header("Content-Length", $size);
$response->header("Accept-Ranges", "bytes");
$response->header("Content-Range", "bytes 0-" . $size . "/" . $size);
return $response;
}
/**
* Get image thumbnail
*
* @param Request $request
* @param $filename
* @return mixed
*/
public function get_thumbnail(Request $request, $filename)
{
// Get file record
$file = FileManagerFile::withTrashed()
->where('user_id', $request->user()->id)
->where('thumbnail', $filename)
->firstOrFail();
/* if ($request->has('token')) {
// Get sharing record
$shared = Share::where('token', $request->token)->firstOrFail();
// Get all children folders
$foldersIds = FileManagerFolder::with('folders:id,parent_id,unique_id,name')
->where('user_id', $user_id)
->where('parent_id', $shared->item_id)
->get();
// Get all authorized parent folders by shared folder as root of tree
$authorized_parent_folder_ids = Arr::flatten([filter_folders_ids($foldersIds), $shared->item_id]);
// Check user access
if ( ! in_array($file->folder_id, $authorized_parent_folder_ids)) abort(401);
}*/
// Check user permission
if ( ! $request->user()->tokenCan('master') ) {
$this->check_access($request, $file);
}
// Get file path
$path = storage_path() . '/app/file-manager/' . $file->getOriginal('thumbnail');
@@ -122,4 +121,40 @@ class FileAccessController extends Controller
return $response;
}
/**
* Check user file access
*
* @param $request
*/
protected function check_access($request, $file): void
{
// check if shared_token cookie exist
if (! $request->hasCookie('shared_token')) abort('401');
// Get shared token
$shared = Share::where(DB::raw('BINARY `token`'), $request->cookie('shared_token'))
->first();
// Check by parent folder permission
if ($shared->type === 'folder') {
// Get all children folders
$foldersIds = FileManagerFolder::with('folders:id,parent_id,unique_id,name')
->where('user_id', $shared->user_id)
->where('parent_id', $shared->item_id)
->get();
// Get all authorized parent folders by shared folder as root of tree
$accessible_folder_ids = Arr::flatten([filter_folders_ids($foldersIds), $shared->item_id]);
// Check user access
if (!in_array($file->folder_id, $accessible_folder_ids)) abort(403);
}
// Check by single file permission
if ($shared->type === 'file') {
if ($shared->item_id !== $file->unique_id) abort(403);
}
}
}

View File

@@ -5,6 +5,7 @@ namespace App\Http\Controllers\FileFunctions;
use App\Share;
use Illuminate\Support\Arr;
use Illuminate\Support\Facades\Auth;
use Illuminate\Support\Facades\DB;
use Intervention\Image\ImageManagerStatic as Image;
use Illuminate\Support\Facades\Validator;
use Illuminate\Support\Facades\Storage;
@@ -26,6 +27,11 @@ class EditController extends Controller
*/
public function create_folder(Request $request)
{
// Check permission to create folder for authenticated public editor
if ( ! $request->user()->tokenCan('master') ) {
$this->check_access($request, $request->parent_id);
}
// Validate request
$validator = Validator::make($request->all(), [
'parent_id' => 'required|integer',
@@ -45,6 +51,7 @@ class EditController extends Controller
'name' => $request->has('name') ? $request->input('name') : 'New Folder',
'type' => 'folder',
'unique_id' => $this->get_unique_id(),
'user_scope' => $request->user()->token()->scopes[0],
]);
// Return new folder
@@ -79,6 +86,11 @@ class EditController extends Controller
->where('user_id', $user_id)
->firstOrFail();
// Check permission to rename for authenticated public editor
if ( ! $request->user()->tokenCan('master') ) {
$this->check_access($request, $item->unique_id);
}
$item->name = $request->name;
$item->save();
@@ -88,6 +100,11 @@ class EditController extends Controller
->where('user_id', $user_id)
->firstOrFail();
// Check permission to rename for authenticated public editor
if ( ! $request->user()->tokenCan('master') ) {
$this->check_access($request, $item->folder_id);
}
$item->name = $request->name;
$item->save();
}
@@ -127,6 +144,11 @@ class EditController extends Controller
->where('unique_id', $request->unique_id)
->first();
// Check permission to delete for authenticated public editor
if ( ! $request->user()->tokenCan('master') ) {
$this->check_access($request, $folder->unique_id);
}
// Force delete children files
if ($request->force_delete) {
@@ -170,6 +192,11 @@ class EditController extends Controller
->where('unique_id', $request->unique_id)
->first();
// Check permission to delete for authenticated public editor
if ( ! $request->user()->tokenCan('master') ) {
$this->check_access($request, $file->folder_id);
}
if ($request->force_delete) {
// Delete file
@@ -196,9 +223,13 @@ class EditController extends Controller
*/
public function upload_item(Request $request)
{
// Check permission to upload for authenticated public editor
if ( ! $request->user()->tokenCan('master') ) {
$this->check_access($request, $request->parent_id);
}
// Check if user can upload
if (config('vuefilemanager.limit_storage_by_capacity') && user_storage_percentage() >= 100) {
abort(423, 'You exceed your storage limit!');
}
@@ -248,15 +279,16 @@ class EditController extends Controller
// Store file
$new_file = FileManagerFile::create([
'user_id' => Auth::id(),
'name' => pathinfo($file->getClientOriginalName())['filename'],
'basename' => $filename,
'folder_id' => $folder_id,
'mimetype' => $file->getClientOriginalExtension(),
'filesize' => $filesize,
'type' => $filetype,
'thumbnail' => $thumbnail,
'unique_id' => $this->get_unique_id(),
'user_id' => Auth::id(),
'name' => pathinfo($file->getClientOriginalName())['filename'],
'basename' => $filename,
'folder_id' => $folder_id,
'mimetype' => $file->getClientOriginalExtension(),
'filesize' => $filesize,
'type' => $filetype,
'thumbnail' => $thumbnail,
'unique_id' => $this->get_unique_id(),
'user_scope' => $request->user()->token()->scopes[0],
]);
return $new_file;
@@ -327,4 +359,31 @@ class EditController extends Controller
return $unique_id;
}
/**
* Check if user has access to requested folder
*
* @param $request
*/
protected function check_access($request, $parent_id): void
{
// check if shared_token cookie exist
if (! $request->hasCookie('shared_token')) abort('401');
// Get shared token
$shared = Share::where(DB::raw('BINARY `token`'), $request->cookie('shared_token'))
->firstOrFail();
// Get all children folders
$foldersIds = FileManagerFolder::with('folders:id,parent_id,unique_id,name')
->where('user_id', $shared->user_id)
->where('parent_id', $shared->item_id)
->get();
// Get all authorized parent folders by shared folder as root of tree
$accessible_folder_ids = Arr::flatten([filter_folders_ids($foldersIds), $shared->item_id]);
// Check user access
if (!in_array($parent_id, $accessible_folder_ids)) abort(403);
}
}

View File

@@ -5,6 +5,7 @@ namespace App\Http\Controllers\FileFunctions;
use Illuminate\Contracts\Routing\ResponseFactory;
use App\Http\Controllers\Controller;
use Illuminate\Support\Facades\Auth;
use Illuminate\Support\Facades\DB;
use Illuminate\Support\Facades\Hash;
use Illuminate\Http\Request;
use Illuminate\Support\Arr;
@@ -28,7 +29,7 @@ class ShareController extends Controller
// Generate unique token
$token = Str::random(16);
} while (Share::where('token', $token)->exists());
} while (Share::where(DB::raw('BINARY `token`'), $token)->exists());
// Create shared options
$options = [

View File

@@ -3,6 +3,9 @@
namespace App\Http\Controllers\Sharing;
use App\Http\Controllers\Controller;
use Illuminate\Contracts\View\Factory;
use Illuminate\Support\Facades\Cookie;
use Illuminate\Support\Facades\DB;
use Illuminate\Support\Facades\Hash;
use Illuminate\Support\Collection;
use Illuminate\Http\Request;
@@ -14,16 +17,42 @@ use App\Share;
class FileSharingController extends Controller
{
/**
* Show page index and delete access_token & shared_token cookie
*
* @return Factory|\Illuminate\View\View
*/
public function index($token)
{
// Get shared token
$shared = Share::where(DB::raw('BINARY `token`'), $token)
->firstOrFail(['token', 'item_id', 'type', 'permission', 'protected']);
// Delete old access_token if exist
Cookie::queue('access_token', '', -1);
// Set cookies
if ($shared->protected) {
// Set shared token
Cookie::queue('shared_token', $token, 43200);
}
// Return page index
return view("index");
}
/**
* Get shared record
*
* @param Request $request
* @return mixed
*/
public function index($token)
public function show($token)
{
// Get sharing record
return Share::where('token', $token)
return Share::where(DB::raw('BINARY `token`'), $token)
->firstOrFail(['token', 'item_id', 'type', 'permission', 'protected']);
}
@@ -39,7 +68,7 @@ class FileSharingController extends Controller
// TODO: validacia
// Get sharing record
$shared = Share::where('token', $token)->firstOrFail();
$shared = Share::where(DB::raw('BINARY `token`'), $token)->firstOrFail();
// Check password
if (!Hash::check($request->password, $shared->password)) {
@@ -54,12 +83,12 @@ class FileSharingController extends Controller
$scope = !is_null($shared->permission) ? $shared->permission : 'visitor';
// Generate token for visitor/editor
$token = $user->createToken('token', [$scope])->accessToken;
$token = $user->createToken('access_token', [$scope])->accessToken;
// Return authorize token with shared options
return response(Arr::except($shared, ['password', 'user_id', 'updated_at', 'created_at']), 200)
->cookie('shared_token', $shared->token, 43200)
->cookie('token', $token, 43200);
->cookie('access_token', $token, 43200);
}
/**
@@ -72,14 +101,11 @@ class FileSharingController extends Controller
public function browse_private(Request $request, $unique_id)
{
// Check if token exist
if (!$request->has('token'))
if (! $request->hasCookie('shared_token') )
abort(404, "Sorry, you don't request any content");
// Get sharing record
$shared = Share::where('token', $request->token)->firstOrFail();
// Check directory authentication
$this->check_authenticated_access($request);
$shared = Share::where('token', $request->cookie('shared_token'))->firstOrFail();
// Check if user can get directory
$this->check_folder_access($unique_id, $shared);
@@ -104,15 +130,10 @@ class FileSharingController extends Controller
* @param $unique_id
* @return Collection
*/
public function browse_public(Request $request, $unique_id)
public function browse_public($token, $unique_id)
{
// Check if token exist
if (!$request->has('token'))
abort(404, "Sorry, you don't request any content");
// Get sharing record
$shared = Share::where('token', $request->token)->firstOrFail();
$shared = Share::where(DB::raw('BINARY `token`'), $token)->firstOrFail();
// Abort if folder is protected
if ($shared->protected) {
@@ -154,7 +175,7 @@ class FileSharingController extends Controller
public function file_public($token)
{
// Get sharing record
$shared = Share::where('token', $token)->firstOrFail();
$shared = Share::where(DB::raw('BINARY `token`'), $token)->firstOrFail();
// Abort if file is protected
if ($shared->protected) {
@@ -173,13 +194,10 @@ class FileSharingController extends Controller
* @param $token
* @return mixed
*/
public function file_private(Request $request, $token)
public function file_private(Request $request)
{
// Get sharing record
$shared = Share::where('token', $token)->firstOrFail();
// Check file authentication
$this->check_authenticated_access($request);
$shared = Share::where('token', $request->cookie('shared_token'))->firstOrFail();
// Return record
return FileManagerFile::where('user_id', $shared->user_id)
@@ -202,10 +220,10 @@ class FileSharingController extends Controller
->get();
// Get all authorized parent folders by shared folder as root of tree
$authorized_parent_folder_ids = Arr::flatten([filter_folders_ids($foldersIds), $shared->item_id]);
$accessible_folder_ids = Arr::flatten([filter_folders_ids($foldersIds), $shared->item_id]);
// Check user access
if (!in_array($unique_id, $authorized_parent_folder_ids)) abort(401);
if (!in_array($unique_id, $accessible_folder_ids)) abort(401);
}
/**

View File

@@ -17,11 +17,11 @@ class CookieAuth
public function handle($request, Closure $next)
{
if (!$request->bearerToken()) {
if ($request->hasCookie('token')) {
if ($request->hasCookie('access_token')) {
$token = $request->cookie('token');
$access_token = $request->cookie('access_token');
$request->headers->add(['Authorization' => 'Bearer ' . $token]);
$request->headers->add(['Authorization' => 'Bearer ' . $access_token]);
} else {
abort(401);

View File

@@ -0,0 +1,32 @@
<?php
use Illuminate\Database\Migrations\Migration;
use Illuminate\Database\Schema\Blueprint;
use Illuminate\Support\Facades\Schema;
class AddUserScopeToFileManagerFilesTable extends Migration
{
/**
* Run the migrations.
*
* @return void
*/
public function up()
{
Schema::table('file_manager_files', function (Blueprint $table) {
$table->string('user_scope')->after('type')->default('master');
});
}
/**
* Reverse the migrations.
*
* @return void
*/
public function down()
{
Schema::table('file_manager_files', function (Blueprint $table) {
//
});
}
}

View File

@@ -0,0 +1,32 @@
<?php
use Illuminate\Database\Migrations\Migration;
use Illuminate\Database\Schema\Blueprint;
use Illuminate\Support\Facades\Schema;
class AddUserScopeToFileManagerFoldersTable extends Migration
{
/**
* Run the migrations.
*
* @return void
*/
public function up()
{
Schema::table('file_manager_folders', function (Blueprint $table) {
$table->string('user_scope')->after('type')->default('master');
});
}
/**
* Reverse the migrations.
*
* @return void
*/
public function down()
{
Schema::table('file_manager_folders', function (Blueprint $table) {
//
});
}
}

View File

@@ -254,5 +254,51 @@
"/js/main.4ca90bdb0b28a0bac77f.hot-update.js": "/js/main.4ca90bdb0b28a0bac77f.hot-update.js",
"/js/main.84c1025500258c824186.hot-update.js": "/js/main.84c1025500258c824186.hot-update.js",
"/js/main.801e23504da473fa4b55.hot-update.js": "/js/main.801e23504da473fa4b55.hot-update.js",
"/js/main.32006f8d1211bd1ac2d7.hot-update.js": "/js/main.32006f8d1211bd1ac2d7.hot-update.js"
"/js/main.32006f8d1211bd1ac2d7.hot-update.js": "/js/main.32006f8d1211bd1ac2d7.hot-update.js",
"/js/main.6a8d550c3990db7478c9.hot-update.js": "/js/main.6a8d550c3990db7478c9.hot-update.js",
"/js/main.5004134af690ec32aab1.hot-update.js": "/js/main.5004134af690ec32aab1.hot-update.js",
"/js/main.41634a1144614d807088.hot-update.js": "/js/main.41634a1144614d807088.hot-update.js",
"/js/main.d5f5f898597444704b60.hot-update.js": "/js/main.d5f5f898597444704b60.hot-update.js",
"/js/main.1e664feef8de56e212bf.hot-update.js": "/js/main.1e664feef8de56e212bf.hot-update.js",
"/js/main.7d581e0210378fd8757b.hot-update.js": "/js/main.7d581e0210378fd8757b.hot-update.js",
"/js/main.43b5aacba74bd554e95c.hot-update.js": "/js/main.43b5aacba74bd554e95c.hot-update.js",
"/js/main.ad3ea3b4851e9f50bb7f.hot-update.js": "/js/main.ad3ea3b4851e9f50bb7f.hot-update.js",
"/js/main.bdf1d8ae0bd5f0c94dff.hot-update.js": "/js/main.bdf1d8ae0bd5f0c94dff.hot-update.js",
"/js/main.69ba7f1ac532e280a94a.hot-update.js": "/js/main.69ba7f1ac532e280a94a.hot-update.js",
"/js/main.d987f755c87ecbfa5a54.hot-update.js": "/js/main.d987f755c87ecbfa5a54.hot-update.js",
"/js/main.0c8af3123ef7c883d969.hot-update.js": "/js/main.0c8af3123ef7c883d969.hot-update.js",
"/js/main.187b03b68915fef4bcb1.hot-update.js": "/js/main.187b03b68915fef4bcb1.hot-update.js",
"/js/main.dffcb583fa1d4ecffc97.hot-update.js": "/js/main.dffcb583fa1d4ecffc97.hot-update.js",
"/js/main.ddca0fc165dac2a29682.hot-update.js": "/js/main.ddca0fc165dac2a29682.hot-update.js",
"/js/main.c17ff75670faa18dd933.hot-update.js": "/js/main.c17ff75670faa18dd933.hot-update.js",
"/js/main.c3eb6b86b455442d8462.hot-update.js": "/js/main.c3eb6b86b455442d8462.hot-update.js",
"/js/main.77c52a7cc53e20947fd7.hot-update.js": "/js/main.77c52a7cc53e20947fd7.hot-update.js",
"/js/main.a616e4cc7a01e8eed242.hot-update.js": "/js/main.a616e4cc7a01e8eed242.hot-update.js",
"/js/main.112dc6ed841f7b808cd8.hot-update.js": "/js/main.112dc6ed841f7b808cd8.hot-update.js",
"/js/main.803859a312ac4e748eff.hot-update.js": "/js/main.803859a312ac4e748eff.hot-update.js",
"/js/main.20cbb4dd19418a5ff851.hot-update.js": "/js/main.20cbb4dd19418a5ff851.hot-update.js",
"/js/main.e25f013b63dc4f541703.hot-update.js": "/js/main.e25f013b63dc4f541703.hot-update.js",
"/js/main.77b2e8162a148bf7a03e.hot-update.js": "/js/main.77b2e8162a148bf7a03e.hot-update.js",
"/js/main.a0f4da8f4727cc6aa706.hot-update.js": "/js/main.a0f4da8f4727cc6aa706.hot-update.js",
"/js/main.810f0d4e727c93679a80.hot-update.js": "/js/main.810f0d4e727c93679a80.hot-update.js",
"/js/main.5953d70bc531273f9b20.hot-update.js": "/js/main.5953d70bc531273f9b20.hot-update.js",
"/js/main.af6b95d41bf9c597c9d1.hot-update.js": "/js/main.af6b95d41bf9c597c9d1.hot-update.js",
"/js/main.b47cb69eb422e75a2ab1.hot-update.js": "/js/main.b47cb69eb422e75a2ab1.hot-update.js",
"/js/main.4147f07ef2cb895c2cfa.hot-update.js": "/js/main.4147f07ef2cb895c2cfa.hot-update.js",
"/js/main.2804ef0f8afb2870c619.hot-update.js": "/js/main.2804ef0f8afb2870c619.hot-update.js",
"/js/main.375bcf3d9411d45c5e8c.hot-update.js": "/js/main.375bcf3d9411d45c5e8c.hot-update.js",
"/js/main.92e2e5e9645d0695e9d8.hot-update.js": "/js/main.92e2e5e9645d0695e9d8.hot-update.js",
"/js/main.ba0c049a37bf7b2a6b79.hot-update.js": "/js/main.ba0c049a37bf7b2a6b79.hot-update.js",
"/js/main.1ef909b95fa306a007d7.hot-update.js": "/js/main.1ef909b95fa306a007d7.hot-update.js",
"/js/main.890b46569bf4f0d2d100.hot-update.js": "/js/main.890b46569bf4f0d2d100.hot-update.js",
"/js/main.c93eb7f3891224263841.hot-update.js": "/js/main.c93eb7f3891224263841.hot-update.js",
"/js/main.e8ed183cd2e394932a9d.hot-update.js": "/js/main.e8ed183cd2e394932a9d.hot-update.js",
"/js/main.a77ed20147d5635562a9.hot-update.js": "/js/main.a77ed20147d5635562a9.hot-update.js",
"/js/main.4ed3ccf3488d1d2a2734.hot-update.js": "/js/main.4ed3ccf3488d1d2a2734.hot-update.js",
"/js/main.0d144f90bc5ed08d20d7.hot-update.js": "/js/main.0d144f90bc5ed08d20d7.hot-update.js",
"/js/main.d0f95d4ae27cb5a01879.hot-update.js": "/js/main.d0f95d4ae27cb5a01879.hot-update.js",
"/js/main.591c675411457ff698d7.hot-update.js": "/js/main.591c675411457ff698d7.hot-update.js",
"/js/main.cccd40ca7d095723a593.hot-update.js": "/js/main.cccd40ca7d095723a593.hot-update.js",
"/js/main.a109b65ef389a64af5d7.hot-update.js": "/js/main.a109b65ef389a64af5d7.hot-update.js",
"/js/main.22245e61bfcf217f706c.hot-update.js": "/js/main.22245e61bfcf217f706c.hot-update.js"
}

View File

@@ -70,7 +70,7 @@
</ul>
<!--ContextMenu for Base location with EDITOR permission-->
<ul v-if="$isThisLocation(['base']) && $checkPermission('editor')" class="menu-options" ref="list">
<ul v-if="$isThisLocation(['base', 'public']) && $checkPermission('editor')" class="menu-options" ref="list">
<li class="menu-option" @click="createFolder">
{{ $t('context_menu.create_folder') }}
</li>
@@ -89,7 +89,7 @@
</ul>
<!--ContextMenu for Base location with VISITOR permission-->
<ul v-if="$isThisLocation(['base']) && $checkPermission('visitor')" class="menu-options" ref="list">
<ul v-if="$isThisLocation(['base', 'public']) && $checkPermission('visitor')" class="menu-options" ref="list">
<li class="menu-option" @click="ItemDetail" v-if="item">
{{ $t('context_menu.detail') }}
</li>

View File

@@ -27,6 +27,12 @@
<span>{{ fileInfoDetail.filesize }}</span>
</li>
<!--Latest change-->
<li v-if="$checkPermission(['master']) && fileInfoDetail.user_scope !== 'master'" class="list-info-item">
<b>Author</b>
<span>Public Participant</span>
</li>
<!--Latest change-->
<li class="list-info-item">
<b>{{ $t('file_detail.created_at') }}</b>
@@ -34,7 +40,7 @@
</li>
<!--Parent-->
<li v-if="$checkPermission(['master', 'editor'])" class="list-info-item">
<li v-if="$checkPermission(['master'])" class="list-info-item">
<b>{{ $t('file_detail.where') }}</b>
<div class="action-button" @click="moveItem">
<FontAwesomeIcon class="icon" icon="pencil-alt" />
@@ -49,7 +55,10 @@
<FontAwesomeIcon class="icon" :icon="sharedIcon" />
<span>{{ sharedInfo }}</span>
</div>
<CopyInput class="copy-sharelink" size="small" :value="fileInfoDetail.shared.link" />
<div class="sharelink">
<FontAwesomeIcon class="lock-icon" :icon="lockIcon" @click="shareItemOptions" />
<CopyInput class="copy-sharelink" size="small" :value="fileInfoDetail.shared.link" />
</div>
</li>
</ul>
</div>
@@ -112,6 +121,9 @@
return 'download'
}
},
lockIcon() {
return this.fileInfoDetail.shared.protected ? 'lock' : 'lock-open'
}
},
methods: {
shareItemOptions() {
@@ -142,7 +154,7 @@
.flex {
display: flex;
align-items: top;
align-items: flex-start;
}
.icon-preview {
@@ -238,8 +250,34 @@
}
}
.copy-sharelink {
.sharelink {
display: flex;
width: 100%;
align-items: center;
margin-top: 10px;
.lock-icon {
@include font-size(10);
display: inline-block;
width: 10px;
margin-right: 9px;
cursor: pointer;
path {
fill: $text;
}
&:hover {
path {
fill: $theme;
}
}
}
.copy-sharelink {
width: 100%;
}
}
@media (prefers-color-scheme: dark) {

View File

@@ -41,7 +41,7 @@
<!--Name-->
<b
ref="name"
@input="changeItemName"
@input="renameItem"
:contenteditable="canEditName"
class="name"
>
@@ -177,12 +177,12 @@
}
}
},
changeItemName: debounce(function (e) {
renameItem: debounce(function (e) {
// Prevent submit empty string
if (e.target.innerText === '') return
this.$store.dispatch('changeItemName', {
this.$store.dispatch('renameItem', {
unique_id: this.data.unique_id,
type: this.data.type,
name: e.target.innerText

View File

@@ -39,7 +39,7 @@
<!--Name-->
<b
ref="name"
@input="changeItemName"
@input="renameItem"
:contenteditable="canEditName"
class="name"
>
@@ -53,6 +53,11 @@
<FontAwesomeIcon class="shared-icon" icon="user-friends"/>
</div>
<!--Participant owner Icon-->
<div v-if="$checkPermission('master') && data.user_scope !== 'master'" class="item-shared">
<FontAwesomeIcon class="shared-icon" icon="user-edit"/>
</div>
<!--Filesize and timestamp-->
<span v-if="! isFolder" class="item-size">{{ data.filesize }}, {{ timeStamp }}</span>
@@ -192,12 +197,12 @@
}
}
},
changeItemName: debounce(function (e) {
renameItem: debounce(function (e) {
// Prevent submit empty string
if (e.target.innerText === '') return
this.$store.dispatch('changeItemName', {
this.$store.dispatch('renameItem', {
unique_id: this.data.unique_id,
type: this.data.type,
name: e.target.innerText

View File

@@ -163,7 +163,7 @@
name: itemName
}
this.$store.dispatch('changeItemName', item)
this.$store.dispatch('renameItem', item)
// Change item name if is mobile device or prompted
if (this.$isMobile()) {

View File

@@ -55,7 +55,7 @@ const Helpers = {
// Prevent submit empty files
if (files && files.length == 0) return
if (this.$store.getters.app.storage.percentage >= 100) {
if (! this.$isThisLocation(['public']) && this.$store.getters.app.storage.percentage >= 100) {
events.$emit('alert:open', {
emoji: '😬😬😬',
title: this.$t('popup_exceed_limit.title'),
@@ -104,7 +104,7 @@ const Helpers = {
}
}).catch(error => {
if (error.response.status == 423) {
/*if (error.response.status === 423) {
events.$emit('alert:open', {
emoji: '😬😬😬',
@@ -119,7 +119,7 @@ const Helpers = {
title: this.$t('popup_error.title'),
message: this.$t('popup_error.message'),
})
}
}*/
})
}
}

View File

@@ -9,6 +9,8 @@ import Helpers from './helpers'
import { library } from '@fortawesome/fontawesome-svg-core'
import { FontAwesomeIcon } from '@fortawesome/vue-fontawesome'
import {
faLock,
faLockOpen,
faDownload,
faUserFriends,
faCheck,
@@ -44,6 +46,8 @@ import {
} from '@fortawesome/free-solid-svg-icons'
library.add(
faLock,
faLockOpen,
faDownload,
faUserFriends,
faCheck,

View File

@@ -77,8 +77,8 @@ const actions = {
}
if (! back) context.commit('FLUSH_BROWSER_HISTORY')
context.commit('FLUSH_DATA')
context.commit('LOADING_STATE', true)
context.commit('FLUSH_DATA')
context.commit('LOADING_STATE', true)
// Create shared object for history
let trash = {
@@ -114,8 +114,8 @@ const actions = {
}
if (! back) context.commit('FLUSH_BROWSER_HISTORY')
context.commit('FLUSH_DATA')
context.commit('LOADING_STATE', true)
context.commit('FLUSH_DATA')
context.commit('LOADING_STATE', true)
// Create trash object for history
let trash = {

View File

@@ -29,10 +29,10 @@ const actions = {
})
.catch(() => isSomethingWrong())
},
changeItemName: ({commit, getters}, data) => {
renameItem: ({commit, getters}, data) => {
// Updated name in favourites panel
if (data.type === 'folder')
if (getters.permission === 'master' && data.type === 'folder')
commit('UPDATE_NAME_IN_FAVOURITES', data)
axios
@@ -69,7 +69,8 @@ const actions = {
.catch(error => {
reject(error)
context.commit('UPDATE_FILE_COUNT_PROGRESS', undefined)
// Reset uploader
commit('UPDATE_FILE_COUNT_PROGRESS', undefined)
})
})
},
@@ -100,10 +101,14 @@ const actions = {
// Remove file
commit('REMOVE_ITEM', data.unique_id)
if (data.type === 'folder')
commit('REMOVE_ITEM_FROM_FAVOURITES', data)
else
commit('REMOVE_ITEM_FROM_RECENT_UPLOAD', data.unique_id)
// Remove item from sidebar
if (getters.permission === 'master') {
if (data.type === 'folder')
commit('REMOVE_ITEM_FROM_FAVOURITES', data)
else
commit('REMOVE_ITEM_FROM_RECENT_UPLOAD', data.unique_id)
}
// Remove file preview
commit('CLEAR_FILEINFO_DETAIL')

View File

@@ -37,15 +37,11 @@ const actions = {
location: 'public'
}
let route = getters.sharedDetail.protected ? '/api/browse-private/' : '/api/browse-public/'
let route = getters.sharedDetail.protected ? '/api/browse-private/' : '/api/browse-public/' + router.currentRoute.params.token +'/'
return new Promise((resolve, reject) => {
axios
.get(route + currentFolder.unique_id, {
params: {
token: router.currentRoute.params.token
}
})
.get(route + currentFolder.unique_id)
.then(response => {
commit('LOADING_STATE', false)
@@ -76,9 +72,9 @@ const actions = {
},
getSingleFile: ({commit, state}) => {
let route = state.sharedDetail.protected ? '/api/file-private/' : '/api/file-public/'
let route = state.sharedDetail.protected ? '/api/file-private/' : '/api/file-public/' + router.currentRoute.params.token
axios.get(route + router.currentRoute.params.token)
axios.get(route)
.then(response => {
commit('STORE_SHARED_FILE', response.data)
})

View File

@@ -4,6 +4,12 @@
<!--Loading Spinenr-->
<Spinner v-if="isPageLoading"/>
<!--System alerts-->
<Alert />
<!--Background vignette-->
<Vignette/>
<!--Password verification-->
<div v-if="currentPage === 'page-password'" id="password-view">
@@ -37,15 +43,10 @@
</div>
</div>
<div v-if="sharedDetail.type === 'folder'" @contextmenu.prevent.capture="contextMenu($event, undefined)" @click="fileViewClick">
<!--Move item window-->
<MoveItem/>
<!--Mobile Menu-->
<MobileMenu/>
<!--Background vignette-->
<Vignette/>
<!--Context menu-->
<ContextMenu/>
@@ -71,7 +72,7 @@
import AuthButton from '@/components/VueFileManagerComponents/Auth/AuthButton'
import Spinner from '@/components/VueFileManagerComponents/FilesView/Spinner'
import Vignette from '@/components/VueFileManagerComponents/Others/Vignette'
import MoveItem from '@/components/VueFileManagerComponents/Others/MoveItem'
import Alert from '@/components/VueFileManagerComponents/FilesView/Alert'
import {required} from 'vee-validate/dist/rules'
import {ResizeSensor} from 'css-element-queries'
import {mapGetters} from 'vuex'
@@ -93,8 +94,8 @@
ButtonBase,
required,
Vignette,
MoveItem,
Spinner,
Alert,
},
computed: {
...mapGetters(['config', 'filesViewWidth', 'sharedDetail', 'sharedFile']),
@@ -150,10 +151,7 @@
})*/
},
download() {
this.$downloadFile(
this.item.file_url,
this.item.name + '.' + this.item.mimetype
)
this.$downloadFile(this.sharedFile.file_url, this.sharedFile.name + '.' + this.sharedFile.mimetype)
},
fileViewClick() {
events.$emit('contextMenu:hide')

View File

@@ -30,26 +30,14 @@ Route::group(['middleware' => ['api']], function () {
// Sharing
Route::post('/shared/authenticate/{token}', 'Sharing\FileSharingController@authenticate');
Route::get('/browse-public/{unique_id}', 'Sharing\FileSharingController@browse_public');
Route::get('/browse-public/{token}/{unique_id}', 'Sharing\FileSharingController@browse_public');
Route::get('/file-public/{token}', 'Sharing\FileSharingController@file_public');
Route::get('/shared/{token}', 'Sharing\FileSharingController@index');
});
// Protected sharing routes
Route::group(['middleware' => ['auth:api', 'auth.cookie', 'scope:visitor,editor']], function () {
// Browse folders & files
Route::get('/browse-private/{unique_id}', 'Sharing\FileSharingController@browse_private');
Route::get('/file-private/{token}', 'Sharing\FileSharingController@file_private');
Route::get('/shared/{token}', 'Sharing\FileSharingController@show');
});
// User master Routes
Route::group(['middleware' => ['auth:api', 'auth.cookie', 'scope:master']], function () {
// File route
Route::get('/thumbnail/{name}', 'FileAccessController@get_thumbnail')->name('thumbnail');
Route::get('/file/{name}', 'FileAccessController@get_file')->name('file');
// User
Route::post('/user/password', 'User\AccountController@change_password');
Route::put('/user/profile', 'User\AccountController@update_profile');
@@ -63,11 +51,7 @@ Route::group(['middleware' => ['auth:api', 'auth.cookie', 'scope:master']], func
Route::get('/search', 'FileBrowser\BrowseController@search');
Route::get('/trash', 'FileBrowser\BrowseController@trash');
// Edit items
Route::post('/create-folder', 'FileFunctions\EditController@create_folder');
Route::post('/rename-item', 'FileFunctions\EditController@rename_item');
Route::post('/remove-item', 'FileFunctions\EditController@delete_item');
Route::post('/upload-file', 'FileFunctions\EditController@upload_item');
// Edit functions
Route::post('/move-item', 'FileFunctions\EditController@move_item');
// Trash
@@ -86,3 +70,29 @@ Route::group(['middleware' => ['auth:api', 'auth.cookie', 'scope:master']], func
// Auth
Route::get('/logout', 'Auth\AuthController@logout');
});
// Protected sharing routes for public user
Route::group(['middleware' => ['auth:api', 'auth.cookie', 'scope:visitor,editor']], function () {
// Browse folders & files
Route::get('/browse-private/{unique_id}', 'Sharing\FileSharingController@browse_private');
Route::get('/file-private', 'Sharing\FileSharingController@file_private');
});
// User master,editor routes
Route::group(['middleware' => ['auth:api', 'auth.cookie', 'scope:master,editor,visitor']], function () {
// File routes
Route::get('/thumbnail/{name}', 'FileAccessController@get_thumbnail')->name('thumbnail');
Route::get('/file/{name}', 'FileAccessController@get_file')->name('file');
});
// User master,editor routes
Route::group(['middleware' => ['auth:api', 'auth.cookie', 'scope:master,editor']], function () {
// Edit items
Route::post('/create-folder', 'FileFunctions\EditController@create_folder');
Route::post('/rename-item', 'FileFunctions\EditController@rename_item');
Route::post('/remove-item', 'FileFunctions\EditController@delete_item');
Route::post('/upload-file', 'FileFunctions\EditController@upload_item');
});

View File

@@ -14,5 +14,8 @@
// Get user avatar
Route::get('/avatars/{avatar}', 'FileAccessController@get_avatar')->name('avatar');
// Get shared page
Route::get('/shared/{token}', 'Sharing\FileSharingController@index');
// Index Page
Route::get('/{any?}', 'AppFunctionsController@index')->where('any', '.*');