#![allow(clippy::doc_markdown)]
use crate::locked;
use crate::prelude::Error as BwxError;
const FILENAME: &str = "touchid.json";
#[derive(serde::Serialize, serde::Deserialize, Debug, Clone)]
pub struct Blob {
pub keychain_label: String,
pub wrapped_priv_key: String,
pub wrapped_org_keys: std::collections::BTreeMap<String, String>,
}
impl Blob {
pub fn path() -> std::path::PathBuf {
crate::dirs::make_all().ok();
data_dir_for_blob().join(FILENAME)
}
pub fn exists() -> bool {
Self::path().exists()
}
pub fn load() -> Result<Self, BwxError> {
let path = Self::path();
let json = std::fs::read_to_string(&path).map_err(|source| {
BwxError::LoadConfig {
source,
file: path.clone(),
}
})?;
serde_json::from_str(&json)
.map_err(|source| BwxError::Json { source })
}
pub fn save(&self) -> Result<(), BwxError> {
use std::io::Write as _;
use std::os::unix::fs::{OpenOptionsExt as _, PermissionsExt as _};
let path = Self::path();
if let Some(parent) = path.parent() {
std::fs::create_dir_all(parent).map_err(|source| {
BwxError::SaveConfig {
source,
file: path.clone(),
}
})?;
}
let json = serde_json::to_string(self)
.map_err(|source| BwxError::Json { source })?;
let mut fh = std::fs::OpenOptions::new()
.write(true)
.create(true)
.truncate(true)
.mode(0o600)
.open(&path)
.map_err(|source| BwxError::SaveConfig {
source,
file: path.clone(),
})?;
fh.set_permissions(std::fs::Permissions::from_mode(0o600))
.map_err(|source| BwxError::SaveConfig {
source,
file: path.clone(),
})?;
fh.write_all(json.as_bytes())
.map_err(|source| BwxError::SaveConfig { source, file: path })?;
Ok(())
}
pub fn remove() -> Result<(), BwxError> {
let path = Self::path();
match std::fs::remove_file(&path) {
Ok(()) => Ok(()),
Err(e) if e.kind() == std::io::ErrorKind::NotFound => Ok(()),
Err(source) => Err(BwxError::SaveConfig { source, file: path }),
}
}
}
fn data_dir_for_blob() -> std::path::PathBuf {
let p = crate::dirs::agent_stdout_file();
p.parent().map_or_else(
|| std::path::PathBuf::from("."),
std::path::Path::to_path_buf,
)
}
pub fn keys_from_wrapper_seed(seed: &[u8]) -> locked::Keys {
assert_eq!(seed.len(), 64, "wrapper seed must be 64 bytes");
let mut buf = locked::Vec::new();
buf.extend(seed.iter().copied());
locked::Keys::new(buf)
}