diff options
Diffstat (limited to 'src/Controllers/Client/ClientController.php')
| -rw-r--r-- | src/Controllers/Client/ClientController.php | 392 |
1 files changed, 369 insertions, 23 deletions
diff --git a/src/Controllers/Client/ClientController.php b/src/Controllers/Client/ClientController.php index c9eb1fa..28aea66 100644 --- a/src/Controllers/Client/ClientController.php +++ b/src/Controllers/Client/ClientController.php @@ -2,6 +2,7 @@ namespace App\Controllers\Client; +use App\App; use App\Database; use App\Errors\AppException; use App\Errors\ErrorResponse; @@ -16,6 +17,8 @@ use App\Support\Logger; use App\Support\Parser; use App\Support\RequestValidator; use Matrix\Data\AccountData; +use Matrix\Data\Capabilities; +use Matrix\Data\Capability\RoomVersionsCapability; use Matrix\Data\DeviceLists; use Matrix\Data\LoginFlow; use Matrix\Data\Presence; @@ -30,6 +33,7 @@ use Matrix\Data\Room\Timeline; use Matrix\Data\Room\UnreadNotificationCounts; use Matrix\Data\Ruleset; use Matrix\Data\ToDevice; +use Matrix\Data\UserId; use Matrix\Enums\AuthenticationType; use Matrix\Enums\ErrorCode; use Matrix\Enums\LoginType; @@ -126,7 +130,7 @@ class ClientController return new JsonResponse(new ClientLoginPostResponse( accessToken: $tokens->getAccessToken(), - deviceId:$device->getId(), + deviceId: $device->getId(), userId: $user->getId(), expiresInMilliseconds: $tokens->getExpiresIn(), refreshToken: $tokens->getRefreshToken(), @@ -208,7 +212,7 @@ class ClientController #[Route(path: "_matrix/client/r0/sync", methods: ["GET"])] #[Route(path: "_matrix/client/v3/sync", methods: ["GET"])] public function sync(Request $request): Response - { + { $user = User::authenticateWithRequest($request); $filter = $request->query->get("filter", ""); @@ -216,7 +220,7 @@ class ClientController $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); + $useStateAfter = $request->query->get("use_state_after", false) ?: $request->query->get("org.matrix.msc4222.use_state_after", false); if (! empty($filter)) { if (str_starts_with($filter, "{")) { @@ -226,6 +230,18 @@ class ClientController } } + // device one time keys count + $deviceOneTimeKeysCount = Database::getInstance() + ->query("select count(*) from one_time_keys where user_id=:user_id and device_id=:device_id", [ + "user_id" => $user->getId(), + "device_id" => $user->getDeviceId(), + ]) + ->fetchColumn(); + $deviceOneTimeKeysCount = [ + "signed_curve25519" => $deviceOneTimeKeysCount, + ]; + + // rooms $rooms = Database::getInstance()->query(<<<SQL select * from rooms left join room_memberships @@ -240,20 +256,24 @@ class ClientController $knockedRooms = []; $leftRooms = []; + $nextBatch = (new \DateTime())->format("U"); + foreach ($rooms as $room) { $events = Database::getInstance()->query(<<<SQL select * from room_events where room_id = :room_id + and origin_server_timestamp > to_timestamp(:since) SQL, [ "room_id" => $room["room_id"], #"limit" => ($filter["room"]["timeline"]["limit"] ?? false) ? "limit " . $filter["room"]["timeline"]["limit"] : "", + "since" => (empty($since) ? \DateTime::createFromTimestamp(0) : \DateTime::createFromTimestamp($since))->format("U"), ])->fetchAll(); - if ($since === "" && MembershipState::tryFrom($room["state"]) === MembershipState::JOIN) { + if (! empty($events) && MembershipState::tryFrom($room["state"]) === MembershipState::JOIN) { $joinedRooms[$room["room_id"]] = new JoinedRoom( accountData: new AccountData([]), ephemeral: new Ephemeral([]), - state: new State([]), + state: new State(array_map([RoomEvent::class, "transformEvent"], $events)), summary: new RoomSummary( heroes: [], invitedMemberCount: 0, @@ -268,18 +288,25 @@ class ClientController unreadThreadNotifications: [], ); } + + if (! empty($events)) { + $newestEvent = RoomEvent::transformEvent($events[array_key_last($events)]); + $nextBatch = \DateTime::createFromTimestamp($newestEvent->getOriginServerTimestamp())->format("U"); + } + } + + if (($timeout / 1000) > App::getExectionTime()) { + sleep(intval(($timeout / 1000) - App::getExectionTime())); } return new JsonResponse(new ClientSyncGetResponse( - nextBatch: "1", + nextBatch: $nextBatch, accountData: new AccountData([]), deviceLists: new DeviceLists([], []), - deviceOneTimeKeysCount: [ - "signed_curve25519" => 10, - ], + deviceOneTimeKeysCount: $deviceOneTimeKeysCount, presence: new Presence([ new PresenceEvent( @@ -331,10 +358,130 @@ class ClientController { $user = User::authenticateWithRequest($request); + $notificationActionBase = [ + "notify", + ]; + $notificationActionSound = $notificationActionBase + [ + [ + "set_tweak" => "sound", + "value" => "default", + ], + ]; + $notificationActionHighlight = $notificationActionBase + [ + [ + "set_tweak" => "highlight", + ], + ]; + $notifactionActionSoundHighlight = $notificationActionSound + [ + [ + "set_tweak" => "highlight", + ], + ]; + + // @see https://spec.matrix.org/v1.16/client-server-api/#predefined-rules return new JsonResponse([ "global" => new Ruleset( content: [ new PushRule( + ruleId: ".m.rule.contains_user_name", + default: true, + enabled: false, + pattern: Parser::parseUser($user->getId())["username"], + actions: [ + ...$notifactionActionSoundHighlight, + ], + ), + ], + + override: [ + new PushRule( + ruleId: ".m.rule.master", + default: true, + enabled: false, + conditions: [], + actions: [], + ), + + new PushRule( + ruleId: ".m.rule.suppress_notices", + default: true, + enabled: true, + conditions: [ + new PushCondition( + kind: PushConditionKind::EVENT_MATCH, + key: "content.msgtype", + pattern: "m.notice", + ), + ], + actions: [], + ), + + new PushRule( + ruleId: ".m.rule.invite_for_me", + default: true, + enabled: true, + conditions: [ + new PushCondition( + kind: PushConditionKind::EVENT_MATCH, + key: "type", + pattern: "m.room.member", + ), + new PushCondition( + kind: PushConditionKind::EVENT_MATCH, + key: "content.membership", + pattern: "invite", + ), + new PushCondition( + kind: PushConditionKind::EVENT_MATCH, + key: "state_key", + pattern: $user->getId(), + ), + ], + actions: [ + ...$notificationActionSound, + ], + ), + + + new PushRule( + ruleId: ".m.rule.member_event", + default: true, + enabled: true, + conditions: [ + new PushCondition( + kind: PushConditionKind::EVENT_MATCH, + key: "type", + pattern: "m.room.member", + ), + ], + actions: [], + ), + + new PushRule( + ruleId: ".m.rule.is_user_mention", + default: true, + enabled: true, + conditions: [ + new PushCondition( + kind: PushConditionKind::EVENT_PROPERTY_CONTAINS, + key: "content.m\\.mentions.user_ids", + value: $user->getId(), + ), + ], + actions: [ + ...$notifactionActionSoundHighlight, + ], + ), + + new PushRule( + ruleId: ".m.rule.contains_display_name", + default: true, + enabled: false, + conditions: [ + new PushCondition( + kind: PushConditionKind::CONTAINS_DISPLAY_NAME, + ), + ], actions: [ "notify", [ @@ -345,20 +492,117 @@ class ClientController "set_tweak" => "highlight", ], ], + ), + + new PushRule( + ruleId: ".m.rule.is_room_mention", default: true, enabled: true, - pattern: "alice", - ruleId: ".m.rule.contains_user_name", + conditions: [ + new PushCondition( + kind: PushConditionKind::EVENT_PROPERTY_IS, + key: "content.m\\.mentions.room", + value: true, + ), + new PushCondition( + kind: PushConditionKind::SENDER_NOTIFICATION_PERMISSION, + key: "room", + ), + ], + actions: [ + ...$notificationActionHighlight, + ], + ), + + new PushRule( + ruleId: ".m.rule.roomnotif", + default: true, + enabled: false, + conditions: [ + new PushCondition( + kind: PushConditionKind::EVENT_MATCH, + key: "content.body", + pattern: "@room", + ), + new PushCondition( + kind: PushConditionKind::SENDER_NOTIFICATION_PERMISSION, + key: "room", + ), + ], + actions: [ + "notify", + [ + "set_tweak" => "highlight", + ], + ], + ), + + new PushRule( + ruleId: ".m.rule.tombstone", + default: true, + enabled: true, + conditions: [ + new PushCondition( + kind: PushConditionKind::EVENT_MATCH, + key: "type", + pattern: "m.room.tombstone", + ), + new PushCondition( + kind: PushConditionKind::EVENT_MATCH, + key: "state_key", + pattern: "", + ), + ], + actions: [ + ...$notificationActionHighlight, + ], ), - ], - override: [ new PushRule( + ruleId: ".m.rule.reaction", + default: true, + enabled: true, + conditions: [ + new PushCondition( + kind: PushConditionKind::EVENT_MATCH, + key: "type", + pattern: "m.reaction", + ), + ], actions: [], - conditions: [], + ), + + new PushRule( + ruleId: ".m.rule.room.server_acl", default: true, - enabled: false, - ruleId: ".m.rule.master", + enabled: true, + conditions: [ + new PushCondition( + kind: PushConditionKind::EVENT_MATCH, + key: "type", + pattern: "m.room.server_acl", + ), + new PushCondition( + kind: PushConditionKind::EVENT_MATCH, + key: "state_key", + pattern: "", + ), + ], + actions: [], + ), + + new PushRule( + ruleId: ".m.rule.suppress_edits", + default: true, + enabled: true, + conditions: [ + new PushCondition( + kind: PushConditionKind::EVENT_PROPERTY_IS, + key: "content.m\\.relates_to.rel_type", + value: "m.replace", + ), + ], + actions: [], ), ], @@ -367,30 +611,132 @@ class ClientController underride: [ new PushRule( + ruleId: ".m.rule.call", + default: true, + enabled: true, + conditions: [ + new PushCondition( + kind: PushConditionKind::EVENT_MATCH, + key: "type", + pattern: "m.call.invite", + ) + ], actions: [ "notify", [ "set_tweak" => "sound", "value" => "ring", ], - [ - "set_tweak" => "highlight", - "value" => false, - ], ], + ), + + new PushRule( + ruleId: ".m.rule.encrypted_room_one_to_one", + default: true, + enabled: true, conditions: [ new PushCondition( + kind: PushConditionKind::ROOM_MEMBER_COUNT, + is: "2", + ), + new PushCondition( kind: PushConditionKind::EVENT_MATCH, key: "type", - pattern: "m.call.invite", - ) + pattern: "m.room.encrypted", + ), ], + actions: [ + ...$notificationActionSound, + ], + ), + + new PushRule( + ruleId: ".m.rule.room_one_to_one", default: true, enabled: true, - ruleId: ".m.rule.master", + conditions: [ + new PushCondition( + kind: PushConditionKind::ROOM_MEMBER_COUNT, + is: "2", + ), + new PushCondition( + kind: PushConditionKind::EVENT_MATCH, + key: "type", + pattern: "m.room.message", + ), + ], + actions: [ + ...$notificationActionSound, + ], + ), + + new PushRule( + ruleId: ".m.rule.message", + default: true, + enabled: true, + conditions: [ + new PushCondition( + kind: PushConditionKind::EVENT_MATCH, + key: "type", + pattern: "m.room.message", + ), + ], + actions: [ + "notify", + ], + ), + + new PushRule( + ruleId: ".m.rule.encrypted", + default: true, + enabled: true, + conditions: [ + new PushCondition( + kind: PushConditionKind::EVENT_MATCH, + key: "type", + pattern: "m.room.encrypted", + ), + ], + actions: [ + "notify", + ], ), ], ), ]); } + + #[Route(path: "/_matrix/client/v3/capabilities", methods: ["GET"])] + public function capabilities(Request $request): Response + { + $user = User::authenticateWithRequest($request); + + return new JsonResponse(new Capabilities( + roomVersions: new RoomVersionsCapability( + available: ["1" => "stable"], + default: "1", + ), + )); + } + + #[Route(path: "/_matrix/client/v3/voip/turnServer", methods: ["GET"])] + public function voipTurnServer(Request $request): Response + { + $user = User::authenticateWithRequest($request); + + return new JsonResponse([ + "password" => "", + "ttl" => 86400, + "uris" => [], + "username" => "", + ]); + } + + #[Route(path: "/_matrix/client/v3/thirdparty/protocols", methods: ["GET"])] + public function thirdPartyProtocols(Request $request): Response + { + $user = User::authenticateWithRequest($request); + + return new JsonResponse(new \stdClass()); + } } |
