Enabled session in 404 responses

Fixes #634
This commit is contained in:
Dan Brown 2017-12-28 13:19:02 +00:00
parent 8b160b9fb4
commit afe781bc39
No known key found for this signature in database
GPG Key ID: 46D9F943C24A2EF9
6 changed files with 55 additions and 5 deletions

View File

@ -4,11 +4,14 @@ namespace BookStack\Exceptions;
use Exception; use Exception;
use Illuminate\Auth\AuthenticationException; use Illuminate\Auth\AuthenticationException;
use Illuminate\Http\Request;
use Illuminate\Pipeline\Pipeline;
use Illuminate\Validation\ValidationException; use Illuminate\Validation\ValidationException;
use Illuminate\Database\Eloquent\ModelNotFoundException; use Illuminate\Database\Eloquent\ModelNotFoundException;
use Symfony\Component\HttpKernel\Exception\HttpException; use Symfony\Component\HttpKernel\Exception\HttpException;
use Illuminate\Foundation\Exceptions\Handler as ExceptionHandler; use Illuminate\Foundation\Exceptions\Handler as ExceptionHandler;
use Illuminate\Auth\Access\AuthorizationException; use Illuminate\Auth\Access\AuthorizationException;
use Symfony\Component\HttpKernel\Exception\NotFoundHttpException;
class Handler extends ExceptionHandler class Handler extends ExceptionHandler
{ {
@ -60,9 +63,32 @@ class Handler extends ExceptionHandler
return response()->view('errors/' . $code, ['message' => $message], $code); return response()->view('errors/' . $code, ['message' => $message], $code);
} }
// Handle 404 errors with a loaded session to enable showing user-specific information
if ($this->isExceptionType($e, NotFoundHttpException::class)) {
return $this->loadErrorMiddleware($request, function ($request) use ($e) {
$message = $e->getMessage() ?: trans('errors.404_page_not_found');
return response()->view('errors/404', ['message' => $message], 404);
});
}
return parent::render($request, $e); return parent::render($request, $e);
} }
/**
* Load the middleware required to show state/session-enabled error pages.
* @param Request $request
* @param $callback
* @return mixed
*/
protected function loadErrorMiddleware(Request $request, $callback)
{
$middleware = (\Route::getMiddlewareGroups()['web_errors']);
return (new Pipeline($this->container))
->send($request)
->through($middleware)
->then($callback);
}
/** /**
* Check the exception chain to compare against the original exception type. * Check the exception chain to compare against the original exception type.
* @param Exception $e * @param Exception $e

View File

@ -145,6 +145,7 @@ class PageController extends Controller
* @param string $bookSlug * @param string $bookSlug
* @param string $pageSlug * @param string $pageSlug
* @return Response * @return Response
* @throws NotFoundException
*/ */
public function show($bookSlug, $pageSlug) public function show($bookSlug, $pageSlug)
{ {
@ -152,7 +153,7 @@ class PageController extends Controller
$page = $this->entityRepo->getBySlug('page', $pageSlug, $bookSlug); $page = $this->entityRepo->getBySlug('page', $pageSlug, $bookSlug);
} catch (NotFoundException $e) { } catch (NotFoundException $e) {
$page = $this->entityRepo->getPageByOldSlug($pageSlug, $bookSlug); $page = $this->entityRepo->getPageByOldSlug($pageSlug, $bookSlug);
if ($page === null) abort(404); if ($page === null) throw $e;
return redirect($page->getUrl()); return redirect($page->getUrl());
} }

View File

@ -33,6 +33,14 @@ class Kernel extends HttpKernel
\Illuminate\Routing\Middleware\SubstituteBindings::class, \Illuminate\Routing\Middleware\SubstituteBindings::class,
\BookStack\Http\Middleware\Localization::class \BookStack\Http\Middleware\Localization::class
], ],
'web_errors' => [
\BookStack\Http\Middleware\EncryptCookies::class,
\Illuminate\Cookie\Middleware\AddQueuedCookiesToResponse::class,
\Illuminate\Session\Middleware\StartSession::class,
\Illuminate\View\Middleware\ShareErrorsFromSession::class,
\BookStack\Http\Middleware\VerifyCsrfToken::class,
\BookStack\Http\Middleware\Localization::class
],
'api' => [ 'api' => [
'throttle:60,1', 'throttle:60,1',
'bindings', 'bindings',

View File

@ -1,8 +1,6 @@
@extends('simple-layout') @extends('simple-layout')
@section('content') @section('content')
<div class="container"> <div class="container">
<p>&nbsp;</p> <p>&nbsp;</p>
@ -16,7 +14,6 @@
</div> </div>
@if (setting('app-public') || !user()->isDefault()) @if (setting('app-public') || !user()->isDefault())
<div class="row"> <div class="row">
<div class="col-md-4"> <div class="col-md-4">
<div class="card"> <div class="card">

View File

@ -6,7 +6,7 @@
<div class="card"> <div class="card">
<h3 class="text-muted">{{ trans('errors.error_occurred') }}</h3> <h3 class="text-muted">{{ trans('errors.error_occurred') }}</h3>
<div class="body"> <div class="body">
<h5>{{ $message }}</h5> <h5>{{ $message or 'An unknown error occurred' }}</h5>
<p><a href="{{ baseUrl('/') }}" class="button outline">{{ trans('errors.return_home') }}</a></p> <p><a href="{{ baseUrl('/') }}" class="button outline">{{ trans('errors.return_home') }}</a></p>
</div> </div>
</div> </div>

18
tests/ErrorTest.php Normal file
View File

@ -0,0 +1,18 @@
<?php namespace Tests;
class ErrorTest extends TestCase
{
public function test_404_page_does_not_show_login()
{
// Due to middleware being handled differently this will not fail
// if our custom, middleware-loaded handler fails but this is here
// as a reminder and as a general check in the event of other issues.
$editor = $this->getEditor();
$this->actingAs($editor);
$notFound = $this->get('/fgfdngldfnotfound');
$notFound->assertStatus(404);
$notFound->assertDontSeeText('Log in');
$notFound->assertSeeText($editor->getShortName(9));
}
}