Skip to main content

pray_core/
trust.rs

1use crate::{PrayError, PrayResult};
2use serde::{Deserialize, Serialize};
3use std::fs;
4use std::path::Path;
5
6#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)]
7pub struct RegistryTrustSettings {
8    #[serde(default)]
9    pub email_confirmation: EmailConfirmationPolicy,
10    #[serde(default)]
11    pub passkeys_enabled: bool,
12    #[serde(default)]
13    pub ssh_keys_enabled: bool,
14    #[serde(default)]
15    pub ssh_agent_signing_enabled: bool,
16}
17
18impl Default for RegistryTrustSettings {
19    fn default() -> Self {
20        Self {
21            email_confirmation: EmailConfirmationPolicy::Required,
22            passkeys_enabled: false,
23            ssh_keys_enabled: false,
24            ssh_agent_signing_enabled: false,
25        }
26    }
27}
28
29#[derive(Debug, Clone, Copy, PartialEq, Eq, Serialize, Deserialize, Default)]
30#[serde(rename_all = "snake_case")]
31pub enum EmailConfirmationPolicy {
32    #[default]
33    Required,
34    Optional,
35    Disabled,
36}
37
38impl RegistryTrustSettings {
39    pub fn email_confirmation_label(&self) -> &'static str {
40        match self.email_confirmation {
41            EmailConfirmationPolicy::Required => "required",
42            EmailConfirmationPolicy::Optional => "optional",
43            EmailConfirmationPolicy::Disabled => "disabled",
44        }
45    }
46
47    pub fn passkeys_label(&self) -> &'static str {
48        if self.passkeys_enabled {
49            "enabled"
50        } else {
51            "disabled"
52        }
53    }
54
55    pub fn ssh_keys_label(&self) -> &'static str {
56        if self.ssh_keys_enabled {
57            "enabled"
58        } else {
59            "disabled"
60        }
61    }
62
63    pub fn ssh_agent_label(&self) -> &'static str {
64        if self.ssh_agent_signing_enabled {
65            "enabled"
66        } else {
67            "disabled"
68        }
69    }
70}
71
72pub fn read_registry_trust_settings(root: &Path) -> PrayResult<RegistryTrustSettings> {
73    let path = root.join("v1/trust.json");
74    let Ok(text) = fs::read_to_string(&path) else {
75        return Ok(RegistryTrustSettings::default());
76    };
77    let settings: RegistryTrustSettings =
78        serde_json::from_str(&text).map_err(|error| PrayError::Parse {
79            kind: "registry trust settings",
80            message: error.to_string(),
81        })?;
82    Ok(settings)
83}
84
85pub fn write_registry_trust_settings(
86    root: &Path,
87    settings: &RegistryTrustSettings,
88) -> PrayResult<()> {
89    let path = root.join("v1/trust.json");
90    if let Some(parent) = path.parent() {
91        fs::create_dir_all(parent)?;
92    }
93    fs::write(
94        path,
95        serde_json::to_string_pretty(settings)
96            .map_err(|error| PrayError::Manifest(error.to_string()))?,
97    )?;
98    Ok(())
99}
100
101#[cfg(test)]
102mod tests {
103    use super::*;
104
105    #[test]
106    fn defaults_require_email_confirmation_and_disable_other_methods() {
107        let settings = RegistryTrustSettings::default();
108        assert_eq!(settings.email_confirmation_label(), "required");
109        assert_eq!(settings.passkeys_label(), "disabled");
110        assert_eq!(settings.ssh_keys_label(), "disabled");
111        assert_eq!(settings.ssh_agent_label(), "disabled");
112    }
113
114    #[test]
115    fn parses_optional_email_confirmation_and_key_methods() {
116        let settings: RegistryTrustSettings = serde_json::from_str(
117            r#"{
118                "email_confirmation": "optional",
119                "passkeys_enabled": true,
120                "ssh_keys_enabled": true,
121                "ssh_agent_signing_enabled": true
122            }"#,
123        )
124        .expect("parse trust settings");
125
126        assert_eq!(
127            settings.email_confirmation,
128            EmailConfirmationPolicy::Optional
129        );
130        assert_eq!(settings.email_confirmation_label(), "optional");
131        assert_eq!(settings.passkeys_label(), "enabled");
132        assert_eq!(settings.ssh_keys_label(), "enabled");
133        assert_eq!(settings.ssh_agent_label(), "enabled");
134    }
135}