|
|
@@ -43,14 +43,13 @@ pub struct User {
|
|
|
}
|
|
|
|
|
|
impl User {
|
|
|
- pub async fn new(config: &Config, is_censor: bool) -> Result<Self> {
|
|
|
- let cred = get_lox_credential(
|
|
|
- &config.la_net,
|
|
|
- &get_open_invitation(&config.la_net).await?,
|
|
|
- get_lox_pub(&config.la_pubkeys),
|
|
|
- )
|
|
|
- .await?
|
|
|
- .0;
|
|
|
+ pub async fn new(
|
|
|
+ config: &Config,
|
|
|
+ is_censor: bool,
|
|
|
+ bridges: &mut HashMap<[u8; 20], Bridge>,
|
|
|
+ censor: &mut Censor,
|
|
|
+ ) -> Result<Self> {
|
|
|
+ let cred = Self::get_new_credential(&config).await?.0;
|
|
|
|
|
|
// Probabilistically decide whether this user submits reports
|
|
|
let submits_reports = if is_censor {
|
|
|
@@ -64,6 +63,21 @@ impl User {
|
|
|
let mut rng = rand::thread_rng();
|
|
|
let prob_use_bridges = rng.gen_range(0.0..=1.0);
|
|
|
|
|
|
+ // If the user cooperates with the censor, immediately tell the
|
|
|
+ // censor about all the bridges
|
|
|
+ if is_censor {
|
|
|
+ let (bucket, _reachcred) = get_bucket(&config.la_net, &cred).await?;
|
|
|
+ for bridgeline in bucket {
|
|
|
+ if bridgeline != BridgeLine::default() {
|
|
|
+ if !bridges.contains_key(&bridgeline.get_hashed_fingerprint()) {
|
|
|
+ let bridge = Bridge::from_bridge_line(&bridgeline);
|
|
|
+ bridges.insert(bridgeline.get_hashed_fingerprint(), bridge);
|
|
|
+ }
|
|
|
+ censor.learn_bridge(&bridgeline.get_hashed_fingerprint());
|
|
|
+ }
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
Ok(Self {
|
|
|
is_censor,
|
|
|
primary_cred: cred,
|
|
|
@@ -73,27 +87,11 @@ impl User {
|
|
|
})
|
|
|
}
|
|
|
|
|
|
- pub async fn trusted_user(config: &Config) -> Result<Self> {
|
|
|
- let cred = get_lox_credential(
|
|
|
- &config.la_net,
|
|
|
- &get_open_invitation(&config.la_net).await?,
|
|
|
- get_lox_pub(&config.la_pubkeys),
|
|
|
- )
|
|
|
- .await?
|
|
|
- .0;
|
|
|
- Ok(Self {
|
|
|
- is_censor: false,
|
|
|
- primary_cred: cred,
|
|
|
- secondary_cred: None,
|
|
|
- submits_reports: true,
|
|
|
- prob_use_bridges: 1.0,
|
|
|
- })
|
|
|
- }
|
|
|
-
|
|
|
// TODO: This should probably return an actual error type
|
|
|
pub async fn invite(
|
|
|
&mut self,
|
|
|
config: &Config,
|
|
|
+ bridges: &mut HashMap<[u8; 20], Bridge>,
|
|
|
censor: &mut Censor,
|
|
|
invited_user_is_censor: bool,
|
|
|
) -> Result<Self> {
|
|
|
@@ -130,17 +128,31 @@ impl User {
|
|
|
// Calling function decides if the invited user is a censor
|
|
|
let is_censor = invited_user_is_censor;
|
|
|
|
|
|
- // Probabilistically decide whether this user submits reports
|
|
|
- let submits_reports = if is_censor {
|
|
|
- false
|
|
|
+ // Decide how likely this user is to use bridges on a given day
|
|
|
+ // and whether they submit reports
|
|
|
+ let (prob_use_bridges, submits_reports) = if is_censor {
|
|
|
+ (0.0, false)
|
|
|
} else {
|
|
|
- event_happens(config.prob_user_submits_reports)
|
|
|
+ let mut rng = rand::thread_rng();
|
|
|
+ let prob_use_bridges = rng.gen_range(0.0..=1.0);
|
|
|
+ let submits_reports = event_happens(config.prob_user_submits_reports);
|
|
|
+ (prob_use_bridges, submits_reports)
|
|
|
};
|
|
|
|
|
|
- // Randomly determine how likely this user is to use bridges on
|
|
|
- // a given day
|
|
|
- let mut rng = rand::thread_rng();
|
|
|
- let prob_use_bridges = rng.gen_range(0.0..=1.0);
|
|
|
+ // If the user cooperates with the censor, immediately tell the
|
|
|
+ // censor about all the bridges
|
|
|
+ if is_censor {
|
|
|
+ let (bucket, _reachcred) = get_bucket(&config.la_net, &self.primary_cred).await?;
|
|
|
+ for bridgeline in bucket {
|
|
|
+ if bridgeline != BridgeLine::default() {
|
|
|
+ if !bridges.contains_key(&bridgeline.get_hashed_fingerprint()) {
|
|
|
+ let bridge = Bridge::from_bridge_line(&bridgeline);
|
|
|
+ bridges.insert(bridgeline.get_hashed_fingerprint(), bridge);
|
|
|
+ }
|
|
|
+ censor.learn_bridge(&bridgeline.get_hashed_fingerprint());
|
|
|
+ }
|
|
|
+ }
|
|
|
+ }
|
|
|
|
|
|
Ok(Self {
|
|
|
is_censor,
|
|
|
@@ -153,8 +165,7 @@ impl User {
|
|
|
|
|
|
// Attempt to "connect" to the bridge, returns true if successful.
|
|
|
// Note that this does not involve making a real connection to a
|
|
|
- // real bridge. The function is async because the *censor* might
|
|
|
- // submit a positive report during this function.
|
|
|
+ // real bridge.
|
|
|
pub fn connect(&self, config: &Config, bridge: &mut Bridge, censor: &Censor) -> bool {
|
|
|
if censor.blocks_bridge(config, &bridge.fingerprint) {
|
|
|
if config.censor_totality == Full
|
|
|
@@ -254,21 +265,14 @@ impl User {
|
|
|
&mut self,
|
|
|
config: &Config,
|
|
|
num_users_requesting_invites: u32,
|
|
|
- num_censor_invites: u32,
|
|
|
bridges: &mut HashMap<[u8; 20], Bridge>,
|
|
|
censor: &mut Censor,
|
|
|
) -> Result<Vec<User>> {
|
|
|
if self.is_censor {
|
|
|
self.daily_tasks_censor(config, bridges, censor).await
|
|
|
} else {
|
|
|
- self.daily_tasks_non_censor(
|
|
|
- config,
|
|
|
- num_users_requesting_invites,
|
|
|
- num_censor_invites,
|
|
|
- bridges,
|
|
|
- censor,
|
|
|
- )
|
|
|
- .await
|
|
|
+ self.daily_tasks_non_censor(config, num_users_requesting_invites, bridges, censor)
|
|
|
+ .await
|
|
|
}
|
|
|
}
|
|
|
|
|
|
@@ -280,7 +284,6 @@ impl User {
|
|
|
&mut self,
|
|
|
config: &Config,
|
|
|
num_users_requesting_invites: u32,
|
|
|
- num_censor_invites: u32,
|
|
|
bridges: &mut HashMap<[u8; 20], Bridge>,
|
|
|
censor: &mut Censor,
|
|
|
) -> Result<Vec<User>> {
|
|
|
@@ -518,10 +521,31 @@ impl User {
|
|
|
None => 0, // This is probably an error case that should not happen
|
|
|
};
|
|
|
let mut new_friends = Vec::<User>::new();
|
|
|
+
|
|
|
+ // Scale the probability of inviting a censor, based on the
|
|
|
+ // user's own trust level. We assume that users with
|
|
|
+ // more-trusted credentials are less likely to invite
|
|
|
+ // censors because they have more to lose.
|
|
|
+ let level_scale = match scalar_u32(&self.primary_cred.trust_level) {
|
|
|
+ // These numbers are fairly arbitrary.
|
|
|
+ Some(4) => 0.01,
|
|
|
+ Some(3) => 0.1,
|
|
|
+ Some(2) => 0.5,
|
|
|
+ _ => 1.0,
|
|
|
+ };
|
|
|
for _i in 0..min(invitations, num_users_requesting_invites) {
|
|
|
if event_happens(config.prob_user_invites_friend) {
|
|
|
- // Invite non-censor friend
|
|
|
- match self.invite(&config, censor, false).await {
|
|
|
+ // With some probability, the user is convinced to
|
|
|
+ // invite a censor. We assume users with higher
|
|
|
+ // trust levels will be more cautious with
|
|
|
+ // invitations because they have more to lose.
|
|
|
+ let invited_friend_is_censor = censor.is_active()
|
|
|
+ && event_happens(config.prob_censor_gets_invite * level_scale);
|
|
|
+ // Invite friend (who might be a censor)
|
|
|
+ match self
|
|
|
+ .invite(&config, bridges, censor, invited_friend_is_censor)
|
|
|
+ .await
|
|
|
+ {
|
|
|
Ok(friend) => {
|
|
|
// You really shouldn't push your friends,
|
|
|
// especially new ones whose boundaries you
|
|
|
@@ -535,22 +559,6 @@ impl User {
|
|
|
}
|
|
|
}
|
|
|
|
|
|
- // Invite censor users if applicable
|
|
|
- let invitations = invitations - new_friends.len() as u32;
|
|
|
- for _i in 0..min(invitations, num_censor_invites) {
|
|
|
- if event_happens(config.prob_user_invites_friend) {
|
|
|
- // Invite non-censor friend
|
|
|
- match self.invite(&config, censor, true).await {
|
|
|
- Ok(friend) => {
|
|
|
- new_friends.push(friend);
|
|
|
- }
|
|
|
- Err(e) => {
|
|
|
- println!("{}", e);
|
|
|
- }
|
|
|
- }
|
|
|
- }
|
|
|
- }
|
|
|
-
|
|
|
Ok(new_friends)
|
|
|
} else {
|
|
|
Ok(Vec::<User>::new())
|
|
|
@@ -641,8 +649,6 @@ impl User {
|
|
|
censor.learn_bridge(&fingerprint);
|
|
|
// Censor doesn't want new_cred yet
|
|
|
self.primary_cred = new_cred;
|
|
|
- } else {
|
|
|
- eprintln!("Censor failed to get new credential");
|
|
|
}
|
|
|
}
|
|
|
|
|
|
@@ -660,15 +666,13 @@ impl User {
|
|
|
censor.learn_bridge(&fingerprint);
|
|
|
// Censor doesn't want new_cred. User doesn't actually use
|
|
|
// secondary_cred, so don't store it.
|
|
|
- } else {
|
|
|
- eprintln!("Censor failed to get new credential");
|
|
|
}
|
|
|
|
|
|
// Censor user invites as many censor friends as possible
|
|
|
let invitations = scalar_u32(&self.primary_cred.invites_remaining).unwrap();
|
|
|
let mut new_friends = Vec::<User>::new();
|
|
|
for _ in 0..invitations {
|
|
|
- match self.invite(&config, censor, true).await {
|
|
|
+ match self.invite(&config, bridges, censor, true).await {
|
|
|
Ok(friend) => {
|
|
|
new_friends.push(friend);
|
|
|
}
|