You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
/// Step 25. While lifetimeTimer has not expired, perform the following actions depending upon lifetimeTimer, and the state and response for each authenticator in authenticators:
153
153
do{
154
-
/// → If lifetimeTimer expires,
155
-
/// For each authenticator in issuedRequests invoke the authenticatorCancel operation on authenticator and remove authenticator from issuedRequests.
156
-
/// → If the user exercises a user agent user-interface option to cancel the process,
157
-
/// For each authenticator in issuedRequests invoke the authenticatorCancel operation on authenticator and remove authenticator from issuedRequests. Throw a "NotAllowedError" DOMException.
158
-
/// → If options.signal is present and aborted,
159
-
/// For each authenticator in issuedRequests invoke the authenticatorCancel operation on authenticator and remove authenticator from issuedRequests. Then throw the options.signal’s abort reason.
160
-
/// → If an authenticator becomes available on this client device,
161
-
/// See ``KeyPairAuthenticator/makeCredentials(with:)`` for full implementation
162
-
/// → If an authenticator ceases to be available on this client device,
163
-
/// Remove authenticator from issuedRequests.
164
-
/// → If any authenticator returns a status indicating that the user cancelled the operation,
165
-
/// 1. Remove authenticator from issuedRequests.
166
-
/// 2. For each remaining authenticator in issuedRequests invoke the authenticatorCancel operation on authenticator and remove it from issuedRequests.
167
-
/// NOTE: Authenticators may return an indication of "the user cancelled the entire operation". How a user agent manifests this state to users is unspecified.
168
-
/// → If any authenticator returns an error status equivalent to "InvalidStateError",
169
-
/// 1. Remove authenticator from issuedRequests.
170
-
/// 2. For each remaining authenticator in issuedRequests invoke the authenticatorCancel operation on authenticator and remove it from issuedRequests.
171
-
/// 3. Throw an "InvalidStateError" DOMException.
172
-
/// NOTE: This error status is handled separately because the authenticator returns it only if excludeCredentialDescriptorList identifies a credential bound to the authenticator and the user has consented to the operation. Given this explicit consent, it is acceptable for this case to be distinguishable to the Relying Party.
173
-
/// → If any authenticator returns an error status not equivalent to "InvalidStateError",
174
-
/// Remove authenticator from issuedRequests.
175
-
/// NOTE: This case does not imply user consent for the operation, so details about the error are hidden from the Relying Party in order to prevent leak of potentially identifying information. See § 14.5.1 Registration Ceremony Privacy for details.
/// Let the caller do what it needs to do to coordinate with authenticators, so long as at least one of them calls the attestation callback.
155
+
letresult:AttestationObject=tryawaitwithCancellableFirstSuccessfulContinuation{[attestRegistration, publicKeyCredentialParameters] continuation in
156
+
/// → If lifetimeTimer expires,
157
+
/// For each authenticator in issuedRequests invoke the authenticatorCancel operation on authenticator and remove authenticator from issuedRequests.
158
+
Task{
159
+
/// Let the timer run in the background to cancel the continuation if it runs over.
160
+
await timeoutTask.value
161
+
continuation.cancel() // TODO: Should be a timeout error
162
+
}
163
+
164
+
/// → If the user exercises a user agent user-interface option to cancel the process,
165
+
/// For each authenticator in issuedRequests invoke the authenticatorCancel operation on authenticator and remove authenticator from issuedRequests. Throw a "NotAllowedError" DOMException.
166
+
// Implemented in catch statement below.
167
+
168
+
/// → If options.signal is present and aborted,
169
+
/// For each authenticator in issuedRequests invoke the authenticatorCancel operation on authenticator and remove authenticator from issuedRequests. Then throw the options.signal’s abort reason.
170
+
// Skip.
171
+
172
+
/// → If an authenticator becomes available on this client device,
173
+
/// See ``KeyPairAuthenticator/makeCredentials(with:)`` for full implementation
174
+
/// → If an authenticator ceases to be available on this client device,
175
+
/// Remove authenticator from issuedRequests.
176
+
/// → If any authenticator returns a status indicating that the user cancelled the operation,
177
+
/// 1. Remove authenticator from issuedRequests.
178
+
/// 2. For each remaining authenticator in issuedRequests invoke the authenticatorCancel operation on authenticator and remove it from issuedRequests.
179
+
/// NOTE: Authenticators may return an indication of "the user cancelled the entire operation". How a user agent manifests this state to users is unspecified.
180
+
// User can cancel the main task instead.
181
+
182
+
/// → If any authenticator returns an error status equivalent to "InvalidStateError",
183
+
/// 1. Remove authenticator from issuedRequests.
184
+
/// 2. For each remaining authenticator in issuedRequests invoke the authenticatorCancel operation on authenticator and remove it from issuedRequests.
185
+
/// 3. Throw an "InvalidStateError" DOMException.
186
+
/// NOTE: This error status is handled separately because the authenticator returns it only if excludeCredentialDescriptorList identifies a credential bound to the authenticator and the user has consented to the operation. Given this explicit consent, it is acceptable for this case to be distinguishable to the Relying Party.
187
+
// TODO: Need to catch this specific type of error
188
+
/// → If any authenticator returns an error status not equivalent to "InvalidStateError",
189
+
/// Remove authenticator from issuedRequests.
190
+
/// NOTE: This case does not imply user consent for the operation, so details about the error are hidden from the Relying Party in order to prevent leak of potentially identifying information. See § 14.5.1 Registration Ceremony Privacy for details.
191
+
192
+
/// Kick off the attestation process, waiting for one to succeed before the timeout.
/// 1. Remove authenticator from issuedRequests. This authenticator is now the selected authenticator.
@@ -234,7 +251,13 @@ public struct WebAuthnClient {
234
251
}catch{
235
252
/// Step 35. Throw a "NotAllowedError" DOMException. In order to prevent information leak that could identify the user without consent, this step MUST NOT be executed before lifetimeTimer has expired. See § 14.5.1 Registration Ceremony Privacy for details.
236
253
/// During the above process, the user agent SHOULD show some UI to the user to guide them in the process of selecting and authorizing an authenticator.
237
-
254
+
awaitwithTaskCancellationHandler{
255
+
/// Make sure to wait until the timeout finishes if an error did occur.
256
+
await timeoutTask.value
257
+
} onCancel:{
258
+
/// However, if the user cancelled the process, stop the timer early.
0 commit comments