|
@@ -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()
|