diff --git a/src/config.rs b/src/config.rs index 86287a5e16e6bc1403d372bdb82b5fade0c4e802..9320830f9d933801b383f04b4782afd10c7071fd 100644 --- a/src/config.rs +++ b/src/config.rs @@ -7,6 +7,8 @@ use std::fs; lazy_static! { static ref CONFIG_FILE: String = fs::read_to_string("config.yml").unwrap(); pub static ref CONFIG: UccbotConfig = serde_yaml::from_str(&CONFIG_FILE).unwrap(); + static ref SECRETS_FILE: String = fs::read_to_string("secrets.yml").unwrap(); + pub static ref SECRETS: UccbotSecrets = serde_yaml::from_str(&SECRETS_FILE).unwrap(); } #[derive(Debug, Deserialize)] @@ -32,7 +34,12 @@ pub struct UccbotConfig { pub react_role_messages: Vec<ReactionMapping>, #[serde(default = "ldap_bind_address")] pub bind_address: String, +} + +#[derive(Debug, Deserialize)] +pub struct UccbotSecrets { pub ldap_pass: String, + pub discord_token: String, } pub fn ldap_bind_address() -> String { diff --git a/src/ldap.rs b/src/ldap.rs index bf9aa123d44d788ba7b5883d43ed9cbac72fa296..1346ffc24bbaec0cff6dd7ede550cbf4cc1006ae 100644 --- a/src/ldap.rs +++ b/src/ldap.rs @@ -1,5 +1,5 @@ +use crate::config::{CONFIG, SECRETS}; use ldap3::{LdapConn, LdapConnSettings, Scope, SearchEntry}; -use crate::config::CONFIG; #[derive(Debug)] pub struct LDAPUser { @@ -10,11 +10,11 @@ pub struct LDAPUser { pub fn ldap_search(username: &str) -> Option<LDAPUser> { let settings = LdapConnSettings::new().set_no_tls_verify(true); - let ldap = LdapConn::with_settings(settings, &CONFIG.bind_address) - .expect("Unable to connect to LDAP"); + let ldap = + LdapConn::with_settings(settings, &CONFIG.bind_address).expect("Unable to connect to LDAP"); ldap.simple_bind( "cn=ucc-discord-bot,cn=Users,dc=ad,dc=ucc,dc=gu,dc=uwa,dc=edu,dc=au", - &CONFIG.ldap_pass, + &SECRETS.ldap_pass, ) .expect("Unable to attempt to bind to LDAP") .success() @@ -29,7 +29,7 @@ pub fn ldap_search(username: &str) -> Option<LDAPUser> { .expect("LDAP error") .success() .expect("LDAP search error"); - if rs.len() != 1 { + if rs.is_empty() { return None; } let result = SearchEntry::construct(rs[0].clone()).attrs; @@ -50,10 +50,7 @@ pub fn ldap_search(username: &str) -> Option<LDAPUser> { } pub fn ldap_exists(username: &str) -> bool { - match ldap_search(username) { - Some(_) => true, - None => false, - } + ldap_search(username).is_some() } #[derive(Debug)] diff --git a/src/main.rs b/src/main.rs index 439e38e279472f7771f7a6637c45dd734207ebc0..2486c3e798119ae609a16c4845963ca1316a43ba 100644 --- a/src/main.rs +++ b/src/main.rs @@ -13,7 +13,7 @@ extern crate diesel; extern crate ldap3; use simplelog::*; -use std::fs::{read_to_string, File}; +use std::fs::File; use chrono::prelude::Utc; use serenity::{ @@ -32,7 +32,7 @@ mod token_management; mod user_management; mod voting; -use config::CONFIG; +use config::{CONFIG, SECRETS}; use reaction_roles::{add_role_by_reaction, remove_role_by_reaction}; use util::get_string_from_react; @@ -135,7 +135,7 @@ impl EventHandler for Handler { _ if message.author.id.0 != CONFIG.bot_id || add_reaction.user_id == CONFIG.bot_id => { - return; + return } MessageType::Motion => voting::reaction_add(ctx, add_reaction), MessageType::LogReact => { @@ -177,7 +177,7 @@ impl EventHandler for Handler { _ if message.author.id.0 != CONFIG.bot_id || removed_reaction.user_id == CONFIG.bot_id => { - return; + return } MessageType::Motion => voting::reaction_remove(ctx, removed_reaction), _ => {} @@ -222,13 +222,10 @@ fn main() { ]) .unwrap(); - // Configure the client with your Discord bot token in the environment. - let token = read_to_string("discord_token").unwrap(); - // Create a new instance of the Client, logging in as a bot. This will // automatically prepend your bot token with "Bot ", which is a requirement // by Discord for bot users. - let mut client = Client::new(&token, Handler).expect("Err creating client"); + let mut client = Client::new(&SECRETS.discord_token, Handler).expect("Err creating client"); // Finally, start a single shard, and start listening to events. // diff --git a/src/token_management.rs b/src/token_management.rs index d32a067c08e90d47161acc3c24947a9005467e7f..ff11f94b0c6889137862ac3cbd7f8d651073b4e2 100644 --- a/src/token_management.rs +++ b/src/token_management.rs @@ -5,6 +5,8 @@ use rand::Rng; use serenity::model::user::User; use std::str; +pub static TOKEN_LIFETIME: i64 = 300; // 5 minutes + lazy_static! { static ref KEY: [u8; 32] = rand::thread_rng().gen::<[u8; 32]>(); static ref CIPHER: Cipher = Cipher::aes_256_cbc(); @@ -76,7 +78,7 @@ pub fn parse_token(discord_user: &User, encrypted_token: &str) -> Result<String, return Err(TokenError::DiscordIdMismatch); } let time_delta_seconds = Utc::now().timestamp() - token_timestamp.timestamp(); - if time_delta_seconds > 5 * 60 { + if time_delta_seconds > TOKEN_LIFETIME { warn!( "... attempt failed : token expired ({} seconds old)", time_delta_seconds diff --git a/src/user_management.rs b/src/user_management.rs index 2bb4019262923db9b3bd7e326838ac17761bb29e..7b5bddffd6f9b52aa6e81090136c256837cb4fc1 100644 --- a/src/user_management.rs +++ b/src/user_management.rs @@ -34,7 +34,7 @@ pub fn new_member(ctx: &Context, mut new_member: Member) { if let Err(why) = new_member.add_role(&ctx.http, CONFIG.unregistered_member_role) { error!("Error adding user role: {:?}", why); - }; + } } fn member_nickname(member: &database::Member) -> String { @@ -400,13 +400,14 @@ impl Commands { Commands::set_info(ctx, msg, ""); return; } - let clear_property = match field { + match field { "bio" => database::set_member_bio(&msg.author.id.0, None), "git" => database::set_member_git(&msg.author.id.0, None), "photo" => database::set_member_photo(&msg.author.id.0, None), "web" => database::set_member_website(&msg.author.id.0, None), "study" => database::set_member_study(&msg.author.id.0, None), _ => Err(diesel::result::Error::NotFound), - }; + } + .expect("Unable to clear profile field"); } } diff --git a/src/voting.rs b/src/voting.rs index bbb5c7daa53975674a364b9b1787eef9a78aac3c..6d679612eed4150e7542545066464c614c6fc5d4 100644 --- a/src/voting.rs +++ b/src/voting.rs @@ -198,6 +198,19 @@ fn set_cached_motion(id: serenity::model::id::MessageId, motion_info: MotionInfo warn!("{}", "Couldn't find motion in cache to set"); } +macro_rules! tiebreaker { + ($ctx: expr, $vote: expr, $motion_info: expr) => { + if $motion_info.votes.get($vote).unwrap().iter().any(|u| { + u.has_role($ctx, CONFIG.server_id, CONFIG.tiebreaker_role) + .unwrap() + }) { + 0.25 + } else { + 0.0 + } + }; +} + fn update_motion( ctx: &Context, msg: &mut Message, @@ -211,31 +224,11 @@ fn update_motion( let against_votes = motion_info.votes.get(&CONFIG.against_vote).unwrap().len() as isize - 1; let abstain_votes = motion_info.votes.get(&CONFIG.abstain_vote).unwrap().len() as isize - 1; - let has_tiebreaker = |users: &Vec<serenity::model::user::User>| { - users.iter().any(|u| { - u.has_role(ctx, CONFIG.server_id, CONFIG.tiebreaker_role) - .unwrap() - }) - }; - - let for_strength = for_votes as f32 - + (if has_tiebreaker(motion_info.votes.get(&CONFIG.for_vote).unwrap()) { - 0.25 - } else { - 0.0 - }); - let against_strength = against_votes as f32 - + (if has_tiebreaker(motion_info.votes.get(&CONFIG.against_vote).unwrap()) { - 0.25 - } else { - 0.0 - }); - let abstain_strength = abstain_votes as f32 - + (if has_tiebreaker(motion_info.votes.get(&CONFIG.abstain_vote).unwrap()) { - 0.25 - } else { - 0.0 - }); + let for_strength = for_votes as f32 + tiebreaker!(ctx, &CONFIG.for_vote, motion_info); + let against_strength = + against_votes as f32 + tiebreaker!(ctx, &CONFIG.against_vote, motion_info); + let abstain_strength = + abstain_votes as f32 + tiebreaker!(ctx, &CONFIG.abstain_vote, motion_info); let old_embed = msg.embeds[0].clone(); let topic = old_embed.clone().title.unwrap();