浏览代码

Update ResetPasswordController, add captcha support, improve security and a new redesigned view

Daniel Supernault 2 年之前
父节点
当前提交
0ab5b96a00
共有 2 个文件被更改,包括 223 次插入60 次删除
  1. 73 0
      app/Http/Controllers/Auth/ResetPasswordController.php
  2. 150 60
      resources/views/auth/passwords/reset.blade.php

+ 73 - 0
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)]]);
+    }
+
 }

+ 150 - 60
resources/views/auth/passwords/reset.blade.php

@@ -1,64 +1,154 @@
-@extends('layouts.app')
+@extends('layouts.blank')
+
+@push('styles')
+<link href="{{ mix('css/landing.css') }}" rel="stylesheet">
+<link rel="preload" as="image" href="{{ url('/_landing/bg.jpg')}}" />
+@endpush
 
 @section('content')
-<div class="container mt-4">
-    <div class="row justify-content-center">
-        <div class="col-lg-5">
-            <div class="card">
-                <div class="card-header bg-white p-3 text-center font-weight-bold">{{ __('Reset Password') }}</div>
-
-                <div class="card-body">
-                    <form method="POST" action="{{ route('password.request') }}">
-                        @csrf
-
-                        <input type="hidden" name="token" value="{{ $token }}">
-
-                        <div class="form-group row">
-                            <div class="col-md-12">
-                                <input id="email" type="email" class="form-control{{ $errors->has('email') ? ' is-invalid' : '' }}" name="email" value="{{ $email ?? old('email') }}" placeholder="{{ __('E-Mail Address') }}" required autofocus>
-                                @if ($errors->has('email'))
-                                    <span class="invalid-feedback">
-                                        <strong>{{ $errors->first('email') }}</strong>
-                                    </span>
-                                @endif
-                            </div>
-                        </div>
-                        <hr>
-                        <div class="form-group row">
-                            <div class="col-md-12">
-                                <input id="password" type="password" class="form-control{{ $errors->has('password') ? ' is-invalid' : '' }}" name="password" placeholder="{{ __('Password') }}" required>
-
-                                @if ($errors->has('password'))
-                                    <span class="invalid-feedback">
-                                        <strong>{{ $errors->first('password') }}</strong>
-                                    </span>
-                                @endif
-                            </div>
-                        </div>
-
-                        <div class="form-group row">
-                            <div class="col-md-12">
-                                <input id="password-confirm" type="password" class="form-control{{ $errors->has('password_confirmation') ? ' is-invalid' : '' }}" name="password_confirmation" placeholder="{{ __('Confirm Password') }}" required>
-
-                                @if ($errors->has('password_confirmation'))
-                                    <span class="invalid-feedback">
-                                        <strong>{{ $errors->first('password_confirmation') }}</strong>
-                                    </span>
-                                @endif
-                            </div>
-                        </div>
-
-                        <div class="form-group row mb-0">
-                            <div class="col-md-12">
-                                <button type="submit" class="btn btn-primary btn-block py-0 font-weight-bold">
-                                    {{ __('Reset Password') }}
-                                </button>
-                            </div>
-                        </div>
-                    </form>
-                </div>
-            </div>
-        </div>
-    </div>
+<div class="page-wrapper">
+	<div class="container mt-4">
+	    <div class="row justify-content-center">
+	        <div class="col-lg-5">
+	        	<div class="text-center">
+	                <a href="/">
+	                	<img src="/img/pixelfed-icon-white.svg" height="60px">
+	            	</a>
+	                <h1 class="pt-4 pb-1">Reset Password</h1>
+	                <p class="font-weight-light pb-2">Use this form to reset your password.</p>
+	            </div>
+
+				@if ($errors)
+					@foreach($errors as $error)
+                    <span class="invalid-feedback">
+                        <strong>{{ $error }}</strong>
+                    </span>
+                    @endforeach
+                @endif
+
+	            <div class="card bg-glass">
+	                <div class="card-header bg-transparent p-3 text-center font-weight-bold" style="border-bottom:1px solid #ffffff20">{{ __('Reset Password') }}</div>
+
+	                <div class="card-body">
+	                    <form id="passwordReset" method="POST" action="{{ route('password.request') }}">
+	                        @csrf
+
+	                        <input type="hidden" name="token" value="{{ $token }}">
+	                        <input type="hidden" name="email" value="{{ $email ?? old('email') }}">
+
+	                        <div class="form-group row">
+	                            <div class="col-md-12">
+	                            	<label class="font-weight-bold small text-muted">Email</label>
+	                                <input
+	                                	id="email"
+	                                	type="email"
+	                                	class="form-control {{ $errors->has('email') ? ' is-invalid' : '' }}"
+	                                	name="email"
+	                                	value="{{ $email ?? old('email') }}"
+	                                	placeholder="{{ __('E-Mail Address') }}"
+	                                	required
+	                                	disabled
+	                                	style="opacity: 20%;">
+
+	                                @if ($errors->has('email'))
+	                                    <span class="invalid-feedback">
+	                                        <strong>{{ $errors->first('email') }}</strong>
+	                                    </span>
+	                                @endif
+	                            </div>
+	                        </div>
+
+	                        <hr class="bg-muted">
+
+	                        <div class="form-group row">
+	                            <div class="col-md-12">
+	                            	<label class="font-weight-bold small text-muted">New Password</label>
+
+	                                <input
+	                                	id="password"
+	                                	type="password"
+	                                	class="form-control{{ $errors->has('password') ? ' is-invalid' : '' }}"
+	                                	name="password"
+	                                	placeholder="{{ __('Password') }}"
+	                                	minlength="{{config('pixelfed.min_password_length')}}"
+	                                	maxlength="72"
+	                                	autocomplete="new-password"
+	                                	autofocus
+	                                	required>
+
+	                                @if ($errors->has('password'))
+	                                    <span class="invalid-feedback">
+	                                        <strong>{{ $errors->first('password') }}</strong>
+	                                    </span>
+	                                @else
+	                                	<p class="help-text small text-muted mb-0 mt-1">Enter a new password between {{config('pixelfed.min_password_length')}}-72 characters long.</p>
+	                                @endif
+	                            </div>
+	                        </div>
+
+	                        <div class="form-group row">
+	                            <div class="col-md-12">
+	                            	<label class="font-weight-bold small text-muted">Confirm New Password</label>
+
+	                                <input
+	                                	id="password-confirm"
+	                                	type="password"
+	                                	class="form-control{{ $errors->has('password_confirmation') ? ' is-invalid' : '' }}"
+	                                	name="password_confirmation"
+	                                	placeholder="{{ __('Confirm Password') }}"
+	                                	minlength="{{config('pixelfed.min_password_length')}}"
+	                                	autocomplete="new-password"
+	                                	maxlength="72"
+	                                	required>
+
+	                                @if ($errors->has('password_confirmation'))
+	                                    <span class="invalid-feedback">
+	                                        <strong>{{ $errors->first('password_confirmation') }}</strong>
+	                                    </span>
+	                                @endif
+	                            </div>
+	                        </div>
+
+							@if(config('captcha.enabled'))
+							<label class="font-weight-bold small pt-3 text-muted">Captcha</label>
+	                        <div class="d-flex flex-grow-1">
+	                            {!! Captcha::display(['data-theme' => 'dark']) !!}
+	                        </div>
+	                        @if ($errors->has('h-captcha-response'))
+                                <div class="text-danger small mb-3">
+                                    <strong>{{ $errors->first('h-captcha-response') }}</strong>
+                                </div>
+                            @endif
+	                        @endif
+
+	                        <div class="form-group row pt-4 mb-0">
+	                            <div class="col-md-12">
+	                                <button
+	                                	type="button"
+	                                	id="sbtn"
+	                                	class="btn btn-success btn-block rounded-pill font-weight-bold"
+	                                	onclick="event.preventDefault();handleSubmit()">
+	                                    {{ __('Reset Password') }}
+	                                </button>
+	                            </div>
+	                        </div>
+	                    </form>
+	                </div>
+	            </div>
+	        </div>
+	    </div>
+	</div>
 </div>
 @endsection
+
+@push('scripts')
+<script type="text/javascript">
+	function handleSubmit() {
+		let btn = document.getElementById('sbtn');
+		btn.classList.add('disabled');
+		btn.setAttribute('disabled', 'disabled');
+		btn.innerHTML = '<div class="spinner-border spinner-border-sm" role="status"><span class="sr-only">Loading...</span></div>';
+		document.getElementById('passwordReset').submit()
+	}
+</script>
+@endpush