From b329ee9edcb14d49b0e900103bbb3002f08745c4 Mon Sep 17 00:00:00 2001 From: Your Name Date: Sun, 29 Mar 2026 19:18:34 +1030 Subject: [PATCH 1/2] API: Media uploads leak orphaned files when status creation validation fails --- app/Http/Controllers/Api/ApiV1Controller.php | 12 ++++++------ app/Http/Controllers/Api/ApiV1Dot1Controller.php | 14 +++++++------- 2 files changed, 13 insertions(+), 13 deletions(-) diff --git a/app/Http/Controllers/Api/ApiV1Controller.php b/app/Http/Controllers/Api/ApiV1Controller.php index 7bdb39211..f9878281a 100644 --- a/app/Http/Controllers/Api/ApiV1Controller.php +++ b/app/Http/Controllers/Api/ApiV1Controller.php @@ -1974,9 +1974,11 @@ class ApiV1Controller extends Controller abort(403, 'Invalid or unsupported mime type.'); } + $hash = \hash_file('sha256', $photo->getRealPath()); + abort_if(MediaBlocklistService::exists($hash) == true, 451); + $storagePath = MediaPathService::get($user, 2); $path = $photo->storePublicly($storagePath); - $hash = \hash_file('sha256', $photo); $license = null; $mime = $photo->getMimeType(); @@ -2000,8 +2002,6 @@ class ApiV1Controller extends Controller } } - abort_if(MediaBlocklistService::exists($hash) == true, 451); - $media = new Media; $media->status_id = null; $media->profile_id = $profile->id; @@ -2201,9 +2201,11 @@ class ApiV1Controller extends Controller abort(403, 'Invalid or unsupported mime type.'); } + $hash = \hash_file('sha256', $photo->getRealPath()); + abort_if(MediaBlocklistService::exists($hash) == true, 451); + $storagePath = MediaPathService::get($user, 2); $path = $photo->storePublicly($storagePath); - $hash = \hash_file('sha256', $photo); $license = null; $mime = $photo->getMimeType(); @@ -2217,8 +2219,6 @@ class ApiV1Controller extends Controller } } - abort_if(MediaBlocklistService::exists($hash) == true, 451); - if ($request->has('replace_id')) { $rpid = $request->input('replace_id'); $removeMedia = Media::whereNull('status_id') diff --git a/app/Http/Controllers/Api/ApiV1Dot1Controller.php b/app/Http/Controllers/Api/ApiV1Dot1Controller.php index e69894c66..43cedcc1f 100644 --- a/app/Http/Controllers/Api/ApiV1Dot1Controller.php +++ b/app/Http/Controllers/Api/ApiV1Dot1Controller.php @@ -1266,9 +1266,15 @@ class ApiV1Dot1Controller extends Controller abort(403, 'Invalid or unsupported mime type.'); } + if ($user->last_active_at == null) { + return []; + } + + $hash = \hash_file('sha256', $photo->getRealPath()); + abort_if(MediaBlocklistService::exists($hash) == true, 451); + $storagePath = MediaPathService::get($user, 2); $path = $photo->storePublicly($storagePath); - $hash = \hash_file('sha256', $photo); $license = null; $mime = $photo->getMimeType(); @@ -1282,17 +1288,11 @@ class ApiV1Dot1Controller extends Controller } } - abort_if(MediaBlocklistService::exists($hash) == true, 451); - $visibility = $profile->is_private ? 'private' : ( $profile->unlisted == true && $request->input('visibility', 'public') == 'public' ? 'unlisted' : $request->input('visibility', 'public')); - - if ($user->last_active_at == null) { - return []; - } $defaultCaption = ''; $cleanedStatus = app(SanitizeService::class)->html($request->input('status', '')); $content = $request->filled('status') ? strip_tags($cleanedStatus) : $defaultCaption; From 14b325641f16e207415db5ed77d6989d1c7dee01 Mon Sep 17 00:00:00 2001 From: Daniel Supernault Date: Wed, 15 Apr 2026 22:46:22 -0600 Subject: [PATCH 2/2] Update Password Change with new Revoke Sessions option As requested in https://lgbtqia.space/@serigala_tropis/116412473982617371 --- .../Controllers/Settings/HomeSettings.php | 60 +++++++++++-------- resources/views/settings/password.blade.php | 8 +++ 2 files changed, 43 insertions(+), 25 deletions(-) diff --git a/app/Http/Controllers/Settings/HomeSettings.php b/app/Http/Controllers/Settings/HomeSettings.php index 774962690..8d73a3ed7 100644 --- a/app/Http/Controllers/Settings/HomeSettings.php +++ b/app/Http/Controllers/Settings/HomeSettings.php @@ -10,10 +10,10 @@ use App\Services\AccountService; use App\Services\PronounService; use App\Util\Lexer\Autolink; use App\Util\Lexer\PrettyNumber; -use Auth; use Cache; use Illuminate\Http\Request; -use Mail; +use Illuminate\Support\Facades\Auth; +use Illuminate\Support\Facades\Mail; use Purify; trait HomeSettings @@ -118,38 +118,48 @@ trait HomeSettings { $this->validate($request, [ 'current' => 'required|string', - 'password' => 'required|string', - 'password_confirmation' => 'required|string', + 'password' => 'required|string|confirmed|min:8|different:current', + 'revoke_sessions' => 'nullable|boolean', ]); $current = $request->input('current'); $new = $request->input('password'); - $confirm = $request->input('password_confirmation'); + $revokeSessions = $request->boolean('revoke_sessions'); - $user = Auth::user(); - - if (password_verify($current, $user->password) && $new === $confirm) { - $user->password = bcrypt($new); - $user->save(); - - $log = new AccountLog; - $log->user_id = $user->id; - $log->item_id = $user->id; - $log->item_type = 'App\User'; - $log->action = 'account.edit.password'; - $log->message = 'Password changed'; - $log->link = null; - $log->ip_address = $request->ip(); - $log->user_agent = $request->userAgent(); - $log->save(); + $user = $request->user(); - Mail::to($request->user())->send(new PasswordChange($user)); - - return redirect('/settings/home')->with('status', 'Password successfully updated!'); - } else { + if (!password_verify($current, $user->password)) { return redirect()->back()->with('error', 'There was an error with your request! Please try again.'); } + $user->password = bcrypt($new); + $user->save(); + + $log = new AccountLog; + $log->user_id = $user->id; + $log->item_id = $user->id; + $log->item_type = 'App\User'; + $log->action = 'account.edit.password'; + $log->message = $revokeSessions + ? 'Password changed and all sessions revoked' + : 'Password changed'; + $log->link = null; + $log->ip_address = $request->ip(); + $log->user_agent = $request->userAgent(); + $log->save(); + + Mail::to($request->user())->send(new PasswordChange($user)); + + if ($revokeSessions) { + $user->tokens->each(function ($token) { + $token->revoke(); + $token->refreshToken?->revoke(); + }); + + Auth::logoutOtherDevices($new); + } + + return redirect('/settings/home')->with('status', 'Password successfully updated!'); } public function email() diff --git a/resources/views/settings/password.blade.php b/resources/views/settings/password.blade.php index 194b49338..1fbfbff68 100644 --- a/resources/views/settings/password.blade.php +++ b/resources/views/settings/password.blade.php @@ -50,6 +50,14 @@ +
+
+
+ + +
+
+