diff --git a/Cargo.toml b/Cargo.toml index 8b097e6749d173f1e0002afb4bceb7c523f43e84..41b499493b2c8857e172a423405052aac4cfdbac 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -15,3 +15,4 @@ serde = "^1.0.104" serde_yaml = "^0.8" serenity = "0.8.0" simplelog = "^0.7.4" +guard = "0.5.0" diff --git a/src/main.rs b/src/main.rs index 0323fa39f4096276fde975b74e2b21eb3ed30f66..cb27c05b4619b8334ea5d8bfb41bf0c62586979a 100644 --- a/src/main.rs +++ b/src/main.rs @@ -4,6 +4,7 @@ extern crate lazy_static; #[macro_use] extern crate log; extern crate simplelog; +#[macro_use] extern crate guard; use simplelog::*; use std::fs::{read_to_string, File}; diff --git a/src/token_management.rs b/src/token_management.rs index 84c357d51e36399e85cdd4f33550e7ae2ff3857f..d32a067c08e90d47161acc3c24947a9005467e7f 100644 --- a/src/token_management.rs +++ b/src/token_management.rs @@ -18,20 +18,19 @@ fn text_encrypt(plaintext: &str) -> String { } fn text_decrypt(ciphertext: &str) -> Option<String> { let iv: &[u8; 16] = &[0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]; - if let Ok(cipher_vec) = base64::decode(ciphertext) { - if let Ok(decrypted_vec) = decrypt(*CIPHER, &*KEY, Some(iv), &cipher_vec) { - if let Ok(decrypted_token) = str::from_utf8(decrypted_vec.as_slice()) { - return Some(decrypted_token.to_owned()); - } else { - warn!("Invalid utf8 in text"); - } - } else { - warn!("Text decryption failed"); - } - } else { + guard!(let Ok(cipher_vec) = base64::decode(ciphertext) else { warn!("Unable to decode base64 text"); - } - None + return None + }); + guard!(let Ok(decrypted_vec) = decrypt(*CIPHER, &*KEY, Some(iv), &cipher_vec) else { + warn!("Text decryption failed"); + return None + }); + guard!(let Ok(decrypted_token) = str::from_utf8(decrypted_vec.as_slice()) else { + warn!("Invalid utf8 in text"); + return None + }); + Some(decrypted_token.to_owned()) } pub fn generate_token(discord_user: &User, username: &str) -> String { @@ -60,34 +59,33 @@ impl std::fmt::Display for TokenError { } pub fn parse_token(discord_user: &User, encrypted_token: &str) -> Result<String, TokenError> { - if let Some(token) = text_decrypt(encrypted_token) { - let token_components: Vec<_> = token.splitn(3, ',').collect(); - info!( - "Verification attempt from '{}'(uid: {}) for account '{}' with token from {}", - discord_user.name, token_components[1], token_components[2], token_components[0] - ); - let token_timestamp = - DateTime::parse_from_rfc3339(token_components[0]).expect("Invalid date format"); - let token_discord_user = token_components[1]; - let token_username = token_components[2]; - if token_discord_user != discord_user.id.0.to_string() { - warn!("... attempt failed : DiscordID mismatch"); - return Err(TokenError::DiscordIdMismatch); - } - let time_delta_seconds = Utc::now().timestamp() - token_timestamp.timestamp(); - if time_delta_seconds > 5 * 60 { - warn!( - "... attempt failed : token expired ({} seconds old)", - time_delta_seconds - ); - return Err(TokenError::TokenExpired); - } - info!( - "... verification successful (token {} seconds old)", + guard!(let Some(token) = text_decrypt(encrypted_token) else { + return Err(TokenError::TokenInvalid) + }); + let token_components: Vec<_> = token.splitn(3, ',').collect(); + info!( + "Verification attempt from '{}'(uid: {}) for account '{}' with token from {}", + discord_user.name, token_components[1], token_components[2], token_components[0] + ); + let token_timestamp = + DateTime::parse_from_rfc3339(token_components[0]).expect("Invalid date format"); + let token_discord_user = token_components[1]; + let token_username = token_components[2]; + if token_discord_user != discord_user.id.0.to_string() { + warn!("... attempt failed : DiscordID mismatch"); + return Err(TokenError::DiscordIdMismatch); + } + let time_delta_seconds = Utc::now().timestamp() - token_timestamp.timestamp(); + if time_delta_seconds > 5 * 60 { + warn!( + "... attempt failed : token expired ({} seconds old)", time_delta_seconds ); - Ok(token_username.to_owned()) - } else { - Err(TokenError::TokenInvalid) + return Err(TokenError::TokenExpired); } + info!( + "... verification successful (token {} seconds old)", + time_delta_seconds + ); + Ok(token_username.to_owned()) } diff --git a/src/voting.rs b/src/voting.rs index b08d8a7112a76628e1fba9357207ab5d236b9902..ebb3e592a3662e0e5e556b8e69e6c1ca3e467b06 100644 --- a/src/voting.rs +++ b/src/voting.rs @@ -349,63 +349,64 @@ pub fn reaction_add(ctx: Context, add_reaction: channel::Reaction) { let react_as_string = get_string_from_react(&add_reaction.emoji); match add_reaction.message(&ctx.http) { Ok(mut message) => { - if let Ok(user) = add_reaction.user(&ctx) { - match user.has_role(&ctx, CONFIG.server_id, CONFIG.vote_role) { - Ok(true) => { - // remove vote if already voted - for react in [ - CONFIG.for_vote.to_string(), - CONFIG.against_vote.to_string(), - CONFIG.abstain_vote.to_string(), - ] - .iter() - .filter(|r| r != &&react_as_string) + guard!(let Ok(user) = add_reaction.user(&ctx) else { + return + }); + match user.has_role(&ctx, CONFIG.server_id, CONFIG.vote_role) { + Ok(true) => { + // remove vote if already voted + for react in [ + CONFIG.for_vote.to_string(), + CONFIG.against_vote.to_string(), + CONFIG.abstain_vote.to_string(), + ] + .iter() + .filter(|r| r != &&react_as_string) + { + for a_user in message + .reaction_users(&ctx, react.as_str(), None, None) + .unwrap() { - for a_user in message - .reaction_users(&ctx, react.as_str(), None, None) - .unwrap() - { - if a_user.id.0 == user.id.0 { - if let Err(why) = add_reaction.delete(&ctx) { - error!("Error deleting react: {:?}", why); - }; - return; - } + if a_user.id.0 == user.id.0 { + if let Err(why) = add_reaction.delete(&ctx) { + error!("Error deleting react: {:?}", why); + }; + return; } } - // remove 'illegal' reacts - if !CONFIG.allowed_reacts().contains(&react_as_string) { - if let Err(why) = add_reaction.delete(&ctx) { - error!("Error deleting react: {:?}", why); - }; - return; - } - // update motion - let mut motion_info = get_cached_motion(&ctx, &message); - if let Some(vote) = motion_info.votes.get_mut(&react_as_string) { - vote.retain(|u| u.id != user.id); - vote.push(user.clone()); - } - set_cached_motion(message.id, motion_info); - update_motion(&ctx, &mut message, &user, "add", add_reaction); } - Ok(false) => { - if ![ - CONFIG.approve_react.to_string(), - CONFIG.disapprove_react.to_string(), - ] - .contains(&react_as_string) - { - if let Err(why) = add_reaction.delete(&ctx) { - error!("Error deleting react: {:?}", why); - }; - return; - } + // remove 'illegal' reacts + if !CONFIG.allowed_reacts().contains(&react_as_string) { + if let Err(why) = add_reaction.delete(&ctx) { + error!("Error deleting react: {:?}", why); + }; + return; + } + // update motion + let mut motion_info = get_cached_motion(&ctx, &message); + if let Some(vote) = motion_info.votes.get_mut(&react_as_string) { + vote.retain(|u| u.id != user.id); + vote.push(user.clone()); } - Err(why) => { - error!("Error getting user role: {:?}", why); + set_cached_motion(message.id, motion_info); + update_motion(&ctx, &mut message, &user, "add", add_reaction); + } + Ok(false) => { + if ![ + CONFIG.approve_react.to_string(), + CONFIG.disapprove_react.to_string(), + ] + .contains(&react_as_string) + { + if let Err(why) = add_reaction.delete(&ctx) { + error!("Error deleting react: {:?}", why); + }; + return; } } + Err(why) => { + error!("Error getting user role: {:?}", why); + } } } Err(why) => {