bucketwarden-server 0.1.0

BucketWarden storage server runtime.
Documentation
use super::*;

impl BucketWarden {
    pub fn console_api_preferences_read(
        &mut self,
        access_key_id: &str,
    ) -> Result<ConsoleApiPreferences, RuntimeError> {
        let principal = self.console_api_principal(access_key_id)?;
        self.require_operator_action(
            &principal,
            OperatorAction::ReadDiagnostics,
            "*",
            "ui:GetPreferences",
        )?;
        Ok(ConsoleApiPreferences {
            values: self
                .console_preferences
                .get(&principal)
                .cloned()
                .unwrap_or_default(),
        })
    }

    pub fn console_api_preferences_write(
        &mut self,
        access_key_id: &str,
        preferences: ConsoleApiPreferences,
    ) -> Result<ConsoleApiPreferences, RuntimeError> {
        let principal = self.console_api_principal(access_key_id)?;
        self.require_operator_action(
            &principal,
            OperatorAction::ReadDiagnostics,
            "*",
            "ui:PutPreferences",
        )?;
        validate_preferences(&preferences.values)?;
        self.console_preferences
            .insert(principal.clone(), preferences.values.clone());
        self.audit.append(
            &principal,
            "ui:PutPreferences",
            "*",
            AuditOutcome::Allowed,
            Some(format!("keys={}", preferences.values.len())),
        );
        Ok(preferences)
    }
}

fn validate_preferences(values: &BTreeMap<String, String>) -> Result<(), RuntimeError> {
    if values.len() > 64 {
        return Err(invalid_preference("count", values.len().to_string()));
    }
    for (key, value) in values {
        if key.trim().is_empty() || key.len() > 128 {
            return Err(invalid_preference("key", key.clone()));
        }
        if value.len() > 4096 {
            return Err(invalid_preference("value", key.clone()));
        }
        if !key
            .chars()
            .all(|ch| ch.is_ascii_alphanumeric() || matches!(ch, '.' | '-' | '_'))
        {
            return Err(invalid_preference("key", key.clone()));
        }
    }
    Ok(())
}

fn invalid_preference(name: &str, value: String) -> RuntimeError {
    RuntimeError::InvalidListParameter {
        name: format!("preference-{name}"),
        value,
    }
}