futu_backend/auth/device/permission_tighten.rs
1#[cfg(unix)]
2use super::storage::try_futu_opend_dir;
3
4/// 启动时扫 `~/.futu-opend-rs/` 把已存在的 secret 文件 (credentials-*.json
5/// / device-*.dat) 收紧到 0600. v1.4.101 及以前版本可能创建了 0644 文件,
6/// 此 fn 是迁移路径.
7///
8/// 由 `init_auth_state` (或类似入口) 在 daemon 启动早期调用. 失败 best-effort
9/// (warn but don't fail), 因为 chmod 失败 != 凭据本身失效.
10pub fn tighten_secret_files_at_startup() {
11 #[cfg(unix)]
12 {
13 use std::os::unix::fs::PermissionsExt;
14 let dir = match try_futu_opend_dir() {
15 Ok(dir) => dir,
16 Err(err) => {
17 tracing::warn!(
18 error = %err,
19 "auth secret-file permission tightening skipped because store dir is unavailable"
20 );
21 return;
22 }
23 };
24 let Ok(entries) = std::fs::read_dir(&dir) else {
25 return;
26 };
27 for entry in entries.flatten() {
28 let path = entry.path();
29 let Some(name) = path.file_name().and_then(|n| n.to_str()) else {
30 continue;
31 };
32 // 仅收紧 secret 文件: credentials-<hash>.json / device-<hash>.dat.
33 // 不收紧 keys.json (用户可能想 ACL 给 systemd group), 不收紧 logs/ etc.
34 //
35 // v1.4.104 external reviewer P2-004 (P2) fix: 扩展到 sidecar 文件 (`.backup` / `.bak` /
36 // `.tmp` / `.swp`). 编辑器 vim / git rebase / external backup tool 等
37 // 可能创建 `credentials-<hash>.json.backup` 0644 文件, 同样含 secret
38 // 不能放任. 任何 name 以 `credentials-` 或 `device-` 开头都收紧.
39 let is_secret = name.starts_with("credentials-") || name.starts_with("device-");
40 if !is_secret {
41 continue;
42 }
43 let Ok(meta) = entry.metadata() else { continue };
44 let mode = meta.permissions().mode() & 0o777;
45 if mode != 0o600 {
46 tracing::warn!(
47 path = %path.display(),
48 actual_mode = format!("0{:o}", mode),
49 "v1.4.102 BUG-012 fix: secret file has loose permissions; tightening to 0600"
50 );
51 if let Err(e) =
52 std::fs::set_permissions(&path, std::fs::Permissions::from_mode(0o600))
53 {
54 tracing::warn!(
55 path = %path.display(),
56 error = %e,
57 "failed to tighten secret file permissions; please chmod 0600 manually"
58 );
59 }
60 }
61 }
62 }
63 #[cfg(not(unix))]
64 {
65 // Windows: ACL 模型不同, 此 fn 不展开.
66 }
67}