diff --git a/app.php b/app.php index 24d297cd..d2310bd0 100644 --- a/app.php +++ b/app.php @@ -3,46 +3,38 @@ use \Psr\Http\Message\ServerRequestInterface as Request; use \Psr\Http\Message\ResponseInterface as Response; -use \Grocy\Middleware\SessionAuthMiddleware; use \Grocy\Helpers\UrlManager; -use \Grocy\Services\ApplicationService; +use \Grocy\Controllers\LoginController; require_once __DIR__ . '/vendor/autoload.php'; require_once __DIR__ . '/data/config.php'; // Setup base application -if (PHP_SAPI !== 'cli') -{ - $appContainer = new \Slim\Container([ - 'settings' => [ - 'displayErrorDetails' => true, - 'determineRouteBeforeAppMiddleware' => true - ], - 'view' => function($container) - { - return new \Slim\Views\Blade(__DIR__ . '/views', __DIR__ . '/data/viewcache'); - }, - 'UrlManager' => function($container) - { - return new UrlManager(BASE_URL); - } - ]); +$appContainer = new \Slim\Container([ + 'settings' => [ + 'displayErrorDetails' => true, + 'determineRouteBeforeAppMiddleware' => true + ], + 'view' => function($container) + { + return new \Slim\Views\Blade(__DIR__ . '/views', __DIR__ . '/data/viewcache'); + }, + 'LoginControllerInstance' => function($container) + { + return new LoginController($container, 'grocy_session'); + }, + 'UrlManager' => function($container) + { + return new UrlManager(BASE_URL); + } +]); +$app = new \Slim\App($appContainer); - $app = new \Slim\App($appContainer); -} -else +if (PHP_SAPI === 'cli') { - $app = new \Slim\App(); $app->add(\pavlakis\cli\CliRequest::class); } -// Add session handling if this is not a demo installation -$applicationService = new ApplicationService(); -if (!$applicationService->IsDemoInstallation()) -{ - $app->add(SessionAuthMiddleware::class); -} - require_once __DIR__ . '/routes.php'; $app->run(); diff --git a/controllers/LoginController.php b/controllers/LoginController.php index 0923feed..5fe24359 100644 --- a/controllers/LoginController.php +++ b/controllers/LoginController.php @@ -9,13 +9,15 @@ use \Grocy\Services\DemoDataGeneratorService; class LoginController extends BaseController { - public function __construct(\Slim\Container $container) + public function __construct(\Slim\Container $container, string $sessionCookieName) { parent::__construct($container); $this->SessionService = new SessionService(); + $this->SessionCookieName = $sessionCookieName; } protected $SessionService; + protected $SessionCookieName; public function ProcessLogin(\Slim\Http\Request $request, \Slim\Http\Response $response, array $args) { @@ -25,7 +27,7 @@ class LoginController extends BaseController if ($postParams['username'] === HTTP_USER && $postParams['password'] === HTTP_PASSWORD) { $sessionKey = $this->SessionService->CreateSession(); - setcookie('grocy_session', $sessionKey, time() + 31536000); // Cookie expires in 1 year, but session validity is up to SessionService + setcookie($this->SessionCookieName, $sessionKey, time() + 31536000); // Cookie expires in 1 year, but session validity is up to SessionService return $response->withRedirect($this->AppContainer->UrlManager->ConstructUrl('/')); } @@ -47,7 +49,7 @@ class LoginController extends BaseController public function Logout(\Slim\Http\Request $request, \Slim\Http\Response $response, array $args) { - $this->SessionService->RemoveSession($_COOKIE['grocy_session']); + $this->SessionService->RemoveSession($_COOKIE[$this->SessionCookieName]); return $response->withRedirect($this->AppContainer->UrlManager->ConstructUrl('/')); } @@ -66,4 +68,9 @@ class LoginController extends BaseController return $response->withRedirect($this->AppContainer->UrlManager->ConstructUrl('/stockoverview')); } + + public function GetSessionCookieName() + { + return $this->SessionCookieName; + } } diff --git a/helpers/extensions.php b/helpers/extensions.php index 8046b772..411d8079 100644 --- a/helpers/extensions.php +++ b/helpers/extensions.php @@ -61,3 +61,14 @@ function GetClassConstants($className) $r = new ReflectionClass($className); return $r->getConstants(); } + +function RandomString($length, $allowedChars = '0123456789abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ') +{ + $randomString = ''; + for ($i = 0; $i < $length; $i++) + { + $randomString .= $allowedChars[rand(0, strlen($allowedChars) - 1)]; + } + + return $randomString; +} diff --git a/middleware/BaseMiddleware.php b/middleware/BaseMiddleware.php index 7be05354..1ba4fd9c 100644 --- a/middleware/BaseMiddleware.php +++ b/middleware/BaseMiddleware.php @@ -2,11 +2,16 @@ namespace Grocy\Middleware; +use \Grocy\Services\ApplicationService; + class BaseMiddleware { - public function __construct(\Slim\Container $container) { + public function __construct(\Slim\Container $container) + { $this->AppContainer = $container; + $this->ApplicationService = new ApplicationService(); } protected $AppContainer; + protected $ApplicationService; } diff --git a/middleware/CliMiddleware.php b/middleware/CliMiddleware.php index 0cf10166..cc08e0f0 100644 --- a/middleware/CliMiddleware.php +++ b/middleware/CliMiddleware.php @@ -13,7 +13,7 @@ class CliMiddleware extends BaseMiddleware } else { - $response = $next($request, $response, $next); + $response = $next($request, $response); return $response->withHeader('Content-Type', 'text/plain'); } } diff --git a/middleware/JsonMiddleware.php b/middleware/JsonMiddleware.php index b970ad69..a20f0ed9 100644 --- a/middleware/JsonMiddleware.php +++ b/middleware/JsonMiddleware.php @@ -6,7 +6,7 @@ class JsonMiddleware extends BaseMiddleware { public function __invoke(\Slim\Http\Request $request, \Slim\Http\Response $response, callable $next) { - $response = $next($request, $response, $next); + $response = $next($request, $response); return $response->withHeader('Content-Type', 'application/json'); } } diff --git a/middleware/SessionAuthMiddleware.php b/middleware/SessionAuthMiddleware.php index baf9c73d..4fbde7ef 100644 --- a/middleware/SessionAuthMiddleware.php +++ b/middleware/SessionAuthMiddleware.php @@ -6,19 +6,27 @@ use \Grocy\Services\SessionService; class SessionAuthMiddleware extends BaseMiddleware { + public function __construct(\Slim\Container $container, string $sessionCookieName) + { + parent::__construct($container); + $this->SessionCookieName = $sessionCookieName; + } + + protected $SessionCookieName; + public function __invoke(\Slim\Http\Request $request, \Slim\Http\Response $response, callable $next) { $route = $request->getAttribute('route'); $routeName = $route->getName(); - if ($routeName === 'root') + if ($routeName === 'root' || $this->ApplicationService->IsDemoInstallation()) { $response = $next($request, $response); } else { $sessionService = new SessionService(); - if ((!isset($_COOKIE['grocy_session']) || !$sessionService->IsValidSession($_COOKIE['grocy_session'])) && $routeName !== 'login') + if ((!isset($_COOKIE[$this->SessionCookieName]) || !$sessionService->IsValidSession($_COOKIE[$this->SessionCookieName])) && $routeName !== 'login') { $response = $response->withRedirect($this->AppContainer->UrlManager->ConstructUrl('/login')); } diff --git a/routes.php b/routes.php index a9599dec..ba8e7354 100644 --- a/routes.php +++ b/routes.php @@ -2,48 +2,51 @@ use \Grocy\Middleware\JsonMiddleware; use \Grocy\Middleware\CliMiddleware; +use \Grocy\Middleware\SessionAuthMiddleware; -// Base route -$app->get('/', 'Grocy\Controllers\LoginController:Root')->setName('root'); +$app->group('', function() +{ + // Base route + $this->get('/', 'LoginControllerInstance:Root')->setName('root'); -// Login routes -$app->get('/login', 'Grocy\Controllers\LoginController:LoginPage')->setName('login'); -$app->post('/login', 'Grocy\Controllers\LoginController:ProcessLogin')->setName('login'); -$app->get('/logout', 'Grocy\Controllers\LoginController:Logout'); + // Login routes + $this->get('/login', 'LoginControllerInstance:LoginPage')->setName('login'); + $this->post('/login', 'LoginControllerInstance:ProcessLogin')->setName('login'); + $this->get('/logout', 'LoginControllerInstance:Logout'); -// Stock routes -$app->get('/stockoverview', 'Grocy\Controllers\StockController:Overview'); -$app->get('/purchase', 'Grocy\Controllers\StockController:Purchase'); -$app->get('/consume', 'Grocy\Controllers\StockController:Consume'); -$app->get('/inventory', 'Grocy\Controllers\StockController:Inventory'); + // Stock routes + $this->get('/stockoverview', 'Grocy\Controllers\StockController:Overview'); + $this->get('/purchase', 'Grocy\Controllers\StockController:Purchase'); + $this->get('/consume', 'Grocy\Controllers\StockController:Consume'); + $this->get('/inventory', 'Grocy\Controllers\StockController:Inventory'); -$app->get('/products', 'Grocy\Controllers\StockController:ProductsList'); -$app->get('/product/{productId}', 'Grocy\Controllers\StockController:ProductEditForm'); + $this->get('/products', 'Grocy\Controllers\StockController:ProductsList'); + $this->get('/product/{productId}', 'Grocy\Controllers\StockController:ProductEditForm'); -$app->get('/locations', 'Grocy\Controllers\StockController:LocationsList'); -$app->get('/location/{locationId}', 'Grocy\Controllers\StockController:LocationEditForm'); + $this->get('/locations', 'Grocy\Controllers\StockController:LocationsList'); + $this->get('/location/{locationId}', 'Grocy\Controllers\StockController:LocationEditForm'); -$app->get('/quantityunits', 'Grocy\Controllers\StockController:QuantityUnitsList'); -$app->get('/quantityunit/{quantityunitId}', 'Grocy\Controllers\StockController:QuantityUnitEditForm'); + $this->get('/quantityunits', 'Grocy\Controllers\StockController:QuantityUnitsList'); + $this->get('/quantityunit/{quantityunitId}', 'Grocy\Controllers\StockController:QuantityUnitEditForm'); -$app->get('/shoppinglist', 'Grocy\Controllers\StockController:ShoppingList'); -$app->get('/shoppinglistitem/{itemId}', 'Grocy\Controllers\StockController:ShoppingListItemEditForm'); + $this->get('/shoppinglist', 'Grocy\Controllers\StockController:ShoppingList'); + $this->get('/shoppinglistitem/{itemId}', 'Grocy\Controllers\StockController:ShoppingListItemEditForm'); -// Habit routes -$app->get('/habitsoverview', 'Grocy\Controllers\HabitsController:Overview'); -$app->get('/habittracking', 'Grocy\Controllers\HabitsController:TrackHabitExecution'); + // Habit routes + $this->get('/habitsoverview', 'Grocy\Controllers\HabitsController:Overview'); + $this->get('/habittracking', 'Grocy\Controllers\HabitsController:TrackHabitExecution'); -$app->get('/habits', 'Grocy\Controllers\HabitsController:HabitsList'); -$app->get('/habit/{habitId}', 'Grocy\Controllers\HabitsController:HabitEditForm'); + $this->get('/habits', 'Grocy\Controllers\HabitsController:HabitsList'); + $this->get('/habit/{habitId}', 'Grocy\Controllers\HabitsController:HabitEditForm'); -// Batterry routes -$app->get('/batteriesoverview', 'Grocy\Controllers\BatteriesController:Overview'); -$app->get('/batterytracking', 'Grocy\Controllers\BatteriesController:TrackChargeCycle'); - -$app->get('/batteries', 'Grocy\Controllers\BatteriesController:BatteriesList'); -$app->get('/battery/{batteryId}', 'Grocy\Controllers\BatteriesController:BatteryEditForm'); + // Batterry routes + $this->get('/batteriesoverview', 'Grocy\Controllers\BatteriesController:Overview'); + $this->get('/batterytracking', 'Grocy\Controllers\BatteriesController:TrackChargeCycle'); + $this->get('/batteries', 'Grocy\Controllers\BatteriesController:BatteriesList'); + $this->get('/battery/{batteryId}', 'Grocy\Controllers\BatteriesController:BatteryEditForm'); +})->add(new SessionAuthMiddleware($appContainer, $appContainer->LoginControllerInstance->GetSessionCookieName())); $app->group('/api', function() { @@ -65,7 +68,7 @@ $app->group('/api', function() $this->get('/batteries/track-charge-cycle/{batteryId}', 'Grocy\Controllers\BatteriesApiController:TrackChargeCycle'); $this->get('/batteries/get-battery-details/{batteryId}', 'Grocy\Controllers\BatteriesApiController:BatteryDetails'); -})->add(JsonMiddleware::class); +})->add(new SessionAuthMiddleware($appContainer, $appContainer->LoginControllerInstance->GetSessionCookieName()))->add(JsonMiddleware::class); $app->group('/cli', function() { diff --git a/services/SessionService.php b/services/SessionService.php index 95bef42d..780e10bc 100644 --- a/services/SessionService.php +++ b/services/SessionService.php @@ -24,11 +24,11 @@ class SessionService extends BaseService */ public function CreateSession() { - $newSessionKey = uniqid() . uniqid() . uniqid(); + $newSessionKey = $this->GenerateSessionKey(); $sessionRow = $this->Database->sessions()->createRow(array( 'session_key' => $newSessionKey, - 'expires' => time() + 2592000 //30 days + 'expires' => time() + 2592000 // 30 days )); $sessionRow->save(); @@ -39,4 +39,9 @@ class SessionService extends BaseService { $this->Database->sessions()->where('session_key', $sessionKey)->delete(); } + + private function GenerateSessionKey() + { + return RandomString(50); + } }