#![allow(dead_code, unused_imports, unused_qualifications, unreachable_patterns)]
use super::platform::BackendKind;
use std::path::PathBuf;
const MARKER_FILENAME: &str = ".backend";
fn marker_path(app_name: &str) -> PathBuf {
crate::internal::core::metadata::config_dir(app_name).join(MARKER_FILENAME)
}
pub fn read(app_name: &str) -> std::io::Result<Option<BackendKind>> {
let path = marker_path(app_name);
let content = match std::fs::read_to_string(&path) {
Ok(s) => s,
Err(e) if e.kind() == std::io::ErrorKind::NotFound => return Ok(None),
Err(e) => return Err(e),
};
Ok(parse_kind(content.trim()))
}
pub fn write(app_name: &str, kind: BackendKind) -> std::io::Result<()> {
let path = marker_path(app_name);
if let Some(parent) = path.parent() {
std::fs::create_dir_all(parent)?;
}
let value = format!("{}\n", kind_str(kind));
crate::internal::core::metadata::atomic_write(&path, value.as_bytes())
.map_err(|e| std::io::Error::other(e.to_string()))
}
fn kind_str(kind: BackendKind) -> &'static str {
match kind {
BackendKind::SecureEnclave => "se",
BackendKind::Tpm => "tpm",
BackendKind::WindowsDpapi => "windows-dpapi",
BackendKind::TpmBridge => "tpm-bridge",
BackendKind::Keyring => "keyring",
}
}
fn parse_kind(s: &str) -> Option<BackendKind> {
match s {
"se" => Some(BackendKind::SecureEnclave),
"tpm" => Some(BackendKind::Tpm),
"windows-dpapi" => Some(BackendKind::WindowsDpapi),
"tpm-bridge" => Some(BackendKind::TpmBridge),
"keyring" => Some(BackendKind::Keyring),
_ => None,
}
}
#[cfg(test)]
#[allow(clippy::unwrap_used, clippy::panic, let_underscore_drop)]
mod tests {
use super::*;
use std::sync::atomic::{AtomicU64, Ordering};
static COUNTER: AtomicU64 = AtomicU64::new(0);
fn unique_app_name() -> String {
format!(
"enclaveapp-app-storage-marker-test-{}-{}",
std::process::id(),
COUNTER.fetch_add(1, Ordering::SeqCst)
)
}
fn cleanup(app_name: &str) {
let dir = crate::internal::core::metadata::config_dir(app_name);
let _ = std::fs::remove_dir_all(&dir);
}
#[test]
fn read_returns_none_when_marker_absent() {
let app = unique_app_name();
cleanup(&app);
assert_eq!(read(&app).unwrap(), None);
}
#[test]
fn write_then_read_roundtrips_each_kind() {
let app = unique_app_name();
cleanup(&app);
for kind in [
BackendKind::SecureEnclave,
BackendKind::Tpm,
BackendKind::WindowsDpapi,
BackendKind::TpmBridge,
BackendKind::Keyring,
] {
write(&app, kind).unwrap();
assert_eq!(read(&app).unwrap(), Some(kind));
}
cleanup(&app);
}
#[test]
fn read_returns_none_for_unrecognized_kind() {
let app = unique_app_name();
let path = marker_path(&app);
std::fs::create_dir_all(path.parent().unwrap()).unwrap();
std::fs::write(&path, "tpm-quantum\n").unwrap();
assert_eq!(read(&app).unwrap(), None);
cleanup(&app);
}
#[test]
fn write_overwrites_existing_marker() {
let app = unique_app_name();
cleanup(&app);
write(&app, BackendKind::Tpm).unwrap();
write(&app, BackendKind::Keyring).unwrap();
assert_eq!(read(&app).unwrap(), Some(BackendKind::Keyring));
cleanup(&app);
}
#[test]
fn parse_kind_se_returns_secure_enclave() {
assert_eq!(parse_kind("se"), Some(BackendKind::SecureEnclave));
}
#[test]
fn parse_kind_tpm_returns_tpm() {
assert_eq!(parse_kind("tpm"), Some(BackendKind::Tpm));
}
#[test]
fn parse_kind_windows_dpapi_returns_windows_dpapi() {
assert_eq!(parse_kind("windows-dpapi"), Some(BackendKind::WindowsDpapi));
}
#[test]
fn parse_kind_tpm_bridge_returns_tpm_bridge() {
assert_eq!(parse_kind("tpm-bridge"), Some(BackendKind::TpmBridge));
}
#[test]
fn parse_kind_keyring_returns_keyring() {
assert_eq!(parse_kind("keyring"), Some(BackendKind::Keyring));
}
#[test]
fn parse_kind_unknown_returns_none() {
assert_eq!(parse_kind("unknown"), None);
assert_eq!(parse_kind(""), None);
assert_eq!(parse_kind("SE"), None);
assert_eq!(parse_kind("TPM"), None);
}
#[test]
fn kind_str_roundtrips_through_parse_kind() {
for kind in [
BackendKind::SecureEnclave,
BackendKind::Tpm,
BackendKind::WindowsDpapi,
BackendKind::TpmBridge,
BackendKind::Keyring,
] {
let s = kind_str(kind);
assert_eq!(parse_kind(s), Some(kind));
}
}
#[test]
fn kind_str_values_are_lowercase_ascii() {
for kind in [
BackendKind::SecureEnclave,
BackendKind::Tpm,
BackendKind::WindowsDpapi,
BackendKind::TpmBridge,
BackendKind::Keyring,
] {
let s = kind_str(kind);
assert!(
s.chars().all(|c| c.is_ascii_lowercase() || c == '-'),
"kind_str({kind:?}) = '{s}' contains unexpected characters"
);
}
}
}