diff --git a/index.bs b/index.bs index d70ec37cf..9ee7f33d5 100644 --- a/index.bs +++ b/index.bs @@ -2953,6 +2953,292 @@ value and terminate the operation. +### Signal Credential Changes to the Authenticator - PublicKeyCredential's [=signal methods=] ### {#sctn-signal-methods} + +
options
object was well formed.
+
+Each [=signal method=] includes authenticator
+actions. [=Authenticators=] MAY choose to deviate in their [=signal
+method/authenticator actions=] from the present specification, e.g. to ignore a
+change they have a reasonable belief would be contrary to the user's wish, or to
+ask the user before making some change. [=signal method/Authenticator actions=]
+are thus provided as the recommended way to handle [=signal methods=].
+
+In cases where an [=authenticator=] does not have the capability to process an
+[=signal method/authenticator action=], [=clients=] MAY choose to use existing
+infrastructure such as [[!FIDO-CTAP]]'s `authenticatorCredentialManagement`
+command to achieve an equivalent effect.
+
+Note: [=Signal methods=] intentionally avoid waiting for [=authenticators=] to
+complete executing the [=signal method/authenticator actions=]. This measure protects users
+from [=[WRPS]=] gaining information about availability of their credentials
+without [=user consent=] based on the timing of the request.
+
+#### Asynchronous RP ID validation algorithm #### {#sctn-signal-methods-async-rp-id-validation}
+
+The [$Asynchronous RP ID validation algorithm$] lets [=signal methods=] validate
+[=RP IDs=] [=in parallel=]. The algorithm takes a {{DOMString}} |rpId| as input
+and returns a promise that rejects if the validation fails. The steps are:
+
+1. Let |effectiveDomain| be the [=relevant settings object=]'s [=environment
+ settings object/origin=]'s [=effective domain=]. If |effective domain| is
+ not a [=valid domain=], then return [=a promise rejected with=]
+ "{{SecurityError}}" {{DOMException}}.
+1. If |rpId| [=is a registrable domain suffix of or is equal to=]
+ |effectiveDomain|, return [=a promise resolved with=] undefined.
+1. If the client does not support [[#sctn-related-origins|related origin
+ requests]], return [=a promise rejected with=] a "{{SecurityError}}"
+ {{DOMException}}.
+1. Let |p| be [=a new promise=].
+1. Execute the following steps [=in parallel=]:
+ 1. If the result of running the [$related origins validation procedure$]
+ with arguments |callerOrigin| and |rpId| is [TRUE], then [=resolve=]
+ |p|.
+ 1. Otherwise, [=reject=] |p| with a "{{SecurityError}}" {{DOMException}}.
+1. Return |p|.
+
+#### {{PublicKeyCredential/signalUnknownCredential(options)}} #### {#sctn-signalUnknownCredential}
+
+The {{PublicKeyCredential/signalUnknownCredential(options)|signalUnknownCredential}} method signals that a [=credential id=] was not recognized by the [=[WRP]=],
+e.g. because it was deleted by the user. Unlike {{PublicKeyCredential/signalAllAcceptedCredentials(options)}}, this
+method does not require passing the entire list of accepted [=credential IDs=]
+and the [=userHandle=], avoiding a privacy leak to an unauthenticated caller
+(see [[#sctn-credential-id-privacy-leak]]).
+
+Upon invocation of {{PublicKeyCredential/signalUnknownCredential(options)}},
+the [=client=] executes these steps:
+
+1. If the result of [=base64url encoding | base64url decoding=]
+ |options|.{{UnknownCredentialOptions/credentialId}}
is an
+ error, then return [=a promise rejected with=] a {{TypeError}}.
+1. Let |p| be the result of executing the [$Asynchronous RP ID validation
+ algorithm$] with |options|.{{UnknownCredentialOptions/rpId}}
.
+1. [=Upon fulfillment=] of |p|, run the following steps [=in parallel=]:
+ 1. For every [=authenticator=] presently available on this [=client
+ platform=], invoke the [=signal method/authenticator
+ action/unknownCredentialId=] [=authenticator action=] with |options| as
+ input.
+1. Return |p|.
+
+The unknownCredentialId
+[=signal method/authenticator action=] takes an {{UnknownCredentialOptions}}
+|options| and is as follows:
+1. [=map/For each=] [=public key credential source=] |credential| in the
+ [=authenticator=]'s [=credential map=]:
+ 1. If the |credential|'s [=public key credential source/rpId=] equals
+ |options|.{{UnknownCredentialOptions/rpId}}
and the
+ |credential|'s [=public key credential source/id=] equals the result of
+ [=base64url encoding | base64url decoding=]
+ |options|.{{UnknownCredentialOptions/credentialId}}
,
+ [=map/remove=] |credential| from the [=credentials map=] or employ an
+ [=authenticator=]-specific procedure to hide it from future
+ [=authentication ceremonies=].
+
+|options|.{{AllAcceptedCredentialsOptions/userId}}
is an
+ error, then return [=a promise rejected with=] a {{TypeError}}.
+1. [=list/For each=] |credentialId| in
+ |options|.{{AllAcceptedCredentialsOptions/allAcceptedCredentialIds}}
:
+ 1. If the result of [=base64url encoding | base64url decoding=]
+ |credentialId| is an error, then return [=a promise rejected with=] a
+ {{TypeError}}.
+1. Let |p| be the result of executing the [$Asynchronous RP ID validation
+ algorithm$] with
+ |options|.{{AllAcceptedCredentialsOptions/rpId}}
.
+1. [=Upon fulfillment=] of |p|, run the following steps [=in parallel=]:
+ 1. For every [=authenticator=] presently available on this [=client
+ platform=], invoke the [=signal method/authenticator
+ actions/allAcceptedCredentialIds=] [=authenticator action=] with
+ |options| as input.
+1. Return |p|.
+
+The allAcceptedCredentialIds [=signal method/authenticator
+actions=] take an {{AllAcceptedCredentialsOptions}} |options| and are as
+follows:
+1. Let |userId| be result of [=base64url encoding | base64url decoding=]
+ |options|.{{AllAcceptedCredentialsOptions/userId}}
.
+1. Assertion: |userId| is not an error.
+1. Let |credential| be
+ [=credentials map=][|options|.{{AllAcceptedCredentialsOptions/rpId}}, |userId|]
.
+1. If |credential| does not exist, abort these steps.
+1. If
+ |options|.{{AllAcceptedCredentialsOptions/allAcceptedCredentialIds}}
+ does NOT [=list/contain=] the result of [=base64url encoding=] the
+ |credential|'s [=public key credential source/id=], then [=map/remove=]
+ |credential| from the [=credentials map=] or employ an
+ [=authenticator=]-specific procedure to hide it from future [=authentication
+ ceremonies=].
+1. Else, if |credential| has been hidden by an [=authenticator=]-specific
+ procecure, reverse the action so that |credential| is present in future
+ [=authentication ceremonies=].
+
+|options|.{{CurrentUserDetailsOptions/userId}}
is an error,
+ then return [=a promise rejected with=] a {{TypeError}}.
+1. Let |p| be the result of executing the [$Asynchronous RP ID validation
+ algorithm$] with
+ |options|.{{CurrentUserDetailsOptions/rpId}}
.
+1. [=Upon fulfillment=] of |p|, run the following steps [=in parallel=]:
+ 1. For every [=authenticator=] presently available on this [=client
+ platform=], invoke the [=signal method/authenticator
+ actions/currentUserDetails=] [=authenticator action=] with |options|
+ as input.
+1. Return |p|.
+
+The currentUserDetails
+[=signal method/authenticator action=] takes a {{CurrentUserDetailsOptions}}
+|options| and is as follows:
+1. Let |userId| be result of [=base64url encoding | base64url decoding=]
+ |options|.{{CurrentUserDetailsOptions/userId}}
.
+1. Assertion: |userId| is not an error.
+1. Let |credential| be
+ [=credentials map=][|options|.{{CurrentUserDetailsOptions/rpId}}, |userId|]
.
+1. If |credential| does not exist, abort these steps.
+1. Update the |credential|'s [=public key credential source/otherUI=] to match
+ |options|.{{CurrentUserDetailsOptions/name}}
and
+ |options|.{{CurrentUserDetailsOptions/displayName}}
.
+
+