-
Notifications
You must be signed in to change notification settings - Fork 27
Add a serializable "permission root locator" to a FileSystemHandle #131
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
base: main
Are you sure you want to change the base?
Conversation
index.bs
Outdated
| 1. Let |locator| be [=this=]'s [=FileSystemHandle/locator=]. | ||
| 1. Let |global| be [=this=]'s [=relevant global object=]. | ||
| 1. [=Enqueue the following steps=] to the [=file system queue=]: | ||
| 1. Let |accessResult| be the result of running |global|'s |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Q: is use of global correct here? (and throughout this PR)
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
No, the algorithm sits on a FileSystemHandle, right? So I'm not sure how this can work. It's already a bit odd to access a FileSystemHandle in parallel. Maybe it would be better if they were associated with the locator? Or does that end up doing the wrong thing?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
The only issue with using the locator is that it doesn't contain the context from which the handle was acquired. For example, consider this scenario:
- The user selects
~/Documents/foo/bar.txtfrom the file picker asfile - The user selects
~/Documents/foo/from the directory picker, then the site callsdir.getFileHandle('bar.txt')to getfileFromDir
Note that in this case, file.isSameEntry(fileFromDir) is true and the respective file system locators are the same
However, if file.requestPermission() is called, the "request access" algorithm corresponds to ~/Documents/foo/bar.txt
Meanwhile, if fileFromDir.requestPermission() is called, the "request access" algorithm (at least in Chromium browsers) corresponds to ~/Documents/foo/. This is because the getFileHandle() method passes down its access check algorithms to its children (see step 6). When serializing a FileSystemHandle, our implementation actually includes the paths of both the parent (which was selected from the picker) and the child in the serialization.
Given all this, I see three paths forward:
- Argue that this is all just an implementation detail (e.g. it's up to the user agent whether
fileFromDir.requestPermission()should request permission to~/Documents/foo/or~/Documents/foo/bar.txt), and for the purposes of the spec we should just tie access checks to a "fie system locator" and call it a day - Give each
FileSystemHandletwo locators - one for itself and one for the root it was created from. Access checks for any handle use the root's locator. Serializing a handle requires serializing both of these locators - Give each
FileSystemHandlesome attribute that encapsulates its access check algorithms (e.g. "file system permission state"). This is passed down to all created children similar to what is currently specified for the access check algorithms (see step 6 ofgetFileHandle()). Access checks are performed based only on this attribute, and the attribute would need to be serialized (though I'm not sure exactly how that would look)
Thoughts?
Edit: numbered options so we can more easily refer to them in future comments
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Looking at the WICG spec more closely... (3) could look like giving a FileSystemHandle a FileSystemPermissionDescriptor member (though I'm not sure if it's a problem that a descriptor is currently specified to have a handle)
I guess there's still:
- Tie access check algorithms to the
FileSystemHandleitself, if there's a way to access aFileSystemHandlein parallel (as the WICG spec currently does by incorrectly usingthisdirectly). As @mkruisselbrink pointed out, though, it's unclear how this permission state could be serialized
FWIW this "inherit permissions from the parent" behavior is also specified in step 3 of the permission state constraints algorithm for a FileSystemPermissionDescriptor. That text's use of "parent" was made outdated by #96, though (i.e. it can no longer be null). It seems that we should either introduce the concept of a "permission root" (as options 2 and 3 do explicitly and 4 does implicitly) or say that the context from which the handle was acquired is not relevant and the locator is all that matters (i.e. that file.requestPermission() should always request permission to ~/Documents/foo/)
On another note... given that that constraint exists, I wonder if updating serialization steps might be unnecessary, since it's just a mechanism used to enforce this constraint?
Lots of options here. Eager to hear thoughts from others :)
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Given that what constraint exists?
I think you're correct that locator alone doesn't work. Presumably if you do subDir.requestPermission() it should still impact rootDir? I think that argues for either storing a reference to the root handle or the root locator that a potential access algorithm could then use.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
In the latest patch I've given each FileSystemHandle a "permission root locator" (let me know if you have a better name for this). As mentioned above, this matches how Chrome serializes a handle today.
In this model, creating a handle through one of the API's entry points (which in this spec is only navigator.storage.getDirectory(), but also includes e.g. the picker methods in https://wicg.github.io/file-system-access/) will set the "permission root locator" to the "locator" of the handle itself. Meanwhile, any children which are created from this handle will be passed the permission root, such that subDir.requestPermission() is the same as rootDir.requestPermission()
A key advantage of this approach (as opposed to passing the access algorithm itself from parent to child) is that it's serializable. The old approach tied "query access" and "request access" algorithms to an entry (and an version of this PR tied these access algorithms to the FileSystemHandle itself). But these algorithms are (presumably? Please let me know if that's incorrect) not serializable, so postMessage() or storing a handle in IDB would lose its "where did I originate from" information
As such, there is now just one "query access" and one "request access" algorithm - which return "granted" for locators in a bucket file system; otherwise "denied" - that I intend to override in https://wicg.github.io/file-system-access/#permissions to handle the non-BucketFileSystem use cases. Does that seem like a reasonable approach?
| [=/reject=] |result| with an "{{InvalidStateError}}" {{DOMException}} and | ||
| abort these steps. | ||
|
|
||
| 1. Let |entry| be the result of [=locating an entry=] given |locator|. |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
FYI: I've re-ordered the "locating an entry" statements in several algorithms, since the |entry| is no longer needed for the access checks
|
cc @mkruisselbrink but he's OOO for a bit so sending over to @annevk for review. Thanks! |
index.bs
Outdated
| 1. Let |locator| be [=this=]'s [=FileSystemHandle/locator=]. | ||
| 1. Let |global| be [=this=]'s [=relevant global object=]. | ||
| 1. [=Enqueue the following steps=] to the [=file system queue=]: | ||
| 1. Let |accessResult| be the result of running |global|'s |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
No, the algorithm sits on a FileSystemHandle, right? So I'm not sure how this can work. It's already a bit odd to access a FileSystemHandle in parallel. Maybe it would be better if they were associated with the locator? Or does that end up doing the wrong thing?
| [=file system locator/resolved=] relative to a parent [=directory locator=]. | ||
|
|
||
| <div algorithm> | ||
| <dfn abstract-op id=entry-query-access lt=QueryFileSystemAccess>QueryFileSystemAccess(|locator|, |mode|)</dfn> |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I don't have much experience with abstract algorithms, so please let me know whether it makes sense to use in this case
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I think abstract-op is primarily for JavaScript and some legacy cases. For new cases we can just define an algorithm as we already do elsewhere.
To query file system access, given ...
annevk
left a comment
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Might be good to get feedback from someone else on the substance of this PR. Just gave some feedback on whether to use an abstract operation.
| [=file system locator/resolved=] relative to a parent [=directory locator=]. | ||
|
|
||
| <div algorithm> | ||
| <dfn abstract-op id=entry-query-access lt=QueryFileSystemAccess>QueryFileSystemAccess(|locator|, |mode|)</dfn> |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I think abstract-op is primarily for JavaScript and some legacy cases. For new cases we can just define an algorithm as we already do elsewhere.
To query file system access, given ...
Until now, access checks were tied to a "file system entry". As of #96, a "file system entry" corresponds to an actual file or directory on disk. We need to support access checks on FileSystemHandles which don't correspond to an entry (e.g. the entry has been removed), so the access checks must be tied to something else.
This PR gives each
FileSystemHandlea "permission root locator". A newly created childFileSystemHandlewill inherit this attribute from its parent (as opposed to its access algorithms), such that ifsubDirwas created fromrootDir,subDir.requestPermission()is equivalent torootDir.requestPermission(). This "permission root locator" is serialized, such that storing a handle in IDB now retains information about where the handle originated fromThe new "query access" and one "request access" algorithms are expected to be overridden in https://wicg.github.io/file-system-access/#permissions to handle non-BucketFileSystem use cases.
Fixes #101
Preview | Diff