"read-only" or one-way only sync

Is there a way to signal to a Y.Doc that it should not accept any incoming state sync directives? I’m particularly interested in this over y-websocket. For certain relms (like the Welcome relm) we want it to be a non-collaborative space until people earn the privilege of modifying the world (i.e. they must gain trust first).

Ideally on the server side we would be able to tell certain Y.Docs to just not accept incoming state sync updates.

1 Like

Hi @canadaduane,

unfortunately we don’t have that feature yet. This also needs to be enforced by the server. Although, I agree, it would be nice to have that information directly in Y.Doc too - as a common API.

Hi @dmonad, is ignoring messages of the format [YjsSyncStep1][YjsUpdate][data] in a client-server setup, like y-websocket, enough to achieve a “read-only” state, or are there other considerations that need to be made?

Sorry for the grave-dig, but it looked like a relevant enough topic :sweat_smile:

That’s fine. Happy you looked for a solution first :slight_smile:

If you want to achieve read-only abilities in y-websockets, you only need to ignore “SyncStep2” and “update” messages. These messages are part of the sync protocol, so you want to disable messages that start with either [0, 1, ..] or [0, 2, ..] (this would be a blacklist approach).

You explicitly want to allow “SyncStep1” because it is a request to the server that asks if there is any new content. So [0, 0] should be allowed.

The first 0 identifies the message as a message from the “sync” protocol. See https://github.com/yjs/y-websocket/blob/master/src/y-websocket.js#L24

The second number is used to identify what kind of sync-message it is. See https://github.com/yjs/y-protocols/blob/master/sync.js#L38

  • [0, 0] is a SyncStep1. It is request to receive the missing state (it contains a state-vector that the server uses to compute the missing updates)
  • [0, 1] is SyncStep2, which is the reply to a SyncStep1. It contains the missing updates. You want to ignore this message as it contains document updates.
  • [0, 2] is a regular document update message.
  • [1, x] Awareness message. This information is only used to represent shared cursors and the name of each user. However, with enough malice intention you could assign other users temporarily false identities.

I think the best approach would be a whitelist approach (safe for future upgrades to the sync-protocol). Something like this

if (!readonly || message[0] !== 0 || message[1] === 0) {
  /* apply message */
} else {  /* filter message */ }
1 Like

Oh, I’ve actually implemented this if anyone is interested:

Basically did exactly what dmonad was suggesting. I modified it to ignore sync step 2 and update messages.

4 Likes

I’d like to have this feature on my server as well. Will likely implement it myself.

  • [0, 0] is a SyncStep1. It is request to receive the missing state (it contains a state-vector that the server uses to compute the missing updates)
  • [0, 1] is SyncStep2,

This info and pointers about the protocol is very useful, thanks!

Also looking for “permissions” feature - perhaps will do it with some sort of end-to-end encryption (to support p2p) and key sharing through central server.

I’ll likely “hack” the y-websocket protocol by adding my own custom e.g. “messageXX = 3/etc” values to set/get readonly info and exchange crypto keys.

This sounds like very interesting work! There are some similar needs we have at Relm. It would be valuable to see how you implement some of these pieces.

This was really useful, thanks!

unfortunately this fails with

const readItemContent = (decoder, info) => contentRefs[info & binary.BITS5](decoder);
                                                                           ^

TypeError: contentRefs[(info & binary.BITS5)] is not a function
    at readItemContent (file:///Users/adelnizamutdinov/Projects/diagrams/node_modules/yjs/dist/yjs.mjs:9426:76)
    at readClientsStructRefs (file:///Users/adelnizamutdinov/Projects/diagrams/node_modules/yjs/dist/yjs.mjs:1308:13)
    at file:///Users/adelnizamutdinov/Projects/diagrams/node_modules/yjs/dist/yjs.mjs:1535:16
    at transact (file:///Users/adelnizamutdinov/Projects/diagrams/node_modules/yjs/dist/yjs.mjs:3198:5)
    at readUpdateV2 (file:///Users/adelnizamutdinov/Projects/diagrams/node_modules/yjs/dist/yjs.mjs:1528:3)
    at readUpdate (file:///Users/adelnizamutdinov/Projects/diagrams/node_modules/yjs/dist/yjs.mjs:1607:58)
    at readSyncMessage (file:///Users/adelnizamutdinov/Projects/diagrams/back/dist/src/sync.js:82:17)

with yjs 13.5.11 when trying to actually write something