pacman_key/
types.rs

1use chrono::NaiveDate;
2
3/// A GPG key from the pacman keyring.
4#[derive(Debug, Clone, PartialEq, Eq)]
5pub struct Key {
6    pub fingerprint: String,
7    pub uid: String,
8    pub created: Option<NaiveDate>,
9    pub expires: Option<NaiveDate>,
10    pub validity: KeyValidity,
11    pub key_type: KeyType,
12}
13
14/// The cryptographic algorithm and key size.
15#[derive(Debug, Clone, PartialEq, Eq)]
16pub struct KeyType {
17    pub algorithm: String,
18    pub bits: u32,
19}
20
21impl std::fmt::Display for KeyType {
22    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
23        write!(f, "{}{}", self.algorithm.to_lowercase(), self.bits)
24    }
25}
26
27/// GPG key validity level.
28///
29/// Represents how confident GPG is that the key belongs to the claimed identity.
30/// This is derived from signature verification and the web of trust, not to be
31/// confused with owner trust (how much we trust the key owner to sign other keys).
32///
33/// Values correspond to GPG's validity field in `--with-colons` output.
34#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash, PartialOrd, Ord, Default)]
35#[non_exhaustive]
36pub enum KeyValidity {
37    /// Validity unknown (new key or insufficient data)
38    #[default]
39    Unknown,
40    /// Validity undefined (not yet computed)
41    Undefined,
42    /// Key is explicitly distrusted
43    Never,
44    /// Marginally valid (some trust path exists)
45    Marginal,
46    /// Fully valid (strong trust path)
47    Full,
48    /// Ultimately valid (user's own key or explicitly trusted)
49    Ultimate,
50    /// Key has expired
51    Expired,
52    /// Key has been revoked
53    Revoked,
54}
55
56impl KeyValidity {
57    pub fn from_gpg_char(c: char) -> Self {
58        match c {
59            'o' => Self::Unknown,
60            'q' => Self::Undefined,
61            'n' => Self::Never,
62            'm' => Self::Marginal,
63            'f' => Self::Full,
64            'u' => Self::Ultimate,
65            'e' => Self::Expired,
66            'r' => Self::Revoked,
67            _ => Self::Unknown,
68        }
69    }
70}
71
72/// A signature on a key.
73#[derive(Debug, Clone, PartialEq, Eq)]
74pub struct Signature {
75    pub keyid: String,
76    pub uid: String,
77    pub created: Option<NaiveDate>,
78    pub expires: Option<NaiveDate>,
79    pub sig_class: String,
80}
81
82/// Progress updates during key refresh operations.
83#[derive(Debug, Clone, PartialEq, Eq)]
84#[non_exhaustive]
85pub enum RefreshProgress {
86    Starting {
87        total_keys: usize,
88    },
89    Refreshing {
90        current: usize,
91        total: usize,
92        keyid: String,
93    },
94    Completed,
95    Error {
96        keyid: String,
97        message: String,
98    },
99}
100
101/// Options for the key refresh operation.
102#[derive(Debug, Clone, Default)]
103pub struct RefreshOptions {
104    /// Timeout for the entire refresh operation, in seconds.
105    /// If None, no timeout is applied.
106    pub timeout_secs: Option<u64>,
107}
108
109
110#[cfg(test)]
111mod tests {
112    use super::*;
113
114    #[test]
115    fn test_key_validity_from_gpg_char() {
116        assert_eq!(KeyValidity::from_gpg_char('o'), KeyValidity::Unknown);
117        assert_eq!(KeyValidity::from_gpg_char('q'), KeyValidity::Undefined);
118        assert_eq!(KeyValidity::from_gpg_char('n'), KeyValidity::Never);
119        assert_eq!(KeyValidity::from_gpg_char('m'), KeyValidity::Marginal);
120        assert_eq!(KeyValidity::from_gpg_char('f'), KeyValidity::Full);
121        assert_eq!(KeyValidity::from_gpg_char('u'), KeyValidity::Ultimate);
122        assert_eq!(KeyValidity::from_gpg_char('e'), KeyValidity::Expired);
123        assert_eq!(KeyValidity::from_gpg_char('r'), KeyValidity::Revoked);
124        assert_eq!(KeyValidity::from_gpg_char('x'), KeyValidity::Unknown);
125        assert_eq!(KeyValidity::from_gpg_char('-'), KeyValidity::Unknown);
126    }
127}