summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorDaniel Weipert <git@mail.dweipert.de>2025-09-12 13:07:20 +0200
committerDaniel Weipert <git@mail.dweipert.de>2025-09-12 13:07:20 +0200
commita20d44d64f02f86d23cba1f1a886352c5f744a1a (patch)
tree98ab2ddf1c27ffe5e56af763750c19b45867cbab
parentb1b101fd98c8b4354a4e0c73e867d817466de30e (diff)
sending messages results in client acknowledging successHEADmain
-rw-r--r--Readme.md3
-rwxr-xr-xsrc/Controllers/AccountController.php35
-rw-r--r--src/Controllers/KeyController.php4
-rwxr-xr-xsrc/Controllers/RoomController.php34
-rwxr-xr-xsrc/Controllers/SyncController.php71
-rw-r--r--src/Models/User.php15
-rw-r--r--src/Router/routes_client_server.php11
-rw-r--r--src/Types/EventType.php1
-rw-r--r--src/Types/MessageType.php8
9 files changed, 167 insertions, 15 deletions
diff --git a/Readme.md b/Readme.md
index 9064374..243eacb 100644
--- a/Readme.md
+++ b/Readme.md
@@ -1 +1,4 @@
Matrix Specification: https://spec.matrix.org/v1.15/
+
+
+# TODO: check if access_token is expired BEFORE using it to fetch the user
diff --git a/src/Controllers/AccountController.php b/src/Controllers/AccountController.php
new file mode 100755
index 0000000..858a6b5
--- /dev/null
+++ b/src/Controllers/AccountController.php
@@ -0,0 +1,35 @@
+<?php
+
+namespace App\Controllers;
+
+use App\Errors\UnauthorizedError;
+use App\Models\Device;
+use App\Models\User;
+use Symfony\Component\HttpFoundation\Request;
+use Symfony\Component\HttpFoundation\Response;
+use Symfony\Component\HttpFoundation\JsonResponse;
+
+class AccountController
+{
+ /**
+ * GET /_matrix/client/v3/account/whoami
+ *
+ * @see https://spec.matrix.org/v1.15/client-server-api/#get_matrixclientv3accountwhoami
+ */
+ public function whoami(Request $request): Response
+ {
+ $accessToken = str_replace("Bearer ", "", $request->headers->get("authorization") ?: "");
+ $user = User::fetchWithAccessToken($accessToken);
+
+ if (empty($user)) {
+ throw new UnauthorizedError();
+ }
+
+ $device = Device::fetch(userId: $user->getId());
+
+ return new JsonResponse([
+ "device_id" => $device->getId(),
+ "user_id" => $user->getId(),
+ ]);
+ }
+}
diff --git a/src/Controllers/KeyController.php b/src/Controllers/KeyController.php
index 53e9ff4..b2a17a6 100644
--- a/src/Controllers/KeyController.php
+++ b/src/Controllers/KeyController.php
@@ -31,7 +31,9 @@ class KeyController
RequestValidator::validateJson();
return new JsonResponse([
- "one_time_key_counts" => count($body["one_time_keys"]),
+ "one_time_key_counts" => [
+ "signed_curve25519" => count($body["one_time_keys"])
+ ],
]);
}
diff --git a/src/Controllers/RoomController.php b/src/Controllers/RoomController.php
index 1067d29..367d754 100755
--- a/src/Controllers/RoomController.php
+++ b/src/Controllers/RoomController.php
@@ -5,7 +5,12 @@ namespace App\Controllers;
use App\Database;
use App\Errors\AppException;
use App\Errors\ErrorCode;
+use App\Errors\UnauthorizedError;
+use App\Models\User;
use App\Support\Parser;
+use App\Support\RequestValidator;
+use App\Types\EventType;
+use App\Types\MessageType;
use Symfony\Component\HttpFoundation\Request;
use Symfony\Component\HttpFoundation\Response;
use Symfony\Component\HttpFoundation\JsonResponse;
@@ -51,4 +56,33 @@ class RoomController
"servers" => [],
]);
}
+
+ /**
+ * PUT /_matrix/client/v3/rooms/{roomId}/send/{eventType}/{txnId}
+ *
+ * @see https://spec.matrix.org/v1.15/client-server-api/#put_matrixclientv3roomsroomidsendeventtypetxnid
+ */
+ public function send(Request $request): Response
+ {
+ $accessToken = str_replace("Bearer ", "", $request->headers->get("authorization") ?: "");
+ $user = User::fetchWithAccessToken($accessToken);
+
+ if (empty($user)) {
+ throw new UnauthorizedError();
+ }
+
+ $roomId = $request->attributes->get("roomId");
+ $eventType = EventType::from($request->attributes->get("eventType"));
+ $transactionId = $request->attributes->get("txnId");
+
+ $body = json_decode($request->getContent(), true);
+ RequestValidator::validateJson();
+
+ $message = $body["body"];
+ $messageType = MessageType::from($body["msgtype"]);
+
+ return new JsonResponse([
+ "event_id" => "\$asdfghjkl:" . $_ENV["DOMAIN"],
+ ]);
+ }
}
diff --git a/src/Controllers/SyncController.php b/src/Controllers/SyncController.php
index 76b6a26..b7d51c3 100755
--- a/src/Controllers/SyncController.php
+++ b/src/Controllers/SyncController.php
@@ -5,6 +5,7 @@ namespace App\Controllers;
use App\Database;
use App\Errors\UnauthorizedError;
use App\Events\PresenceEvent;
+use App\Models\User;
use App\Types\PresenceState;
use Symfony\Component\HttpFoundation\Request;
use Symfony\Component\HttpFoundation\Response;
@@ -21,13 +22,7 @@ class SyncController
public function sync(Request $request): Response
{
$accessToken = str_replace("Bearer ", "", $request->headers->get("authorization") ?: "");
- $user = Database::getInstance()->query(<<<SQL
- select users.* from users left join tokens on tokens.user_id = users.id where tokens.access_token=:access_token
- SQL, [
- "access_token" => $accessToken,
- ])->fetch();
-
- # TODO: token validation
+ $user = User::fetchWithAccessToken($accessToken);
if (empty($user)) {
throw new UnauthorizedError();
@@ -39,6 +34,49 @@ class SyncController
$since = $request->query->get("since", "");
$timeout = $request->query->get("timeout", 0);
+ $rooms = Database::getInstance()->query(<<<SQL
+ select * from rooms
+ SQL)->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" => [],
+ "limited" => false,
+ "prev_batch" => "",
+ ],
+
+ "unread_notifications" => [
+ "highlight_count" => 1,
+ "notification_count" => 2,
+ ],
+
+ "unread_thread_notifications" => new \stdClass(),
+ ];
+ }
+ }
+
return new JsonResponse([
"account_data" => [
"events" => [
@@ -46,23 +84,28 @@ class SyncController
],
],
- "device_lists" => [],
+ "device_lists" => [
+ "changed" => [],
+ "left" => [],
+ ],
- "device_one_time_keys_count" => 10,
+ "device_one_time_keys_count" => [
+ "signed_curve25519" => 10,
+ ],
"next_batch" => "next_batch_id",
"presence" => [
"events" => [
- (new PresenceEvent(sender: $user["id"]))->toJsonEncodeable(),
+ (new PresenceEvent(sender: $user->getId()))->toJsonEncodeable(),
],
],
"rooms" => [
- "invite" => [],
- "join" => [],
- "knock" => [],
- "leave" => [],
+ "invite" => new \stdClass(),
+ "join" => $joinedRooms,
+ "knock" => new \stdClass(),
+ "leave" => new \stdClass(),
],
"to_device" => [
diff --git a/src/Models/User.php b/src/Models/User.php
index 354c466..423394a 100644
--- a/src/Models/User.php
+++ b/src/Models/User.php
@@ -50,6 +50,21 @@ class User implements ConnectsToDatabase
return self::fromDatabase($row);
}
+ public static function fetchWithAccessToken(string $accessToken): ?static
+ {
+ $row = Database::getInstance()->query(<<<SQL
+ select users.* from users left join tokens on tokens.user_id = users.id where tokens.access_token=:access_token
+ SQL, [
+ "access_token" => $accessToken,
+ ])->fetch();
+
+ if (empty($row)) {
+ return null;
+ }
+
+ return self::fromDatabase($row);
+ }
+
public static function new(string $id): self
{
return new self($id);
diff --git a/src/Router/routes_client_server.php b/src/Router/routes_client_server.php
index 6e7bb8d..7543892 100644
--- a/src/Router/routes_client_server.php
+++ b/src/Router/routes_client_server.php
@@ -2,6 +2,7 @@
namespace App\Router;
+use App\Controllers\AccountController;
use App\Controllers\KeyController;
use App\Controllers\LoginController;
use App\Controllers\RoomController;
@@ -57,4 +58,14 @@ return function (RouteConfigurator $routes): void
->add("matrix_client_v3_directory_room_alias_get", "/_matrix/client/v3/directory/room/{roomAlias}")
->controller([RoomController::class, "resolveAlias"])
->methods(["GET"]);
+
+ $routes
+ ->add("matrix_client_v3_account_whoami", "/_matrix/client/v3/account/whoami")
+ ->controller([AccountController::class, "whoami"])
+ ->methods(["GET"]);
+
+ $routes
+ ->add("matrix_client_v3_rooms_id_send_event_transaction", "/_matrix/client/v3/rooms/{roomId}/send/{eventType}/{txnId}")
+ ->controller([RoomController::class, "send"])
+ ->methods(["PUT"]);
};
diff --git a/src/Types/EventType.php b/src/Types/EventType.php
index a79debc..d599c6f 100644
--- a/src/Types/EventType.php
+++ b/src/Types/EventType.php
@@ -7,4 +7,5 @@ enum EventType: string
case PRESENCE = "m.presence";
case ROOM_NAME = "m.room.name";
case ROOM_MEMBER = "m.room.member";
+ case ROOM_MESSAGE = "m.room.message";
}
diff --git a/src/Types/MessageType.php b/src/Types/MessageType.php
new file mode 100644
index 0000000..ded17a0
--- /dev/null
+++ b/src/Types/MessageType.php
@@ -0,0 +1,8 @@
+<?php
+
+namespace App\Types;
+
+enum MessageType: string
+{
+ case TEXT = "m.text";
+}