Test dropping NRs with repeated nonces and DB storage before processing

This commit is contained in:
Vecna 2024-04-12 12:26:36 -04:00
parent c82e604e3d
commit c5a05be6d8
2 changed files with 307 additions and 4 deletions

View File

@ -20,7 +20,7 @@ pub enum NegativeReportError {
}
/// A report that the user was unable to connect to the bridge
#[derive(Eq, PartialEq, Ord, PartialOrd)]
#[derive(Debug, Eq, PartialEq, Ord, PartialOrd)]
pub struct NegativeReport {
/// hashed fingerprint (SHA-1 hash of 20-byte bridge ID)
pub fingerprint: [u8; 20],
@ -200,7 +200,7 @@ impl SerializableNegativeReport {
}
/// Proof that the user knows (and should be able to access) a given bridge
#[derive(Eq, PartialEq, Ord, PartialOrd, Serialize, Deserialize)]
#[derive(Debug, Eq, PartialEq, Ord, PartialOrd, Serialize, Deserialize)]
pub enum ProofOfBridgeKnowledge {
/// Hash of bridge line as proof of knowledge of bridge line
HashOfBridgeLine(HashOfBridgeLine),
@ -210,7 +210,7 @@ pub enum ProofOfBridgeKnowledge {
}
/// Hash of bridge line to prove knowledge of that bridge
#[derive(Eq, PartialEq, Ord, PartialOrd, Serialize, Deserialize)]
#[derive(Debug, Eq, PartialEq, Ord, PartialOrd, Serialize, Deserialize)]
pub struct HashOfBridgeLine {
hash: [u8; 32],
}
@ -227,7 +227,7 @@ impl HashOfBridgeLine {
}
/// Hash of bucket ID to prove knowledge of bridges in that bucket
#[derive(Eq, PartialEq, Ord, PartialOrd, Serialize, Deserialize)]
#[derive(Debug, Eq, PartialEq, Ord, PartialOrd, Serialize, Deserialize)]
pub struct HashOfBucket {
hash: [u8; 32],
}

View File

@ -327,6 +327,237 @@ fn test_negative_reports() {
assert!(!invalid_report_4.verify(&bridge_info_1));
assert!(!invalid_report_5.verify(&bridge_info_2));
// Test that reports with duplicate nonces are rejected
// Open test database
let db: Db = sled::open("test_db").unwrap();
// Delete all data in test DB
db.clear().unwrap();
assert!(!db.contains_key("nrs-to-process").unwrap());
let mut nonce = [0; 32];
rng.fill_bytes(&mut nonce);
// A valid report
let valid_report_1 = NegativeReport::new(
bridges[0].fingerprint,
ProofOfBridgeKnowledge::HashOfBridgeLine(HashOfBridgeLine::new(&bridges[0], date, nonce)),
"ru".to_string(),
date,
nonce,
BridgeDistributor::Lox,
);
// Report which reuses this nonce
let invalid_report_1 = NegativeReport::new(
bridges[0].fingerprint,
ProofOfBridgeKnowledge::HashOfBridgeLine(HashOfBridgeLine::new(&bridges[0], date, nonce)),
"ru".to_string(),
date,
nonce,
BridgeDistributor::Lox,
);
// This is the same report
assert_eq!(valid_report_1, invalid_report_1);
// Report which reuses this nonce for a different bridge
let invalid_report_2 = NegativeReport::new(
bridges[1].fingerprint,
ProofOfBridgeKnowledge::HashOfBridgeLine(HashOfBridgeLine::new(&bridges[1], date, nonce)),
"ru".to_string(),
date,
nonce,
BridgeDistributor::Lox,
);
// Report which uses this nonce but on a different day
let valid_report_2 = NegativeReport::new(
bridges[0].fingerprint,
ProofOfBridgeKnowledge::HashOfBridgeLine(HashOfBridgeLine::new(
&bridges[0],
date - 1,
nonce,
)),
"ru".to_string(),
date - 1,
nonce,
BridgeDistributor::Lox,
);
// Report with different nonce
let mut nonce = [0; 32];
rng.fill_bytes(&mut nonce);
let valid_report_3 = NegativeReport::new(
bridges[0].fingerprint,
ProofOfBridgeKnowledge::HashOfBridgeLine(HashOfBridgeLine::new(&bridges[0], date, nonce)),
"ru".to_string(),
date,
nonce,
BridgeDistributor::Lox,
);
let map_key_1 = format!(
"{}_{}_{}",
array_bytes::bytes2hex("", valid_report_1.fingerprint),
"ru".to_string(),
date
);
save_negative_report_to_process(&db, valid_report_1);
let nrs_to_process: BTreeMap<String, Vec<SerializableNegativeReport>> =
bincode::deserialize(&db.get("nrs-to-process").unwrap().unwrap()).unwrap();
let negative_reports = nrs_to_process.get(&map_key_1).unwrap();
assert_eq!(negative_reports.len(), 1);
save_negative_report_to_process(&db, invalid_report_1); // no change
let nrs_to_process: BTreeMap<String, Vec<SerializableNegativeReport>> =
bincode::deserialize(&db.get("nrs-to-process").unwrap().unwrap()).unwrap();
let negative_reports = nrs_to_process.get(&map_key_1).unwrap();
assert_eq!(negative_reports.len(), 1);
let map_key_2 = format!(
"{}_{}_{}",
array_bytes::bytes2hex("", invalid_report_2.fingerprint),
"ru".to_string(),
date
);
save_negative_report_to_process(&db, invalid_report_2); // no change
let nrs_to_process: BTreeMap<String, Vec<SerializableNegativeReport>> =
bincode::deserialize(&db.get("nrs-to-process").unwrap().unwrap()).unwrap();
assert!(!nrs_to_process.contains_key(&map_key_2));
let map_key_3 = format!(
"{}_{}_{}",
array_bytes::bytes2hex("", valid_report_2.fingerprint),
"ru".to_string(),
date - 1
);
save_negative_report_to_process(&db, valid_report_2);
let nrs_to_process: BTreeMap<String, Vec<SerializableNegativeReport>> =
bincode::deserialize(&db.get("nrs-to-process").unwrap().unwrap()).unwrap();
let negative_reports = nrs_to_process.get(&map_key_3).unwrap();
assert_eq!(negative_reports.len(), 1);
save_negative_report_to_process(&db, valid_report_3);
let nrs_to_process: BTreeMap<String, Vec<SerializableNegativeReport>> =
bincode::deserialize(&db.get("nrs-to-process").unwrap().unwrap()).unwrap();
let negative_reports = nrs_to_process.get(&map_key_1).unwrap();
assert_eq!(negative_reports.len(), 2);
// Same tests, but use hash of bucket
// Delete all data in test DB
db.clear().unwrap();
assert!(!db.contains_key("nrs-to-process").unwrap());
let mut nonce = [0; 32];
rng.fill_bytes(&mut nonce);
// A valid report
let valid_report_1 = NegativeReport::new(
bridges[0].fingerprint,
ProofOfBridgeKnowledge::HashOfBucket(HashOfBucket::new(&cred.bucket, date, nonce)),
"ru".to_string(),
date,
nonce,
BridgeDistributor::Lox,
);
// Report which reuses this nonce
let invalid_report_1 = NegativeReport::new(
bridges[0].fingerprint,
ProofOfBridgeKnowledge::HashOfBucket(HashOfBucket::new(&cred.bucket, date, nonce)),
"ru".to_string(),
date,
nonce,
BridgeDistributor::Lox,
);
// This is the same report
assert_eq!(valid_report_1, invalid_report_1);
// Report which reuses this nonce for a different bridge
let invalid_report_2 = NegativeReport::new(
bridges[1].fingerprint,
ProofOfBridgeKnowledge::HashOfBucket(HashOfBucket::new(&cred.bucket, date, nonce)),
"ru".to_string(),
date,
nonce,
BridgeDistributor::Lox,
);
// Report which uses this nonce but on a different day
let valid_report_2 = NegativeReport::new(
bridges[0].fingerprint,
ProofOfBridgeKnowledge::HashOfBucket(HashOfBucket::new(&cred.bucket, date - 1, nonce)),
"ru".to_string(),
date - 1,
nonce,
BridgeDistributor::Lox,
);
// Report with different nonce
let mut nonce = [0; 32];
rng.fill_bytes(&mut nonce);
let valid_report_3 = NegativeReport::new(
bridges[0].fingerprint,
ProofOfBridgeKnowledge::HashOfBucket(HashOfBucket::new(&cred.bucket, date, nonce)),
"ru".to_string(),
date,
nonce,
BridgeDistributor::Lox,
);
let map_key_1 = format!(
"{}_{}_{}",
array_bytes::bytes2hex("", valid_report_1.fingerprint),
"ru".to_string(),
date
);
save_negative_report_to_process(&db, valid_report_1);
let nrs_to_process: BTreeMap<String, Vec<SerializableNegativeReport>> =
bincode::deserialize(&db.get("nrs-to-process").unwrap().unwrap()).unwrap();
let negative_reports = nrs_to_process.get(&map_key_1).unwrap();
assert_eq!(negative_reports.len(), 1);
save_negative_report_to_process(&db, invalid_report_1); // no change
let nrs_to_process: BTreeMap<String, Vec<SerializableNegativeReport>> =
bincode::deserialize(&db.get("nrs-to-process").unwrap().unwrap()).unwrap();
let negative_reports = nrs_to_process.get(&map_key_1).unwrap();
assert_eq!(negative_reports.len(), 1);
let map_key_2 = format!(
"{}_{}_{}",
array_bytes::bytes2hex("", invalid_report_2.fingerprint),
"ru".to_string(),
date
);
save_negative_report_to_process(&db, invalid_report_2); // no change
let nrs_to_process: BTreeMap<String, Vec<SerializableNegativeReport>> =
bincode::deserialize(&db.get("nrs-to-process").unwrap().unwrap()).unwrap();
assert!(!nrs_to_process.contains_key(&map_key_2));
let map_key_3 = format!(
"{}_{}_{}",
array_bytes::bytes2hex("", valid_report_2.fingerprint),
"ru".to_string(),
date - 1
);
save_negative_report_to_process(&db, valid_report_2);
let nrs_to_process: BTreeMap<String, Vec<SerializableNegativeReport>> =
bincode::deserialize(&db.get("nrs-to-process").unwrap().unwrap()).unwrap();
let negative_reports = nrs_to_process.get(&map_key_3).unwrap();
assert_eq!(negative_reports.len(), 1);
save_negative_report_to_process(&db, valid_report_3);
let nrs_to_process: BTreeMap<String, Vec<SerializableNegativeReport>> =
bincode::deserialize(&db.get("nrs-to-process").unwrap().unwrap()).unwrap();
let negative_reports = nrs_to_process.get(&map_key_1).unwrap();
assert_eq!(negative_reports.len(), 2);
}
#[test]
@ -469,4 +700,76 @@ fn test_positive_reports() {
assert!(invalid_report_4.to_report().is_err());
assert!(invalid_report_5.to_report().is_err());
// Test storing to-be-processed positive reports to database
// Create reports
let report_1 = PositiveReport::from_lox_credential(
bridges[0].fingerprint,
None,
&cred,
&th.ba.lox_pub,
"ru".to_string(),
)
.unwrap();
let report_2 = PositiveReport::from_lox_credential(
bridges[0].fingerprint,
None,
&cred,
&th.ba.lox_pub,
"ru".to_string(),
)
.unwrap();
let report_3 = PositiveReport::from_lox_credential(
bridges[1].fingerprint,
None,
&cred,
&th.ba.lox_pub,
"ru".to_string(),
)
.unwrap();
// Open test database
let db: Db = sled::open("test_db").unwrap();
// Delete all data in test DB
db.clear().unwrap();
assert!(!db.contains_key("prs-to-process").unwrap());
let map_key_1 = format!(
"{}_{}_{}",
array_bytes::bytes2hex("", report_1.fingerprint),
&report_1.country,
&report_1.date
);
let map_key_2 = format!(
"{}_{}_{}",
array_bytes::bytes2hex("", report_3.fingerprint),
&report_3.country,
&report_3.date
);
save_positive_report_to_process(&db, report_1);
let prs_to_process: BTreeMap<String, Vec<SerializablePositiveReport>> =
bincode::deserialize(&db.get("prs-to-process").unwrap().unwrap()).unwrap();
let positive_reports = prs_to_process.get(&map_key_1).unwrap();
assert_eq!(positive_reports.len(), 1);
assert!(!prs_to_process.contains_key(&map_key_2));
save_positive_report_to_process(&db, report_2);
let prs_to_process: BTreeMap<String, Vec<SerializablePositiveReport>> =
bincode::deserialize(&db.get("prs-to-process").unwrap().unwrap()).unwrap();
let positive_reports = prs_to_process.get(&map_key_1).unwrap();
assert_eq!(positive_reports.len(), 2);
assert!(!prs_to_process.contains_key(&map_key_2));
save_positive_report_to_process(&db, report_3);
let prs_to_process: BTreeMap<String, Vec<SerializablePositiveReport>> =
bincode::deserialize(&db.get("prs-to-process").unwrap().unwrap()).unwrap();
// Check that this has not changed
let positive_reports = prs_to_process.get(&map_key_1).unwrap();
assert_eq!(positive_reports.len(), 2);
// New report added to its own collection
let positive_reports = prs_to_process.get(&map_key_2).unwrap();
assert_eq!(positive_reports.len(), 1);
}