Some checks failed
Secrets CLI - Build & Release / 版本 & Release (push) Successful in 2s
Secrets CLI - Build & Release / 质量检查 (fmt / clippy / test) (push) Successful in 1m42s
Secrets CLI - Build & Release / Build (x86_64-unknown-linux-musl) (push) Successful in 1m18s
Secrets CLI - Build & Release / 发布草稿 Release (push) Successful in 2s
Secrets CLI - Build & Release / Build (aarch64-apple-darwin) (push) Failing after 7m40s
Secrets CLI - Build & Release / Build (x86_64-pc-windows-msvc) (push) Has been cancelled
P0: - fix(config): config_dir 使用 home_dir 回退,避免 ~ 不展开 - fix(search): 模糊查询转义 LIKE 通配符 % 和 _ P1: - chore(db): 连接池添加 acquire_timeout 10s - refactor(update): 消除 meta_keys/secret_keys 重复计算 P2: - refactor(config): 合并 ConfigAction 枚举 - chore(deps): 移除 clap/env、uuid/v4 无用 features - perf(main): delete 命令跳过 master_key 加载 - i18n(config): 统一错误消息为英文 - perf(search): show_secrets=false 时不再解密获取 key_count - feat(delete,update): 支持 -o json/json-compact 输出 P3: - feat(search): --tag 支持多值交叉过滤 docs: 将 seed-data.sh 替换为 setup-gitea-actions.sh Made-with: Cursor
74 lines
2.2 KiB
Rust
74 lines
2.2 KiB
Rust
use anyhow::{Context, Result};
|
|
use serde::{Deserialize, Serialize};
|
|
use std::fs;
|
|
use std::path::PathBuf;
|
|
|
|
#[derive(Debug, Serialize, Deserialize, Default)]
|
|
pub struct Config {
|
|
pub database_url: Option<String>,
|
|
}
|
|
|
|
pub fn config_dir() -> PathBuf {
|
|
dirs::config_dir()
|
|
.or_else(|| dirs::home_dir().map(|h| h.join(".config")))
|
|
.unwrap_or_else(|| PathBuf::from(".config"))
|
|
.join("secrets")
|
|
}
|
|
|
|
pub fn config_path() -> PathBuf {
|
|
config_dir().join("config.toml")
|
|
}
|
|
|
|
pub fn load_config() -> Result<Config> {
|
|
let path = config_path();
|
|
if !path.exists() {
|
|
return Ok(Config::default());
|
|
}
|
|
let content = fs::read_to_string(&path)
|
|
.with_context(|| format!("failed to read config file: {}", path.display()))?;
|
|
let config: Config = toml::from_str(&content)
|
|
.with_context(|| format!("failed to parse config file: {}", path.display()))?;
|
|
Ok(config)
|
|
}
|
|
|
|
pub fn save_config(config: &Config) -> Result<()> {
|
|
let dir = config_dir();
|
|
fs::create_dir_all(&dir)
|
|
.with_context(|| format!("failed to create config dir: {}", dir.display()))?;
|
|
|
|
let path = config_path();
|
|
let content = toml::to_string_pretty(config).context("failed to serialize config")?;
|
|
fs::write(&path, &content)
|
|
.with_context(|| format!("failed to write config file: {}", path.display()))?;
|
|
|
|
// Set file permissions to 0600 (owner read/write only)
|
|
#[cfg(unix)]
|
|
{
|
|
use std::os::unix::fs::PermissionsExt;
|
|
let perms = fs::Permissions::from_mode(0o600);
|
|
fs::set_permissions(&path, perms)
|
|
.with_context(|| format!("failed to set file permissions: {}", path.display()))?;
|
|
}
|
|
|
|
Ok(())
|
|
}
|
|
|
|
/// Resolve database URL by priority:
|
|
/// 1. --db-url CLI flag (if non-empty)
|
|
/// 2. database_url in ~/.config/secrets/config.toml
|
|
/// 3. Error with setup instructions
|
|
pub fn resolve_db_url(cli_db_url: &str) -> Result<String> {
|
|
if !cli_db_url.is_empty() {
|
|
return Ok(cli_db_url.to_string());
|
|
}
|
|
|
|
let config = load_config()?;
|
|
if let Some(url) = config.database_url
|
|
&& !url.is_empty()
|
|
{
|
|
return Ok(url);
|
|
}
|
|
|
|
anyhow::bail!("Database not configured. Run:\n\n secrets config set-db <DATABASE_URL>\n")
|
|
}
|