bp_core/
config.rs

1//! XDG-compliant configuration paths for BillPouch.
2//!
3//! All paths are rooted at the platform data directory
4//! (`~/.local/share/billpouch` on Linux, `~/Library/Application Support/billpouch` on macOS).
5//! Call [`ensure_dirs`] once at daemon startup to create the directory tree.
6
7use crate::error::{BpError, BpResult};
8use directories::ProjectDirs;
9use std::path::PathBuf;
10
11/// Returns the base BillPouch config directory (~/.local/share/billpouch on Linux).
12pub fn base_dir() -> BpResult<PathBuf> {
13    ProjectDirs::from("io", "billpouch", "billpouch")
14        .map(|pd| pd.data_local_dir().to_path_buf())
15        .ok_or_else(|| BpError::Config("Cannot determine home directory".into()))
16}
17
18/// Path to the stored keypair (identity) — plaintext.
19pub fn identity_path() -> BpResult<PathBuf> {
20    Ok(base_dir()?.join("identity.key"))
21}
22
23/// Path to the passphrase-encrypted keypair (Argon2id + AES-256-GCM).
24///
25/// Present only when the user creates the identity with `--passphrase`.
26/// Takes precedence over [`identity_path`] when both files are checked.
27pub fn encrypted_identity_path() -> BpResult<PathBuf> {
28    Ok(base_dir()?.join("identity.key.enc"))
29}
30
31/// Path to the user profile JSON (display name, etc.).
32pub fn profile_path() -> BpResult<PathBuf> {
33    Ok(base_dir()?.join("profile.json"))
34}
35
36/// Path to the daemon PID file.
37pub fn pid_path() -> BpResult<PathBuf> {
38    Ok(base_dir()?.join("daemon.pid"))
39}
40
41/// Path to the Unix control socket.
42pub fn socket_path() -> BpResult<PathBuf> {
43    Ok(base_dir()?.join("control.sock"))
44}
45
46/// Path to persisted service registry.
47pub fn services_path() -> BpResult<PathBuf> {
48    Ok(base_dir()?.join("services.json"))
49}
50
51/// Path to persisted network membership list.
52pub fn networks_path() -> BpResult<PathBuf> {
53    Ok(base_dir()?.join("networks.json"))
54}
55
56/// Path to the persisted Kademlia peer multi-addresses.
57///
58/// Saved periodically and on daemon shutdown so the next startup can
59/// immediately dial previously-known peers, skipping the mDNS warm-up.
60pub fn kad_peers_path() -> BpResult<PathBuf> {
61    Ok(base_dir()?.join("kad_peers.json"))
62}
63
64/// Path to the user-editable bootstrap node list.
65///
66/// Each entry is a multiaddr string that includes a `/p2p/<PeerId>` suffix,
67/// for example `/ip4/203.0.113.1/tcp/4001/p2p/12D3KooW...`.
68/// The list is read once at daemon startup; add entries with a text editor
69/// or via `bp bootstrap add <addr>` (when implemented).
70pub fn bootstrap_path() -> BpResult<PathBuf> {
71    Ok(base_dir()?.join("bootstrap.json"))
72}
73
74/// Path to the per-network secret keys store.
75///
76/// JSON map: `{ "<network_id>": "<hex-encoded 32-byte key>" }`.
77/// Each entry is a randomly generated secret — **not** derived from the
78/// network name.  This file must never leave the local machine; keys are
79/// distributed to new members exclusively via signed+encrypted invite tokens.
80pub fn network_keys_path() -> BpResult<PathBuf> {
81    Ok(base_dir()?.join("network_keys.json"))
82}
83
84/// Path to the persisted per-chunk CEK hints.
85///
86/// JSON map: `{ "<chunk_id>": "<hex-encoded 32-byte plaintext hash>" }`.
87/// The plaintext hash is used to re-derive the per-user CEK at `GetFile` time.
88/// Without this file, files encrypted with a previous daemon session cannot
89/// be decrypted after a daemon restart.
90pub fn cek_hints_path() -> BpResult<PathBuf> {
91    Ok(base_dir()?.join("cek_hints.json"))
92}
93
94/// Path to the file registry (uploaded file catalogue).
95///
96/// JSON list of `StoredFileEntry` records written by `PutFile` so that
97/// `bp ls` can enumerate all files the user has uploaded.
98pub fn file_registry_path() -> BpResult<PathBuf> {
99    Ok(base_dir()?.join("file_registry.json"))
100}
101
102/// Ensure the base directory (and any subdirs) exist.
103pub fn ensure_dirs() -> BpResult<()> {
104    std::fs::create_dir_all(base_dir()?).map_err(BpError::Io)
105}