From 26f99eb3574e38467741d75bbdaa89f33f6832d4 Mon Sep 17 00:00:00 2001 From: Chris Salvador Date: Mon, 29 Sep 2025 22:02:24 -0700 Subject: [PATCH 1/6] Convert AuthenticatorTransport from enum to struct --- .../PublicKeyCredentialRequestOptions.swift | 36 +++++++++++++++---- 1 file changed, 30 insertions(+), 6 deletions(-) diff --git a/Sources/WebAuthn/Ceremonies/Authentication/PublicKeyCredentialRequestOptions.swift b/Sources/WebAuthn/Ceremonies/Authentication/PublicKeyCredentialRequestOptions.swift index 81340ed..44d0995 100644 --- a/Sources/WebAuthn/Ceremonies/Authentication/PublicKeyCredentialRequestOptions.swift +++ b/Sources/WebAuthn/Ceremonies/Authentication/PublicKeyCredentialRequestOptions.swift @@ -70,20 +70,40 @@ public struct PublicKeyCredentialRequestOptions: Encodable, Sendable { public struct PublicKeyCredentialDescriptor: Equatable, Encodable, Sendable { /// Defines hints as to how clients might communicate with a particular authenticator in order to obtain an /// assertion for a specific credential - public enum AuthenticatorTransport: String, Equatable, Encodable, Sendable { + public struct AuthenticatorTransport: RawRepresentable, Equatable, Hashable, Encodable, Sendable { + public let rawValue: String + + public init?(rawValue: String) { + switch rawValue { + case "usb", "nfc", "ble", "hybrid", "internal": + self.rawValue = rawValue + default: + return nil + } + } + + private init(_ rawValue: String) { + self.rawValue = rawValue + } + + public func encode(to encoder: any Encoder) throws { + var container = encoder.singleValueContainer() + try container.encode(rawValue) + } + /// Indicates the respective authenticator can be contacted over removable USB. - case usb + public static let usb = AuthenticatorTransport("usb") /// Indicates the respective authenticator can be contacted over Near Field Communication (NFC). - case nfc + public static let nfc = AuthenticatorTransport("nfc") /// Indicates the respective authenticator can be contacted over Bluetooth Smart (Bluetooth Low Energy / BLE). - case ble + public static let ble = AuthenticatorTransport("ble") /// Indicates the respective authenticator can be contacted using a combination of (often separate) /// data-transport and proximity mechanisms. This supports, for example, authentication on a desktop /// computer using a smartphone. - case hybrid + public static let hybrid = AuthenticatorTransport("hybrid") /// Indicates the respective authenticator is contacted using a client device-specific transport, i.e., it is /// a platform authenticator. These authenticators are not removable from the client device. - case `internal` + public static let `internal` = AuthenticatorTransport("internal") } /// Will always be ``CredentialType/publicKey`` @@ -122,6 +142,10 @@ public struct PublicKeyCredentialDescriptor: Equatable, Encodable, Sendable { } } +extension PublicKeyCredentialDescriptor.AuthenticatorTransport: CustomStringConvertible { + public var description: String { rawValue } +} + /// The Relying Party may require user verification for some of its operations but not for others, and may use this /// type to express its needs. public enum UserVerificationRequirement: String, Encodable, Sendable { From 486057714eabd6e4b13c132de2422da1788647bf Mon Sep 17 00:00:00 2001 From: Chris Salvador Date: Mon, 29 Sep 2025 22:03:22 -0700 Subject: [PATCH 2/6] Convert UserVerificationRequirement from enum to struct --- .../PublicKeyCredentialRequestOptions.swift | 33 ++++++++++++++++--- 1 file changed, 29 insertions(+), 4 deletions(-) diff --git a/Sources/WebAuthn/Ceremonies/Authentication/PublicKeyCredentialRequestOptions.swift b/Sources/WebAuthn/Ceremonies/Authentication/PublicKeyCredentialRequestOptions.swift index 44d0995..290069d 100644 --- a/Sources/WebAuthn/Ceremonies/Authentication/PublicKeyCredentialRequestOptions.swift +++ b/Sources/WebAuthn/Ceremonies/Authentication/PublicKeyCredentialRequestOptions.swift @@ -148,13 +148,38 @@ extension PublicKeyCredentialDescriptor.AuthenticatorTransport: CustomStringConv /// The Relying Party may require user verification for some of its operations but not for others, and may use this /// type to express its needs. -public enum UserVerificationRequirement: String, Encodable, Sendable { +public struct UserVerificationRequirement: RawRepresentable, Equatable, Hashable, Encodable, Sendable { + public let rawValue: String + + public init?(rawValue: String) { + switch rawValue { + case "required", "preferred", "discouraged": + self.rawValue = rawValue + default: + return nil + } + } + + private init(_ rawValue: String) { + self.rawValue = rawValue + } + + public func encode(to encoder: Encoder) throws { + var container = encoder.singleValueContainer() + try container.encode(rawValue) + } + /// The Relying Party requires user verification for the operation and will fail the overall ceremony if the /// user wasn't verified. - case required + public static let required = UserVerificationRequirement("required") /// The Relying Party prefers user verification for the operation if possible, but will not fail the operation. - case preferred + public static let preferred = UserVerificationRequirement("preferred") /// The Relying Party does not want user verification employed during the operation (e.g., in the interest of /// minimizing disruption to the user interaction flow). - case discouraged + public static let discouraged = UserVerificationRequirement("discouraged") } + +extension UserVerificationRequirement: CustomStringConvertible { + public var description: String { rawValue } +} + From 097ce54c9563f784cc4f559661e046291326c28e Mon Sep 17 00:00:00 2001 From: Chris Salvador Date: Mon, 29 Sep 2025 22:05:42 -0700 Subject: [PATCH 3/6] Convert CredentialDeviceType from enum to struct --- .../VerifiedAuthentication.swift | 35 +++++++++++++++++-- 1 file changed, 32 insertions(+), 3 deletions(-) diff --git a/Sources/WebAuthn/Ceremonies/Authentication/VerifiedAuthentication.swift b/Sources/WebAuthn/Ceremonies/Authentication/VerifiedAuthentication.swift index 723b777..81ba326 100644 --- a/Sources/WebAuthn/Ceremonies/Authentication/VerifiedAuthentication.swift +++ b/Sources/WebAuthn/Ceremonies/Authentication/VerifiedAuthentication.swift @@ -15,9 +15,34 @@ import Foundation /// On successful authentication, this structure contains a summary of the authentication flow public struct VerifiedAuthentication: Sendable { - public enum CredentialDeviceType: String, Sendable { - case singleDevice = "single_device" - case multiDevice = "multi_device" + public struct CredentialDeviceType: RawRepresentable, Equatable, Hashable, Codable, Sendable { + public let rawValue: String + + public init?(rawValue: String) { + switch rawValue { + case "single_device", "multi_device": + self.rawValue = rawValue + default: + return nil + } + } + + private init(_ rawValue: String) { + self.rawValue = rawValue + } + + public init(from decoder: Decoder) throws { + let container = try decoder.singleValueContainer() + rawValue = try container.decode(String.self) + } + + public func encode(to encoder: Encoder) throws { + var container = encoder.singleValueContainer() + try container.encode(rawValue) + } + + public static let singleDevice = CredentialDeviceType("single_device") + public static let multiDevice = CredentialDeviceType("multi_device") } /// The credential id associated with the public key @@ -30,3 +55,7 @@ public struct VerifiedAuthentication: Sendable { /// Whether the authenticator is known to be backed up currently public let credentialBackedUp: Bool } + +extension VerifiedAuthentication.CredentialDeviceType: CustomStringConvertible { + public var description: String { rawValue } +} From cda9a5cc699eb04fb261ea6fda43e24aff2920df Mon Sep 17 00:00:00 2001 From: Chris Salvador Date: Mon, 29 Sep 2025 22:06:48 -0700 Subject: [PATCH 4/6] Convert AttestationConveyancePreference from enum to struct --- .../AttestationConveyancePreference.swift | 34 ++++++++++++++++--- 1 file changed, 29 insertions(+), 5 deletions(-) diff --git a/Sources/WebAuthn/Ceremonies/Registration/AttestationConveyancePreference.swift b/Sources/WebAuthn/Ceremonies/Registration/AttestationConveyancePreference.swift index 770af12..e17e8f9 100644 --- a/Sources/WebAuthn/Ceremonies/Registration/AttestationConveyancePreference.swift +++ b/Sources/WebAuthn/Ceremonies/Registration/AttestationConveyancePreference.swift @@ -14,10 +14,34 @@ /// Options to specify the Relying Party's preference regarding attestation conveyance during credential generation. /// /// Currently only supports `none`. -public enum AttestationConveyancePreference: String, Encodable, Sendable { +public struct AttestationConveyancePreference: RawRepresentable, Equatable, Hashable, Encodable, Sendable { + public let rawValue: String + + public init?(rawValue: String) { + switch rawValue { + case "none": + self.rawValue = rawValue + default: + return nil + } + } + + private init(_ rawValue: String) { + self.rawValue = rawValue + } + + public func encode(to encoder: Encoder) throws { + var container = encoder.singleValueContainer() + try container.encode(rawValue) + } + /// Indicates the Relying Party is not interested in authenticator attestation. - case none - // case indirect - // case direct - // case enterprise + public static let none = AttestationConveyancePreference("none") +// public static let indirect = AttestationConveyancePreference("indirect") +// public static let direct = AttestationConveyancePreference("direct") +// public static let enterprise = AttestationConveyancePreference("enterprise") +} + +extension AttestationConveyancePreference: CustomStringConvertible { + public var description: String { rawValue } } From fd6db581f512cda8e8662d012fe2ee817a04a3f8 Mon Sep 17 00:00:00 2001 From: Chris Salvador Date: Mon, 29 Sep 2025 22:08:53 -0700 Subject: [PATCH 5/6] Convert AttestationFormat from enum to struct --- .../Registration/AttestationFormat.swift | 45 +++++++++++++++---- 1 file changed, 37 insertions(+), 8 deletions(-) diff --git a/Sources/WebAuthn/Ceremonies/Registration/AttestationFormat.swift b/Sources/WebAuthn/Ceremonies/Registration/AttestationFormat.swift index 521fd38..a046ef1 100644 --- a/Sources/WebAuthn/Ceremonies/Registration/AttestationFormat.swift +++ b/Sources/WebAuthn/Ceremonies/Registration/AttestationFormat.swift @@ -11,12 +11,41 @@ // //===----------------------------------------------------------------------===// -public enum AttestationFormat: String, RawRepresentable, Equatable, Sendable { - case packed - case tpm - case androidKey = "android-key" - case androidSafetynet = "android-safetynet" - case fidoU2F = "fido-u2f" - case apple - case none +public struct AttestationFormat: RawRepresentable, Equatable, Hashable, Codable, Sendable { + public let rawValue: String + + public init?(rawValue: String) { + switch rawValue { + case "packed", "tpm", "android-key", "android-safetynet", "fido-u2f", "apple", "none": + self.rawValue = rawValue + default: + return nil + } + } + + private init(_ rawValue: String) { + self.rawValue = rawValue + } + + public init(from decoder: Decoder) throws { + let container = try decoder.singleValueContainer() + rawValue = try container.decode(String.self) + } + + public func encode(to encoder: Encoder) throws { + var container = encoder.singleValueContainer() + try container.encode(rawValue) + } + + public static let packed = AttestationFormat("packed") + public static let tpm = AttestationFormat("tpm") + public static let androidKey = AttestationFormat("android-key") + public static let androidSafetynet = AttestationFormat("android-safetynet") + public static let fidoU2F = AttestationFormat("fido-u2f") + public static let apple = AttestationFormat("apple") + public static let none = AttestationFormat("none") +} + +extension AttestationFormat: CustomStringConvertible { + public var description: String { rawValue } } From aaf902d8fe2e89f1daaf069d95bc0815ba2340e3 Mon Sep 17 00:00:00 2001 From: Chris Salvador Date: Mon, 29 Sep 2025 22:09:53 -0700 Subject: [PATCH 6/6] Convert CeremonyType from enum to struct --- .../Shared/CollectedClientData.swift | 35 +++++++++++++++++-- 1 file changed, 32 insertions(+), 3 deletions(-) diff --git a/Sources/WebAuthn/Ceremonies/Shared/CollectedClientData.swift b/Sources/WebAuthn/Ceremonies/Shared/CollectedClientData.swift index 88ca7f3..db562c7 100644 --- a/Sources/WebAuthn/Ceremonies/Shared/CollectedClientData.swift +++ b/Sources/WebAuthn/Ceremonies/Shared/CollectedClientData.swift @@ -22,9 +22,34 @@ public struct CollectedClientData: Codable, Hashable, Sendable { case originDoesNotMatch } - public enum CeremonyType: String, Codable, Sendable { - case create = "webauthn.create" - case assert = "webauthn.get" + public struct CeremonyType: RawRepresentable, Equatable, Hashable, Codable, Sendable { + public let rawValue: String + + public init?(rawValue: String) { + switch rawValue { + case "webauthn.create", "webauthn.get": + self.rawValue = rawValue + default: + return nil + } + } + + private init(_ rawValue: String) { + self.rawValue = rawValue + } + + public init(from decoder: Decoder) throws { + let container = try decoder.singleValueContainer() + rawValue = try container.decode(String.self) + } + + public func encode(to encoder: Encoder) throws { + var container = encoder.singleValueContainer() + try container.encode(rawValue) + } + + public static let create = CeremonyType("webauthn.create") + public static let assert = CeremonyType("webauthn.get") } /// Contains the string "webauthn.create" when creating new credentials, @@ -42,3 +67,7 @@ public struct CollectedClientData: Codable, Hashable, Sendable { guard origin == relyingPartyOrigin else { throw .originDoesNotMatch } } } + +extension CollectedClientData.CeremonyType: CustomStringConvertible { + public var description: String { rawValue } +}