From bd11271621bd3759cfd194ed0119c0dc28155fd0 Mon Sep 17 00:00:00 2001 From: Daniel Weipert Date: Thu, 5 Mar 2026 14:57:28 +0100 Subject: update --- src/Controllers/LoginController.php | 12 +- src/Controllers/RoomController.php | 154 ++++++++++++++++++++++- src/Controllers/ServerDiscoveryController.php | 2 +- src/Controllers/SyncController.php | 168 +++++++++++++------------- src/Controllers/UserController.php | 27 ++++- src/Database.php | 8 +- src/Events/Event.php | 20 --- src/Events/PresenceEvent.php | 40 ------ src/Events/RoomMemberEvent.php | 36 ------ src/Events/RoomMessageEvent.php | 86 ------------- src/Events/RoomNameEvent.php | 33 ----- src/Models/RoomEvent.php | 64 ++++++++++ src/Models/Tokens.php | 29 ++++- src/Models/User.php | 35 +++++- src/Router/Router.php | 37 ++++-- src/Router/routes_client_server.php | 19 +++ src/Support/ArrayTransformable.php | 11 -- src/Support/Id.php | 21 ++++ src/Support/Logger.php | 1 + src/Types/AuthenticationType.php | 14 --- src/Types/EventType.php | 11 -- src/Types/IdentifierType.php | 10 -- src/Types/LoginFlow.php | 27 ----- src/Types/LoginType.php | 9 -- src/Types/MembershipState.php | 12 -- src/Types/MessageType.php | 8 -- src/Types/PresenceState.php | 10 -- src/Types/UserRegistrationKind.php | 9 -- 28 files changed, 466 insertions(+), 447 deletions(-) delete mode 100644 src/Events/Event.php delete mode 100644 src/Events/PresenceEvent.php delete mode 100644 src/Events/RoomMemberEvent.php delete mode 100644 src/Events/RoomMessageEvent.php delete mode 100644 src/Events/RoomNameEvent.php create mode 100644 src/Models/RoomEvent.php delete mode 100644 src/Support/ArrayTransformable.php create mode 100644 src/Support/Id.php delete mode 100644 src/Types/AuthenticationType.php delete mode 100644 src/Types/EventType.php delete mode 100644 src/Types/IdentifierType.php delete mode 100644 src/Types/LoginFlow.php delete mode 100644 src/Types/LoginType.php delete mode 100644 src/Types/MembershipState.php delete mode 100644 src/Types/MessageType.php delete mode 100644 src/Types/PresenceState.php delete mode 100644 src/Types/UserRegistrationKind.php (limited to 'src') diff --git a/src/Controllers/LoginController.php b/src/Controllers/LoginController.php index c520e25..9ae3a48 100644 --- a/src/Controllers/LoginController.php +++ b/src/Controllers/LoginController.php @@ -9,10 +9,12 @@ use App\Errors\UnknownError; use App\Models\Device; use App\Models\Tokens; use App\Models\User; +use App\Support\Logger; +use App\Support\Parser; use App\Support\RequestValidator; -use App\Types\UserRegistrationKind; use Matrix\Data\LoginFlow; use Matrix\Enums\LoginType; +use Matrix\Enums\UserRegistrationKind; use Matrix\Responses\ClientLoginGetResponse; use Matrix\Responses\ClientLoginPostResponse; use Matrix\Responses\ClientRegisterPostResponse; @@ -37,6 +39,8 @@ class LoginController */ public function login(Request $request): Response { + Logger::logRequestToFile($request); + $body = json_decode($request->getContent(), true); RequestValidator::validateJson(); @@ -49,7 +53,11 @@ class LoginController } // get user id - $userId = $body["identifier"]["user"]; + $userId = Parser::parseUser($body["identifier"]["user"]); + if (empty($userId["server"])) { + #$userId = "@$userId[username]:$_ENV[DOMAIN]"; + $userId = "@$userId[username]:localhost"; + } #if ($loginType == LoginType::PASSWORD) {} diff --git a/src/Controllers/RoomController.php b/src/Controllers/RoomController.php index c02d5ce..dcc0415 100755 --- a/src/Controllers/RoomController.php +++ b/src/Controllers/RoomController.php @@ -7,18 +7,155 @@ use App\Errors\AppException; use App\Errors\ErrorCode; use App\Errors\UnauthorizedError; use App\Events\RoomMessageEvent; +use App\Models\RoomEvent; use App\Models\User; +use App\Support\Id; use App\Support\Parser; use App\Support\RequestValidator; -use App\Types\EventType; -use App\Types\MembershipState; -use App\Types\MessageType; +use Matrix\Enums\EventType; +use Matrix\Enums\MembershipState; +use Matrix\Enums\MessageType; +use Matrix\Enums\RoomGuestAccess; +use Matrix\Enums\RoomHistoryVisibility; +use Matrix\Enums\RoomJoinRule; +use Matrix\Enums\RoomVisibility; +use Matrix\Events\Room\CreateEvent; +use Matrix\Events\Room\GuestAccessEvent; +use Matrix\Events\Room\HistoryVisibilityEvent; +use Matrix\Events\Room\JoinRulesEvent; +use Matrix\Events\Room\MemberEvent; +use Matrix\Events\Room\NameEvent; +use Matrix\Events\Room\PowerLevelsEvent; use Symfony\Component\HttpFoundation\Request; use Symfony\Component\HttpFoundation\Response; use Symfony\Component\HttpFoundation\JsonResponse; class RoomController { + public function createRoom(Request $request): Response + { + $user = User::authenticateWithRequest($request); + $body = json_decode($request->getContent(), true); + RequestValidator::validateJson(); + + $creationContent = $body["creation_content"] ?? []; + $initialState = $body["initial_state"] ?? []; + $invite = $body["invite"] ?? []; + $body["invite_3pid"] ?? []; + $body["is_direct"] ?? false; + $name = $body["name"] ?? ""; + $body["power_level_content_override"] ?? []; + $preset = $body["preset"] ?? ""; + $roomAliasName = $body["room_alias_name"] ?? ""; + $roomVersion = $body["room_version"] ?? "DEFAULT_ROOM_VERSION"; + $topic = $body["topic"] ?? ""; + $visibility = RoomVisibility::tryFrom($body["visibility"] ?? "private"); + + if (! $preset) { + $preset = $visibility->value . "_chat"; + } + + # TODO: get events for preset + # TODO: override preset events with initial state + # TODO: override events with name and topic if applicable + $state = []; + + if ($name) { + $state[EventType::ROOM_NAME->value] = $name; + } + + if ($topic) { + $state[EventType::ROOM_TOPIC->value] = $topic; + } + + // create room + $roomId = Id::generateRoomId(); + Database::getInstance()->query(<< $roomId, + "name" => $roomAliasName, # "#$roomAliasName:$_ENV[DOMAIN]", + ]); + + $roomCreateEvent = new RoomEvent(new CreateEvent( + eventId: Id::generateEventId(), + originServerTimestamp: time(), + roomId: $roomId, + sender: $user->getId(), + roomVersion: "12", + )); + $roomCreateEvent->insert(); + + $roomMemberEvent = new RoomEvent(new MemberEvent( + eventId: Id::generateEventId(), + originServerTimestamp: time(), + roomId: $roomId, + sender: $user->getId(), + stateKey: $user->getId(), + isDirect: false, + membership: MembershipState::JOIN, + displayName: $user->getName(), + )); + $roomMemberEvent->insert(); + + $roomPowerLevelsEvent = new RoomEvent(new PowerLevelsEvent( + eventId: Id::generateEventId(), + originServerTimestamp: time(), + roomId: $roomId, + sender: $user->getId(), + )); + $roomPowerLevelsEvent->insert(); + + $roomJoinRulesEvent = new RoomEvent(new JoinRulesEvent( + eventId: Id::generateEventId(), + originServerTimestamp: time(), + roomId: $roomId, + sender: $user->getId(), + joinRule: RoomJoinRule::INVITE, + )); + $roomJoinRulesEvent->insert(); + + $roomHistoryVisibilityEvent = new RoomEvent(new HistoryVisibilityEvent( + eventId: Id::generateEventId(), + originServerTimestamp: time(), + roomId: $roomId, + sender: $user->getId(), + historyVisibility: RoomHistoryVisibility::SHARED, + )); + $roomHistoryVisibilityEvent->insert(); + + $roomGuestAccessEvent = new RoomEvent(new GuestAccessEvent( + eventId: Id::generateEventId(), + originServerTimestamp: time(), + roomId: $roomId, + sender: $user->getId(), + guestAccess: RoomGuestAccess::CAN_JOIN, + )); + $roomGuestAccessEvent->insert(); + + $roomNameEvent = new RoomEvent(new NameEvent( + eventId: Id::generateEventId(), + originServerTimestamp: time(), + roomId: $roomId, + sender: $user->getId(), + name: $roomAliasName, + )); + $roomNameEvent->insert(); + + Database::getInstance()->query(<< $roomId, + "user_id" => $user->getId(), + "state" => MembershipState::JOIN->value, + ]); + + return new JsonResponse([ + "room_id" => $roomId, + ]); + } + /** * GET /_matrix/client/v3/directory/room/{roomAlias} * @@ -59,6 +196,17 @@ class RoomController ]); } + public function readMarkers(Request $request): Response + { + $user = User::authenticateWithRequest($request); + $body = json_decode($request->getContent(), true); + RequestValidator::validateJson(); + + $roomId = $request->attributes->get("roomId"); + + return new JsonResponse(); + } + /** * PUT /_matrix/client/v3/rooms/{roomId}/send/{eventType}/{txnId} * diff --git a/src/Controllers/ServerDiscoveryController.php b/src/Controllers/ServerDiscoveryController.php index f3b96b2..917df14 100644 --- a/src/Controllers/ServerDiscoveryController.php +++ b/src/Controllers/ServerDiscoveryController.php @@ -19,7 +19,7 @@ class ServerDiscoveryController { return new JsonResponse([ "m.homeserver" => [ - "base_url" => "https://$_ENV[DOMAIN]", + "base_url" => "http://$_ENV[DOMAIN]", ], ]); } diff --git a/src/Controllers/SyncController.php b/src/Controllers/SyncController.php index 243fab5..acebb11 100755 --- a/src/Controllers/SyncController.php +++ b/src/Controllers/SyncController.php @@ -3,13 +3,23 @@ namespace App\Controllers; use App\Database; -use App\Errors\UnauthorizedError; -use App\Events\PresenceEvent; -use App\Events\RoomMemberEvent; -use App\Events\RoomMessageEvent; +use App\Models\RoomEvent; use App\Models\User; -use App\Types\MembershipState; -use App\Types\PresenceState; +use Matrix\Data\AccountData; +use Matrix\Data\DeviceLists; +use Matrix\Data\Presence; +use Matrix\Data\Room\Ephemeral; +use Matrix\Data\Room\JoinedRoom; +use Matrix\Data\Room\RoomSummary; +use Matrix\Data\Room\Rooms; +use Matrix\Data\Room\State; +use Matrix\Data\Room\Timeline; +use Matrix\Data\Room\UnreadNotificationCounts; +use Matrix\Data\ToDevice; +use Matrix\Enums\MembershipState; +use Matrix\Enums\PresenceState; +use Matrix\Events\PresenceEvent; +use Matrix\Responses\ClientSyncGetResponse; use Symfony\Component\HttpFoundation\Request; use Symfony\Component\HttpFoundation\Response; use Symfony\Component\HttpFoundation\JsonResponse; @@ -24,99 +34,93 @@ class SyncController */ public function sync(Request $request): Response { - $accessToken = str_replace("Bearer ", "", $request->headers->get("authorization") ?: ""); - $user = User::fetchWithAccessToken($accessToken); - - if (empty($user)) { - throw new UnauthorizedError(); - } + $user = User::authenticateWithRequest($request); $filter = $request->query->get("filter", ""); $syncFullState = $request->query->get("full_state", false); $setPresence = PresenceState::tryFrom($request->query->get("set_presence") ?? "") ?? PresenceState::ONLINE; $since = $request->query->get("since", ""); $timeout = $request->query->get("timeout", 0); + $useStateAfter = $request->query->get("use_state_after", false); + + if (! empty($filter)) { + if (str_starts_with($filter, "{")) { + $filter = json_decode($filter, true); + } else { + $filter = Database::getInstance()->query("select * from filters where id=:id", ["id" => $filter])->fetch(); + } + } $rooms = Database::getInstance()->query(<<fetchAll(); - - $joinedRooms = new \stdClass(); - if (! empty($rooms)) { - $joinedRooms = []; - foreach ($rooms as $room) { - $joinedRooms[$room["id"]] = [ - "account_data" => [ - "events" => [], - ], - - "ephemeral" => [ - "events" => [], - ], - - "state" => [ - "events" => [], - ], - - "summary" => [ - "m.heroes" => [], - "m.invited_member_count" => 0, - "m.joined_member_count" => 1, - ], - - "timeline" => [ - "events" => [ - (new RoomMemberEvent($user->getId(), $user->getId(), MembershipState::JOIN))->toJsonEncodeable(), - (new RoomMessageEvent($user->getId(), "Hallo Test Nachricht"))->toJsonEncodeable(), - ], - "limited" => false, - "prev_batch" => "", - ], - - "unread_notifications" => [ - "highlight_count" => random_int(0, 1), - "notification_count" => random_int(0, 10), - ], - - "unread_thread_notifications" => new \stdClass(), - ]; + left join room_memberships + on rooms.id = room_memberships.room_id + where room_memberships.user_id = :user_id + SQL, [ + "user_id" => $user->getId(), + ])->fetchAll(); + + $invitedRooms = []; + $joinedRooms = []; + $knockedRooms = []; + $leftRooms = []; + + foreach ($rooms as $room) { + $events = Database::getInstance()->query(<< $room["room_id"], + #"limit" => ($filter["room"]["timeline"]["limit"] ?? false) ? "limit " . $filter["room"]["timeline"]["limit"] : "", + ])->fetchAll(); + + if ($since === "" && MembershipState::tryFrom($room["state"]) === MembershipState::JOIN) { + $joinedRooms[$room["room_id"]] = new JoinedRoom( + accountData: new AccountData([]), + ephemeral: new Ephemeral([]), + state: new State([]), + summary: new RoomSummary( + heroes: [], + invitedMemberCount: 0, + joinedMemberCount: 1, + ), + timeline: new Timeline( + events: array_map([RoomEvent::class, "transformEvent"], $events), + limited: false,# $filter["room"]["timeline"]["limit"] ?? false, + previousBatch: null, + ), + unreadNotifications: new UnreadNotificationCounts(0, 0), + unreadThreadNotifications: [], + ); } } - return new JsonResponse([ - "account_data" => [ - "events" => [ + return new JsonResponse(new ClientSyncGetResponse( + nextBatch: "1", - ], - ], + accountData: new AccountData([]), - "device_lists" => [ - "changed" => [], - "left" => [], - ], + deviceLists: new DeviceLists([], []), - "device_one_time_keys_count" => [ + deviceOneTimeKeysCount: [ "signed_curve25519" => 10, ], - "next_batch" => "next_batch_id", - - "presence" => [ - "events" => [ - (new PresenceEvent(sender: $user->getId()))->toJsonEncodeable(), - ], - ], - - "rooms" => [ - "invite" => new \stdClass(), - "join" => $joinedRooms, - "knock" => new \stdClass(), - "leave" => new \stdClass(), - ], - - "to_device" => [ - "events" => [], - ], - ]); + presence: new Presence([ + new PresenceEvent( + sender: $user->getId(), + presence: $setPresence, + ), + ]), + + rooms: new Rooms( + $invitedRooms, + $joinedRooms, + $knockedRooms, + $leftRooms, + ), + + toDevice: new ToDevice([]), + )); } } diff --git a/src/Controllers/UserController.php b/src/Controllers/UserController.php index a056e1d..d102160 100755 --- a/src/Controllers/UserController.php +++ b/src/Controllers/UserController.php @@ -2,8 +2,10 @@ namespace App\Controllers; +use App\Database; use App\Errors\UnauthorizedError; use App\Models\User; +use App\Support\RequestValidator; use Symfony\Component\HttpFoundation\Request; use Symfony\Component\HttpFoundation\Response; use Symfony\Component\HttpFoundation\JsonResponse; @@ -25,8 +27,31 @@ class UserController throw new UnauthorizedError(); } + $userId = $request->get("userId"); + if ($user->getId() !== $userId) { + throw new UnauthorizedError(); + } + + $body = json_decode($request->getContent(), true); + RequestValidator::validateJson(); + + $filterId = md5($userId . random_bytes(512)); + + Database::getInstance()->query(<< $filterId, + "account_data" => isset($body["account_data"]) ? json_encode($body["account_data"]) : null, + "event_fields" => isset($body["event_fields"]) ? json_encode($body["event_fields"]) : null, + "event_format" => isset($body["event_format"]) ? json_encode($body["event_format"]) : null, + "presence" => isset($body["presence"]) ? json_encode($body["presence"]) : null, + "room" => isset($body["room"]) ? json_encode($body["room"]) : null, + "user_id" => $userId, + ]); + return new JsonResponse([ - "filter_id" => "1234", + "filter_id" => $filterId, ]); } } diff --git a/src/Database.php b/src/Database.php index e84abc1..4c26a93 100644 --- a/src/Database.php +++ b/src/Database.php @@ -2,9 +2,6 @@ namespace App; -use PDO; -use PDOStatement; - class Database { use Singleton; @@ -40,4 +37,9 @@ class Database return $statement; } + + public function getLastInsertId(string $name = ""): string|false + { + return $this->connection->lastInsertId($name); + } } diff --git a/src/Events/Event.php b/src/Events/Event.php deleted file mode 100644 index 7dbf242..0000000 --- a/src/Events/Event.php +++ /dev/null @@ -1,20 +0,0 @@ - - */ - abstract public function toJsonEncodeable(): array; -} diff --git a/src/Events/PresenceEvent.php b/src/Events/PresenceEvent.php deleted file mode 100644 index cd230c5..0000000 --- a/src/Events/PresenceEvent.php +++ /dev/null @@ -1,40 +0,0 @@ - $this->type, - "sender" => $this->sender, - "content" => [ - "avatar_url" => $this->avatarUrl, - "currently_active" => $this->currentlyActive, - "last_active_ago" => $this->lastActiveAgo, - "presence" => $this->presence, - "status_msg" => $this->statusMessage, - ], - ]; - } -} diff --git a/src/Events/RoomMemberEvent.php b/src/Events/RoomMemberEvent.php deleted file mode 100644 index 79ba0cc..0000000 --- a/src/Events/RoomMemberEvent.php +++ /dev/null @@ -1,36 +0,0 @@ - $this->type, - "sender" => $this->sender, - "state_key" => $this->stateKey, - "event_id" => "\$0", - "origin_server_ts" => time(), - "content" => [ - "membership" => $this->membership, - ], - ]; - } -} diff --git a/src/Events/RoomMessageEvent.php b/src/Events/RoomMessageEvent.php deleted file mode 100644 index 3ccc408..0000000 --- a/src/Events/RoomMessageEvent.php +++ /dev/null @@ -1,86 +0,0 @@ - $this->type, - "sender" => $this->sender, - "event_id" => $this->id, - "origin_server_ts" => $this->originServerTimestamp->format("U.v"), - "content" => [ - "body" => $this->body, - "msgtype" => MessageType::TEXT, - ], - "unsigned" => [ - "age" => 1234, - "membership" => MembershipState::JOIN, - ], - "room_id" => $this->roomId, - ]; - } - - public static function fromDatabase(array $row): self - { - } - - public static function fetch(): ?self - { - } - - public static function fetchAll(): array - { - } - - public function insert(): bool - { - return !! Database::getInstance()->query( - << $this->id, - "type" => $this->type->value, - "sender" => $this->sender, - "origin_server_timestamp" => (new \DateTime("now"))->format("U.v"), - "content" => json_encode($this->content), - "unsigned" => json_encode($this->unsigned), - "room_id" => $this->roomId, - ] - ); - } - - public function update(): bool - { - } - - public function delete(): bool - { - } -} diff --git a/src/Events/RoomNameEvent.php b/src/Events/RoomNameEvent.php deleted file mode 100644 index 279e6c1..0000000 --- a/src/Events/RoomNameEvent.php +++ /dev/null @@ -1,33 +0,0 @@ - $this->type, - "sender" => $this->sender, - "state_key" => $this->stateKey, - "content" => [ - "name" => $this->name, - ], - ]; - } -} diff --git a/src/Models/RoomEvent.php b/src/Models/RoomEvent.php new file mode 100644 index 0000000..96dc204 --- /dev/null +++ b/src/Models/RoomEvent.php @@ -0,0 +1,64 @@ + $row + */ + public static function transformEvent(array $row): ClientEvent + { + return new ClientEvent( + content: json_decode($row["content"], true), + eventId: $row["id"], + originServerTimestamp: new \DateTime($row["origin_server_timestamp"])->getTimestamp(), + roomId: $row["room_id"], + sender: $row["sender"], + type: EventType::from($row["type"]), + unsigned: json_decode($row["unsigned"], true), + ); + } + + public function insert(): bool + { + if ($this->event instanceof StateEvent) { + return !! Database::getInstance()->query(<< $this->event->getId(), + "content" => json_encode($this->event->getContent()), + "type" => $this->event->getType()->value, + "sender" => $this->event->getSender(), + "origin_server_timestamp" => \DateTime::createFromTimestamp($this->event->getOriginServerTimestamp())->format("U.v"), + "room_id" => $this->event->getRoomId(), + "unsigned" => json_encode($this->event->getUnsigned()), + "state_key" => $this->event->getStateKey(), + ]); + } + + return !! Database::getInstance()->query(<< $this->event->getId(), + "content" => json_encode($this->event->getContent()), + "type" => $this->event->getType()->value, + "sender" => $this->event->getSender(), + "origin_server_timestamp" => \DateTime::createFromTimestamp($this->event->getOriginServerTimestamp())->format("U.v"), + "room_id" => $this->event->getRoomId(), + "unsigned" => json_encode($this->event->getUnsigned()), + ]); + } +} diff --git a/src/Models/Tokens.php b/src/Models/Tokens.php index 4ad8e1d..ee912fb 100644 --- a/src/Models/Tokens.php +++ b/src/Models/Tokens.php @@ -37,9 +37,9 @@ class Tokens implements ConnectsToDatabase $isExpiredSql = ""; if ($isExpired) { - $isExpiredSql = "and expires_at <= current_timestamp"; + #$isExpiredSql = "and expires_at <= current_timestamp"; } else { - $isExpiredSql = "and expires_at > current_timestamp"; + #$isExpiredSql = "and expires_at > current_timestamp"; } $row = []; @@ -78,6 +78,26 @@ class Tokens implements ConnectsToDatabase public static function fetchAll(): array {} + public static function fetchWithAccessToken(string $accessToken): ?self + { + $row = Database::getInstance()->query( + << $accessToken, + ] + )->fetch(); + + if (empty($row)) { + return null; + } + + return self::fromDatabase($row); + } + public static function fetchWithRefreshToken(string $refreshToken): ?self { $row = Database::getInstance()->query( @@ -140,6 +160,11 @@ class Tokens implements ConnectsToDatabase ); } + public function isExpired(): bool + { + return $this->expiresAt->format("U.v") <= time(); + } + public function getAccessToken(): string { return $this->accessToken; diff --git a/src/Models/User.php b/src/Models/User.php index c0c73f8..c92f5b3 100644 --- a/src/Models/User.php +++ b/src/Models/User.php @@ -3,19 +3,26 @@ namespace App\Models; use App\Database; +use App\Errors\AppException; +use App\Errors\ErrorCode; use App\Errors\UnauthorizedError; use App\Support\ConnectsToDatabase; use Symfony\Component\HttpFoundation\Request; +use Symfony\Component\HttpFoundation\Response; class User implements ConnectsToDatabase { - public function __construct(private string $id) + public function __construct( + private string $id, + private string $name, + ) {} public static function fromDatabase(array $row): self { return new self( $row["id"], + $row["name"], ); } @@ -67,9 +74,9 @@ class User implements ConnectsToDatabase return self::fromDatabase($row); } - public static function new(string $id): self + public static function new(string $id, string $name): self { - return new self($id); + return new self($id, $name); } public static function authenticateWithRequest(Request $request): self @@ -81,6 +88,17 @@ class User implements ConnectsToDatabase throw new UnauthorizedError(); } + $tokens = Tokens::fetchWithAccessToken($accessToken); + + if (empty($tokens) /*|| $tokens->isExpired()*/) { + throw new AppException( + ErrorCode::UNKNOWN_TOKEN, + "Soft logged out", + Response::HTTP_UNAUTHORIZED, + ["soft_logout" => true], + ); + } + return $user; } @@ -88,11 +106,12 @@ class User implements ConnectsToDatabase { return !! Database::getInstance()->query( << $this->id, + "name" => $this->name, ] ); } @@ -108,10 +127,16 @@ class User implements ConnectsToDatabase return $this->id; } + public function getName(): string + { + return $this->name; + } + public function fetchDevice(string $id): ?Device { return Device::fetch($id, $this->id); } + /** * @return Device[] */ diff --git a/src/Router/Router.php b/src/Router/Router.php index 534b7f7..377821f 100644 --- a/src/Router/Router.php +++ b/src/Router/Router.php @@ -6,6 +6,7 @@ use App\Errors\ErrorCode; use App\Errors\ErrorResponse; use App\Errors\Exception; use App\Singleton; +use App\Support\Logger; use Symfony\Component\HttpFoundation\Request; use Symfony\Component\HttpFoundation\Response; use Symfony\Component\Routing\Exception\MethodNotAllowedException; @@ -38,14 +39,14 @@ class Router { $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", - ]); + $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", + ]); + if ($request->isMethod("OPTIONS")) { return $response; } @@ -64,22 +65,34 @@ class Router array_flip(["_controller", "_route"]) )); - return (new $class)->$method($request); + Logger::logRequestToFile($request); + + $response = (new $class)->$method($request); } catch (Exception $exception) { - return ErrorResponse::fromException($exception); + $response = ErrorResponse::fromException($exception); } catch (ResourceNotFoundException $exception) { - return new ErrorResponse(ErrorCode::NOT_FOUND, "404", Response::HTTP_NOT_FOUND); + $response = new ErrorResponse(ErrorCode::NOT_FOUND, "404", Response::HTTP_NOT_FOUND); } catch (MethodNotAllowedException $exception) { - return new ErrorResponse(ErrorCode::FORBIDDEN, "403", Response::HTTP_FORBIDDEN); + $response = new ErrorResponse(ErrorCode::FORBIDDEN, "403", Response::HTTP_FORBIDDEN); } catch (\LogicException $exception) { // display logic exceptions normally throw $exception; } catch (\Exception $exception) { - return new ErrorResponse( + $response = new ErrorResponse( ErrorCode::UNKNOWN, $exception->getMessage() ?: "Unknown error occured", Response::HTTP_INTERNAL_SERVER_ERROR ); + } catch (\Error $error) { + error_log($error->getMessage() ?: "Unknown error occured"); + + $response = new ErrorResponse( + ErrorCode::UNKNOWN, + $error->getMessage() ?: "Unknown error occured", + Response::HTTP_INTERNAL_SERVER_ERROR + ); } + + return $response; } /** diff --git a/src/Router/routes_client_server.php b/src/Router/routes_client_server.php index fd39d08..590520b 100644 --- a/src/Router/routes_client_server.php +++ b/src/Router/routes_client_server.php @@ -34,6 +34,10 @@ return function (RouteConfigurator $routes): void ->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_r0_login", "/_matrix/client/r0/login") @@ -89,4 +93,19 @@ return function (RouteConfigurator $routes): void ->add("matrix_client_r0_user_id_filter", "/_matrix/client/r0/user/{userId}/filter") ->controller([UserController::class, "uploadFilter"]) ->methods(["POST"]); + + $routes + ->add("matrix_client_v3_user_id_filter", "/_matrix/client/v3/user/{userId}/filter") + ->controller([UserController::class, "uploadFilter"]) + ->methods(["POST"]); + + $routes + ->add("matrix_client_v3_room_create", "/_matrix/client/v3/createRoom") + ->controller([RoomController::class, "createRoom"]) + ->methods(["POST"]); + + $routes + ->add("matrix_client_v3_rooms_id_read_markers", "/_matrix/client/v3/rooms/{roomId}/read_markers") + ->controller([RoomController::class, "readMarkers"]) + ->methods(["POST"]); }; diff --git a/src/Support/ArrayTransformable.php b/src/Support/ArrayTransformable.php deleted file mode 100644 index f1adf81..0000000 --- a/src/Support/ArrayTransformable.php +++ /dev/null @@ -1,11 +0,0 @@ -getPathInfo()); file_put_contents( diff --git a/src/Types/AuthenticationType.php b/src/Types/AuthenticationType.php deleted file mode 100644 index dc768d0..0000000 --- a/src/Types/AuthenticationType.php +++ /dev/null @@ -1,14 +0,0 @@ - $this->type, - ]; - - if ($this->type == LoginType::TOKEN) { - $flow["get_login_token"] = $this->get_login_token; - } - - return $flow; - } -} diff --git a/src/Types/LoginType.php b/src/Types/LoginType.php deleted file mode 100644 index a5e3d8b..0000000 --- a/src/Types/LoginType.php +++ /dev/null @@ -1,9 +0,0 @@ -