Skip to content

Commit ffa421c

Browse files
chore(api): mark growable public response and spec types non_exhaustive (#293)
Marks the public types that model device responses and protocol data as non-exhaustive, so adding fields or variants after 1.0 does not break downstream code. Types that callers construct directly are left exhaustive to keep them ergonomic to build. This is groundwork for committing to a stable API.
1 parent 537aca1 commit ffa421c

10 files changed

Lines changed: 39 additions & 4 deletions

File tree

libwebauthn/src/ops/webauthn/make_credential.rs

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -652,7 +652,8 @@ pub struct MakeCredentialsRequestExtensions {
652652
pub type MakeCredentialsResponseExtensions = Ctap2MakeCredentialsResponseExtensions;
653653

654654
impl MakeCredentialRequest {
655-
pub fn dummy() -> Self {
655+
#[cfg(test)]
656+
pub(crate) fn dummy() -> Self {
656657
Self {
657658
challenge: Vec::new(),
658659
origin: "example.org".to_owned(),

libwebauthn/src/proto/ctap1/model.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -86,7 +86,7 @@ impl Ctap1RegisterRequest {
8686
}
8787
}
8888

89-
pub fn dummy(timeout: Duration) -> Self {
89+
pub(crate) fn dummy(timeout: Duration) -> Self {
9090
Ctap1RegisterRequest {
9191
version: Ctap1Version::U2fV2,
9292
app_id_hash: vec![0; 32],

libwebauthn/src/proto/ctap2/model.rs

Lines changed: 24 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -50,8 +50,29 @@ pub use credential_management::{
5050
mod large_blobs;
5151
pub use large_blobs::{Ctap2LargeBlobsRequest, Ctap2LargeBlobsResponse};
5252

53+
/// CTAP2 command codes; `#[non_exhaustive]` so consumers handle unknown variants.
54+
///
55+
/// ```compile_fail
56+
/// use libwebauthn::proto::ctap2::Ctap2CommandCode;
57+
/// let code = Ctap2CommandCode::AuthenticatorGetInfo;
58+
/// let _value: u8 = match code {
59+
/// Ctap2CommandCode::AuthenticatorMakeCredential => 0x01,
60+
/// Ctap2CommandCode::AuthenticatorGetAssertion => 0x02,
61+
/// Ctap2CommandCode::AuthenticatorGetInfo => 0x04,
62+
/// Ctap2CommandCode::AuthenticatorClientPin => 0x06,
63+
/// Ctap2CommandCode::AuthenticatorGetNextAssertion => 0x08,
64+
/// Ctap2CommandCode::AuthenticatorBioEnrollment => 0x09,
65+
/// Ctap2CommandCode::AuthenticatorBioEnrollmentPreview => 0x40,
66+
/// Ctap2CommandCode::AuthenticatorCredentialManagement => 0x0A,
67+
/// Ctap2CommandCode::AuthenticatorCredentialManagementPreview => 0x41,
68+
/// Ctap2CommandCode::AuthenticatorSelection => 0x0B,
69+
/// Ctap2CommandCode::AuthenticatorLargeBlobs => 0x0C,
70+
/// Ctap2CommandCode::AuthenticatorConfig => 0x0D,
71+
/// };
72+
/// ```
5373
#[derive(Debug, IntoPrimitive, TryFromPrimitive, Copy, Clone, PartialEq, Serialize_repr)]
5474
#[repr(u8)]
75+
#[non_exhaustive]
5576
pub enum Ctap2CommandCode {
5677
AuthenticatorMakeCredential = 0x01,
5778
AuthenticatorGetAssertion = 0x02,
@@ -78,7 +99,7 @@ pub struct Ctap2PublicKeyCredentialRpEntity {
7899
}
79100

80101
impl Ctap2PublicKeyCredentialRpEntity {
81-
pub fn dummy() -> Self {
102+
pub(crate) fn dummy() -> Self {
82103
Self {
83104
id: String::from(".dummy"),
84105
name: Some(String::from(".dummy")),
@@ -109,7 +130,7 @@ pub struct Ctap2PublicKeyCredentialUserEntity {
109130
}
110131

111132
impl Ctap2PublicKeyCredentialUserEntity {
112-
pub fn dummy() -> Self {
133+
pub(crate) fn dummy() -> Self {
113134
Self {
114135
id: ByteBuf::from([1]),
115136
name: Some(String::from("dummy")),
@@ -150,6 +171,7 @@ pub enum Ctap2PublicKeyCredentialType {
150171
/// AuthenticatorTransport from a credential descriptor. Unknown values are kept in `Other` so they pass through unchanged.
151172
#[derive(Debug, Clone, PartialEq, Eq, Hash, Serialize, Deserialize)]
152173
#[serde(from = "String", into = "String")]
174+
#[non_exhaustive]
153175
pub enum Ctap2Transport {
154176
Ble,
155177
Nfc,

libwebauthn/src/proto/ctap2/model/bio_enrollment.rs

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -68,6 +68,7 @@ pub struct Ctap2BioEnrollmentParams {
6868
}
6969

7070
#[derive(Debug, Default, Clone, DeserializeIndexed)]
71+
#[non_exhaustive]
7172
pub struct Ctap2BioEnrollmentResponse {
7273
// modality (0x01) Unsigned Integer Optional The user verification modality.
7374
#[serde(skip_serializing_if = "Option::is_none")]
@@ -145,12 +146,14 @@ pub enum Ctap2LastEnrollmentSampleStatus {
145146

146147
#[repr(u64)]
147148
#[derive(Debug, Clone, FromPrimitive, PartialEq, Serialize_repr, Deserialize_repr)]
149+
#[non_exhaustive]
148150
pub enum Ctap2BioEnrollmentModality {
149151
Fingerprint = 0x01, // Fingerprint was too high.
150152
}
151153

152154
#[repr(u64)]
153155
#[derive(Debug, Clone, FromPrimitive, PartialEq, Serialize_repr, Deserialize_repr)]
156+
#[non_exhaustive]
154157
pub enum Ctap2BioEnrollmentFingerprintKind {
155158
Touch = 0x01,
156159
Swipe = 0x02,

libwebauthn/src/proto/ctap2/model/client_pin.rs

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -224,6 +224,7 @@ pub enum Ctap2PinUvAuthProtocolCommand {
224224

225225
#[cfg_attr(test, derive(SerializeIndexed))]
226226
#[derive(Debug, Clone, Default, DeserializeIndexed)]
227+
#[non_exhaustive]
227228
pub struct Ctap2ClientPinResponse {
228229
/// keyAgreement (0x01)
229230
#[serde(skip_serializing_if = "Option::is_none")]

libwebauthn/src/proto/ctap2/model/credential_management.rs

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -89,6 +89,7 @@ pub struct Ctap2CredentialManagementParams {
8989
}
9090

9191
#[derive(Debug, Default, Clone, DeserializeIndexed)]
92+
#[non_exhaustive]
9293
pub struct Ctap2CredentialManagementResponse {
9394
// existingResidentCredentialsCount (0x01) Unsigned Integer Number of existing discoverable credentials present on the authenticator.
9495
#[serde(skip_serializing_if = "Option::is_none")]

libwebauthn/src/proto/ctap2/model/get_assertion.rs

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -92,6 +92,7 @@ pub struct AppleAnonymousAttestationStmt {
9292

9393
#[derive(Debug, Clone, Deserialize, Serialize)]
9494
#[serde(untagged)]
95+
#[non_exhaustive]
9596
pub enum Ctap2AttestationStatement {
9697
PackedOrAndroid(PackedAttestationStmt),
9798
Tpm(TpmAttestationStmt),
@@ -512,6 +513,7 @@ pub struct CalculatedHMACGetSecretInput {
512513
}
513514

514515
#[derive(Debug, Clone, DeserializeIndexed)]
516+
#[non_exhaustive]
515517
pub struct Ctap2GetAssertionResponse {
516518
#[serde(skip_serializing_if = "Option::is_none")]
517519
#[serde(index = 0x01)]
@@ -687,6 +689,7 @@ impl Ctap2GetAssertionResponse {
687689

688690
#[derive(Debug, Default, Clone, Serialize, Deserialize)]
689691
#[serde(rename_all = "camelCase")]
692+
#[non_exhaustive]
690693
pub struct Ctap2GetAssertionResponseExtensions {
691694
// Stored credBlob
692695
#[serde(default, skip_serializing_if = "Option::is_none", with = "serde_bytes")]

libwebauthn/src/proto/ctap2/model/get_info.rs

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,7 @@ use super::{Ctap2CredentialType, Ctap2UserVerificationOperation};
1010

1111
#[cfg_attr(test, derive(SerializeIndexed))]
1212
#[derive(Debug, Clone, DeserializeIndexed, Default)]
13+
#[non_exhaustive]
1314
pub struct Ctap2GetInfoResponse {
1415
/// versions (0x01)
1516
#[serde(index = 0x01)]

libwebauthn/src/proto/ctap2/model/large_blobs.rs

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -88,6 +88,7 @@ impl Ctap2LargeBlobsRequest {
8888

8989
#[cfg_attr(test, derive(SerializeIndexed))]
9090
#[derive(Debug, Default, Clone, DeserializeIndexed)]
91+
#[non_exhaustive]
9192
pub struct Ctap2LargeBlobsResponse {
9293
#[serde(skip_serializing_if = "Option::is_none")]
9394
#[serde(index = 0x01)]

libwebauthn/src/proto/ctap2/model/make_credential.rs

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -357,6 +357,7 @@ impl Ctap2MakeCredentialsRequestExtensions {
357357
}
358358

359359
#[derive(Debug, Clone, DeserializeIndexed)]
360+
#[non_exhaustive]
360361
pub struct Ctap2MakeCredentialResponse {
361362
#[serde(index = 0x01)]
362363
pub format: String,
@@ -469,6 +470,7 @@ impl Ctap2UserVerifiableRequest for Ctap2MakeCredentialRequest {
469470

470471
#[derive(Debug, Default, Clone, Serialize, Deserialize)]
471472
#[serde(rename_all = "camelCase")]
473+
#[non_exhaustive]
472474
pub struct Ctap2MakeCredentialsResponseExtensions {
473475
// If storing credBlob was successful
474476
#[serde(default, skip_serializing_if = "Option::is_none")]

0 commit comments

Comments
 (0)