diff --git a/CHANGELOG.md b/CHANGELOG.md index bbe27debf..c7a1bf33e 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -31,6 +31,11 @@ - Update RegisterController, store client ip during registration ([d4c967de](https://github.com/pixelfed/pixelfed/commit/d4c967de)) - Update ApiV1Controller, fix account blocks. Closes #4304 ([98739139](https://github.com/pixelfed/pixelfed/commit/98739139)) - Update RegisterController, improve max_users calculation and add kb page to redirect to if conditions are met ([1bbee6d0](https://github.com/pixelfed/pixelfed/commit/1bbee6d0)) +- Update SecuritySettings, remove imagick depdency for 2FA qr code generation image ([506f95c6](https://github.com/pixelfed/pixelfed/commit/506f95c6)) +- Update 2fa checkpoint view design ([86c472ac](https://github.com/pixelfed/pixelfed/commit/86c472ac)) +- Update sudo mode checkpoint view design ([091e0b2c](https://github.com/pixelfed/pixelfed/commit/091e0b2c)) +- Update ForgotPasswordController, add captcha support, improve security and a new redesigned view ([f6e7ff64](https://github.com/pixelfed/pixelfed/commit/f6e7ff64)) +- Update ResetPasswordController, add captcha support, improve security and a new redesigned view ([0ab5b96a](https://github.com/pixelfed/pixelfed/commit/0ab5b96a)) - ([](https://github.com/pixelfed/pixelfed/commit/)) ## [v0.11.5 (2023-03-25)](https://github.com/pixelfed/pixelfed/compare/v0.11.4...v0.11.5) diff --git a/app/Http/Controllers/Auth/ForgotPasswordController.php b/app/Http/Controllers/Auth/ForgotPasswordController.php index f74df8fa7..618c495e2 100644 --- a/app/Http/Controllers/Auth/ForgotPasswordController.php +++ b/app/Http/Controllers/Auth/ForgotPasswordController.php @@ -43,6 +43,8 @@ class ForgotPasswordController extends Controller abort_if(BouncerService::checkIp(request()->ip()), 404); } + usleep(random_int(100000, 300000)); + return view('auth.passwords.email'); } @@ -52,12 +54,51 @@ class ForgotPasswordController extends Controller * @param \Illuminate\Http\Request $request * @return void */ - protected function validateEmail(Request $request) + public function validateEmail(Request $request) { if(config('pixelfed.bouncer.cloud_ips.ban_logins')) { abort_if(BouncerService::checkIp($request->ip()), 404); } - $request->validate(['email' => 'required|email']); + usleep(random_int(100000, 3000000)); + + if(config('captcha.enabled')) { + $rules = [ + 'email' => 'required|email', + 'h-captcha-response' => 'required|captcha' + ]; + } else { + $rules = [ + 'email' => 'required|email' + ]; + } + + $request->validate($rules, [ + 'h-captcha-response' => 'Failed to validate the captcha.', + ]); + } + + /** + * Get the response for a failed password reset link. + * + * @param \Illuminate\Http\Request $request + * @param string $response + * @return \Illuminate\Http\RedirectResponse + * + * @throws \Illuminate\Validation\ValidationException + */ + public function sendResetLinkFailedResponse(Request $request, $response) + { + if ($request->wantsJson()) { + throw ValidationException::withMessages([ + 'email' => [trans($response)], + ]); + } + + return back() + ->withInput($request->only('email')) + ->withErrors([ + 'email' => trans($response), + ]); } } diff --git a/app/Http/Controllers/Auth/ResetPasswordController.php b/app/Http/Controllers/Auth/ResetPasswordController.php index 23d3c2821..a92c4e38d 100644 --- a/app/Http/Controllers/Auth/ResetPasswordController.php +++ b/app/Http/Controllers/Auth/ResetPasswordController.php @@ -7,6 +7,7 @@ use Illuminate\Foundation\Auth\ResetsPasswords; use Illuminate\Support\Facades\Password; use Illuminate\Http\Request; use App\Services\BouncerService; +use Illuminate\Validation\Rules; class ResetPasswordController extends Controller { @@ -40,6 +41,46 @@ class ResetPasswordController extends Controller $this->middleware('guest'); } + /** + * Get the password reset validation rules. + * + * @return array + */ + protected function rules() + { + usleep(random_int(100000, 3000000)); + + if(config('captcha.enabled')) { + return [ + 'token' => 'required', + 'email' => 'required|email', + 'password' => ['required', 'confirmed', 'max:72', Rules\Password::defaults()], + 'h-captcha-response' => ['required' ,'filled', 'captcha'] + ]; + } + + return [ + 'token' => 'required', + 'email' => 'required|email', + 'password' => ['required', 'confirmed', 'max:72', Rules\Password::defaults()], + ]; + } + + /** + * Get the password reset validation error messages. + * + * @return array + */ + protected function validationErrorMessages() + { + return [ + 'password.max' => 'Passwords should not exceed 72 characters.', + 'h-captcha-response.required' => 'Failed to validate the captcha.', + 'h-captcha-response.filled' => 'Failed to validate the captcha.', + 'h-captcha-response.captcha' => 'Failed to validate the captcha.', + ]; + } + /** * Display the password reset view for the given token. * @@ -54,6 +95,8 @@ class ResetPasswordController extends Controller abort_if(BouncerService::checkIp($request->ip()), 404); } + usleep(random_int(100000, 300000)); + $token = $request->route()->parameter('token'); return view('auth.passwords.reset')->with( @@ -86,4 +129,34 @@ class ResetPasswordController extends Controller : $this->sendResetFailedResponse($request, $response); } + /** + * Get the password reset credentials from the request. + * + * @param \Illuminate\Http\Request $request + * @return array + */ + protected function credentials(Request $request) + { + return $request->only( + 'email', 'password', 'password_confirmation', 'token' + ); + } + + /** + * Get the response for a failed password reset. + * + * @param \Illuminate\Http\Request $request + * @param string $response + * @return \Illuminate\Http\RedirectResponse|\Illuminate\Http\JsonResponse + */ + protected function sendResetFailedResponse(Request $request, $response) + { + if ($request->wantsJson()) { + throw ValidationException::withMessages(['email' => [trans($response)]]); + } + return redirect()->back() + ->withInput($request->only('email')) + ->withErrors(['email' => [trans($response)]]); + } + } diff --git a/app/Http/Controllers/Settings/SecuritySettings.php b/app/Http/Controllers/Settings/SecuritySettings.php index 1acb96078..604a1e90b 100644 --- a/app/Http/Controllers/Settings/SecuritySettings.php +++ b/app/Http/Controllers/Settings/SecuritySettings.php @@ -16,7 +16,7 @@ use Carbon\Carbon; use Illuminate\Http\Request; use PragmaRX\Google2FA\Google2FA; use BaconQrCode\Renderer\ImageRenderer; -use BaconQrCode\Renderer\Image\ImagickImageBackEnd; +use BaconQrCode\Renderer\Image\SvgImageBackEnd; use BaconQrCode\Renderer\RendererStyle\RendererStyle; use BaconQrCode\Writer; @@ -56,13 +56,15 @@ trait SecuritySettings $key, 500 ); + + $writer = new Writer( new ImageRenderer( new RendererStyle(400), - new ImagickImageBackEnd() + new SvgImageBackEnd() ) ); - $qrcode = base64_encode($writer->writeString($qrcode)); + $qrcode = $writer->writeString($qrcode); $user->{'2fa_secret'} = $key; $user->{'2fa_backup_codes'} = json_encode($backups); $user->save(); @@ -162,4 +164,4 @@ trait SecuritySettings 'msg' => 'Successfully removed 2fa device' ], 200); } -} \ No newline at end of file +} diff --git a/resources/views/auth/checkpoint.blade.php b/resources/views/auth/checkpoint.blade.php index 1c84e8e2a..480be02d6 100644 --- a/resources/views/auth/checkpoint.blade.php +++ b/resources/views/auth/checkpoint.blade.php @@ -1,55 +1,105 @@ @extends('layouts.blank') +@push('styles') + + +@endpush + @section('content') -
-
-
-
- -

Verify Two Factor Code

-
-
- If you lose access to your 2FA device, contact the admins. -
-
-
-
- @csrf +
+
+
+
+
+ + + +

2FA Checkpoint

+

+ Enter the 2FA code from your device. +

+

+ If you lose access to your 2FA device, contact the admins. +

+
+
+
+ + @csrf -
+
-
- +
+ + - @if ($errors->has('code')) - - {{ $errors->first('code') }} - - @endif -
-
+ @if ($errors->has('code')) + + {{ $errors->first('code') }} + + @endif +
+
-
-
- +
+
+ -
-
- -
-
-
- Logged in as: {{Auth::user()->username}} - - Logout - - -
-
-
+
+
+ +
+
+
+

+ Logged in as: {{request()->user()->username}} +

+ +
+ @csrf + +
+
+
+
+
@endsection + +@push('scripts') + +@endpush diff --git a/resources/views/auth/passwords/email.blade.php b/resources/views/auth/passwords/email.blade.php index ab2d6985a..d144e142a 100644 --- a/resources/views/auth/passwords/email.blade.php +++ b/resources/views/auth/passwords/email.blade.php @@ -1,47 +1,123 @@ -@extends('layouts.app') +@extends('layouts.blank') + +@push('styles') + + +@endpush @section('content') -
-
-
-
-
{{ __('Reset Password') }}
+
+
+
+
+
+ + + +

Reset Password

+

Send a password reset mail to reset your password

+
-
- @if (session('status') || $errors->has('email')) - -
-
+ + Forgot email? +
+
+
+
@endsection + +@push('scripts') + +@endpush diff --git a/resources/views/auth/passwords/reset.blade.php b/resources/views/auth/passwords/reset.blade.php index e160f2109..efe59ac95 100644 --- a/resources/views/auth/passwords/reset.blade.php +++ b/resources/views/auth/passwords/reset.blade.php @@ -1,64 +1,154 @@ -@extends('layouts.app') +@extends('layouts.blank') + +@push('styles') + + +@endpush @section('content') -
-
-
-
-
{{ __('Reset Password') }}
+
+
+
+
+
+ + + +

Reset Password

+

Use this form to reset your password.

+
-
-
- @csrf + @if ($errors) + @foreach($errors as $error) + + {{ $error }} + + @endforeach + @endif - +
+
{{ __('Reset Password') }}
-
-
- - @if ($errors->has('email')) - - {{ $errors->first('email') }} - - @endif -
-
-
-
-
- +
+ + @csrf - @if ($errors->has('password')) - - {{ $errors->first('password') }} - - @endif -
-
+ + -
-
- +
+
+ + - @if ($errors->has('password_confirmation')) - - {{ $errors->first('password_confirmation') }} - - @endif -
-
+ @if ($errors->has('email')) + + {{ $errors->first('email') }} + + @endif +
+
-
-
- -
-
- -
-
-
-
+
+ +
+
+ + + + + @if ($errors->has('password')) + + {{ $errors->first('password') }} + + @else +

Enter a new password between {{config('pixelfed.min_password_length')}}-72 characters long.

+ @endif +
+
+ +
+
+ + + + + @if ($errors->has('password_confirmation')) + + {{ $errors->first('password_confirmation') }} + + @endif +
+
+ + @if(config('captcha.enabled')) + +
+ {!! Captcha::display(['data-theme' => 'dark']) !!} +
+ @if ($errors->has('h-captcha-response')) +
+ {{ $errors->first('h-captcha-response') }} +
+ @endif + @endif + +
+
+ +
+
+ +
+
+
+
+
@endsection + +@push('scripts') + +@endpush diff --git a/resources/views/auth/sudo.blade.php b/resources/views/auth/sudo.blade.php index ccaf6cc39..34b206671 100644 --- a/resources/views/auth/sudo.blade.php +++ b/resources/views/auth/sudo.blade.php @@ -1,47 +1,104 @@ @extends('layouts.blank') +@push('styles') + + +@endpush + @section('content') -
-
-
-
- -

Confirm password to continue

-
-
-
-
- @csrf +
+
+
+
+
+ + + +

Sudo Mode

+

Confirm password to continue

+
+
+
+ + @csrf -
- +
+ + - @if ($errors->has('password')) - - {{ $errors->first('password') }} - - @endif -
+ @if ($errors->has('password')) + + {{ $errors->first('password') }} + + @endif +
-
-
- - -
-
+
+
+ + +
+
-
-
- +
+
+ -
-
- -
-
-
-
+
+
+ +
+
+ +
+

+ Logged in as: {{request()->user()->username}} +

+ +
+ @csrf + +
+
+
+
+
@endsection + +@push('scripts') + +@endpush diff --git a/resources/views/settings/security/2fa/setup.blade.php b/resources/views/settings/security/2fa/setup.blade.php index 39e83a9c6..1ac247d59 100644 --- a/resources/views/settings/security/2fa/setup.blade.php +++ b/resources/views/settings/security/2fa/setup.blade.php @@ -50,7 +50,7 @@

QR Code

- + {!!$qrcode!!}

OTP Secret