first commit
This commit is contained in:
12
linux-hello-common/Cargo.toml
Normal file
12
linux-hello-common/Cargo.toml
Normal file
@@ -0,0 +1,12 @@
|
||||
[package]
|
||||
name = "linux-hello-common"
|
||||
version.workspace = true
|
||||
edition.workspace = true
|
||||
license.workspace = true
|
||||
description = "Shared types and utilities for Linux Hello"
|
||||
|
||||
[dependencies]
|
||||
thiserror.workspace = true
|
||||
serde.workspace = true
|
||||
toml.workspace = true
|
||||
tracing.workspace = true
|
||||
237
linux-hello-common/src/config.rs
Normal file
237
linux-hello-common/src/config.rs
Normal file
@@ -0,0 +1,237 @@
|
||||
//! Configuration for Linux Hello
|
||||
|
||||
use serde::{Deserialize, Serialize};
|
||||
use std::path::Path;
|
||||
|
||||
use crate::error::{Error, Result};
|
||||
|
||||
/// Main configuration structure
|
||||
#[derive(Debug, Clone, Serialize, Deserialize)]
|
||||
pub struct Config {
|
||||
#[serde(default)]
|
||||
pub general: GeneralConfig,
|
||||
#[serde(default)]
|
||||
pub camera: CameraConfig,
|
||||
#[serde(default)]
|
||||
pub detection: DetectionConfig,
|
||||
#[serde(default)]
|
||||
pub embedding: EmbeddingConfig,
|
||||
#[serde(default)]
|
||||
pub anti_spoofing: AntiSpoofingConfig,
|
||||
#[serde(default)]
|
||||
pub tpm: TpmConfig,
|
||||
}
|
||||
|
||||
#[derive(Debug, Clone, Serialize, Deserialize)]
|
||||
pub struct GeneralConfig {
|
||||
#[serde(default = "default_log_level")]
|
||||
pub log_level: String,
|
||||
#[serde(default = "default_timeout")]
|
||||
pub timeout_seconds: u32,
|
||||
}
|
||||
|
||||
#[derive(Debug, Clone, Serialize, Deserialize)]
|
||||
pub struct CameraConfig {
|
||||
#[serde(default = "default_auto")]
|
||||
pub device: String,
|
||||
#[serde(default = "default_auto")]
|
||||
pub ir_emitter: String,
|
||||
#[serde(default = "default_resolution")]
|
||||
pub resolution: [u32; 2],
|
||||
#[serde(default = "default_fps")]
|
||||
pub fps: u32,
|
||||
}
|
||||
|
||||
#[derive(Debug, Clone, Serialize, Deserialize)]
|
||||
pub struct DetectionConfig {
|
||||
#[serde(default = "default_model")]
|
||||
pub model: String,
|
||||
#[serde(default = "default_min_face_size")]
|
||||
pub min_face_size: u32,
|
||||
#[serde(default = "default_confidence_threshold")]
|
||||
pub confidence_threshold: f32,
|
||||
}
|
||||
|
||||
#[derive(Debug, Clone, Serialize, Deserialize)]
|
||||
pub struct EmbeddingConfig {
|
||||
#[serde(default = "default_embedding_model")]
|
||||
pub model: String,
|
||||
#[serde(default = "default_distance_threshold")]
|
||||
pub distance_threshold: f32,
|
||||
}
|
||||
|
||||
#[derive(Debug, Clone, Serialize, Deserialize)]
|
||||
pub struct AntiSpoofingConfig {
|
||||
#[serde(default = "default_true")]
|
||||
pub enabled: bool,
|
||||
#[serde(default = "default_true")]
|
||||
pub depth_check: bool,
|
||||
#[serde(default = "default_true")]
|
||||
pub liveness_model: bool,
|
||||
#[serde(default = "default_true")]
|
||||
pub temporal_check: bool,
|
||||
#[serde(default = "default_min_score")]
|
||||
pub min_score: f32,
|
||||
}
|
||||
|
||||
#[derive(Debug, Clone, Serialize, Deserialize)]
|
||||
pub struct TpmConfig {
|
||||
#[serde(default = "default_true")]
|
||||
pub enabled: bool,
|
||||
#[serde(default)]
|
||||
pub pcr_binding: bool,
|
||||
}
|
||||
|
||||
// Default value functions
|
||||
fn default_log_level() -> String {
|
||||
"info".to_string()
|
||||
}
|
||||
fn default_timeout() -> u32 {
|
||||
5
|
||||
}
|
||||
fn default_auto() -> String {
|
||||
"auto".to_string()
|
||||
}
|
||||
fn default_resolution() -> [u32; 2] {
|
||||
[640, 480]
|
||||
}
|
||||
fn default_fps() -> u32 {
|
||||
30
|
||||
}
|
||||
fn default_model() -> String {
|
||||
"blazeface".to_string()
|
||||
}
|
||||
fn default_min_face_size() -> u32 {
|
||||
80
|
||||
}
|
||||
fn default_confidence_threshold() -> f32 {
|
||||
0.9
|
||||
}
|
||||
fn default_embedding_model() -> String {
|
||||
"mobilefacenet".to_string()
|
||||
}
|
||||
fn default_distance_threshold() -> f32 {
|
||||
0.6
|
||||
}
|
||||
fn default_true() -> bool {
|
||||
true
|
||||
}
|
||||
fn default_min_score() -> f32 {
|
||||
0.7
|
||||
}
|
||||
|
||||
impl Default for GeneralConfig {
|
||||
fn default() -> Self {
|
||||
Self {
|
||||
log_level: default_log_level(),
|
||||
timeout_seconds: default_timeout(),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl Default for CameraConfig {
|
||||
fn default() -> Self {
|
||||
Self {
|
||||
device: default_auto(),
|
||||
ir_emitter: default_auto(),
|
||||
resolution: default_resolution(),
|
||||
fps: default_fps(),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl Default for DetectionConfig {
|
||||
fn default() -> Self {
|
||||
Self {
|
||||
model: default_model(),
|
||||
min_face_size: default_min_face_size(),
|
||||
confidence_threshold: default_confidence_threshold(),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl Default for EmbeddingConfig {
|
||||
fn default() -> Self {
|
||||
Self {
|
||||
model: default_embedding_model(),
|
||||
distance_threshold: default_distance_threshold(),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl Default for AntiSpoofingConfig {
|
||||
fn default() -> Self {
|
||||
Self {
|
||||
enabled: default_true(),
|
||||
depth_check: default_true(),
|
||||
liveness_model: default_true(),
|
||||
temporal_check: default_true(),
|
||||
min_score: default_min_score(),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl Default for TpmConfig {
|
||||
fn default() -> Self {
|
||||
Self {
|
||||
enabled: default_true(),
|
||||
pcr_binding: false,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl Default for Config {
|
||||
fn default() -> Self {
|
||||
Self {
|
||||
general: GeneralConfig::default(),
|
||||
camera: CameraConfig::default(),
|
||||
detection: DetectionConfig::default(),
|
||||
embedding: EmbeddingConfig::default(),
|
||||
anti_spoofing: AntiSpoofingConfig::default(),
|
||||
tpm: TpmConfig::default(),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl Config {
|
||||
/// Load configuration from a TOML file
|
||||
pub fn load<P: AsRef<Path>>(path: P) -> Result<Self> {
|
||||
let content = std::fs::read_to_string(path)?;
|
||||
toml::from_str(&content).map_err(|e| Error::Config(e.to_string()))
|
||||
}
|
||||
|
||||
/// Load configuration from the default path or return defaults
|
||||
pub fn load_or_default() -> Self {
|
||||
Self::load("/etc/linux-hello/config.toml").unwrap_or_default()
|
||||
}
|
||||
|
||||
/// Save configuration to a TOML file
|
||||
pub fn save<P: AsRef<Path>>(&self, path: P) -> Result<()> {
|
||||
let content = toml::to_string_pretty(self).map_err(|e| Error::Serialization(e.to_string()))?;
|
||||
std::fs::write(path, content)?;
|
||||
Ok(())
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
mod tests {
|
||||
use super::*;
|
||||
|
||||
#[test]
|
||||
fn test_default_config() {
|
||||
let config = Config::default();
|
||||
assert_eq!(config.general.log_level, "info");
|
||||
assert_eq!(config.general.timeout_seconds, 5);
|
||||
assert_eq!(config.camera.device, "auto");
|
||||
assert_eq!(config.camera.resolution, [640, 480]);
|
||||
assert!(config.anti_spoofing.enabled);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_config_serialization() {
|
||||
let config = Config::default();
|
||||
let toml_str = toml::to_string(&config).unwrap();
|
||||
let parsed: Config = toml::from_str(&toml_str).unwrap();
|
||||
assert_eq!(parsed.general.log_level, config.general.log_level);
|
||||
}
|
||||
}
|
||||
63
linux-hello-common/src/error.rs
Normal file
63
linux-hello-common/src/error.rs
Normal file
@@ -0,0 +1,63 @@
|
||||
//! Error types for Linux Hello
|
||||
|
||||
use thiserror::Error;
|
||||
|
||||
/// Main error type for Linux Hello
|
||||
#[derive(Error, Debug)]
|
||||
pub enum Error {
|
||||
#[error("Camera error: {0}")]
|
||||
Camera(String),
|
||||
|
||||
#[error("No IR camera found")]
|
||||
NoCameraFound,
|
||||
|
||||
#[error("IR emitter control failed: {0}")]
|
||||
IrEmitter(String),
|
||||
|
||||
#[error("Face detection error: {0}")]
|
||||
Detection(String),
|
||||
|
||||
#[error("No face detected in frame")]
|
||||
NoFaceDetected,
|
||||
|
||||
#[error("Multiple faces detected")]
|
||||
MultipleFacesDetected,
|
||||
|
||||
#[error("Model loading error: {0}")]
|
||||
ModelLoad(String),
|
||||
|
||||
#[error("Configuration error: {0}")]
|
||||
Config(String),
|
||||
|
||||
#[error("TPM error: {0}")]
|
||||
Tpm(String),
|
||||
|
||||
#[error("Authentication failed")]
|
||||
AuthenticationFailed,
|
||||
|
||||
#[error("User not enrolled: {0}")]
|
||||
UserNotEnrolled(String),
|
||||
|
||||
#[error("IO error: {0}")]
|
||||
Io(#[from] std::io::Error),
|
||||
|
||||
#[error("Serialization error: {0}")]
|
||||
Serialization(String),
|
||||
}
|
||||
|
||||
/// Result type alias for Linux Hello
|
||||
pub type Result<T> = std::result::Result<T, Error>;
|
||||
|
||||
#[cfg(test)]
|
||||
mod tests {
|
||||
use super::*;
|
||||
|
||||
#[test]
|
||||
fn test_error_display() {
|
||||
let err = Error::NoCameraFound;
|
||||
assert_eq!(err.to_string(), "No IR camera found");
|
||||
|
||||
let err = Error::Camera("device busy".to_string());
|
||||
assert_eq!(err.to_string(), "Camera error: device busy");
|
||||
}
|
||||
}
|
||||
10
linux-hello-common/src/lib.rs
Normal file
10
linux-hello-common/src/lib.rs
Normal file
@@ -0,0 +1,10 @@
|
||||
//! Linux Hello Common Library
|
||||
//!
|
||||
//! Shared types, configuration, and error handling for the Linux Hello
|
||||
//! facial authentication system.
|
||||
|
||||
pub mod config;
|
||||
pub mod error;
|
||||
|
||||
pub use config::Config;
|
||||
pub use error::{Error, Result};
|
||||
Reference in New Issue
Block a user