Merge changes from upstream

This commit is contained in:
Vecna 2024-02-20 16:45:56 -05:00
commit 65e763724b
17 changed files with 431 additions and 37 deletions

8
Cargo.lock generated
View File

@ -1919,9 +1919,9 @@ dependencies = [
[[package]]
name = "serde_with"
version = "3.4.0"
version = "3.5.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "64cd236ccc1b7a29e7e2739f27c0b2dd199804abc4290e32f59f3b68d6405c23"
checksum = "f58c3a1b3e418f61c25b2aeb43fc6c95eaa252b8cecdda67f401943e9e08d33f"
dependencies = [
"base64",
"chrono",
@ -1936,9 +1936,9 @@ dependencies = [
[[package]]
name = "serde_with_macros"
version = "3.4.0"
version = "3.5.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "93634eb5f75a2323b16de4748022ac4297f9e76b6dced2be287a099f41b5e788"
checksum = "d2068b437a31fc68f25dd7edc296b078f04b45145c199d8eed9866e45f1ff274"
dependencies = [
"darling",
"proc-macro2",

View File

@ -25,7 +25,7 @@ tokio = { version = "1", features = ["full", "macros", "signal"] }
rand = "0.8.5"
reqwest = { version = "0.11", features = ["json", "stream"]}
serde = { version = "1.0", features = ["derive", "rc"] }
serde_with = "3.4.0"
serde_with = "3.5.0"
lox-zkp = { git = "https://gitlab.torproject.org/onyinyang/lox-zkp", version = "0.8.0" }
lox-library = { path = "../lox-library", version = "0.1.0"}
lox_utils = { path = "../lox-utils", version = "0.1.0"}

View File

@ -3,6 +3,7 @@
"db_path": "lox_db"
},
"lox_authority_port": 8001,
"metrics_port": 5222,
"bridge_config": {
"watched_blockages": [

File diff suppressed because one or more lines are too long

View File

@ -499,7 +499,23 @@ impl LoxServerContext {
Ok(resp) => prepare_header(resp),
Err(e) => {
println!("Error parsing today to JSON");
prepare_error_header(e.to_string())
let response = json!({"error": e.to_string()});
let val = serde_json::to_string(&response).unwrap();
return prepare_header(val);
}
}
}
// Return the serialized pubkeys for the Bridge Authority as an HTTP response
pub fn send_constants(self) -> Response<Body> {
let constants = lox_utils::LOX_SYSTEM_INFO;
match serde_json::to_string(&constants) {
Ok(resp) => prepare_header(resp),
Err(e) => {
println!("Error parsing Constants to JSON");
let response = json!({"error": e.to_string()});
let val = serde_json::to_string(&response).unwrap();
prepare_header(val)
}
}
}
@ -710,7 +726,11 @@ impl LoxServerContext {
pub fn advance_days_with_response_test(self, request: Bytes) -> Response<Body> {
let req: u16 = match serde_json::from_slice(&request) {
Ok(req) => req,
Err(e) => return prepare_error_header(e.to_string()),
Err(e) => {
let response = json!({"error": e.to_string()});
let val = serde_json::to_string(&response).unwrap();
return prepare_header(val);
}
};
self.advance_days_test(req);
self.send_today()

View File

@ -63,6 +63,7 @@ struct Args {
struct Config {
db: DbConfig,
metrics_port: u16,
lox_authority_port: u16,
bridge_config: BridgeConfig,
rtype: ResourceInfo,
}
@ -121,7 +122,7 @@ async fn rdsys_request_creator(
// Makes a request to rdsys for the full set of Resources assigned to lox every interval
// (defined in the function)
async fn rdsys_request(rtype: ResourceInfo, tx: mpsc::Sender<ResourceState>) {
let mut interval = interval(Duration::from_secs(5));
let mut interval = interval(Duration::from_secs(120));
loop {
interval.tick().await;
let resources = match request_resources(
@ -355,7 +356,7 @@ async fn main() {
async move { Ok::<_, Infallible>(service) }
});
let addr = SocketAddr::from(([127, 0, 0, 1], 8001));
let addr = SocketAddr::from(([127, 0, 0, 1], config.lox_authority_port));
let server = Server::bind(&addr).serve(make_service);
let graceful = server.with_graceful_shutdown(shutdown_signal());
println!("Listening on {}", addr);

View File

@ -22,6 +22,7 @@ pub async fn handle(
}
(&Method::POST, "/pubkeys") => Ok::<_, Infallible>(cloned_context.send_keys()),
(&Method::POST, "/today") => Ok::<_, Infallible>(cloned_context.send_today()),
(&Method::POST, "/constants") => Ok::<_, Infallible>(cloned_context.send_constants()),
(&Method::POST, "/openreq") => Ok::<_, Infallible>({
let bytes = body::to_bytes(req.into_body()).await.unwrap();
cloned_context.verify_and_send_open_cred(bytes)
@ -93,6 +94,7 @@ mod tests {
fn invite(&self) -> Request<Body>;
fn reachability(&self) -> Request<Body>;
fn pubkeys(&self) -> Request<Body>;
fn constants(&self) -> Request<Body>;
fn openinvite(&self, request: proto::open_invite::Request) -> Request<Body>;
fn trustpromo(&self, request: proto::trust_promotion::Request) -> Request<Body>;
fn trustmigration(&self, request: proto::migration::Request) -> Request<Body>;
@ -129,6 +131,14 @@ mod tests {
.unwrap()
}
fn constants(&self) -> Request<Body> {
Request::builder()
.method("POST")
.uri("http://localhost/constants")
.body(Body::empty())
.unwrap()
}
fn openinvite(&self, request: proto::open_invite::Request) -> Request<Body> {
let req_str = serde_json::to_string(&request).unwrap();
Request::builder()
@ -378,6 +388,16 @@ mod tests {
assert_eq!(pubkey_response.status(), StatusCode::OK);
}
#[tokio::test]
async fn test_handle_constants() {
let th = TestHarness::new();
let lc = LoxClientMock {};
// Test Pubkeys
let constant_request = lc.constants();
let constant_response = handle(th.context.clone(), constant_request).await.unwrap();
assert_eq!(constant_response.status(), StatusCode::OK);
}
#[tokio::test]
async fn test_handle_lox_protocols() {
let mut th = TestHarness::new();

View File

@ -76,8 +76,9 @@ pub fn parse_into_buckets(
count += 1;
} else {
buckets.push(bucket);
count = 0;
bucket = [BridgeLine::default(); MAX_BRIDGES_PER_BUCKET];
bucket[0] = bridgeline;
count = 1;
}
}
// Handle the extra buckets that were not allocated already

View File

@ -20,7 +20,7 @@ bincode = "1"
chrono = "0.4"
rand = { version = "0.8", features = ["std_rng"]}
serde = "1.0.195"
serde_with = {version = "3.4.0", features = ["json"]}
serde_with = {version = "3.5.0", features = ["json"]}
sha2 = "0.10"
statistical = "1.0.0"
lazy_static = "1"

View File

@ -25,7 +25,7 @@ use std::convert::{TryFrom, TryInto};
use subtle::ConstantTimeEq;
/// Each bridge information line is serialized into this many bytes
pub const BRIDGE_BYTES: usize = 200;
pub const BRIDGE_BYTES: usize = 250;
/// The max number of bridges per bucket
pub const MAX_BRIDGES_PER_BUCKET: usize = 3;

View File

@ -556,8 +556,24 @@ impl BridgeAuth {
}
res = ReplaceSuccess::Replaced
} else if !self.bridge_table.spares.is_empty() {
// First get the bucketnums for the replacement bridge in case it is a spare
let mut bucketnums: Vec<u32> = Vec::new();
for (bucketnum, _) in positions.iter() {
bucketnums.push(*bucketnum);
}
// Get the first spare and remove it from the spares set.
let spare = *self.bridge_table.spares.iter().next().unwrap();
let mut spare = *self.bridge_table.spares.iter().next().unwrap();
// Check that the first spare in the list of spares is not the one to be replaced
if bucketnums.contains(&spare) {
// If it is, take the last spare instead
spare = *self.bridge_table.spares.iter().last().unwrap();
// If this is the same bucketnum, there is only one spare bucket with the bridge
// to be replaced in it, so don't replace it.
if bucketnums.contains(&spare) {
res = ReplaceSuccess::NotReplaced;
return res;
}
}
self.bridge_table.spares.remove(&spare);
self.bridge_table.recycleable_keys.push(spare);
// Get the actual bridges from the spare bucket
@ -596,6 +612,7 @@ impl BridgeAuth {
}
res = ReplaceSuccess::Replaced
} else {
println!("No available bridges");
// If there are no available bridges that can be assigned here, the only thing
// that can be done is return an indication that updating the gone bridge
// didn't work.

View File

@ -1057,13 +1057,15 @@ fn test_update_bridge() {
#[test]
fn test_bridge_replace() {
// Create 3 open invitation buckets and 3 spare buckets
let cases = vec!["not found", "available", "unallocated", "failed", "spare"];
let cases = vec!["not found", "available", "unallocated", "spare", "failed"];
let num_buckets = 5;
let hot_spare = 0;
for case in cases {
let mut th: TestHarness;
if case != "failed" {
if String::from(case) != "failed" {
th = TestHarness::new();
} else {
th = TestHarness::new_buckets(5, 0);
th = TestHarness::new_buckets(num_buckets, hot_spare);
}
// Randomly select a bridge to replace
@ -1072,6 +1074,7 @@ fn test_bridge_replace() {
while !th.ba.bridge_table.buckets.contains_key(&num) {
num = rand::thread_rng().gen_range(0..th.ba.bridge_table.counter);
}
println!("chosen num is: {:?}", num);
let replaceable_bucket = *th.ba.bridge_table.buckets.get(&num).unwrap();
let replacement_bridge = &replaceable_bucket[0];
assert!(
@ -1207,7 +1210,7 @@ fn test_bridge_replace() {
"Extra spare bridges not added to unallocated bridges"
);
println!("Successfully added unallocated bridgeline");
println!("Successfully added bridgeline from spare");
}
"failed" => {
// Case four: available_bridge == None and unallocated_bridges == None and spare buckets == None

View File

@ -15,7 +15,7 @@ repository = "https://gitlab.torproject.org/tpo/anti-censorship/lox.git/"
lox-library = {path = "../lox-library", version = "0.1.0"}
serde = "1"
serde_json = "1.0.108"
serde_with = "3.4.0"
serde_with = "3.5.0"
[features]

View File

@ -2,7 +2,7 @@ use lox_library::bridge_table::{
from_scalar, BridgeLine, BridgeTable, EncryptedBucket, MAX_BRIDGES_PER_BUCKET,
};
use lox_library::cred::{BucketReachability, Invitation, Lox};
use lox_library::proto;
use lox_library::proto::{self, check_blockage, level_up, trust_promotion};
use lox_library::{IssuerPubKey, OPENINV_LENGTH};
use serde::{Deserialize, Serialize};
use serde_with::serde_as;
@ -75,17 +75,21 @@ pub struct PubKeys {
#[derive(Debug, Deserialize, Serialize)]
pub struct LoxSystemInfo {
max_blockages: [u32; proto::level_up::MAX_LEVEL + 1],
level_interval: [u32; proto::level_up::MAX_LEVEL + 1],
level_invitations: [u32; proto::level_up::MAX_LEVEL + 1],
min_trust_level: u32,
pub max_level: usize,
pub untrusted_interval: u32,
pub max_blockages: [u32; level_up::MAX_LEVEL + 1],
pub level_interval: [u32; level_up::MAX_LEVEL + 1],
pub level_invitations: [u32; level_up::MAX_LEVEL + 1],
pub min_blockage_migration_trust_level: u32,
}
pub const LOX_SYSTEM_INFO: LoxSystemInfo = LoxSystemInfo {
max_blockages: proto::level_up::MAX_BLOCKAGES,
level_interval: proto::level_up::LEVEL_INTERVAL,
level_invitations: proto::level_up::LEVEL_INVITATIONS,
min_trust_level: proto::check_blockage::MIN_TRUST_LEVEL,
max_level: level_up::MAX_LEVEL,
untrusted_interval: trust_promotion::UNTRUSTED_INTERVAL,
max_blockages: level_up::MAX_BLOCKAGES,
level_interval: level_up::LEVEL_INTERVAL,
level_invitations: level_up::LEVEL_INVITATIONS,
min_blockage_migration_trust_level: check_blockage::MIN_TRUST_LEVEL,
};
#[serde_as]

View File

@ -19,6 +19,8 @@ import init, {
set_panic_hook, get_last_upgrade_time, get_trust_level, get_invites_remaining, get_issued_invite_expiry, get_received_invite_expiry, get_bridgelines_from_bucket} from "./pkg/lox_wasm.js";
let pubkeys = await simple_request("/pubkeys");
console.log("Got pubkeys: " + pubkeys);
let constants = await simple_request("/constants");
console.log("Got constants: " + constants);
// Get Lox Invitation
let requested_invite = await init().then(() => {

View File

@ -789,19 +789,12 @@ pub fn get_bridgelines_from_bucket(
}
}
pub fn get_constants() -> Result<String, JsValue> {
match serde_json::to_string(&lox_utils::LOX_SYSTEM_INFO) {
Ok(system_info_str) => Ok(system_info_str),
Err(e) => Err(JsValue::from(e.to_string())),
}
}
#[wasm_bindgen]
pub fn invitation_is_trusted(unspecified_invitation_str: String) -> Result<bool, JsValue> {
match serde_json::from_str::<Invitation>(&unspecified_invitation_str) {
Ok(_) => Ok(true),
Err(_) => {
let invite = unspecified_invitation_str.as_bytes();
match lox_utils::validate(invite) {
match serde_json::from_str::<lox_utils::Invite>(&unspecified_invitation_str){
Ok(_) => Ok(false),
Err(e) => Err(JsValue::from(e.to_string())),
}

332
doc/lox-distributor-api.md Normal file

File diff suppressed because one or more lines are too long