Repository: astral-sh/uv
File: crates/uv-keyring/src/windows.rs (Rust)

Code before:
        }
        if let Some(target_alias) = attributes.get(&"target_alias") {
            cred.target_alias = (*target_alias).to_string();
        }
        if let Some(username) = attributes.get(&"username") {
            cred.username = (*username).to_string();
        }
        cred.validate_attributes(Some(&secret), None)?;
        cred.save_credential(&secret).await
    }

    /// Delete the underlying generic credential for this entry, if any.
    ///
    /// Returns a [`NoEntry`](ErrorCode::NoEntry) error if there is no
    /// credential in the store.
    async fn delete_credential(&self) -> Result<()> {
        self.validate_attributes(None, None)?;
        let target_name = to_wstr(&self.target_name);
        let cred_type = CRED_TYPE_GENERIC;
        // SAFETY: Calling Windows API
        let winerr: u32 = crate::blocking::spawn_blocking(move || unsafe {
            Ok(if CredDeleteW(target_name.as_ptr(), cred_type, 0) != 0 {
                0 // success
            } else {
                GetLastError()
            })
        })
        .await?;

        if winerr == 0 {
            Ok(())
        } else {
            Err(Error::from_win32_code(winerr).into())
        }
    }

    /// Return the underlying concrete object with an `Any` type so that it can
    /// be downgraded to a [`WinCredential`] for platform-specific processing.
    fn as_any(&self) -> &dyn std::any::Any {
        self
    }

    /// Expose the concrete debug formatter for use via the [`Credential`] trait
    fn debug_fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
        std::fmt::Debug::fmt(self, f)
    }
}

impl WinCredential {
    fn validate_attributes(&self, secret: Option<&[u8]>, password: Option<&str>) -> Result<()> {
        if self.username.len() > CRED_MAX_USERNAME_LENGTH as usize {

Review comment (security):
Notice here we called `decode_error` which invokes `GetLastError` _outside_ of the credential delete thread

Code after:
        }
        if let Some(target_alias) = attributes.get(&"target_alias") {
            cred.target_alias = (*target_alias).to_string();
        }
        if let Some(username) = attributes.get(&"username") {
            cred.username = (*username).to_string();
        }
        cred.validate_attributes(Some(&secret), None)?;
        cred.save_credential(&secret).await
    }

    /// Delete the underlying generic credential for this entry, if any.
    ///
    /// Returns a [`NoEntry`](ErrorCode::NoEntry) error if there is no
    /// credential in the store.
    async fn delete_credential(&self) -> Result<()> {
        self.validate_attributes(None, None)?;
        let target_name = to_wstr(&self.target_name);
        let cred_type = CRED_TYPE_GENERIC;
        crate::blocking::spawn_blocking(move || {
            // SAFETY: Calling Windows API
            if unsafe { CredDeleteW(target_name.as_ptr(), cred_type, 0) } != 0 {
                Ok(())
            } else {
                // SAFETY: Calling Windows API
                Err(Error::from_win32_code(unsafe { GetLastError() }).into())
            }
        })
        .await
    }

    /// Return the underlying concrete object with an `Any` type so that it can
    /// be downgraded to a [`WinCredential`] for platform-specific processing.
    fn as_any(&self) -> &dyn std::any::Any {
        self
    }

    /// Expose the concrete debug formatter for use via the [`Credential`] trait
    fn debug_fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
        std::fmt::Debug::fmt(self, f)
    }
}

impl WinCredential {
    fn validate_attributes(&self, secret: Option<&[u8]>, password: Option<&str>) -> Result<()> {
        if self.username.len() > CRED_MAX_USERNAME_LENGTH as usize {
            return Err(ErrorCode::TooLong(
                String::from("user"),
                CRED_MAX_USERNAME_LENGTH,
            ));
        }