commit 1d95b0f6f7b1a68e29404a5dcd679b573d460618
parent 873a002485f4bdf0c6631c35eecfaab6f5507581
Author: Zack Newman <zack@philomathiclife.com>
Date: Sun, 22 Jun 2025 22:31:58 -0600
more lints
Diffstat:
14 files changed, 92 insertions(+), 35 deletions(-)
diff --git a/Cargo.toml b/Cargo.toml
@@ -13,18 +13,45 @@ rust-version = "1.87.0"
version = "0.4.0"
[lints.rust]
-unknown_lints = { level = "deny", priority = -1 }
+ambiguous_negative_literals = { level = "deny", priority = -1 }
+closure_returning_async_block = { level = "deny", priority = -1 }
+deref_into_dyn_supertrait = { level = "deny", priority = -1 }
+ffi_unwind_calls = { level = "deny", priority = -1 }
future_incompatible = { level = "deny", priority = -1 }
+impl_trait_redundant_captures = { level = "deny", priority = -1 }
+keyword-idents = { level = "deny", priority = -1 }
let_underscore = { level = "deny", priority = -1 }
+linker_messages = { level = "deny", priority = -1 }
+macro_use_extern_crate = { level = "deny", priority = -1 }
+meta_variable_misuse = { level = "deny", priority = -1 }
+missing_copy_implementations = { level = "deny", priority = -1 }
+missing_debug_implementations = { level = "deny", priority = -1 }
missing_docs = { level = "deny", priority = -1 }
+non_ascii_idents = { level = "deny", priority = -1 }
nonstandard_style = { level = "deny", priority = -1 }
+redundant_imports = { level = "deny", priority = -1 }
+redundant_lifetimes = { level = "deny", priority = -1 }
refining_impl_trait = { level = "deny", priority = -1 }
rust_2018_compatibility = { level = "deny", priority = -1 }
rust_2018_idioms = { level = "deny", priority = -1 }
rust_2021_compatibility = { level = "deny", priority = -1 }
rust_2024_compatibility = { level = "deny", priority = -1 }
+single-use-lifetimes = { level = "deny", priority = -1 }
+trivial_casts = { level = "deny", priority = -1 }
+trivial_numeric_casts = { level = "deny", priority = -1 }
+unit_bindings = { level = "deny", priority = -1 }
+unknown_lints = { level = "deny", priority = -1 }
+unnameable_types = { level = "deny", priority = -1 }
+unreachable_pub = { level = "deny", priority = -1 }
unsafe_code = { level = "deny", priority = -1 }
+unstable_features = { level = "deny", priority = -1 }
unused = { level = "deny", priority = -1 }
+unused_crate_dependencies = { level = "deny", priority = -1 }
+unused_import_braces = { level = "deny", priority = -1 }
+unused_lifetimes = { level = "deny", priority = -1 }
+unused_qualifications = { level = "deny", priority = -1 }
+unused_results = { level = "deny", priority = -1 }
+variant_size_differences = { level = "deny", priority = -1 }
warnings = { level = "deny", priority = -1 }
[lints.clippy]
diff --git a/src/hash.rs b/src/hash.rs
@@ -34,7 +34,7 @@ pub mod hash_set;
/// [`NonDiscoverableCredentialRequestOptions::start_ceremony`] respectively. Since `Challenge` is already based on
/// a random `u128`, other `Hasher`s will be slower and likely produce lower-quality hashes (and never
/// higher quality).
-#[derive(Debug)]
+#[derive(Clone, Copy, Debug)]
pub struct IdentityHasher(u64);
// Note it is _not_ required for `write_*` methods to do the same thing as other `write_*` methods
// (e.g., `Self::write_u64` may not be the same thing as 8 calls to `Self::write_u8`).
diff --git a/src/hash/hash_map.rs b/src/hash/hash_map.rs
@@ -170,7 +170,7 @@ impl<K: Eq + Hash, V, S: BuildHasher> FixedCapHashMap<K, V, S> {
if full {
None
} else {
- ent.insert(v);
+ _ = ent.insert(v);
Some(None)
}
}
diff --git a/src/hash/hash_set.rs b/src/hash/hash_set.rs
@@ -127,7 +127,7 @@ impl<T: Eq + Hash, S: BuildHasher> FixedCapHashSet<T, S> {
if full {
None
} else {
- ent.insert();
+ _ = ent.insert();
Some(true)
}
} else {
@@ -147,7 +147,7 @@ impl<T: Eq + Hash, S: BuildHasher> FixedCapHashSet<T, S> {
} else if self.0.len() == self.0.capacity() {
None
} else {
- self.0.insert(value);
+ _ = self.0.insert(value);
Some(None)
}
}
diff --git a/src/lib.rs b/src/lib.rs
@@ -1062,12 +1062,13 @@ impl<'cred, 'user, const USER_LEN: usize, PublicKey>
///
/// Errors iff the passed arguments are invalid. Read [`CredentialErr`]
/// for more information.
+ #[expect(single_use_lifetimes, reason = "false positive")]
#[cfg_attr(docsrs, doc(cfg(any(feature = "bin", feature = "custom"))))]
#[cfg(any(feature = "bin", feature = "custom"))]
#[inline]
pub fn new<'a: 'cred, 'b: 'user>(
id: CredentialId<&'a [u8]>,
- user_id: &'user UserHandle<USER_LEN>,
+ user_id: &'b UserHandle<USER_LEN>,
static_state: StaticState<PublicKey>,
dynamic_state: DynamicState,
) -> Result<Self, CredentialErr> {
diff --git a/src/request.rs b/src/request.rs
@@ -193,6 +193,10 @@ pub(super) mod ser_server_state;
// `SentChallenge` since it is used during ceremony validation; thus we must keep `Challenge` and `SentChallenge`
// as separate types.
/// [Cryptographic challenge](https://www.w3.org/TR/webauthn-3/#sctn-cryptographic-challenges).
+#[expect(
+ missing_copy_implementations,
+ reason = "want to enforce randomly-generated challenges"
+)]
#[derive(Debug)]
pub struct Challenge(u128);
impl Challenge {
@@ -277,7 +281,7 @@ impl AsciiDomain {
.unwrap_or_else(|| unreachable!("there is a bug in AsciiDomain::try_from"))
== b'.'
{
- self.0.pop();
+ _ = self.0.pop();
}
}
}
@@ -761,6 +765,7 @@ impl<'b> DomainOrigin<'_, 'b> {
/// Origin(Cow::Borrowed("https://www.example.com:443"))
/// );
/// ```
+ #[expect(single_use_lifetimes, reason = "false positive")]
#[must_use]
#[inline]
pub const fn new<'c: 'b>(host: &'c str) -> Self {
@@ -790,6 +795,7 @@ impl<'b> DomainOrigin<'_, 'b> {
/// Origin(Cow::Borrowed("https://www.example.com"))
/// );
/// ```
+ #[expect(single_use_lifetimes, reason = "false positive")]
#[must_use]
#[inline]
pub const fn new_ignore_port<'c: 'b>(host: &'c str) -> Self {
@@ -1581,6 +1587,7 @@ mod tests {
signature::{Keypair, SignatureEncoding},
traits::PublicKeyParts,
};
+ use serde_json as _;
#[cfg(feature = "custom")]
const CBOR_UINT: u8 = 0b000_00000;
#[cfg(feature = "custom")]
@@ -1956,7 +1963,7 @@ mod tests {
fn eddsa_auth() -> Result<(), AggErr> {
let rp_id = RpId::Domain(AsciiDomain::try_from("example.com".to_owned())?);
let mut creds = AllowedCredentials::with_capacity(1);
- creds.push(AllowedCredential {
+ _ = creds.push(AllowedCredential {
credential: PublicKeyCredentialDescriptor {
id: CredentialId::try_from(vec![0; 16])?,
transports: AuthTransports::NONE,
diff --git a/src/request/auth.rs b/src/request/auth.rs
@@ -280,7 +280,7 @@ impl From<Vec<PublicKeyCredentialDescriptor<Vec<u8>>>> for AllowedCredentials {
fn from(value: Vec<PublicKeyCredentialDescriptor<Vec<u8>>>) -> Self {
let mut creds = Self::with_capacity(value.len());
value.into_iter().fold((), |(), credential| {
- creds.push(AllowedCredential {
+ _ = creds.push(AllowedCredential {
credential,
extension: CredentialSpecificExtension { prf: None },
});
@@ -317,6 +317,7 @@ impl<'rp_id, 'prf_first, 'prf_second>
/// ));
/// # Ok::<_, webauthn_rp::AggErr>(())
/// ```
+ #[expect(single_use_lifetimes, reason = "false positive")]
#[inline]
#[must_use]
pub fn passkey<'a: 'rp_id>(rp_id: &'a RpId) -> Self {
@@ -448,6 +449,7 @@ impl<'rp_id, 'prf_first, 'prf_second>
/// );
/// # Ok::<_, webauthn_rp::AggErr>(())
/// ```
+ #[expect(single_use_lifetimes, reason = "false positive")]
#[inline]
pub fn second_factor<'a: 'rp_id>(
rp_id: &'a RpId,
@@ -548,6 +550,7 @@ impl<'rp_id> PublicKeyCredentialRequestOptions<'rp_id, '_, '_> {
/// ));
/// # Ok::<_, webauthn_rp::AggErr>(())
/// ```
+ #[expect(single_use_lifetimes, reason = "false positive")]
#[inline]
#[must_use]
pub fn passkey<'a: 'rp_id>(rp_id: &'a RpId) -> Self {
@@ -576,6 +579,7 @@ impl<'rp_id> PublicKeyCredentialRequestOptions<'rp_id, '_, '_> {
/// ));
/// # Ok::<_, webauthn_rp::AggErr>(())
/// ```
+ #[expect(single_use_lifetimes, reason = "false positive")]
#[inline]
#[must_use]
pub fn second_factor<'a: 'rp_id>(rp_id: &'a RpId) -> Self {
@@ -1069,8 +1073,6 @@ impl DiscoverableAuthenticationServerState {
#[inline]
pub fn verify<
'a,
- 'cred_id,
- 'user,
const USER_LEN: usize,
O: PartialEq<Origin<'a>>,
T: PartialEq<Origin<'a>>,
@@ -1083,8 +1085,8 @@ impl DiscoverableAuthenticationServerState {
rp_id: &RpId,
response: &'a DiscoverableAuthentication<USER_LEN>,
cred: &mut AuthenticatedCredential<
- 'cred_id,
- 'user,
+ '_,
+ '_,
USER_LEN,
CompressedPubKey<EdKey, P256Key, P384Key, RsaKey>,
>,
@@ -1145,8 +1147,6 @@ impl NonDiscoverableAuthenticationServerState {
#[inline]
pub fn verify<
'a,
- 'cred_id,
- 'user,
const USER_LEN: usize,
O: PartialEq<Origin<'a>>,
T: PartialEq<Origin<'a>>,
@@ -1159,8 +1159,8 @@ impl NonDiscoverableAuthenticationServerState {
rp_id: &RpId,
response: &'a NonDiscoverableAuthentication<USER_LEN>,
cred: &mut AuthenticatedCredential<
- 'cred_id,
- 'user,
+ '_,
+ '_,
USER_LEN,
CompressedPubKey<EdKey, P256Key, P384Key, RsaKey>,
>,
@@ -1243,8 +1243,6 @@ impl AuthenticationServerState {
/// of the settings in `options`.
fn verify<
'a,
- 'cred_id,
- 'user,
const USER_LEN: usize,
const DISCOVERABLE: bool,
O: PartialEq<Origin<'a>>,
@@ -1259,8 +1257,8 @@ impl AuthenticationServerState {
rp_id: &RpId,
response: &'a Authentication<USER_LEN, DISCOVERABLE>,
cred: &mut AuthenticatedCredential<
- 'cred_id,
- 'user,
+ '_,
+ '_,
USER_LEN,
CompressedPubKey<EdKey, P256Key, P384Key, RsaKey>,
>,
@@ -1662,7 +1660,7 @@ mod tests {
fn eddsa_auth_ser() -> Result<(), AggErr> {
let rp_id = RpId::Domain(AsciiDomain::try_from("example.com".to_owned())?);
let mut creds = AllowedCredentials::with_capacity(1);
- creds.push(AllowedCredential {
+ _ = creds.push(AllowedCredential {
credential: PublicKeyCredentialDescriptor {
id: CredentialId::try_from(vec![0; 16])?,
transports: AuthTransports::NONE,
diff --git a/src/request/register.rs b/src/request/register.rs
@@ -233,6 +233,7 @@ impl<'a> Nickname<'a> {
///
/// Errors iff `value` violates [RFC 8266 § 2.3](https://www.rfc-editor.org/rfc/rfc8266.html#section-2.3)
/// or the resulting length exceeds [`Self::RECOMMENDED_MAX_LEN`].
+ #[expect(single_use_lifetimes, reason = "false positive")]
#[inline]
pub fn with_recommended_len<'b: 'a>(value: Cow<'b, str>) -> Result<Self, NicknameErr> {
precis_profiles::Nickname::new()
@@ -251,6 +252,7 @@ impl<'a> Nickname<'a> {
///
/// Errors iff `value` violates [RFC 8266 § 2.3](https://www.rfc-editor.org/rfc/rfc8266.html#section-2.3)
/// or the resulting length exceeds [`Self::MAX_LEN`].
+ #[expect(single_use_lifetimes, reason = "false positive")]
#[inline]
pub fn with_max_len<'b: 'a>(value: Cow<'b, str>) -> Result<Self, NicknameErr> {
Self::try_from(value)
@@ -399,6 +401,7 @@ impl<'a> Username<'a> {
///
/// Errors iff `value` violates [RFC 8265 § 3.4.3](https://www.rfc-editor.org/rfc/rfc8265.html#section-3.4.3)
/// or the resulting length exceeds [`Self::RECOMMENDED_MAX_LEN`].
+ #[expect(single_use_lifetimes, reason = "false positive")]
#[inline]
pub fn with_recommended_len<'b: 'a>(value: Cow<'b, str>) -> Result<Self, UsernameErr> {
UsernameCasePreserved::default()
@@ -417,6 +420,7 @@ impl<'a> Username<'a> {
///
/// Errors iff `value` violates [RFC 8265 § 3.4.3](https://www.rfc-editor.org/rfc/rfc8265.html#section-3.4.3)
/// or the resulting length exceeds [`Self::MAX_LEN`].
+ #[expect(single_use_lifetimes, reason = "false positive")]
#[inline]
pub fn with_max_len<'b: 'a>(value: Cow<'b, str>) -> Result<Self, UsernameErr> {
Self::try_from(value)
@@ -1341,6 +1345,7 @@ impl<
{
/// Sets [`Self::mediation`] to [`CredentialMediationRequirement::default`] and
/// [`Self::public_key`] to [`PublicKeyCredentialCreationOptions::passkey`].
+ #[expect(single_use_lifetimes, reason = "false positive")]
#[inline]
#[must_use]
pub fn passkey<'a: 'rp_id, 'b: 'user_name, 'c: 'user_display_name, 'd: 'user_id>(
@@ -1360,6 +1365,7 @@ impl<
/// Convenience function for [`Self::passkey`] passing an empty `Vec`.
///
/// This MUST only be used when this is the first credential for a user.
+ #[expect(single_use_lifetimes, reason = "false positive")]
#[inline]
#[must_use]
pub fn first_passkey<'a: 'rp_id, 'b: 'user_name, 'c: 'user_display_name, 'd: 'user_id>(
@@ -1376,6 +1382,7 @@ impl<
///
/// Because user information is likely known for existing accounts, this will often only be called during
/// greenfield deployments.
+ #[expect(single_use_lifetimes, reason = "false positive")]
#[inline]
#[must_use]
pub fn first_passkey_with_blank_user_info<'a: 'rp_id, 'b: 'user_id>(
@@ -1386,6 +1393,7 @@ impl<
}
/// Sets [`Self::mediation`] to [`CredentialMediationRequirement::default`] and
/// [`Self::public_key`] to [`PublicKeyCredentialCreationOptions::second_factor`].
+ #[expect(single_use_lifetimes, reason = "false positive")]
#[inline]
#[must_use]
pub fn second_factor<'a: 'rp_id, 'b: 'user_name, 'c: 'user_display_name, 'd: 'user_id>(
@@ -1406,6 +1414,7 @@ impl<
/// Convenience function for [`Self::second_factor`] passing an empty `Vec`.
///
/// This MUST only be used when this is the first credential for a user.
+ #[expect(single_use_lifetimes, reason = "false positive")]
#[inline]
#[must_use]
pub fn first_second_factor<'a: 'rp_id, 'b: 'user_name, 'c: 'user_display_name, 'd: 'user_id>(
@@ -1614,6 +1623,7 @@ impl<'rp_id, 'user_name, 'user_display_name, 'user_id, const USER_LEN: usize>
/// ));
/// # Ok::<_, webauthn_rp::AggErr>(())
/// ```
+ #[expect(single_use_lifetimes, reason = "false positive")]
#[inline]
#[must_use]
pub fn passkey<'a: 'rp_id, 'b: 'user_name, 'c: 'user_display_name, 'd: 'user_id>(
@@ -1643,6 +1653,7 @@ impl<'rp_id, 'user_name, 'user_display_name, 'user_id, const USER_LEN: usize>
/// Convenience function for [`Self::passkey`] passing an empty `Vec`.
///
/// This MUST only be used when this is the first credential for a user.
+ #[expect(single_use_lifetimes, reason = "false positive")]
#[inline]
#[must_use]
pub fn first_passkey<'a: 'rp_id, 'b: 'user_name, 'c: 'user_display_name, 'd: 'user_id>(
@@ -1659,6 +1670,7 @@ impl<'rp_id, 'user_name, 'user_display_name, 'user_id, const USER_LEN: usize>
///
/// Because user information is likely known for existing accounts, this will often only be called during
/// greenfield deployments.
+ #[expect(single_use_lifetimes, reason = "false positive")]
#[inline]
#[must_use]
pub fn first_passkey_with_blank_user_info<'a: 'rp_id, 'b: 'user_id>(
@@ -1712,6 +1724,7 @@ impl<'rp_id, 'user_name, 'user_display_name, 'user_id, const USER_LEN: usize>
/// );
/// # Ok::<_, webauthn_rp::AggErr>(())
/// ```
+ #[expect(single_use_lifetimes, reason = "false positive")]
#[inline]
#[must_use]
pub fn second_factor<'a: 'rp_id, 'b: 'user_name, 'c: 'user_display_name, 'd: 'user_id>(
@@ -1731,6 +1744,7 @@ impl<'rp_id, 'user_name, 'user_display_name, 'user_id, const USER_LEN: usize>
/// Convenience function for [`Self::second_factor`] passing an empty `Vec`.
///
/// This MUST only be used when this is the first credential for a user.
+ #[expect(single_use_lifetimes, reason = "false positive")]
#[inline]
#[must_use]
pub fn first_second_factor<'a: 'rp_id, 'b: 'user_name, 'c: 'user_display_name, 'd: 'user_id>(
@@ -3234,7 +3248,7 @@ mod tests {
.as_slice(),
);
}
- options.min_pin.map(|p| {
+ _ = options.min_pin.map(|p| {
assert!(p.value() <= 23, "bug");
attestation_object.extend_from_slice(
[
diff --git a/src/response.rs b/src/response.rs
@@ -519,6 +519,7 @@ impl<T> CredentialId<T> {
}
impl<'a> CredentialId<&'a [u8]> {
/// Creates a `CredentialId` from a `slice`.
+ #[expect(single_use_lifetimes, reason = "false positive")]
fn from_slice<'b: 'a>(value: &'b [u8]) -> Result<Self, CredentialIdErr> {
if (CRED_ID_MIN_LEN..=CRED_ID_MAX_LEN).contains(&value.len()) {
Ok(Self(value))
@@ -790,6 +791,7 @@ impl<'a> CollectedClientData<'a> {
/// assert!(!CollectedClientData::from_client_data_json::<false>(br#"{"type":"webauthn.get","challenge":"AAAAAAAAAAAAAAAAAAAAAA","origin":"https://example.com","crossOrigin":false}"#.as_slice())?.cross_origin);
/// # Ok::<_, CollectedClientDataErr>(())
/// ```
+ #[expect(single_use_lifetimes, reason = "false positive")]
#[inline]
pub fn from_client_data_json<'b: 'a, const REGISTRATION: bool>(json: &'b [u8]) -> Result<Self, CollectedClientDataErr> {
LimitedVerificationParser::<REGISTRATION>::parse(json)
@@ -837,6 +839,7 @@ impl<'a> CollectedClientData<'a> {
/// }")?.cross_origin);
/// # Ok::<_, SerdeJsonErr>(())
/// ```
+ #[expect(single_use_lifetimes, reason = "false positive")]
#[cfg_attr(docsrs, doc(cfg(feature = "serde_relaxed")))]
#[cfg(feature = "serde_relaxed")]
#[inline]
diff --git a/src/response/auth/error.rs b/src/response/auth/error.rs
@@ -310,7 +310,7 @@ impl Error for AuthCeremonyErr {}
/// This can be sent to the client when an authentication ceremony fails due to an unknown [`CredentialId`]. This
/// can be due to the user deleting a credential on the RP's side but not deleting it on the authenticator. This
/// response can be forwarded to the authenticator which can subsequently delete the credential.
-#[derive(Debug)]
+#[derive(Clone, Copy, Debug)]
pub struct UnknownCredentialOptions<'rp, 'cred> {
/// [`rpId`](https://www.w3.org/TR/webauthn-3/#dictdef-unknowncredentialoptions-rpid).
pub rp_id: &'rp RpId,
@@ -318,7 +318,7 @@ pub struct UnknownCredentialOptions<'rp, 'cred> {
pub credential_id: CredentialId<&'cred [u8]>,
}
/// Error when a [`UserHandle`] does not exist that is required to.
-#[derive(Debug)]
+#[derive(Clone, Copy, Debug)]
pub struct MissingUserHandleErr;
impl Display for MissingUserHandleErr {
#[inline]
diff --git a/src/response/register.rs b/src/response/register.rs
@@ -2738,6 +2738,7 @@ impl<'a> AttestationObject<'a> {
/// [attestation object layout](https://www.w3.org/TR/webauthn-3/#attestation-object)
/// returning [`Self`] and the index within `data` that the authenticator data portion
/// begins.
+ #[expect(single_use_lifetimes, reason = "false positive")]
#[expect(
clippy::panic_in_result_fn,
reason = "we want to crash when there is a bug"
diff --git a/src/response/register/bin.rs b/src/response/register/bin.rs
@@ -368,7 +368,7 @@ impl Encode for Metadata<'_> {
}
}
/// Owned version of [`Metadata`] that exists to [`Self::decode`] the output of [`Metadata::encode`].
-#[derive(Debug)]
+#[derive(Clone, Copy, Debug)]
pub struct MetadataOwned {
/// [`Metadata::attestation`].
pub attestation: Attestation,
diff --git a/src/response/register/ser.rs b/src/response/register/ser.rs
@@ -72,7 +72,7 @@ mod spki {
/// for an uncompressed ECDSA public key based on secp256r1/P-256.
const P256_HEADER_LEN: usize = 27;
/// Number of bytes the x-coordinate takes in an uncompressed P-256 public key.
- pub const P256_X_LEN: usize = <NistP256 as Curve>::FieldBytesSize::INT;
+ const P256_X_LEN: usize = <NistP256 as Curve>::FieldBytesSize::INT;
/// Number of bytes the y-coordinate takes in an uncompressed P-256 public key.
const P256_Y_LEN: usize = <NistP256 as Curve>::FieldBytesSize::INT;
/// Number of bytes the x and y coordinates take in an uncompressed P-256 public key when concatenated together.
@@ -92,7 +92,7 @@ mod spki {
/// for an uncompressed ECDSA public key based on secp384r1/P-384.
const P384_HEADER_LEN: usize = 24;
/// Number of bytes the x-coordinate takes in an uncompressed P-384 public key.
- pub const P384_X_LEN: usize = <NistP384 as Curve>::FieldBytesSize::INT;
+ const P384_X_LEN: usize = <NistP384 as Curve>::FieldBytesSize::INT;
/// Number of bytes the y-coordinate takes in an uncompressed P-384 public key.
const P384_Y_LEN: usize = <NistP384 as Curve>::FieldBytesSize::INT;
/// Number of bytes the x and y coordinates take in an uncompressed P-384 public key when concatenated together.
@@ -109,7 +109,7 @@ mod spki {
)]
const P384_LEN_U8: u8 = P384_LEN as u8;
/// Error returned from [`SubjectPublicKeyInfo::from_der`].
- pub enum SubjectPublicKeyInfoErr {
+ pub(super) enum SubjectPublicKeyInfoErr {
/// The DER-encoded `SubjectPublicKeyInfo` had an invalid length.
Len,
/// The length of the DER-encoded Ed25519 key was invalid.
@@ -165,16 +165,18 @@ mod spki {
/// Types that can be deserialized from the DER-encoded ASN.1 `SubjectPublicKeyInfo` as defined in
/// [RFC 5280](https://datatracker.ietf.org/doc/html/rfc5280#appendix-A.1) and other applicable RFCs
/// and documents (e.g., [ITU-T X.690](https://www.itu.int/rec/T-REC-X.690-202102-I/en)).
- pub trait SubjectPublicKeyInfo<'a>: Sized {
+ pub(super) trait SubjectPublicKeyInfo<'a>: Sized {
/// Transforms the DER-encoded ASN.1 `SubjectPublicKeyInfo` into `Self`.
///
/// # Errors
///
/// Errors iff `der` does not conform.
+ #[expect(single_use_lifetimes, reason = "false positive")]
fn from_der<'b: 'a>(der: &'b [u8]) -> Result<Self, SubjectPublicKeyInfoErr>;
}
impl<'a> SubjectPublicKeyInfo<'a> for Ed25519PubKey<&'a [u8]> {
- fn from_der<'b: 'a>(der: &'a [u8]) -> Result<Self, SubjectPublicKeyInfoErr> {
+ #[expect(single_use_lifetimes, reason = "false positive")]
+ fn from_der<'b: 'a>(der: &'b [u8]) -> Result<Self, SubjectPublicKeyInfoErr> {
/// ```asn
/// SubjectPublicKeyInfo ::= SEQUENCE {
/// algorithm AlgorithmIdentifier,
@@ -230,6 +232,7 @@ mod spki {
}
}
impl<'a> SubjectPublicKeyInfo<'a> for UncompressedP256PubKey<'a> {
+ #[expect(single_use_lifetimes, reason = "false positive")]
fn from_der<'b: 'a>(der: &'b [u8]) -> Result<Self, SubjectPublicKeyInfoErr> {
// ```asn
// SubjectPublicKeyInfo ::= SEQUENCE {
@@ -321,6 +324,7 @@ mod spki {
}
}
impl<'a> SubjectPublicKeyInfo<'a> for UncompressedP384PubKey<'a> {
+ #[expect(single_use_lifetimes, reason = "false positive")]
fn from_der<'b: 'a>(der: &'b [u8]) -> Result<Self, SubjectPublicKeyInfoErr> {
// ```asn
// SubjectPublicKeyInfo ::= SEQUENCE {
@@ -409,6 +413,7 @@ mod spki {
}
}
impl<'a> SubjectPublicKeyInfo<'a> for RsaPubKey<&'a [u8]> {
+ #[expect(single_use_lifetimes, reason = "false positive")]
#[expect(
clippy::arithmetic_side_effects,
clippy::big_endian_bytes,
@@ -643,6 +648,7 @@ mod spki {
}
}
impl<'a> SubjectPublicKeyInfo<'a> for UncompressedPubKey<'a> {
+ #[expect(single_use_lifetimes, reason = "false positive")]
fn from_der<'b: 'a>(der: &'b [u8]) -> Result<Self, SubjectPublicKeyInfoErr> {
// The lengths of the three key types do not overlap.
match der.len() {
@@ -744,7 +750,7 @@ impl<'e> Deserialize<'e> for AttObj {
struct AttObjVisitor;
impl Visitor<'_> for AttObjVisitor {
type Value = AttObj;
- fn expecting(&self, formatter: &mut fmt::Formatter<'_>) -> fmt::Result {
+ fn expecting(&self, formatter: &mut Formatter<'_>) -> fmt::Result {
formatter.write_str("base64url-encoded attestation object")
}
#[expect(
diff --git a/src/response/register/ser_relaxed.rs b/src/response/register/ser_relaxed.rs
@@ -22,7 +22,7 @@ use core::{
};
use serde::de::{Deserialize, Deserializer, Error, MapAccess, Unexpected, Visitor};
/// `newtype` around `CredentialPropertiesOutput` with a "relaxed" [`Self::deserialize`] implementation.
-#[derive(Debug)]
+#[derive(Clone, Copy, Debug)]
pub struct CredentialPropertiesOutputRelaxed(pub CredentialPropertiesOutput);
impl From<CredentialPropertiesOutputRelaxed> for CredentialPropertiesOutput {
#[inline]
@@ -49,7 +49,7 @@ impl<'de> Deserialize<'de> for CredentialPropertiesOutputRelaxed {
}
}
/// `newtype` around `AuthenticationExtensionsPrfOutputs` with a "relaxed" [`Self::deserialize`] implementation.
-#[derive(Debug)]
+#[derive(Clone, Copy, Debug)]
pub struct AuthenticationExtensionsPrfOutputsRelaxed(AuthenticationExtensionsPrfOutputs);
impl From<AuthenticationExtensionsPrfOutputsRelaxed> for AuthenticationExtensionsPrfOutputs {
#[inline]
@@ -94,7 +94,7 @@ impl<'de> Deserialize<'de> for AuthenticationExtensionsPrfOutputsRelaxed {
}
}
/// `newtype` around `ClientExtensionsOutputs` with a "relaxed" [`Self::deserialize`] implementation.
-#[derive(Debug)]
+#[derive(Clone, Copy, Debug)]
pub struct ClientExtensionsOutputsRelaxed(pub ClientExtensionsOutputs);
impl ClientExtensions for ClientExtensionsOutputsRelaxed {
fn empty() -> Self {