use crate::{ get_date, simulation::{bridge::Bridge, state::State}, PositiveReport, }; use lox_cli::{get_lox_pub, networking::Networking}; use lox_library::{cred::Lox, scalar_u32}; use rand::Rng; use std::collections::{HashMap, HashSet}; pub struct Censor { pub country: String, pub known_bridges: HashSet<[u8; 20]>, pub lox_credentials: HashMap<[u8; 20], Lox>, // How fast does this censor block bridges after learning about them? pub speed: Speed, // If censor implements random blocking, this is the date when it // will start blocking all the bridges it knows. pub delay_date: u32, // Does the censor attempt to hide the fact that a bridge has been blocked? pub hides: Hides, // Does the censor block bridges uniformly across the country? pub totality: Totality, // If censor implements partial blocking, what percent of // connections are blocked? If totality is not partial, this is set // to 100%. pub partial_blocking_percent: f64, } impl Censor { pub fn new(country: String, speed: Speed, hides: Hides, totality: Totality) -> Self { let mut rng = rand::thread_rng(); let delay_date = if speed == Speed::Random { let num: u32 = rng.gen_range(1..365); get_date() + num } else { 0 }; let partial_blocking_percent = if totality == Totality::Partial { let num: f64 = rng.gen_range(0.0..1.0); num } else { 1.0 }; Censor { country: country, known_bridges: HashSet::<[u8; 20]>::new(), lox_credentials: HashMap::<[u8; 20], Lox>::new(), speed: speed, delay_date: delay_date, hides: hides, totality: totality, partial_blocking_percent: partial_blocking_percent, } } pub fn knows_bridge(&self, fingerprint: &[u8; 20]) -> bool { self.known_bridges.contains(fingerprint) } pub fn learn_bridge(&mut self, fingerprint: &[u8; 20]) { self.known_bridges.insert(*fingerprint); } pub fn has_lox_cred(&self, fingerprint: &[u8; 20]) -> bool { self.lox_credentials.contains_key(fingerprint) } pub fn give_lox_cred(&mut self, fingerprint: &[u8; 20], cred: &Lox) { // We only need one level 3+ credential per bridge. (This will // change if we restrict positive reports to one per bridge per // credential.) if !self.has_lox_cred(fingerprint) && scalar_u32(&cred.trust_level).unwrap() >= 3 { // We want to clone the credential, but that's not allowed, // so we're going to serialize it and then deserialize it. let cloned_cred = bincode::deserialize(&bincode::serialize(&cred).unwrap()).unwrap(); self.lox_credentials.insert(*fingerprint, cloned_cred); } } // Make a bunch of connections and submit positive reports if possible async fn flood(&self, state: &State, bridges: &mut HashMap<[u8; 20], Bridge>) { // Only do this if Flooding censor if self.hides == Hides::Flooding { for fingerprint in &self.known_bridges { // Only do this if we're blocking the bridge if self.speed == Speed::Fast || self.speed == Speed::Lox && self.has_lox_cred(fingerprint) || self.speed == Speed::Random && self.delay_date <= get_date() { let bridge = bridges.get_mut(fingerprint).unwrap(); let mut rng = rand::thread_rng(); let num_connections = rng.gen_range(1000..30000); // Make a bunch of connections to the bridge bridge.censor_flood(&self.country, num_connections); // If we have a lv3+ credential, submit a bunch of // positive reports if self.has_lox_cred(fingerprint) { let lox_pub = get_lox_pub(&state.la_pubkeys); for _ in 0..num_connections { let pr = PositiveReport::from_lox_credential( bridge.fingerprint, None, &self.lox_credentials.get(&bridge.fingerprint).unwrap(), lox_pub, self.country.clone(), ) .unwrap(); state .tp_net .request("/positivereport".to_string(), pr.to_json().into_bytes()) .await; } } } } } } // TODO: How do we want to do this? We don't want to stop blocking // bridges the day after we start. fn recompute_delay(&mut self) { // Only do this if Random censor if self.speed == Speed::Random && self.delay_date <= get_date() { // Compute new delay date self.delay_date = { let mut rng = rand::thread_rng(); let num: u32 = rng.gen_range(1..365); get_date() + num } } } pub async fn end_of_day_tasks( &mut self, state: &State, bridges: &mut HashMap<[u8; 20], Bridge>, ) { if self.hides == Hides::Flooding && !(self.speed == Speed::Random && self.delay_date <= get_date()) { self.flood(state, bridges).await; } // TODO: recompute_delay sometimes //self.recompute_delay(); } } #[derive(PartialEq)] pub enum Speed { Fast, Lox, Random, } #[derive(PartialEq)] pub enum Hides { Overt, Hiding, Flooding, } #[derive(PartialEq)] pub enum Totality { Full, Partial, Throttling, }