Skip to content

Commit de47752

Browse files
Added a CredentialType enumeration
1 parent f15bc61 commit de47752

10 files changed

+63
-30
lines changed

Sources/WebAuthn/Ceremonies/Authentication/AuthenticationCredential.swift

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -31,8 +31,8 @@ public struct AuthenticationCredential {
3131
/// navigator.credentials.get() methods successfully complete
3232
public let authenticatorAttachment: AuthenticatorAttachment?
3333

34-
/// Value will always be "public-key" (for now)
35-
public let type: String
34+
/// Value will always be ``CredentialType/publicKey`` (for now)
35+
public let type: CredentialType
3636
}
3737

3838
extension AuthenticationCredential: Decodable {
@@ -43,7 +43,7 @@ extension AuthenticationCredential: Decodable {
4343
rawID = try container.decodeBytesFromURLEncodedBase64(forKey: .rawID)
4444
response = try container.decode(AuthenticatorAssertionResponse.self, forKey: .response)
4545
authenticatorAttachment = try container.decodeIfPresent(AuthenticatorAttachment.self, forKey: .authenticatorAttachment)
46-
type = try container.decode(String.self, forKey: .type)
46+
type = try container.decode(CredentialType.self, forKey: .type)
4747
}
4848

4949
private enum CodingKeys: String, CodingKey {

Sources/WebAuthn/Ceremonies/Authentication/PublicKeyCredentialRequestOptions.swift

Lines changed: 7 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -87,8 +87,8 @@ public struct PublicKeyCredentialDescriptor: Equatable, Encodable {
8787
case `internal`
8888
}
8989

90-
/// Will always be 'public-key'
91-
public let type: String
90+
/// Will always be ``CredentialType/publicKey``
91+
public let type: CredentialType
9292

9393
/// The sequence of bytes representing the credential's ID
9494
///
@@ -98,7 +98,11 @@ public struct PublicKeyCredentialDescriptor: Equatable, Encodable {
9898
/// The types of connections to the client/browser the authenticator supports
9999
public let transports: [AuthenticatorTransport]
100100

101-
public init(type: String, id: [UInt8], transports: [AuthenticatorTransport] = []) {
101+
public init(
102+
type: CredentialType = .publicKey,
103+
id: [UInt8],
104+
transports: [AuthenticatorTransport] = []
105+
) {
102106
self.type = type
103107
self.id = id
104108
self.transports = transports

Sources/WebAuthn/Ceremonies/Registration/Credential.swift

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -17,8 +17,8 @@ import Foundation
1717
/// After a successful registration ceremony we pass this data back to the relying party. It contains all needed
1818
/// information about a WebAuthn credential for storage in e.g. a database.
1919
public struct Credential {
20-
/// Value will always be "public-key" (for now)
21-
public let type: String
20+
/// Value will always be ``CredentialType/publicKey`` (for now)
21+
public let type: CredentialType
2222

2323
/// base64 encoded String of the credential ID bytes
2424
public let id: String

Sources/WebAuthn/Ceremonies/Registration/PublicKeyCredentialCreationOptions.swift

Lines changed: 5 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -72,19 +72,19 @@ public struct PublicKeyCredentialCreationOptions: Encodable {
7272
// MARK: - Credential parameters
7373
/// From §5.3 (https://w3c.github.io/TR/webauthn/#dictionary-credential-params)
7474
public struct PublicKeyCredentialParameters: Equatable, Encodable {
75-
/// The type of credential to be created. At the time of writing always "public-key".
76-
public let type: String
75+
/// The type of credential to be created. At the time of writing always ``CredentialType/publicKey``.
76+
public let type: CredentialType
7777
/// The cryptographic signature algorithm with which the newly generated credential will be used, and thus also
7878
/// the type of asymmetric key pair to be generated, e.g., RSA or Elliptic Curve.
7979
public let alg: COSEAlgorithmIdentifier
8080

8181
/// Creates a new `PublicKeyCredentialParameters` instance.
8282
///
8383
/// - Parameters:
84-
/// - type: The type of credential to be created. At the time of writing always "public-key".
84+
/// - type: The type of credential to be created. At the time of writing always ``CredentialType/publicKey``.
8585
/// - alg: The cryptographic signature algorithm to be used with the newly generated credential.
8686
/// For example RSA or Elliptic Curve.
87-
public init(type: String = "public-key", alg: COSEAlgorithmIdentifier) {
87+
public init(type: CredentialType = .publicKey, alg: COSEAlgorithmIdentifier) {
8888
self.type = type
8989
self.alg = alg
9090
}
@@ -94,7 +94,7 @@ extension Array where Element == PublicKeyCredentialParameters {
9494
/// A list of `PublicKeyCredentialParameters` WebAuthn Swift currently supports.
9595
public static var supported: [Element] {
9696
COSEAlgorithmIdentifier.allCases.map {
97-
Element.init(type: "public-key", alg: $0)
97+
Element.init(type: .publicKey, alg: $0)
9898
}
9999
}
100100
}

Sources/WebAuthn/Ceremonies/Registration/RegistrationCredential.swift

Lines changed: 7 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -22,8 +22,8 @@ public struct RegistrationCredential {
2222
/// The credential ID of the newly created credential.
2323
public let id: URLEncodedBase64
2424

25-
/// Value will always be "public-key" (for now)
26-
public let type: String
25+
/// Value will always be ``CredentialType/publicKey`` (for now)
26+
public let type: CredentialType
2727

2828
/// The raw credential ID of the newly created credential.
2929
public let rawID: [UInt8]
@@ -37,7 +37,7 @@ extension RegistrationCredential: Decodable {
3737
let container = try decoder.container(keyedBy: CodingKeys.self)
3838

3939
id = try container.decode(URLEncodedBase64.self, forKey: .id)
40-
type = try container.decode(String.self, forKey: .type)
40+
type = try container.decode(CredentialType.self, forKey: .type)
4141
guard let rawID = try container.decode(URLEncodedBase64.self, forKey: .rawID).decodedBytes else {
4242
throw DecodingError.dataCorruptedError(
4343
forKey: .rawID,
@@ -61,8 +61,8 @@ extension RegistrationCredential: Decodable {
6161
struct ParsedCredentialCreationResponse {
6262
let id: URLEncodedBase64
6363
let rawID: Data
64-
/// Value will always be "public-key" (for now)
65-
let type: String
64+
/// Value will always be ``CredentialType/publicKey`` (for now)
65+
let type: CredentialType
6666
let raw: AuthenticatorAttestationResponse
6767
let response: ParsedAuthenticatorAttestationResponse
6868

@@ -71,9 +71,8 @@ struct ParsedCredentialCreationResponse {
7171
id = rawResponse.id
7272
rawID = Data(rawResponse.rawID)
7373

74-
guard rawResponse.type == "public-key" else {
75-
throw WebAuthnError.invalidCredentialCreationType
76-
}
74+
guard rawResponse.type == .publicKey
75+
else { throw WebAuthnError.invalidCredentialCreationType }
7776
type = rawResponse.type
7877

7978
raw = rawResponse.attestationResponse
Lines changed: 29 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,29 @@
1+
//===----------------------------------------------------------------------===//
2+
//
3+
// This source file is part of the WebAuthn Swift open source project
4+
//
5+
// Copyright (c) 2024 the WebAuthn Swift project authors
6+
// Licensed under Apache License v2.0
7+
//
8+
// See LICENSE.txt for license information
9+
// See CONTRIBUTORS.txt for the list of WebAuthn Swift project authors
10+
//
11+
// SPDX-License-Identifier: Apache-2.0
12+
//
13+
//===----------------------------------------------------------------------===//
14+
15+
/// The type of credential being used.
16+
///
17+
/// Only ``CredentialType/publicKey`` is supported by WebAuthn.
18+
/// - SeeAlso: [Credential Management Level 1 Editor's Draft §2.1.2. Credential Type Registry](https://w3c.github.io/webappsec-credential-management/#sctn-cred-type-registry)
19+
/// - SeeAlso: [WebAuthn Level 3 Editor's Draft §5.1. PublicKeyCredential Interface](https://w3c.github.io/webauthn/#iface-pkcredential)
20+
public struct CredentialType: UnreferencedStringEnumeration {
21+
public var rawValue: String
22+
public init(_ rawValue: String) {
23+
self.rawValue = rawValue
24+
}
25+
26+
/// A public key credential.
27+
/// - SeeAlso: [WebAuthn Level 3 Editor's Draft §5.1. PublicKeyCredential Interface](https://w3c.github.io/webauthn/#iface-pkcredential)
28+
public static let publicKey: Self = "public-key"
29+
}

Sources/WebAuthn/WebAuthnManager.swift

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -167,7 +167,8 @@ public struct WebAuthnManager {
167167
credentialCurrentSignCount: UInt32,
168168
requireUserVerification: Bool = false
169169
) throws -> VerifiedAuthentication {
170-
guard credential.type == "public-key" else { throw WebAuthnError.invalidAssertionCredentialType }
170+
guard credential.type == .publicKey
171+
else { throw WebAuthnError.invalidAssertionCredentialType }
171172

172173
let parsedAssertion = try ParsedAuthenticatorAssertionResponse(from: credential.response)
173174
try parsedAssertion.verify(

Tests/WebAuthnTests/WebAuthnManagerAuthenticationTests.swift

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -35,7 +35,7 @@ final class WebAuthnManagerAuthenticationTests: XCTestCase {
3535
}
3636

3737
func testBeginAuthentication() async throws {
38-
let allowCredentials: [PublicKeyCredentialDescriptor] = [.init(type: "public-key", id: [1, 0, 2, 30])]
38+
let allowCredentials: [PublicKeyCredentialDescriptor] = [.init(type: .publicKey, id: [1, 0, 2, 30])]
3939
let options = try webAuthnManager.beginAuthentication(
4040
timeout: .seconds(1234),
4141
allowCredentials: allowCredentials,
@@ -166,7 +166,7 @@ final class WebAuthnManagerAuthenticationTests: XCTestCase {
166166
userHandle: [UInt8]? = "36323638424436452d303831452d344331312d413743332d334444304146333345433134".hexadecimal!,
167167
attestationObject: [UInt8]? = nil,
168168
authenticatorAttachment: AuthenticatorAttachment? = .platform,
169-
type: String = "public-key",
169+
type: CredentialType = .publicKey,
170170
expectedChallenge: [UInt8] = TestConstants.mockChallenge,
171171
credentialPublicKey: [UInt8] = TestCredentialPublicKeyBuilder().validMock().buildAsByteArray(),
172172
credentialCurrentSignCount: UInt32 = 0,

Tests/WebAuthnTests/WebAuthnManagerIntegrationTests.swift

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -65,7 +65,7 @@ final class WebAuthnManagerIntegrationTests: XCTestCase {
6565

6666
let registrationResponse = RegistrationCredential(
6767
id: mockCredentialID.base64URLEncodedString(),
68-
type: "public-key",
68+
type: .publicKey,
6969
rawID: mockCredentialID,
7070
attestationResponse: AuthenticatorAttestationResponse(
7171
clientDataJSON: mockClientDataJSON.jsonBytes,
@@ -89,14 +89,14 @@ final class WebAuthnManagerIntegrationTests: XCTestCase {
8989
XCTAssertEqual(credential.attestationClientDataJSON.challenge, mockChallenge.base64URLEncodedString())
9090
XCTAssertEqual(credential.isBackedUp, false)
9191
XCTAssertEqual(credential.signCount, 0)
92-
XCTAssertEqual(credential.type, "public-key")
92+
XCTAssertEqual(credential.type, .publicKey)
9393
XCTAssertEqual(credential.publicKey, mockCredentialPublicKey)
9494

9595
// Step 3.: Begin Authentication
9696
let authenticationTimeout: Duration = .seconds(4567)
9797
let userVerification: UserVerificationRequirement = .preferred
9898
let rememberedCredentials = [PublicKeyCredentialDescriptor(
99-
type: "public-key",
99+
type: .publicKey,
100100
id: [UInt8](URLEncodedBase64(credential.id).urlDecoded.decoded!)
101101
)]
102102

@@ -144,7 +144,7 @@ final class WebAuthnManagerIntegrationTests: XCTestCase {
144144
attestationObject: nil
145145
),
146146
authenticatorAttachment: .platform,
147-
type: "public-key"
147+
type: .publicKey
148148
)
149149

150150
// Step 4.: Finish Authentication

Tests/WebAuthnTests/WebAuthnManagerRegistrationTests.swift

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -38,7 +38,7 @@ final class WebAuthnManagerRegistrationTests: XCTestCase {
3838

3939
func testBeginRegistrationReturns() throws {
4040
let user = PublicKeyCredentialUserEntity.mock
41-
let publicKeyCredentialParameter = PublicKeyCredentialParameters(type: "public-key", alg: .algES256)
41+
let publicKeyCredentialParameter = PublicKeyCredentialParameters(type: .publicKey, alg: .algES256)
4242
let options = webAuthnManager.beginRegistration(
4343
user: user,
4444
publicKeyCredentialParameters: [publicKeyCredentialParameter]
@@ -371,7 +371,7 @@ final class WebAuthnManagerRegistrationTests: XCTestCase {
371371

372372
private func finishRegistration(
373373
challenge: [UInt8] = TestConstants.mockChallenge,
374-
type: String = "public-key",
374+
type: CredentialType = .publicKey,
375375
rawID: [UInt8] = "e0fac9350509f71748d83782ccaf6b4c1462c615c70e255da1344e40887c8fcd".hexadecimal!,
376376
clientDataJSON: [UInt8] = TestClientDataJSON().jsonBytes,
377377
attestationObject: [UInt8] = TestAttestationObjectBuilder().validMock().build().cborEncoded,

0 commit comments

Comments
 (0)