webauthn_rp

WebAuthn Level 3 RP library.
git clone https://git.philomathiclife.com/repos/webauthn_rp
Log | Files | Refs | README

ser.rs (47984B)


      1 extern crate alloc;
      2 use super::{
      3     AllAcceptedCredentialsOptions, AuthTransports, AuthenticatorAttachment, AuthenticatorTransport,
      4     Challenge, CredentialId, CurrentUserDetailsOptions, Origin, SentChallenge,
      5 };
      6 use alloc::borrow::Cow;
      7 use core::{
      8     fmt::{self, Formatter},
      9     marker::PhantomData,
     10 };
     11 use data_encoding::BASE64URL_NOPAD;
     12 use serde::{
     13     de::{Deserialize, Deserializer, Error, IgnoredAny, MapAccess, SeqAccess, Unexpected, Visitor},
     14     ser::{Serialize, SerializeSeq as _, SerializeStruct as _, Serializer},
     15 };
     16 /// [`"ble"`](https://www.w3.org/TR/webauthn-3/#dom-authenticatortransport-ble).
     17 const BLE: &str = "ble";
     18 /// [`"hybrid"`](https://www.w3.org/TR/webauthn-3/#dom-authenticatortransport-hybrid).
     19 const HYBRID: &str = "hybrid";
     20 /// [`"internal"`](https://www.w3.org/TR/webauthn-3/#dom-authenticatortransport-internal).
     21 const INTERNAL: &str = "internal";
     22 /// [`"nfc"`](https://www.w3.org/TR/webauthn-3/#dom-authenticatortransport-nfc).
     23 const NFC: &str = "nfc";
     24 /// [`"smart-card"`](https://www.w3.org/TR/webauthn-3/#dom-authenticatortransport-smart-card).
     25 const SMART_CARD: &str = "smart-card";
     26 /// [`"usb"`](https://www.w3.org/TR/webauthn-3/#dom-authenticatortransport-usb).
     27 const USB: &str = "usb";
     28 impl Serialize for AuthenticatorTransport {
     29     /// Serializes `self` as
     30     /// [`AuthenticatorTransport`](https://www.w3.org/TR/webauthn-3/#enumdef-authenticatortransport).
     31     ///
     32     /// # Examples
     33     ///
     34     /// ```
     35     /// # use webauthn_rp::response::AuthenticatorTransport;
     36     /// assert_eq!(
     37     ///     serde_json::to_string(&AuthenticatorTransport::Usb)?,
     38     ///     r#""usb""#
     39     /// );
     40     /// # Ok::<_, serde_json::Error>(())
     41     /// ```
     42     #[inline]
     43     fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
     44     where
     45         S: Serializer,
     46     {
     47         serializer.serialize_str(match *self {
     48             Self::Ble => BLE,
     49             Self::Hybrid => HYBRID,
     50             Self::Internal => INTERNAL,
     51             Self::Nfc => NFC,
     52             Self::SmartCard => SMART_CARD,
     53             Self::Usb => USB,
     54         })
     55     }
     56 }
     57 impl<'de> Deserialize<'de> for AuthenticatorTransport {
     58     /// Deserializes [`prim@str`] based on
     59     /// [`AuthenticatorTransport`](https://www.w3.org/TR/webauthn-3/#enumdef-authenticatortransport).
     60     ///
     61     /// Note `"cable"` is also supported and will be interpreted as [`Self::Hybrid`].
     62     ///
     63     /// # Examples
     64     ///
     65     /// ```
     66     /// # use webauthn_rp::response::AuthenticatorTransport;
     67     /// assert!(matches!(
     68     ///     serde_json::from_str::<AuthenticatorTransport>(r#""usb""#)?,
     69     ///     AuthenticatorTransport::Usb
     70     /// ));
     71     /// // Case matters.
     72     /// assert!(serde_json::from_str::<AuthenticatorTransport>(r#""Usb""#).is_err());
     73     /// # Ok::<_, serde_json::Error>(())
     74     /// ```
     75     #[inline]
     76     fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>
     77     where
     78         D: Deserializer<'de>,
     79     {
     80         /// `Visitor` for `AuthenticatorTransport`.
     81         struct AuthenticatorTransportVisitor;
     82         impl Visitor<'_> for AuthenticatorTransportVisitor {
     83             type Value = AuthenticatorTransport;
     84             fn expecting(&self, formatter: &mut Formatter<'_>) -> fmt::Result {
     85                 formatter.write_str("AuthenticatorTransport")
     86             }
     87             fn visit_str<E>(self, v: &str) -> Result<Self::Value, E>
     88             where
     89                 E: Error,
     90             {
     91                 /// Legacy version of [`Self::Hybrid`].
     92                 const CA_BLE: &str = "cable";
     93                 match v {
     94                     BLE => Ok(AuthenticatorTransport::Ble),
     95                     CA_BLE | HYBRID => Ok(AuthenticatorTransport::Hybrid),
     96                     INTERNAL => Ok(AuthenticatorTransport::Internal),
     97                     NFC => Ok(AuthenticatorTransport::Nfc),
     98                     SMART_CARD => Ok(AuthenticatorTransport::SmartCard),
     99                     USB => Ok(AuthenticatorTransport::Usb),
    100                     _ => Err(E::invalid_value(
    101                         Unexpected::Str(v),
    102                         &format!(
    103                             "'{BLE}', '{CA_BLE}', '{HYBRID}', '{INTERNAL}', '{NFC}', '{SMART_CARD}', or '{USB}'"
    104                         )
    105                         .as_str(),
    106                     )),
    107                 }
    108             }
    109         }
    110         deserializer.deserialize_str(AuthenticatorTransportVisitor)
    111     }
    112 }
    113 impl Serialize for AuthTransports {
    114     /// Serializes `self` based on
    115     /// [`transports`](https://www.w3.org/TR/webauthn-3/#dom-publickeycredentialdescriptor-transports).
    116     ///
    117     /// # Examples
    118     ///
    119     /// ```
    120     /// # use webauthn_rp::response::{AuthTransports, AuthenticatorTransport};
    121     /// # #[cfg(feature = "custom")]
    122     /// assert_eq!(
    123     ///     serde_json::to_string(&AuthTransports::ALL)?,
    124     ///     r#"["ble","hybrid","internal","nfc","smart-card","usb"]"#
    125     /// );
    126     /// # Ok::<_, serde_json::Error>(())
    127     /// ```
    128     #[expect(clippy::unreachable, reason = "there is a bug, so we want to crash")]
    129     #[inline]
    130     fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
    131     where
    132         S: Serializer,
    133     {
    134         let count = usize::try_from(self.count())
    135             .unwrap_or_else(|_e| unreachable!("there is a bug in AuthenticatorTransports::count"));
    136         serializer.serialize_seq(Some(count)).and_then(|mut ser| {
    137             if self.contains(AuthenticatorTransport::Ble) {
    138                 ser.serialize_element(&AuthenticatorTransport::Ble)
    139             } else {
    140                 Ok(())
    141             }
    142             .and_then(|()| {
    143                 if self.contains(AuthenticatorTransport::Hybrid) {
    144                     ser.serialize_element(&AuthenticatorTransport::Hybrid)
    145                 } else {
    146                     Ok(())
    147                 }
    148                 .and_then(|()| {
    149                     if self.contains(AuthenticatorTransport::Internal) {
    150                         ser.serialize_element(&AuthenticatorTransport::Internal)
    151                     } else {
    152                         Ok(())
    153                     }
    154                     .and_then(|()| {
    155                         if self.contains(AuthenticatorTransport::Nfc) {
    156                             ser.serialize_element(&AuthenticatorTransport::Nfc)
    157                         } else {
    158                             Ok(())
    159                         }
    160                         .and_then(|()| {
    161                             if self.contains(AuthenticatorTransport::SmartCard) {
    162                                 ser.serialize_element(&AuthenticatorTransport::SmartCard)
    163                             } else {
    164                                 Ok(())
    165                             }
    166                             .and_then(|()| {
    167                                 if self.contains(AuthenticatorTransport::Usb) {
    168                                     ser.serialize_element(&AuthenticatorTransport::Usb)
    169                                 } else {
    170                                     Ok(())
    171                                 }
    172                                 .and_then(|()| ser.end())
    173                             })
    174                         })
    175                     })
    176                 })
    177             })
    178         })
    179     }
    180 }
    181 impl<'de> Deserialize<'de> for AuthTransports {
    182     /// Deserializes a sequence based on
    183     /// [`transports`](https://www.w3.org/TR/webauthn-3/#dom-publickeycredentialdescriptor-transports).
    184     ///
    185     /// # Examples
    186     ///
    187     /// ```
    188     /// # use webauthn_rp::response::{AuthTransports, AuthenticatorTransport};
    189     /// # #[cfg(feature = "custom")]
    190     /// assert_eq!(
    191     ///     serde_json::from_str::<AuthTransports>(
    192     ///         r#"["ble","hybrid","internal","nfc","smart-card","usb"]"#
    193     ///     )
    194     ///     ?.count(),
    195     ///     6
    196     /// );
    197     /// // Errors since `"foo"` is not valid.
    198     /// assert!(serde_json::from_str::<AuthTransports>(r#"["foo"]"#).is_err());
    199     /// # Ok::<_, serde_json::Error>(())
    200     /// ```
    201     #[inline]
    202     fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>
    203     where
    204         D: Deserializer<'de>,
    205     {
    206         /// `Visitor` for `AuthTransports`.
    207         struct AuthTransportsVisitor;
    208         impl<'d> Visitor<'d> for AuthTransportsVisitor {
    209             type Value = AuthTransports;
    210             fn expecting(&self, formatter: &mut Formatter<'_>) -> fmt::Result {
    211                 formatter.write_str("AuthTransports")
    212             }
    213             fn visit_seq<A>(self, mut seq: A) -> Result<Self::Value, A::Error>
    214             where
    215                 A: SeqAccess<'d>,
    216             {
    217                 let mut transports = AuthTransports::new();
    218                 while let Some(val) = seq.next_element::<AuthenticatorTransport>()? {
    219                     transports = transports.add_transport(val);
    220                 }
    221                 Ok(transports)
    222             }
    223         }
    224         deserializer.deserialize_seq(AuthTransportsVisitor)
    225     }
    226 }
    227 impl<T: AsRef<[u8]>> Serialize for CredentialId<T> {
    228     /// Serializes `self` into a [`prim@str`] based on
    229     /// [`id`](https://www.w3.org/TR/webauthn-3/#dom-publickeycredentialdescriptorjson-id).
    230     ///
    231     /// # Examples
    232     ///
    233     /// ```
    234     /// # use webauthn_rp::response::CredentialId;
    235     /// // `CredentialId::try_from` only exists when `custom` is enabled; and even then, it is
    236     /// // likely never needed since the `CredentialId` was originally sent from the client and is likely
    237     /// // stored in a database which would be fetched by `UserHandle` or `Authentication::raw_id`.
    238     /// # #[cfg(feature = "custom")]
    239     /// assert_eq!(
    240     ///     serde_json::to_string(&CredentialId::try_from(vec![0; 16])?).unwrap(),
    241     ///     r#""AAAAAAAAAAAAAAAAAAAAAA""#
    242     /// );
    243     /// # Ok::<_, webauthn_rp::AggErr>(())
    244     ///```
    245     #[inline]
    246     fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
    247     where
    248         S: Serializer,
    249     {
    250         serializer.serialize_str(BASE64URL_NOPAD.encode(self.0.as_ref()).as_str())
    251     }
    252 }
    253 impl<'de> Deserialize<'de> for CredentialId<Vec<u8>> {
    254     /// Deserializes [`prim@str`] based on
    255     /// [`id`](https://www.w3.org/TR/webauthn-3/#dom-publickeycredentialdescriptorjson-id).
    256     ///
    257     /// # Examples
    258     ///
    259     /// ```
    260     /// # use webauthn_rp::response::CredentialId;
    261     /// # #[cfg(feature = "custom")]
    262     /// assert_eq!(
    263     ///     serde_json::from_str::<CredentialId<_>>(r#""AAAAAAAAAAAAAAAAAAAAAA""#).unwrap(),
    264     ///     CredentialId::try_from(vec![0; 16])?
    265     /// );
    266     /// # Ok::<_, webauthn_rp::AggErr>(())
    267     ///```
    268     #[inline]
    269     fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>
    270     where
    271         D: Deserializer<'de>,
    272     {
    273         /// `Visitor` for `CredentialId`.
    274         struct CredentialIdVisitor;
    275         impl Visitor<'_> for CredentialIdVisitor {
    276             type Value = CredentialId<Vec<u8>>;
    277             fn expecting(&self, formatter: &mut Formatter<'_>) -> fmt::Result {
    278                 formatter.write_str("CredentialId")
    279             }
    280             #[expect(clippy::unreachable, reason = "we want to crash when there is a bug")]
    281             fn visit_str<E>(self, v: &str) -> Result<Self::Value, E>
    282             where
    283                 E: Error,
    284             {
    285                 // Any value between `super::CRED_ID_MIN_LEN` and `super::CRED_ID_MIN_LEN` can be base64url encoded
    286                 // without fear since that range is just 16 to 1023, and
    287                 // 4/3 of 1023 is less than `usize::MAX`.
    288                 if (crate::base64url_nopad_len(super::CRED_ID_MIN_LEN).unwrap_or_else(|| {
    289                     unreachable!("there is a bug in webauthn_rp::base64url_nopad_len")
    290                 })
    291                     ..=crate::base64url_nopad_len(super::CRED_ID_MAX_LEN).unwrap_or_else(|| {
    292                         unreachable!("there is a bug in webauthn_rp::base64url_nopad_len")
    293                     }))
    294                     .contains(&v.len())
    295                 {
    296                     BASE64URL_NOPAD
    297                         .decode(v.as_bytes())
    298                         .map_err(E::custom)
    299                         .map(CredentialId)
    300                 } else {
    301                     Err(E::invalid_value(
    302                         Unexpected::Str(v),
    303                         &"16 to 1023 bytes encoded in base64url without padding",
    304                     ))
    305                 }
    306             }
    307         }
    308         deserializer.deserialize_str(CredentialIdVisitor)
    309     }
    310 }
    311 impl<'de> Deserialize<'de> for AuthenticatorAttachment {
    312     /// Deserializes [`prim@str`] based on
    313     /// [`AuthenticatorAttachment`](https://www.w3.org/TR/webauthn-3/#enumdef-authenticatorattachment).
    314     ///
    315     /// # Examples
    316     ///
    317     /// ```
    318     /// # use webauthn_rp::response::AuthenticatorAttachment;
    319     /// assert!(matches!(
    320     ///     serde_json::from_str::<AuthenticatorAttachment>(r#""cross-platform""#)?,
    321     ///     AuthenticatorAttachment::CrossPlatform)
    322     /// );
    323     /// assert!(matches!(
    324     ///     serde_json::from_str::<AuthenticatorAttachment>(r#""platform""#)?,
    325     ///     AuthenticatorAttachment::Platform)
    326     /// );
    327     /// // Case matters.
    328     /// assert!(serde_json::from_str::<AuthenticatorAttachment>(r#""Platform""#).is_err());
    329     /// // `AuthenticatorAttachment::None` is not deserializable.
    330     /// assert!(serde_json::from_str::<AuthenticatorAttachment>(r#""""#).is_err());
    331     /// assert!(serde_json::from_str::<AuthenticatorAttachment>("null").is_err());
    332     /// assert!(serde_json::from_str::<AuthenticatorAttachment>(r#""none""#).is_err());
    333     /// assert!(serde_json::from_str::<AuthenticatorAttachment>(r#""None""#).is_err());
    334     /// # Ok::<_, serde_json::Error>(())
    335     ///```
    336     #[inline]
    337     fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>
    338     where
    339         D: Deserializer<'de>,
    340     {
    341         /// `Visitor` for `AuthenticatorAttachment`.
    342         struct AuthenticatorAttachmentVisitor;
    343         impl Visitor<'_> for AuthenticatorAttachmentVisitor {
    344             type Value = AuthenticatorAttachment;
    345             fn expecting(&self, formatter: &mut Formatter<'_>) -> fmt::Result {
    346                 formatter.write_str("AuthenticatorAttachment")
    347             }
    348             fn visit_str<E>(self, v: &str) -> Result<Self::Value, E>
    349             where
    350                 E: Error,
    351             {
    352                 /// `"platform"`
    353                 const PLATFORM: &str = "platform";
    354                 /// `"cross-platform"`
    355                 const CROSS_PLATFORM: &str = "cross-platform";
    356                 match v {
    357                     PLATFORM => Ok(AuthenticatorAttachment::Platform),
    358                     CROSS_PLATFORM => Ok(AuthenticatorAttachment::CrossPlatform),
    359                     _ => Err(E::invalid_value(
    360                         Unexpected::Str(v),
    361                         &format!("'{PLATFORM}' or '{CROSS_PLATFORM}'").as_str(),
    362                     )),
    363                 }
    364             }
    365         }
    366         deserializer.deserialize_str(AuthenticatorAttachmentVisitor)
    367     }
    368 }
    369 /// Container of data that was encoded in base64url.
    370 pub(super) struct Base64DecodedVal(pub Vec<u8>);
    371 impl<'de> Deserialize<'de> for Base64DecodedVal {
    372     fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>
    373     where
    374         D: Deserializer<'de>,
    375     {
    376         /// `Visitor` for `Base64DecodedVal`.
    377         struct Base64DecodedValVisitor;
    378         impl Visitor<'_> for Base64DecodedValVisitor {
    379             type Value = Base64DecodedVal;
    380             fn expecting(&self, formatter: &mut Formatter<'_>) -> fmt::Result {
    381                 formatter.write_str("base64url-encoded data")
    382             }
    383             fn visit_str<E>(self, v: &str) -> Result<Self::Value, E>
    384             where
    385                 E: Error,
    386             {
    387                 BASE64URL_NOPAD
    388                     .decode(v.as_bytes())
    389                     .map_err(E::custom)
    390                     .map(Base64DecodedVal)
    391             }
    392         }
    393         deserializer.deserialize_str(Base64DecodedValVisitor)
    394     }
    395 }
    396 impl<'de> Deserialize<'de> for SentChallenge {
    397     /// Deserializes `[u8]` or [`prim@str`] based on
    398     /// [`challenge`](https://www.w3.org/TR/webauthn-3/#dom-collectedclientdata-challenge).
    399     ///
    400     /// Specifically a `[u8]` or `str` is base64url-decoded and interpreted as a little-endian
    401     /// `u128`.
    402     ///
    403     /// # Examples
    404     ///
    405     /// ```
    406     /// # use webauthn_rp::response::SentChallenge;
    407     /// assert_eq!(
    408     ///     serde_json::from_slice::<SentChallenge>(br#""AAAAAAAAAAAAAAAAAAAAAA""#)?,
    409     ///     SentChallenge(0)
    410     /// );
    411     /// # Ok::<_, serde_json::Error>(())
    412     ///```
    413     #[inline]
    414     fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>
    415     where
    416         D: Deserializer<'de>,
    417     {
    418         /// `Visitor` for `SentChallenge`.
    419         struct ChallengeVisitor;
    420         impl Visitor<'_> for ChallengeVisitor {
    421             type Value = SentChallenge;
    422             fn expecting(&self, formatter: &mut Formatter<'_>) -> fmt::Result {
    423                 formatter.write_str(
    424                     "base64 encoding of the 16-byte challenge in a URL safe way without padding",
    425                 )
    426             }
    427             #[expect(
    428                 clippy::panic_in_result_fn,
    429                 reason = "we want to crash when there is a bug"
    430             )]
    431             fn visit_bytes<E>(self, v: &[u8]) -> Result<Self::Value, E>
    432             where
    433                 E: Error,
    434             {
    435                 if v.len() == Challenge::BASE64_LEN {
    436                     let mut data = [0; 16];
    437                     BASE64URL_NOPAD
    438                         .decode_mut(v, data.as_mut_slice())
    439                         .map_err(|err| E::custom(err.error))
    440                         .map(|len| {
    441                             assert_eq!(len, 16, "there is a bug in BASE64URL_NOPAD::decode_mut");
    442                             SentChallenge::from_array(data)
    443                         })
    444                 } else {
    445                     Err(E::invalid_value(
    446                         Unexpected::Bytes(v),
    447                         &"22 bytes encoded in base64url without padding",
    448                     ))
    449                 }
    450             }
    451             fn visit_str<E>(self, v: &str) -> Result<Self::Value, E>
    452             where
    453                 E: Error,
    454             {
    455                 self.visit_bytes(v.as_bytes())
    456             }
    457         }
    458         deserializer.deserialize_bytes(ChallengeVisitor)
    459     }
    460 }
    461 impl<'de: 'a, 'a> Deserialize<'de> for Origin<'a> {
    462     /// Deserializes [`prim@str`] by borrowing the data when possible.
    463     ///
    464     /// # Examples
    465     ///
    466     /// ```
    467     /// # extern crate alloc;
    468     /// # use alloc::borrow::Cow;
    469     /// # use webauthn_rp::response::Origin;
    470     /// let origin_borrowed = "https://example.com";
    471     /// let origin_owned = "\\\\https://example.com";
    472     /// assert!(
    473     ///     matches!(serde_json::from_str::<Origin<'_>>(format!("\"{origin_borrowed}\"").as_str())?.0, Cow::Borrowed(val) if val == origin_borrowed)
    474     /// );
    475     /// assert!(
    476     ///     matches!(serde_json::from_str::<Origin<'_>>(format!("\"{origin_owned}\"").as_str())?.0, Cow::Owned(val) if *val.as_bytes() == origin_owned.as_bytes()[1..])
    477     /// );
    478     /// # Ok::<_, serde_json::Error>(())
    479     ///```
    480     #[inline]
    481     fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>
    482     where
    483         D: Deserializer<'de>,
    484     {
    485         /// `Visitor` for `Origin`.
    486         struct OriginVisitor<'b>(PhantomData<fn() -> &'b ()>);
    487         impl<'d: 'b, 'b> Visitor<'d> for OriginVisitor<'b> {
    488             type Value = Origin<'b>;
    489             fn expecting(&self, formatter: &mut Formatter<'_>) -> fmt::Result {
    490                 formatter.write_str("Origin")
    491             }
    492             fn visit_borrowed_str<E>(self, v: &'d str) -> Result<Self::Value, E>
    493             where
    494                 E: Error,
    495             {
    496                 Ok(Origin(Cow::Borrowed(v)))
    497             }
    498             fn visit_string<E>(self, v: String) -> Result<Self::Value, E>
    499             where
    500                 E: Error,
    501             {
    502                 Ok(Origin(Cow::Owned(v)))
    503             }
    504             fn visit_str<E>(self, v: &str) -> Result<Self::Value, E>
    505             where
    506                 E: Error,
    507             {
    508                 self.visit_string(v.to_owned())
    509             }
    510         }
    511         deserializer.deserialize_str(OriginVisitor(PhantomData))
    512     }
    513 }
    514 /// `trait` that returns an empty instance of `Self`.
    515 pub(super) trait ClientExtensions: Sized {
    516     /// Returns an empty instance of `Self`.
    517     fn empty() -> Self;
    518 }
    519 /// Response for both registration and authentication ceremonies.
    520 ///
    521 /// [`Self::raw_id`] is always `Some` when `!RELAXED` or `!REG`.
    522 ///
    523 /// `RELAXED` and `REG` are used purely for deserialization purposes.
    524 pub(super) struct PublicKeyCredential<const RELAXED: bool, const REG: bool, AuthResp, Ext> {
    525     /// [`rawId`](https://www.w3.org/TR/webauthn-3/#dom-publickeycredential-rawid).
    526     pub id: Option<CredentialId<Vec<u8>>>,
    527     /// [`response`](https://www.w3.org/TR/webauthn-3/#dom-publickeycredential-response).
    528     pub response: AuthResp,
    529     /// [`authenticatorAttachment`](https://www.w3.org/TR/webauthn-3/#dom-publickeycredential-authenticatorattachment).
    530     pub authenticator_attachment: AuthenticatorAttachment,
    531     /// [`getClientExtensionResults`](https://www.w3.org/TR/webauthn-3/#dom-publickeycredential-getclientextensionresults).
    532     pub client_extension_results: Ext,
    533 }
    534 /// Deserializes the value for type.
    535 pub(super) struct Type;
    536 impl<'e> Deserialize<'e> for Type {
    537     fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>
    538     where
    539         D: Deserializer<'e>,
    540     {
    541         /// `Visitor` for `Type`.
    542         struct TypeVisitor;
    543         impl Visitor<'_> for TypeVisitor {
    544             type Value = Type;
    545             fn expecting(&self, formatter: &mut Formatter<'_>) -> fmt::Result {
    546                 formatter.write_str(PUBLIC_KEY)
    547             }
    548             fn visit_str<E>(self, v: &str) -> Result<Self::Value, E>
    549             where
    550                 E: Error,
    551             {
    552                 if v == PUBLIC_KEY {
    553                     Ok(Type)
    554                 } else {
    555                     Err(E::invalid_value(Unexpected::Str(v), &PUBLIC_KEY))
    556                 }
    557             }
    558         }
    559         deserializer.deserialize_str(TypeVisitor)
    560     }
    561 }
    562 /// `Visitor` for `PublicKeyCredential`.
    563 ///
    564 /// When `!RELAXED`, `REG` is ignored and all fields must exist and unknown fields are not allowed.
    565 /// When `RELAXED`, unknown fields are ignored.
    566 /// When `RELAXED` and `REG`, only `response` is required.
    567 /// When `RELAXED` and `!REG`, only `id` and `response` are required.
    568 struct PublicKeyCredentialVisitor<const RELAXED: bool, const REG: bool, R, E>(
    569     pub PhantomData<fn() -> (R, E)>,
    570 );
    571 impl<'d, const REL: bool, const REGI: bool, R, E> Visitor<'d>
    572     for PublicKeyCredentialVisitor<REL, REGI, R, E>
    573 where
    574     R: Deserialize<'d>,
    575     E: for<'a> Deserialize<'a> + ClientExtensions,
    576 {
    577     type Value = PublicKeyCredential<REL, REGI, R, E>;
    578     fn expecting(&self, formatter: &mut Formatter<'_>) -> fmt::Result {
    579         formatter.write_str("PublicKeyCredential")
    580     }
    581     #[expect(
    582         clippy::too_many_lines,
    583         reason = "rather hide all the internal logic instead instead of moving into an outer scope"
    584     )]
    585     fn visit_map<A>(self, mut map: A) -> Result<Self::Value, A::Error>
    586     where
    587         A: MapAccess<'d>,
    588     {
    589         /// `PublicKeyCredentialJSON` fields.
    590         enum Field<const IGNORE_UNKNOWN: bool> {
    591             /// `id`.
    592             Id,
    593             /// `type`.
    594             Type,
    595             /// `rawId`.
    596             RawId,
    597             /// `response`.
    598             Response,
    599             /// `authenticatorAttachment`.
    600             AuthenticatorAttachment,
    601             /// `clientExtensionResults`.
    602             ClientExtensionResults,
    603             /// Unknown field.
    604             Other,
    605         }
    606         impl<'e, const IGNORE: bool> Deserialize<'e> for Field<IGNORE> {
    607             fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>
    608             where
    609                 D: Deserializer<'e>,
    610             {
    611                 /// `Visitor` for `Field`.
    612                 struct FieldVisitor<const IGNORE_UNKNOWN: bool>;
    613                 impl<const IGN: bool> Visitor<'_> for FieldVisitor<IGN> {
    614                     type Value = Field<IGN>;
    615                     fn expecting(&self, formatter: &mut Formatter<'_>) -> fmt::Result {
    616                         write!(
    617                             formatter,
    618                             "'{ID}', '{TYPE}', '{RAW_ID}', '{RESPONSE}', '{AUTHENTICATOR_ATTACHMENT}', or '{CLIENT_EXTENSION_RESULTS}'"
    619                         )
    620                     }
    621                     fn visit_str<E>(self, v: &str) -> Result<Self::Value, E>
    622                     where
    623                         E: Error,
    624                     {
    625                         match v {
    626                             ID => Ok(Field::Id),
    627                             TYPE => Ok(Field::Type),
    628                             RAW_ID => Ok(Field::RawId),
    629                             RESPONSE => Ok(Field::Response),
    630                             AUTHENTICATOR_ATTACHMENT => Ok(Field::AuthenticatorAttachment),
    631                             CLIENT_EXTENSION_RESULTS => Ok(Field::ClientExtensionResults),
    632                             _ => {
    633                                 if IGN {
    634                                     Ok(Field::Other)
    635                                 } else {
    636                                     Err(E::unknown_field(v, REG_FIELDS))
    637                                 }
    638                             }
    639                         }
    640                     }
    641                 }
    642                 deserializer.deserialize_identifier(FieldVisitor::<IGNORE>)
    643             }
    644         }
    645         let mut opt_id = None;
    646         let mut typ = false;
    647         let mut raw = None;
    648         let mut resp = None;
    649         let mut attach = None;
    650         let mut ext = None;
    651         while let Some(key) = map.next_key::<Field<REL>>()? {
    652             match key {
    653                 Field::Id => {
    654                     if opt_id.is_some() {
    655                         return Err(Error::duplicate_field(ID));
    656                     }
    657                     opt_id = map.next_value::<CredentialId<_>>().map(Some)?;
    658                 }
    659                 Field::Type => {
    660                     if typ {
    661                         return Err(Error::duplicate_field(TYPE));
    662                     }
    663                     typ = map.next_value::<Type>().map(|_| true)?;
    664                 }
    665                 Field::RawId => {
    666                     if raw.is_some() {
    667                         return Err(Error::duplicate_field(RAW_ID));
    668                     }
    669                     raw = map.next_value::<CredentialId<_>>().map(Some)?;
    670                 }
    671                 Field::Response => {
    672                     if resp.is_some() {
    673                         return Err(Error::duplicate_field(RESPONSE));
    674                     }
    675                     resp = map.next_value::<R>().map(Some)?;
    676                 }
    677                 Field::AuthenticatorAttachment => {
    678                     if attach.is_some() {
    679                         return Err(Error::duplicate_field(AUTHENTICATOR_ATTACHMENT));
    680                     }
    681                     attach = map.next_value().map(Some)?;
    682                 }
    683                 Field::ClientExtensionResults => {
    684                     if ext.is_some() {
    685                         return Err(Error::duplicate_field(CLIENT_EXTENSION_RESULTS));
    686                     }
    687                     ext = map.next_value::<Option<E>>().map(Some)?;
    688                 }
    689                 Field::Other => map.next_value::<IgnoredAny>().map(|_| ())?,
    690             }
    691         }
    692         resp.ok_or_else(|| Error::missing_field(RESPONSE))
    693             .and_then(|response| {
    694                 opt_id.map_or_else(
    695                     || {
    696                         if REL && REGI {
    697                             Ok(None)
    698                         } else {
    699                             Err(Error::missing_field(ID))
    700                         }
    701                     },
    702                     |id| Ok(Some(id)),
    703                 )
    704                 .and_then(|id| {
    705                     raw.map_or_else(
    706                         || {
    707                             if REL {
    708                                 Ok(())
    709                             } else {
    710                                 Err(Error::missing_field(RAW_ID))
    711                             }
    712                         },
    713                         |raw_id| {
    714                             id.as_ref().map_or_else(
    715                                 || Ok(()),
    716                                 |i| {
    717                                     if raw_id == i {
    718                                         Ok(())
    719                                     } else {
    720                                         Err(Error::invalid_value(
    721                                             Unexpected::Bytes(raw_id.as_ref()),
    722                                             &format!("{ID} and {RAW_ID} to match: {i:?}").as_str(),
    723                                         ))
    724                                     }
    725                                 },
    726                             )
    727                         }
    728                     )
    729                     .and_then(|()| {
    730                         ext.ok_or(false).and_then(|opt_ext| opt_ext.ok_or(true)).map_or_else(
    731                             |flag| {
    732                                 if REL {
    733                                     Ok(E::empty())
    734                                 } else if flag {
    735                                     Err(Error::invalid_type(Unexpected::Other("null"), &format!("{CLIENT_EXTENSION_RESULTS} to be a map of allowed client extensions").as_str()))
    736                                 } else {
    737                                     Err(Error::missing_field(CLIENT_EXTENSION_RESULTS))
    738                                 }
    739                             },
    740                             Ok
    741                         )
    742                         .and_then(|client_extension_results| {
    743                             if typ || REL {
    744                                 Ok(PublicKeyCredential {
    745                                     id,
    746                                     response,
    747                                     authenticator_attachment: attach.flatten().unwrap_or(AuthenticatorAttachment::None),
    748                                     client_extension_results,
    749                                 })
    750                             } else {
    751                                 Err(Error::missing_field(TYPE))
    752                             }
    753                         })
    754                     })
    755                 })
    756             })
    757     }
    758 }
    759 /// `"id"`.
    760 const ID: &str = "id";
    761 /// `"type"`.
    762 const TYPE: &str = "type";
    763 /// `"rawId"`.
    764 const RAW_ID: &str = "rawId";
    765 /// `"response"`.
    766 const RESPONSE: &str = "response";
    767 /// `"authenticatorAttachment"`.
    768 const AUTHENTICATOR_ATTACHMENT: &str = "authenticatorAttachment";
    769 /// `"clientExtensionResults"`.
    770 const CLIENT_EXTENSION_RESULTS: &str = "clientExtensionResults";
    771 /// `"public-key"`.
    772 const PUBLIC_KEY: &str = "public-key";
    773 /// Fields for `PublicKeyCredentialJSON`.
    774 const REG_FIELDS: &[&str; 6] = &[
    775     ID,
    776     TYPE,
    777     RAW_ID,
    778     RESPONSE,
    779     AUTHENTICATOR_ATTACHMENT,
    780     CLIENT_EXTENSION_RESULTS,
    781 ];
    782 impl<'de, const REL: bool, const REGI: bool, R, E> Deserialize<'de>
    783     for PublicKeyCredential<REL, REGI, R, E>
    784 where
    785     R: Deserialize<'de>,
    786     E: for<'a> Deserialize<'a> + ClientExtensions,
    787 {
    788     /// Deserializes a `struct` based on
    789     /// [`PublicKeyCredentialJSON`](https://www.w3.org/TR/webauthn-3/#typedefdef-publickeycredentialjson).
    790     ///
    791     /// `REL` iff unknown fields should be ignored and not cause an error.
    792     /// `REGI` iff `Self` is from a registration ceremony.
    793     fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>
    794     where
    795         D: Deserializer<'de>,
    796     {
    797         deserializer.deserialize_struct(
    798             "PublicKeyCredential",
    799             REG_FIELDS,
    800             PublicKeyCredentialVisitor::<REL, REGI, _, _>(PhantomData),
    801         )
    802     }
    803 }
    804 use super::UserHandle;
    805 impl<const USER_LEN: usize> Serialize for AllAcceptedCredentialsOptions<'_, '_, USER_LEN>
    806 where
    807     UserHandle<USER_LEN>: Serialize,
    808 {
    809     /// Serializes `self` to conform with
    810     /// [`AllAcceptedCredentialsOptions`](https://www.w3.org/TR/webauthn-3/#dictdef-allacceptedcredentialsoptions).
    811     ///
    812     /// # Examples
    813     ///
    814     /// ```
    815     /// # use core::str::FromStr;
    816     /// # #[cfg(feature = "bin")]
    817     /// # use webauthn_rp::bin::Decode;
    818     /// # use webauthn_rp::{
    819     /// #     request::{register::{UserHandle, USER_HANDLE_MIN_LEN}, AsciiDomain, RpId},
    820     /// #     response::{error::CredentialIdErr, AllAcceptedCredentialsOptions, CredentialId},
    821     /// # };
    822     /// /// Retrieves the `CredentialId`s associated with `user_id` from the database.
    823     /// # #[cfg(all(feature = "bin", feature = "custom"))]
    824     /// fn get_credential_ids(user_id: UserHandle<USER_HANDLE_MIN_LEN>) -> Result<Vec<CredentialId<Vec<u8>>>, CredentialIdErr> {
    825     ///     // ⋮
    826     /// #     CredentialId::decode(vec![0; 16]).map(|cred_id| vec![cred_id])
    827     /// }
    828     /// /// Retrieves the `UserHandle` from a session cookie.
    829     /// # #[cfg(feature = "custom")]
    830     /// fn get_user_handle() -> UserHandle<USER_HANDLE_MIN_LEN> {
    831     ///     // ⋮
    832     /// #     [0].into()
    833     /// }
    834     /// # #[cfg(feature = "custom")]
    835     /// let user_id = get_user_handle();
    836     /// # #[cfg(all(feature = "bin", feature = "custom"))]
    837     /// assert_eq!(
    838     ///     serde_json::to_string(&AllAcceptedCredentialsOptions {
    839     ///         rp_id: &RpId::Domain(AsciiDomain::try_from("example.com".to_owned())?),
    840     ///         user_id: &user_id,
    841     ///         all_accepted_credential_ids: get_credential_ids(user_id)?,
    842     ///     })
    843     ///     .unwrap(),
    844     ///     r#"{"rpId":"example.com","userId":"AA","allAcceptedCredentialIds":["AAAAAAAAAAAAAAAAAAAAAA"]}"#
    845     /// );
    846     /// # Ok::<_, webauthn_rp::AggErr>(())
    847     /// ```
    848     #[inline]
    849     fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
    850     where
    851         S: Serializer,
    852     {
    853         serializer
    854             .serialize_struct("AllAcceptedCredentialsOptions", 3)
    855             .and_then(|mut ser| {
    856                 ser.serialize_field("rpId", self.rp_id).and_then(|()| {
    857                     ser.serialize_field("userId", &self.user_id).and_then(|()| {
    858                         ser.serialize_field(
    859                             "allAcceptedCredentialIds",
    860                             &self.all_accepted_credential_ids,
    861                         )
    862                         .and_then(|()| ser.end())
    863                     })
    864                 })
    865             })
    866     }
    867 }
    868 impl<const LEN: usize> Serialize for CurrentUserDetailsOptions<'_, '_, '_, '_, LEN>
    869 where
    870     UserHandle<LEN>: Serialize,
    871 {
    872     /// Serializes `self` to conform with
    873     /// [`CurrentUserDetailsOptions`](https://www.w3.org/TR/webauthn-3/#dictdef-currentuserdetailsoptions).
    874     ///
    875     /// # Examples
    876     ///
    877     /// ```
    878     /// # use core::str::FromStr;
    879     /// # #[cfg(feature = "bin")]
    880     /// # use webauthn_rp::bin::Decode;
    881     /// # use webauthn_rp::{
    882     /// #     request::{register::{Nickname, PublicKeyCredentialUserEntity, UserHandle, USER_HANDLE_MIN_LEN, Username}, AsciiDomain, RpId},
    883     /// #     response::CurrentUserDetailsOptions,
    884     /// #     AggErr,
    885     /// # };
    886     /// /// Retrieves the `PublicKeyCredentialUserEntity` info associated with `user_id` from the database.
    887     /// # #[cfg(feature = "bin")]
    888     /// fn get_user_info(user_id: UserHandle<USER_HANDLE_MIN_LEN>) -> Result<(Username<'static>, Option<Nickname<'static>>), AggErr> {
    889     ///     // ⋮
    890     /// #     Ok((Username::decode("foo").unwrap(), Some(Nickname::decode("foo").unwrap())))
    891     /// }
    892     /// /// Retrieves the `UserHandle` from a session cookie.
    893     /// # #[cfg(feature = "custom")]
    894     /// fn get_user_handle() -> UserHandle<USER_HANDLE_MIN_LEN> {
    895     ///     // ⋮
    896     /// #     [0].into()
    897     /// }
    898     /// # #[cfg(feature = "custom")]
    899     /// let user_handle = get_user_handle();
    900     /// # #[cfg(all(feature = "bin", feature = "custom"))]
    901     /// let (name, display_name) = get_user_info(user_handle)?;
    902     /// # #[cfg(all(feature = "bin", feature = "custom"))]
    903     /// assert_eq!(
    904     ///     serde_json::to_string(&CurrentUserDetailsOptions {
    905     ///         rp_id: &RpId::Domain(AsciiDomain::try_from("example.com".to_owned())?),
    906     ///         user: PublicKeyCredentialUserEntity { name, id: &user_handle, display_name, },
    907     ///     })
    908     ///     .unwrap(),
    909     ///     r#"{"rpId":"example.com","userId":"AA","name":"foo","displayName":"foo"}"#
    910     /// );
    911     /// # Ok::<_, AggErr>(())
    912     /// ```
    913     #[inline]
    914     fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
    915     where
    916         S: Serializer,
    917     {
    918         serializer
    919             .serialize_struct("CurrentUserDetailsOptions", 4)
    920             .and_then(|mut ser| {
    921                 ser.serialize_field("rpId", self.rp_id).and_then(|()| {
    922                     ser.serialize_field("userId", &self.user.id).and_then(|()| {
    923                         ser.serialize_field("name", &self.user.name).and_then(|()| {
    924                             ser.serialize_field("displayName", &self.user.display_name)
    925                                 .and_then(|()| ser.end())
    926                         })
    927                     })
    928                 })
    929             })
    930     }
    931 }
    932 /// JSON `null`.
    933 struct Null;
    934 impl<'de> Deserialize<'de> for Null {
    935     fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>
    936     where
    937         D: Deserializer<'de>,
    938     {
    939         /// `Visitor` for `Null`.
    940         struct NullVisitor;
    941         impl Visitor<'_> for NullVisitor {
    942             type Value = Null;
    943             fn expecting(&self, formatter: &mut Formatter<'_>) -> fmt::Result {
    944                 formatter.write_str("null")
    945             }
    946             fn visit_none<E>(self) -> Result<Self::Value, E>
    947             where
    948                 E: Error,
    949             {
    950                 Ok(Null)
    951             }
    952         }
    953         deserializer.deserialize_option(NullVisitor)
    954     }
    955 }
    956 /// [`AuthenticationExtensionsPRFValues`](https://www.w3.org/TR/webauthn-3/#dictdef-authenticationextensionsprfvalues).
    957 pub(super) struct AuthenticationExtensionsPrfValues;
    958 /// `Visitor` for `AuthenticationExtensionsPrfValues`.
    959 ///
    960 /// Unknown fields are ignored iff `RELAXED`.`first` must always exist if `second` does.
    961 /// `first` and `second` must be `null` if they exist. `first` must exist iff `!RELAXED`.
    962 pub(super) struct AuthenticationExtensionsPrfValuesVisitor<const RELAXED: bool>;
    963 impl<'d, const R: bool> Visitor<'d> for AuthenticationExtensionsPrfValuesVisitor<R> {
    964     type Value = AuthenticationExtensionsPrfValues;
    965     fn expecting(&self, formatter: &mut Formatter<'_>) -> fmt::Result {
    966         formatter.write_str("AuthenticationExtensionsPrfValues")
    967     }
    968     fn visit_map<A>(self, mut map: A) -> Result<Self::Value, A::Error>
    969     where
    970         A: MapAccess<'d>,
    971     {
    972         /// Fields.
    973         enum Field<const IGNORE_UNKNOWN: bool> {
    974             /// `first` field.
    975             First,
    976             /// `second` field.
    977             Second,
    978             /// Unknown field.
    979             Other,
    980         }
    981         impl<'e, const I: bool> Deserialize<'e> for Field<I> {
    982             fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>
    983             where
    984                 D: Deserializer<'e>,
    985             {
    986                 /// `Visitor` for `Field`.
    987                 ///
    988                 /// Unknown fields are ignored iff `IGNORE_UNKNOWN`.
    989                 struct FieldVisitor<const IGNORE_UNKNOWN: bool>;
    990                 impl<const IG: bool> Visitor<'_> for FieldVisitor<IG> {
    991                     type Value = Field<IG>;
    992                     fn expecting(&self, formatter: &mut Formatter<'_>) -> fmt::Result {
    993                         write!(formatter, "'{FIRST}' or '{SECOND}'")
    994                     }
    995                     fn visit_str<E>(self, v: &str) -> Result<Self::Value, E>
    996                     where
    997                         E: Error,
    998                     {
    999                         match v {
   1000                             FIRST => Ok(Field::First),
   1001                             SECOND => Ok(Field::Second),
   1002                             _ => {
   1003                                 if IG {
   1004                                     Ok(Field::Other)
   1005                                 } else {
   1006                                     Err(E::unknown_field(v, PRF_VALUES_FIELDS))
   1007                                 }
   1008                             }
   1009                         }
   1010                     }
   1011                 }
   1012                 deserializer.deserialize_identifier(FieldVisitor)
   1013             }
   1014         }
   1015         let mut first = None;
   1016         let mut second = None;
   1017         while let Some(key) = map.next_key::<Field<R>>()? {
   1018             match key {
   1019                 Field::First => {
   1020                     if first.is_some() {
   1021                         return Err(Error::duplicate_field(FIRST));
   1022                     }
   1023                     first = map.next_value::<Null>().map(Some)?;
   1024                 }
   1025                 Field::Second => {
   1026                     if second.is_some() {
   1027                         return Err(Error::duplicate_field(SECOND));
   1028                     }
   1029                     second = map.next_value::<Null>().map(Some)?;
   1030                 }
   1031                 Field::Other => map.next_value::<IgnoredAny>().map(|_| ())?,
   1032             }
   1033         }
   1034         if first.is_some() || (R && second.is_none()) {
   1035             Ok(AuthenticationExtensionsPrfValues)
   1036         } else {
   1037             Err(Error::missing_field(FIRST))
   1038         }
   1039     }
   1040 }
   1041 /// `"first"`
   1042 const FIRST: &str = "first";
   1043 /// `"second"`
   1044 const SECOND: &str = "second";
   1045 /// `AuthenticationExtensionsPrfValues` fields.
   1046 pub(super) const PRF_VALUES_FIELDS: &[&str; 2] = &[FIRST, SECOND];
   1047 impl<'de> Deserialize<'de> for AuthenticationExtensionsPrfValues {
   1048     fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>
   1049     where
   1050         D: Deserializer<'de>,
   1051     {
   1052         deserializer.deserialize_struct(
   1053             "AuthenticationExtensionsPrfValues",
   1054             PRF_VALUES_FIELDS,
   1055             AuthenticationExtensionsPrfValuesVisitor::<false>,
   1056         )
   1057     }
   1058 }
   1059 /// [`AuthenticationExtensionsPRFOutputs`](https://www.w3.org/TR/webauthn-3/#dictdef-authenticationextensionsprfoutputs).
   1060 ///
   1061 /// `RELAXED` iff unknown fields are ignored.
   1062 ///
   1063 /// `REGISTRATION` iff
   1064 /// [`enabled`](https://www.w3.org/TR/webauthn-3/#dom-authenticationextensionsprfoutputs-enabled)
   1065 /// is required (and must not be `null`); otherwise it's forbidden.
   1066 ///
   1067 /// The contained `Option` is `Some` iff `REGISTRATION`.
   1068 pub(super) struct AuthenticationExtensionsPrfOutputsHelper<
   1069     const RELAXED: bool,
   1070     const REGISTRATION: bool,
   1071     Prf,
   1072 >(pub Option<bool>, pub PhantomData<fn() -> Prf>);
   1073 /// `Visitor` for `AuthenticationExtensionsPrfOutputs`.
   1074 ///
   1075 /// Unknown fields are ignored iff `RELAXED`.`enabled` must exist and not be `null` iff `REGISTRATION`.
   1076 struct AuthenticationExtensionsPrfOutputsVisitor<const RELAXED: bool, const REGISTRATION: bool, Prf>(
   1077     PhantomData<fn() -> Prf>,
   1078 );
   1079 impl<'d, const REL: bool, const REG: bool, Prf> Visitor<'d>
   1080     for AuthenticationExtensionsPrfOutputsVisitor<REL, REG, Prf>
   1081 where
   1082     Prf: for<'a> Deserialize<'a>,
   1083 {
   1084     type Value = AuthenticationExtensionsPrfOutputsHelper<REL, REG, Prf>;
   1085     fn expecting(&self, formatter: &mut Formatter<'_>) -> fmt::Result {
   1086         formatter.write_str("AuthenticationExtensionsPrfOutputs")
   1087     }
   1088     fn visit_map<A>(self, mut map: A) -> Result<Self::Value, A::Error>
   1089     where
   1090         A: MapAccess<'d>,
   1091     {
   1092         /// Fields.
   1093         enum Field<const IGNORE_UNKNOWN: bool, const REGI: bool> {
   1094             /// `enabled` field.
   1095             Enabled,
   1096             /// `results` field.
   1097             Results,
   1098             /// Unknown field.
   1099             Other,
   1100         }
   1101         impl<'e, const I: bool, const R: bool> Deserialize<'e> for Field<I, R> {
   1102             fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>
   1103             where
   1104                 D: Deserializer<'e>,
   1105             {
   1106                 /// `Visitor` for `Field`.
   1107                 ///
   1108                 /// Unknown fields are ignored iff `IGNORE_UNKNOWN`.
   1109                 /// `enabled` is allowed to exist iff `REGI`.
   1110                 struct FieldVisitor<const IGNORE_UNKNOWN: bool, const REGI: bool>;
   1111                 impl<const IG: bool, const RE: bool> Visitor<'_> for FieldVisitor<IG, RE> {
   1112                     type Value = Field<IG, RE>;
   1113                     fn expecting(&self, formatter: &mut Formatter<'_>) -> fmt::Result {
   1114                         if RE {
   1115                             write!(formatter, "'{ENABLED}' or '{RESULTS}'")
   1116                         } else {
   1117                             write!(formatter, "'{RESULTS}'")
   1118                         }
   1119                     }
   1120                     fn visit_str<E>(self, v: &str) -> Result<Self::Value, E>
   1121                     where
   1122                         E: Error,
   1123                     {
   1124                         match v {
   1125                             ENABLED => {
   1126                                 if RE {
   1127                                     Ok(Field::Enabled)
   1128                                 } else {
   1129                                     Err(E::unknown_field(v, PRF_AUTH_OUTPUTS_FIELDS))
   1130                                 }
   1131                             }
   1132                             RESULTS => Ok(Field::Results),
   1133                             _ => {
   1134                                 if IG {
   1135                                     Ok(Field::Other)
   1136                                 } else if RE {
   1137                                     Err(E::unknown_field(v, PRF_REG_OUTPUTS_FIELDS))
   1138                                 } else {
   1139                                     Err(E::unknown_field(v, PRF_AUTH_OUTPUTS_FIELDS))
   1140                                 }
   1141                             }
   1142                         }
   1143                     }
   1144                 }
   1145                 deserializer.deserialize_identifier(FieldVisitor)
   1146             }
   1147         }
   1148         let mut enabled = None;
   1149         let mut results = None;
   1150         while let Some(key) = map.next_key::<Field<REL, REG>>()? {
   1151             match key {
   1152                 Field::Enabled => {
   1153                     if enabled.is_some() {
   1154                         return Err(Error::duplicate_field(ENABLED));
   1155                     }
   1156                     enabled = map.next_value().map(Some)?;
   1157                 }
   1158                 Field::Results => {
   1159                     if results.is_some() {
   1160                         return Err(Error::duplicate_field(RESULTS));
   1161                     }
   1162                     results = map.next_value::<Option<Prf>>().map(Some)?;
   1163                 }
   1164                 Field::Other => map.next_value::<IgnoredAny>().map(|_| ())?,
   1165             }
   1166         }
   1167         if REG {
   1168             enabled.ok_or_else(|| Error::missing_field(ENABLED)).and_then(|e| {
   1169                 if e || results.is_none() {
   1170                     Ok(())
   1171                 } else {
   1172                     Err(Error::custom("prf must not have 'results', including a null 'results', if 'enabled' is false"))
   1173                 }
   1174             })
   1175         } else {
   1176             Ok(())
   1177         }.map(|()| AuthenticationExtensionsPrfOutputsHelper(enabled, PhantomData))
   1178     }
   1179 }
   1180 /// `"enabled"`
   1181 const ENABLED: &str = "enabled";
   1182 /// `"results"`
   1183 const RESULTS: &str = "results";
   1184 /// `AuthenticationExtensionsPrfOutputs` field during registration.
   1185 const PRF_REG_OUTPUTS_FIELDS: &[&str; 2] = &[ENABLED, RESULTS];
   1186 /// `AuthenticationExtensionsPrfOutputs` field during authentication.
   1187 const PRF_AUTH_OUTPUTS_FIELDS: &[&str; 1] = &[RESULTS];
   1188 impl<'de, const REL: bool, const REG: bool, Prf> Deserialize<'de>
   1189     for AuthenticationExtensionsPrfOutputsHelper<REL, REG, Prf>
   1190 where
   1191     for<'a> Prf: Deserialize<'a>,
   1192 {
   1193     fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>
   1194     where
   1195         D: Deserializer<'de>,
   1196     {
   1197         deserializer.deserialize_struct(
   1198             "AuthenticationExtensionsPrfOutputs",
   1199             if REG {
   1200                 PRF_REG_OUTPUTS_FIELDS
   1201             } else {
   1202                 PRF_AUTH_OUTPUTS_FIELDS
   1203             },
   1204             AuthenticationExtensionsPrfOutputsVisitor::<REL, REG, Prf>(PhantomData),
   1205         )
   1206     }
   1207 }