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

Fix FedCM connection status computations #526

Merged
merged 2 commits into from
Aug 16, 2024
Merged
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
105 changes: 59 additions & 46 deletions spec/index.bs
Original file line number Diff line number Diff line change
Expand Up @@ -470,24 +470,44 @@ cross-origin communication.
If a user clears browsing data for an |origin| (cookies, localStorage, etc.), the user agent MUST
[=list/remove=] all triples with an [=/origin=] matching the |origin| from <a>connected accounts set</a>.

<div algorithm="compute the connection status">
To <dfn>compute the connection status</dfn> given an {{IdentityProviderConfig}} |provider|, an
{{IdentityProviderAccount}} |account|, and a |globalObject|, run the following steps. This returns
<dfn for="compute the connection status">connected</dfn> or
<dfn for="compute the connection status">disconnected</dfn>.
1. If |account| [=map/contains=] {{IdentityProviderAccount/approved_clients}} and
|account|'s {{IdentityProviderAccount/approved_clients}} does not [=list/contain=]
|provider|'s {{IdentityProviderConfig/clientId}}, return
[=compute the connection status/disconnected=].
<div algorithm>
To <dfn>compute the connected account key</dfn> given an {{IdentityProviderConfig}} |provider|, an
{{IdentityProviderAccount}} |account|, and a |globalObject|, run the following steps. It returns a
triple of the form (rp, idp, account).
1. Let |configUrl| be the result of running [=parse url=] with |provider|'s
{{IdentityProviderConfig/configURL}} and |globalObject|.
1. Let |idpOrigin| be the [=url/origin=] corresponding to |configUrl|.
1. Let |rpOrigin| be |globalObject|'s [=associated Document=]'s [=Document/origin=].
1. Let |accountId| be |account|'s {{IdentityProviderAccount/id}}.
1. Let |triple| be (|rpOrigin|, |idpOrigin|, |accountId|).
1. If [=connected accounts set=] [=list/contains=] |triple| , return
1. Return (|rpOrigin|, |idpOrigin|, |accountId|).
</div>

<div algorithm>
When asked whether an {{IdentityProviderAccount}} |account| is
<dfn>eligible for auto reauthentication</dfn> given an {{IdentityProviderConfig}} |provider| and a
|globalObject|, run the following steps. This returns a boolean.
1. If |account| [=map/contains=] {{IdentityProviderAccount/approved_clients}} and
|account|'s {{IdentityProviderAccount/approved_clients}} does not [=list/contain=]
|provider|'s {{IdentityProviderConfig/clientId}}, return false.
1. Let |triple| be the result of running [=compute the connected account key=] given |provider|,
|account|, and |globalObject|.
1. Return whether [=connected accounts set=] [=list/contains=] |triple|.
</div>

<div algorithm="compute the connection status">
When asked to <dfn>compute the connection status</dfn> given an {{IdentityProviderAccount}}
|account|, an {{IdentityProviderConfig}} |provider| and a |globalObject|, run the following steps.
This returns <dfn for="compute the connection status">connected</dfn> or
<dfn for="compute the connection status">disconnected</dfn>.
1. If |account| [=map/contains=] {{IdentityProviderAccount/approved_clients}}:
1. If |account|'s {{IdentityProviderAccount/approved_clients}} [=list/contains=]|provider|'s
{{IdentityProviderConfig/clientId}}, return [=compute the connection status/connected=].
1. Return [=compute the connection status/disconnected=].
1. Let |triple| be the result of running [=compute the connected account key=] given |provider|,
|account|, and |globalObject|.
1. If [=connected accounts set=] [=list/contains=] |triple|, return
[=compute the connection status/connected=].
1. Otherwise, return [=compute the connection status/disconnected=].
1. Return [=compute the connection status/disconnected=].
</div>

<div algorithm>
Expand Down Expand Up @@ -596,10 +616,10 @@ When asked to <dfn>attempt to disconnect</dfn> given an {{IdentityCredentialDisc
"{{NetworkError}}" {{DOMException}}.
1. If the user has disabled the FedCM API on the |globalObject|, [=reject=] |promise| with a
"{{NetworkError}}" {{DOMException}}.
1. If there does not exist an account |account| such that [=compute the connection status=] of
|options|, |account|, and |globalObject| returns
[=compute the connection status/connected=], then [=reject=] |promise| with a
"{{NetworkError}}" {{DOMException}}. This check can be performed by iterating over the
1. If there does not exist an account |account| such that [=connected accounts set=]
[=list/contains=] the result of [=compute the connected account key=] given |account|,
|options|, and |globalObject|, then [=reject=] |promise| with a "{{NetworkError}}"
{{DOMException}}. This check can be performed by iterating over the
[=connected accounts set=] or by keeping a separate data structure to make this lookup fast.
1. Let |config| be the result of running [=fetch the config file=] with
|provider| and |globalObject|.
Expand Down Expand Up @@ -963,41 +983,35 @@ the exception thrown.
1. Let |registeredAccount|, |numRegisteredAccounts| be null and 0, respectively.
1. Let |account| be null.
1. For each |acc| in |accountsList|:
1. Let |accState| be the result of running the [=compute the connection status=] algorithm given
|provider| and |acc|.
1. If |accState| is [=compute the connection status/connected=], set |registeredAccount| to
|acc| and increase |numRegisteredAccounts| by 1.
1. If |acc| is [=eligible for auto reauthentication=] given |provider|, and |globalObject|,
set |registeredAccount| to |acc| and increase |numRegisteredAccounts| by 1.
1. Let |permission|, |disclosureTextShown|, and |isAutoSelected| be set to false.
1. If |mediation| is not "{{CredentialMediationRequirement/required}}", |requiresUserMediation|
is false, and |numRegisteredAccounts| is equal to 1:
1. Set |account| to |registeredAccount| and |accountState| to the result of running
[=compute the connection status=] algorithm given |provider| and |account|. When doing this,
the user agent MAY show some UI to the user indicating that they are being
1. Set |account| to |registeredAccount| and |permission| to true. When doing this, the user
agent MAY show some UI to the user indicating that they are being
<dfn>auto-reauthenticated</dfn>.
1. Set |isAutoSelected| to true.
1. Otherwise, if |mediation| is "{{CredentialMediationRequirement/silent}}", return (failure, true).
1. Otherwise, if |accountsList|'s size is 1:
1. Set |account| to |accountsList|[0].
1. Set |accountState| to the result of running the [=compute the connection status=] algorithm
given |provider|, |account|, and |globalObject|.
1. If |accountState| is [=compute the connection status/disconnected=],
let |permission| be the result of running [=request permission to sign-up=] algorithm
with |account|, |accountState|, |config|, |provider|, and |globalObject|. Also set
|disclosureTextShown| to true.
1. Otherwise, show a dialog to request user permission to sign in via |account|, and set the
result in |permission|. The user agent MAY use |options|'s
1. If [=compute the connection status=] of |account|, |provider| and |globalObject| returns
[=compute the connection status/connected=], show a dialog to request user permission to sign
in via |account|, and set the result in |permission|. The user agent MAY use |options|'s
{{IdentityCredentialRequestOptions/context}} to customize the dialog.
1. Otherwise, let |permission| be the result of running [=request permission to sign-up=]
algorithm with |account|, |config|, |provider|, and |globalObject|. Also set
|disclosureTextShown| to true.
1. Otherwise:
1. Set |account| to the result of running the [=select an account=] from the
|accountsList|.
1. If |account| is failure, return (failure, true).
1. Set |accountState| to the result of running the [=compute the connection status=] algorithm
given |provider| and |account|.
1. If |accountState| is [=compute the connection status/disconnected=]:
1. If [=compute the connection status=] of |account|, |provider| and |globalObject| is
[=compute the connection status/connected=], set |permission| to true.
1. Otherwise:
1. Let |permission| be the result of running the [=request permission to sign-up=]
algorithm with |account|, |config|, |provider|, and |globalObject|.
1. Set |disclosureTextShown| to true.
1. Otherwise, set |permission| to true.
1. Wait until the [=user agent=]'s dialogs requesting for user choice or permission to be
closed, if any are created in the previous steps.
1. Assert: |account| is not null.
Expand Down Expand Up @@ -1629,9 +1643,9 @@ When invoking the {{IdentityProvider/getUserInfo()}} method given an {{IdentityP
1. Let |document| be |globalObject|'s [=associated Document=].
1. If |document| is not [=allowed to use=] the [=identity-credentials-get=]
[=policy-controlled feature=], throw a "{{NotAllowedError}}" {{DOMException}}.
1. If there does not exist an account |account| such that [=compute the connection status=] of
|provider|, |account|, and |globalObject| returns
[=compute the connection status/connected=], then throw a new "{{NetworkError}}"
1. If there does not exist an account |account| such that [=connected accounts set=]
[=list/contains=] the result of [=compute the connected account key=] given |account|,
|provider|, and |globalObject|, then [=reject=] |promise| with a "{{NetworkError}}"
{{DOMException}}. This check can be performed by iterating over the
[=connected accounts set=] or by keeping a separate data structure to make this lookup fast.
1. Let |configUrl| be the result of running [=parse url=] with |provider|'s
Expand All @@ -1653,7 +1667,7 @@ When invoking the {{IdentityProvider/getUserInfo()}} method given an {{IdentityP
{{DOMException}}.
1. Let |accountsList| be the result of [=fetch the accounts=] with |config|, |provider|,
and |globalObject|.
1. Let |hasReturningAccount| be false.
1. Let |hasAccountEligibleForAutoReauthentication| be false.
1. For each |account| in |accountsList|:
1. If |account|["{{IdentityProviderAccount/approved_clients}}"] is not empty and it does not
[=list/contain=] |provider|'s {{IdentityProviderConfig/clientId}}, continue.
Expand All @@ -1662,11 +1676,10 @@ When invoking the {{IdentityProvider/getUserInfo()}} method given an {{IdentityP
This could be useful for instance in cases where the user has disconnected the
account out of band.

1. [=Compute the connection status=] of |provider|, |account|, and |globalObject|. If the
result is [=compute the connection status/connected=], set |hasReturningAccount| to
true.
1. If |hasReturningAccount| is false, [=reject=] |promise| with a new "{{NetworkError}}"
{{DOMException}}.
1. If |account| is [=eligible for auto reauthentication=] given |provider| and
|globalObject|, set |hasAccountEligibleForAutoReauthentication| to true.
1. If |hasAccountEligibleForAutoReauthentication| is false, [=reject=] |promise| with a new
"{{NetworkError}}" {{DOMException}}.
1. Let |userInfoList| be a new [=list=].
1. For each |account| in |accountsList|:
1. [=list/Append=] an {{IdentityUserInfo}} to |userInfoList| with the following values:
Expand Down Expand Up @@ -2352,8 +2365,8 @@ The [=remote end steps=] are:
if present
1. `idpConfigUrl` set to the {{IdentityProviderConfig/configURL}} of the
IDP this account belongs to
1. `loginState` to `"SignUp"` if |accountState| is [=compute the connection status/disconnected=]
and `"SignIn"` otherwise
1. `loginState` to `"SignUp"` if |accountState| is
[=compute the connection status/disconnected=] and `"SignIn"` otherwise
1. `termsOfServiceUrl` to the {{IdentityProviderClientMetadata/terms_of_service_url}}
if one was provided and the `loginState` is `"SignUp"`, otherwise {{undefined}}
1. `privacyPolicyUrl` to the {{IdentityProviderClientMetadata/privacy_policy_url}}
Expand Down
Loading