I’m attempting to investigate the feasibility of revoking/removing access to future versions of some shared private file/directory in your filesystem, for a specific user which you have previously shared with.
I imagine this must be possible, but I do not see any high-level method to achieve this within the scope of the current SDK.
I see that FileSystem.root.sharedLinks provides a mapping of the generated share keys and their respective SimpleLink objects, but i’m a bit lost as to how to go from this information, to resolving the location in the PrivateTree which contains the share, and then removing it?
If anyone could provide some insight into approaching this, it would be greatly appreciated!
It is possible for sure, but there’s no interface for it.
how to go from this information, to resolving the location in the PrivateTree which contains the share, and then removing it?
If I understand correctly, you want to remove access to future versions, not the share all together right? To remove access to future versions of a file or directory, we’d need to rotate the private name (ie. namefilter) of that item. You could also change the encryption key, but I think changing the key on its own would result in an error for the person trying to access the older version of the share.
To be on the safe side I think it’d be best to rotate the key as well, but that complicates things. In that case we’d also need to walk through the skeleton of the private trees and do a recursive update.
You could also remove the entry from FileSystem.root.sharedLinks to remove access to the share for anyone that had not accessed/accepted the share yet. The people who accessed it already will still have access, because they already have the private name and key for the data in the form of a symlink stored in their own file system.
Here’s a rough idea of what to do for the rotation of the private name:
Get the PrivateTree or PrivateFile instance of the tree or file you want to rotate the private name on. For example, using fs.get()
Reset the bare namefilter and revision in the .header object, the combination of these two properties makes up the private name. See the static create method of the respective class on how to do that.
Every name filter of a child depends on its parent’s name filter. Meaning we need to do a recursive update of the name filters. For example, say we have the path private/A/B/C/D.txt. If we rotate B, we need to update the name filters of C and D.txt as well (see recursive functions in BaseTree class)
Call .put() on the instance of the tree or file you changed (not the children). This will add it to the MMPT (aka. private forest) which acts as our lookup table for all private items.
Update the MMPT pointer in the root tree: await fs.root.updatePuttable("private", fs.root.mmpt)
fs.publish() to update your data root / DNS pointer so your other devices have the changes too.
The plan to actually do this is quite speculative, so let me know if you want me to make a demo and/or walk you through the sharedLinks idea.
All that said, we’re actually moving away from this implementation of the file system. GitHub - wnfs-wg/rs-wnfs: Rust implementation of the WebNative FileSystem (WNFS) specification will be used in the future, which works a whole lot different (including private sharing). Hence why we’re not adding anymore features to the current version of the file system. Although we’re still a few months away from having all of that on feature parity and in Webnative.
That was very insightful, thanks for taking the time to respond!
If I understand correctly, the above rotation steps you have outlined would revoke future access to all shares of that Tree/File?
In a situation where you wish to revoke access to some subset of users, whilst the remainder retain access, is it correct that you could remove only the share namefilter entries from the private forest, for each exchange key you are revoking?
Disclaimer: I think I may need to look further into how namefilters differ between a standard private file entry and a share entry (and also how this differs between the new spec and the current SDK)
Good question! You’re partially correct, you could loop over each exchange key and remove access to some exchange keys. However, that piece isn’t in the private forest, it’s in the /shared DAG under the root tree (where sharedTree[shareKey] = encrypted_with_exchange_key_share_payload).
Also, true only if by revoke access you mean revoke future access.
To be clear, there is a private forest piece in here as well, but that’s the same for all users, so we can’t remove that.
For how this would work, you’d basically do the reverse of the addShares function in src/fs/root/tree.ts. Where the name of each link is a share key, which can be reconstructed using create in src/fs/protocol/shared/key.ts. This has the shape ${recipientExchangeDid}${senderRootDid}${counter}. The difficult part here is the counter. I guess you could loop from 0 to the number that’s stored in the sharedCounter root branch in case you don’t know it