diff --git a/meta/definitions/authorize.php b/meta/definitions/authorize.php index 9a26943..ce3789f 100644 --- a/meta/definitions/authorize.php +++ b/meta/definitions/authorize.php @@ -1,9 +1,17 @@ create(Authenticate::class)->constructor(get(Entity\UserInterface::class), get(Session::class), get(Cookie::class), get('authentication.method')), - Authorize::class => create(Authorize::class)->constructor(get(Entity\UserInterface::class), get(Session::class), get(Cookie::class), get('authentication.method')), - HeaderAuthenticationMiddleware::class => create(HeaderAuthenticationMiddleware::class)->constructor(get(Authorize::class), get(Entity\UserInterface::class), get('authorize.error')), + Authenticate::class => create(Authenticate::class)->constructor(get(Entity\UserInterface::class), get(Session::class), get(Cookie::class), get('authentication.method')), - PostRequestAuthentication::class => create(PostRequestAuthentication::class)->constructor(get(Authenticate::class), "email", "email", "password"), + AuthenticationMiddleware::class => create(AuthenticationMiddleware::class)->constructor(get(Authorize::class), get('authorize.error')), - PostRequestAuthenticationMiddleware::class => create(PostRequestAuthenticationMiddleware::class)->constructor(get(Entity\UserInterface::class), get('authentication.error'), get(PostRequestAuthentication::class)), + HeaderAuthentication::class => autowire(HeaderAuthentication::class), + + HeaderAuthenticationMiddleware::class => create(HeaderAuthenticationMiddleware::class)->constructor(get(HeaderAuthentication::class)), + + CookieAuthentication::class => autowire(CookieAuthentication::class), + + CookieAuthenticationMiddleware::class => create(CookieAuthenticationMiddleware::class)->constructor(get(CookieAuthentication::class), get(Cookie::class)), + + PostRequestAuthentication::class => create(PostRequestAuthentication::class)->constructor("email", "email", "password"), + + PostRequestAuthenticationMiddleware::class => create(PostRequestAuthenticationMiddleware::class)->constructor(get(PostRequestAuthentication::class)), MacAddressAuthentication::class => create(MacAddressAuthentication::class)->constructor(get(Authenticate::class), "mac"), @@ -32,18 +49,19 @@ return [ 'authentication.method' => null, - 'authorize.error' => function($c) { + 'authorize.error' => function(ContainerInterface $c) { return function(array $errorData) use ($c) { - return $c->get(\Lean\Factory\HttpFactoryInterface::class)::createJsonResponse($errorData + [ - 'api.error' => "Authorization failed", - 'api.datetime' => (new \DateTime)->format(\DateTime::ATOM), - ], 403); + return $c->get(HttpFactoryInterface::class)::createJsonResponse($errorData + [ + 'api.error' => "Authorization failed", + 'api.datetime' => (new \DateTime)->format(\DateTime::ATOM), + ], 403); }; }, 'authentication.error' => function($c, Picea $picea) { - return function($message) use ($picea, $c) { - return $c->get(\Lean\Factory\HttpFactoryInterface::class)::createHtmlResponse($picea->renderHtml('lean/error/500', [ + return function($message) use ($c, $picea) { + return $c->get(HttpFactoryInterface::class)::createHtmlResponse($picea->renderHtml('lean/error/500', [ + 'title' => "Authentication failed", 'subtitle' => "", 'message' => $message, diff --git a/meta/definitions/http.php b/meta/definitions/http.php index b0bae16..74b0d29 100644 --- a/meta/definitions/http.php +++ b/meta/definitions/http.php @@ -1,11 +1,18 @@ function ($c) { @@ -19,4 +26,33 @@ return [ NotFoundDecoratorInterface::class => autowire(NotFoundDecorator::class), # MethodNotAllowedInterface::class => autowire(MethodNotAllowedDecorator::class), + HttpFactoryInterface::class => create(HttpFactory::class), + + Cookie::class => create(Cookie::class)->constructor([ + 'secure' => true, + 'path' => getenv('URL_BASE') ?: '/', + 'httponly' => true, + 'samesite'=> "Lax", + ], getenv("LEAN_RANDOM")), + + Session::class => create(Session::class)->constructor(get(Cookie::class), [ 'path' => getenv('URL_BASE') ?: '/', ]), + + SessionMiddleware::class => create(SessionMiddleware::class)->constructor(get(Cookie::class), [ + 'name' => "lean_sess_" . substr(md5(getenv("LEAN_RANDOM")), 0, 12), + 'path' => getenv('URL_BASE') ?: '/', + 'samesite' => getenv("LEAN_COOKIE_SAMESITE") ?? "Lax", + 'secure' => (bool) getenv('LEAN_COOKIE_SECURE') ?? false + ]), + + 'error.401' => function(ContainerInterface $c, Picea $picea) { + return $c->get(HttpFactoryInterface::class)::createHtmlResponse($picea->renderHtml("lean/error/401", []), 401); + }, + + 'error.404' => function(ContainerInterface $c, Picea $picea) { + return $c->get(HttpFactoryInterface::class)::createHtmlResponse($picea->renderHtml("lean/error/404", []), 404); + }, + + 'error.500' => function(ContainerInterface $c, Picea $picea) { + return $c->get(HttpFactoryInterface::class)::createHtmlResponse($picea->renderHtml("lean/error/500", []), 500); + }, ]; diff --git a/meta/definitions/routes.php b/meta/definitions/routes.php index 3416c6e..38ab958 100644 --- a/meta/definitions/routes.php +++ b/meta/definitions/routes.php @@ -15,6 +15,11 @@ use Notes\Breadcrumb\Breadcrumb; use Storage\SessionMiddleware; +use Ulmus\User\Middleware\{ + HeaderAuthenticationMiddleware, + PostRequestAuthenticationMiddleware +}; + use Psr\Http\Message\{ ResponseInterface, ServerRequestInterface }; return [ @@ -65,7 +70,8 @@ return [ } } - $router->addPatternMatcher('email', '[^@ \t\r\n]+@[^@ \t\r\n]+\.[^@ \t\r\n/]+'); + $router->addPatternMatcher('email', '[^@ \t\r\n/]+@[^@ \t\r\n/]+\.[^@ \t\r\n/]+'); + $router->addPatternMatcher('ids', '\b\d[\d,]*\b'); $routing = $container->get(Lean\Routing::class); $routing->registerRoute($container, getenv('URL_BASE')); diff --git a/meta/definitions/software.php b/meta/definitions/software.php index b3ef6b2..48c2278 100644 --- a/meta/definitions/software.php +++ b/meta/definitions/software.php @@ -6,9 +6,6 @@ use TheBugs\JavascriptMiddleware; use Lean\Lean; -use Storage\Cookie, - Storage\Session, - Storage\SessionMiddleware; use function DI\autowire, DI\create, DI\get, DI\add; @@ -78,12 +75,6 @@ return [ JavascriptMiddleware::class => create(JavascriptMiddleware::class), - Cookie::class => create(Cookie::class)->constructor([ 'secure' => true, 'path' => getenv('URL_BASE') ?: '/', ], getenv("LEAN_RANDOM")), - - Session::class => create(Session::class)->constructor(get(Cookie::class), [ 'path' => getenv('URL_BASE') ?: '/', ]), - - SessionMiddleware::class => create(SessionMiddleware::class)->constructor(get(Cookie::class), [ 'name' => "lean_sess_" . substr(md5(getenv("LEAN_RANDOM")), 0, 12), 'path' => getenv('URL_BASE') ?: '/' ]), - 'git.commit' => function($c) { if ( getenv("DEBUG") ) { return uniqid("debug_"); diff --git a/skeleton/cli b/skeleton/cli old mode 100755 new mode 100644 diff --git a/skeleton/composer.json.dist b/skeleton/composer.json.dist index 442b98f..3dacb66 100644 --- a/skeleton/composer.json.dist +++ b/skeleton/composer.json.dist @@ -37,7 +37,6 @@ "mcnd/picea-ui": "dev-master", "mcnd/picea-asset": "~1.0.2", "mcnd/cronard": "dev-master", - "mcnd/lean-api": "dev-master", "mcnd/lean-console": "~1.3.2", "mcnd/kash": "dev-master", "mcnd/taxus": "dev-master", diff --git a/skeleton/meta/config.php b/skeleton/meta/config.php index 722b116..a43390b 100644 --- a/skeleton/meta/config.php +++ b/skeleton/meta/config.php @@ -10,7 +10,7 @@ return [ ], 'keys' => (function() { - return explode(',', getenv('KEYS') ?? "") ; + return explode(',', getenvonce('KEYS') ?? "") ; })(), 'meta' => [ diff --git a/skeleton/meta/definitions/auth.php b/skeleton/meta/definitions/auth.php index 5d6645f..53b7c74 100644 --- a/skeleton/meta/definitions/auth.php +++ b/skeleton/meta/definitions/auth.php @@ -4,6 +4,7 @@ use function DI\autowire, DI\create, DI\get; use %NAMESPACE%\Entity; +use Psr\Container\ContainerInterface; use Psr\Http\Message\ServerRequestInterface; use Ulmus\Entity\Field\Datetime, @@ -21,16 +22,18 @@ use TheBugs\Email\{ EmailConfiguration, MailerInterface, SwiftMailer }; use Taxus\{ Taxus, PermissionGrantInterface }; +use Lean\Factory\HttpFactoryInterface; + return [ \Ulmus\User\Entity\UserInterface::class => autowire(Entity\User::class), - SecurityHandler::class => create(SecurityHandler::class)->constructor(function() { - return Lean\Factory\HttpFactory::createRedirectResponse(getenv("URL_BASE")."/login"); + SecurityHandler::class => create(SecurityHandler::class)->constructor(function(ContainerInterface $c) { + return $c->get(HttpFactoryInterface::class)::createRedirectResponse(getenv("URL_BASE")."/login"); }, get('authentication.unauthorize'), get(Taxus::class)), - 'authentication.unauthorize' => function($c, Picea $picea) { - return function($message) use ($picea) { - return Lean\Factory\HttpFactory::createHtmlResponse($picea->renderHtml('lean/error/401', [ + 'authentication.unauthorize' => function(ContainerInterface $c, Picea $picea) { + return function($message) use ($c, $picea) { + return $c->get(HttpFactoryInterface::class)::createHtmlResponse($picea->renderHtml('lean/error/401', [ 'title' => "", 'subtitle' => "", 'message' => $message, diff --git a/skeleton/meta/definitions/env/prod.php b/skeleton/meta/definitions/env/prod.php index 097f571..1163712 100644 --- a/skeleton/meta/definitions/env/prod.php +++ b/skeleton/meta/definitions/env/prod.php @@ -4,7 +4,7 @@ use Picea\Picea; use Negundo\Client\{ NegundoMiddleware, SoftwareConfig }; -use Lean\Factory\HttpFactory; +use Lean\Factory\HttpFactoryInterface; use Psr\Http\Server\MiddlewareInterface, Psr\Http\Message\ServerRequestInterface, @@ -31,11 +31,11 @@ return [ "errorHandler" => create(NegundoMiddleware::class)->constructor(get(SoftwareConfig::class), null, get('app.errorhandler.html')), - 'app.errorhandler.html' => function($c, Picea $picea) { - return function(\Throwable $exception) use ($picea) { + 'app.errorhandler.html' => function(\Psr\Container\ContainerInterface $c, Picea $picea) { + return function(\Throwable $exception) use ($c, $picea) { error_log($exception->getMessage()); - return HttpFactory::createHtmlResponse($picea->renderHtml('lean/error/500', [ + return $c->get(HttpFactoryInterface::class)::createHtmlResponse($picea->renderHtml('lean/error/500', [ 'title' => "Une erreur s'est produite lors de l'exécution du script.", 'subtitle' => "Êtes-vous connecté avec le bon compte ?", 'message' => $exception->getMessage(), diff --git a/src/ApplicationStrategy/NotFoundDecorator.php b/src/ApplicationStrategy/NotFoundDecorator.php index 8ce628f..d4ac54d 100644 --- a/src/ApplicationStrategy/NotFoundDecorator.php +++ b/src/ApplicationStrategy/NotFoundDecorator.php @@ -39,7 +39,7 @@ class NotFoundDecorator implements NotFoundDecoratorInterface public function throw404(ServerRequestInterface $request) : ResponseInterface { - return $this->checkAssetTrigger($request) ?: $this->httpFactory->createHtmlResponse($this->picea->renderHtml("lean/error/404", [], $this), 404); + return $this->checkAssetTrigger($request) ?: $this->container->get('error.404'); } protected function checkAssetTrigger(ServerRequestInterface $request) : false|ResponseInterface diff --git a/src/ControllerTrait.php b/src/ControllerTrait.php index 31dcbc0..35388fe 100644 --- a/src/ControllerTrait.php +++ b/src/ControllerTrait.php @@ -7,7 +7,6 @@ use Lean\Factory\HttpFactory; use Notes\Attribute\Ignore; use Notes\Route\Attribute\Object\Route; use Notes\Security\Attribute\Security; -use Picea, Picea\Ui\Method\FormContext; use Picea\Ui\Method\FormContextInterface; use TheBugs\Email\MailerInterface; use Storage\{ Cookie, Session }; @@ -210,6 +209,16 @@ trait ControllerTrait { return $this->picea->compiler->getExtensionFromToken('route')->buildRouteUrl($name, $parameters); } + #[Ignore] + public function form(FormInterface $form, ? FormContextInterface $formContext = null) : Picea\Ui\Method\FormHandler + { + if (! $this->picea ) { + throw new \Exception("A picea object must be provided on class initialization to use this method."); + } + + return $this->picea->compiler->getExtensionInstanceOf(Picea\Ui\Method\Form::class)->formClass($form, $formContext); + } + #[Ignore] public function json($data, int $flags = 0) : string { diff --git a/src/Factory/HttpFactoryInterface.php b/src/Factory/HttpFactoryInterface.php index 81a6173..d44ae58 100644 --- a/src/Factory/HttpFactoryInterface.php +++ b/src/Factory/HttpFactoryInterface.php @@ -2,9 +2,6 @@ namespace Lean\Factory; -use Laminas\Diactoros\Response\{EmptyResponse, HtmlResponse, JsonResponse, RedirectResponse, TextResponse}; -use Lean\Response\{ DownloadResponse, ImageResponse, FileDownloadResponse, PdfResponse }; -use Laminas\Diactoros\Response; use Psr\Http\Message\ResponseInterface; use Psr\Http\Message\StreamInterface; @@ -20,6 +17,5 @@ interface HttpFactoryInterface public static function createDownloadableResponse(string $data, string $filename, int $code = 200, array $headers = []) : ResponseInterface; public static function createImageResponse(string $data, int $code = 200, array $headers = []) : ResponseInterface; public static function createFileDownloadResponse(string $path, int $code = 200, array $headers = []) : ResponseInterface; - public static function createStream(string $content) : StreamInterface; -} +} \ No newline at end of file diff --git a/src/Kernel.php b/src/Kernel.php index 4c926d9..21fc2cc 100644 --- a/src/Kernel.php +++ b/src/Kernel.php @@ -11,13 +11,16 @@ use League\Route\Strategy\ApplicationStrategy; use Psr\Http\Message\ServerRequestInterface; +use Tell\I18n; +use Ulmus\Container\AdapterProxy; + use Laminas\Diactoros\ServerRequestFactory, Laminas\HttpHandlerRunner\Emitter\EmitterInterface; use Ulmus\Ulmus; -class Kernel -{ +class Kernel { + protected Container $container; protected string $locale; @@ -34,10 +37,12 @@ class Kernel public function __construct( public string $projectPath - ) - { + ) { # Still not sure about adding a folder check each call just to add a basic project setup error ... # File::assertFolderExists($this->projectPath); + + define('IS_CLI', php_sapi_name() === 'cli' OR defined('STDIN')); + $this->setEnvironment(); $this->initializeEngine(); $this->setupContainer(); @@ -74,12 +79,14 @@ class Kernel // Paths and directories foreach($this->paths as $name => $envkey) { - if (!getenv($name)) { + if ( ! getenv($name) ) { $path = getenv("PROJECT_PATH") . DIRECTORY_SEPARATOR . getenv($envkey); if (getenv('DEBUG') && ! file_exists($path)) { - if (false === mkdir($path, 0755, true)) { - throw new \Exception(sprintf("Folder '%s' could not be created", $path)); + if (false === @mkdir($path, 0755, true)) { + if (! IS_CLI) { + throw new \Exception(sprintf("Folder '%s' could not be created", $path)); + } } } @@ -96,7 +103,7 @@ class Kernel setlocale(LC_ALL, $this->locale = getenv("DEFAULT_LOCAL")); setlocale(LC_TIME, getenv("DEFAULT_TIME"), getenv("DEFAULT_TIME_FALLBACK")); - if (class_exists('Locale')) { + if ( class_exists('Locale') ) { \Locale::setDefault($this->locale); } @@ -122,8 +129,7 @@ class Kernel if (getenv("APP_ENV") === "prod") { if (getenv("CACHE_PATH")) { - # check if ACPU is there first, - # $containerBuilder->enableDefinitionCache(); # Do not work .. ? + # check if ACPU is there first, $containerBuilder->enableDefinitionCache(); $containerBuilder->enableCompilation(getenv("CACHE_PATH") . "/di/"); # No proxies yet... $containerBuilder->writeProxiesToFile(true, getenv("CACHE_PATH") . "/di/"); @@ -190,4 +196,4 @@ class Kernel return $this; } -} \ No newline at end of file +}; diff --git a/src/Routing.php b/src/Routing.php index c359c40..adc6a50 100644 --- a/src/Routing.php +++ b/src/Routing.php @@ -44,6 +44,11 @@ class Routing { $container->set(ServerRequestInterface::class, $request); + # Decoding arguments received from the router + foreach($arguments as &$arg) { + $arg = urldecode($arg); + } + return $this->response ?? $object->$method($request, $arguments); }); }