mirror of
https://github.com/jackwener/wx-cli.git
synced 2026-10-08 15:45:46 +00:00
fix(daemon,scanner,crypto): harden lifecycle, widen Windows page scan, fix SQLCipher short read (#54)
- daemon: write pid file only after IPC bound; clean sock+pid on normal return - transport: PidFile JSON metadata + identity verification (ps/QueryFullProcessImageNameW); SIGTERM with poll-timeout; backward-compat read for plain-text pid - daemon_cmd: status/stop work with both new JSON and legacy plain-text pid file - config: cwd → exe_dir → ~/.wx-cli config precedence matches `wx init` write order; Windows DB auto-detect picks newest by latest mtime - crypto: full_decrypt uses read_exact for intermediate pages, zero-pads only the final partial page; tests cover short-chunk reads and early EOF - scanner/windows: page protect check covers PAGE_READWRITE / PAGE_WRITECOPY / PAGE_EXECUTE_*WRITE* with modifier-bit stripping Cross-reviewed by @wx-cli-coder. Windows verified via `cargo check --target x86_64-pc-windows-gnu` (no Windows runtime test).
This commit is contained in:
+21
-10
@@ -25,9 +25,7 @@ async fn async_run() -> Result<()> {
|
||||
tokio::fs::create_dir_all(&cli_dir).await?;
|
||||
tokio::fs::create_dir_all(config::cache_dir()).await?;
|
||||
|
||||
// 写 PID 文件
|
||||
let pid = std::process::id();
|
||||
tokio::fs::write(config::pid_path(), pid.to_string()).await?;
|
||||
|
||||
// 注册 SIGTERM / SIGINT 处理
|
||||
setup_signal_handler().await;
|
||||
@@ -39,7 +37,8 @@ async fn async_run() -> Result<()> {
|
||||
eprintln!("[daemon] DB_DIR: {}", cfg.db_dir.display());
|
||||
|
||||
// 加载密钥
|
||||
let keys_content = tokio::fs::read_to_string(&cfg.keys_file).await
|
||||
let keys_content = tokio::fs::read_to_string(&cfg.keys_file)
|
||||
.await
|
||||
.map_err(|e| anyhow::anyhow!("读取密钥文件 {:?} 失败: {}", cfg.keys_file, e))?;
|
||||
let keys_raw: serde_json::Value = serde_json::from_str(&keys_content)?;
|
||||
let all_keys = extract_keys(&keys_raw);
|
||||
@@ -49,11 +48,14 @@ async fn async_run() -> Result<()> {
|
||||
let db = Arc::new(cache::DbCache::new(cfg.db_dir.clone(), all_keys.clone()).await?);
|
||||
|
||||
// 收集消息 DB 列表
|
||||
let msg_db_keys: Vec<String> = all_keys.keys()
|
||||
let msg_db_keys: Vec<String> = all_keys
|
||||
.keys()
|
||||
.filter(|k| {
|
||||
let k = k.replace('\\', "/");
|
||||
k.contains("message/message_") && k.ends_with(".db")
|
||||
&& !k.contains("_fts") && !k.contains("_resource")
|
||||
k.contains("message/message_")
|
||||
&& k.ends_with(".db")
|
||||
&& !k.contains("_fts")
|
||||
&& !k.contains("_resource")
|
||||
})
|
||||
.cloned()
|
||||
.collect();
|
||||
@@ -82,7 +84,9 @@ async fn async_run() -> Result<()> {
|
||||
let names_arc = Arc::new(tokio::sync::RwLock::new(Arc::new(names)));
|
||||
|
||||
// 启动 IPC server(阻塞)
|
||||
server::serve(Arc::clone(&db), Arc::clone(&names_arc)).await?;
|
||||
let serve_result = server::serve(Arc::clone(&db), Arc::clone(&names_arc)).await;
|
||||
cleanup_ipc_files();
|
||||
serve_result?;
|
||||
|
||||
Ok(())
|
||||
}
|
||||
@@ -96,7 +100,9 @@ fn extract_keys(json: &serde_json::Value) -> HashMap<String, String> {
|
||||
let mut result = HashMap::new();
|
||||
if let Some(obj) = json.as_object() {
|
||||
for (k, v) in obj {
|
||||
if k.starts_with('_') { continue; }
|
||||
if k.starts_with('_') {
|
||||
continue;
|
||||
}
|
||||
let enc_key = if let Some(s) = v.as_str() {
|
||||
s.to_string()
|
||||
} else if let Some(obj2) = v.as_object() {
|
||||
@@ -132,8 +138,13 @@ async fn setup_signal_handler() {
|
||||
});
|
||||
}
|
||||
|
||||
#[cfg(unix)]
|
||||
fn cleanup_and_exit() {
|
||||
let _ = std::fs::remove_file(config::sock_path());
|
||||
let _ = std::fs::remove_file(config::pid_path());
|
||||
cleanup_ipc_files();
|
||||
std::process::exit(0);
|
||||
}
|
||||
|
||||
fn cleanup_ipc_files() {
|
||||
let _ = std::fs::remove_file(config::sock_path());
|
||||
let _ = std::fs::remove_file(config::pid_path());
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user