Skip to content

Commit 4869699

Browse files
authored
Merge pull request #48 from dimitribouniol/dimitri/unreferenced-string-enumeration
Unreferenced String Enumeration
2 parents ff8e863 + de47752 commit 4869699

12 files changed

+134
-34
lines changed

Sources/WebAuthn/Ceremonies/Authentication/AuthenticationCredential.swift

Lines changed: 5 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -29,10 +29,10 @@ public struct AuthenticationCredential {
2929

3030
/// Reports the authenticator attachment modality in effect at the time the navigator.credentials.create() or
3131
/// navigator.credentials.get() methods successfully complete
32-
public let authenticatorAttachment: String?
32+
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 {
@@ -42,8 +42,8 @@ extension AuthenticationCredential: Decodable {
4242
id = try container.decode(URLEncodedBase64.self, forKey: .id)
4343
rawID = try container.decodeBytesFromURLEncodedBase64(forKey: .rawID)
4444
response = try container.decode(AuthenticatorAssertionResponse.self, forKey: .response)
45-
authenticatorAttachment = try container.decodeIfPresent(String.self, forKey: .authenticatorAttachment)
46-
type = try container.decode(String.self, forKey: .type)
45+
authenticatorAttachment = try container.decodeIfPresent(AuthenticatorAttachment.self, forKey: .authenticatorAttachment)
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: 34 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,34 @@
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+
/// An authenticators' attachment modalities.
16+
///
17+
/// Relying Parties use this to express a preferred authenticator attachment modality when registering a credential, and clients use this to report the authenticator attachment modality used to complete a registration or authentication ceremony.
18+
/// - SeeAlso: [WebAuthn Level 3 Editor's Draft §5.4.5. Authenticator Attachment Enumeration (enum AuthenticatorAttachment)](https://w3c.github.io/webauthn/#enum-attachment)
19+
/// - SeeAlso: [WebAuthn Level 3 Editor's Draft §6.2.1. Authenticator Attachment Modality](https://w3c.github.io/webauthn/#sctn-authenticator-attachment-modality)
20+
///
21+
public struct AuthenticatorAttachment: UnreferencedStringEnumeration {
22+
public var rawValue: String
23+
public init(_ rawValue: String) {
24+
self.rawValue = rawValue
25+
}
26+
27+
/// A platform authenticator is attached using a client device-specific transport, called platform attachment, and is usually not removable from the client device. A public key credential bound to a platform authenticator is called a platform credential.
28+
/// - SeeAlso: [WebAuthn Level 3 Editor's Draft §6.2.1. Authenticator Attachment Modality](https://w3c.github.io/webauthn/#platform-attachment)
29+
public static let platform: Self = "platform"
30+
31+
/// A roaming authenticator is attached using cross-platform transports, called cross-platform attachment. Authenticators of this class are removable from, and can "roam" between, client devices. A public key credential bound to a roaming authenticator is called a roaming credential.
32+
/// - SeeAlso: [WebAuthn Level 3 Editor's Draft §6.2.1. Authenticator Attachment Modality](https://w3c.github.io/webauthn/#cross-platform-attachment)
33+
public static let crossPlatform: Self = "cross-platform"
34+
}
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+
}
Lines changed: 33 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,33 @@
1+
//===----------------------------------------------------------------------===//
2+
//
3+
// This source file is part of the WebAuthn Swift open source project
4+
//
5+
// Copyright (c) 2022 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+
/// An enumeration type that is not referenced by other parts of the Web IDL because that would preclude other values from being used without updating the specification and its implementations.
16+
/// - SeeAlso: [WebAuthn Level 3 Editor's Draft §2.1.1. Enumerations as DOMString types](https://w3c.github.io/webauthn/#sct-domstring-backwards-compatibility)
17+
public protocol UnreferencedStringEnumeration: RawRepresentable, Codable, ExpressibleByStringLiteral, Hashable, Comparable where RawValue == String {
18+
init(_ rawValue: RawValue)
19+
}
20+
21+
extension UnreferencedStringEnumeration {
22+
public init(rawValue: RawValue) {
23+
self.init(rawValue)
24+
}
25+
26+
public init(stringLiteral value: String) {
27+
self.init(value)
28+
}
29+
30+
public static func < (lhs: Self, rhs: Self) -> Bool {
31+
lhs.rawValue < rhs.rawValue
32+
}
33+
}

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: 3 additions & 3 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,
@@ -165,8 +165,8 @@ final class WebAuthnManagerAuthenticationTests: XCTestCase {
165165
signature: [UInt8] = TestECCKeyPair.signature,
166166
userHandle: [UInt8]? = "36323638424436452d303831452d344331312d413743332d334444304146333345433134".hexadecimal!,
167167
attestationObject: [UInt8]? = nil,
168-
authenticatorAttachment: String? = "platform",
169-
type: String = "public-key",
168+
authenticatorAttachment: AuthenticatorAttachment? = .platform,
169+
type: CredentialType = .publicKey,
170170
expectedChallenge: [UInt8] = TestConstants.mockChallenge,
171171
credentialPublicKey: [UInt8] = TestCredentialPublicKeyBuilder().validMock().buildAsByteArray(),
172172
credentialCurrentSignCount: UInt32 = 0,

0 commit comments

Comments
 (0)