summaryrefslogtreecommitdiff
path: root/src/Controllers/Client/ClientController.php
diff options
context:
space:
mode:
Diffstat (limited to 'src/Controllers/Client/ClientController.php')
-rw-r--r--src/Controllers/Client/ClientController.php392
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());
+ }
}