Repository: google/OpenSK
File: src/ctap/mod.rs (Rust)

Code before:
            .check_command_permission(now)?;
        let (assertion_input, credential_key) = self
            .stateful_command_permission
            .next_assertion_credential()?;
        let credential = self.persistent_store.get_credential(credential_key)?;
        self.assertion_response(credential, assertion_input, None)
    }

    fn process_get_info(&self) -> Result<ResponseData, Ctap2StatusCode> {
        let has_always_uv = self.persistent_store.has_always_uv()?;
        #[cfg(feature = "with_ctap1")]
        let mut versions = vec![
            String::from(FIDO2_VERSION_STRING),
            String::from(FIDO2_1_VERSION_STRING),
        ];
        #[cfg(feature = "with_ctap1")]
        {
            if !has_always_uv {
                versions.insert(0, String::from(U2F_VERSION_STRING))
            }
        }
        #[cfg(not(feature = "with_ctap1"))]
        let versions = vec![
            String::from(FIDO2_VERSION_STRING),
            String::from(FIDO2_1_VERSION_STRING),
        ];
        let mut options_map = BTreeMap::new();
        options_map.insert(String::from("rk"), true);
        options_map.insert(
            String::from("clientPin"),
            self.persistent_store.pin_hash()?.is_some(),
        );
        options_map.insert(String::from("up"), true);
        options_map.insert(String::from("pinUvAuthToken"), true);
        options_map.insert(String::from("largeBlobs"), true);
        options_map.insert(String::from("authnrCfg"), true);
        options_map.insert(String::from("credMgmt"), true);
        options_map.insert(String::from("setMinPINLength"), true);
        options_map.insert(String::from("makeCredUvNotRqd"), !has_always_uv);
        options_map.insert(String::from("alwaysUv"), has_always_uv);
        Ok(ResponseData::AuthenticatorGetInfo(
            AuthenticatorGetInfoResponse {
                versions,
                extensions: Some(vec![
                    String::from("hmac-secret"),
                    String::from("credProtect"),
                    String::from("minPinLength"),
                    String::from("credBlob"),
                    String::from("largeBlobKey"),
                ]),
                aaguid: self.persistent_store.aaguid()?,

Review comment (suggestion):
I guess this is convoluted because of the "mut" that should only be present with ctap1. What about disabling the lint for that line instead and only define the versions variable once? The lint may actually be disable only when not ctap1.

Code after:
            stored_credentials.sort_unstable_by_key(|&(_key, order)| order);
            let mut stored_credentials: Vec<usize> = stored_credentials
                .into_iter()
                .map(|(key, _order)| key)
                .collect();
            let credential = stored_credentials
                .pop()
                .map(|key| self.persistent_store.get_credential(key))
                .transpose()?;
            (credential, stored_credentials)
        };

        // This check comes before CTAP2_ERR_NO_CREDENTIALS in CTAP 2.0.
        // For CTAP 2.1, it was moved to a later protocol step.
        if options.up {
            (self.check_user_presence)(cid)?;
        }

        let credential = credential.ok_or(Ctap2StatusCode::CTAP2_ERR_NO_CREDENTIALS)?;

        self.increment_global_signature_counter()?;

        let assertion_input = AssertionInput {
            client_data_hash,
            auth_data: self.generate_auth_data(&rp_id_hash, flags)?,
            extensions,
            has_uv,
        };
        let number_of_credentials = if next_credential_keys.is_empty() {
            None
        } else {
            let number_of_credentials = Some(next_credential_keys.len() + 1);
            let assertion_state = StatefulCommand::GetAssertion(Box::new(AssertionState {
                assertion_input: assertion_input.clone(),
                next_credential_keys,
            }));
            self.stateful_command_permission
                .set_command(now, assertion_state);
            number_of_credentials
        };
        self.assertion_response(credential, assertion_input, number_of_credentials)
    }

    fn process_get_next_assertion(
        &mut self,
        now: ClockValue,
    ) -> Result<ResponseData, Ctap2StatusCode> {
        self.stateful_command_permission
            .check_command_permission(now)?;
        let (assertion_input, credential_key) = self
            .stateful_command_permission