Skip to content
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

Hook into Permissions API to get permission #68

Merged
merged 4 commits into from Mar 25, 2021
Merged
Changes from 2 commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Jump to
Jump to file
Failed to load files.
Diff view
Diff view
213 changes: 99 additions & 114 deletions index.html
Expand Up @@ -44,7 +44,7 @@
};
</script>
</head>
<body data-cite="secure-contexts permissions-policy">
<body data-cite="secure-contexts permissions-policy permissions">
<section id="abstract">
<p>
This specification defines an API that provides scripted access to
Expand Down Expand Up @@ -254,27 +254,23 @@ <h2>
The API defined in this specification is used to retrieve the
geographic location of a hosting device. In almost all cases, this
information also discloses the location of the user of the device,
thereby potentially compromising the user's privacy. A conforming
implementation of this specification MUST provide a mechanism that
protects the user's privacy and this mechanism SHOULD ensure that no
location information is made available through this API without the
user's express permission.
thereby potentially compromising the user's privacy. User agents MUST
NOT send location information to Web sites without the express
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think this is mostly redundant with the "Ask the user’s permission for the calling algorithm" step in https://www.w3.org/TR/permissions/#request-permission-to-use and the "reflects the user’s intent" bit of https://www.w3.org/TR/permissions/#permission-state.

To the extent that you're trying to tighten the UA's ability to infer the user's intent, that seems like something that needs more discussion in #54: I don't agree that "the express permission of the user" includes permission by the device owner, who might not be the user or have even disclosed their permission grant to the user. It probably does make sense to say that a UA mustn't infer a user's intent to give away geolocation information based on other users' behavior, but a UA should still be able to infer that a user might want to not give away that information based on other users revoking permission, as is allowed by https://www.w3.org/TR/permissions/#new-information-about-the-users-intent.

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

To the extent that you're trying to tighten the UA's ability to infer the user's intent, that seems like something that needs more discussion in #54: I don't agree that "the express permission of the user" includes permission by the device owner, who might not be the user or have even disclosed their permission grant to the user.

That's a whole other level of discussion. Basically, if a user willingly takes a device that they don't administer, there is zero privacy assurances. I really don't want to go down that rabbit hole.

permission of the user.
</p>
<section id="privacy_for_uas">
<h3>
Privacy considerations for implementers of the Geolocation API
Privacy considerations for geolocation permission UI
</h3>
<p>
User agents MUST NOT send location information to Web sites without
the express permission of the user. User agents MUST acquire
permission through a user interface, unless they have prearranged
trust relationships with users, as described below. The user
interface MUST include the {{URL/host}} component of the document's
URL. Those permissions that are acquired through the user interface
and that are preserved beyond the current browsing session (i.e.
beyond the time when the <a>browsing context</a> is navigated to
another URL) MUST be revocable and user agents MUST respect revoked
permissions.
User agents MUST acquire permission through a user interface, unless
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This seems to be covered by https://www.w3.org/TR/permissions/#request-permission-to-use. At least, I'm not sure how to "Ask the user’s permission" without a user interface.

The "unless they have prearranged trust relationships" bit then softens it to almost exactly the model in the permissions spec, where browsers are expected to infer the user's intent based on all the information they have.

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

agree... this whole section can go.

they have prearranged trust relationships with users, as described
below. The user interface MUST include the {{URL/host}} component of
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Is there anything special about geolocation that requires the host to be visible, or should that move to the permissions spec? Must it be the whole host, or could a UA emphasize a suffix in the case of a very long host?

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think it should move to the permissions spec, tbh. There is nothing special about Geo. I think Geolocation was the first permission prompt to show the origin (2010) and why this is here... it's legacy stuff.

the document's URL. Those permissions that are acquired through the
user interface and that are preserved beyond the current browsing
session (i.e. beyond the time when the <a>browsing context</a> is
navigated to another URL) MUST be revocable and user agents MUST
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The idea that users MUST be able to revoke permissions they've granted belongs in the generic Permissions spec, and I think we're missing some wording about it from there. However, we have to be a bit more subtle than this to accommodate device policy, where users might not be able to revoke all permissions. This might be part of the question to answer in https://github.com/w3c/permissions/issues/231.

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Agree.

respect revoked permissions.
</p>
<p>
Some user agents will have prearranged trust relationships that do
Expand Down Expand Up @@ -396,49 +392,37 @@ <h3>
</h3>
<p data-tests=
"getCurrentPosition_IDL.https.html, getCurrentPosition_TypeError.html">
The <dfn>getCurrentPosition()</dfn> method takes one, two or three
arguments. When called, it MUST immediately return and then
asynchronously attempt to obtain the current location of the
device. If the attempt is successful, the
|successCallback:PositionCallback| MUST be invoked with a new
{{GeolocationPosition}} object, reflecting the current location of
the device. If the attempt fails, the
|errorCallback:PositionErrorCallback| MUST be invoked with a new
{{GeolocationPositionError}} object, reflecting the reason for the
failure.
</p>
<p>
The implementation of the {{Geolocation/getCurrentPosition()}}
method MUST execute the following set of steps:
When {{Geolocation/getCurrentPosition()}} is invoked, the user
agent MUST:
</p>
<ol>
<li>Return and continue asynchronously.
<li>Return and continue [=in parallel=].
</li>
<li>If the <a>environment settings object</a> is a <a>non-secure
context</a> or the <a>current settings object</a>'s [=environment
settings object / responsible document=] is not [=allowed to use=]
the "geolocation" feature:
<ol>
<li>If |errorCallback| is not null, invoke the |errorCallback|
with a newly created {{GeolocationPositionError}} object whose
{{GeolocationPositionError/code}} attribute is initialized to
{{GeolocationPositionError/PERMISSION_DENIED}}.
</li>
<li>Terminate this algorithm.
</li>
</ol>
context</a>, then [=call back with error=] |errorCallback| and
{{GeolocationPositionError/PERMISSION_DENIED}} and terminate this
algorithm.
</li>
<li>[=Request permission to use=] "geolocation" (see
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

You need to capture the result of this call, which will be "granted" or "denied", and fail if it returns "denied".

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yeah, I was trying to be clever and just let "allowed to use" deal with it. I'll do as you suggest.

[[[#privacy_for_uas]]] for permissions UI requirements).
</li>
<li data-tests=
"getCurrentPosition_permission_allow.https.html, getCurrentPosition_permission_deny.https.html">
If the <a>current settings object</a>'s [=environment settings
object / responsible document=] is not [=allowed to use=] the
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This is covered when https://www.w3.org/TR/permissions/#request-permission-to-use looks at the permission state.

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Agree... fixing.

"geolocation" feature, then [=call back with error=]
|errorCallback| and {{GeolocationPositionError/PERMISSION_DENIED}}
and terminate this algorithm.
</li>
<li>If a cached {{GeolocationPosition}} object, whose age is no
greater than the value of the {{PositionOptions/maximumAge}}
variable, is available, invoke the |successCallback| with the
cached {{GeolocationPosition}} object as a parameter and exit this
set of steps.
cached {{GeolocationPosition}} object as a parameter and terminate
this algorithm.
</li>
<li>If the value of the timeout variable is 0, invoke the
|errorCallback| (if present) with a new
{{GeolocationPositionError}} object whose
{{GeolocationPositionError/code}} attribute is set to
{{GeolocationPositionError.TIMEOUT}} and exit this set of steps.
<li>If the value of the timeout variable is 0, [=call back with
error=] |errorCallback| and {{GeolocationPositionError/TIMEOUT}}
and terminate this algorithm.
</li>
<li>Start a location acquisition operation (e.g. by invoking a
platform-specific API), possibly taking into account the value of
Expand All @@ -447,21 +431,17 @@ <h3>
<li>Start a timer that will fire after the number of milliseconds
denoted by the value of the timeout variable. When the timer fires,
cancel any ongoing location acquisition operations associated with
this instance of the steps, invoke the |errorCallback| (if present)
with a new {{GeolocationPositionError}} object whose
{{GeolocationPositionError/code}} attribute is set to
{{GeolocationPositionError.TIMEOUT}}, and exit this set of steps.
this instance of the steps, [=call back with error=]
|errorCallback| and {{GeolocationPositionError/TIMEOUT}}.
</li>
<li>If the operation completes successfully before the timeout
expires, cancel the pending timer, invoke the |successCallback|
with a new {{GeolocationPosition}} object that reflects the result
of the acquisition operation and exit this set of steps.
of the acquisition operation and terminate this algorithm.
</li>
<li>If the operation fails before the timeout expires, cancel the
pending timer and invoke the |errorCallback| (if present) with a
new {{GeolocationPositionError}} object whose
{{GeolocationPositionError/code}} is set to
{{GeolocationPositionError.POSITION_UNAVAILABLE}}.
pending timer and [=call back with error=] |errorCallback| and
{{GeolocationPositionError/POSITION_UNAVAILABLE}}.
</li>
</ol>
</section>
Expand All @@ -470,40 +450,42 @@ <h3>
`watchPosition()` method
</h3>
<p>
The <dfn>watchPosition()</dfn> method takes one, two or three
arguments. When called, immediately return a long value that
uniquely identifies a <a>watch process</a> and continue
asynchronously.
When <dfn>watchPosition()</dfn> is invoked, the user agent MUST:
</p>
<ol>
<li>Let |watchId:long| be {{long}} that uniquely identifies a
<a>watch process</a>.
</li>
<li>Return |watchId| and continue [=in parallel=].
</li>
<li>If the <a>environment settings object</a> is a <a>non-secure
context</a> or the <a>current settings object</a>'s [=environment
settings object / responsible document=] is not [=allowed to use=]
the "geolocation" feature:
<ol>
<li>If |errorCallback| is not null, invoke the |errorCallback|
with a newly created {{GeolocationPositionError}} object whose
{{GeolocationPositionError/code}} attribute is initialized to
{{GeolocationPositionError/PERMISSION_DENIED}}.
</li>
<li>Terminate this algorithm.
</li>
</ol>
context</a>, then [=call back with error=] |errorCallback| and
{{GeolocationPositionError/PERMISSION_DENIED}} and terminate this
algorithm.
</li>
<li>[=Request permission to use=] "geolocation" (see
[[[#privacy_for_uas]]] for permissions UI requirements).
</li>
<li data-tests="watchPosition_permission_deny.https.html">If the
<a>current settings object</a>'s [=environment settings object /
responsible document=] is not [=allowed to use=] the "geolocation"
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Similarly here, "request permission to use" will return "denied" if the current settings object isn't allowed to use geolocation.

feature, then [=call back with error=] |errorCallback| and
{{GeolocationPositionError/PERMISSION_DENIED}} and terminate this
algorithm.
</li>
<li>
<p>
Otherwise, start the watch operation. This operation MUST first
attempt to obtain the current location of the device. If the
attempt is successful, the |successCallback| MUST be invoked
with a new {{GeolocationPosition}} object, reflecting the
current location of the device. If the attempt fails, the
|errorCallback| MUST be invoked with a new
{{GeolocationPositionError}} object, reflecting the reason for
the failure. The <a>watch process</a> then MUST continue to
monitor the position of the device and invoke the appropriate
callback every time this position changes. The <a>watch
process</a> MUST continue until the
{{Geolocation/clearWatch()}} method is called with the
current location of the device. If the attempt fails, [=call
back with error=], |errorCallback| and a {{unsigned short}}
code that reflects the reason for the failure. The <a>watch
process</a> then MUST continue to monitor the position of the
device and invoke the appropriate callback every time this
position changes. The <a>watch process</a> MUST continue until
the {{Geolocation/clearWatch()}} method is called with the
corresponding identifier.
</p>
</li>
Expand Down Expand Up @@ -531,11 +513,9 @@ <h3>
<ol>
<li>If the timer is not already running, start a timer that
will fire after the number of milliseconds denoted by the value
of the timeout variable. When the timer fires, invoke the
|errorCallback| (if present) with a new
{{GeolocationPositionError}} object whose
{{GeolocationPositionError/code}} attribute is set to
{{GeolocationPositionError.TIMEOUT}} and jump to the <a>wait
of the timeout variable. When the timer fires, [=call back with
error=] |errorCallback| and
{{GeolocationPositionError/TIMEOUT}} and jump to the <a>wait
for a system event to be received</a> step.
</li>
<li>If the location acquisition operation successfully yields a
Expand All @@ -555,11 +535,9 @@ <h3>
</ol>
</li>
<li>Else, if the location acquisition operation reports an
error before the {{PositionOptions/timeout}} expires, invoke
the |errorCallback| (if present) with a new
{{GeolocationPositionError}} object whose
{{GeolocationPositionError/code}} is set to
{{GeolocationPositionError.POSITION_UNAVAILABLE}}. This step
error before the {{PositionOptions/timeout}} expires, [=call
back with error=] |errorCallback| and
{{GeolocationPositionError/POSITION_UNAVAILABLE}}. This step
MAY be subject to callback [=rate limitation=].
</li>
</ol>
Expand All @@ -580,25 +558,12 @@ <h3>
limit</dfn> on the frequency of callbacks so as to avoid
inadvertently consuming a disproportionate amount of resources.
</p>
<p data-tests=
"getCurrentPosition_permission_allow.https.html, getCurrentPosition_permission_deny.https.html, watchPosition_permission_deny.https.html">
For both {{Geolocation/getCurrentPosition()}} and
{{Geolocation/watchPosition()}}, the implementation MUST never
invoke the |successCallback| without having first obtained
permission from the user to share location. Furthermore, the
implementation SHOULD always obtain the user's permission to share
location before executing any of the
{{Geolocation/getCurrentPosition()}} or
{{Geolocation/watchPosition()}} steps described above. If the user
grants permission, the appropriate callback MUST be invoked as
described above. If the user denies permission, the |errorCallback|
(if present) MUST be invoked with {{GeolocationPositionError/code}}
set to {{GeolocationPositionError.PERMISSION_DENIED}}, irrespective
of any other errors encountered in the above steps. The time that
is spent obtaining the user permission MUST NOT be included in the
period covered by the {{PositionOptions/timeout}} attribute of the
{{PositionOptions}} parameter. The {{PositionOptions/timeout}}
attribute MUST only apply to the location acquisition operation.
<p>
The time that is spent obtaining the user permission MUST NOT be
included in the period covered by the {{PositionOptions/timeout}}
attribute of the {{PositionOptions}} parameter. The
{{PositionOptions/timeout}} attribute MUST only apply to the
location acquisition operation.
</p>
</section>
<section>
Expand All @@ -615,6 +580,26 @@ <h3>
immediately stopped and no further callbacks MUST be invoked.
</p>
</section>
<section>
<h3>
Callback with error
</h3>
<p>
When instructed to <dfn>call back with error</dfn>, given an
{{PositionErrorCallback}}? |callback:PositionErrorCallback?| and
{{unsigned short}} |code:unsigned short|:
</p>
<ol class="algorithm">
<li>If |callback| is null, return.
</li>
<li>Let |error| be a a newly created {{GeolocationPositionError}}
object whose {{GeolocationPositionError/code}} attribute is
initialized to |code|.
</li>
<li>Call |callback| with |error|.
</li>
</ol>
</section>
<section data-dfn-for="PositionCallBack">
<h3>
`PositionCallBack` callback
Expand Down Expand Up @@ -695,7 +680,7 @@ <h3>
timeout elapses, and no other errors have occurred in this
interval, then the corresponding |errorCallback| MUST be invoked
with a {{GeolocationPositionError}} object whose code attribute is
set to {{GeolocationPositionError.TIMEOUT}}. Note that the time
set to {{GeolocationPositionError/TIMEOUT}}. Note that the time
that is spent obtaining the user permission is not included in the
period covered by the {{PositionOptions/timeout}} attribute. The
{{PositionOptions/timeout}} attribute only applies to the location
Expand Down