Development over
This commit is contained in:
@@ -1,11 +1,88 @@
|
||||
//! Configuration for Linux Hello
|
||||
//! Configuration Module for Linux Hello
|
||||
//!
|
||||
//! This module provides configuration structures for all Linux Hello components.
|
||||
//! Configuration is stored in TOML format and supports sensible defaults.
|
||||
//!
|
||||
//! # Configuration File Location
|
||||
//!
|
||||
//! The default configuration file is located at `/etc/linux-hello/config.toml`.
|
||||
//!
|
||||
//! # Configuration Sections
|
||||
//!
|
||||
//! - **general** - Logging and timeout settings
|
||||
//! - **camera** - Camera device selection and resolution
|
||||
//! - **detection** - Face detection model and thresholds
|
||||
//! - **embedding** - Face embedding extraction settings
|
||||
//! - **anti_spoofing** - Liveness detection configuration
|
||||
//! - **tpm** - TPM2 hardware security settings
|
||||
//!
|
||||
//! # Example Configuration
|
||||
//!
|
||||
//! ```toml
|
||||
//! [general]
|
||||
//! log_level = "info"
|
||||
//! timeout_seconds = 5
|
||||
//!
|
||||
//! [camera]
|
||||
//! device = "auto"
|
||||
//! ir_emitter = "auto"
|
||||
//! resolution = [640, 480]
|
||||
//! fps = 30
|
||||
//!
|
||||
//! [detection]
|
||||
//! model = "blazeface"
|
||||
//! min_face_size = 80
|
||||
//! confidence_threshold = 0.9
|
||||
//!
|
||||
//! [embedding]
|
||||
//! model = "mobilefacenet"
|
||||
//! distance_threshold = 0.6
|
||||
//!
|
||||
//! [anti_spoofing]
|
||||
//! enabled = true
|
||||
//! depth_check = true
|
||||
//! liveness_model = true
|
||||
//! temporal_check = true
|
||||
//! min_score = 0.7
|
||||
//!
|
||||
//! [tpm]
|
||||
//! enabled = true
|
||||
//! pcr_binding = false
|
||||
//! ```
|
||||
//!
|
||||
//! # Example Usage
|
||||
//!
|
||||
//! ```rust,no_run
|
||||
//! use linux_hello_common::Config;
|
||||
//!
|
||||
//! // Load from default location with fallback to defaults
|
||||
//! let config = Config::load_or_default();
|
||||
//!
|
||||
//! // Check settings
|
||||
//! if config.anti_spoofing.enabled {
|
||||
//! println!("Anti-spoofing is enabled");
|
||||
//! }
|
||||
//! ```
|
||||
|
||||
use serde::{Deserialize, Serialize};
|
||||
use std::path::Path;
|
||||
|
||||
use crate::error::{Error, Result};
|
||||
|
||||
/// Main configuration structure
|
||||
/// Main configuration structure for Linux Hello.
|
||||
///
|
||||
/// This structure contains all configuration sections for the facial
|
||||
/// authentication system. All fields have sensible defaults.
|
||||
///
|
||||
/// # Example
|
||||
///
|
||||
/// ```rust
|
||||
/// use linux_hello_common::Config;
|
||||
///
|
||||
/// let config = Config::default();
|
||||
/// assert_eq!(config.general.timeout_seconds, 5);
|
||||
/// assert!(config.anti_spoofing.enabled);
|
||||
/// ```
|
||||
#[derive(Debug, Clone, Serialize, Deserialize)]
|
||||
pub struct Config {
|
||||
#[serde(default)]
|
||||
@@ -22,62 +99,140 @@ pub struct Config {
|
||||
pub tpm: TpmConfig,
|
||||
}
|
||||
|
||||
/// General system configuration.
|
||||
///
|
||||
/// Controls logging verbosity and authentication timeout.
|
||||
#[derive(Debug, Clone, Serialize, Deserialize)]
|
||||
pub struct GeneralConfig {
|
||||
/// Log level: "error", "warn", "info", "debug", or "trace".
|
||||
/// Default: "info"
|
||||
#[serde(default = "default_log_level")]
|
||||
pub log_level: String,
|
||||
/// Authentication timeout in seconds. If face detection or matching
|
||||
/// takes longer than this, authentication fails.
|
||||
/// Default: 5
|
||||
#[serde(default = "default_timeout")]
|
||||
pub timeout_seconds: u32,
|
||||
}
|
||||
|
||||
/// Camera hardware configuration.
|
||||
///
|
||||
/// Specifies which camera device to use and capture parameters.
|
||||
/// Set `device` and `ir_emitter` to "auto" for automatic detection.
|
||||
#[derive(Debug, Clone, Serialize, Deserialize)]
|
||||
pub struct CameraConfig {
|
||||
/// Camera device path (e.g., "/dev/video0") or "auto" for automatic detection.
|
||||
/// Auto-detection prefers IR cameras over regular webcams.
|
||||
/// Default: "auto"
|
||||
#[serde(default = "default_auto")]
|
||||
pub device: String,
|
||||
/// IR emitter control path or "auto" for automatic detection.
|
||||
/// Controls the infrared LED for illumination during capture.
|
||||
/// Default: "auto"
|
||||
#[serde(default = "default_auto")]
|
||||
pub ir_emitter: String,
|
||||
/// Capture resolution as [width, height] in pixels.
|
||||
/// Default: [640, 480]
|
||||
#[serde(default = "default_resolution")]
|
||||
pub resolution: [u32; 2],
|
||||
/// Target frame rate in frames per second.
|
||||
/// Default: 30
|
||||
#[serde(default = "default_fps")]
|
||||
pub fps: u32,
|
||||
}
|
||||
|
||||
/// Face detection configuration.
|
||||
///
|
||||
/// Controls the face detection model and sensitivity thresholds.
|
||||
#[derive(Debug, Clone, Serialize, Deserialize)]
|
||||
pub struct DetectionConfig {
|
||||
/// Face detection model to use: "blazeface" or "mtcnn".
|
||||
/// Default: "blazeface"
|
||||
#[serde(default = "default_model")]
|
||||
pub model: String,
|
||||
/// Minimum face size in pixels for detection.
|
||||
/// Faces smaller than this are ignored.
|
||||
/// Default: 80
|
||||
#[serde(default = "default_min_face_size")]
|
||||
pub min_face_size: u32,
|
||||
/// Minimum confidence score (0.0-1.0) for accepting a face detection.
|
||||
/// Higher values reduce false positives but may miss valid faces.
|
||||
/// Default: 0.9
|
||||
#[serde(default = "default_confidence_threshold")]
|
||||
pub confidence_threshold: f32,
|
||||
}
|
||||
|
||||
/// Face embedding extraction configuration.
|
||||
///
|
||||
/// Controls the neural network model used to generate face embeddings
|
||||
/// and the distance threshold for matching.
|
||||
#[derive(Debug, Clone, Serialize, Deserialize)]
|
||||
pub struct EmbeddingConfig {
|
||||
/// Embedding extraction model: "mobilefacenet" or "arcface".
|
||||
/// Default: "mobilefacenet"
|
||||
#[serde(default = "default_embedding_model")]
|
||||
pub model: String,
|
||||
/// Maximum cosine distance (0.0-2.0) for a successful match.
|
||||
/// Lower values are more strict. A value of 0.6 means embeddings
|
||||
/// must be at least 70% similar.
|
||||
/// Default: 0.6
|
||||
#[serde(default = "default_distance_threshold")]
|
||||
pub distance_threshold: f32,
|
||||
}
|
||||
|
||||
/// Anti-spoofing and liveness detection configuration.
|
||||
///
|
||||
/// Controls multiple detection methods to prevent authentication attacks
|
||||
/// using photos, videos, or masks. Each method can be individually enabled.
|
||||
///
|
||||
/// # Security Considerations
|
||||
///
|
||||
/// For maximum security, enable all detection methods. However, this may
|
||||
/// increase authentication time. Adjust based on your security requirements.
|
||||
#[derive(Debug, Clone, Serialize, Deserialize)]
|
||||
pub struct AntiSpoofingConfig {
|
||||
/// Master switch to enable/disable all anti-spoofing checks.
|
||||
/// Default: true
|
||||
#[serde(default = "default_true")]
|
||||
pub enabled: bool,
|
||||
/// Enable depth estimation to detect flat images (photos/screens).
|
||||
/// Default: true
|
||||
#[serde(default = "default_true")]
|
||||
pub depth_check: bool,
|
||||
/// Enable ML-based liveness detection model.
|
||||
/// Default: true
|
||||
#[serde(default = "default_true")]
|
||||
pub liveness_model: bool,
|
||||
/// Enable temporal analysis (micro-movements, blink detection).
|
||||
/// Requires multiple frames and increases authentication time.
|
||||
/// Default: true
|
||||
#[serde(default = "default_true")]
|
||||
pub temporal_check: bool,
|
||||
/// Minimum combined liveness score (0.0-1.0) to pass anti-spoofing.
|
||||
/// Default: 0.7
|
||||
#[serde(default = "default_min_score")]
|
||||
pub min_score: f32,
|
||||
}
|
||||
|
||||
/// TPM2 (Trusted Platform Module) configuration.
|
||||
///
|
||||
/// When enabled, face templates are encrypted using keys bound to the
|
||||
/// TPM hardware, making them inaccessible on other machines.
|
||||
///
|
||||
/// # Hardware Requirements
|
||||
///
|
||||
/// Requires a TPM 2.0 chip. Most modern laptops include one.
|
||||
/// Falls back to software encryption if TPM is unavailable.
|
||||
#[derive(Debug, Clone, Serialize, Deserialize)]
|
||||
pub struct TpmConfig {
|
||||
/// Enable TPM-based encryption for face templates.
|
||||
/// Default: true
|
||||
#[serde(default = "default_true")]
|
||||
pub enabled: bool,
|
||||
/// Bind encryption keys to PCR (Platform Configuration Register) values.
|
||||
/// If enabled, templates become inaccessible if the boot configuration changes.
|
||||
/// Provides additional security but may require re-enrollment after BIOS updates.
|
||||
/// Default: false
|
||||
#[serde(default)]
|
||||
pub pcr_binding: bool,
|
||||
}
|
||||
|
||||
@@ -1,51 +1,130 @@
|
||||
//! Error types for Linux Hello
|
||||
//! Error Types for Linux Hello
|
||||
//!
|
||||
//! This module defines all error types used throughout the Linux Hello system.
|
||||
//! Errors are designed to be informative while not leaking sensitive information.
|
||||
//!
|
||||
//! # Error Categories
|
||||
//!
|
||||
//! - **Camera errors** - Hardware access, IR emitter control, device not found
|
||||
//! - **Detection errors** - Face detection failures, multiple faces, no face
|
||||
//! - **Authentication errors** - Template matching failures, user not enrolled
|
||||
//! - **Storage errors** - Configuration, serialization, I/O failures
|
||||
//! - **Security errors** - TPM failures, encryption errors
|
||||
//!
|
||||
//! # Example
|
||||
//!
|
||||
//! ```rust
|
||||
//! use linux_hello_common::{Error, Result};
|
||||
//!
|
||||
//! fn authenticate_user(user: &str) -> Result<bool> {
|
||||
//! // Simulate checking if user is enrolled
|
||||
//! if user.is_empty() {
|
||||
//! return Err(Error::UserNotEnrolled("unknown".to_string()));
|
||||
//! }
|
||||
//! Ok(true)
|
||||
//! }
|
||||
//!
|
||||
//! match authenticate_user("") {
|
||||
//! Ok(true) => println!("Authenticated!"),
|
||||
//! Ok(false) => println!("Authentication failed"),
|
||||
//! Err(Error::UserNotEnrolled(user)) => println!("User {} not enrolled", user),
|
||||
//! Err(e) => println!("Error: {}", e),
|
||||
//! }
|
||||
//! ```
|
||||
|
||||
use thiserror::Error;
|
||||
|
||||
/// Main error type for Linux Hello
|
||||
/// Main error type for Linux Hello.
|
||||
///
|
||||
/// All operations in Linux Hello return this error type or wrap it
|
||||
/// in a [`Result`]. Error messages are designed to be user-friendly
|
||||
/// without exposing internal implementation details.
|
||||
///
|
||||
/// # Security Note
|
||||
///
|
||||
/// Error messages intentionally avoid including sensitive information
|
||||
/// like internal paths or cryptographic details to prevent information disclosure.
|
||||
#[derive(Error, Debug)]
|
||||
pub enum Error {
|
||||
/// Camera hardware access error.
|
||||
/// Includes the underlying system error message.
|
||||
#[error("Camera error: {0}")]
|
||||
Camera(String),
|
||||
|
||||
/// No suitable IR camera was detected on the system.
|
||||
/// Ensure an IR camera is connected and accessible.
|
||||
#[error("No IR camera found")]
|
||||
NoCameraFound,
|
||||
|
||||
/// Failed to control the IR emitter (LED).
|
||||
/// The emitter may be in use by another process.
|
||||
#[error("IR emitter control failed: {0}")]
|
||||
IrEmitter(String),
|
||||
|
||||
/// Face detection failed during processing.
|
||||
/// May indicate a model loading issue or corrupted frame.
|
||||
#[error("Face detection error: {0}")]
|
||||
Detection(String),
|
||||
|
||||
/// No face was detected in the captured frame.
|
||||
/// Ensure face is visible and properly lit.
|
||||
#[error("No face detected in frame")]
|
||||
NoFaceDetected,
|
||||
|
||||
/// Multiple faces were detected when only one is expected.
|
||||
/// For security, authentication requires exactly one face.
|
||||
#[error("Multiple faces detected")]
|
||||
MultipleFacesDetected,
|
||||
|
||||
/// Failed to load an ML model (detection or embedding).
|
||||
#[error("Model loading error: {0}")]
|
||||
ModelLoad(String),
|
||||
|
||||
/// Configuration file parsing or validation error.
|
||||
#[error("Configuration error: {0}")]
|
||||
Config(String),
|
||||
|
||||
/// TPM (Trusted Platform Module) operation failed.
|
||||
/// May indicate TPM is unavailable or key access was denied.
|
||||
#[error("TPM error: {0}")]
|
||||
Tpm(String),
|
||||
|
||||
/// Face did not match any enrolled template.
|
||||
/// Generic error to prevent information disclosure.
|
||||
#[error("Authentication failed")]
|
||||
AuthenticationFailed,
|
||||
|
||||
/// The specified user has no enrolled face templates.
|
||||
#[error("User not enrolled: {0}")]
|
||||
UserNotEnrolled(String),
|
||||
|
||||
/// File system or network I/O error.
|
||||
#[error("IO error: {0}")]
|
||||
Io(#[from] std::io::Error),
|
||||
|
||||
/// JSON/TOML serialization or deserialization error.
|
||||
#[error("Serialization error: {0}")]
|
||||
Serialization(String),
|
||||
|
||||
/// D-Bus communication error with system services.
|
||||
#[error("D-Bus error: {0}")]
|
||||
Dbus(String),
|
||||
}
|
||||
|
||||
/// Result type alias for Linux Hello
|
||||
/// Result type alias for Linux Hello operations.
|
||||
///
|
||||
/// This is a convenience alias for `std::result::Result<T, Error>`.
|
||||
///
|
||||
/// # Example
|
||||
///
|
||||
/// ```rust
|
||||
/// use linux_hello_common::Result;
|
||||
///
|
||||
/// fn do_something() -> Result<()> {
|
||||
/// // ... operation that might fail
|
||||
/// Ok(())
|
||||
/// }
|
||||
/// ```
|
||||
pub type Result<T> = std::result::Result<T, Error>;
|
||||
|
||||
#[cfg(test)]
|
||||
|
||||
@@ -1,7 +1,52 @@
|
||||
//! Linux Hello Common Library
|
||||
//!
|
||||
//! Shared types, configuration, and error handling for the Linux Hello
|
||||
//! facial authentication system.
|
||||
//! This crate provides shared types, configuration, and error handling for the
|
||||
//! Linux Hello facial authentication system. It serves as the foundation for
|
||||
//! both the daemon and CLI components.
|
||||
//!
|
||||
//! # Overview
|
||||
//!
|
||||
//! Linux Hello is a facial authentication system for Linux, similar to Windows Hello.
|
||||
//! It uses IR camera technology combined with anti-spoofing measures to provide
|
||||
//! secure biometric authentication.
|
||||
//!
|
||||
//! # Modules
|
||||
//!
|
||||
//! - [`config`] - Configuration structures for all system components
|
||||
//! - [`error`] - Error types and result aliases
|
||||
//! - [`template`] - Face template storage and management
|
||||
//!
|
||||
//! # Security Model
|
||||
//!
|
||||
//! The system implements a layered security approach:
|
||||
//!
|
||||
//! 1. **IR Camera Verification** - Uses infrared cameras to prevent photo attacks
|
||||
//! 2. **Anti-Spoofing** - Multiple liveness detection methods (depth, texture, blink)
|
||||
//! 3. **Encrypted Storage** - Templates are encrypted at rest using AES-256-GCM
|
||||
//! 4. **TPM Integration** - Hardware-bound encryption when TPM2 is available
|
||||
//! 5. **Memory Protection** - Sensitive data is zeroized on drop
|
||||
//!
|
||||
//! # Example
|
||||
//!
|
||||
//! ```rust,no_run
|
||||
//! use linux_hello_common::{Config, TemplateStore, Result};
|
||||
//!
|
||||
//! fn main() -> Result<()> {
|
||||
//! // Load configuration
|
||||
//! let config = Config::load_or_default();
|
||||
//!
|
||||
//! // Initialize template storage
|
||||
//! let store = TemplateStore::new(TemplateStore::default_path());
|
||||
//! store.initialize()?;
|
||||
//!
|
||||
//! // Check if user is enrolled
|
||||
//! if store.is_enrolled("john") {
|
||||
//! println!("User john is enrolled");
|
||||
//! }
|
||||
//!
|
||||
//! Ok(())
|
||||
//! }
|
||||
//! ```
|
||||
|
||||
pub mod config;
|
||||
pub mod error;
|
||||
@@ -9,4 +54,4 @@ pub mod template;
|
||||
|
||||
pub use config::Config;
|
||||
pub use error::{Error, Result};
|
||||
pub use template::{FaceTemplate, TemplateStore};
|
||||
pub use template::{FaceTemplate, TemplateStore};
|
||||
@@ -1,7 +1,57 @@
|
||||
//! Template Storage Module
|
||||
//! Face Template Storage Module
|
||||
//!
|
||||
//! Handles storage and retrieval of face templates (embeddings) for enrolled users.
|
||||
//! Currently uses unencrypted file-based storage. TPM encryption will be added in Phase 3.
|
||||
//! This module handles storage and retrieval of face templates (embeddings) for
|
||||
//! enrolled users. Templates are stored as JSON files organized by user.
|
||||
//!
|
||||
//! # Storage Layout
|
||||
//!
|
||||
//! Templates are stored in a hierarchical structure:
|
||||
//!
|
||||
//! ```text
|
||||
//! /var/lib/linux-hello/templates/
|
||||
//! john/
|
||||
//! default.json
|
||||
//! backup.json
|
||||
//! alice/
|
||||
//! default.json
|
||||
//! ```
|
||||
//!
|
||||
//! # Security Considerations
|
||||
//!
|
||||
//! - This module provides unencrypted storage for templates
|
||||
//! - For production use, combine with `SecureTemplateStore` from `linux-hello-daemon` for encryption
|
||||
//! - Templates contain biometric data and should be protected
|
||||
//! - Directory permissions should be restricted (0700)
|
||||
//!
|
||||
//! # Example
|
||||
//!
|
||||
//! ```rust,no_run
|
||||
//! use linux_hello_common::{FaceTemplate, TemplateStore};
|
||||
//!
|
||||
//! // Create and initialize store
|
||||
//! let store = TemplateStore::new("/var/lib/linux-hello/templates");
|
||||
//! store.initialize().expect("Failed to create template directory");
|
||||
//!
|
||||
//! // Create a template
|
||||
//! let template = FaceTemplate {
|
||||
//! user: "john".to_string(),
|
||||
//! label: "default".to_string(),
|
||||
//! embedding: vec![0.1, 0.2, 0.3], // Actual embeddings are 128-512 dimensions
|
||||
//! enrolled_at: 1234567890,
|
||||
//! frame_count: 5,
|
||||
//! };
|
||||
//!
|
||||
//! // Store the template
|
||||
//! store.store(&template).expect("Failed to store template");
|
||||
//!
|
||||
//! // Check enrollment status
|
||||
//! if store.is_enrolled("john") {
|
||||
//! println!("User john is enrolled");
|
||||
//! }
|
||||
//!
|
||||
//! // Load template for matching
|
||||
//! let loaded = store.load("john", "default").expect("Template not found");
|
||||
//! ```
|
||||
|
||||
use serde::{Deserialize, Serialize};
|
||||
use std::path::{Path, PathBuf};
|
||||
@@ -9,57 +59,131 @@ use std::fs;
|
||||
|
||||
use crate::error::{Error, Result};
|
||||
|
||||
/// A face template (embedding vector) for a user
|
||||
/// A face template containing the embedding vector for a user.
|
||||
///
|
||||
/// Templates are created during enrollment by capturing multiple frames,
|
||||
/// extracting face embeddings, and averaging them for robustness.
|
||||
///
|
||||
/// # Fields
|
||||
///
|
||||
/// - `user` - System username this template belongs to
|
||||
/// - `label` - Identifier for multiple enrollments (e.g., "default", "glasses")
|
||||
/// - `embedding` - Normalized face embedding vector (typically 128 or 512 dimensions)
|
||||
/// - `enrolled_at` - Unix timestamp when the template was created
|
||||
/// - `frame_count` - Number of frames used to generate the averaged embedding
|
||||
///
|
||||
/// # Example
|
||||
///
|
||||
/// ```rust
|
||||
/// use linux_hello_common::FaceTemplate;
|
||||
///
|
||||
/// let template = FaceTemplate {
|
||||
/// user: "alice".to_string(),
|
||||
/// label: "default".to_string(),
|
||||
/// embedding: vec![0.1, 0.2, 0.3, 0.4], // Simplified example
|
||||
/// enrolled_at: std::time::SystemTime::now()
|
||||
/// .duration_since(std::time::UNIX_EPOCH)
|
||||
/// .unwrap()
|
||||
/// .as_secs(),
|
||||
/// frame_count: 5,
|
||||
/// };
|
||||
/// ```
|
||||
#[derive(Debug, Clone, Serialize, Deserialize)]
|
||||
pub struct FaceTemplate {
|
||||
/// User identifier
|
||||
/// System username this template belongs to.
|
||||
pub user: String,
|
||||
/// Label for this enrollment (e.g., "default", "backup")
|
||||
/// Label for this enrollment (e.g., "default", "glasses", "backup").
|
||||
/// Users can have multiple templates with different labels.
|
||||
pub label: String,
|
||||
/// Face embedding vector (normalized)
|
||||
/// Normalized face embedding vector.
|
||||
/// Typically 128 dimensions (MobileFaceNet) or 512 dimensions (ArcFace).
|
||||
pub embedding: Vec<f32>,
|
||||
/// Timestamp when enrolled
|
||||
/// Unix timestamp when this template was enrolled.
|
||||
pub enrolled_at: u64,
|
||||
/// Number of frames used to generate this template
|
||||
/// Number of frames averaged to create this template.
|
||||
/// More frames generally produce more robust templates.
|
||||
pub frame_count: u32,
|
||||
}
|
||||
|
||||
/// Template storage manager
|
||||
/// File-based template storage manager.
|
||||
///
|
||||
/// Manages face templates on the filesystem with operations for storing,
|
||||
/// loading, listing, and removing templates.
|
||||
///
|
||||
/// # Thread Safety
|
||||
///
|
||||
/// This struct is not thread-safe. For concurrent access, use external
|
||||
/// synchronization or wrap in a `Mutex`.
|
||||
pub struct TemplateStore {
|
||||
/// Base directory for template storage
|
||||
base_path: PathBuf,
|
||||
}
|
||||
|
||||
impl TemplateStore {
|
||||
/// Create a new template store
|
||||
/// Create a new template store at the specified path.
|
||||
///
|
||||
/// # Arguments
|
||||
///
|
||||
/// * `base_path` - Directory where templates will be stored
|
||||
///
|
||||
/// # Example
|
||||
///
|
||||
/// ```rust
|
||||
/// use linux_hello_common::TemplateStore;
|
||||
///
|
||||
/// let store = TemplateStore::new("/var/lib/linux-hello/templates");
|
||||
/// ```
|
||||
pub fn new<P: AsRef<Path>>(base_path: P) -> Self {
|
||||
Self {
|
||||
base_path: base_path.as_ref().to_path_buf(),
|
||||
}
|
||||
}
|
||||
|
||||
/// Get the default template storage path
|
||||
/// Get the default template storage path.
|
||||
///
|
||||
/// Returns `/var/lib/linux-hello/templates`.
|
||||
pub fn default_path() -> PathBuf {
|
||||
PathBuf::from("/var/lib/linux-hello/templates")
|
||||
}
|
||||
|
||||
/// Initialize the template store (create directories if needed)
|
||||
/// Initialize the template store by creating the storage directory.
|
||||
///
|
||||
/// This must be called before storing templates. Creates the directory
|
||||
/// with all parent directories if they don't exist.
|
||||
///
|
||||
/// # Errors
|
||||
///
|
||||
/// Returns an error if the directory cannot be created (permission denied, etc.).
|
||||
pub fn initialize(&self) -> Result<()> {
|
||||
fs::create_dir_all(&self.base_path)?;
|
||||
Ok(())
|
||||
}
|
||||
|
||||
/// Get the path for a user's template directory
|
||||
/// Get the path for a user's template directory.
|
||||
fn user_path(&self, user: &str) -> PathBuf {
|
||||
self.base_path.join(user)
|
||||
}
|
||||
|
||||
/// Get the path for a specific template file
|
||||
/// Get the path for a specific template file.
|
||||
fn template_path(&self, user: &str, label: &str) -> PathBuf {
|
||||
self.user_path(user).join(format!("{}.json", label))
|
||||
}
|
||||
|
||||
/// Store a template for a user
|
||||
/// Store a face template for a user.
|
||||
///
|
||||
/// Creates the user's directory if it doesn't exist and writes the
|
||||
/// template as a JSON file.
|
||||
///
|
||||
/// # Arguments
|
||||
///
|
||||
/// * `template` - The face template to store
|
||||
///
|
||||
/// # Errors
|
||||
///
|
||||
/// Returns an error if:
|
||||
/// - The directory cannot be created
|
||||
/// - The file cannot be written
|
||||
/// - JSON serialization fails
|
||||
pub fn store(&self, template: &FaceTemplate) -> Result<()> {
|
||||
let user_dir = self.user_path(&template.user);
|
||||
fs::create_dir_all(&user_dir)?;
|
||||
@@ -208,7 +332,6 @@ impl TemplateStore {
|
||||
#[cfg(test)]
|
||||
mod tests {
|
||||
use super::*;
|
||||
use std::fs;
|
||||
use tempfile::TempDir;
|
||||
|
||||
#[test]
|
||||
|
||||
Reference in New Issue
Block a user