1use crate::error::{Error, Result};
2
3pub fn validate_keyring_name(name: &str) -> Result<&str> {
12 if name.is_empty() {
13 return Err(Error::InvalidKeyringName {
14 name: name.to_string(),
15 reason: "keyring name cannot be empty".to_string(),
16 });
17 }
18
19 if !name
20 .chars()
21 .all(|c| c.is_ascii_alphanumeric() || c == '-' || c == '_')
22 {
23 return Err(Error::InvalidKeyringName {
24 name: name.to_string(),
25 reason:
26 "keyring name must contain only alphanumeric characters, hyphens, or underscores"
27 .to_string(),
28 });
29 }
30
31 Ok(name)
32}
33
34pub fn validate_keyid(keyid: &str) -> Result<String> {
44 if keyid.is_empty() {
45 return Err(Error::InvalidKeyId {
46 keyid: keyid.to_string(),
47 reason: "key ID cannot be empty".to_string(),
48 });
49 }
50
51 let normalized = keyid
52 .strip_prefix("0x")
53 .or_else(|| keyid.strip_prefix("0X"))
54 .unwrap_or(keyid)
55 .to_uppercase();
56
57 if !normalized.chars().all(|c| c.is_ascii_hexdigit()) {
58 return Err(Error::InvalidKeyId {
59 keyid: keyid.to_string(),
60 reason: "key ID must contain only hexadecimal characters".to_string(),
61 });
62 }
63
64 match normalized.len() {
65 8 | 16 | 40 => Ok(normalized),
66 len => Err(Error::InvalidKeyId {
67 keyid: keyid.to_string(),
68 reason: format!("key ID must be 8, 16, or 40 hex characters (got {})", len),
69 }),
70 }
71}
72
73#[cfg(test)]
74mod tests {
75 use super::*;
76
77 #[test]
78 fn test_valid_keyring_names() {
79 assert_eq!(validate_keyring_name("archlinux").unwrap(), "archlinux");
80 assert_eq!(
81 validate_keyring_name("archlinuxarm").unwrap(),
82 "archlinuxarm"
83 );
84 assert_eq!(validate_keyring_name("arch-linux").unwrap(), "arch-linux");
85 assert_eq!(validate_keyring_name("arch_linux").unwrap(), "arch_linux");
86 assert_eq!(validate_keyring_name("manjaro").unwrap(), "manjaro");
87 assert_eq!(validate_keyring_name("test123").unwrap(), "test123");
88 }
89
90 #[test]
91 fn test_invalid_keyring_name_empty() {
92 let err = validate_keyring_name("").unwrap_err();
93 assert!(matches!(err, Error::InvalidKeyringName { .. }));
94 }
95
96 #[test]
97 fn test_invalid_keyring_name_special_chars() {
98 let err = validate_keyring_name("$(whoami)").unwrap_err();
99 assert!(matches!(err, Error::InvalidKeyringName { .. }));
100
101 let err = validate_keyring_name("arch;linux").unwrap_err();
102 assert!(matches!(err, Error::InvalidKeyringName { .. }));
103
104 let err = validate_keyring_name("arch&linux").unwrap_err();
105 assert!(matches!(err, Error::InvalidKeyringName { .. }));
106
107 let err = validate_keyring_name("arch|linux").unwrap_err();
108 assert!(matches!(err, Error::InvalidKeyringName { .. }));
109
110 let err = validate_keyring_name("arch`whoami`").unwrap_err();
111 assert!(matches!(err, Error::InvalidKeyringName { .. }));
112
113 let err = validate_keyring_name("arch linux").unwrap_err();
114 assert!(matches!(err, Error::InvalidKeyringName { .. }));
115
116 let err = validate_keyring_name("arch\nlinux").unwrap_err();
117 assert!(matches!(err, Error::InvalidKeyringName { .. }));
118 }
119
120 #[test]
121 fn test_valid_short_keyid() {
122 assert_eq!(validate_keyid("DEADBEEF").unwrap(), "DEADBEEF");
123 assert_eq!(validate_keyid("deadbeef").unwrap(), "DEADBEEF");
124 }
125
126 #[test]
127 fn test_valid_long_keyid() {
128 assert_eq!(
129 validate_keyid("786C63F330D7CB92").unwrap(),
130 "786C63F330D7CB92"
131 );
132 }
133
134 #[test]
135 fn test_valid_fingerprint() {
136 assert_eq!(
137 validate_keyid("ABAF11C65A2970B130ABE3C479BE3E4300411886").unwrap(),
138 "ABAF11C65A2970B130ABE3C479BE3E4300411886"
139 );
140 }
141
142 #[test]
143 fn test_valid_with_0x_prefix() {
144 assert_eq!(validate_keyid("0xDEADBEEF").unwrap(), "DEADBEEF");
145 assert_eq!(validate_keyid("0XDEADBEEF").unwrap(), "DEADBEEF");
146 }
147
148 #[test]
149 fn test_invalid_empty() {
150 let err = validate_keyid("").unwrap_err();
151 assert!(matches!(err, Error::InvalidKeyId { .. }));
152 }
153
154 #[test]
155 fn test_invalid_non_hex() {
156 let err = validate_keyid("DEADBEEG").unwrap_err();
157 assert!(matches!(err, Error::InvalidKeyId { .. }));
158 }
159
160 #[test]
161 fn test_invalid_wrong_length() {
162 let err = validate_keyid("DEADBE").unwrap_err();
163 assert!(matches!(err, Error::InvalidKeyId { .. }));
164 }
165
166 #[test]
167 fn test_invalid_contains_spaces() {
168 let err = validate_keyid("DEAD BEEF").unwrap_err();
169 assert!(matches!(err, Error::InvalidKeyId { .. }));
170 }
171
172}