-
Notifications
You must be signed in to change notification settings - Fork 10
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 draft of spec #6
Conversation
This ensures that CORS or an rSA call indicates embedee opt-in.
Ah, didn't notice this when looking at #5 😆. Similar comments probably apply :) |
yup, I addressed your comments in this one 😄 I think we're pretty clearly moving to "require explicit rSA invocation" at this point, so this is the better PR. It's just a matter of clarifying the subresource request portion. |
got one round of review from @johannhof already...wondering if @domfarolino would want to take a look as well (we discussed parts of this today out-of-band). There's probably a good bit of work still needed, but the more we can knock out now, the better. |
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.
Took a quick pass, can finish the rest next week but here's a few comments for now.
Btw, feel free to use https://github.com/domfarolino/specfmt if you feel so daring to format the spec incrementally and be one of that project's first guinea pigs :)
requestStorageAccessForOrigin.bs
Outdated
1. Run these steps [=in parallel=]: | ||
1. Let |hasAccess| be [=a new promise=]. | ||
1. [=Determine the top-level storage access policy=] with |descriptor|, |doc| and |hasAccess|. | ||
1. [=Queue a global task=] on the [=permission task source=] given |global| to resolve or reject |p| based on the result of |hasAccess|. |
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 result of |hasAccess| is just a promise right? Do you mean to wait for the result of |hasAccess| and resolve/reject |p| with the same value? It seems like "Determine the top-level storage access policy" already queues its own task on the global it receives, to resolve/reject the promise it is given though (which is |hasAccess| IIUC), so I'm a bit confused what is going on here. It's also a little late so maybe I'm just not squinting hard enough :)
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.
ah, the former (again modeled on the storage access API spec, perhaps poorly).
I modified the other function to just resolve or reject the promise it is given, which might help?
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 other function" being "Determine the top-level storage access policy", right? So there's a few things to note here:
- We can't resolve/reject promises "in parallel"; that has to be done in a global task
- We can't create new promise objects "in parallel"... maybe we could bend the rules on this one for
hasAccess
since it isn't web-exposed, but that's probably not a good precedent to set
If I understand correctly, the "Determine the top-level storage access policy" algorithm used to queue its own task on a global to resolve/reject the promise it is given accordingly. So can we just pass |p|
into that algorithm, instead of create a new promise (|hasAccess|
) and use its resolution to inform |p|
's resolution? Does that make sense?
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.
yes, that makes more sense. I do note that this seems to re-add global
use in these parallel steps (which I thought was one of the main thread items to watch out for), unless my mechanism for resolving or rejecting the promise is wrong. Alternatively, maybe that's fine since it's queueing a task vs mutating global or relying on its state being unchanged.
requestStorageAccessForOrigin.bs
Outdated
1. If |existing state| is [=permission/granted=], return true. | ||
1. Return false. | ||
|
||
To <dfn type="abstract-op">determine the top-level storage access policy</dfn> for {{TopLevelStorageAccessPermissionDescriptor}} |descriptor|, with {{Document}} |doc| and {{Promise}} |p|, run these steps: |
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.
It would be good to know where this is supposed to be running? On the "main thread", or "in parallel"? It seems to kind of interact with main thread state, but earlier it seems to be called in parallel.
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.
ah, to a large extent I was mimicking the equivalent in the storage access API spec (or well, how it is expected to be). I think it does need to run in parallel, since presumably we'd not wait on a permission request (which can prompt the user) to return the promise in the actual rSAFor
function call.
I can go through and try to identify which of this state lives on the main thread and react accordingly.
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.
(removed the global
variable and the top-level site in favor of plumbing it in; attempted to follow the docs, though I suspect user activation will also have to be plumbed in)
requestStorageAccessForOrigin.bs
Outdated
1. Run these steps [=in parallel=]: | ||
1. Let |hasAccess| be [=a new promise=]. | ||
1. [=Determine the top-level storage access policy=] with |descriptor|, |doc| and |hasAccess|. | ||
1. [=Queue a global task=] on the [=permission task source=] given |global| to resolve or reject |p| based on the result of |hasAccess|. |
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 other function" being "Determine the top-level storage access policy", right? So there's a few things to note here:
- We can't resolve/reject promises "in parallel"; that has to be done in a global task
- We can't create new promise objects "in parallel"... maybe we could bend the rules on this one for
hasAccess
since it isn't web-exposed, but that's probably not a good precedent to set
If I understand correctly, the "Determine the top-level storage access policy" algorithm used to queue its own task on a global to resolve/reject the promise it is given accordingly. So can we just pass |p|
into that algorithm, instead of create a new promise (|hasAccess|
) and use its resolution to inform |p|
's resolution? Does that make sense?
requestStorageAccessForOrigin.bs
Outdated
|
||
<!-- this long chain pulled from fetch, but may be unusual or unsafe --> | ||
1. Let |settings| be |request|'s [=request/client=]'s [=relevant global object=]'s [=associated document=]'s [=relevant settings object=]. | ||
1. Let |embedded origin| be |request|'s [=request/url=]. |
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.
This variable is of type "URL" but the variable name is "origin". That's a little confusing, but I guess it matches the fact that TopLevelStorageAccessPermissionDescriptor's requestedOrigin is a USVString (not an origin), but I think we still need to pull the serialized origin out of the URL right? Or else the dictionary's requestedOrigin member will actually be the entire URL string?
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.
hm...I went with USVString for the descriptor, but perhaps it would be better to use origin? I wasn't sure what the correct IDL type would be. Regardless, yes, I at least switched to the request's url's origin here.
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.
This seems good to merge from my side :)
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.
A few nits mostly around touching main-thread state from an in-parallel context. This is probably good enough for a draft provided we follow-up on some of the comments accordingly. It'll probably be another week until I can take another close look, so feel free to not block on me if you need to publish. I can take another close look after the holidays or maybe in between them etc.
1. [=Queue a global task=] on the [=permission task source=] given |global| to [=reject=] |p| with a "{{NotAllowedError}}" {{DOMException}}. | ||
1. Return. | ||
1. Assert that |doc|'s [=node navigable=] is a [=traversable navigable=]. | ||
1. If this algorithm was invoked when |doc|'s {{Window}} object did not have [=transient activation=]: |
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.
This is a bit handwavy as we're doing some action-at-a-distance, looking backwards to state that lived on a different thread. I think it's best to pull the state of the user activation out early on the main thread and plumb it through
1. [=Queue a global task=] on the [=permission task source=] given |global| to [=resolve=] |p|. | ||
1. Return. | ||
1. If |implicitly denied| is true: | ||
1. [=reject=] |p| with a "{{NotAllowedError}}" {{DOMException}}. |
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.
We have to queue a task to do this on the main thread right? Also nit: "Reject", since it is the beginning of a sentence
1. If |permissionState| is [=permission/granted=]: | ||
1. [=Queue a global task=] on the [=permission task source=] given |global| to [=resolve=] |p|. | ||
1. Return. | ||
1. If |doc|'s {{Window}} object has [=transient activation=], [=consume user activation=] with it. |
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.
User activation querying and consumption should be done on the main thread. How does this work implementation-wise?
To <dfn type="abstract-op">determine if a request has top-level storage access</dfn> with [=request=] |request|, run these steps: | ||
|
||
1. Let |settings| be |request|'s [=request/client=]'s [=relevant global object=]'s [=relevant settings object=]. | ||
1. Let |embedded origin| be |request|'s [=request/url=]'s [=/origin=]. |
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.
Should "/origin" be "url/origin" here?
will address remaining domfarolino@ comments in a follow-up PR (cleaning this up as it was from before moving the repo). Thanks! |
This ensures that CORS +
use-credentials
is used in top-level subresource requests, and leaves open the possibility of an rSA call indicating embeddee opt-in for frames (with the latter point to be clarified in a later effort based on the outcome of per-frame discussions elsewhere).