mirror of
https://github.com/BookStackApp/BookStack.git
synced 2024-10-01 01:36:00 -04:00
Updated email confirmation flow so confirmation is done via POST
To avoid non-user GET requests (Such as those from email scanners) auto-triggering the confirm submission. Made auto-submit the form via JavaScript in this extra added step with user-link backup to keep existing user flow experience. Closes #3797
This commit is contained in:
parent
0e627a6e05
commit
a1b1f8138a
@ -51,14 +51,28 @@ class ConfirmEmailController extends Controller
|
||||
return view('auth.user-unconfirmed', ['user' => $user]);
|
||||
}
|
||||
|
||||
/**
|
||||
* Show the form for a user to provide their positive confirmation of their email.
|
||||
*/
|
||||
public function showAcceptForm(string $token)
|
||||
{
|
||||
return view('auth.register-confirm-accept', ['token' => $token]);
|
||||
}
|
||||
|
||||
/**
|
||||
* Confirms an email via a token and logs the user into the system.
|
||||
*
|
||||
* @throws ConfirmationEmailException
|
||||
* @throws Exception
|
||||
*/
|
||||
public function confirm(string $token)
|
||||
public function confirm(Request $request)
|
||||
{
|
||||
$validated = $this->validate($request, [
|
||||
'token' => ['required', 'string']
|
||||
]);
|
||||
|
||||
$token = $validated['token'];
|
||||
|
||||
try {
|
||||
$userId = $this->emailConfirmationService->checkTokenAndGetUserId($token);
|
||||
} catch (UserTokenNotFoundException $exception) {
|
||||
|
12
resources/js/components/auto-submit.js
Normal file
12
resources/js/components/auto-submit.js
Normal file
@ -0,0 +1,12 @@
|
||||
|
||||
class AutoSubmit {
|
||||
|
||||
setup() {
|
||||
this.form = this.$el;
|
||||
|
||||
this.form.submit();
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
export default AutoSubmit;
|
@ -4,6 +4,7 @@ import ajaxForm from "./ajax-form.js"
|
||||
import attachments from "./attachments.js"
|
||||
import attachmentsList from "./attachments-list.js"
|
||||
import autoSuggest from "./auto-suggest.js"
|
||||
import autoSubmit from "./auto-submit.js";
|
||||
import backToTop from "./back-to-top.js"
|
||||
import bookSort from "./book-sort.js"
|
||||
import chapterContents from "./chapter-contents.js"
|
||||
@ -64,6 +65,7 @@ const componentMapping = {
|
||||
"attachments": attachments,
|
||||
"attachments-list": attachmentsList,
|
||||
"auto-suggest": autoSuggest,
|
||||
"auto-submit": autoSubmit,
|
||||
"back-to-top": backToTop,
|
||||
"book-sort": bookSort,
|
||||
"chapter-contents": chapterContents,
|
||||
|
@ -61,6 +61,8 @@ return [
|
||||
'email_confirm_send_error' => 'Email confirmation required but the system could not send the email. Contact the admin to ensure email is set up correctly.',
|
||||
'email_confirm_success' => 'Your email has been confirmed! You should now be able to login using this email address.',
|
||||
'email_confirm_resent' => 'Confirmation email resent, Please check your inbox.',
|
||||
'email_confirm_thanks' => 'Thanks for confirming!',
|
||||
'email_confirm_thanks_desc' => 'Please wait a moment while your confirmation is handled. If you are not redirected after 3 seconds press the "Continue" link below to proceed.',
|
||||
|
||||
'email_not_confirmed' => 'Email Address Not Confirmed',
|
||||
'email_not_confirmed_text' => 'Your email address has not yet been confirmed.',
|
||||
|
27
resources/views/auth/register-confirm-accept.blade.php
Normal file
27
resources/views/auth/register-confirm-accept.blade.php
Normal file
@ -0,0 +1,27 @@
|
||||
@extends('layouts.simple')
|
||||
|
||||
@section('content')
|
||||
|
||||
<div class="container very-small mt-xl">
|
||||
<div class="card content-wrap auto-height">
|
||||
<h1 class="list-heading">{{ trans('auth.email_confirm_thanks') }}</h1>
|
||||
|
||||
<p class="mb-none">{{ trans('auth.email_confirm_thanks_desc') }}</p>
|
||||
|
||||
<div class="flex-container-row items-center wrap">
|
||||
<div class="flex min-width-s">
|
||||
@include('common.loading-icon')
|
||||
</div>
|
||||
<div class="flex min-width-s text-s-right">
|
||||
<form component="auto-submit" action="{{ url('/register/confirm/accept') }}" method="post">
|
||||
{{ csrf_field() }}
|
||||
<input type="hidden" name="token" value="{{ $token }}">
|
||||
<button class="text-button">{{ trans('common.continue') }}</button>
|
||||
</form>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
</div>
|
||||
</div>
|
||||
|
||||
@stop
|
@ -316,7 +316,8 @@ Route::get('/register', [Auth\RegisterController::class, 'getRegister']);
|
||||
Route::get('/register/confirm', [Auth\ConfirmEmailController::class, 'show']);
|
||||
Route::get('/register/confirm/awaiting', [Auth\ConfirmEmailController::class, 'showAwaiting']);
|
||||
Route::post('/register/confirm/resend', [Auth\ConfirmEmailController::class, 'resend']);
|
||||
Route::get('/register/confirm/{token}', [Auth\ConfirmEmailController::class, 'confirm']);
|
||||
Route::get('/register/confirm/{token}', [Auth\ConfirmEmailController::class, 'showAcceptForm']);
|
||||
Route::post('/register/confirm/accept', [Auth\ConfirmEmailController::class, 'confirm']);
|
||||
Route::post('/register', [Auth\RegisterController::class, 'postRegister']);
|
||||
|
||||
// SAML routes
|
||||
|
@ -46,8 +46,18 @@ class RegistrationTest extends TestCase
|
||||
return $notification->token === $emailConfirmation->token;
|
||||
});
|
||||
|
||||
// Check confirmation email confirmation activation.
|
||||
$this->get('/register/confirm/' . $emailConfirmation->token)->assertRedirect('/login');
|
||||
// Check confirmation email confirmation accept page.
|
||||
$resp = $this->get('/register/confirm/' . $emailConfirmation->token);
|
||||
$acceptPage = $this->withHtml($resp);
|
||||
$resp->assertOk();
|
||||
$resp->assertSee('Thanks for confirming!');
|
||||
$acceptPage->assertElementExists('form[method="post"][action$="/register/confirm/accept"][component="auto-submit"] button');
|
||||
$acceptPage->assertFieldHasValue('token', $emailConfirmation->token);
|
||||
|
||||
// Check acceptance confirm
|
||||
$this->post('/register/confirm/accept', ['token' => $emailConfirmation->token])->assertRedirect('/login');
|
||||
|
||||
// Check state on login redirect
|
||||
$this->get('/login')->assertSee('Your email has been confirmed! You should now be able to login using this email address.');
|
||||
$this->assertDatabaseMissing('email_confirmations', ['token' => $emailConfirmation->token]);
|
||||
$this->assertDatabaseHas('users', ['name' => $dbUser->name, 'email' => $dbUser->email, 'email_confirmed' => true]);
|
||||
|
Loading…
Reference in New Issue
Block a user