diff --git a/lib/Service/DocumentService.php b/lib/Service/DocumentService.php index f8532b34cf7..18665591a77 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; + } + }