diff options
Diffstat (limited to 'src/Models')
| -rw-r--r-- | src/Models/RoomEvent.php | 74 | ||||
| -rw-r--r-- | src/Models/Tokens.php | 29 | ||||
| -rw-r--r-- | src/Models/User.php | 67 |
3 files changed, 160 insertions, 10 deletions
diff --git a/src/Models/RoomEvent.php b/src/Models/RoomEvent.php new file mode 100644 index 0000000..11d74b0 --- /dev/null +++ b/src/Models/RoomEvent.php @@ -0,0 +1,74 @@ +<?php + +namespace App\Models; + +use App\Database; +use Matrix\Data\UnsignedData; +use Matrix\Enums\EventType; +use Matrix\Events\ClientEvent; +use Matrix\Events\StateEvent; + +class RoomEvent +{ + public function __construct( + private ClientEvent $event, + ) + {} + + /** + * @param array<string, mixed> $row + */ + public static function transformEvent(array $row): ClientEvent + { + $rowUnsigned = json_decode($row["unsigned"], true); + $unsigned = new UnsignedData( + age: $row["age"] ?? ((time() - new \DateTime($row["origin_server_timestamp"])->getTimestamp()) * 1000), + membership: $row["membership"] ?? null, + previousContent: $row["previous_content"] ?? null, + redactedBecause: $row["redacted_because"] ?? null, + transactionId: $row["transaction_id"] ?? null, + ); + + 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: $unsigned, + ); + } + + public function insert(): bool + { + if ($this->event instanceof StateEvent) { + return !! Database::getInstance()->query(<<<SQL + insert into room_events (id, content, type, sender, origin_server_timestamp, room_id, unsigned, state_key) + values (:id, :content, :type, :sender, to_timestamp(:origin_server_timestamp), :room_id, :unsigned, :state_key) + SQL, [ + "id" => $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(<<<SQL + insert into room_events (id, content, type, sender, origin_server_timestamp, room_id, unsigned) + values (:id, :content, :type, :sender, to_timestamp(:origin_server_timestamp), :room_id, :unsigned) + SQL, [ + "id" => $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( + <<<SQL + select * from tokens + where access_token=:access_token + order by created_at desc + SQL, + [ + "access_token" => $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..a30bee0 100644 --- a/src/Models/User.php +++ b/src/Models/User.php @@ -3,19 +3,28 @@ namespace App\Models; use App\Database; +use App\Errors\AppException; use App\Errors\UnauthorizedError; use App\Support\ConnectsToDatabase; +use Matrix\Enums\ErrorCode; use Symfony\Component\HttpFoundation\Request; +use Symfony\Component\HttpFoundation\Response; class User implements ConnectsToDatabase { - public function __construct(private string $id) + private string $deviceId; + + public function __construct( + private string $id, + private string $name, + ) {} public static function fromDatabase(array $row): self { return new self( $row["id"], + $row["name"], ); } @@ -55,7 +64,7 @@ class User implements ConnectsToDatabase 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 + select users.*, tokens.device_id from users left join tokens on tokens.user_id = users.id where tokens.access_token=:access_token SQL, [ "access_token" => $accessToken, ])->fetch(); @@ -64,23 +73,42 @@ class User implements ConnectsToDatabase return null; } - return self::fromDatabase($row); + $user = self::fromDatabase($row); + $user->setDeviceId($row["device_id"]); + + return $user; } - 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 { $accessToken = str_replace("Bearer ", "", $request->headers->get("authorization") ?: ""); + + if (empty($accessToken)) { + throw new AppException(ErrorCode::UNAUTHORIZED, "Missing access token", Response::HTTP_UNAUTHORIZED); + } + $user = self::fetchWithAccessToken($accessToken); if (empty($user)) { 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 +116,12 @@ class User implements ConnectsToDatabase { return !! Database::getInstance()->query( <<<SQL - insert into users (id) - values (:id) + insert into users (id, name) + values (:id, :name) SQL, [ "id" => $this->id, + "name" => $this->name, ] ); } @@ -108,10 +137,32 @@ class User implements ConnectsToDatabase return $this->id; } + public function getName(): string + { + return $this->name; + } + + public function setDeviceId(string $id): void + { + $this->deviceId = $id; + } + + public function getDeviceId(): string + { + return $this->deviceId; + } + public function fetchDevice(string $id): ?Device { - return Device::fetch($id, $this->id); + $device = Device::fetch($id, $this->id); + + if ($device) { + $this->setDeviceId($device->getId()); + } + + return $device; } + /** * @return Device[] */ |
