Repository: meilisearch/meilisearch
File: crates/meilisearch-types/src/settings.rs (Rust)

Code before:
    #[deserr(skip)]
    pub _kind: PhantomData<T>,
}

impl<T> Settings<T> {
    pub fn hide_secrets(&mut self) {
        let Setting::Set(embedders) = &mut self.embedders else {
            return;
        };

        for mut embedder in embedders.values_mut() {
            let SettingEmbeddingSettings { inner: Setting::Set(embedder) } = &mut embedder else {
                continue;
            };

            let Setting::Set(api_key) = &mut embedder.api_key else {
                continue;
            };

            hide_secret(api_key, 0);
        }
    }
}

pub fn hide_secret(secret: &mut String, secret_offset: usize) {
    match secret.len().checked_sub(secret_offset) {
        None => (),
        Some(x) if x < 10 => {
            secret.replace_range(secret_offset.., "XXX...");
        }
        Some(x) if x < 20 => {
            secret.replace_range((secret_offset + 2).., "XXXX...");
        }
        Some(x) if x < 30 => {
            secret.replace_range((secret_offset + 3).., "XXXXX...");
        }
        Some(_x) => {
            secret.replace_range((secret_offset + 5).., "XXXXXX...");
        }
    }
}

impl Settings<Checked> {
    pub fn cleared() -> Settings<Checked> {
        Settings {
            displayed_attributes: Setting::Reset.into(),
            searchable_attributes: Setting::Reset.into(),
            filterable_attributes: Setting::Reset,
            sortable_attributes: Setting::Reset,
            ranking_rules: Setting::Reset,
            stop_words: Setting::Reset,

Review comment (security):
```suggestion
/// Redact a secret string, starting from the `secret_offset`th byte.
pub fn hide_secret(secret: &mut String, secret_offset: usize) {
```

Code after:
    #[deserr(skip)]
    pub _kind: PhantomData<T>,
}

impl<T> Settings<T> {
    pub fn hide_secrets(&mut self) {
        let Setting::Set(embedders) = &mut self.embedders else {
            return;
        };

        for mut embedder in embedders.values_mut() {
            let SettingEmbeddingSettings { inner: Setting::Set(embedder) } = &mut embedder else {
                continue;
            };

            let Setting::Set(api_key) = &mut embedder.api_key else {
                continue;
            };

            hide_secret(api_key, 0);
        }
    }
}

/// Redact a secret string, starting from the `secret_offset`th byte.
pub fn hide_secret(secret: &mut String, secret_offset: usize) {
    match secret.len().checked_sub(secret_offset) {
        None => (),
        Some(x) if x < 10 => {
            secret.replace_range(secret_offset.., "XXX...");
        }
        Some(x) if x < 20 => {
            secret.replace_range((secret_offset + 2).., "XXXX...");
        }
        Some(x) if x < 30 => {
            secret.replace_range((secret_offset + 3).., "XXXXX...");
        }
        Some(_x) => {
            secret.replace_range((secret_offset + 5).., "XXXXXX...");
        }
    }
}

impl Settings<Checked> {
    pub fn cleared() -> Settings<Checked> {
        Settings {
            displayed_attributes: Setting::Reset.into(),
            searchable_attributes: Setting::Reset.into(),
            filterable_attributes: Setting::Reset,
            sortable_attributes: Setting::Reset,
            ranking_rules: Setting::Reset,