mirror of
https://github.com/pixelfed/pixelfed.git
synced 2024-12-27 07:23:17 +00:00
Update ResetPasswordController, add captcha support, improve security and a new redesigned view
This commit is contained in:
parent
f6e7ff649e
commit
0ab5b96a00
2 changed files with 216 additions and 53 deletions
|
@ -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)]]);
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
@ -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="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>
|
||||
|
||||
<div class="card-body">
|
||||
<form method="POST" action="{{ route('password.request') }}">
|
||||
@csrf
|
||||
@if ($errors)
|
||||
@foreach($errors as $error)
|
||||
<span class="invalid-feedback">
|
||||
<strong>{{ $error }}</strong>
|
||||
</span>
|
||||
@endforeach
|
||||
@endif
|
||||
|
||||
<input type="hidden" name="token" value="{{ $token }}">
|
||||
<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="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>
|
||||
<div class="card-body">
|
||||
<form id="passwordReset" method="POST" action="{{ route('password.request') }}">
|
||||
@csrf
|
||||
|
||||
@if ($errors->has('password'))
|
||||
<span class="invalid-feedback">
|
||||
<strong>{{ $errors->first('password') }}</strong>
|
||||
</span>
|
||||
@endif
|
||||
</div>
|
||||
</div>
|
||||
<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">
|
||||
<input id="password-confirm" type="password" class="form-control{{ $errors->has('password_confirmation') ? ' is-invalid' : '' }}" name="password_confirmation" placeholder="{{ __('Confirm Password') }}" required>
|
||||
<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('password_confirmation'))
|
||||
<span class="invalid-feedback">
|
||||
<strong>{{ $errors->first('password_confirmation') }}</strong>
|
||||
</span>
|
||||
@endif
|
||||
</div>
|
||||
</div>
|
||||
@if ($errors->has('email'))
|
||||
<span class="invalid-feedback">
|
||||
<strong>{{ $errors->first('email') }}</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>
|
||||
<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
|
||||
|
|
Loading…
Reference in a new issue