Initial Version

This commit is contained in:
root
2025-12-21 10:09:54 -05:00
commit 4ae6befc7b
422 changed files with 47225 additions and 0 deletions

View File

@@ -0,0 +1,38 @@
<?php
namespace KTXC\Http\Middleware;
use KTXC\Http\Request\Request;
use KTXC\Http\Response\Response;
use KTXC\Service\SecurityService;
use KTXC\SessionIdentity;
/**
* Authentication middleware
* Authenticates the request and initializes session identity
*
* Note: This middleware does NOT enforce authentication.
* It only attempts to authenticate if credentials are present.
* Route-level authentication is enforced by RouterMiddleware.
*/
class AuthenticationMiddleware implements MiddlewareInterface
{
public function __construct(
private readonly SecurityService $securityService,
private readonly SessionIdentity $sessionIdentity
) {}
public function process(Request $request, RequestHandlerInterface $handler): Response
{
// Attempt to authenticate the request
$identity = $this->securityService->authenticate($request);
// Initialize session identity if authentication succeeded
if ($identity) {
$this->sessionIdentity->initialize($identity, true);
}
// Continue to next middleware (authentication is optional at this stage)
return $handler->handle($request);
}
}

View File

@@ -0,0 +1,32 @@
<?php
namespace KTXC\Http\Middleware;
use KTXC\Http\Request\Request;
use KTXC\Http\Response\Response;
use KTXC\Service\FirewallService;
/**
* Firewall middleware
* Checks if the request is authorized to proceed
*/
class FirewallMiddleware implements MiddlewareInterface
{
public function __construct(
private readonly FirewallService $firewall
) {}
public function process(Request $request, RequestHandlerInterface $handler): Response
{
// Check firewall authorization
if (!$this->firewall->authorized($request)) {
return new Response(
Response::$statusTexts[Response::HTTP_FORBIDDEN],
Response::HTTP_FORBIDDEN
);
}
// Continue to next middleware
return $handler->handle($request);
}
}

View File

@@ -0,0 +1,21 @@
<?php
namespace KTXC\Http\Middleware;
use KTXC\Http\Request\Request;
use KTXC\Http\Response\Response;
/**
* PSR-15 style middleware interface
*/
interface MiddlewareInterface
{
/**
* Process an incoming server request.
*
* @param Request $request The request to process
* @param RequestHandlerInterface $handler The next handler in the pipeline
* @return Response The response from processing
*/
public function process(Request $request, RequestHandlerInterface $handler): Response;
}

View File

@@ -0,0 +1,112 @@
<?php
namespace KTXC\Http\Middleware;
use KTXC\Http\Request\Request;
use KTXC\Http\Response\Response;
use Psr\Container\ContainerInterface;
/**
* Middleware pipeline - processes request through a stack of middleware
*/
class MiddlewarePipeline implements RequestHandlerInterface
{
/** @var array<string|MiddlewareInterface> */
private array $middleware = [];
private ?ContainerInterface $container = null;
public function __construct(?ContainerInterface $container = null)
{
$this->container = $container;
}
/**
* Add middleware to the pipeline
*
* @param string|MiddlewareInterface $middleware Middleware class name or instance
* @return self
*/
public function pipe(string|MiddlewareInterface $middleware): self
{
$this->middleware[] = $middleware;
return $this;
}
/**
* Handle the request through the middleware pipeline
*
* @param Request $request
* @return Response
*/
public function handle(Request $request): Response
{
// Create a handler for the pipeline
$handler = $this->createHandler(0);
return $handler->handle($request);
}
/**
* Create a handler for a specific position in the pipeline
*
* @param int $index Current position in the middleware stack
* @return RequestHandlerInterface
*/
public function createHandler(int $index): RequestHandlerInterface
{
// If we've reached the end of the pipeline, return a default handler
if (!isset($this->middleware[$index])) {
return new class implements RequestHandlerInterface {
public function handle(Request $request): Response {
return new Response(Response::$statusTexts[Response::HTTP_NOT_FOUND], Response::HTTP_NOT_FOUND);
}
};
}
return new class($this->middleware[$index], $this, $index, $this->container) implements RequestHandlerInterface {
private string|MiddlewareInterface $middleware;
private MiddlewarePipeline $pipeline;
private int $index;
private ?ContainerInterface $container;
public function __construct(
string|MiddlewareInterface $middleware,
MiddlewarePipeline $pipeline,
int $index,
?ContainerInterface $container
) {
$this->middleware = $middleware;
$this->pipeline = $pipeline;
$this->index = $index;
$this->container = $container;
}
public function handle(Request $request): Response
{
// Resolve middleware instance if it's a class name
$middleware = $this->middleware;
if (is_string($middleware)) {
if ($this->container && $this->container->has($middleware)) {
$middleware = $this->container->get($middleware);
} else {
$middleware = new $middleware();
}
}
if (!$middleware instanceof MiddlewareInterface) {
throw new \RuntimeException(
sprintf('Middleware must implement %s', MiddlewareInterface::class)
);
}
// Create the next handler in the chain
$next = $this->pipeline->createHandler($this->index + 1);
// Process this middleware
return $middleware->process($request, $next);
}
};
}
}

View File

@@ -0,0 +1,20 @@
<?php
namespace KTXC\Http\Middleware;
use KTXC\Http\Request\Request;
use KTXC\Http\Response\Response;
/**
* PSR-15 style request handler interface
*/
interface RequestHandlerInterface
{
/**
* Handle the request and return a response.
*
* @param Request $request The request to handle
* @return Response The response from handling the request
*/
public function handle(Request $request): Response;
}

View File

@@ -0,0 +1,62 @@
<?php
namespace KTXC\Http\Middleware;
use KTXC\Http\Request\Request;
use KTXC\Http\Response\Response;
use KTXC\Routing\Router;
use KTXC\Routing\Route;
use KTXC\SessionIdentity;
use KTXC\Security\Authorization\PermissionChecker;
/**
* Router middleware
* Matches routes and dispatches to controllers
*/
class RouterMiddleware implements MiddlewareInterface
{
public function __construct(
private readonly Router $router,
private readonly SessionIdentity $sessionIdentity,
private readonly PermissionChecker $permissionChecker
) {}
public function process(Request $request, RequestHandlerInterface $handler): Response
{
// Attempt to match the route
$match = $this->router->match($request);
if (!$match instanceof Route) {
// No route matched, continue to next handler (will return 404)
return $handler->handle($request);
}
// Check if route requires authentication
if ($match->authenticated && $this->sessionIdentity->identity() === null) {
return new Response(
Response::$statusTexts[Response::HTTP_UNAUTHORIZED],
Response::HTTP_UNAUTHORIZED
);
}
// Check permissions (if any specified)
if ($match->authenticated && !empty($match->permissions)) {
if (!$this->permissionChecker->canAny($match->permissions)) {
return new Response(
Response::$statusTexts[Response::HTTP_FORBIDDEN],
Response::HTTP_FORBIDDEN
);
}
}
// Dispatch to the controller
$response = $this->router->dispatch($match, $request);
if ($response instanceof Response) {
return $response;
}
// If dispatch didn't return a response, continue to next handler
return $handler->handle($request);
}
}

View File

@@ -0,0 +1,35 @@
<?php
namespace KTXC\Http\Middleware;
use KTXC\Http\Request\Request;
use KTXC\Http\Response\Response;
use KTXC\SessionTenant;
/**
* Tenant resolution middleware
* Configures the tenant based on the request host
*/
class TenantMiddleware implements MiddlewareInterface
{
public function __construct(
private readonly SessionTenant $sessionTenant
) {}
public function process(Request $request, RequestHandlerInterface $handler): Response
{
// Configure tenant from request host
$this->sessionTenant->configure($request->getHost());
// Check if tenant is configured and enabled
if (!$this->sessionTenant->configured() || !$this->sessionTenant->enabled()) {
return new Response(
Response::$statusTexts[Response::HTTP_UNAUTHORIZED],
Response::HTTP_UNAUTHORIZED
);
}
// Continue to next middleware
return $handler->handle($request);
}
}