Skip to main content

aster/codesign/
storage.rs

1//! 签名存储管理
2
3use std::collections::HashMap;
4use std::path::PathBuf;
5use std::sync::RwLock;
6
7use once_cell::sync::Lazy;
8
9use super::types::{CodeSignature, SigningKey};
10
11/// 签名目录
12fn get_signing_dir() -> PathBuf {
13    dirs::home_dir()
14        .unwrap_or_else(|| PathBuf::from("."))
15        .join(".aster")
16        .join("signing")
17}
18
19/// 密钥文件路径
20fn get_keys_file() -> PathBuf {
21    get_signing_dir().join("keys.json")
22}
23
24/// 签名文件路径
25fn get_signatures_file() -> PathBuf {
26    get_signing_dir().join("signatures.json")
27}
28
29/// 签名缓存
30static SIGNATURE_CACHE: Lazy<RwLock<HashMap<String, CodeSignature>>> =
31    Lazy::new(|| RwLock::new(HashMap::new()));
32
33/// 初始化签名系统
34pub fn init_signing() {
35    let dir = get_signing_dir();
36    if !dir.exists() {
37        let _ = std::fs::create_dir_all(&dir);
38        #[cfg(unix)]
39        {
40            use std::os::unix::fs::PermissionsExt;
41            let _ = std::fs::set_permissions(&dir, std::fs::Permissions::from_mode(0o700));
42        }
43    }
44}
45
46/// 保存密钥
47pub fn save_key(key: &SigningKey) -> Result<(), String> {
48    init_signing();
49
50    let mut keys = load_keys();
51    keys.retain(|k| k.id != key.id);
52    keys.push(key.clone());
53
54    let json = serde_json::to_string_pretty(&keys)
55        .map_err(|e| format!("Failed to serialize keys: {}", e))?;
56
57    std::fs::write(get_keys_file(), json).map_err(|e| format!("Failed to write keys: {}", e))?;
58
59    Ok(())
60}
61
62/// 加载密钥
63pub fn load_keys() -> Vec<SigningKey> {
64    let file = get_keys_file();
65    if !file.exists() {
66        return Vec::new();
67    }
68
69    std::fs::read_to_string(&file)
70        .ok()
71        .and_then(|s| serde_json::from_str(&s).ok())
72        .unwrap_or_default()
73}
74
75/// 缓存签名
76pub fn cache_signature(path: &str, signature: CodeSignature) {
77    if let Ok(mut cache) = SIGNATURE_CACHE.write() {
78        cache.insert(path.to_string(), signature);
79    }
80}
81
82/// 获取缓存的签名
83pub fn get_cached_signature(path: &str) -> Option<CodeSignature> {
84    // 先尝试从缓存获取
85    if let Ok(cache) = SIGNATURE_CACHE.read() {
86        if let Some(sig) = cache.get(path) {
87            return Some(sig.clone());
88        }
89    }
90
91    // 从文件加载
92    load_signatures();
93
94    SIGNATURE_CACHE.read().ok()?.get(path).cloned()
95}
96
97/// 保存签名到文件
98pub fn save_signatures() {
99    init_signing();
100
101    let signatures: HashMap<String, CodeSignature> = SIGNATURE_CACHE
102        .read()
103        .map(|c| c.clone())
104        .unwrap_or_default();
105
106    if let Ok(json) = serde_json::to_string_pretty(&signatures) {
107        let _ = std::fs::write(get_signatures_file(), json);
108    }
109}
110
111/// 从文件加载签名
112pub fn load_signatures() {
113    let file = get_signatures_file();
114    if !file.exists() {
115        return;
116    }
117
118    if let Ok(content) = std::fs::read_to_string(&file) {
119        if let Ok(sigs) = serde_json::from_str::<HashMap<String, CodeSignature>>(&content) {
120            if let Ok(mut cache) = SIGNATURE_CACHE.write() {
121                for (path, sig) in sigs {
122                    cache.insert(path, sig);
123                }
124            }
125        }
126    }
127}
128
129/// 清除文件签名
130pub fn clear_signature(file_path: &str) {
131    use std::path::Path;
132
133    let absolute_path = Path::new(file_path)
134        .canonicalize()
135        .map(|p| p.to_string_lossy().to_string())
136        .unwrap_or_else(|_| file_path.to_string());
137
138    if let Ok(mut cache) = SIGNATURE_CACHE.write() {
139        cache.remove(&absolute_path);
140    }
141    save_signatures();
142}
143
144/// 获取所有已签名文件
145pub fn get_signed_files() -> Vec<(String, CodeSignature)> {
146    load_signatures();
147
148    SIGNATURE_CACHE
149        .read()
150        .map(|c| c.iter().map(|(k, v)| (k.clone(), v.clone())).collect())
151        .unwrap_or_default()
152}
153
154/// 检查文件是否已签名
155pub fn is_signed(file_path: &str) -> bool {
156    use std::path::Path;
157
158    let absolute_path = Path::new(file_path)
159        .canonicalize()
160        .map(|p| p.to_string_lossy().to_string())
161        .unwrap_or_else(|_| file_path.to_string());
162
163    load_signatures();
164
165    SIGNATURE_CACHE
166        .read()
167        .map(|c| c.contains_key(&absolute_path))
168        .unwrap_or(false)
169}