146 lines
5.1 KiB
PHP
146 lines
5.1 KiB
PHP
<?php
|
|
|
|
namespace KTXC\Controllers;
|
|
|
|
use KTXC\Http\Response\Response;
|
|
use KTXC\Http\Response\FileResponse;
|
|
use KTXC\Http\Response\JsonResponse;
|
|
use KTXC\Http\Response\RedirectResponse;
|
|
use KTXC\Server;
|
|
use KTXF\Controller\ControllerAbstract;
|
|
use KTXF\Routing\Attributes\AnonymousRoute;
|
|
use KTXC\Service\SecurityService;
|
|
use KTXC\SessionIdentity;
|
|
use KTXC\SessionTenant;
|
|
use KTXC\Http\Request\Request;
|
|
|
|
class DefaultController extends ControllerAbstract
|
|
{
|
|
public function __construct(
|
|
private readonly SecurityService $securityService,
|
|
private readonly SessionTenant $tenant,
|
|
private readonly SessionIdentity $identity,
|
|
) {}
|
|
|
|
#[AnonymousRoute('/', name: 'root', methods: ['GET'])]
|
|
public function home(Request $request): Response
|
|
{
|
|
// If an authenticated identity is available, serve the private app
|
|
if ($this->identity->identifier()) {
|
|
return new FileResponse(
|
|
Server::runtimeRootLocation() . '/public/private.html',
|
|
Response::HTTP_OK,
|
|
['Content-Type' => 'text/html']
|
|
);
|
|
}
|
|
|
|
// User is not authenticated - serve the public app
|
|
// If there's an accessToken cookie present but invalid, clear it
|
|
$response = new FileResponse(
|
|
Server::runtimeRootLocation() . '/public/public.html',
|
|
Response::HTTP_OK,
|
|
['Content-Type' => 'text/html']
|
|
);
|
|
|
|
// Clear any stale auth cookies since the user is not authenticated
|
|
if ($request->cookies->has('accessToken')) {
|
|
$response->headers->clearCookie('accessToken', '/');
|
|
}
|
|
if ($request->cookies->has('refreshToken')) {
|
|
$response->headers->clearCookie('refreshToken', '/security/refresh');
|
|
}
|
|
|
|
return $response;
|
|
}
|
|
|
|
#[AnonymousRoute('/login', name: 'login', methods: ['GET'])]
|
|
public function login(): Response
|
|
{
|
|
return new FileResponse(
|
|
Server::runtimeRootLocation() . '/public/public.html',
|
|
Response::HTTP_OK,
|
|
['Content-Type' => 'text/html']
|
|
);
|
|
}
|
|
|
|
#[AnonymousRoute('/logout', name: 'logout_get', methods: ['GET'])]
|
|
public function logoutGet(Request $request): Response
|
|
{
|
|
// Blacklist the current access token if present
|
|
$accessToken = $request->cookies->get('accessToken');
|
|
if ($accessToken) {
|
|
$claims = $this->securityService->extractTokenClaims($accessToken);
|
|
if ($claims && isset($claims['jti'])) {
|
|
$this->securityService->logout($claims['jti'], $claims['exp'] ?? null);
|
|
}
|
|
}
|
|
|
|
$response = new RedirectResponse(
|
|
'/login',
|
|
Response::HTTP_SEE_OTHER
|
|
);
|
|
|
|
// Clear both authentication cookies
|
|
$response->headers->clearCookie('accessToken', '/');
|
|
$response->headers->clearCookie('refreshToken', '/security/refresh');
|
|
|
|
return $response;
|
|
}
|
|
|
|
#[AnonymousRoute('/logout', name: 'logout_post', methods: ['POST'])]
|
|
public function logoutPost(Request $request): Response
|
|
{
|
|
// Blacklist the current access token if present
|
|
$accessToken = $request->cookies->get('accessToken');
|
|
if ($accessToken) {
|
|
$claims = $this->securityService->extractTokenClaims($accessToken);
|
|
if ($claims && isset($claims['jti'])) {
|
|
$this->securityService->logout($claims['jti'], $claims['exp'] ?? null);
|
|
}
|
|
}
|
|
|
|
$response = new JsonResponse(['message' => 'Logged out successfully']);
|
|
|
|
// Clear both authentication cookies
|
|
$response->headers->clearCookie('accessToken', '/');
|
|
$response->headers->clearCookie('refreshToken', '/security/refresh');
|
|
|
|
return $response;
|
|
}
|
|
|
|
/**
|
|
* Catch-all route for SPA routing.
|
|
* Serves the appropriate HTML based on authentication status,
|
|
* allowing client-side routing to handle the actual path.
|
|
*/
|
|
#[AnonymousRoute('/{path}', name: 'spa_catchall', methods: ['GET'])]
|
|
public function catchAll(Request $request, string $path = ''): Response
|
|
{
|
|
// If an authenticated identity is available, serve the private app
|
|
if ($this->identity->identifier()) {
|
|
return new FileResponse(
|
|
Server::runtimeRootLocation() . '/public/private.html',
|
|
Response::HTTP_OK,
|
|
['Content-Type' => 'text/html']
|
|
);
|
|
}
|
|
|
|
// User is not authenticated - serve the public app
|
|
$response = new FileResponse(
|
|
Server::runtimeRootLocation() . '/public/public.html',
|
|
Response::HTTP_OK,
|
|
['Content-Type' => 'text/html']
|
|
);
|
|
|
|
// Clear any stale auth cookies since the user is not authenticated
|
|
if ($request->cookies->has('accessToken')) {
|
|
$response->headers->clearCookie('accessToken', '/');
|
|
}
|
|
if ($request->cookies->has('refreshToken')) {
|
|
$response->headers->clearCookie('refreshToken', '/security/refresh');
|
|
}
|
|
|
|
return $response;
|
|
}
|
|
}
|