From 5013145206d8954dc756195408a307e3e1b36154 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Nicol=C3=A1s=20Pe=C3=B1a=20Moreno?= Date: Fri, 16 Aug 2024 14:02:47 -0400 Subject: [PATCH] Fix FedCM connection status computations (#526) * rebase * rebase --- spec/index.bs | 105 ++++++++++++++++++++++++++++---------------------- 1 file changed, 59 insertions(+), 46 deletions(-) diff --git a/spec/index.bs b/spec/index.bs index 29dee0d7..e67d0917 100644 --- a/spec/index.bs +++ b/spec/index.bs @@ -472,24 +472,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 connected accounts set. -
-To compute the connection status given an {{IdentityProviderConfig}} |provider|, an -{{IdentityProviderAccount}} |account|, and a |globalObject|, run the following steps. This returns -connected or -disconnected. - 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=]. +
+To compute the connected account key 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|). +
+ +
+When asked whether an {{IdentityProviderAccount}} |account| is +eligible for auto reauthentication 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|. +
+ +
+When asked to compute the connection status given an {{IdentityProviderAccount}} +|account|, an {{IdentityProviderConfig}} |provider| and a |globalObject|, run the following steps. +This returns connected or +disconnected. + 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=].
@@ -598,10 +618,10 @@ When asked to attempt to disconnect 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|. @@ -965,41 +985,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 auto-reauthenticated. 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. @@ -1627,9 +1641,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 @@ -1651,7 +1665,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. @@ -1660,11 +1674,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: @@ -2350,8 +2363,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}}