Skip to content

Commit 817b02e

Browse files
Updated client to use task groups instead of custom cancellable child tasks
1 parent f21ce6f commit 817b02e

7 files changed

+197
-279
lines changed

Sources/WebAuthn/Authenticators/Protocol/AssertionAuthenticationRequest.swift

+15-32
Original file line numberDiff line numberDiff line change
@@ -17,53 +17,36 @@
1717
public struct AssertionAuthenticationRequest: Sendable {
1818
public var options: PublicKeyCredentialRequestOptions
1919
public var clientDataHash: SHA256Digest
20-
public var attemptAuthentication: Callback
2120

2221
init(
2322
options: PublicKeyCredentialRequestOptions,
24-
clientDataHash: SHA256Digest,
25-
attemptAuthentication: @Sendable @escaping (_ assertionResults: Results) async throws -> ()
23+
clientDataHash: SHA256Digest
2624
) {
2725
self.options = options
2826
self.clientDataHash = clientDataHash
29-
self.attemptAuthentication = Callback(callback: attemptAuthentication)
3027
}
3128
}
3229

3330
extension AssertionAuthenticationRequest {
34-
public struct Callback: Sendable {
35-
/// The internal callback the attestation should call.
36-
var callback: @Sendable (_ assertionResults: Results) async throws -> ()
31+
public struct Results: Sendable {
32+
public var credentialID: [UInt8]
33+
public var authenticatorData: [UInt8]
34+
public var signature: [UInt8]
35+
public var userHandle: [UInt8]?
36+
public var authenticatorAttachment: AuthenticatorAttachment
3737

38-
/// Submit the results of asserting a user's authentication request.
39-
///
40-
/// Authenticators should call this to submit a successful authentication and cancel any other pending authenticators.
41-
///
42-
/// - SeeAlso: https://w3c.github.io/webauthn/#sctn-generating-an-attestation-object
43-
public func submitAssertionResults(
38+
public init(
4439
credentialID: [UInt8],
4540
authenticatorData: [UInt8],
4641
signature: [UInt8],
47-
userHandle: [UInt8]?,
42+
userHandle: [UInt8]? = nil,
4843
authenticatorAttachment: AuthenticatorAttachment
49-
) async throws {
50-
try await callback(Results(
51-
credentialID: credentialID,
52-
authenticatorData: authenticatorData,
53-
signature: signature,
54-
userHandle: userHandle,
55-
authenticatorAttachment: authenticatorAttachment
56-
))
44+
) {
45+
self.credentialID = credentialID
46+
self.authenticatorData = authenticatorData
47+
self.signature = signature
48+
self.userHandle = userHandle
49+
self.authenticatorAttachment = authenticatorAttachment
5750
}
5851
}
5952
}
60-
61-
extension AssertionAuthenticationRequest {
62-
struct Results {
63-
var credentialID: [UInt8]
64-
var authenticatorData: [UInt8]
65-
var signature: [UInt8]
66-
var userHandle: [UInt8]?
67-
var authenticatorAttachment: AuthenticatorAttachment
68-
}
69-
}

Sources/WebAuthn/Authenticators/Protocol/AttestationRegistrationRequest.swift

+1-28
Original file line numberDiff line numberDiff line change
@@ -19,41 +19,14 @@ public struct AttestationRegistrationRequest: Sendable {
1919
var options: PublicKeyCredentialCreationOptions
2020
var publicKeyCredentialParameters: [PublicKeyCredentialParameters]
2121
var clientDataHash: SHA256Digest
22-
var attemptRegistration: Callback
2322

2423
init(
2524
options: PublicKeyCredentialCreationOptions,
2625
publicKeyCredentialParameters: [PublicKeyCredentialParameters],
27-
clientDataHash: SHA256Digest,
28-
attemptRegistration: @Sendable @escaping (_ attestationObject: AttestationObject) async throws -> ()
26+
clientDataHash: SHA256Digest
2927
) {
3028
self.options = options
3129
self.publicKeyCredentialParameters = publicKeyCredentialParameters
3230
self.clientDataHash = clientDataHash
33-
self.attemptRegistration = Callback(callback: attemptRegistration)
34-
}
35-
}
36-
37-
extension AttestationRegistrationRequest {
38-
public struct Callback: Sendable {
39-
/// The internal callback the attestation should call.
40-
var callback: @Sendable (_ attestationObject: AttestationObject) async throws -> ()
41-
42-
/// Generate an attestation object for registration and submit it.
43-
///
44-
/// Authenticators should call this to submit a successful registration and cancel any other pending authenticators.
45-
///
46-
/// - SeeAlso: https://w3c.github.io/webauthn/#sctn-generating-an-attestation-object
47-
public func submitAttestationObject(
48-
attestationFormat: AttestationFormat,
49-
authenticatorData: AuthenticatorData,
50-
attestationStatement: CBOR
51-
) async throws {
52-
try await callback(AttestationObject(
53-
authenticatorData: authenticatorData,
54-
format: attestationFormat,
55-
attestationStatement: attestationStatement
56-
))
57-
}
5831
}
5932
}

Sources/WebAuthn/Authenticators/Protocol/AuthenticatorProtocol.swift

+38-11
Original file line numberDiff line numberDiff line change
@@ -17,7 +17,34 @@ import SwiftCBOR
1717

1818
public typealias CredentialStore<A: AuthenticatorProtocol> = [A.CredentialSource.ID : A.CredentialSource]
1919

20-
public protocol AuthenticatorProtocol<CredentialSource> {
20+
21+
public protocol AuthenticatorRegistrationConsumer: Sendable {
22+
associatedtype CredentialOutput: Sendable
23+
24+
/// Generate an attestation object for registration and submit it.
25+
///
26+
/// Authenticators should call this to submit a successful registration and cancel any other pending authenticators.
27+
///
28+
/// - SeeAlso: https://w3c.github.io/webauthn/#sctn-generating-an-attestation-object
29+
func makeCredentials(with registration: AttestationRegistrationRequest) async throws -> (AttestationObject, CredentialOutput)
30+
}
31+
32+
public protocol AuthenticatorAssertionConsumer: Sendable {
33+
associatedtype CredentialInput: Sendable
34+
associatedtype CredentialOutput: Sendable
35+
36+
/// Submit the results of asserting a user's authentication request.
37+
///
38+
/// Authenticators should call this to submit a successful authentication and cancel any other pending authenticators.
39+
///
40+
/// - SeeAlso: https://w3c.github.io/webauthn/#sctn-generating-an-attestation-object
41+
func assertCredentials(
42+
authenticationRequest: AssertionAuthenticationRequest,
43+
credentials: CredentialInput
44+
) async throws -> (AssertionAuthenticationRequest.Results, CredentialOutput)
45+
}
46+
47+
public protocol AuthenticatorProtocol<CredentialSource>: AuthenticatorRegistrationConsumer, AuthenticatorAssertionConsumer {
2148
associatedtype CredentialSource: AuthenticatorCredentialSourceProtocol
2249

2350
var attestationGloballyUniqueID: AAGUID { get }
@@ -62,10 +89,10 @@ public protocol AuthenticatorProtocol<CredentialSource> {
6289

6390
/// Make credentials for the specified registration request, returning the credential source that the caller should store for subsequent authentication.
6491
///
65-
/// - Important: Depending on the authenticator being used, the credential source may contain private keys, and must be stored sequirely, such as in the user's Keychain, or in a Hardware Security Module appropriate with the level of security you wish to secure your user's account with.
92+
/// - Important: Depending on the authenticator being used, the credential source may contain private keys, and must be stored securely, such as in the user's Keychain, or in a Hardware Security Module appropriate with the level of security you wish to secure your user's account with.
6693
/// - SeeAlso: [WebAuthn Level 3 Editor's Draft §5.1.3. Create a New Credential - PublicKeyCredential’s Create(origin, options, sameOriginWithAncestors) Method, Step 25.]( https://w3c.github.io/webauthn/#CreateCred-async-loop)
6794
/// - SeeAlso: [WebAuthn Level 3 Editor's Draft §6.3.2. The authenticatorMakeCredential Operation](https://w3c.github.io/webauthn/#sctn-op-make-cred)
68-
func makeCredentials(with registration: AttestationRegistrationRequest) async throws -> CredentialSource
95+
func makeCredentials(with registration: AttestationRegistrationRequest) async throws -> (AttestationObject, CredentialSource)
6996

7097
/// Filter the provided credential descriptors to determine which, if any, should be handled by this authenticator.
7198
///
@@ -106,7 +133,7 @@ public protocol AuthenticatorProtocol<CredentialSource> {
106133
func assertCredentials(
107134
authenticationRequest: AssertionAuthenticationRequest,
108135
credentials: CredentialStore<Self>
109-
) async throws -> CredentialSource
136+
) async throws -> (AssertionAuthenticationRequest.Results, CredentialSource)
110137
}
111138

112139
// MARK: - Default Implementations
@@ -142,7 +169,7 @@ extension AuthenticatorProtocol {
142169
extension AuthenticatorProtocol {
143170
public func makeCredentials(
144171
with registration: AttestationRegistrationRequest
145-
) async throws -> CredentialSource {
172+
) async throws -> (AttestationObject, CredentialSource) {
146173
/// See [WebAuthn Level 3 Editor's Draft §5.1.3. Create a New Credential - PublicKeyCredential’s Create(origin, options, sameOriginWithAncestors) Method, Step 25.]( https://w3c.github.io/webauthn/#CreateCred-async-loop)
147174
/// Step 1. This authenticator is now the candidate authenticator.
148175
/// Step 2. If pkOptions.authenticatorSelection is present:
@@ -328,13 +355,13 @@ extension AuthenticatorProtocol {
328355
)
329356

330357
/// On successful completion of this operation, the authenticator returns the attestation object to the client.
331-
try await registration.attemptRegistration.submitAttestationObject(
332-
attestationFormat: attestationFormat,
358+
let attestationObject = AttestationObject(
333359
authenticatorData: authenticatorData,
360+
format: attestationFormat,
334361
attestationStatement: attestationStatement
335362
)
336363

337-
return credentialSource
364+
return (attestationObject, credentialSource)
338365
}
339366
}
340367

@@ -344,7 +371,7 @@ extension AuthenticatorProtocol {
344371
public func assertCredentials(
345372
authenticationRequest: AssertionAuthenticationRequest,
346373
credentials: CredentialStore<Self>
347-
) async throws -> CredentialSource {
374+
) async throws -> (AssertionAuthenticationRequest.Results, CredentialSource) {
348375
/// [WebAuthn Level 3 Editor's Draft §5.1.4.2. Issuing a Credential Request to an Authenticator](https://w3c.github.io/webauthn/#sctn-issuing-cred-request-to-authenticator)
349376
/// Step 1. If pkOptions.userVerification is set to required and the authenticator is not capable of performing user verification, return false.
350377
if authenticationRequest.options.userVerification == .required && !canPerformUserVerification {
@@ -473,7 +500,7 @@ extension AuthenticatorProtocol {
473500
/// signature
474501
/// selectedCredential.userHandle
475502
/// NOTE: In cases where allowCredentialDescriptorList was supplied the returned userHandle value may be null, see: userHandleResult.
476-
try await authenticationRequest.attemptAuthentication.submitAssertionResults(
503+
let assertionResults = AssertionAuthenticationRequest.Results(
477504
credentialID: selectedCredential.id.bytes,
478505
authenticatorData: authenticatorData,
479506
signature: signature,
@@ -484,6 +511,6 @@ extension AuthenticatorProtocol {
484511
/// If the authenticator cannot find any credential corresponding to the specified Relying Party that matches the specified criteria, it terminates the operation and returns an error.
485512
// Already done.
486513

487-
return selectedCredential
514+
return (assertionResults, selectedCredential)
488515
}
489516
}

Sources/WebAuthn/Ceremonies/Registration/AttestationObject.swift

+1-1
Original file line numberDiff line numberDiff line change
@@ -35,7 +35,7 @@ public struct AttestationObject: Sendable {
3535
self.attestationStatement = attestationStatement
3636
}
3737

38-
init(
38+
public init(
3939
authenticatorData: AuthenticatorData,
4040
format: AttestationFormat,
4141
attestationStatement: CBOR

Sources/WebAuthn/Helpers/CancellableContinuationTask.swift

-92
This file was deleted.

0 commit comments

Comments
 (0)