summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorDaniel Weipert <git@mail.dweipert.de>2025-12-13 16:27:53 +0100
committerDaniel Weipert <git@mail.dweipert.de>2025-12-13 16:27:53 +0100
commit2386148b8f048ba40d9f26cc97898bdcdc778ea2 (patch)
tree48ca45de3dc6133cb0225eba8c5917f813082b2b
parentb19a8f63ad727a3633885d3f2b81edf8181a53b9 (diff)
matrix specification splitHEADmain
-rw-r--r--composer.json8
-rw-r--r--composer.lock14
-rw-r--r--docker-compose.yml2
-rw-r--r--matrix-specification/Data/AuthenticationData.php24
-rw-r--r--matrix-specification/Data/Contact.php2
-rw-r--r--matrix-specification/Data/DiscoveryInformation.php2
-rw-r--r--matrix-specification/Data/Filters/EventFilter.php2
-rw-r--r--matrix-specification/Data/Filters/RoomEventFilter.php2
-rw-r--r--matrix-specification/Data/Filters/RoomFilter.php2
-rw-r--r--matrix-specification/Data/Room/JoinedRoom.php2
-rw-r--r--matrix-specification/Data/Room/LeftRoom.php2
-rw-r--r--matrix-specification/Data/Room/RoomSummary.php2
-rw-r--r--matrix-specification/Data/Room/ThreadNotificationCounts.php2
-rw-r--r--matrix-specification/Data/Room/Timeline.php2
-rw-r--r--matrix-specification/Data/Room/UnreadNotificationCounts.php2
-rw-r--r--matrix-specification/Enums/UserRegistrationKind.php14
-rw-r--r--matrix-specification/Events/PresenceEvent.php2
-rw-r--r--matrix-specification/Events/UnsignedData.php2
-rw-r--r--matrix-specification/Message.php18
-rw-r--r--matrix-specification/Request.php15
-rw-r--r--matrix-specification/Requests/ClientAccountWhoamiGetRequest.php27
-rw-r--r--matrix-specification/Requests/ClientDirectoryRoomAliasGetRequest.php4
-rw-r--r--matrix-specification/Requests/ClientKeysUploadPostRequest.php18
-rw-r--r--matrix-specification/Requests/ClientLoginPostRequest.php18
-rw-r--r--matrix-specification/Requests/ClientRefreshPostRequest.php17
-rw-r--r--matrix-specification/Requests/ClientRegisterPostRequest.php57
-rw-r--r--matrix-specification/Requests/ClientSyncGetRequest.php16
-rw-r--r--matrix-specification/Requests/ClientUserIdFilterPostRequest.php17
-rw-r--r--matrix-specification/Requests/RateLimited.php4
-rw-r--r--matrix-specification/Requests/RequiresAuthentication.php4
-rw-r--r--matrix-specification/Requests/RequiresAuthenticationOptional.php6
-rw-r--r--matrix-specification/Response.php8
-rw-r--r--matrix-specification/Responses/ClientAccountWhoamiGetResponse.php8
-rw-r--r--matrix-specification/Responses/ClientDirectoryRoomAliasGetResponse.php6
-rw-r--r--matrix-specification/Responses/ClientKeysUploadPostResponse.php9
-rw-r--r--matrix-specification/Responses/ClientLoginGetResponse.php5
-rw-r--r--matrix-specification/Responses/ClientLoginPostResponse.php7
-rw-r--r--matrix-specification/Responses/ClientRefreshPostResponse.php8
-rw-r--r--matrix-specification/Responses/ClientRegisterPostResponse.php39
-rw-r--r--matrix-specification/Responses/ClientSyncGetResponse.php7
-rw-r--r--matrix-specification/Responses/ClientUserIdFilterPostResponse.php11
-rw-r--r--matrix-specification/Responses/ClientVersionsGetResponse.php8
-rw-r--r--matrix-specification/Responses/WellKnownMatrixClientGetResponse.php7
-rw-r--r--matrix-specification/Responses/WellKnownMatrixSupportGetResponse.php7
-rwxr-xr-xsrc/Controllers/AccountController.php18
-rw-r--r--src/Controllers/KeyController.php31
-rw-r--r--src/Controllers/LoginController.php44
-rw-r--r--src/Models/User.php16
48 files changed, 405 insertions, 143 deletions
diff --git a/composer.json b/composer.json
index 49923a9..5a1178e 100644
--- a/composer.json
+++ b/composer.json
@@ -8,11 +8,11 @@
}
],
"require": {
+ "psr/http-message": "^2.0",
"psr/log": "^3.0",
"symfony/dotenv": "^7.3",
"symfony/http-foundation": "^7.3",
- "symfony/routing": "^7.3",
- "psr/http-message": "^2.0"
+ "symfony/routing": "^7.3"
},
"require-dev": {
"guzzlehttp/guzzle": "^7.9",
@@ -21,8 +21,8 @@
"autoload": {
"psr-4": {
"App\\": "src/",
- "Tests\\": "tests/",
- "Matrix\\": "matrix-specification"
+ "Matrix\\": "matrix-specification",
+ "Tests\\": "tests/"
}
},
"scripts": {
diff --git a/composer.lock b/composer.lock
index 398e061..d720eb4 100644
--- a/composer.lock
+++ b/composer.lock
@@ -4,7 +4,7 @@
"Read more about it at https://getcomposer.org/doc/01-basic-usage.md#installing-dependencies",
"This file is @generated automatically"
],
- "content-hash": "1e6280a905a847ca703c88bbef0521b2",
+ "content-hash": "4964ee19b991107643bde192528a6119",
"packages": [
{
"name": "psr/http-message",
@@ -256,16 +256,16 @@
},
{
"name": "symfony/http-foundation",
- "version": "v7.3.2",
+ "version": "v7.3.3",
"source": {
"type": "git",
"url": "https://github.com/symfony/http-foundation.git",
- "reference": "6877c122b3a6cc3695849622720054f6e6fa5fa6"
+ "reference": "7475561ec27020196c49bb7c4f178d33d7d3dc00"
},
"dist": {
"type": "zip",
- "url": "https://api.github.com/repos/symfony/http-foundation/zipball/6877c122b3a6cc3695849622720054f6e6fa5fa6",
- "reference": "6877c122b3a6cc3695849622720054f6e6fa5fa6",
+ "url": "https://api.github.com/repos/symfony/http-foundation/zipball/7475561ec27020196c49bb7c4f178d33d7d3dc00",
+ "reference": "7475561ec27020196c49bb7c4f178d33d7d3dc00",
"shasum": ""
},
"require": {
@@ -315,7 +315,7 @@
"description": "Defines an object-oriented layer for the HTTP specification",
"homepage": "https://symfony.com",
"support": {
- "source": "https://github.com/symfony/http-foundation/tree/v7.3.2"
+ "source": "https://github.com/symfony/http-foundation/tree/v7.3.3"
},
"funding": [
{
@@ -335,7 +335,7 @@
"type": "tidelift"
}
],
- "time": "2025-07-10T08:47:49+00:00"
+ "time": "2025-08-20T08:04:18+00:00"
},
{
"name": "symfony/polyfill-mbstring",
diff --git a/docker-compose.yml b/docker-compose.yml
index ea5668f..519873f 100644
--- a/docker-compose.yml
+++ b/docker-compose.yml
@@ -1,6 +1,6 @@
services:
db:
- image: postgres
+ image: postgres:17
environment:
- "POSTGRES_DB=${DB_NAME}"
- "POSTGRES_USER=${DB_USER}"
diff --git a/matrix-specification/Data/AuthenticationData.php b/matrix-specification/Data/AuthenticationData.php
new file mode 100644
index 0000000..64fdd95
--- /dev/null
+++ b/matrix-specification/Data/AuthenticationData.php
@@ -0,0 +1,24 @@
+<?php
+
+namespace Matrix\Data;
+
+class AuthenticationData implements \JsonSerializable
+{
+ public function __construct(
+ private ?string $session = null,
+ private ?string $type = null,
+ )
+ {
+ # TODO: throw for session and type
+ # TODO: throw for keys dependent on login type
+ # throw new \InvalidArgumentException("at least one is required");
+ }
+
+ public function jsonSerialize(): array
+ {
+ return [
+ "session" => $this->session,
+ "type" => $this->type,
+ ];
+ }
+}
diff --git a/matrix-specification/Data/Contact.php b/matrix-specification/Data/Contact.php
index 9eeefe5..54a48e4 100644
--- a/matrix-specification/Data/Contact.php
+++ b/matrix-specification/Data/Contact.php
@@ -23,6 +23,6 @@ class Contact implements \JsonSerializable
"email_address" => $this->emailAddress,
"matrix_id" => $this->matrixId,
"role" => $this->role,
- ], "is_null");
+ ], fn ($value) => ! is_null($value));
}
}
diff --git a/matrix-specification/Data/DiscoveryInformation.php b/matrix-specification/Data/DiscoveryInformation.php
index 42a3dc2..f4eda64 100644
--- a/matrix-specification/Data/DiscoveryInformation.php
+++ b/matrix-specification/Data/DiscoveryInformation.php
@@ -24,7 +24,7 @@ class DiscoveryInformation implements \JsonSerializable
],
$this->otherProperties ?? [],
),
- "is_null"
+ fn ($value) => ! is_null($value)
);
}
}
diff --git a/matrix-specification/Data/Filters/EventFilter.php b/matrix-specification/Data/Filters/EventFilter.php
index 98788ad..cd8fdf2 100644
--- a/matrix-specification/Data/Filters/EventFilter.php
+++ b/matrix-specification/Data/Filters/EventFilter.php
@@ -31,6 +31,6 @@ class EventFilter implements \JsonSerializable
"not_types" => $this->notTypes,
"senders" => $this->senders,
"types" => $this->types,
- ], "is_null");
+ ], fn ($value) => ! is_null($value));
}
}
diff --git a/matrix-specification/Data/Filters/RoomEventFilter.php b/matrix-specification/Data/Filters/RoomEventFilter.php
index 915c9a0..b7ce87b 100644
--- a/matrix-specification/Data/Filters/RoomEventFilter.php
+++ b/matrix-specification/Data/Filters/RoomEventFilter.php
@@ -45,6 +45,6 @@ class RoomEventFilter extends EventFilter
"not_rooms" => $this->notRooms,
"rooms" => $this->rooms,
"unread_thread_notifications" => $this->unreadThreadNotifications,
- ], "is_null");
+ ], fn ($value) => ! is_null($value));
}
}
diff --git a/matrix-specification/Data/Filters/RoomFilter.php b/matrix-specification/Data/Filters/RoomFilter.php
index dd110bd..fe741c5 100644
--- a/matrix-specification/Data/Filters/RoomFilter.php
+++ b/matrix-specification/Data/Filters/RoomFilter.php
@@ -34,6 +34,6 @@ class RoomFilter
"rooms" => $this->rooms,
"state" => $this->state,
"timeline" => $this->timeline,
- ], "is_null");
+ ], fn ($value) => ! is_null($value));
}
}
diff --git a/matrix-specification/Data/Room/JoinedRoom.php b/matrix-specification/Data/Room/JoinedRoom.php
index 89f64b9..0057071 100644
--- a/matrix-specification/Data/Room/JoinedRoom.php
+++ b/matrix-specification/Data/Room/JoinedRoom.php
@@ -32,6 +32,6 @@ class JoinedRoom implements \JsonSerializable
"timeline" => $this->timeline,
"unread_notifications" => $this->unreadNotifications,
"unreadThreadNotifications" => $this->unreadThreadNotifications,
- ], "is_null");
+ ], fn ($value) => ! is_null($value));
}
}
diff --git a/matrix-specification/Data/Room/LeftRoom.php b/matrix-specification/Data/Room/LeftRoom.php
index 18e97b5..64b9462 100644
--- a/matrix-specification/Data/Room/LeftRoom.php
+++ b/matrix-specification/Data/Room/LeftRoom.php
@@ -25,6 +25,6 @@ class LeftRoom implements \JsonSerializable
"state" => $this->state,
"state_after" => $this->stateAfter,
"timeline" => $this->timeline,
- ], "is_null");
+ ], fn ($value) => ! is_null($value));
}
}
diff --git a/matrix-specification/Data/Room/RoomSummary.php b/matrix-specification/Data/Room/RoomSummary.php
index 91d170f..5ac86a8 100644
--- a/matrix-specification/Data/Room/RoomSummary.php
+++ b/matrix-specification/Data/Room/RoomSummary.php
@@ -20,6 +20,6 @@ class RoomSummary implements \JsonSerializable
"m.heroes" => $this->heroes,
"m.invited_member_count" => $this->invitedMemberCount,
"m.joined_member_count" => $this->joinedMemberCount,
- ], "is_null");
+ ], fn ($value) => ! is_null($value));
}
}
diff --git a/matrix-specification/Data/Room/ThreadNotificationCounts.php b/matrix-specification/Data/Room/ThreadNotificationCounts.php
index 346aeb3..602de61 100644
--- a/matrix-specification/Data/Room/ThreadNotificationCounts.php
+++ b/matrix-specification/Data/Room/ThreadNotificationCounts.php
@@ -15,6 +15,6 @@ class ThreadNotificationCounts implements \JsonSerializable
return array_filter([
"highlight_count" => $this->highlightCount,
"notification_count" => $this->notificationCount,
- ], "is_null");
+ ], fn ($value) => ! is_null($value));
}
}
diff --git a/matrix-specification/Data/Room/Timeline.php b/matrix-specification/Data/Room/Timeline.php
index cc88472..8d70ddd 100644
--- a/matrix-specification/Data/Room/Timeline.php
+++ b/matrix-specification/Data/Room/Timeline.php
@@ -22,6 +22,6 @@ class Timeline implements \JsonSerializable
"events" => $this->events,
"limited" => $this->limited,
"prev_batch" => $this->previousBatch,
- ], "is_null");
+ ], fn ($value) => ! is_null($value));
}
}
diff --git a/matrix-specification/Data/Room/UnreadNotificationCounts.php b/matrix-specification/Data/Room/UnreadNotificationCounts.php
index d2600e6..f00a6a5 100644
--- a/matrix-specification/Data/Room/UnreadNotificationCounts.php
+++ b/matrix-specification/Data/Room/UnreadNotificationCounts.php
@@ -15,6 +15,6 @@ class UnreadNotificationCounts implements \JsonSerializable
return array_filter([
"highlight_count" => $this->highlightCount,
"notification_count" => $this->notificationCount,
- ], "is_null");
+ ], fn ($value) => ! is_null($value));
}
}
diff --git a/matrix-specification/Enums/UserRegistrationKind.php b/matrix-specification/Enums/UserRegistrationKind.php
new file mode 100644
index 0000000..28ddd40
--- /dev/null
+++ b/matrix-specification/Enums/UserRegistrationKind.php
@@ -0,0 +1,14 @@
+<?php
+
+namespace Matrix\Enums;
+
+enum UserRegistrationKind: string implements \JsonSerializable
+{
+ case GUEST = "guest";
+ case USER = "user";
+
+ public function jsonSerialize(): string
+ {
+ return $this->value;
+ }
+}
diff --git a/matrix-specification/Events/PresenceEvent.php b/matrix-specification/Events/PresenceEvent.php
index c8c2023..7854444 100644
--- a/matrix-specification/Events/PresenceEvent.php
+++ b/matrix-specification/Events/PresenceEvent.php
@@ -25,7 +25,7 @@ class PresenceEvent extends SenderEvent
"last_active_ago" => $lastActiveAgo,
"presence" => $presence,
"status_msg" => $statusMessage,
- ], "is_null"),
+ ], fn ($value) => ! is_null($value)),
$sender,
EventType::PRESENCE
);
diff --git a/matrix-specification/Events/UnsignedData.php b/matrix-specification/Events/UnsignedData.php
index 924af29..3c5cd46 100644
--- a/matrix-specification/Events/UnsignedData.php
+++ b/matrix-specification/Events/UnsignedData.php
@@ -26,6 +26,6 @@ class UnsignedData implements \JsonSerializable
"prev_content" => $this->previousContent,
"redacted_because" => $this->redactedBecause,
"transaction_id" => $this->transactionId,
- ], "is_null");
+ ], fn ($value) => ! is_null($value));
}
}
diff --git a/matrix-specification/Message.php b/matrix-specification/Message.php
new file mode 100644
index 0000000..015348a
--- /dev/null
+++ b/matrix-specification/Message.php
@@ -0,0 +1,18 @@
+<?php
+
+namespace Matrix;
+
+abstract class Message implements \JsonSerializable
+{
+ public function setDefaults(): void {}
+
+ /**
+ * @return array<string, string>
+ */
+ abstract public function getBody(): array;
+
+ public function jsonSerialize(): array
+ {
+ return $this->getBody();
+ }
+}
diff --git a/matrix-specification/Request.php b/matrix-specification/Request.php
index c9f315f..c8a13d6 100644
--- a/matrix-specification/Request.php
+++ b/matrix-specification/Request.php
@@ -3,24 +3,13 @@
namespace Matrix;
use Matrix\Enums\ApiPathVersion;
-use Psr\Http\Message\RequestInterface;
-abstract class Request implements RequestInterface, \JsonSerializable
+abstract class Request extends Message
{
- abstract public function getUri(string $serverName, ApiPathVersion $version): string;
+ abstract public function getUri(string $scheme, string $serverName, ApiPathVersion $version): string;
/**
* @return array<string, string>
*/
abstract public function getQueryParameters(): array;
-
- /**
- * @return array<string, string>
- */
- abstract public function getBody(): array;
-
- public function jsonSerialize(): array
- {
- return $this->getBody();
- }
}
diff --git a/matrix-specification/Requests/ClientAccountWhoamiGetRequest.php b/matrix-specification/Requests/ClientAccountWhoamiGetRequest.php
new file mode 100644
index 0000000..50313bb
--- /dev/null
+++ b/matrix-specification/Requests/ClientAccountWhoamiGetRequest.php
@@ -0,0 +1,27 @@
+<?php
+
+namespace Matrix\Requests;
+
+use Matrix\Enums\ApiPathVersion;
+use Matrix\Request;
+
+class ClientAccountWhoamiGetRequest extends Request implements RateLimited, RequiresAuthentication
+{
+ public function __construct()
+ {}
+
+ public function getUri(string $scheme, string $serverName, ApiPathVersion $version): string
+ {
+ return "{$scheme}://{$serverName}/_matrix/client/{$version}/account/whoami";
+ }
+
+ public function getQueryParameters(): array
+ {
+ return [];
+ }
+
+ public function getBody(): array
+ {
+ return [];
+ }
+}
diff --git a/matrix-specification/Requests/ClientDirectoryRoomAliasGetRequest.php b/matrix-specification/Requests/ClientDirectoryRoomAliasGetRequest.php
index 174a5c2..ea104a2 100644
--- a/matrix-specification/Requests/ClientDirectoryRoomAliasGetRequest.php
+++ b/matrix-specification/Requests/ClientDirectoryRoomAliasGetRequest.php
@@ -12,9 +12,9 @@ class ClientDirectoryRoomAliasGetRequest extends Request
)
{}
- public function getUri(string $serverName, ApiPathVersion $version): string
+ public function getUri(string $scheme, string $serverName, ApiPathVersion $version): string
{
- return "https://$serverName/_matrix/client/{$version}/directory/room/{$this->roomAlias}";
+ return "{$scheme}://{$serverName}/_matrix/client/{$version}/directory/room/{$this->roomAlias}";
}
public function getQueryParameters(): array
diff --git a/matrix-specification/Requests/ClientKeysUploadPostRequest.php b/matrix-specification/Requests/ClientKeysUploadPostRequest.php
index 40d9eae..05b2fde 100644
--- a/matrix-specification/Requests/ClientKeysUploadPostRequest.php
+++ b/matrix-specification/Requests/ClientKeysUploadPostRequest.php
@@ -4,8 +4,10 @@ namespace Matrix\Requests;
use Matrix\Data\DeviceKeys;
use Matrix\Data\KeyObject;
+use Matrix\Enums\ApiPathVersion;
+use Matrix\Request;
-class ClientKeysUploadPostRequest implements RateLimited, RequiresAuthentication, \JsonSerializable
+class ClientKeysUploadPostRequest extends Request implements RateLimited, RequiresAuthentication
{
/**
* @param array<string, string|KeyObject> $fallbackKeys
@@ -18,12 +20,22 @@ class ClientKeysUploadPostRequest implements RateLimited, RequiresAuthentication
)
{}
- public function jsonSerialize(): array
+ public function getUri(string $scheme, string $serverName, ApiPathVersion $version): string
+ {
+ return "{$scheme}://{$serverName}/_matrix/client/{$version}/keys/upload";
+ }
+
+ public function getQueryParameters(): array
+ {
+ return [];
+ }
+
+ public function getBody(): array
{
return array_filter([
"device_keys" => $this->deviceKeys,
"fallback_keys" => $this->fallbackKeys,
"one_time_keys" => $this->oneTimeKeys,
- ], "is_null");
+ ], fn ($value) => ! is_null($value));
}
}
diff --git a/matrix-specification/Requests/ClientLoginPostRequest.php b/matrix-specification/Requests/ClientLoginPostRequest.php
index 44497e7..161c6de 100644
--- a/matrix-specification/Requests/ClientLoginPostRequest.php
+++ b/matrix-specification/Requests/ClientLoginPostRequest.php
@@ -3,9 +3,11 @@
namespace Matrix\Requests;
use Matrix\Data\UserIdentifier;
+use Matrix\Enums\ApiPathVersion;
use Matrix\Enums\LoginType;
+use Matrix\Request;
-class ClientLoginPostRequest implements RateLimited, \JsonSerializable
+class ClientLoginPostRequest extends Request implements RateLimited
{
public function __construct(
private LoginType $type,
@@ -26,7 +28,17 @@ class ClientLoginPostRequest implements RateLimited, \JsonSerializable
}
}
- public function jsonSerialize(): array
+ public function getUri(string $scheme, string $serverName, ApiPathVersion $version): string
+ {
+ return "{$scheme}://{$serverName}/_matrix/client/{$version}/login";
+ }
+
+ public function getQueryParameters(): array
+ {
+ return [];
+ }
+
+ public function getBody(): array
{
$request = [
"device_id" => $this->deviceId,
@@ -48,6 +60,6 @@ class ClientLoginPostRequest implements RateLimited, \JsonSerializable
default => [],
};
- return array_filter($request, "is_null");
+ return array_filter($request, fn ($value) => ! is_null($value));
}
}
diff --git a/matrix-specification/Requests/ClientRefreshPostRequest.php b/matrix-specification/Requests/ClientRefreshPostRequest.php
index 733ca75..3733945 100644
--- a/matrix-specification/Requests/ClientRefreshPostRequest.php
+++ b/matrix-specification/Requests/ClientRefreshPostRequest.php
@@ -2,14 +2,27 @@
namespace Matrix\Requests;
-class ClientRefreshPostRequest implements RateLimited, \JsonSerializable
+use Matrix\Enums\ApiPathVersion;
+use Matrix\Request;
+
+class ClientRefreshPostRequest extends Request implements RateLimited
{
public function __construct(
private string $refreshToken,
)
{}
- public function jsonSerialize(): array
+ public function getUri(string $scheme, string $serverName, ApiPathVersion $version): string
+ {
+ return "{$scheme}://{$serverName}/_matrix/client/{$version}/refresh";
+ }
+
+ public function getQueryParameters(): array
+ {
+ return [];
+ }
+
+ public function getBody(): array
{
return [
"refresh_token" => $this->refreshToken,
diff --git a/matrix-specification/Requests/ClientRegisterPostRequest.php b/matrix-specification/Requests/ClientRegisterPostRequest.php
new file mode 100644
index 0000000..74c0c1d
--- /dev/null
+++ b/matrix-specification/Requests/ClientRegisterPostRequest.php
@@ -0,0 +1,57 @@
+<?php
+
+namespace Matrix\Requests;
+
+use Matrix\Data\AuthenticationData;
+use Matrix\Enums\ApiPathVersion;
+use Matrix\Enums\UserRegistrationKind;
+use Matrix\Request;
+
+/**
+ * @see https://spec.matrix.org/v1.16/client-server-api/#post_matrixclientv3register
+ */
+class ClientRegisterPostRequest extends Request implements RateLimited
+{
+ public function __construct(
+ private AuthenticationData $authenticationData,
+ private string $password,
+ private ?UserRegistrationKind $kind = null,
+ private ?string $deviceId = null,
+ private ?bool $inhibitLogin = null,
+ private ?string $initialDeviceDisplayName = null,
+ private ?string $username = null,
+ private ?bool $refreshToken = null,
+ )
+ {}
+
+ public function setDefaults(): void
+ {
+ $this->kind ??= UserRegistrationKind::USER;
+ $this->inhibitLogin ??= false;
+ }
+
+ public function getUri(string $scheme, string $serverName, ApiPathVersion $version): string
+ {
+ return "{$scheme}://{$serverName}/_matrix/client/{$version}/register";
+ }
+
+ public function getQueryParameters(): array
+ {
+ return array_filter([
+ "kind" => $this->kind,
+ ], fn ($value) => ! is_null($value));
+ }
+
+ public function getBody(): array
+ {
+ return array_filter([
+ "auth" => $this->authenticationData,
+ "device_id" => $this->deviceId,
+ "inhibit_login" => $this->inhibitLogin,
+ "initial_device_display_name" => $this->initialDeviceDisplayName,
+ "password" => $this->password,
+ "refresh_token" => $this->refreshToken,
+ "username" => $this->username,
+ ], fn ($value) => ! is_null($value));
+ }
+}
diff --git a/matrix-specification/Requests/ClientSyncGetRequest.php b/matrix-specification/Requests/ClientSyncGetRequest.php
index 2ab7d9e..f19e820 100644
--- a/matrix-specification/Requests/ClientSyncGetRequest.php
+++ b/matrix-specification/Requests/ClientSyncGetRequest.php
@@ -2,9 +2,11 @@
namespace Matrix\Requests;
+use Matrix\Enums\ApiPathVersion;
use Matrix\Enums\PresenceState;
+use Matrix\Request;
-class ClientSyncGetRequest implements RequiresAuthentication
+class ClientSyncGetRequest extends Request implements RequiresAuthentication
{
public function __construct(
private ?string $filter = null,
@@ -24,6 +26,11 @@ class ClientSyncGetRequest implements RequiresAuthentication
$this->useStateAfter ??= false;
}
+ public function getUri(string $scheme, string $serverName, ApiPathVersion $version): string
+ {
+ return "{$scheme}://{$serverName}/_matrix/client/{$version}/sync";
+ }
+
public function getQueryParameters(): array
{
return array_filter([
@@ -33,6 +40,11 @@ class ClientSyncGetRequest implements RequiresAuthentication
"since" => $this->since,
"timeout" => $this->timeout,
"use_state_after" => $this->useStateAfter,
- ], "is_null");
+ ], fn ($value) => ! is_null($value));
+ }
+
+ public function getBody(): array
+ {
+ return [];
}
}
diff --git a/matrix-specification/Requests/ClientUserIdFilterPostRequest.php b/matrix-specification/Requests/ClientUserIdFilterPostRequest.php
index 2edc4c5..cd01532 100644
--- a/matrix-specification/Requests/ClientUserIdFilterPostRequest.php
+++ b/matrix-specification/Requests/ClientUserIdFilterPostRequest.php
@@ -4,9 +4,10 @@ namespace Matrix\Requests;
use Matrix\Data\Filters\EventFilter;
use Matrix\Data\Filters\RoomFilter;
+use Matrix\Enums\ApiPathVersion;
+use Matrix\Request;
- # ClientUserUserIdFilterPostRequest?
-class ClientUserIdFilterPostRequest implements RequiresAuthentication, \JsonSerializable
+class ClientUserIdFilterPostRequest extends Request implements RequiresAuthentication
{
/**
* @param string[] $eventFields
@@ -21,7 +22,17 @@ class ClientUserIdFilterPostRequest implements RequiresAuthentication, \JsonSeri
)
{}
- public function jsonSerialize(): array
+ public function getUri(string $scheme, string $serverName, ApiPathVersion $version): string
+ {
+ return "{$scheme}://{$serverName}/_matrix/client/{$version}/user/{$this->userId}/filter";
+ }
+
+ public function getQueryParameters(): array
+ {
+ return [];
+ }
+
+ public function getBody(): array
{
return [
"account_data" => $this->accountData,
diff --git a/matrix-specification/Requests/RateLimited.php b/matrix-specification/Requests/RateLimited.php
index 9f917a4..a75054f 100644
--- a/matrix-specification/Requests/RateLimited.php
+++ b/matrix-specification/Requests/RateLimited.php
@@ -3,6 +3,4 @@
namespace Matrix\Requests;
interface RateLimited
-{
- # TODO
-}
+{}
diff --git a/matrix-specification/Requests/RequiresAuthentication.php b/matrix-specification/Requests/RequiresAuthentication.php
index a762405..cc4b3e6 100644
--- a/matrix-specification/Requests/RequiresAuthentication.php
+++ b/matrix-specification/Requests/RequiresAuthentication.php
@@ -3,6 +3,4 @@
namespace Matrix\Requests;
interface RequiresAuthentication
-{
- //public function authenticateUser(): bool;
-}
+{}
diff --git a/matrix-specification/Requests/RequiresAuthenticationOptional.php b/matrix-specification/Requests/RequiresAuthenticationOptional.php
new file mode 100644
index 0000000..2ff7980
--- /dev/null
+++ b/matrix-specification/Requests/RequiresAuthenticationOptional.php
@@ -0,0 +1,6 @@
+<?php
+
+namespace Matrix\Requests;
+
+interface RequiresAuthenticationOptional
+{}
diff --git a/matrix-specification/Response.php b/matrix-specification/Response.php
new file mode 100644
index 0000000..d44acb6
--- /dev/null
+++ b/matrix-specification/Response.php
@@ -0,0 +1,8 @@
+<?php
+
+namespace Matrix;
+
+abstract class Response extends Message
+{
+ public function validateRequired(): void {}
+}
diff --git a/matrix-specification/Responses/ClientAccountWhoamiGetResponse.php b/matrix-specification/Responses/ClientAccountWhoamiGetResponse.php
index 48fbbde..2f7ff81 100644
--- a/matrix-specification/Responses/ClientAccountWhoamiGetResponse.php
+++ b/matrix-specification/Responses/ClientAccountWhoamiGetResponse.php
@@ -2,7 +2,9 @@
namespace Matrix\Responses;
-class ClientAccountWhoamiGetResponse implements \JsonSerializable
+use Matrix\Response;
+
+class ClientAccountWhoamiGetResponse extends Response
{
public function __construct(
private string $userId,
@@ -11,12 +13,12 @@ class ClientAccountWhoamiGetResponse implements \JsonSerializable
)
{}
- public function jsonSerialize(): array
+ public function getBody(): array
{
return array_filter([
"device_id" => $this->deviceId,
"is_guest" => $this->isGuest,
"user_id" => $this->userId,
- ], "is_null");
+ ], fn ($value) => ! is_null($value));
}
}
diff --git a/matrix-specification/Responses/ClientDirectoryRoomAliasGetResponse.php b/matrix-specification/Responses/ClientDirectoryRoomAliasGetResponse.php
index a2a6346..4a5977a 100644
--- a/matrix-specification/Responses/ClientDirectoryRoomAliasGetResponse.php
+++ b/matrix-specification/Responses/ClientDirectoryRoomAliasGetResponse.php
@@ -2,7 +2,9 @@
namespace Matrix\Responses;
-class ClientDirectoryRoomAliasGetResponse implements \JsonSerializable
+use Matrix\Response;
+
+class ClientDirectoryRoomAliasGetResponse extends Response
{
/**
* @param string[] $servers
@@ -13,7 +15,7 @@ class ClientDirectoryRoomAliasGetResponse implements \JsonSerializable
)
{}
- public function jsonSerialize(): array
+ public function getBody(): array
{
return [
"room_id" => $this->roomId,
diff --git a/matrix-specification/Responses/ClientKeysUploadPostResponse.php b/matrix-specification/Responses/ClientKeysUploadPostResponse.php
index ff81734..3d335e4 100644
--- a/matrix-specification/Responses/ClientKeysUploadPostResponse.php
+++ b/matrix-specification/Responses/ClientKeysUploadPostResponse.php
@@ -2,7 +2,12 @@
namespace Matrix\Responses;
-class ClientKeysUploadPostResponse implements \JsonSerializable
+use Matrix\Response;
+
+/**
+ * @see https://spec.matrix.org/v1.16/client-server-api/#post_matrixclientv3keysupload
+ */
+class ClientKeysUploadPostResponse extends Response
{
/**
* @param array<string, integer> $oneTimeKeyCounts
@@ -12,7 +17,7 @@ class ClientKeysUploadPostResponse implements \JsonSerializable
)
{}
- public function jsonSerialize(): array
+ public function getBody(): array
{
return [
"one_time_keys_counts" => $this->oneTimeKeyCounts,
diff --git a/matrix-specification/Responses/ClientLoginGetResponse.php b/matrix-specification/Responses/ClientLoginGetResponse.php
index b3b65c3..b8badbd 100644
--- a/matrix-specification/Responses/ClientLoginGetResponse.php
+++ b/matrix-specification/Responses/ClientLoginGetResponse.php
@@ -3,8 +3,9 @@
namespace Matrix\Responses;
use Matrix\Data\LoginFlow;
+use Matrix\Response;
-class ClientLoginGetResponse implements \JsonSerializable
+class ClientLoginGetResponse extends Response
{
/**
* @param LoginFlow[] $loginFlows
@@ -14,7 +15,7 @@ class ClientLoginGetResponse implements \JsonSerializable
)
{}
- public function jsonSerialize(): array
+ public function getBody(): array
{
return [
"flows" => $this->loginFlows,
diff --git a/matrix-specification/Responses/ClientLoginPostResponse.php b/matrix-specification/Responses/ClientLoginPostResponse.php
index 4bb893d..4a0fa7d 100644
--- a/matrix-specification/Responses/ClientLoginPostResponse.php
+++ b/matrix-specification/Responses/ClientLoginPostResponse.php
@@ -3,8 +3,9 @@
namespace Matrix\Responses;
use Matrix\Data\DiscoveryInformation;
+use Matrix\Response;
-class ClientLoginPostResponse implements \JsonSerializable
+class ClientLoginPostResponse extends Response
{
public function __construct(
private string $accessToken,
@@ -16,7 +17,7 @@ class ClientLoginPostResponse implements \JsonSerializable
)
{}
- public function jsonSerialize(): array
+ public function getBody(): array
{
return array_filter([
"access_token" => $this->accessToken,
@@ -25,6 +26,6 @@ class ClientLoginPostResponse implements \JsonSerializable
"refresh_token" => $this->refreshToken,
"user_id" => $this->userId,
"well_known" => $this->wellKnown,
- ], "is_null");
+ ], fn ($value) => ! is_null($value));
}
}
diff --git a/matrix-specification/Responses/ClientRefreshPostResponse.php b/matrix-specification/Responses/ClientRefreshPostResponse.php
index b1e1154..38519a3 100644
--- a/matrix-specification/Responses/ClientRefreshPostResponse.php
+++ b/matrix-specification/Responses/ClientRefreshPostResponse.php
@@ -2,7 +2,9 @@
namespace Matrix\Responses;
-class ClientRefreshPostResponse implements \JsonSerializable
+use Matrix\Response;
+
+class ClientRefreshPostResponse extends Response
{
public function __construct(
private string $accessToken,
@@ -11,12 +13,12 @@ class ClientRefreshPostResponse implements \JsonSerializable
)
{}
- public function jsonSerialize(): array
+ public function getBody(): array
{
return array_filter([
"access_token" => $this->accessToken,
"expires_in_ms" => $this->expiresInMilliseconds,
"refresh_token" => $this->refreshToken,
- ], "is_null");
+ ], fn ($value) => ! is_null($value));
}
}
diff --git a/matrix-specification/Responses/ClientRegisterPostResponse.php b/matrix-specification/Responses/ClientRegisterPostResponse.php
new file mode 100644
index 0000000..6ed65ce
--- /dev/null
+++ b/matrix-specification/Responses/ClientRegisterPostResponse.php
@@ -0,0 +1,39 @@
+<?php
+
+namespace Matrix\Responses;
+
+use Matrix\Requests\ClientRegisterPostRequest;
+use Matrix\Response;
+
+class ClientRegisterPostResponse extends Response
+{
+ public function __construct(
+ private string $userId,
+ private ?string $accessToken = null,
+ private ?string $deviceId = null,
+ private ?int $expiresInMilliseconds = null,
+ private ?string $homeServer = null,
+ private ?string $refreshToken = null,
+ )
+ {}
+
+ public function validateRequired(ClientRegisterPostRequest $request): void
+ {
+ $requestBody = $request->getBody();
+ if ($requestBody["inhibit_login"] === false) {
+ # TODO: validate
+ }
+ }
+
+ public function getBody(): array
+ {
+ return array_filter([
+ "access_token" => $this->accessToken,
+ "device_id" => $this->deviceId,
+ "expires_in_ms" => $this->expiresInMilliseconds,
+ "home_server" => $this->homeServer,
+ "refresh_token" => $this->refreshToken,
+ "user_id" => $this->userId,
+ ], fn ($value) => ! is_null($value));
+ }
+}
diff --git a/matrix-specification/Responses/ClientSyncGetResponse.php b/matrix-specification/Responses/ClientSyncGetResponse.php
index ccdc5e6..dbe2a29 100644
--- a/matrix-specification/Responses/ClientSyncGetResponse.php
+++ b/matrix-specification/Responses/ClientSyncGetResponse.php
@@ -7,8 +7,9 @@ use Matrix\Data\DeviceLists;
use Matrix\Data\Presence;
use Matrix\Data\Room\Rooms;
use Matrix\Data\ToDevice;
+use Matrix\Response;
-class ClientSyncGetResponse implements \JsonSerializable
+class ClientSyncGetResponse extends Response
{
/**
* @param array<string, int> $deviceOneTimeKeysCount
@@ -24,7 +25,7 @@ class ClientSyncGetResponse implements \JsonSerializable
)
{}
- public function jsonSerialize(): array
+ public function getBody(): array
{
return array_filter([
"account_data" => $this->accountData,
@@ -34,6 +35,6 @@ class ClientSyncGetResponse implements \JsonSerializable
"presence" => $this->presence,
"rooms" => $this->rooms,
"to_device" => $this->toDevice,
- ], "is_null");
+ ], fn ($value) => ! is_null($value));
}
}
diff --git a/matrix-specification/Responses/ClientUserIdFilterPostResponse.php b/matrix-specification/Responses/ClientUserIdFilterPostResponse.php
index ed7ba37..0a5d062 100644
--- a/matrix-specification/Responses/ClientUserIdFilterPostResponse.php
+++ b/matrix-specification/Responses/ClientUserIdFilterPostResponse.php
@@ -2,18 +2,23 @@
namespace Matrix\Responses;
-class ClientUserIdFilterPostResponse implements \JsonSerializable
+use Matrix\Response;
+
+class ClientUserIdFilterPostResponse extends Response
{
public function __construct(
private string $filterId,
)
{
if (str_starts_with($filterId, "{")) {
- throw new \InvalidArgumentException("filterId cannot start with a { as this character is used to determine if the filter provided is inline JSON or a previously declared filter by homeservers on some APIs");
+ throw new \InvalidArgumentException(
+ "filterId cannot start with a { as this character is used to determine if the filter provided is inline JSON " .
+ "or a previously declared filter by homeservers on some APIs"
+ );
}
}
- public function jsonSerialize(): array
+ public function getBody(): array
{
return [
"filter_id" => $this->filterId,
diff --git a/matrix-specification/Responses/ClientVersionsGetResponse.php b/matrix-specification/Responses/ClientVersionsGetResponse.php
index 9ec701d..44d2cd0 100644
--- a/matrix-specification/Responses/ClientVersionsGetResponse.php
+++ b/matrix-specification/Responses/ClientVersionsGetResponse.php
@@ -2,7 +2,9 @@
namespace Matrix\Responses;
-class ClientVersionsGetResponse implements \JsonSerializable
+use Matrix\Response;
+
+class ClientVersionsGetResponse extends Response
{
/**
* @param string[] $versions
@@ -14,11 +16,11 @@ class ClientVersionsGetResponse implements \JsonSerializable
)
{}
- public function jsonSerialize(): array
+ public function getBody(): array
{
return array_filter([
"unstable_features" => $this->unstableFeatures,
"versions" => $this->versions,
- ], "is_null");
+ ], fn ($value) => ! is_null($value));
}
}
diff --git a/matrix-specification/Responses/WellKnownMatrixClientGetResponse.php b/matrix-specification/Responses/WellKnownMatrixClientGetResponse.php
index 769268f..2a0c6d1 100644
--- a/matrix-specification/Responses/WellKnownMatrixClientGetResponse.php
+++ b/matrix-specification/Responses/WellKnownMatrixClientGetResponse.php
@@ -3,16 +3,17 @@
namespace Matrix\Responses;
use Matrix\Data\DiscoveryInformation;
+use Matrix\Response;
-class WellKnownMatrixClientGetResponse implements \JsonSerializable
+class WellKnownMatrixClientGetResponse extends Response
{
public function __construct(
private DiscoveryInformation $discoveryInformation,
)
{}
- public function jsonSerialize(): array
+ public function getBody(): array
{
- return $this->discoveryInformation;
+ return $this->discoveryInformation->jsonSerialize();
}
}
diff --git a/matrix-specification/Responses/WellKnownMatrixSupportGetResponse.php b/matrix-specification/Responses/WellKnownMatrixSupportGetResponse.php
index f38e2b0..bdd971a 100644
--- a/matrix-specification/Responses/WellKnownMatrixSupportGetResponse.php
+++ b/matrix-specification/Responses/WellKnownMatrixSupportGetResponse.php
@@ -3,8 +3,9 @@
namespace Matrix\Responses;
use Matrix\Data\Contact;
+use Matrix\Response;
-class WellKnownMatrixSupportGetResponse implements \JsonSerializable
+class WellKnownMatrixSupportGetResponse extends Response
{
/**
* @param Contact[] $contacts
@@ -23,11 +24,11 @@ class WellKnownMatrixSupportGetResponse implements \JsonSerializable
}
}
- public function jsonSerialize(): array
+ public function getBody(): array
{
return array_filter([
"contacts" => $this->contacts,
"support_page" => $this->supportPage,
- ], "is_null");
+ ], fn ($value) => ! is_null($value));
}
}
diff --git a/src/Controllers/AccountController.php b/src/Controllers/AccountController.php
index 858a6b5..8e20880 100755
--- a/src/Controllers/AccountController.php
+++ b/src/Controllers/AccountController.php
@@ -2,9 +2,9 @@
namespace App\Controllers;
-use App\Errors\UnauthorizedError;
use App\Models\Device;
use App\Models\User;
+use Matrix\Responses\ClientAccountWhoamiGetResponse;
use Symfony\Component\HttpFoundation\Request;
use Symfony\Component\HttpFoundation\Response;
use Symfony\Component\HttpFoundation\JsonResponse;
@@ -18,18 +18,12 @@ class AccountController
*/
public function whoami(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);
$device = Device::fetch(userId: $user->getId());
- return new JsonResponse([
- "device_id" => $device->getId(),
- "user_id" => $user->getId(),
- ]);
+ return new JsonResponse(new ClientAccountWhoamiGetResponse(
+ userId: $user->getId(),
+ deviceId: $device->getId(),
+ ));
}
}
diff --git a/src/Controllers/KeyController.php b/src/Controllers/KeyController.php
index a8b4fb1..7777229 100644
--- a/src/Controllers/KeyController.php
+++ b/src/Controllers/KeyController.php
@@ -4,10 +4,11 @@ namespace App\Controllers;
use App\Errors\AppException;
use App\Errors\ErrorCode;
-use App\Errors\UnauthorizedError;
use App\Models\Tokens;
use App\Models\User;
use App\Support\RequestValidator;
+use Matrix\Responses\ClientKeysUploadPostResponse;
+use Matrix\Responses\ClientRefreshPostResponse;
use Symfony\Component\HttpFoundation\Request;
use Symfony\Component\HttpFoundation\Response;
use Symfony\Component\HttpFoundation\JsonResponse;
@@ -29,22 +30,14 @@ class KeyController
*/
public function upload(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);
$body = json_decode($request->getContent(), true);
RequestValidator::validateJson();
- return new JsonResponse([
- "one_time_key_counts" => [
- "curve25519" => 0,
- "signed_curve25519" => count($body["one_time_keys"])
- ],
- ]);
+ return new JsonResponse(new ClientKeysUploadPostResponse([
+ "curve25519" => 0,
+ "signed_curve25519" => count($body["one_time_keys"]),
+ ]));
}
public function query(Request $request): Response
@@ -74,10 +67,10 @@ class KeyController
$newTokens = Tokens::new($tokens->getUserId(), $tokens->getDeviceId());
$newTokens->insert();
- return new JsonResponse([
- "access_token" => $newTokens->getAccessToken(),
- "expires_in" => $newTokens->getExpiresIn(),
- "refresh_token" => $newTokens->getRefreshToken(),
- ]);
+ return new JsonResponse(new ClientRefreshPostResponse(
+ accessToken: $newTokens->getAccessToken(),
+ expiresInMilliseconds: $newTokens->getExpiresIn(),
+ refreshToken: $newTokens->getRefreshToken(),
+ ));
}
}
diff --git a/src/Controllers/LoginController.php b/src/Controllers/LoginController.php
index 15f1583..c520e25 100644
--- a/src/Controllers/LoginController.php
+++ b/src/Controllers/LoginController.php
@@ -10,9 +10,12 @@ use App\Models\Device;
use App\Models\Tokens;
use App\Models\User;
use App\Support\RequestValidator;
-use App\Types\LoginFlow;
-use App\Types\LoginType;
use App\Types\UserRegistrationKind;
+use Matrix\Data\LoginFlow;
+use Matrix\Enums\LoginType;
+use Matrix\Responses\ClientLoginGetResponse;
+use Matrix\Responses\ClientLoginPostResponse;
+use Matrix\Responses\ClientRegisterPostResponse;
use Symfony\Component\HttpFoundation\Request;
use Symfony\Component\HttpFoundation\Response;
use Symfony\Component\HttpFoundation\JsonResponse;
@@ -24,11 +27,9 @@ class LoginController
*/
public function supportedLoginTypes(Request $request): Response
{
- return new JsonResponse([
- "flows" => [
- (new LoginFlow(LoginType::PASSWORD))->toArray(),
- ],
- ]);
+ return new JsonResponse(new ClientLoginGetResponse([
+ (new LoginFlow(LoginType::PASSWORD)),
+ ]));
}
/**
@@ -87,14 +88,13 @@ class LoginController
}
}
- return new JsonResponse([
- "access_token" => $tokens->getAccessToken(),
- "device_id" => $device->getId(),
- "expires_in_ms" => $tokens->getExpiresIn(),
- "refresh_token" => $tokens->getRefreshToken(),
- "user_id" => $user->getId(),
- #"well_known" => [],
- ]);
+ return new JsonResponse(new ClientLoginPostResponse(
+ accessToken: $tokens->getAccessToken(),
+ deviceId:$device->getId(),
+ userId: $user->getId(),
+ expiresInMilliseconds: $tokens->getExpiresIn(),
+ refreshToken: $tokens->getRefreshToken(),
+ ));
}
/**
@@ -130,12 +130,12 @@ class LoginController
$tokens = Tokens::new($userId, $device->getId());
$tokens->insert();
- return new JsonResponse([
- "access_token" => $tokens->getAccessToken(),
- "device_id" => $device->getId(),
- "expires_in_ms" => $tokens->getExpiresIn(),
- "refresh_token" => $tokens->getRefreshToken(),
- "user_id" => $userId,
- ]);
+ return new JsonResponse(new ClientRegisterPostResponse(
+ accessToken: $tokens->getAccessToken(),
+ deviceId: $device->getId(),
+ expiresInMilliseconds: $tokens->getExpiresIn(),
+ refreshToken: $tokens->getRefreshToken(),
+ userId: $userId,
+ ));
}
}
diff --git a/src/Models/User.php b/src/Models/User.php
index 423394a..c0c73f8 100644
--- a/src/Models/User.php
+++ b/src/Models/User.php
@@ -3,7 +3,9 @@
namespace App\Models;
use App\Database;
+use App\Errors\UnauthorizedError;
use App\Support\ConnectsToDatabase;
+use Symfony\Component\HttpFoundation\Request;
class User implements ConnectsToDatabase
{
@@ -50,7 +52,7 @@ class User implements ConnectsToDatabase
return self::fromDatabase($row);
}
- public static function fetchWithAccessToken(string $accessToken): ?static
+ public static function fetchWithAccessToken(string $accessToken): ?self
{
$row = Database::getInstance()->query(<<<SQL
select users.* from users left join tokens on tokens.user_id = users.id where tokens.access_token=:access_token
@@ -70,6 +72,18 @@ class User implements ConnectsToDatabase
return new self($id);
}
+ public static function authenticateWithRequest(Request $request): self
+ {
+ $accessToken = str_replace("Bearer ", "", $request->headers->get("authorization") ?: "");
+ $user = self::fetchWithAccessToken($accessToken);
+
+ if (empty($user)) {
+ throw new UnauthorizedError();
+ }
+
+ return $user;
+ }
+
public function insert(): bool
{
return !! Database::getInstance()->query(