Merge pull request 'allowList + break off behaviours to own file' (#4) from allowList into main

Reviewed-on: #4
Reviewed-by: Sarah Jamie Lewis <sarah@openprivacy.ca>
This commit is contained in:
Sarah Jamie Lewis 2022-05-02 22:12:12 +00:00
commit 4327bfe839
4 changed files with 159 additions and 105 deletions

View File

@ -6,6 +6,6 @@ edition = "2021"
# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html
[dependencies]
libcwtch = "0.3.0"
libcwtch = "0.3.2"
serde_json = "1.0"
chrono = "0.4.19"

109
src/behaviour.rs Normal file
View File

@ -0,0 +1,109 @@
/// defines a locked list of allowed peers and groups the bot may communicate with
/// others will be blocked, and peers listed here will be peered with actively
pub struct AllowListMembers {
/// list of peers to allow by handle
pub peers: Vec<String>,
/// list of groups to join and listen for peers in peer list from
pub groups: Vec<String>,
}
impl AllowListMembers {
/// constructs a new AllowListMembers struct
pub fn new(peers: Vec<String>, groups: Vec<String>) -> Self {
AllowListMembers {peers: peers, groups: groups}
}
}
/// How new contacts should be treated
pub enum NewContactPolicy {
/// Do not react, leave it for the custom event handler
Ignore,
/// Block all new contacts
Block,
/// Accept all new contacts
Accept,
/// AllowList is a list of handles that connections will be allowed from and connected to, and will be accepted
/// everything else will be ignored
AllowList(AllowListMembers)
}
/// Settings for the bot on how it should automatically behave
pub struct Behaviour {
/// The bot will enable experimental feautres (required for any experiments to be used)
pub proto_experiments: bool,
/// The bot will enable the file sharing experiment
pub proto_experiment_fileshare: bool,
/// The bot will enable the groups experiment
pub proto_experiment_groups: bool,
/// The profile name the bot will share with accepted conversations
pub profile_name: String,
/// The profile pic the bot with share with accepted conversations IF the file share exoeriment is enabled
pub profile_pic_path: Option<String>,
/// Policy dictacting how the bot should automatically handle ContactCreated events
pub new_contant_policy: NewContactPolicy,
}
/// intermediary struct for building a Behaviour using builder patern
pub struct BehaviourBuilder {
behaviour: Behaviour,
}
impl BehaviourBuilder {
/// Returns a new empty default off for features behaviour builder
pub fn new() -> Self {
return BehaviourBuilder {
behaviour: Behaviour {
proto_experiments: false,
proto_experiment_fileshare: false,
proto_experiment_groups: false,
new_contant_policy: NewContactPolicy::Ignore,
profile_name: "".to_string(),
profile_pic_path: None,
},
};
}
/// Build the defined behaviours into a Behaviour struct
pub fn build(self) -> Behaviour {
self.behaviour
}
/// Control if the Behaviour of the bot should include groups (enabling experiments and the group experiment)
pub fn groups(mut self, val: bool) -> Self {
self.behaviour.proto_experiment_groups = val;
self.behaviour.proto_experiments = true;
self
}
/// Control if the Behaviour of the bot should include filesharing (enabling experiments and the filesharing experiment)
pub fn fileshare(mut self, val: bool) -> Self {
self.behaviour.proto_experiment_fileshare = val;
self.behaviour.proto_experiments = true;
self
}
/// Set a profile pic for the bot and enable the filesharing experiment
pub fn profile_pic_path(mut self, val: String) -> Self {
self.behaviour.profile_pic_path = Some(val);
self.behaviour.proto_experiment_fileshare = true;
self.behaviour.proto_experiments = true;
self
}
/// Set a name for the behaviour
pub fn name(mut self, val: String) -> Self {
self.behaviour.profile_name = val;
self
}
/// Set a new contact policy for the behaviour
pub fn new_contact_policy(mut self, val: NewContactPolicy) -> Self {
self.behaviour.new_contant_policy = val;
self
}
}

View File

@ -3,98 +3,18 @@ use libcwtch::structs::*;
use libcwtch::CwtchLib;
use serde_json;
/// How new contacts should be treated
pub enum NewContactPolicy {
/// Do not react, leave it for the custom event handler
Ignore,
/// Block all new contacts
Block,
/// Accept all new contacts
Accept,
}
/// Settings for the bot on how it should automatically behave
pub struct Behaviour {
/// The bot will enable experimental feautres (required for any experiments to be used)
pub proto_experiments: bool,
/// The bot will enable the file sharing experiment
pub proto_experiment_fileshare: bool,
/// The bot will enable the groups experiment
pub proto_experiment_groups: bool,
/// The profile name the bot will share with accepted conversations
pub profile_name: String,
/// The profile pic the bot with share with accepted conversations IF the file share exoeriment is enabled
pub profile_pic_path: Option<String>,
/// Policy dictacting how the bot should automatically handle ContactCreated events
pub new_contant_policy: NewContactPolicy,
}
pub struct BehaviourBuilder {
behaviour: Behaviour,
}
impl BehaviourBuilder {
pub fn new() -> Self {
return BehaviourBuilder {
behaviour: Behaviour {
proto_experiments: false,
proto_experiment_fileshare: false,
proto_experiment_groups: false,
new_contant_policy: NewContactPolicy::Ignore,
profile_name: "".to_string(),
profile_pic_path: None,
},
};
}
pub fn build(self) -> Behaviour {
self.behaviour
}
pub fn groups(mut self, val: bool) -> Self {
self.behaviour.proto_experiment_groups = val;
self.behaviour.proto_experiments = true;
self
}
pub fn fileshare(mut self, val: bool) -> Self {
self.behaviour.proto_experiment_fileshare = val;
self.behaviour.proto_experiments = true;
self
}
pub fn profile_pic_path(mut self, val: String) -> Self {
self.behaviour.profile_pic_path = Some(val);
self.behaviour.proto_experiment_fileshare = true;
self.behaviour.proto_experiments = true;
self
}
pub fn name(mut self, val: String) -> Self {
self.behaviour.profile_name = val;
self
}
pub fn new_contact_policy(mut self, val: NewContactPolicy) -> Self {
self.behaviour.new_contant_policy = val;
self
}
}
use crate::behaviour::{Behaviour, NewContactPolicy};
use crate::behaviour::NewContactPolicy::AllowList;
/// Trait to be used by implementors of imp bots to supply their custom event handling
/// the handle function is called after the default imp automatic event handling has run on each new event
pub trait EventHandler {
fn handle(&mut self, cwtch: &dyn CwtchLib, profile: Option<&Profile>, event: Event);
fn handle(&mut self, cwtch: &dyn libcwtch::CwtchLib, profile: Option<&Profile>, event: Event);
}
/// Cwtch bot
pub struct Imp {
cwtch: Box<dyn CwtchLib>,
cwtch: Box<dyn libcwtch::CwtchLib>,
behaviour: Behaviour,
password: String,
home_dir: String,
@ -213,22 +133,22 @@ impl Imp {
);
for (_id, conversation) in &profile.conversations {
match self.behaviour.new_contant_policy {
NewContactPolicy::Accept => {
self.cwtch
.accept_conversation(&profile.handle.clone(), conversation.identifier);
self.process_contact(conversation.identifier);
}
// Allow list should add all people in the list
if let AllowList(allow_list) = &self.behaviour.new_contant_policy {
for handle in &allow_list.peers {
if let None = profile.find_conversation_id_by_handle(handle.clone()) {
self.cwtch.import_bundle(&profile.handle.clone(), &handle.clone());
}
NewContactPolicy::Block => self
.cwtch
.block_contact(&profile.handle.clone(), conversation.identifier),
NewContactPolicy::Ignore => (),
}
}
self.profile = Some(profile);
}
Event::AppError { data } => {
if initialized && data["Error"] == "Loaded 0 profiles" {
if initialized && data.contains_key("Error") && data["Error"] == "Loaded 0 profiles" {
self.cwtch
.create_profile(&self.behaviour.profile_name, &self.password);
}
@ -236,7 +156,6 @@ impl Imp {
Event::ContactCreated { data } => {
println!("Contact Created");
let convo_handle = data["RemotePeer"].to_string();
let convo_id = data["ConversationID"].parse::<i32>().unwrap();
let acl: ACL = serde_json::from_str(&data["accessControlList"]).expect("Error parsing conversation");
@ -251,20 +170,13 @@ impl Imp {
is_group: false, // by definition
};
self.process_contact(conversation.identifier);
match self.profile.as_mut() {
Some(profile) => {
profile
.conversations
.insert(data["RemotePeer"].to_string(), conversation);
match self.behaviour.new_contant_policy {
NewContactPolicy::Accept => {
self.cwtch
.accept_conversation(&profile.handle.clone(), convo_id);
}
NewContactPolicy::Block => self.cwtch.block_contact(&profile.handle.clone(), convo_id),
NewContactPolicy::Ignore => (),
}
.insert(conversation.identifier, conversation);
}
None => (),
};
@ -277,4 +189,36 @@ impl Imp {
handler.handle(self.cwtch.as_ref(), self.profile.as_ref(), event);
}
}
fn process_contact(&self, conversation_id: i32) {
match &self.profile {
Some(profile) => {
let profile_handle = profile.handle.clone();
match &self.behaviour.new_contant_policy {
NewContactPolicy::Accept => {
self.cwtch
.accept_conversation(&profile_handle.clone(), conversation_id);
}
NewContactPolicy::Block => self.cwtch.block_contact(&profile_handle.clone(), conversation_id),
NewContactPolicy::AllowList(allow_list) => {
match profile.conversations.get(&conversation_id) {
Some(conversation) => {
if allow_list.peers.contains(&conversation.handle) {
self.cwtch
.accept_conversation(&profile_handle.clone(), conversation_id);
} else {
self.cwtch.block_contact(&profile_handle.clone(), conversation_id);
}
},
None => {},
}
}
NewContactPolicy::Ignore => (),
}
},
None => {},
}
}
}

View File

@ -1,2 +1,3 @@
pub mod event;
pub mod imp;
pub mod behaviour;