use tor_guardmgr::VanguardMode;
use crate::onion_service::OnionServiceConfig;
#[derive(Debug, Clone, Copy, PartialEq, Eq, Default)]
pub enum SecurityLevel {
Standard,
#[default]
Enhanced,
Maximum,
}
impl SecurityLevel {
pub fn vanguard_mode(&self) -> VanguardMode {
match self {
SecurityLevel::Standard => VanguardMode::Lite,
SecurityLevel::Enhanced => VanguardMode::Lite,
SecurityLevel::Maximum => VanguardMode::Full,
}
}
pub fn onion_service_config(&self, nickname: impl Into<String>) -> OnionServiceConfig {
match self {
SecurityLevel::Standard => OnionServiceConfig::new(nickname),
SecurityLevel::Enhanced => OnionServiceConfig::new(nickname)
.with_pow()
.rate_limit_at_intro(50.0, 100)
.max_streams_per_circuit(500),
SecurityLevel::Maximum => OnionServiceConfig::new(nickname)
.with_pow()
.rate_limit_at_intro(10.0, 20)
.max_streams_per_circuit(100)
.num_intro_points(5),
}
}
pub fn pow_enabled(&self) -> bool {
!matches!(self, SecurityLevel::Standard)
}
pub fn full_vanguards(&self) -> bool {
matches!(self, SecurityLevel::Maximum)
}
}
#[derive(Debug, Clone)]
pub struct ClientSecurityConfig {
pub level: SecurityLevel,
pub vanguard_mode: VanguardMode,
pub strict_isolation: bool,
}
impl Default for ClientSecurityConfig {
fn default() -> Self {
Self::enhanced()
}
}
impl ClientSecurityConfig {
pub fn standard() -> Self {
Self {
level: SecurityLevel::Standard,
vanguard_mode: VanguardMode::Lite,
strict_isolation: false,
}
}
pub fn enhanced() -> Self {
Self {
level: SecurityLevel::Enhanced,
vanguard_mode: VanguardMode::Lite,
strict_isolation: true,
}
}
pub fn maximum() -> Self {
Self {
level: SecurityLevel::Maximum,
vanguard_mode: VanguardMode::Full,
strict_isolation: true,
}
}
}
#[derive(Debug, Clone)]
pub struct ServiceSecurityConfig {
pub level: SecurityLevel,
pub enable_pow: bool,
pub rate_limit: Option<(f64, u32)>,
pub max_streams: u32,
pub num_intro_points: u8,
}
impl Default for ServiceSecurityConfig {
fn default() -> Self {
Self::enhanced()
}
}
impl ServiceSecurityConfig {
pub fn standard() -> Self {
Self {
level: SecurityLevel::Standard,
enable_pow: false,
rate_limit: None,
max_streams: 65535,
num_intro_points: 3,
}
}
pub fn enhanced() -> Self {
Self {
level: SecurityLevel::Enhanced,
enable_pow: true,
rate_limit: Some((50.0, 100)),
max_streams: 500,
num_intro_points: 3,
}
}
pub fn maximum() -> Self {
Self {
level: SecurityLevel::Maximum,
enable_pow: true,
rate_limit: Some((10.0, 20)),
max_streams: 100,
num_intro_points: 5,
}
}
pub fn to_onion_config(&self, nickname: impl Into<String>) -> OnionServiceConfig {
let mut config = OnionServiceConfig::new(nickname);
if self.enable_pow {
config = config.with_pow();
}
if let Some((rate, burst)) = self.rate_limit {
config = config.rate_limit_at_intro(rate, burst);
}
config
.max_streams_per_circuit(self.max_streams)
.num_intro_points(self.num_intro_points)
}
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn test_security_levels() {
let standard = SecurityLevel::Standard;
assert!(!standard.pow_enabled());
assert!(!standard.full_vanguards());
assert_eq!(standard.vanguard_mode(), VanguardMode::Lite);
let enhanced = SecurityLevel::Enhanced;
assert!(enhanced.pow_enabled());
assert!(!enhanced.full_vanguards());
let maximum = SecurityLevel::Maximum;
assert!(maximum.pow_enabled());
assert!(maximum.full_vanguards());
assert_eq!(maximum.vanguard_mode(), VanguardMode::Full);
}
#[test]
fn test_client_security_configs() {
let standard = ClientSecurityConfig::standard();
assert!(!standard.strict_isolation);
let enhanced = ClientSecurityConfig::enhanced();
assert!(enhanced.strict_isolation);
let maximum = ClientSecurityConfig::maximum();
assert_eq!(maximum.vanguard_mode, VanguardMode::Full);
}
#[test]
fn test_service_security_configs() {
let standard = ServiceSecurityConfig::standard();
assert!(!standard.enable_pow);
assert!(standard.rate_limit.is_none());
let enhanced = ServiceSecurityConfig::enhanced();
assert!(enhanced.enable_pow);
assert!(enhanced.rate_limit.is_some());
let maximum = ServiceSecurityConfig::maximum();
assert_eq!(maximum.num_intro_points, 5);
assert_eq!(maximum.max_streams, 100);
}
#[test]
fn test_service_to_onion_config() {
let security = ServiceSecurityConfig::maximum();
let config = security.to_onion_config("test-service");
assert!(config.enable_pow);
assert_eq!(config.max_streams_per_circuit, 100);
assert_eq!(config.num_intro_points, 5);
assert_eq!(config.rate_limit_at_intro, Some((10.0, 20)));
}
#[test]
fn test_level_to_onion_config() {
let config = SecurityLevel::Maximum.onion_service_config("secure-svc");
assert!(config.enable_pow);
assert_eq!(config.num_intro_points, 5);
}
}