Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Expanded PublicKeyCredentialCreationOptions #76

Open
wants to merge 7 commits into
base: main
Choose a base branch
from
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,7 @@ import Foundation
///
/// - SeeAlso: https://www.w3.org/TR/webauthn-2/#dictionary-makecredentialoptions
public struct PublicKeyCredentialCreationOptions: Encodable, Sendable {

Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Please remove.

/// A byte array randomly generated by the Relying Party. Should be at least 16 bytes long to ensure sufficient
/// entropy.
///
Expand All @@ -39,13 +40,27 @@ public struct PublicKeyCredentialCreationOptions: Encodable, Sendable {

/// A time, in seconds, that the caller is willing to wait for the call to complete. This is treated as a
/// hint, and may be overridden by the client.
///
/// - Note: When encoded, this value is represented in milleseconds as a ``UInt32``.
Comment on lines -42 to -43
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Please remove

public let timeout: Duration?

/// Sets the Relying Party's preference for attestation conveyance. At the time of writing only `none` is
/// supported.
public let attestation: AttestationConveyancePreference

/// Use this enumeration to communicate hints to the user-agent about how a request may be best completed. These hints are not requirements, and do not bind the user-agent, but may guide it in providing the best experience by using contextual information that the Relying Party has about the request.
/// https://www.w3.org/TR/webauthn-3/#enum-hints
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Minor nit, but would be good to follow this convention for references:

/// - SeeAlso: [WebAuthn Leven 3 Editor's Draft §6. WebAuthn Authenticator Model](https://w3c.github.io/webauthn/#aaguid)

let hints: [Hint]

/// This client registration extension facilitates reporting certain credential properties known by the client to the requesting WebAuthn Relying Party upon creation of a public key credential source as a result of a registration ceremony.
/// https://www.w3.org/TR/webauthn-2/#sctn-extensions-inputs-outputs
let extensions: Extensions

/// This member is intended for use by Relying Parties that wish to limit the creation of multiple credentials for the same account on a single authenticator
/// https://www.w3.org/TR/webauthn-2/#dom-publickeycredentialcreationoptions-excludecredentials
let excludeCredentials: [PublicKeyCredentialDescriptor]

/// This member is intended for use by Relying Parties that wish to select the appropriate authenticators to participate in the create() operation.
/// https://www.w3.org/TR/webauthn-3/#dom-publickeycredentialcreationoptions-authenticatorselection
let authenticatorSelection: AuthenticatorSelectionCriteria

public func encode(to encoder: any Encoder) throws {
var container = encoder.container(keyedBy: CodingKeys.self)
Expand All @@ -56,6 +71,10 @@ public struct PublicKeyCredentialCreationOptions: Encodable, Sendable {
try container.encode(publicKeyCredentialParameters, forKey: .publicKeyCredentialParameters)
try container.encodeIfPresent(timeout?.milliseconds, forKey: .timeout)
try container.encode(attestation, forKey: .attestation)
try container.encode(authenticatorSelection, forKey: .authenticatorSelection)
try container.encode(hints, forKey: .hints)
try container.encode(extensions, forKey: .extensions)
try container.encode(excludeCredentials, forKey: .excludeCredentials)
}

private enum CodingKeys: String, CodingKey {
Expand All @@ -65,6 +84,10 @@ public struct PublicKeyCredentialCreationOptions: Encodable, Sendable {
case publicKeyCredentialParameters = "pubKeyCredParams"
case timeout
case attestation
case authenticatorSelection
case hints
case extensions
case excludeCredentials
}
}

Expand Down Expand Up @@ -156,3 +179,60 @@ public struct PublicKeyCredentialUserEntity: Encodable, Sendable {
case displayName
}
}

public struct Hint: UnreferencedStringEnumeration, Sendable {
public var rawValue: String
public init(_ rawValue: String) {
self.rawValue = rawValue
}

/// Indicates that the Relying Party believes that users will satisfy this request with a platform authenticator attached to the client device.
public static let clientDevice: Self = "client-device"

/// Indicates that the Relying Party believes that users will satisfy this request with a physical security key
public static let securityKey: Self = "security-key"

/// Indicates that the Relying Party believes that users will satisfy this request with general-purpose authenticators such as smartphones.
public static let hybrid: Self = "hybrid"
}


struct Extensions: Encodable {
/// Indicate that this extension is requested by the Relying Party.
/// https://www.w3.org/TR/webauthn-3/#sctn-authenticator-credential-properties-extension
let credProps: Bool
}
Comment on lines +200 to +204
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This doesn't feel like the best Swift API for this, though not having looked deeper, I don't have a suggestion for improvement yet.


struct AuthenticatorSelectionCriteria: Encodable {
/// Specifies the extent to which the Relying Party desires to create a client-side discoverable credential.
/// https://www.w3.org/TR/webauthn-3/#dom-authenticatorselectioncriteria-residentkey
let residentKey: ResidentKeyRequirement

/// Relying Parties SHOULD set this to true if, and only if, `residentKey` is set to `required`.
/// https://www.w3.org/TR/webauthn-3/#dom-authenticatorselectioncriteria-requireresidentkey
let requireResidentKey: Bool

/// This member specifies the Relying Party's requirements regarding user verification for the create() operation.
/// https://www.w3.org/TR/webauthn-3/#dom-authenticatorselectioncriteria-userverification
let userVerification: UserVerificationRequirement
}
Comment on lines +200 to +218
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

These should be made public, and probably placed in their own files



public struct ResidentKeyRequirement: UnreferencedStringEnumeration, Sendable {
public var rawValue: String
public init(_ rawValue: String) {
self.rawValue = rawValue
}

/// The Relying Party requires a client-side discoverable credential.
/// https://www.w3.org/TR/webauthn-3/#dom-residentkeyrequirement-required
public static let required: Self = "required"

/// The Relying Party strongly prefers creating a client-side discoverable credential, but will accept a server-side credential.
/// https://www.w3.org/TR/webauthn-3/#dom-residentkeyrequirement-preferred
public static let preferred: Self = "preferred"

/// The Relying Party prefers creating a server-side credential, but will accept a client-side discoverable credential.
/// https://www.w3.org/TR/webauthn-3/#dom-residentkeyrequirement-discouraged
public static let discouraged: Self = "discouraged"
}
8 changes: 7 additions & 1 deletion Sources/WebAuthn/WebAuthnManager.swift
Original file line number Diff line number Diff line change
Expand Up @@ -69,7 +69,13 @@ public struct WebAuthnManager: Sendable {
relyingParty: .init(id: configuration.relyingPartyID, name: configuration.relyingPartyName),
publicKeyCredentialParameters: publicKeyCredentialParameters,
timeout: timeout,
attestation: attestation
attestation: attestation,
hints: [],
extensions: .init(credProps: true),
excludeCredentials: [],
authenticatorSelection: .init(residentKey: .preferred,
requireResidentKey: false,
userVerification: .preferred)
Comment on lines +72 to +78
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I'll need to review the spec to make sure these won't cause issues in the default case, though at a glance, this could be breaking as it specifies more than what was there currently for all cases.

)
}

Expand Down