From 0040a86fee4d228bef00381174b16b0779df4764 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Julius=20H=C3=A4rtl?= Date: Thu, 13 Jun 2024 07:38:21 +0200 Subject: [PATCH] fix: Ignore pushes of update steps for read only sessions MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Signed-off-by: Julius Härtl --- lib/Service/DocumentService.php | 6 +++++- lib/YjsMessage.php | 13 +++++++++++++ 2 files changed, 18 insertions(+), 1 deletion(-) diff --git a/lib/Service/DocumentService.php b/lib/Service/DocumentService.php index 38e6c4f2cba..f4e23325f3a 100644 --- a/lib/Service/DocumentService.php +++ b/lib/Service/DocumentService.php @@ -220,11 +220,15 @@ public function writeDocumentState(int $documentId, string $content): void { */ public function addStep(Document $document, Session $session, array $steps, int $version, ?string $shareToken): array { $documentId = $session->getDocumentId(); + $readOnly = $this->isReadOnly($this->getFileForSession($session, $shareToken), $shareToken); $stepsToInsert = []; $querySteps = []; $newVersion = $version; foreach ($steps as $step) { $message = YjsMessage::fromBase64($step); + if ($readOnly && $message->isUpdate()) { + continue; + } // Filter out query steps as they would just trigger clients to send their steps again if ($message->getYjsMessageType() === YjsMessage::YJS_MESSAGE_SYNC && $message->getYjsSyncType() === YjsMessage::YJS_MESSAGE_SYNC_STEP1) { $querySteps[] = $step; @@ -233,7 +237,7 @@ public function addStep(Document $document, Session $session, array $steps, int } } if (count($stepsToInsert) > 0) { - if ($this->isReadOnly($this->getFileForSession($session, $shareToken), $shareToken)) { + if ($readOnly) { throw new NotPermittedException('Read-only client tries to push steps with changes'); } $newVersion = $this->insertSteps($document, $session, $stepsToInsert); diff --git a/lib/YjsMessage.php b/lib/YjsMessage.php index 913d9e91f0a..54752270966 100644 --- a/lib/YjsMessage.php +++ b/lib/YjsMessage.php @@ -82,4 +82,17 @@ public function getYjsSyncType(): int { return $syncType; } + /** + * Based on https://github.com/yjs/y-protocols/blob/master/PROTOCOL.md#handling-read-only-users + */ + public function isUpdate(): bool { + if ($this->getYjsMessageType() === self::YJS_MESSAGE_SYNC) { + if (in_array($this->getYjsSyncType(), [self::YJS_MESSAGE_SYNC_STEP2, self::YJS_MESSAGE_SYNC_UPDATE])) { + return true; + } + } + + return false; + } + }