From c135fcf9041c604b32827a1cb027010bca5915ab Mon Sep 17 00:00:00 2001 From: Daniel Weipert Date: Thu, 14 Aug 2025 14:37:56 +0200 Subject: POST login possible --- .gitignore | 3 +- Readme.md | 2 +- src/App.php | 1 + src/Controllers/LoginController.php | 25 ++++++++++- src/ErrorCode.php | 47 -------------------- src/ErrorResponse.php | 16 ------- src/Errors/ErrorCode.php | 47 ++++++++++++++++++++ src/Errors/ErrorResponse.php | 30 +++++++++++++ src/Errors/Exception.php | 21 +++++++++ src/Errors/RateLimitError.php | 20 +++++++++ src/Errors/UnknownError.php | 16 +++++++ src/Router.php | 70 ------------------------------ src/Router/Router.php | 85 +++++++++++++++++++++++++++++++++++++ src/Router/routes_client_server.php | 41 ++++++++++++++++++ src/Router/routes_server_server.php | 24 +++++++++++ src/Support/Parser.php | 27 ++++++++++++ src/Types/AuthenticationType.php | 14 ++++++ src/routes.php | 55 ------------------------ 18 files changed, 353 insertions(+), 191 deletions(-) delete mode 100644 src/ErrorCode.php delete mode 100644 src/ErrorResponse.php create mode 100644 src/Errors/ErrorCode.php create mode 100644 src/Errors/ErrorResponse.php create mode 100644 src/Errors/Exception.php create mode 100644 src/Errors/RateLimitError.php create mode 100644 src/Errors/UnknownError.php delete mode 100644 src/Router.php create mode 100644 src/Router/Router.php create mode 100644 src/Router/routes_client_server.php create mode 100644 src/Router/routes_server_server.php create mode 100644 src/Support/Parser.php create mode 100644 src/Types/AuthenticationType.php delete mode 100644 src/routes.php diff --git a/.gitignore b/.gitignore index ca29c74..62a128a 100644 --- a/.gitignore +++ b/.gitignore @@ -3,4 +3,5 @@ .env -credentials.json +/credentials.json +/store/ diff --git a/Readme.md b/Readme.md index fda8853..9064374 100644 --- a/Readme.md +++ b/Readme.md @@ -1 +1 @@ -Matrix Specification: https://spec.matrix.org/v1.5/ +Matrix Specification: https://spec.matrix.org/v1.15/ diff --git a/src/App.php b/src/App.php index 33f71ef..9b1edf9 100644 --- a/src/App.php +++ b/src/App.php @@ -2,6 +2,7 @@ namespace App; +use App\Router\Router; use Symfony\Component\Dotenv\Dotenv; class App diff --git a/src/Controllers/LoginController.php b/src/Controllers/LoginController.php index f5ca3be..d48628b 100644 --- a/src/Controllers/LoginController.php +++ b/src/Controllers/LoginController.php @@ -2,6 +2,8 @@ namespace App\Controllers; +use App\Errors\UnknownError; +use App\Support\Parser; use App\Types\LoginFlow; use App\Types\LoginType; use Symfony\Component\HttpFoundation\Request; @@ -10,6 +12,10 @@ use Symfony\Component\HttpFoundation\JsonResponse; class LoginController { + /** + * GET /_matrix/client/r0/login + * GET /_matrix/client/v3/login + */ public function supportedLoginTypes(): Response { return new JsonResponse([ @@ -19,16 +25,33 @@ class LoginController ]); } + /** + * POST /_matrix/client/v3/login + */ public function login(): Response { $request = Request::createFromGlobals(); + $content = json_decode($request->getContent(), true); + + // validate login type + $loginType = null; + try { + $loginType = LoginType::from($content["type"]); + } catch (\ValueError $error) { + throw new UnknownError("Bad login type.", Response::HTTP_BAD_REQUEST); + } + + // get user name + $user = Parser::parseUser($content["identifier"]["user"]); + + #if ($loginType == LoginType::PASSWORD) {} return new JsonResponse([ "access_token" => "abc123", "device_id" => "ABC", "expires_in_ms" => 60000, "refresh_token" => "def456", - "user_id" => "@php:localhost", + "user_id" => "@{$user["username"]}:{$_ENV["DOMAIN"]}", #"well_known" => [], ]); } diff --git a/src/ErrorCode.php b/src/ErrorCode.php deleted file mode 100644 index 2149d37..0000000 --- a/src/ErrorCode.php +++ /dev/null @@ -1,47 +0,0 @@ - $code, - "error" => $message, - ]); - } -} diff --git a/src/Errors/ErrorCode.php b/src/Errors/ErrorCode.php new file mode 100644 index 0000000..b59f0a1 --- /dev/null +++ b/src/Errors/ErrorCode.php @@ -0,0 +1,47 @@ + $code, + "error" => $message, + ], + $httpCode + ); + } + + public static function fromException(Exception $exception): self + { + $self = new self($exception->getErrorCode(), $exception->getMessage(), $exception->getCode()); + + $self->setData( + json_decode($self->data, true) + $exception->getAdditionalData() + ); + + return $self; + } +} diff --git a/src/Errors/Exception.php b/src/Errors/Exception.php new file mode 100644 index 0000000..ccb124e --- /dev/null +++ b/src/Errors/Exception.php @@ -0,0 +1,21 @@ +errorCode; + } + + /** + * @return void + */ + abstract public function getAdditionalData(): array; +} diff --git a/src/Errors/RateLimitError.php b/src/Errors/RateLimitError.php new file mode 100644 index 0000000..d84f66a --- /dev/null +++ b/src/Errors/RateLimitError.php @@ -0,0 +1,20 @@ + $this->retryAfter, + ]; + } +} diff --git a/src/Errors/UnknownError.php b/src/Errors/UnknownError.php new file mode 100644 index 0000000..f861597 --- /dev/null +++ b/src/Errors/UnknownError.php @@ -0,0 +1,16 @@ +routes = new RouteCollection(); - $this->configurator = new RouteConfigurator($this->routes, $this->routes); - - $this->addRoutes(); - } - - /** - * match the current url against the routes. - * also add preflight CORS headers on OPTIONS requests. - */ - public function run(): Response - { - $request = Request::createFromGlobals(); - - if ($request->isMethod("OPTIONS")) { - $response = new Response(); - $response->headers->add([ - "Access-Control-Allow-Origin" => "*", - "Access-Control-Allow-Methods" => "GET, POST, PUT, DELETE, OPTIONS, PATCH, HEAD", - "Access-Control-Allow-Headers" => "X-Requested-With, Content-Type, Authorization", - ]); - - return $response; - } - - $context = new RequestContext(); - $context->fromRequest($request); - - try { - $matcher = new UrlMatcher($this->routes, $context); - $match = $matcher->matchRequest($request); - - $class = $match["_controller"][0]; - $method = $match["_controller"][1]; - - return (new $class)->$method(); - } catch (\Exception $exception) { - return new ErrorResponse(ErrorCode::UNKNOWN, "Unknown error occured"); - } - } - - /** - * add routes from the routes file - */ - private function addRoutes(): void - { - $routes = include_once(__DIR__ . "/routes.php"); - $routes($this->configurator); - } -} diff --git a/src/Router/Router.php b/src/Router/Router.php new file mode 100644 index 0000000..b167142 --- /dev/null +++ b/src/Router/Router.php @@ -0,0 +1,85 @@ +routes = new RouteCollection(); + $this->configurator = new RouteConfigurator($this->routes, $this->routes); + + $this->addRoutes(); + } + + /** + * match the current url against the routes. + * also add preflight CORS headers on OPTIONS requests. + */ + public function run(): Response + { + $request = Request::createFromGlobals(); + + if ($request->isMethod("OPTIONS")) { + $response = new Response(); + $response->headers->add([ + "Access-Control-Allow-Origin" => "*", + "Access-Control-Allow-Methods" => "GET, POST, PUT, DELETE, OPTIONS, PATCH, HEAD", + "Access-Control-Allow-Headers" => "X-Requested-With, Content-Type, Authorization", + ]); + + return $response; + } + + $context = new RequestContext(); + $context->fromRequest($request); + + try { + $matcher = new UrlMatcher($this->routes, $context); + $match = $matcher->matchRequest($request); + + $class = $match["_controller"][0]; + $method = $match["_controller"][1]; + + return (new $class)->$method(); + } catch (Exception $exception) { + return ErrorResponse::fromException($exception); + } catch (ResourceNotFoundException $exception) { + return new ErrorResponse(ErrorCode::NOT_FOUND, "404", Response::HTTP_NOT_FOUND); + } catch (MethodNotAllowedException $exception) { + return new ErrorResponse(ErrorCode::FORBIDDEN, "403", Response::HTTP_FORBIDDEN); + } catch (\Exception $exception) { + return new ErrorResponse(ErrorCode::UNKNOWN, "Unknown error occured", Response::HTTP_INTERNAL_SERVER_ERROR); + } + } + + /** + * add routes from the routes file + */ + private function addRoutes(): void + { + $routesClientServer = include_once(__DIR__ . "/routes_client_server.php"); + $routesClientServer($this->configurator); + + $routesServerServer = include_once(__DIR__ . "/routes_server_server.php"); + $routesServerServer($this->configurator); + } +} diff --git a/src/Router/routes_client_server.php b/src/Router/routes_client_server.php new file mode 100644 index 0000000..eff0be5 --- /dev/null +++ b/src/Router/routes_client_server.php @@ -0,0 +1,41 @@ +add("well_known_matrix_client", "/.well-known/matrix/client") + ->controller([ServerDiscoveryController::class, "client"]) + ->methods(["GET"]); + + $routes + ->add("well_known_matrix_support", "/.well-known/matrix/support") + ->controller([ServerDiscoveryController::class, "support"]) + ->methods(["GET"]); + + $routes + ->add("matrix_client_versions", "/_matrix/client/versions") + ->controller([ServerImplementationController::class, "versions"]) + ->methods(["GET"]); + + $supportedLoginTypes = [LoginController::class, "supportedLoginTypes"]; + $routes + ->add("matrix_client_r0_login_types", "/_matrix/client/r0/login") + ->controller($supportedLoginTypes) + ->methods(["GET"]); + $routes + ->add("matrix_client_v3_login_types", "/_matrix/client/v3/login") + ->controller($supportedLoginTypes) + ->methods(["GET"]); + + $routes + ->add("matrix_client_v3_login", "/_matrix/client/v3/login") + ->controller([LoginController::class, "login"]) + ->methods(["POST"]); +}; diff --git a/src/Router/routes_server_server.php b/src/Router/routes_server_server.php new file mode 100644 index 0000000..2e85a17 --- /dev/null +++ b/src/Router/routes_server_server.php @@ -0,0 +1,24 @@ +add("well_known_matrix_server", "/.well-known/matrix/server") + ->controller([ServerDiscoveryController::class, "server"]) + ->methods(["GET"]); + + $routes + ->add("matrix_federation_version", "/_matrix/federation/v1/version") + ->controller([ServerImplementationController::class, "version"]) + ->methods(["GET"]); + + # /_matrix/key/v2/server + # /_matrix/key/v2/query + # /_matrix/key/v2/query/{serverName} +}; diff --git a/src/Support/Parser.php b/src/Support/Parser.php new file mode 100644 index 0000000..d850de1 --- /dev/null +++ b/src/Support/Parser.php @@ -0,0 +1,27 @@ + + */ + public static function parseUser(string $user): array + { + $username = $user; + $server = ""; + + if (str_starts_with($user, "@")) { + $username = substr($user, 1); + $usernameParts = explode(":", $username); + $username = $usernameParts[0]; + $server = $usernameParts[1]; + } + + return [ + "username" => $username, + "server" => $server, + ]; + } +} diff --git a/src/Types/AuthenticationType.php b/src/Types/AuthenticationType.php new file mode 100644 index 0000000..dc768d0 --- /dev/null +++ b/src/Types/AuthenticationType.php @@ -0,0 +1,14 @@ +add("well_known_matrix_server", "/.well-known/matrix/server") - ->controller([ServerDiscoveryController::class, "server"]) - ->methods(["GET"]); - - $routes - ->add("well_known_matrix_client", "/.well-known/matrix/client") - ->controller([ServerDiscoveryController::class, "client"]) - ->methods(["GET"]); - - $routes - ->add("well_known_matrix_support", "/.well-known/matrix/support") - ->controller([ServerDiscoveryController::class, "support"]) - ->methods(["GET"]); - - $routes - ->add("matrix_federation_version", "/_matrix/federation/v1/version") - ->controller([ServerImplementationController::class, "version"]) - ->methods(["GET"]); - - $routes - ->add("matrix_client_versions", "/_matrix/client/versions") - ->controller([ServerImplementationController::class, "versions"]) - ->methods(["GET"]); - - # /_matrix/key/v2/server - # /_matrix/key/v2/query - # /_matrix/key/v2/query/{serverName} - - $supportedLoginTypes = [LoginController::class, "supportedLoginTypes"]; - $routes - ->add("matrix_client_r0_login_types", "/_matrix/client/r0/login") - ->controller($supportedLoginTypes) - ->methods(["GET"]); - $routes - ->add("matrix_client_v3_login_types", "/_matrix/client/v3/login") - ->controller($supportedLoginTypes) - ->methods(["GET"]); - - $routes - ->add("matrix_client_v3_login", "/_matrix/client/v3/login") - ->controller($supportedLoginTypes) - ->methods(["POST"]); -}; -- cgit v1.2.3