chore(hardening): tighten security and footprint defaults
This commit is contained in:
125
crates/core/src/paths.rs
Normal file
125
crates/core/src/paths.rs
Normal file
@@ -0,0 +1,125 @@
|
||||
use std::path::PathBuf;
|
||||
|
||||
use crate::types::ModelId;
|
||||
|
||||
#[derive(Debug, Clone, PartialEq, Eq)]
|
||||
pub struct AppPaths {
|
||||
app_data_dir: PathBuf,
|
||||
}
|
||||
|
||||
impl AppPaths {
|
||||
pub fn current() -> Self {
|
||||
Self {
|
||||
app_data_dir: resolve_app_data_dir(),
|
||||
}
|
||||
}
|
||||
|
||||
pub fn app_data_dir(&self) -> PathBuf {
|
||||
self.app_data_dir.clone()
|
||||
}
|
||||
|
||||
pub fn database_path(&self) -> PathBuf {
|
||||
self.app_data_dir.join("kon.db")
|
||||
}
|
||||
|
||||
pub fn recordings_dir(&self) -> PathBuf {
|
||||
self.app_data_dir.join("recordings")
|
||||
}
|
||||
|
||||
pub fn crashes_dir(&self) -> PathBuf {
|
||||
self.app_data_dir.join("crashes")
|
||||
}
|
||||
|
||||
pub fn logs_dir(&self) -> PathBuf {
|
||||
self.app_data_dir.join("logs")
|
||||
}
|
||||
|
||||
pub fn diagnostic_reports_dir(&self) -> PathBuf {
|
||||
self.app_data_dir.join("diagnostic-reports")
|
||||
}
|
||||
|
||||
pub fn models_dir(&self) -> PathBuf {
|
||||
self.app_data_dir.join("models")
|
||||
}
|
||||
|
||||
pub fn speech_model_dir(&self, id: &ModelId) -> PathBuf {
|
||||
self.models_dir().join(id.as_str())
|
||||
}
|
||||
|
||||
pub fn llm_models_dir(&self) -> PathBuf {
|
||||
self.models_dir().join("llm")
|
||||
}
|
||||
|
||||
pub fn migration_sentinel(&self, name: &str) -> PathBuf {
|
||||
self.app_data_dir.join(format!(".{name}.sentinel"))
|
||||
}
|
||||
}
|
||||
|
||||
pub fn app_paths() -> AppPaths {
|
||||
AppPaths::current()
|
||||
}
|
||||
|
||||
pub fn app_data_dir() -> PathBuf {
|
||||
app_paths().app_data_dir()
|
||||
}
|
||||
|
||||
fn resolve_app_data_dir() -> PathBuf {
|
||||
#[cfg(target_os = "windows")]
|
||||
{
|
||||
let local_app_data = std::env::var("LOCALAPPDATA").unwrap_or_else(|_| ".".to_string());
|
||||
return PathBuf::from(local_app_data).join("kon");
|
||||
}
|
||||
|
||||
#[cfg(target_os = "macos")]
|
||||
{
|
||||
let home = std::env::var("HOME").unwrap_or_else(|_| "/tmp".to_string());
|
||||
return PathBuf::from(home)
|
||||
.join("Library")
|
||||
.join("Application Support")
|
||||
.join("Kon");
|
||||
}
|
||||
|
||||
#[cfg(target_os = "linux")]
|
||||
{
|
||||
let home = std::env::var("HOME").unwrap_or_else(|_| "/tmp".to_string());
|
||||
let legacy = PathBuf::from(&home).join(".kon");
|
||||
if legacy.exists() {
|
||||
return legacy;
|
||||
}
|
||||
if let Ok(xdg) = std::env::var("XDG_DATA_HOME") {
|
||||
if !xdg.is_empty() {
|
||||
return PathBuf::from(xdg).join("kon");
|
||||
}
|
||||
}
|
||||
PathBuf::from(home).join(".local").join("share").join("kon")
|
||||
}
|
||||
|
||||
#[cfg(not(any(target_os = "windows", target_os = "macos", target_os = "linux")))]
|
||||
{
|
||||
let home = std::env::var("HOME").unwrap_or_else(|_| "/tmp".to_string());
|
||||
PathBuf::from(home).join(".kon")
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
mod tests {
|
||||
use super::AppPaths;
|
||||
use crate::types::ModelId;
|
||||
use std::path::PathBuf;
|
||||
|
||||
#[test]
|
||||
fn derives_all_paths_from_one_base() {
|
||||
let paths = AppPaths {
|
||||
app_data_dir: PathBuf::from("/tmp/kon-test"),
|
||||
};
|
||||
assert_eq!(paths.database_path(), PathBuf::from("/tmp/kon-test/kon.db"));
|
||||
assert_eq!(
|
||||
paths.speech_model_dir(&ModelId::new("whisper-base-en")),
|
||||
PathBuf::from("/tmp/kon-test/models/whisper-base-en")
|
||||
);
|
||||
assert_eq!(
|
||||
paths.llm_models_dir(),
|
||||
PathBuf::from("/tmp/kon-test/models/llm")
|
||||
);
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user