-
Notifications
You must be signed in to change notification settings - Fork 20
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
Add a serializable "permission root locator" to a FileSystemHandle #131
base: main
Are you sure you want to change the base?
Conversation
index.bs
Outdated
@@ -488,9 +486,9 @@ The <dfn method for=FileSystemFileHandle>getFile()</dfn> method steps are: | |||
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.txt
from 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
FileSystemHandle
two 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
FileSystemHandle
some 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
FileSystemHandle
itself, if there's a way to access aFileSystemHandle
in parallel (as the WICG spec currently does by incorrectly usingthis
directly). 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?
@@ -637,6 +634,7 @@ The <dfn method for=FileSystemFileHandle>createSyncAccessHandle()</dfn> method s | |||
[=/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
@@ -488,9 +486,9 @@ The <dfn method for=FileSystemFileHandle>getFile()</dfn> method steps are: | |||
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?
@@ -318,6 +284,62 @@ with the website process. The [=/file system path=] might contain components | |||
which are not known to the website unless the [=/file system locator=] is later | |||
[=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 ...
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.
@@ -318,6 +284,62 @@ with the website process. The [=/file system path=] might contain components | |||
which are not known to the website unless the [=/file system locator=] is later | |||
[=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
FileSystemHandle
a "permission root locator". A newly created childFileSystemHandle
will inherit this attribute from its parent (as opposed to its access algorithms), such that ifsubDir
was 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