1
0
mirror of https://github.com/flarum/core.git synced 2025-08-21 07:41:49 +02:00

Merge branch 'sudo-mode'

# Conflicts:
#	CHANGELOG.md
This commit is contained in:
Toby Zerner
2015-12-03 15:12:51 +10:30
68 changed files with 1071 additions and 509 deletions

View File

@@ -42,6 +42,8 @@ class AdminServiceProvider extends AbstractServiceProvider
*/
public function boot()
{
$this->loadViewsFrom(__DIR__.'/../../views', 'flarum.admin');
$this->flushAssetsWhenThemeChanged();
$this->flushAssetsWhenExtensionsChanged();

View File

@@ -10,26 +10,39 @@
namespace Flarum\Admin\Middleware;
use Flarum\Core\Access\Gate;
use Exception;
use Flarum\Core\Access\AssertPermissionTrait;
use Flarum\Forum\Controller\LogInController;
use Illuminate\Contracts\Container\Container;
use Illuminate\Contracts\View\Factory;
use Psr\Http\Message\ResponseInterface as Response;
use Psr\Http\Message\ServerRequestInterface as Request;
use Flarum\Core\Exception\PermissionDeniedException;
use Zend\Diactoros\Response\HtmlResponse;
use Zend\Diactoros\Response\RedirectResponse;
use Zend\Stratigility\MiddlewareInterface;
class RequireAdministrateAbility implements MiddlewareInterface
{
/**
* @var Gate
*/
protected $gate;
use AssertPermissionTrait;
/**
* @param Gate $gate
* @var LogInController
*/
public function __construct(Gate $gate)
private $logInController;
/**
* @var Factory
*/
private $view;
/**
* @param LogInController $logInController
* @param Factory $view
*/
public function __construct(LogInController $logInController, Factory $view)
{
$this->gate = $gate;
$this->logInController = $logInController;
$this->view = $view;
}
/**
@@ -37,10 +50,24 @@ class RequireAdministrateAbility implements MiddlewareInterface
*/
public function __invoke(Request $request, Response $response, callable $out = null)
{
$actor = $request->getAttribute('actor');
try {
$this->assertAdminAndSudo($request);
} catch (Exception $e) {
if ($request->getMethod() === 'POST') {
$response = $this->logInController->handle($request);
if (! $this->gate->forUser($actor)->allows('administrate')) {
throw new PermissionDeniedException;
if ($response->getStatusCode() === 200) {
return $response
->withStatus(302)
->withHeader('location', app('Flarum\Admin\UrlGenerator')->toRoute('index'));
}
}
return new HtmlResponse(
$this->view->make('flarum.admin::login')
->with('token', $request->getAttribute('session')->csrf_token)
->render()
);
}
return $out ? $out($request, $response) : $response;

View File

@@ -13,6 +13,7 @@ namespace Flarum\Admin;
use Flarum\Foundation\Application;
use Flarum\Http\AbstractServer;
use Zend\Diactoros\Response\HtmlResponse;
use Zend\Stratigility\MiddlewarePipe;
use Flarum\Http\Middleware\HandleErrors;
@@ -30,8 +31,10 @@ class Server extends AbstractServer
$errorDir = __DIR__ . '/../../error';
if ($app->isUpToDate()) {
$pipe->pipe($adminPath, $app->make('Flarum\Http\Middleware\AuthenticateWithCookie'));
$pipe->pipe($adminPath, $app->make('Flarum\Http\Middleware\ParseJsonBody'));
$pipe->pipe($adminPath, $app->make('Flarum\Http\Middleware\AuthorizeWithCookie'));
$pipe->pipe($adminPath, $app->make('Flarum\Http\Middleware\StartSession'));
$pipe->pipe($adminPath, $app->make('Flarum\Http\Middleware\SetLocale'));
$pipe->pipe($adminPath, $app->make('Flarum\Admin\Middleware\RequireAdministrateAbility'));
$pipe->pipe($adminPath, $app->make('Flarum\Http\Middleware\DispatchRoute', ['routes' => $app->make('flarum.admin.routes')]));
$pipe->pipe($adminPath, new HandleErrors($errorDir, $app->inDebugMode()));

View File

@@ -1,80 +0,0 @@
<?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\Api;
use Flarum\Database\AbstractModel;
use DateTime;
/**
* @property string $id
* @property int $user_id
* @property \Carbon\Carbon $created_at
* @property \Carbon\Carbon $expires_at
* @property \Flarum\Core\User|null $user
*/
class AccessToken extends AbstractModel
{
/**
* {@inheritdoc}
*/
protected $table = 'access_tokens';
/**
* Use a custom primary key for this model.
*
* @var bool
*/
public $incrementing = false;
/**
* {@inheritdoc}
*/
protected $dates = ['created_at', 'expires_at'];
/**
* Generate an access token for the specified user.
*
* @param int $userId
* @param int $minutes
* @return static
*/
public static function generate($userId, $minutes = 60)
{
$token = new static;
$token->id = str_random(40);
$token->user_id = $userId;
$token->created_at = time();
$token->expires_at = time() + $minutes * 60;
return $token;
}
/**
* Check that the token has not expired.
*
* @return bool
*/
public function isValid()
{
return $this->expires_at > new DateTime;
}
/**
* Define the relationship with the owner of this access token.
*
* @return \Illuminate\Database\Eloquent\Relations\BelongsTo
*/
public function user()
{
return $this->belongsTo('Flarum\Core\User');
}
}

View File

@@ -44,9 +44,13 @@ class ApiServiceProvider extends AbstractServiceProvider
$handler->registerHandler(new Handler\FloodingExceptionHandler);
$handler->registerHandler(new Handler\IlluminateValidationExceptionHandler);
$handler->registerHandler(new Handler\InvalidAccessTokenExceptionHandler);
$handler->registerHandler(new Handler\InvalidConfirmationTokenExceptionHandler);
$handler->registerHandler(new Handler\MethodNotAllowedExceptionHandler);
$handler->registerHandler(new Handler\ModelNotFoundExceptionHandler);
$handler->registerHandler(new Handler\PermissionDeniedExceptionHandler);
$handler->registerHandler(new Handler\RouteNotFoundExceptionHandler);
$handler->registerHandler(new Handler\TokenMismatchExceptionHandler);
$handler->registerHandler(new Handler\ValidationExceptionHandler);
$handler->registerHandler(new InvalidParameterExceptionHandler);
$handler->registerHandler(new FallbackExceptionHandler($this->app->inDebugMode()));

View File

@@ -12,6 +12,7 @@ namespace Flarum\Api;
use Flarum\Http\Controller\ControllerInterface;
use Flarum\Core\User;
use Flarum\Http\Session;
use Illuminate\Contracts\Container\Container;
use Exception;
use InvalidArgumentException;
@@ -43,14 +44,23 @@ class Client
* Execute the given API action class, pass the input and return its response.
*
* @param string|ControllerInterface $controller
* @param User $actor
* @param Session|User|null $session
* @param array $queryParams
* @param array $body
* @return \Psr\Http\Message\ResponseInterface
*/
public function send($controller, User $actor, array $queryParams = [], array $body = [])
public function send($controller, $session, array $queryParams = [], array $body = [])
{
$request = ServerRequestFactory::fromGlobals(null, $queryParams, $body)->withAttribute('actor', $actor);
$request = ServerRequestFactory::fromGlobals(null, $queryParams, $body);
if ($session instanceof Session) {
$request = $request->withAttribute('session', $session);
$actor = $session->user;
} else {
$actor = $session;
}
$request = $request->withAttribute('actor', $actor);
if (is_string($controller)) {
$controller = $this->container->make($controller);

View File

@@ -1,29 +0,0 @@
<?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\Api\Command;
class GenerateAccessToken
{
/**
* The ID of the user to generate an access token for.
*
* @var int
*/
public $userId;
/**
* @param int $userId The ID of the user to generate an access token for.
*/
public function __construct($userId)
{
$this->userId = $userId;
}
}

View File

@@ -1,30 +0,0 @@
<?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\Api\Command;
use Flarum\Api\AccessToken;
use Flarum\Api\Command\GenerateAccessToken;
class GenerateAccessTokenHandler
{
/**
* @param GenerateAccessToken $command
* @return AccessToken
*/
public function handle(GenerateAccessToken $command)
{
$token = AccessToken::generate($command->userId);
$token->save();
return $token;
}
}

View File

@@ -10,12 +10,15 @@
namespace Flarum\Api\Controller;
use Flarum\Core\Access\AssertPermissionTrait;
use Flarum\Core\Command\DeleteDiscussion;
use Illuminate\Contracts\Bus\Dispatcher;
use Psr\Http\Message\ServerRequestInterface;
class DeleteDiscussionController extends AbstractDeleteController
{
use AssertPermissionTrait;
/**
* @var Dispatcher
*/
@@ -38,6 +41,8 @@ class DeleteDiscussionController extends AbstractDeleteController
$actor = $request->getAttribute('actor');
$input = $request->getParsedBody();
$this->assertSudo($request);
$this->bus->dispatch(
new DeleteDiscussion($id, $actor, $input)
);

View File

@@ -10,12 +10,15 @@
namespace Flarum\Api\Controller;
use Flarum\Core\Access\AssertPermissionTrait;
use Flarum\Core\Command\DeleteGroup;
use Illuminate\Contracts\Bus\Dispatcher;
use Psr\Http\Message\ServerRequestInterface;
class DeleteGroupController extends AbstractDeleteController
{
use AssertPermissionTrait;
/**
* @var Dispatcher
*/
@@ -34,6 +37,8 @@ class DeleteGroupController extends AbstractDeleteController
*/
protected function delete(ServerRequestInterface $request)
{
$this->assertSudo($request);
$this->bus->dispatch(
new DeleteGroup(array_get($request->getQueryParams(), 'id'), $request->getAttribute('actor'))
);

View File

@@ -10,12 +10,15 @@
namespace Flarum\Api\Controller;
use Flarum\Core\Access\AssertPermissionTrait;
use Flarum\Core\Command\DeletePost;
use Illuminate\Contracts\Bus\Dispatcher;
use Psr\Http\Message\ServerRequestInterface;
class DeletePostController extends AbstractDeleteController
{
use AssertPermissionTrait;
/**
* @var Dispatcher
*/
@@ -34,6 +37,8 @@ class DeletePostController extends AbstractDeleteController
*/
protected function delete(ServerRequestInterface $request)
{
$this->assertSudo($request);
$this->bus->dispatch(
new DeletePost(array_get($request->getQueryParams(), 'id'), $request->getAttribute('actor'))
);

View File

@@ -10,12 +10,15 @@
namespace Flarum\Api\Controller;
use Flarum\Core\Access\AssertPermissionTrait;
use Flarum\Core\Command\DeleteUser;
use Illuminate\Contracts\Bus\Dispatcher;
use Psr\Http\Message\ServerRequestInterface;
class DeleteUserController extends AbstractDeleteController
{
use AssertPermissionTrait;
/**
* @var Dispatcher
*/
@@ -34,6 +37,8 @@ class DeleteUserController extends AbstractDeleteController
*/
protected function delete(ServerRequestInterface $request)
{
$this->assertSudo($request);
$this->bus->dispatch(
new DeleteUser(array_get($request->getQueryParams(), 'id'), $request->getAttribute('actor'))
);

View File

@@ -25,7 +25,7 @@ class SetPermissionController implements ControllerInterface
*/
public function handle(ServerRequestInterface $request)
{
$this->assertAdmin($request->getAttribute('actor'));
$this->assertAdminAndSudo($request);
$body = $request->getParsedBody();
$permission = array_get($body, 'permission');

View File

@@ -47,7 +47,7 @@ class SetSettingsController implements ControllerInterface
*/
public function handle(ServerRequestInterface $request)
{
$this->assertAdmin($request->getAttribute('actor'));
$this->assertAdminAndSudo($request);
$settings = $request->getParsedBody();

View File

@@ -10,11 +10,10 @@
namespace Flarum\Api\Controller;
use Flarum\Api\Command\GenerateAccessToken;
use Flarum\Core\Exception\PermissionDeniedException;
use Flarum\Core\Repository\UserRepository;
use Flarum\Event\UserEmailChangeWasRequested;
use Flarum\Http\Controller\ControllerInterface;
use Flarum\Http\Session;
use Illuminate\Contracts\Bus\Dispatcher as BusDispatcher;
use Illuminate\Contracts\Events\Dispatcher as EventDispatcher;
use Psr\Http\Message\ServerRequestInterface;
@@ -65,19 +64,13 @@ class TokenController implements ControllerInterface
throw new PermissionDeniedException;
}
if (! $user->is_activated) {
$this->events->fire(new UserEmailChangeWasRequested($user, $user->email));
$session = $request->getAttribute('session') ?: Session::generate($user);
$session->assign($user)->regenerateId()->renew()->save();
return new JsonResponse(['emailConfirmationRequired' => $user->email], 401);
}
$token = $this->bus->dispatch(
new GenerateAccessToken($user->id)
);
return new JsonResponse([
'token' => $token->id,
return (new JsonResponse([
'token' => $session->id,
'userId' => $user->id
]);
]))
->withHeader('X-CSRF-Token', $session->csrf_token);
}
}

View File

@@ -33,7 +33,7 @@ class UninstallExtensionController extends AbstractDeleteController
protected function delete(ServerRequestInterface $request)
{
$this->assertAdmin($request->getAttribute('actor'));
$this->assertAdminAndSudo($request);
$name = array_get($request->getQueryParams(), 'name');

View File

@@ -38,7 +38,7 @@ class UpdateExtensionController implements ControllerInterface
*/
public function handle(ServerRequestInterface $request)
{
$this->assertAdmin($request->getAttribute('actor'));
$this->assertAdminAndSudo($request);
$enabled = array_get($request->getParsedBody(), 'enabled');
$name = array_get($request->getQueryParams(), 'name');

View File

@@ -10,6 +10,7 @@
namespace Flarum\Api\Controller;
use Flarum\Core\Access\AssertPermissionTrait;
use Flarum\Core\Command\EditUser;
use Illuminate\Contracts\Bus\Dispatcher;
use Psr\Http\Message\ServerRequestInterface;
@@ -17,6 +18,8 @@ use Tobscure\JsonApi\Document;
class UpdateUserController extends AbstractResourceController
{
use AssertPermissionTrait;
/**
* {@inheritdoc}
*/
@@ -49,6 +52,8 @@ class UpdateUserController extends AbstractResourceController
$actor = $request->getAttribute('actor');
$data = array_get($request->getParsedBody(), 'data', []);
$this->assertSudo($request);
return $this->bus->dispatch(
new EditUser($id, $actor, $data)
);

View File

@@ -0,0 +1,17 @@
<?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\Api\Exception;
use Exception;
class InvalidAccessTokenException extends Exception
{
}

View File

@@ -31,7 +31,10 @@ class FloodingExceptionHandler implements ExceptionHandlerInterface
public function handle(Exception $e)
{
$status = 429;
$error = [];
$error = [
'status' => (string) $status,
'code' => 'too_many_requests'
];
return new ResponseBag($status, [$error]);
}

View File

@@ -44,8 +44,10 @@ class IlluminateValidationExceptionHandler implements ExceptionHandlerInterface
{
$errors = array_map(function ($field, $messages) {
return [
'status' => '422',
'code' => 'validation_error',
'detail' => implode("\n", $messages),
'source' => ['pointer' => '/data/attributes/' . $field],
'source' => ['pointer' => "/data/attributes/$field"]
];
}, array_keys($errors), $errors);

View File

@@ -0,0 +1,41 @@
<?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\Api\Handler;
use Exception;
use Flarum\Api\Exception\InvalidAccessTokenException;
use Tobscure\JsonApi\Exception\Handler\ExceptionHandlerInterface;
use Tobscure\JsonApi\Exception\Handler\ResponseBag;
class InvalidAccessTokenExceptionHandler implements ExceptionHandlerInterface
{
/**
* {@inheritdoc}
*/
public function manages(Exception $e)
{
return $e instanceof InvalidAccessTokenException;
}
/**
* {@inheritdoc}
*/
public function handle(Exception $e)
{
$status = 401;
$error = [
'status' => (string) $status,
'code' => 'invalid_access_token'
];
return new ResponseBag($status, [$error]);
}
}

View File

@@ -31,7 +31,10 @@ class InvalidConfirmationTokenExceptionHandler implements ExceptionHandlerInterf
public function handle(Exception $e)
{
$status = 403;
$error = ['code' => 'invalid_confirmation_token'];
$error = [
'status' => (string) $status,
'code' => 'invalid_confirmation_token'
];
return new ResponseBag($status, [$error]);
}

View File

@@ -0,0 +1,41 @@
<?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\Api\Handler;
use Exception;
use Flarum\Http\Exception\MethodNotAllowedException;
use Tobscure\JsonApi\Exception\Handler\ExceptionHandlerInterface;
use Tobscure\JsonApi\Exception\Handler\ResponseBag;
class MethodNotAllowedExceptionHandler implements ExceptionHandlerInterface
{
/**
* {@inheritdoc}
*/
public function manages(Exception $e)
{
return $e instanceof MethodNotAllowedException;
}
/**
* {@inheritdoc}
*/
public function handle(Exception $e)
{
$status = 405;
$error = [
'status' => (string) $status,
'code' => 'method_not_allowed'
];
return new ResponseBag($status, [$error]);
}
}

View File

@@ -11,6 +11,7 @@
namespace Flarum\Api\Handler;
use Exception;
use Flarum\Http\Exception\RouteNotFoundException;
use Illuminate\Database\Eloquent\ModelNotFoundException;
use Tobscure\JsonApi\Exception\Handler\ExceptionHandlerInterface;
use Tobscure\JsonApi\Exception\Handler\ResponseBag;
@@ -31,7 +32,10 @@ class ModelNotFoundExceptionHandler implements ExceptionHandlerInterface
public function handle(Exception $e)
{
$status = 404;
$error = [];
$error = [
'status' => '404',
'code' => 'resource_not_found'
];
return new ResponseBag($status, [$error]);
}

View File

@@ -31,7 +31,10 @@ class PermissionDeniedExceptionHandler implements ExceptionHandlerInterface
public function handle(Exception $e)
{
$status = 401;
$error = [];
$error = [
'status' => (string) $status,
'code' => 'permission_denied'
];
return new ResponseBag($status, [$error]);
}

View File

@@ -0,0 +1,41 @@
<?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\Api\Handler;
use Exception;
use Flarum\Http\Exception\RouteNotFoundException;
use Tobscure\JsonApi\Exception\Handler\ExceptionHandlerInterface;
use Tobscure\JsonApi\Exception\Handler\ResponseBag;
class RouteNotFoundExceptionHandler implements ExceptionHandlerInterface
{
/**
* {@inheritdoc}
*/
public function manages(Exception $e)
{
return $e instanceof RouteNotFoundException;
}
/**
* {@inheritdoc}
*/
public function handle(Exception $e)
{
$status = 404;
$error = [
'status' => (string) $status,
'code' => 'route_not_found'
];
return new ResponseBag($status, [$error]);
}
}

View File

@@ -0,0 +1,41 @@
<?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\Api\Handler;
use Exception;
use Flarum\Http\Exception\TokenMismatchException;
use Tobscure\JsonApi\Exception\Handler\ExceptionHandlerInterface;
use Tobscure\JsonApi\Exception\Handler\ResponseBag;
class TokenMismatchExceptionHandler implements ExceptionHandlerInterface
{
/**
* {@inheritdoc}
*/
public function manages(Exception $e)
{
return $e instanceof TokenMismatchException;
}
/**
* {@inheritdoc}
*/
public function handle(Exception $e)
{
$status = 400;
$error = [
'status' => (string) $status,
'code' => 'csrf_token_mismatch'
];
return new ResponseBag($status, [$error]);
}
}

View File

@@ -33,10 +33,13 @@ class ValidationExceptionHandler implements ExceptionHandlerInterface
$status = 422;
$messages = $e->getMessages();
$errors = array_map(function ($path, $detail) {
$source = ['pointer' => '/data/attributes/' . $path];
return compact('source', 'detail');
$errors = array_map(function ($path, $detail) use ($status) {
return [
'status' => (string) $status,
'code' => 'validation_error',
'detail' => $detail,
'source' => ['pointer' => "/data/attributes/$path"]
];
}, array_keys($messages), $messages);
return new ResponseBag($status, $errors);

View File

@@ -1,93 +0,0 @@
<?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\Api\Middleware;
use Flarum\Api\AccessToken;
use Flarum\Api\ApiKey;
use Flarum\Core\Guest;
use Flarum\Core\User;
use Flarum\Locale\LocaleManager;
use Illuminate\Contracts\Container\Container;
use Psr\Http\Message\ResponseInterface as Response;
use Psr\Http\Message\ServerRequestInterface as Request;
use Zend\Stratigility\MiddlewareInterface;
class AuthenticateWithHeader implements MiddlewareInterface
{
/**
* @var string
*/
protected $prefix = 'Token ';
/**
* @var LocaleManager
*/
protected $locales;
/**
* @param LocaleManager $locales
*/
public function __construct(LocaleManager $locales)
{
$this->locales = $locales;
}
/**
* {@inheritdoc}
*/
public function __invoke(Request $request, Response $response, callable $out = null)
{
$request = $this->logIn($request);
return $out ? $out($request, $response) : $response;
}
/**
* @param Request $request
* @return Request
*/
protected function logIn(Request $request)
{
$header = $request->getHeaderLine('authorization');
$parts = explode(';', $header);
$actor = new Guest;
if (isset($parts[0]) && starts_with($parts[0], $this->prefix)) {
$token = substr($parts[0], strlen($this->prefix));
if (($accessToken = AccessToken::find($token)) && $accessToken->isValid()) {
$actor = $accessToken->user;
$actor->updateLastSeen()->save();
} elseif (isset($parts[1]) && ($apiKey = ApiKey::valid($token))) {
$userParts = explode('=', trim($parts[1]));
if (isset($userParts[0]) && $userParts[0] === 'userId') {
$actor = User::find($userParts[1]);
}
}
}
if ($actor->exists) {
$locale = $actor->getPreference('locale');
} else {
$locale = array_get($request->getCookieParams(), 'locale');
}
if ($locale && $this->locales->hasLocale($locale)) {
$this->locales->setLocale($locale);
}
return $request->withAttribute('actor', $actor ?: new Guest);
}
}

View File

@@ -28,10 +28,12 @@ class Server extends AbstractServer
$apiPath = parse_url($app->url('api'), PHP_URL_PATH);
if ($app->isInstalled() && $app->isUpToDate()) {
$pipe->pipe($apiPath, $app->make('Flarum\Http\Middleware\AuthenticateWithCookie'));
$pipe->pipe($apiPath, $app->make('Flarum\Api\Middleware\AuthenticateWithHeader'));
$pipe->pipe($apiPath, $app->make('Flarum\Http\Middleware\ParseJsonBody'));
$pipe->pipe($apiPath, $app->make('Flarum\Api\Middleware\FakeHttpMethods'));
$pipe->pipe($apiPath, $app->make('Flarum\Http\Middleware\AuthorizeWithCookie'));
$pipe->pipe($apiPath, $app->make('Flarum\Http\Middleware\AuthorizeWithHeader'));
$pipe->pipe($apiPath, $app->make('Flarum\Http\Middleware\StartSession'));
$pipe->pipe($apiPath, $app->make('Flarum\Http\Middleware\SetLocale'));
$pipe->pipe($apiPath, $app->make('Flarum\Http\Middleware\DispatchRoute', ['routes' => $app->make('flarum.api.routes')]));
$pipe->pipe($apiPath, $app->make('Flarum\Api\Middleware\HandleErrors'));
} else {

View File

@@ -10,8 +10,10 @@
namespace Flarum\Core\Access;
use Flarum\Api\Exception\InvalidAccessTokenException;
use Flarum\Core\Exception\PermissionDeniedException;
use Flarum\Core\User;
use Psr\Http\Message\ServerRequestInterface;
trait AssertPermissionTrait
{
@@ -61,6 +63,30 @@ trait AssertPermissionTrait
*/
protected function assertAdmin(User $actor)
{
$this->assertPermission($actor->isAdmin());
$this->assertCan($actor, 'administrate');
}
/**
* @param ServerRequestInterface $request
* @throws InvalidAccessTokenException
*/
protected function assertSudo(ServerRequestInterface $request)
{
$session = $request->getAttribute('session');
if (! $session || ! $session->isSudo()) {
throw new InvalidAccessTokenException;
}
}
/**
* @param ServerRequestInterface $request
* @throws PermissionDeniedException
*/
protected function assertAdminAndSudo(ServerRequestInterface $request)
{
$this->assertAdmin($request->getAttribute('actor'));
$this->assertSudo($request);
}
}

View File

@@ -135,7 +135,7 @@ class User extends AbstractModel
$user->read()->detach();
$user->groups()->detach();
$user->accessTokens()->delete();
$user->sessions()->delete();
$user->notifications()->delete();
});
@@ -654,13 +654,13 @@ class User extends AbstractModel
}
/**
* Define the relationship with the user's access tokens.
* Define the relationship with the user's sessions.
*
* @return \Illuminate\Database\Eloquent\Relations\HasMany
*/
public function accessTokens()
public function sessions()
{
return $this->hasMany('Flarum\Api\AccessToken');
return $this->hasMany('Flarum\Http\Session');
}
/**

View File

@@ -11,16 +11,17 @@
namespace Flarum\Event;
use Flarum\Core\User;
use Flarum\Http\Session;
class UserLoggedIn
{
public $user;
public $token;
public $session;
public function __construct(User $user, $token)
public function __construct(User $user, Session $session)
{
$this->user = $user;
$this->token = $token;
$this->session = $session;
}
}

View File

@@ -12,14 +12,11 @@ namespace Flarum\Forum\Controller;
use Flarum\Core\User;
use Zend\Diactoros\Response\HtmlResponse;
use Flarum\Api\Command\GenerateAccessToken;
use Flarum\Core\AuthToken;
use DateTime;
use Psr\Http\Message\ServerRequestInterface as Request;
trait AuthenticateUserTrait
{
use WriteRememberCookieTrait;
/**
* @var \Illuminate\Contracts\Bus\Dispatcher
*/
@@ -45,7 +42,7 @@ trait AuthenticateUserTrait
* @param array $suggestions
* @return HtmlResponse
*/
protected function authenticate(array $identification, array $suggestions = [])
protected function authenticate(Request $request, array $identification, array $suggestions = [])
{
$user = User::where($identification)->first();
@@ -70,13 +67,8 @@ trait AuthenticateUserTrait
$response = new HtmlResponse($content);
if ($user) {
// Extend the token's expiry to 2 weeks so that we can set a
// remember cookie
$accessToken = $this->bus->dispatch(new GenerateAccessToken($user->id));
$accessToken::unguard();
$accessToken->update(['expires_at' => new DateTime('+2 weeks')]);
$response = $this->withRememberCookie($response, $accessToken->id);
$session = $request->getAttribute('session');
$session->assign($user)->regenerateId()->renew()->setDuration(60 * 24 * 14)->save();
}
return $response;

View File

@@ -11,7 +11,6 @@
namespace Flarum\Forum\Controller;
use Flarum\Core\Command\ConfirmEmail;
use Flarum\Api\Command\GenerateAccessToken;
use Flarum\Core\Exception\InvalidConfirmationTokenException;
use Flarum\Foundation\Application;
use Flarum\Http\Controller\ControllerInterface;
@@ -22,8 +21,6 @@ use Zend\Diactoros\Response\RedirectResponse;
class ConfirmEmailController implements ControllerInterface
{
use WriteRememberCookieTrait;
/**
* @var Dispatcher
*/
@@ -60,13 +57,9 @@ class ConfirmEmailController implements ControllerInterface
return new HtmlResponse('Invalid confirmation token');
}
$token = $this->bus->dispatch(
new GenerateAccessToken($user->id)
);
$session = $request->getAttribute('session');
$session->assign($user)->regenerateId()->renew()->setDuration(60 * 24 * 14)->save();
return $this->withRememberCookie(
new RedirectResponse($this->app->url()),
$token->id
);
return new RedirectResponse($this->app->url());
}
}

View File

@@ -11,19 +11,16 @@
namespace Flarum\Forum\Controller;
use Flarum\Api\Client;
use Flarum\Api\AccessToken;
use Flarum\Http\Session;
use Flarum\Event\UserLoggedIn;
use Flarum\Core\Repository\UserRepository;
use Flarum\Http\Controller\ControllerInterface;
use Psr\Http\Message\ServerRequestInterface as Request;
use Zend\Diactoros\Response\EmptyResponse;
use Zend\Diactoros\Response\JsonResponse;
use DateTime;
class LoginController implements ControllerInterface
class LogInController implements ControllerInterface
{
use WriteRememberCookieTrait;
/**
* @var \Flarum\Core\Repository\UserRepository
*/
@@ -52,26 +49,20 @@ class LoginController implements ControllerInterface
public function handle(Request $request, array $routeParams = [])
{
$controller = 'Flarum\Api\Controller\TokenController';
$actor = $request->getAttribute('actor');
$session = $request->getAttribute('session');
$params = array_only($request->getParsedBody(), ['identification', 'password']);
$response = $this->apiClient->send($controller, $actor, [], $params);
$response = $this->apiClient->send($controller, $session, [], $params);
if ($response->getStatusCode() === 200) {
$data = json_decode($response->getBody());
// Extend the token's expiry to 2 weeks so that we can set a
// remember cookie
AccessToken::where('id', $data->token)->update(['expires_at' => new DateTime('+2 weeks')]);
$session = Session::find($data->token);
$session->setDuration(60 * 24 * 14)->save();
event(new UserLoggedIn($this->users->findOrFail($data->userId), $data->token));
return $this->withRememberCookie(
$response,
$data->token
);
} else {
return $response;
event(new UserLoggedIn($this->users->findOrFail($data->userId), $session));
}
return $response;
}
}

View File

@@ -10,18 +10,16 @@
namespace Flarum\Forum\Controller;
use Flarum\Api\AccessToken;
use Flarum\Event\UserLoggedOut;
use Flarum\Foundation\Application;
use Flarum\Http\Controller\ControllerInterface;
use Flarum\Http\Exception\TokenMismatchException;
use Illuminate\Contracts\Events\Dispatcher;
use Psr\Http\Message\ServerRequestInterface as Request;
use Zend\Diactoros\Response\RedirectResponse;
class LogoutController implements ControllerInterface
class LogOutController implements ControllerInterface
{
use WriteRememberCookieTrait;
/**
* @var Application
*/
@@ -46,21 +44,24 @@ class LogoutController implements ControllerInterface
* @param Request $request
* @param array $routeParams
* @return \Psr\Http\Message\ResponseInterface
* @throws TokenMismatchException
*/
public function handle(Request $request, array $routeParams = [])
{
$user = $request->getAttribute('actor');
$session = $request->getAttribute('session');
if ($user->exists) {
$token = array_get($request->getQueryParams(), 'token');
if ($user = $session->user) {
if (array_get($request->getQueryParams(), 'token') !== $session->csrf_token) {
throw new TokenMismatchException;
}
AccessToken::where('user_id', $user->id)->findOrFail($token);
$session->exists = false;
$user->accessTokens()->delete();
$user->sessions()->delete();
$this->events->fire(new UserLoggedOut($user));
}
return $this->withForgetCookie(new RedirectResponse($this->app->url()));
return new RedirectResponse($this->app->url());
}
}

View File

@@ -11,19 +11,15 @@
namespace Flarum\Forum\Controller;
use Flarum\Api\Client;
use Flarum\Api\AccessToken;
use Flarum\Core\User;
use Flarum\Http\Controller\ControllerInterface;
use Flarum\Api\Command\GenerateAccessToken;
use Psr\Http\Message\ServerRequestInterface as Request;
use Zend\Diactoros\Response\EmptyResponse;
use Zend\Diactoros\Response\JsonResponse;
use Illuminate\Contracts\Bus\Dispatcher;
use DateTime;
class RegisterController implements ControllerInterface
{
use WriteRememberCookieTrait;
/**
* @var Dispatcher
*/
@@ -61,21 +57,13 @@ class RegisterController implements ControllerInterface
$body = json_decode($response->getBody());
$statusCode = $response->getStatusCode();
$response = new JsonResponse($body, $statusCode);
if (isset($body->data)) {
$user = User::find($body->data->id);
if (! empty($body->data->attributes->isActivated)) {
$token = $this->bus->dispatch(new GenerateAccessToken($body->data->id));
// Extend the token's expiry to 2 weeks so that we can set a
// remember cookie
AccessToken::where('id', $token->id)->update(['expires_at' => new DateTime('+2 weeks')]);
return $this->withRememberCookie(
$response,
$token->id
);
$session = $request->getAttribute('session');
$session->assign($user)->regenerateId()->renew()->setDuration(60 * 24 * 14)->save();
}
return $response;
return new JsonResponse($body, $statusCode);
}
}

View File

@@ -1,42 +0,0 @@
<?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\Forum\Controller;
use Dflydev\FigCookies\FigResponseCookies;
use Dflydev\FigCookies\SetCookie;
use Psr\Http\Message\ResponseInterface;
trait WriteRememberCookieTrait
{
protected function withRememberCookie(ResponseInterface $response, $token)
{
// Set a long-living cookie (two weeks) with the remember token
return FigResponseCookies::set(
$response,
SetCookie::create('flarum_remember', $token)
->withMaxAge(14 * 24 * 60 * 60)
->withPath('/')
->withHttpOnly(true)
);
}
protected function withForgetCookie(ResponseInterface $response)
{
// Delete the cookie by setting it to an expiration date in the past
return FigResponseCookies::set(
$response,
SetCookie::create('flarum_remember')
->withMaxAge(-2628000)
->withPath('/')
->withHttpOnly(true)
);
}
}

View File

@@ -35,8 +35,10 @@ class Server extends AbstractServer
$pipe->pipe($basePath, $app->make('Flarum\Http\Middleware\DispatchRoute', ['routes' => $app->make('flarum.install.routes')]));
$pipe->pipe($basePath, new HandleErrors($errorDir, true));
} elseif ($app->isUpToDate()) {
$pipe->pipe($basePath, $app->make('Flarum\Http\Middleware\AuthenticateWithCookie'));
$pipe->pipe($basePath, $app->make('Flarum\Http\Middleware\ParseJsonBody'));
$pipe->pipe($basePath, $app->make('Flarum\Http\Middleware\AuthorizeWithCookie'));
$pipe->pipe($basePath, $app->make('Flarum\Http\Middleware\StartSession'));
$pipe->pipe($basePath, $app->make('Flarum\Http\Middleware\SetLocale'));
$pipe->pipe($basePath, $app->make('Flarum\Http\Middleware\DispatchRoute', ['routes' => $app->make('flarum.forum.routes')]));
$pipe->pipe($basePath, new HandleErrors($errorDir, $app->inDebugMode()));
} else {

View File

@@ -339,9 +339,11 @@ class ClientView implements Renderable
*/
protected function getSession()
{
$session = $this->request->getAttribute('session');
return [
'userId' => $this->actor->id,
'token' => array_get($this->request->getCookieParams(), 'flarum_remember'),
'csrfToken' => $session->csrf_token
];
}
}

View File

@@ -0,0 +1,22 @@
<?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\Exception;
use Exception;
class MethodNotAllowedException extends Exception
{
public function __construct($message = null, $code = 405, Exception $previous = null)
{
parent::__construct($message, $code, $previous);
}
}

View File

@@ -0,0 +1,18 @@
<?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\Exception;
use Exception;
class TokenMismatchException extends Exception
{
}

View File

@@ -10,82 +10,43 @@
namespace Flarum\Http\Middleware;
use Flarum\Api\AccessToken;
use Flarum\Core\Guest;
use Flarum\Locale\LocaleManager;
use Flarum\Http\Exception\TokenMismatchException;
use Flarum\Http\Session;
use Psr\Http\Message\ResponseInterface as Response;
use Psr\Http\Message\ServerRequestInterface as Request;
use Zend\Stratigility\MiddlewareInterface;
class AuthenticateWithCookie implements MiddlewareInterface
{
/**
* @var LocaleManager
*/
protected $locales;
/**
* @param LocaleManager $locales
*/
public function __construct(LocaleManager $locales)
{
$this->locales = $locales;
}
/**
* {@inheritdoc}
*/
public function __invoke(Request $request, Response $response, callable $out = null)
{
$request = $this->logIn($request);
$id = array_get($request->getCookieParams(), 'flarum_session');
if ($id) {
$session = Session::find($id);
$request = $request->withAttribute('session', $session);
if (! $this->isReading($request) && ! $this->tokensMatch($request)) {
throw new TokenMismatchException;
}
}
return $out ? $out($request, $response) : $response;
}
/**
* Set the application's actor instance according to the request token.
*
* @param Request $request
* @return Request
*/
protected function logIn(Request $request)
private function isReading(Request $request)
{
$actor = new Guest;
if ($token = $this->getToken($request)) {
if (! $token->isValid()) {
// TODO: https://github.com/flarum/core/issues/253
} elseif ($token->user) {
$actor = $token->user;
$actor->updateLastSeen()->save();
}
}
if ($actor->exists) {
$locale = $actor->getPreference('locale');
} else {
$locale = array_get($request->getCookieParams(), 'locale');
}
if ($locale && $this->locales->hasLocale($locale)) {
$this->locales->setLocale($locale);
}
return $request->withAttribute('actor', $actor);
return in_array($request->getMethod(), ['HEAD', 'GET', 'OPTIONS']);
}
/**
* Get the access token referred to by the request cookie.
*
* @param Request $request
* @return AccessToken|null
*/
protected function getToken(Request $request)
private function tokensMatch(Request $request)
{
$token = array_get($request->getCookieParams(), 'flarum_remember');
$input = $request->getHeaderLine('X-CSRF-Token') ?: array_get($request->getParsedBody(), 'token');
if ($token) {
return AccessToken::find($token);
}
return $request->getAttribute('session')->csrf_token === $input;
}
}

View File

@@ -0,0 +1,61 @@
<?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 Flarum\Api\ApiKey;
use Flarum\Core\User;
use Flarum\Http\Session;
use Psr\Http\Message\ResponseInterface as Response;
use Psr\Http\Message\ServerRequestInterface as Request;
use Zend\Stratigility\MiddlewareInterface;
class AuthenticateWithHeader implements MiddlewareInterface
{
/**
* @var string
*/
protected $prefix = 'Token ';
/**
* {@inheritdoc}
*/
public function __invoke(Request $request, Response $response, callable $out = null)
{
$headerLine = $request->getHeaderLine('authorization');
$parts = explode(';', $headerLine);
if (isset($parts[0]) && starts_with($parts[0], $this->prefix)) {
$id = substr($parts[0], strlen($this->prefix));
if (isset($parts[1]) && ApiKey::valid($id)) {
if ($actor = $this->getUser($parts[1])) {
$request = $request->withAttribute('actor', $actor);
}
} else {
$session = Session::find($id);
$request = $request->withAttribute('session', $session);
}
}
return $out ? $out($request, $response) : $response;
}
private function getUser($string)
{
$parts = explode('=', trim($string));
if (isset($parts[0]) && $parts[0] === 'userId') {
return User::find($parts[1]);
}
}
}

View File

@@ -13,8 +13,9 @@ namespace Flarum\Http\Middleware;
use FastRoute\Dispatcher;
use FastRoute\RouteParser;
use Flarum\Http\RouteCollection;
use Flarum\Http\Exception\MethodNotAllowedException;
use Flarum\Http\Exception\RouteNotFoundException;
use Flarum\Http\RouteCollection;
use Psr\Http\Message\ResponseInterface as Response;
use Psr\Http\Message\ServerRequestInterface as Request;
@@ -47,6 +48,7 @@ class DispatchRoute
* @param Response $response
* @param callable $out
* @return Response
* @throws MethodNotAllowedException
* @throws RouteNotFoundException
*/
public function __invoke(Request $request, Response $response, callable $out = null)
@@ -58,8 +60,11 @@ class DispatchRoute
switch ($routeInfo[0]) {
case Dispatcher::NOT_FOUND:
case Dispatcher::METHOD_NOT_ALLOWED:
throw new RouteNotFoundException;
case Dispatcher::METHOD_NOT_ALLOWED:
throw new MethodNotAllowedException;
case Dispatcher::FOUND:
$handler = $routeInfo[1];
$parameters = $routeInfo[2];

View File

@@ -0,0 +1,52 @@
<?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 Flarum\Locale\LocaleManager;
use Psr\Http\Message\ResponseInterface as Response;
use Psr\Http\Message\ServerRequestInterface as Request;
use Zend\Stratigility\MiddlewareInterface;
class SetLocale implements MiddlewareInterface
{
/**
* @var LocaleManager
*/
protected $locales;
/**
* @param LocaleManager $locales
*/
public function __construct(LocaleManager $locales)
{
$this->locales = $locales;
}
/**
* {@inheritdoc}
*/
public function __invoke(Request $request, Response $response, callable $out = null)
{
$actor = $request->getAttribute('actor');
if ($actor->exists) {
$locale = $actor->getPreference('locale');
} else {
$locale = array_get($request->getCookieParams(), 'locale');
}
if ($locale && $this->locales->hasLocale($locale)) {
$this->locales->setLocale($locale);
}
return $out ? $out($request, $response) : $response;
}
}

View File

@@ -0,0 +1,81 @@
<?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 Dflydev\FigCookies\FigResponseCookies;
use Dflydev\FigCookies\SetCookie;
use Dflydev\FigCookies\SetCookies;
use Flarum\Http\Session;
use Flarum\Core\Guest;
use Flarum\Http\WriteSessionCookieTrait;
use Psr\Http\Message\ResponseInterface as Response;
use Psr\Http\Message\ServerRequestInterface as Request;
use Zend\Stratigility\MiddlewareInterface;
class StartSession implements MiddlewareInterface
{
use WriteSessionCookieTrait;
/**
* {@inheritdoc}
*/
public function __invoke(Request $request, Response $response, callable $out = null)
{
$this->collectGarbage();
$session = $this->getSession($request);
$actor = $this->getActor($session);
$request = $request
->withAttribute('session', $session)
->withAttribute('actor', $actor);
$response = $out ? $out($request, $response) : $response;
return $this->addSessionCookieToResponse($response, $session, 'flarum_session');
}
private function getSession(Request $request)
{
$session = $request->getAttribute('session');
if (! $session) {
$session = Session::generate();
}
$session->extend()->save();
return $session;
}
private function getActor(Session $session)
{
$actor = $session->user ?: new Guest;
if ($actor->exists) {
$actor->updateLastSeen()->save();
}
return $actor;
}
private function collectGarbage()
{
if ($this->hitsLottery()) {
Session::whereRaw('last_activity <= ? - duration * 60', [time()])->delete();
}
}
private function hitsLottery()
{
return mt_rand(1, 100) <= 1;
}
}

140
src/Http/Session.php Normal file
View File

@@ -0,0 +1,140 @@
<?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;
use DateTime;
use Flarum\Core\User;
use Flarum\Database\AbstractModel;
use Illuminate\Support\Str;
/**
* @property string $id
* @property int $user_id
* @property int $last_activity
* @property int $duration
* @property \Carbon\Carbon $sudo_expiry_time
* @property string $csrf_token
* @property \Flarum\Core\User|null $user
*/
class Session extends AbstractModel
{
/**
* {@inheritdoc}
*/
protected $table = 'sessions';
/**
* Use a custom primary key for this model.
*
* @var bool
*/
public $incrementing = false;
/**
* {@inheritdoc}
*/
protected $dates = ['sudo_expiry_time'];
/**
* Generate a session.
*
* @param User|null $user
* @param int $duration How long before the session will expire, in minutes.
* @return static
*/
public static function generate(User $user = null, $duration = 60)
{
$session = new static;
$session->assign($user)
->regenerateId()
->renew()
->setDuration($duration);
return $session->extend();
}
/**
* Assign the session to a user.
*
* @param User|null $user
* @return $this
*/
public function assign(User $user = null)
{
$this->user_id = $user ? $user->id : null;
return $this;
}
/**
* Regenerate the session ID.
*
* @return $this
*/
public function regenerateId()
{
$this->id = sha1(uniqid('', true).Str::random(25).microtime(true));
$this->csrf_token = Str::random(40);
return $this;
}
/**
* @return $this
*/
public function extend()
{
$this->last_activity = time();
return $this;
}
/**
* @return $this
*/
public function renew()
{
$this->extend();
$this->sudo_expiry_time = time() + 30 * 60;
return $this;
}
/**
* @param int $duration How long before the session will expire, in minutes.
* @return $this
*/
public function setDuration($duration)
{
$this->duration = $duration;
return $this;
}
/**
* @return bool
*/
public function isSudo()
{
return $this->sudo_expiry_time > new DateTime;
}
/**
* Define the relationship with the owner of this access token.
*
* @return \Illuminate\Database\Eloquent\Relations\BelongsTo
*/
public function user()
{
return $this->belongsTo(User::class);
}
}

View File

@@ -0,0 +1,29 @@
<?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;
use Dflydev\FigCookies\FigResponseCookies;
use Dflydev\FigCookies\SetCookie;
use Psr\Http\Message\ResponseInterface as Response;
trait WriteSessionCookieTrait
{
protected function addSessionCookieToResponse(Response $response, Session $session, $cookieName)
{
return FigResponseCookies::set(
$response,
SetCookie::create($cookieName, $session->exists ? $session->id : null)
->withMaxAge($session->exists ? $session->duration * 60 : -2628000)
->withPath('/')
->withHttpOnly(true)
);
}
}

View File

@@ -10,14 +10,15 @@
namespace Flarum\Install\Controller;
use Flarum\Core\User;
use Flarum\Http\Controller\ControllerInterface;
use Flarum\Http\Session;
use Flarum\Http\WriteSessionCookieTrait;
use Psr\Http\Message\ServerRequestInterface as Request;
use Zend\Diactoros\Response\HtmlResponse;
use Zend\Diactoros\Response;
use Flarum\Install\Console\InstallCommand;
use Flarum\Install\Console\DefaultsDataProvider;
use Flarum\Api\Command\GenerateAccessToken;
use Flarum\Forum\Controller\WriteRememberCookieTrait;
use Symfony\Component\Console\Output\StreamOutput;
use Symfony\Component\Console\Input\StringInput;
use Illuminate\Contracts\Bus\Dispatcher;
@@ -26,7 +27,7 @@ use DateTime;
class InstallController implements ControllerInterface
{
use WriteRememberCookieTrait;
use WriteSessionCookieTrait;
protected $command;
@@ -87,14 +88,9 @@ class InstallController implements ControllerInterface
return new HtmlResponse($e->getMessage(), 500);
}
$token = $this->bus->dispatch(
new GenerateAccessToken(1)
);
$token->update(['expires_at' => new DateTime('+2 weeks')]);
$session = Session::generate(User::find(1), 60 * 24 * 14);
$session->save();
return $this->withRememberCookie(
new Response($body, 200),
$token->id
);
return $this->addSessionCookieToResponse(new Response($body, 200), $session, 'flarum_session');
}
}