Browse Source

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

Daniel Supernault 2 years ago
parent
commit
f6e7ff649e

+ 43 - 2
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),
+            ]);
     }
 }

+ 114 - 38
resources/views/auth/passwords/email.blade.php

@@ -1,47 +1,123 @@
-@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">
-                    @if (session('status') || $errors->has('email'))
-                        <div class="alert alert-success">
-                            {{ session('status') ?? $errors->first('email') }}
-                        </div>
-                    @endif
+<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">Send a password reset mail to reset your password</p>
+	            </div>
 
-                    <form method="POST" action="{{ route('password.email') }}">
-                        @csrf
+                @if(session('status') || $errors->has('email'))
+                    <div class="alert alert-info small">
+                    	<div class="d-flex align-items-center font-weight-bold" style="gap:0.5rem;">
+                    		<i class="far fa-exclamation-triangle fa-lg" style="opacity:20%"></i>
 
-                        <div class="form-group row">
-                            <div class="col-md-12">
-                                <input id="email" type="email" class="form-control" name="email" placeholder="{{ __('E-Mail Address') }}" required>
-                            </div>
+                        	{{ session('status') ?? $errors->first('email') }}
                         </div>
+                    </div>
+                @endif
 
-                        <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">
-                                    {{ __('Send Password Reset Link') }}
-                                </button>
-                            </div>
-                        </div>
-                    </form>
-                </div>
-            </div>
-
-            <div class="card mt-3">
-                <div class="card-body text-center">
-                    <a class="btn btn-link font-weight-bold" href="{{ route('login') }}">
-                        {{ __('Back to Login') }}
+	            <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.email') }}">
+	                        @csrf
+
+	                        <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" name="email" placeholder="{{ __('E-Mail Address') }}" required>
+	                                 @if ($errors->has('email') && $errors->first('email') === 'The email must be a valid email address.')
+	                                    <span class="text-danger small mb-3">
+	                                        <strong>{{ $errors->first('email') }}</strong>
+	                                    </span>
+	                                 @endif
+	                            </div>
+	                        </div>
+
+							@if(config('captcha.enabled'))
+							<label class="font-weight-bold small 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-primary btn-block rounded-pill font-weight-bold" onclick="event.preventDefault();handleSubmit()">
+	                                    {{ __('Send Password Reset Link') }}
+	                                </button>
+	                            </div>
+	                        </div>
+	                    </form>
+	                </div>
+	            </div>
+
+	            <div class="mt-3 d-flex justify-content-between align-items-center">
+                    <a class="btn btn-link text-white font-weight-bold text-decoration-none" href="{{ route('login') }}">
+                        <i class="far fa-long-arrow-left fa-lg mr-1"></i> {{ __('Back to Login') }}
                     </a>
-                </div>
-            </div>
-        </div>
-    </div>
+
+                    <a href="#" class="text-white font-weight-bold text-decoration-none" onclick="event.preventDefault();forgotUsername()">Forgot email?</a>
+	            </div>
+	        </div>
+	    </div>
+	</div>
 </div>
 @endsection
+
+@push('scripts')
+<script type="text/javascript">
+	function forgotUsername() {
+		swal({
+			title: 'Forgot email?',
+			text: 'Contact the instance admins to assist you in recovering your account.',
+			icon: 'info',
+			buttons: {
+				contact: {
+					text: "Contact Admins",
+					value: "contact",
+					className: "bg-danger"
+				},
+				cancel: "Close",
+			},
+		})
+		.then((value) => {
+			switch(value) {
+				case 'contact':
+					window.location.href = '/site/contact';
+				break;
+			}
+		});
+	}
+
+	function handleSubmit() {
+		let email = document.getElementById('email');
+		email.classList.add('disabled');
+
+		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