Skip to content

Commit d76772a

Browse files
Updated all timeouts to be represented in seconds when consumed from the Swift API surface
1 parent 3ebcd30 commit d76772a

File tree

5 files changed

+29
-25
lines changed

5 files changed

+29
-25
lines changed

Sources/WebAuthn/Ceremonies/Authentication/PublicKeyCredentialRequestOptions.swift

Lines changed: 9 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -17,16 +17,20 @@ import Foundation
1717
/// The `PublicKeyCredentialRequestOptions` gets passed to the WebAuthn API (`navigator.credentials.get()`)
1818
///
1919
/// When encoding using `Encodable`, the byte arrays are encoded as base64url.
20+
///
21+
/// - SeeAlso: https://www.w3.org/TR/webauthn-2/#dictionary-assertion-options
2022
public struct PublicKeyCredentialRequestOptions: Encodable {
2123
/// A challenge that the authenticator signs, along with other data, when producing an authentication assertion
2224
///
2325
/// When encoding using `Encodable` this is encoded as base64url.
2426
public let challenge: [UInt8]
2527

26-
/// The number of milliseconds that the Relying Party is willing to wait for the call to complete. The value is treated
27-
/// as a hint, and may be overridden by the client.
28+
/// A time, in seconds, that the caller is willing to wait for the call to complete. This is treated as a
29+
/// hint, and may be overridden by the client.
30+
///
31+
/// - Note: When encoded, this value is represented in milleseconds as a ``UInt32``.
2832
/// See https://www.w3.org/TR/webauthn-2/#dictionary-assertion-options
29-
public let timeout: UInt32?
33+
public let timeout: TimeInterval?
3034

3135
/// The Relying Party ID.
3236
public let rpId: String?
@@ -43,7 +47,8 @@ public struct PublicKeyCredentialRequestOptions: Encodable {
4347
var container = encoder.container(keyedBy: CodingKeys.self)
4448

4549
try container.encode(challenge.base64URLEncodedString(), forKey: .challenge)
46-
try container.encodeIfPresent(timeout, forKey: .timeout)
50+
let timeoutInMilliseconds = timeout.map { UInt32($0 * 1000) }
51+
try container.encodeIfPresent(timeoutInMilliseconds, forKey: .timeout)
4752
try container.encodeIfPresent(rpId, forKey: .rpId)
4853
try container.encodeIfPresent(allowCredentials, forKey: .allowCredentials)
4954
try container.encodeIfPresent(userVerification, forKey: .userVerification)

Sources/WebAuthn/Ceremonies/Registration/PublicKeyCredentialCreationOptions.swift

Lines changed: 11 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -12,10 +12,14 @@
1212
//
1313
//===----------------------------------------------------------------------===//
1414

15+
import Foundation
16+
1517
/// The `PublicKeyCredentialCreationOptions` gets passed to the WebAuthn API (`navigator.credentials.create()`)
1618
///
1719
/// Generally this should not be created manually. Instead use `RelyingParty.beginRegistration()`. When encoding using
1820
/// `Encodable` byte arrays are base64url encoded.
21+
///
22+
/// - SeeAlso: https://www.w3.org/TR/webauthn-2/#dictionary-makecredentialoptions
1923
public struct PublicKeyCredentialCreationOptions: Encodable {
2024
/// A byte array randomly generated by the Relying Party. Should be at least 16 bytes long to ensure sufficient
2125
/// entropy.
@@ -34,9 +38,11 @@ public struct PublicKeyCredentialCreationOptions: Encodable {
3438
/// preferred.
3539
public let publicKeyCredentialParameters: [PublicKeyCredentialParameters]
3640

37-
/// A time, in milliseconds, that the caller is willing to wait for the call to complete. This is treated as a
41+
/// A time, in seconds, that the caller is willing to wait for the call to complete. This is treated as a
3842
/// hint, and may be overridden by the client.
39-
public let timeoutInMilliseconds: UInt32?
43+
///
44+
/// - Note: When encoded, this value is represented in milleseconds as a ``UInt32``.
45+
public let timeout: TimeInterval?
4046

4147
/// Sets the Relying Party's preference for attestation conveyance. At the time of writing only `none` is
4248
/// supported.
@@ -49,7 +55,8 @@ public struct PublicKeyCredentialCreationOptions: Encodable {
4955
try container.encode(user, forKey: .user)
5056
try container.encode(relyingParty, forKey: .relyingParty)
5157
try container.encode(publicKeyCredentialParameters, forKey: .publicKeyCredentialParameters)
52-
try container.encodeIfPresent(timeoutInMilliseconds, forKey: .timeoutInMilliseconds)
58+
let timeoutInMilliseconds = timeout.map { UInt32($0 * 1000) }
59+
try container.encodeIfPresent(timeoutInMilliseconds, forKey: .timeout)
5360
try container.encode(attestation, forKey: .attestation)
5461
}
5562

@@ -58,7 +65,7 @@ public struct PublicKeyCredentialCreationOptions: Encodable {
5865
case user
5966
case relyingParty = "rp"
6067
case publicKeyCredentialParameters = "pubKeyCredParams"
61-
case timeoutInMilliseconds = "timeout"
68+
case timeout
6269
case attestation
6370
}
6471
}

Sources/WebAuthn/WebAuthnManager.swift

Lines changed: 5 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -47,31 +47,26 @@ public struct WebAuthnManager {
4747
/// This method will use the Relying Party information from the WebAuthnManager's config to create ``PublicKeyCredentialCreationOptions``
4848
/// - Parameters:
4949
/// - user: The user to register.
50-
/// - timeoutInSeconds: How long the browser should give the user to choose an authenticator. This value
50+
/// - timeout: How long the browser should give the user to choose an authenticator. This value
5151
/// is a *hint* and may be ignored by the browser. Defaults to 60 seconds.
5252
/// - attestation: The Relying Party's preference regarding attestation. Defaults to `.none`.
5353
/// - publicKeyCredentialParameters: A list of public key algorithms the Relying Party chooses to restrict
5454
/// support to. Defaults to all supported algorithms.
5555
/// - Returns: Registration options ready for the browser.
5656
public func beginRegistration(
5757
user: PublicKeyCredentialUserEntity,
58-
timeoutInSeconds: TimeInterval? = 3600,
58+
timeout: TimeInterval? = 3600,
5959
attestation: AttestationConveyancePreference = .none,
6060
publicKeyCredentialParameters: [PublicKeyCredentialParameters] = .supported
6161
) -> PublicKeyCredentialCreationOptions {
6262
let challenge = challengeGenerator.generate()
6363

64-
var timeoutInMilliseconds: UInt32?
65-
if let timeoutInSeconds {
66-
timeoutInMilliseconds = UInt32(timeoutInSeconds * 1000)
67-
}
68-
6964
return PublicKeyCredentialCreationOptions(
7065
challenge: challenge,
7166
user: user,
7267
relyingParty: .init(id: config.relyingPartyID, name: config.relyingPartyName),
7368
publicKeyCredentialParameters: publicKeyCredentialParameters,
74-
timeoutInMilliseconds: timeoutInMilliseconds,
69+
timeout: timeout,
7570
attestation: attestation
7671
)
7772
}
@@ -144,13 +139,10 @@ public struct WebAuthnManager {
144139
userVerification: UserVerificationRequirement = .preferred
145140
) throws -> PublicKeyCredentialRequestOptions {
146141
let challenge = challengeGenerator.generate()
147-
var timeoutInMilliseconds: UInt32? = nil
148-
if let timeout {
149-
timeoutInMilliseconds = UInt32(timeout * 1000)
150-
}
142+
151143
return PublicKeyCredentialRequestOptions(
152144
challenge: challenge,
153-
timeout: timeoutInMilliseconds,
145+
timeout: timeout,
154146
rpId: config.relyingPartyID,
155147
allowCredentials: allowCredentials,
156148
userVerification: userVerification

Tests/WebAuthnTests/WebAuthnManagerAuthenticationTests.swift

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -43,7 +43,7 @@ final class WebAuthnManagerAuthenticationTests: XCTestCase {
4343
)
4444

4545
XCTAssertEqual(options.challenge, challenge)
46-
XCTAssertEqual(options.timeout, 1234000) // timeout converted to milliseconds
46+
XCTAssertEqual(options.timeout, 1234)
4747
XCTAssertEqual(options.rpId, relyingPartyID)
4848
XCTAssertEqual(options.allowCredentials, allowCredentials)
4949
XCTAssertEqual(options.userVerification, .preferred)

Tests/WebAuthnTests/WebAuthnManagerIntegrationTests.swift

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -37,7 +37,7 @@ final class WebAuthnManagerIntegrationTests: XCTestCase {
3737

3838
let registrationOptions = webAuthnManager.beginRegistration(
3939
user: mockUser,
40-
timeoutInSeconds: timeout,
40+
timeout: timeout,
4141
attestation: attestationPreference,
4242
publicKeyCredentialParameters: publicKeyCredentialParameters
4343
)
@@ -49,7 +49,7 @@ final class WebAuthnManagerIntegrationTests: XCTestCase {
4949
XCTAssertEqual(registrationOptions.attestation, attestationPreference)
5050
XCTAssertEqual(registrationOptions.relyingParty.id, config.relyingPartyID)
5151
XCTAssertEqual(registrationOptions.relyingParty.name, config.relyingPartyName)
52-
XCTAssertEqual(registrationOptions.timeoutInMilliseconds, UInt32(timeout * 1000))
52+
XCTAssertEqual(registrationOptions.timeout, timeout)
5353
XCTAssertEqual(registrationOptions.publicKeyCredentialParameters, publicKeyCredentialParameters)
5454

5555
// Now send `registrationOptions` to client, which in turn will send the authenticator's response back to us:
@@ -107,7 +107,7 @@ final class WebAuthnManagerIntegrationTests: XCTestCase {
107107
)
108108

109109
XCTAssertEqual(authenticationOptions.rpId, config.relyingPartyID)
110-
XCTAssertEqual(authenticationOptions.timeout, UInt32(authenticationTimeout * 1000)) // timeout is in milliseconds
110+
XCTAssertEqual(authenticationOptions.timeout, authenticationTimeout)
111111
XCTAssertEqual(authenticationOptions.challenge, mockChallenge)
112112
XCTAssertEqual(authenticationOptions.userVerification, userVerification)
113113
XCTAssertEqual(authenticationOptions.allowCredentials, rememberedCredentials)

0 commit comments

Comments
 (0)