Multiple fixes and improvements

- Fixed JS exploit using SVG
 - Improved security
 - Now sanitizing EXIF and metadata
 - Now allowing multiple file types as profile picture
 - Added error messages
This commit is contained in:
Julian Prieber 2023-07-27 15:45:05 +02:00
parent 2180fec604
commit 07336bb34c
3 changed files with 102 additions and 33 deletions

View File

@ -9,6 +9,8 @@ use Illuminate\Support\Facades\Schema;
use Illuminate\Support\Facades\Route; use Illuminate\Support\Facades\Route;
use Illuminate\Support\Facades\Response; use Illuminate\Support\Facades\Response;
use JeroenDesloovere\VCard\VCard; use JeroenDesloovere\VCard\VCard;
use Illuminate\Validation\Rule;
use Illuminate\Support\Facades\Validator;
use Auth; use Auth;
use DB; use DB;
@ -708,37 +710,57 @@ class UserController extends Controller
} }
//Save littlelink page (name, description, logo) //Save littlelink page (name, description, logo)
public function editPage(request $request) public function editPage(Request $request)
{ {
$request->validate([
'littlelink_name' => 'sometimes|max:255|string|isunique:users,id,'.Auth::id(),
'name' => 'sometimes|max:255|string',
]);
$userId = Auth::user()->id; $userId = Auth::user()->id;
$littlelink_name = Auth::user()->littlelink_name; $littlelink_name = Auth::user()->littlelink_name;
$validator = Validator::make($request->all(), [
'littlelink_name' => [
'sometimes',
'max:255',
'string',
'isunique:users,id,'.$userId,
],
'name' => 'sometimes|max:255|string',
'image' => 'sometimes|image|mimes:jpeg,jpg,png,webp|max:2048', // Max file size: 2MB
], [
'littlelink_name.unique' => 'That handle has already been taken.',
'image.image' => 'The selected file must be an image.',
'image.mimes' => 'The image must be a: JPEG, JPG, PNG, webP.',
'image.max' => 'The image size should not exceed 2MB.',
]);
if ($validator->fails()) {
return redirect('/studio/page')->withErrors($validator)->withInput();
}
$profilePhoto = $request->file('image'); $profilePhoto = $request->file('image');
$pageName = $request->littlelink_name; $pageName = $request->littlelink_name;
$pageDescription = strip_tags($request->pageDescription,'<a><p><strong><i><ul><ol><li><blockquote><h2><h3><h4>'); $pageDescription = strip_tags($request->pageDescription, '<a><p><strong><i><ul><ol><li><blockquote><h2><h3><h4>');
$pageDescription = preg_replace("/<a([^>]*)>/i", "<a $1 rel=\"noopener noreferrer nofollow\">", $pageDescription); $pageDescription = preg_replace("/<a([^>]*)>/i", "<a $1 rel=\"noopener noreferrer nofollow\">", $pageDescription);
$name = $request->name; $name = $request->name;
$checkmark = $request->checkmark; $checkmark = $request->checkmark;
$sharebtn = $request->sharebtn; $sharebtn = $request->sharebtn;
User::where('id', $userId)->update(['littlelink_name' => $pageName, 'littlelink_description' => $pageDescription, 'name' => $name]); User::where('id', $userId)->update([
'littlelink_name' => $pageName,
'littlelink_description' => $pageDescription,
'name' => $name
]);
if ($request->hasFile('image')) { if ($request->hasFile('image')) {
$profilePhoto->move(base_path('assets/img'), $userId . '_' . time() . ".png"); $fileName = $userId . '_' . time() . "." . $profilePhoto->extension();
$profilePhoto->move(base_path('assets/img'), $fileName);
} }
if($checkmark == "on"){ if ($checkmark == "on") {
UserData::saveData($userId, 'checkmark', true); UserData::saveData($userId, 'checkmark', true);
} else { } else {
UserData::saveData($userId, 'checkmark', false); UserData::saveData($userId, 'checkmark', false);
} }
if($sharebtn == "on"){ if ($sharebtn == "on") {
UserData::saveData($userId, 'disable-sharebtn', false); UserData::saveData($userId, 'disable-sharebtn', false);
} else { } else {
UserData::saveData($userId, 'disable-sharebtn', true); UserData::saveData($userId, 'disable-sharebtn', true);
@ -748,28 +770,50 @@ class UserController extends Controller
} }
//Upload custom theme background image //Upload custom theme background image
public function themeBackground(request $request) public function themeBackground(Request $request)
{ {
$userId = Auth::user()->id; $userId = Auth::user()->id;
$littlelink_name = Auth::user()->littlelink_name; $littlelink_name = Auth::user()->littlelink_name;
$request->validate([
'image' => 'required|image|mimes:jpeg,jpg,png,webp,gif|max:2048', // Max file size: 2MB
], [
'image.required' => 'Please select an image file.',
'image.image' => 'The selected file must be an image.',
'image.mimes' => 'The image must be a: JPEG, JPG, PNG, webP, GIF.',
'image.max' => 'The image size should not exceed 2MB.',
]);
$customBackground = $request->file('image'); $customBackground = $request->file('image');
if (!empty($customBackground)) { if ($customBackground) {
$directory = base_path('assets/img/background-img/'); $directory = base_path('assets/img/background-img/');
$files = scandir($directory); $files = scandir($directory);
$pathinfo = "error.error"; $pathinfo = "error.error";
foreach($files as $file) { foreach ($files as $file) {
if (strpos($file, $userId.'.') !== false) { if (strpos($file, $userId . '.') !== false) {
$pathinfo = $userId. "." . pathinfo($file, PATHINFO_EXTENSION); $pathinfo = $userId . "." . pathinfo($file, PATHINFO_EXTENSION);
}} }
if(file_exists(base_path('assets/img/background-img/').$pathinfo)){File::delete(base_path('assets/img/background-img/').$pathinfo);} }
$customBackground->move(base_path('assets/img/background-img/'), $userId . '_' . time() . "." . $request->file('image')->extension()); if (file_exists(base_path('assets/img/background-img/') . $pathinfo)) {
File::delete(base_path('assets/img/background-img/') . $pathinfo);
}
$fileName = $userId . '_' . time() . "." . $customBackground->extension();
$customBackground->move(base_path('assets/img/background-img/'), $fileName);
if (extension_loaded('imagick')) {
$imagePath = base_path('assets/img/background-img/') . $fileName;
$image = new \Imagick($imagePath);
$image->stripImage();
$image->writeImage($imagePath);
}
return redirect('/studio/theme');
} }
return Redirect('/studio/theme'); return redirect('/studio/theme')->with('error', 'Please select a valid image file.');
} }
//Delete custom background image //Delete custom background image

View File

@ -194,6 +194,18 @@
</div> </div>
<section class='text-gray-400'> <section class='text-gray-400'>
<h3 class="mb-4 card-header"><i class="bi bi-file-earmark-break"> {{__('messages.My Profile')}}</i></h3> <h3 class="mb-4 card-header"><i class="bi bi-file-earmark-break"> {{__('messages.My Profile')}}</i></h3>
@if($errors->any())
<div class="alert alert-danger d-flex align-items-center" role="alert">
<svg class="bi flex-shrink-0 me-2" width="24" height="24">
<use xlink:href="#exclamation-triangle-fill"></use>
</svg>
<div>
@foreach ($errors->all() as $error)
{{ $error }}
@endforeach
</div>
</div>
@endif
<div> <div>
<div></div> <div></div>
@ -203,7 +215,7 @@
@if($page->littlelink_name != '') @if($page->littlelink_name != '')
<div class="form-group col-lg-8"> <div class="form-group col-lg-8">
<label class="form-label" for="customFile">{{__('messages.Profile Picture')}}</label> <label class="form-label" for="customFile">{{__('messages.Profile Picture')}}</label>
<input type="file" accept="image/jpeg,image/jpg,image/png" name="image" class="form-control" id="customFile"> <input type="file" accept="image/jpeg,image/jpg,image/png,image/webp" name="image" class="form-control" id="customFile">
</div> </div>
@endif @endif

View File

@ -17,6 +17,19 @@
<h3 class="mb-4 card-header"><i class="bi bi-brush">{{__('messages.Select a theme')}}</i></h3> <h3 class="mb-4 card-header"><i class="bi bi-brush">{{__('messages.Select a theme')}}</i></h3>
<div> <div>
@if($errors->any())
<div class="alert alert-danger d-flex align-items-center" role="alert">
<svg class="bi flex-shrink-0 me-2" width="24" height="24">
<use xlink:href="#exclamation-triangle-fill"></use>
</svg>
<div>
@foreach ($errors->all() as $error)
{{ $error }}
@endforeach
</div>
</div>
@endif
<button type="button" class="btn btn-primary mb-5" data-bs-toggle="modal" data-bs-target="#exampleModal"> <button type="button" class="btn btn-primary mb-5" data-bs-toggle="modal" data-bs-target="#exampleModal">
{{__('messages.Select theme')}} {{__('messages.Select theme')}}
</button> </button>
@ -74,7 +87,7 @@
<br> <br>
<br><br> <br><br>
<div class="mb-3"> <div class="mb-3">
<input type="file" accept="image/jpeg,image/jpg,image/png" class="form-control form-control-lg" name="image"><br> <input type="file" accept="image/jpeg,image/jpg,image/png,image/webp,image/gif" class="form-control form-control-lg" name="image"><br>
</div> </div>
</div> </div>
<button type="submit" class="btn btn-primary">{{__('messages.Apply')}}</button> <button type="submit" class="btn btn-primary">{{__('messages.Apply')}}</button>