Assorted improvements, mostly suggested by clippy

This commit is contained in:
Vecna 2024-05-29 13:20:56 -04:00
parent f245ee21f9
commit 461d7d4ce5
7 changed files with 102 additions and 117 deletions

View File

@ -23,7 +23,7 @@ impl EciesCiphertext {
let mut rng = rand::thread_rng();
let secret = EphemeralSecret::random_from_rng(&mut rng);
let client_pubkey = PublicKey::from(&secret);
let shared_secret = secret.diffie_hellman(&receiver_pubkey);
let shared_secret = secret.diffie_hellman(receiver_pubkey);
// Compute key
let hk = Hkdf::<Sha3_256>::new(None, shared_secret.as_bytes());
@ -39,11 +39,11 @@ impl EciesCiphertext {
let key: Key<Aes256Gcm> = symmetric_key.into();
let cipher = Aes256Gcm::new(&key);
let nonce = Aes256Gcm::generate_nonce(&mut rng);
match cipher.encrypt(&nonce, &*message) {
match cipher.encrypt(&nonce, message) {
Ok(ct) => Ok(EciesCiphertext {
pubkey: client_pubkey,
nonce: nonce.to_vec(),
ct: ct,
ct,
}),
Err(_) => Err("Failed to encrypt".to_string()),
}

View File

@ -60,7 +60,7 @@ impl ExtraInfo {
let date_str = if entry.contains_key("bridge-stats-end") {
let line = entry.get("bridge-stats-end").unwrap();
// Parse out (86400 s) from end of line
&line[..line.find("(").unwrap() - 1]
&line[..line.find('(').unwrap() - 1]
} else {
entry.get("published").unwrap().as_str()
};
@ -77,7 +77,7 @@ impl ExtraInfo {
let mut bridge_ips: BTreeMap<String, u32> = BTreeMap::new();
let countries: Vec<&str> = bridge_ips_str.split(',').collect();
for country in countries {
if country != "" {
if !country.is_empty() {
// bridge-ips may be empty
let (cc, count) = country.split_once('=').unwrap();
bridge_ips.insert(cc.to_string(), count.parse::<u32>().unwrap());
@ -94,46 +94,43 @@ impl ExtraInfo {
/// Accepts a downloaded extra-infos file as a big string, returns a set of
/// the ExtraInfos represented by the file.
pub fn parse_file<'a>(extra_info_str: &str) -> HashSet<Self> {
pub fn parse_file(extra_info_str: &str) -> HashSet<Self> {
let mut set = HashSet::<Self>::new();
let mut entry = HashMap::<String, String>::new();
for line in extra_info_str.lines() {
let line = line;
if line.starts_with("@type bridge-extra-info ") {
if !entry.is_empty() {
let extra_info = Self::from_map(&entry);
if extra_info.is_ok() {
set.insert(extra_info.unwrap());
if let Ok(ei) = extra_info {
set.insert(ei);
} else {
// Just print the error and continue.
println!("{}", extra_info.err().unwrap());
}
entry = HashMap::<String, String>::new();
}
} else {
if line.starts_with("extra-info ") {
// extra-info line has format:
// extra-info <nickname> <fingerprint>
let line_split: Vec<&str> = line.split(' ').collect();
if line_split.len() != 3 {
println!("Misformed extra-info line");
} else {
entry.insert("nickname".to_string(), line_split[1].to_string());
entry.insert("fingerprint".to_string(), line_split[2].to_string());
}
} else if line.starts_with("extra-info ") {
// extra-info line has format:
// extra-info <nickname> <fingerprint>
let line_split: Vec<&str> = line.split(' ').collect();
if line_split.len() != 3 {
println!("Misformed extra-info line");
} else {
let (key, value) = match line.split_once(' ') {
Some((k, v)) => (k, v),
None => (line, ""),
};
entry.insert(key.to_string(), value.to_string());
entry.insert("nickname".to_string(), line_split[1].to_string());
entry.insert("fingerprint".to_string(), line_split[2].to_string());
}
} else {
let (key, value) = match line.split_once(' ') {
Some((k, v)) => (k, v),
None => (line, ""),
};
entry.insert(key.to_string(), value.to_string());
}
}
// Do for the last one
let extra_info = Self::from_map(&entry);
if extra_info.is_ok() {
set.insert(extra_info.unwrap());
if let Ok(ei) = extra_info {
set.insert(ei);
} else {
println!("{}", extra_info.err().unwrap());
}
@ -168,7 +165,7 @@ impl fmt::Display for ExtraInfo {
str.push_str(format!("{}={}", cc, count,).as_str());
first_cc = false;
}
str.push_str("\n");
str.push('\n');
write!(f, "{}", str)
}

View File

@ -7,7 +7,7 @@ use lazy_static::lazy_static;
use serde::{Deserialize, Serialize};
use sled::Db;
use std::{
collections::{BTreeMap, HashMap, HashSet},
collections::{btree_map, hash_map, BTreeMap, HashMap, HashSet},
fmt,
};
use x25519_dalek::{PublicKey, StaticSecret};
@ -130,7 +130,7 @@ pub struct BridgeInfo {
impl BridgeInfo {
pub fn new(fingerprint: [u8; 20], nickname: &String) -> Self {
Self {
fingerprint: fingerprint,
fingerprint,
nickname: nickname.to_string(),
info_by_country: HashMap::<String, BridgeCountryInfo>::new(),
}
@ -182,13 +182,17 @@ impl BridgeCountryInfo {
Self {
info_by_day: BTreeMap::<u32, BTreeMap<BridgeInfoType, u32>>::new(),
blocked: false,
first_seen: first_seen,
first_seen,
first_pr: None,
}
}
pub fn add_info(&mut self, info_type: BridgeInfoType, date: u32, count: u32) {
if self.info_by_day.contains_key(&date) {
if let btree_map::Entry::Vacant(e) = self.info_by_day.entry(date) {
let mut info = BTreeMap::<BridgeInfoType, u32>::new();
info.insert(info_type, count);
e.insert(info);
} else {
let info = self.info_by_day.get_mut(&date).unwrap();
if !info.contains_key(&info_type) {
info.insert(info_type, count);
@ -202,10 +206,6 @@ impl BridgeCountryInfo {
let new_count = info.get(&info_type).unwrap() + count;
info.insert(info_type, new_count);
}
} else {
let mut info = BTreeMap::<BridgeInfoType, u32>::new();
info.insert(info_type, count);
self.info_by_day.insert(date, info);
}
// If this is the first instance of positive reports, save the date
@ -229,18 +229,18 @@ impl fmt::Display for BridgeCountryInfo {
for date in self.info_by_day.keys() {
let info = self.info_by_day.get(date).unwrap();
let ip_count = match info.get(&BridgeInfoType::BridgeIps) {
Some(v) => v,
None => &0,
Some(&v) => v,
None => 0,
};
let nr_count = match info.get(&BridgeInfoType::NegativeReports) {
Some(v) => v,
None => &0,
Some(&v) => v,
None => 0,
};
let pr_count = match info.get(&BridgeInfoType::PositiveReports) {
Some(v) => v,
None => &0,
Some(&v) => v,
None => 0,
};
if ip_count > &0 || nr_count > &0 || pr_count > &0 {
if ip_count > 0 || nr_count > 0 || pr_count > 0 {
str.push_str(
format!(
"\n date: {}\n connections: {}\n negative reports: {}\n positive reports: {}",
@ -319,7 +319,7 @@ pub fn add_extra_info_to_db(db: &Db, extra_info: ExtraInfo) {
let mut bridge_info = match db.get(fingerprint).unwrap() {
Some(v) => bincode::deserialize(&v).unwrap(),
None => {
add_bridge_to_db(&db, fingerprint);
add_bridge_to_db(db, fingerprint);
BridgeInfo::new(fingerprint, &extra_info.nickname)
}
};
@ -402,7 +402,7 @@ pub async fn update_extra_infos(
// Add new extra-infos data to database
for extra_info in new_extra_infos {
add_extra_info_to_db(&db, extra_info);
add_extra_info_to_db(db, extra_info);
}
// Store which files we've already downloaded and processed
@ -429,16 +429,16 @@ pub fn new_negative_report_key(db: &Db, date: u32) -> Option<PublicKey> {
Err(_) => BTreeMap::<u32, StaticSecret>::new(),
}
};
if nr_keys.contains_key(&date) {
None
} else {
let mut rng = rand::thread_rng();
let secret = StaticSecret::random_from_rng(&mut rng);
if let btree_map::Entry::Vacant(_e) = nr_keys.entry(date) {
let rng = rand::thread_rng();
let secret = StaticSecret::random_from_rng(rng);
let public = PublicKey::from(&secret);
nr_keys.insert(date, secret);
db.insert("nr-keys", bincode::serialize(&nr_keys).unwrap())
.unwrap();
Some(public)
} else {
None
}
}
@ -465,23 +465,16 @@ pub fn get_negative_report_secret_key(db: &Db, date: u32) -> Option<StaticSecret
/// If we have a key for the requested day, return the public part.
pub fn get_negative_report_public_key(db: &Db, date: u32) -> Option<PublicKey> {
match get_negative_report_secret_key(&db, date) {
Some(secret) => Some(PublicKey::from(&secret)),
None => None,
}
get_negative_report_secret_key(db, date).map(|secret| PublicKey::from(&secret))
}
/// Receive an encrypted negative report. Attempt to decrypt it and if
/// successful, add it to the database to be processed later.
pub fn handle_encrypted_negative_report(db: &Db, enc_report: EncryptedNegativeReport) {
match get_negative_report_secret_key(&db, enc_report.date) {
Some(secret) => match enc_report.decrypt(&secret) {
Ok(nr) => {
save_negative_report_to_process(&db, nr);
}
Err(_) => {}
},
None => {}
if let Some(secret) = get_negative_report_secret_key(db, enc_report.date) {
if let Ok(nr) = enc_report.decrypt(&secret) {
save_negative_report_to_process(db, nr);
}
}
}
@ -508,19 +501,18 @@ pub fn save_negative_report_to_process(db: &Db, nr: NegativeReport) {
// Store to-be-processed reports with key [fingerprint]_[country]_[date]
let map_key = format!(
"{}_{}_{}",
array_bytes::bytes2hex("", &nr.fingerprint),
array_bytes::bytes2hex("", nr.fingerprint),
&nr.country,
&nr.date,
);
if reports.contains_key(&map_key) {
if let btree_map::Entry::Vacant(e) = reports.entry(map_key.clone()) {
let nrs = vec![nr.to_serializable_report()];
e.insert(nrs);
} else {
reports
.get_mut(&map_key)
.unwrap()
.push(nr.to_serializable_report());
} else {
let mut nrs = Vec::<SerializableNegativeReport>::new();
nrs.push(nr.to_serializable_report());
reports.insert(map_key, nrs);
}
// Commit changes to database
db.insert("nrs-to-process", bincode::serialize(&reports).unwrap())
@ -580,7 +572,7 @@ pub async fn update_negative_reports(db: &Db, distributors: &BTreeMap<BridgeDist
let fingerprint = first_report.fingerprint;
let date = first_report.date;
let country = first_report.country.clone();
let count_valid = verify_negative_reports(&distributors, reports).await;
let count_valid = verify_negative_reports(distributors, reports).await;
// If we have new historical data, re-evaluate this bridge
if count_valid > 0 && date < today {
@ -600,22 +592,23 @@ pub async fn update_negative_reports(db: &Db, distributors: &BTreeMap<BridgeDist
None => {
// This case shouldn't happen unless the bridge hasn't
// published any bridge stats.
add_bridge_to_db(&db, fingerprint);
add_bridge_to_db(db, fingerprint);
BridgeInfo::new(fingerprint, &String::default())
}
};
// Add the new report count to it
if bridge_info.info_by_country.contains_key(&country) {
let bridge_country_info = bridge_info.info_by_country.get_mut(&country).unwrap();
bridge_country_info.add_info(BridgeInfoType::NegativeReports, date, count_valid);
} else {
if let hash_map::Entry::Vacant(_e) = bridge_info.info_by_country.entry(country.clone())
{
// No existing entry; make a new one.
let mut bridge_country_info = BridgeCountryInfo::new(date);
bridge_country_info.add_info(BridgeInfoType::NegativeReports, date, count_valid);
bridge_info
.info_by_country
.insert(country, bridge_country_info);
} else {
let bridge_country_info = bridge_info.info_by_country.get_mut(&country).unwrap();
bridge_country_info.add_info(BridgeInfoType::NegativeReports, date, count_valid);
}
// Commit changes to database
db.insert(fingerprint, bincode::serialize(&bridge_info).unwrap())
@ -648,19 +641,18 @@ pub fn save_positive_report_to_process(db: &Db, pr: PositiveReport) {
// Store to-be-processed reports with key [fingerprint]_[country]_[date]
let map_key = format!(
"{}_{}_{}",
array_bytes::bytes2hex("", &pr.fingerprint),
array_bytes::bytes2hex("", pr.fingerprint),
&pr.country,
&pr.date,
);
if reports.contains_key(&map_key) {
if let btree_map::Entry::Vacant(e) = reports.entry(map_key.clone()) {
let prs = vec![pr.to_serializable_report()];
e.insert(prs);
} else {
reports
.get_mut(&map_key)
.unwrap()
.push(pr.to_serializable_report());
} else {
let mut prs = Vec::<SerializablePositiveReport>::new();
prs.push(pr.to_serializable_report());
reports.insert(map_key, prs);
}
// Commit changes to database
db.insert("prs-to-process", bincode::serialize(&reports).unwrap())
@ -719,7 +711,7 @@ pub async fn update_positive_reports(db: &Db, distributors: &BTreeMap<BridgeDist
let fingerprint = first_report.fingerprint;
let date = first_report.date;
let country = first_report.country.clone();
let count_valid = verify_positive_reports(&distributors, reports).await;
let count_valid = verify_positive_reports(distributors, reports).await;
// If we have new historical data, re-evaluate this bridge
if count_valid > 0 && date < today {
@ -739,22 +731,20 @@ pub async fn update_positive_reports(db: &Db, distributors: &BTreeMap<BridgeDist
None => {
// This case shouldn't happen unless the bridge hasn't
// published any bridge stats.
add_bridge_to_db(&db, fingerprint);
add_bridge_to_db(db, fingerprint);
BridgeInfo::new(fingerprint, &String::default())
}
};
// Add the new report count to it
if bridge_info.info_by_country.contains_key(&country) {
let bridge_country_info = bridge_info.info_by_country.get_mut(&country).unwrap();
bridge_country_info.add_info(BridgeInfoType::PositiveReports, date, count_valid);
} else {
if let hash_map::Entry::Vacant(e) = bridge_info.info_by_country.entry(country.clone()) {
// No existing entry; make a new one.
let mut bridge_country_info = BridgeCountryInfo::new(date);
bridge_country_info.add_info(BridgeInfoType::PositiveReports, date, count_valid);
bridge_info
.info_by_country
.insert(country, bridge_country_info);
e.insert(bridge_country_info);
} else {
let bridge_country_info = bridge_info.info_by_country.get_mut(&country).unwrap();
bridge_country_info.add_info(BridgeInfoType::PositiveReports, date, count_valid);
}
// Commit changes to database
db.insert(fingerprint, bincode::serialize(&bridge_info).unwrap())
@ -806,7 +796,7 @@ pub fn guess_blockages(
let mut bridge_info: BridgeInfo =
bincode::deserialize(&db.get(fingerprint).unwrap().unwrap()).unwrap();
let mut new_blockages = HashSet::<String>::new();
let fpr_str = array_bytes::bytes2hex("", &fingerprint);
let fpr_str = array_bytes::bytes2hex("", fingerprint);
let first_date = if bridges_to_re_evaluate.contains_key(&fpr_str) {
*bridges_to_re_evaluate.get(&fpr_str).unwrap()
} else {
@ -871,12 +861,12 @@ pub async fn report_blockages(
let mut blockages_str = HashMap::<String, HashSet<String>>::new();
for (fingerprint, countries) in blockages {
let fpr_string = array_bytes::bytes2hex("", fingerprint);
if countries.len() > 0 {
if !countries.is_empty() {
blockages_str.insert(fpr_string, countries);
}
}
if blockages_str.len() > 0 {
if !blockages_str.is_empty() {
// Report blocked bridges to bridge distributor
let client = Client::new();
let req = Request::builder()

View File

@ -24,7 +24,7 @@ use tokio::{
sync::{broadcast, mpsc, oneshot},
time::sleep,
};
#[cfg(not(features = "simulation"))]
#[cfg(not(feature = "simulation"))]
use tokio_cron::{Job, Scheduler};
async fn shutdown_signal() {
@ -95,22 +95,20 @@ async fn update_daily_info(
min_historical_days: u32,
max_historical_days: u32,
) -> HashMap<[u8; 20], HashSet<String>> {
update_extra_infos(&db, &extra_infos_base_url)
.await
.unwrap();
update_negative_reports(&db, &distributors).await;
update_positive_reports(&db, &distributors).await;
update_extra_infos(db, extra_infos_base_url).await.unwrap();
update_negative_reports(db, distributors).await;
update_positive_reports(db, distributors).await;
let new_blockages = guess_blockages(
&db,
db,
&analysis::NormalAnalyzer::new(max_threshold, scaling_factor),
confidence,
min_historical_days,
max_historical_days,
);
report_blockages(&distributors, new_blockages.clone()).await;
report_blockages(distributors, new_blockages.clone()).await;
// Generate tomorrow's key if we don't already have it
new_negative_report_key(&db, get_date() + 1);
new_negative_report_key(db, get_date() + 1);
// Return new detected blockages
new_blockages
@ -177,7 +175,7 @@ async fn context_manager(
let blockages = update_daily_info(
&db,
&distributors,
&extra_infos_base_url,
extra_infos_base_url,
confidence,
max_threshold,
scaling_factor,

View File

@ -148,7 +148,7 @@ impl NegativeReport {
/// Deserializes the report from slice, eliding the underlying process
pub fn from_slice(slice: &[u8]) -> Result<Self, NegativeReportError> {
match serde_json::from_slice::<SerializableNegativeReport>(&slice) {
match serde_json::from_slice::<SerializableNegativeReport>(slice) {
Ok(v) => v.to_report(),
Err(_) => Err(NegativeReportError::FailedToDeserialize),
}
@ -163,7 +163,7 @@ impl NegativeReport {
}
ProofOfBridgeKnowledge::HashOfBucket(pok) => {
for b in &bridge_info.buckets {
let hash = HashOfBucket::new(&b, self.date, self.nonce);
let hash = HashOfBucket::new(b, self.date, self.nonce);
if hash == pok {
return true;
}
@ -188,7 +188,7 @@ pub struct SerializableNegativeReport {
impl SerializableNegativeReport {
pub fn to_report(self) -> Result<NegativeReport, NegativeReportError> {
if self.country == "" {
if self.country.is_empty() {
return Err(NegativeReportError::MissingCountryCode);
}
if !COUNTRY_CODES.contains(self.country.as_str()) {
@ -205,7 +205,7 @@ impl SerializableNegativeReport {
fingerprint: self.fingerprint,
bridge_pok: self.bridge_pok,
country: self.country.to_string(),
date: self.date.try_into().unwrap(),
date: self.date,
nonce: self.nonce,
distributor: self.distributor,
})
@ -224,7 +224,7 @@ pub struct EncryptedNegativeReport {
impl EncryptedNegativeReport {
pub fn decrypt(self, secret: &StaticSecret) -> Result<NegativeReport, NegativeReportError> {
match self.ciphertext.decrypt(&secret) {
match self.ciphertext.decrypt(secret) {
Ok(m) => match bincode::deserialize::<SerializableNegativeReport>(&m) {
Ok(ser_report) => ser_report.to_report(),
Err(_) => Err(NegativeReportError::FailedToDeserialize),

View File

@ -93,7 +93,7 @@ impl PositiveReport {
};
SerializablePositiveReport {
fingerprint: self.fingerprint,
bridge_token: bridge_token,
bridge_token,
lox_proof: self.lox_proof,
country: self.country,
date: self.date,
@ -115,7 +115,7 @@ impl PositiveReport {
/// Deserializes the report from slice, eliding the underlying process
pub fn from_slice(slice: &[u8]) -> Result<Self, PositiveReportError> {
match serde_json::from_slice::<SerializablePositiveReport>(&slice) {
match serde_json::from_slice::<SerializablePositiveReport>(slice) {
Ok(v) => v.to_report(),
Err(_) => Err(PositiveReportError::FailedToDeserialize),
}
@ -152,7 +152,7 @@ impl PositiveReport {
let BP = self.lox_proof.BP;
for bucket in buckets {
if bucket * Htable == BP {
return la.handle_positive_report(self.lox_proof, &Htable).is_ok();
return la.handle_positive_report(self.lox_proof, Htable).is_ok();
}
}
false
@ -177,7 +177,7 @@ impl SerializablePositiveReport {
if REQUIRE_BRIDGE_TOKEN && self.bridge_token.is_none() {
return Err(PositiveReportError::MissingBridgeToken);
}
if self.country == "" {
if self.country.is_empty() {
return Err(PositiveReportError::MissingCountryCode);
}
if !COUNTRY_CODES.contains(self.country.as_str()) {
@ -209,7 +209,7 @@ impl SerializablePositiveReport {
};
Ok(PositiveReport {
fingerprint: self.fingerprint,
bridge_token: bridge_token,
bridge_token,
lox_proof: self.lox_proof,
country: self.country,
date: self.date,
@ -275,9 +275,9 @@ pub struct SerializableUnsignedBridgeToken {
impl SerializableUnsignedBridgeToken {
pub fn to_unsigned_bridge_token(self) -> Result<UnsignedBridgeToken, PositiveReportError> {
if self.country == ""
if self.country.is_empty()
|| !COUNTRY_CODES.contains(self.country.as_str())
|| self.date > get_date().into()
|| self.date > get_date()
{
return Err(PositiveReportError::InvalidBridgeToken);
}
@ -345,7 +345,7 @@ impl SerializableBridgeToken {
pub fn to_bridge_token(self) -> Result<BridgeToken, PositiveReportError> {
let unsigned_bridge_token = self.unsigned_bridge_token.to_unsigned_bridge_token()?;
Ok(BridgeToken {
unsigned_bridge_token: unsigned_bridge_token,
unsigned_bridge_token,
sig: self.sig,
})
}

View File

@ -48,7 +48,7 @@ pub async fn handle(db: &Db, req: Request<Body>) -> Result<Response<Body>, Infal
return Ok(prepare_header(val));
}
};
handle_encrypted_negative_report(&db, enr);
handle_encrypted_negative_report(db, enr);
prepare_header("OK".to_string())
}),
(&Method::POST, "/positivereport") => Ok::<_, Infallible>({
@ -61,7 +61,7 @@ pub async fn handle(db: &Db, req: Request<Body>) -> Result<Response<Body>, Infal
return Ok(prepare_header(val));
}
};
save_positive_report_to_process(&db, pr);
save_positive_report_to_process(db, pr);
prepare_header("OK".to_string())
}),
_ => {