mirror of
https://github.com/flarum/core.git
synced 2025-08-02 22:47:33 +02:00
merges 5.5 and master into next-back
This commit is contained in:
@@ -11,28 +11,30 @@
|
||||
|
||||
namespace Flarum\Http\Controller;
|
||||
|
||||
use Illuminate\Contracts\Support\Renderable;
|
||||
use Psr\Http\Message\ServerRequestInterface as Request;
|
||||
use Zend\Diactoros\Response;
|
||||
use Zend\Diactoros\Response\HtmlResponse;
|
||||
|
||||
abstract class AbstractHtmlController implements ControllerInterface
|
||||
{
|
||||
/**
|
||||
* @param Request $request
|
||||
* @return \Zend\Diactoros\Response
|
||||
* @return HtmlResponse
|
||||
*/
|
||||
public function handle(Request $request)
|
||||
{
|
||||
$view = $this->render($request);
|
||||
|
||||
$response = new Response;
|
||||
$response->getBody()->write($view);
|
||||
if ($view instanceof Renderable) {
|
||||
$view = $view->render();
|
||||
}
|
||||
|
||||
return $response;
|
||||
return new HtmlResponse($view);
|
||||
}
|
||||
|
||||
/**
|
||||
* @param Request $request
|
||||
* @return \Illuminate\Contracts\Support\Renderable
|
||||
* @return string|Renderable
|
||||
*/
|
||||
abstract protected function render(Request $request);
|
||||
}
|
||||
|
@@ -17,16 +17,46 @@ use Flarum\Foundation\Application;
|
||||
class CookieFactory
|
||||
{
|
||||
/**
|
||||
* @var Application
|
||||
* The prefix for the cookie names.
|
||||
*
|
||||
* @var string
|
||||
*/
|
||||
protected $app;
|
||||
protected $prefix;
|
||||
|
||||
/**
|
||||
* A path scope for the cookies.
|
||||
*
|
||||
* @var string
|
||||
*/
|
||||
protected $path;
|
||||
|
||||
/**
|
||||
* A domain scope for the cookies.
|
||||
*
|
||||
* @var string
|
||||
*/
|
||||
protected $domain;
|
||||
|
||||
/**
|
||||
* Whether the cookie(s) can be requested only over HTTPS.
|
||||
*
|
||||
* @var bool
|
||||
*/
|
||||
protected $secure;
|
||||
|
||||
/**
|
||||
* @param Application $app
|
||||
*/
|
||||
public function __construct(Application $app)
|
||||
{
|
||||
$this->app = $app;
|
||||
// Parse the forum's base URL so that we can determine the optimal cookie settings
|
||||
$url = parse_url(rtrim($app->url(), '/'));
|
||||
|
||||
// Get the cookie settings from the config or use the default values
|
||||
$this->prefix = $app->config('cookie.name', 'flarum');
|
||||
$this->path = $app->config('cookie.path', array_get($url, 'path') ?: '/');
|
||||
$this->domain = $app->config('cookie.domain');
|
||||
$this->secure = $app->config('cookie.secure', array_get($url, 'scheme') === 'https');
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -42,10 +72,7 @@ class CookieFactory
|
||||
*/
|
||||
public function make($name, $value = null, $maxAge = null)
|
||||
{
|
||||
// Parse the forum's base URL so that we can determine the optimal cookie settings
|
||||
$url = parse_url(rtrim($this->app->url(), '/'));
|
||||
|
||||
$cookie = SetCookie::create($name, $value);
|
||||
$cookie = SetCookie::create($this->getName($name), $value);
|
||||
|
||||
// Make sure we send both the MaxAge and Expires parameters (the former
|
||||
// is not supported by all browser versions)
|
||||
@@ -55,9 +82,35 @@ class CookieFactory
|
||||
->withExpires(time() + $maxAge);
|
||||
}
|
||||
|
||||
if ($this->domain != null) {
|
||||
$cookie = $cookie->withDomain($this->domain);
|
||||
}
|
||||
|
||||
return $cookie
|
||||
->withPath(array_get($url, 'path') ?: '/')
|
||||
->withSecure(array_get($url, 'scheme') === 'https')
|
||||
->withPath($this->path)
|
||||
->withSecure($this->secure)
|
||||
->withHttpOnly(true);
|
||||
}
|
||||
|
||||
/**
|
||||
* Make an expired cookie instance.
|
||||
*
|
||||
* @param string $name
|
||||
* @return \Dflydev\FigCookies\SetCookie
|
||||
*/
|
||||
public function expire($name)
|
||||
{
|
||||
return $this->make($name)->expire();
|
||||
}
|
||||
|
||||
/**
|
||||
* Get a cookie name.
|
||||
*
|
||||
* @param string $name
|
||||
* @return string
|
||||
*/
|
||||
public function getName($name)
|
||||
{
|
||||
return $this->prefix.'_'.$name;
|
||||
}
|
||||
}
|
||||
|
@@ -20,10 +20,7 @@ use Zend\Stratigility\MiddlewareInterface;
|
||||
|
||||
class AuthenticateWithHeader implements MiddlewareInterface
|
||||
{
|
||||
/**
|
||||
* @var string
|
||||
*/
|
||||
protected $prefix = 'Token ';
|
||||
const TOKEN_PREFIX = 'Token ';
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
@@ -34,13 +31,14 @@ class AuthenticateWithHeader implements MiddlewareInterface
|
||||
|
||||
$parts = explode(';', $headerLine);
|
||||
|
||||
if (isset($parts[0]) && starts_with($parts[0], $this->prefix)) {
|
||||
$id = substr($parts[0], strlen($this->prefix));
|
||||
if (isset($parts[0]) && starts_with($parts[0], self::TOKEN_PREFIX)) {
|
||||
$id = substr($parts[0], strlen(self::TOKEN_PREFIX));
|
||||
|
||||
if (isset($parts[1])) {
|
||||
if (ApiKey::find($id)) {
|
||||
if ($key = ApiKey::find($id)) {
|
||||
$actor = $this->getUser($parts[1]);
|
||||
|
||||
$request = $request->withAttribute('apiKey', $key);
|
||||
$request = $request->withAttribute('bypassFloodgate', true);
|
||||
}
|
||||
} elseif ($token = AccessToken::find($id)) {
|
||||
|
@@ -12,38 +12,55 @@
|
||||
namespace Flarum\Http\Middleware;
|
||||
|
||||
use Exception;
|
||||
use Flarum\Settings\SettingsRepositoryInterface;
|
||||
use Franzl\Middleware\Whoops\ErrorMiddleware as WhoopsMiddleware;
|
||||
use Illuminate\Contracts\View\Factory as ViewFactory;
|
||||
use Psr\Http\Message\ResponseInterface as Response;
|
||||
use Psr\Http\Message\ServerRequestInterface as Request;
|
||||
use Psr\Log\LoggerInterface;
|
||||
use Symfony\Component\Translation\TranslatorInterface;
|
||||
use Zend\Diactoros\Response\HtmlResponse;
|
||||
|
||||
class HandleErrors
|
||||
{
|
||||
/**
|
||||
* @var string
|
||||
* @var ViewFactory
|
||||
*/
|
||||
protected $templateDir;
|
||||
protected $view;
|
||||
|
||||
/**
|
||||
* @var LoggerInterface
|
||||
*/
|
||||
protected $logger;
|
||||
|
||||
/**
|
||||
* @var TranslatorInterface
|
||||
*/
|
||||
protected $translator;
|
||||
|
||||
/**
|
||||
* @var SettingsRepositoryInterface
|
||||
*/
|
||||
protected $settings;
|
||||
|
||||
/**
|
||||
* @var bool
|
||||
*/
|
||||
protected $debug;
|
||||
|
||||
/**
|
||||
* @param string $templateDir
|
||||
* @param ViewFactory $view
|
||||
* @param LoggerInterface $logger
|
||||
* @param TranslatorInterface $translator
|
||||
* @param SettingsRepositoryInterface $settings
|
||||
* @param bool $debug
|
||||
*/
|
||||
public function __construct($templateDir, LoggerInterface $logger, $debug = false)
|
||||
public function __construct(ViewFactory $view, LoggerInterface $logger, TranslatorInterface $translator, SettingsRepositoryInterface $settings, $debug = false)
|
||||
{
|
||||
$this->templateDir = $templateDir;
|
||||
$this->view = $view;
|
||||
$this->logger = $logger;
|
||||
$this->translator = $translator;
|
||||
$this->settings = $settings;
|
||||
$this->debug = $debug;
|
||||
}
|
||||
|
||||
@@ -75,7 +92,7 @@ class HandleErrors
|
||||
$status = $errorCode;
|
||||
}
|
||||
|
||||
if ($this->debug && ! in_array($errorCode, [403, 404])) {
|
||||
if ($this->debug) {
|
||||
$whoops = new WhoopsMiddleware;
|
||||
|
||||
return $whoops($error, $request, $response, $out);
|
||||
@@ -84,21 +101,33 @@ class HandleErrors
|
||||
// Log the exception (with trace)
|
||||
$this->logger->debug($error);
|
||||
|
||||
$errorPage = $this->getErrorPage($status);
|
||||
|
||||
return new HtmlResponse($errorPage, $status);
|
||||
}
|
||||
|
||||
/**
|
||||
* @param string $status
|
||||
* @return string
|
||||
*/
|
||||
protected function getErrorPage($status)
|
||||
{
|
||||
if (! file_exists($errorPage = $this->templateDir."/$status.html")) {
|
||||
$errorPage = $this->templateDir.'/500.html';
|
||||
if (! $this->view->exists($name = 'flarum.forum::error.'.$status)) {
|
||||
$name = 'flarum.forum::error.default';
|
||||
}
|
||||
|
||||
return file_get_contents($errorPage);
|
||||
$view = $this->view->make($name)
|
||||
->with('error', $error)
|
||||
->with('message', $this->getMessage($status));
|
||||
|
||||
return new HtmlResponse($view->render(), $status);
|
||||
}
|
||||
|
||||
private function getMessage($status)
|
||||
{
|
||||
if (! $translation = $this->getTranslationIfExists($status)) {
|
||||
if (! $translation = $this->getTranslationIfExists(500)) {
|
||||
$translation = 'An error occurred while trying to load this page.';
|
||||
}
|
||||
}
|
||||
|
||||
return $translation;
|
||||
}
|
||||
|
||||
private function getTranslationIfExists($status)
|
||||
{
|
||||
$key = 'core.views.error.'.$status.'_message';
|
||||
$translation = $this->translator->trans($key, ['{forum}' => $this->settings->get('forum_title')]);
|
||||
|
||||
return $translation === $key ? false : $translation;
|
||||
}
|
||||
}
|
||||
|
62
src/Http/Middleware/ShareErrorsFromSession.php
Normal file
62
src/Http/Middleware/ShareErrorsFromSession.php
Normal file
@@ -0,0 +1,62 @@
|
||||
<?php
|
||||
/*
|
||||
* This file is part of Flarum.
|
||||
*
|
||||
* (c) Toby Zerner <toby.zerner@gmail.com>
|
||||
*
|
||||
* For the full copyright and license information, please view the LICENSE
|
||||
* file that was distributed with this source code.
|
||||
*/
|
||||
|
||||
namespace Flarum\Http\Middleware;
|
||||
|
||||
use Illuminate\Contracts\View\Factory as ViewFactory;
|
||||
use Illuminate\Support\ViewErrorBag;
|
||||
use Psr\Http\Message\ResponseInterface as Response;
|
||||
use Psr\Http\Message\ServerRequestInterface as Request;
|
||||
use Zend\Stratigility\MiddlewareInterface;
|
||||
|
||||
/**
|
||||
* Inspired by Illuminate\View\Middleware\ShareErrorsFromSession.
|
||||
*
|
||||
* @author Taylor Otwell
|
||||
*/
|
||||
class ShareErrorsFromSession implements MiddlewareInterface
|
||||
{
|
||||
/**
|
||||
* @var ViewFactory
|
||||
*/
|
||||
protected $view;
|
||||
|
||||
/**
|
||||
* @param ViewFactory $view
|
||||
*/
|
||||
public function __construct(ViewFactory $view)
|
||||
{
|
||||
$this->view = $view;
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function __invoke(Request $request, Response $response, callable $out = null)
|
||||
{
|
||||
$session = $request->getAttribute('session');
|
||||
|
||||
// If the current session has an "errors" variable bound to it, we will share
|
||||
// its value with all view instances so the views can easily access errors
|
||||
// without having to bind. An empty bag is set when there aren't errors.
|
||||
$this->view->share(
|
||||
'errors', $session->get('errors', new ViewErrorBag)
|
||||
);
|
||||
|
||||
// Putting the errors in the view for every view allows the developer to just
|
||||
// assume that some errors are always available, which is convenient since
|
||||
// they don't have to continually run checks for the presence of errors.
|
||||
|
||||
$session->remove('errors');
|
||||
|
||||
return $out ? $out($request, $response) : $response;
|
||||
}
|
||||
}
|
||||
|
@@ -22,13 +22,14 @@ use Zend\Stratigility\MiddlewareInterface;
|
||||
|
||||
class StartSession implements MiddlewareInterface
|
||||
{
|
||||
const COOKIE_NAME = 'session';
|
||||
|
||||
/**
|
||||
* @var CookieFactory
|
||||
*/
|
||||
protected $cookie;
|
||||
|
||||
/**
|
||||
* Rememberer constructor.
|
||||
* @param CookieFactory $cookie
|
||||
*/
|
||||
public function __construct(CookieFactory $cookie)
|
||||
@@ -56,7 +57,7 @@ class StartSession implements MiddlewareInterface
|
||||
{
|
||||
$session = new Session;
|
||||
|
||||
$session->setName('flarum_session');
|
||||
$session->setName($this->cookie->getName(self::COOKIE_NAME));
|
||||
$session->start();
|
||||
|
||||
if (! $session->has('csrf_token')) {
|
||||
@@ -79,7 +80,7 @@ class StartSession implements MiddlewareInterface
|
||||
{
|
||||
return FigResponseCookies::set(
|
||||
$response,
|
||||
$this->cookie->make($session->getName(), $session->getId())
|
||||
$this->cookie->make(self::COOKIE_NAME, $session->getId())
|
||||
);
|
||||
}
|
||||
}
|
||||
|
@@ -16,7 +16,7 @@ use Psr\Http\Message\ResponseInterface;
|
||||
|
||||
class Rememberer
|
||||
{
|
||||
protected $cookieName = 'flarum_remember';
|
||||
const COOKIE_NAME = 'remember';
|
||||
|
||||
/**
|
||||
* @var CookieFactory
|
||||
@@ -24,7 +24,6 @@ class Rememberer
|
||||
protected $cookie;
|
||||
|
||||
/**
|
||||
* Rememberer constructor.
|
||||
* @param CookieFactory $cookie
|
||||
*/
|
||||
public function __construct(CookieFactory $cookie)
|
||||
@@ -32,18 +31,16 @@ class Rememberer
|
||||
$this->cookie = $cookie;
|
||||
}
|
||||
|
||||
public function remember(ResponseInterface $response, AccessToken $token, $session = false)
|
||||
public function remember(ResponseInterface $response, AccessToken $token)
|
||||
{
|
||||
$lifetime = null;
|
||||
|
||||
if (! $session) {
|
||||
$token->lifetime = $lifetime = 5 * 365 * 24 * 60 * 60; // 5 years
|
||||
$token->save();
|
||||
}
|
||||
$token->lifetime = 5 * 365 * 24 * 60 * 60; // 5 years
|
||||
$token->save();
|
||||
|
||||
return FigResponseCookies::set(
|
||||
$response,
|
||||
$this->cookie->make($this->cookieName, $token->id, $lifetime)
|
||||
$this->cookie->make(self::COOKIE_NAME, $token->id, $token->lifetime)
|
||||
);
|
||||
}
|
||||
|
||||
@@ -56,6 +53,9 @@ class Rememberer
|
||||
|
||||
public function forget(ResponseInterface $response)
|
||||
{
|
||||
return FigResponseCookies::expire($response, $this->cookieName);
|
||||
return FigResponseCookies::set(
|
||||
$response,
|
||||
$this->cookie->expire(self::COOKIE_NAME)
|
||||
);
|
||||
}
|
||||
}
|
||||
|
Reference in New Issue
Block a user