From 51e52b6c878d5907fc1680ec12a6f97467941b7a Mon Sep 17 00:00:00 2001 From: Nell Shamrell Date: Tue, 7 Apr 2020 15:05:00 -0700 Subject: [PATCH 01/18] Sets up skeleton work for new command Signed-off-by: Nell Shamrell refactors parse_config_value_set into a more central place Signed-off-by: Nell Shamrell --- src/commands/heroku.rs | 27 ++++++++++++++++++++++++++- src/config.rs | 30 ++---------------------------- src/lib.rs | 5 ++++- src/utilities.rs | 28 ++++++++++++++++++++++++++++ 4 files changed, 60 insertions(+), 30 deletions(-) create mode 100644 src/utilities.rs diff --git a/src/commands/heroku.rs b/src/commands/heroku.rs index 26ce77b..a87b63c 100644 --- a/src/commands/heroku.rs +++ b/src/commands/heroku.rs @@ -58,7 +58,7 @@ pub fn get_app(ctx: &mut Context, msg: &Message, mut args: Args) -> CommandResul // Config variables that can be updated through Discord // Set only as "FOO" until we fill this in with the real config vars // for our Heroku account that we want to allow to be updated -const AUTHORIZED_CONFIG_VARS: &[&str] = &["FOO"]; +const AUTHORIZED_CONFIG_VARS: &[&str] = &["BLOCKED_IPS"]; // Get app by name or id #[command] @@ -110,6 +110,31 @@ pub fn update_app_config(ctx: &mut Context, msg: &Message, mut args: Args) -> Co Ok(()) } +#[command] +#[num_args(2)] +pub fn block_ip(ctx: &mut Context, msg: &Message, mut args: Args) -> CommandResult { + let app_name = args + .single::() + .expect("You must include an app name"); + + let ip_addr = args + .single::() + .expect("You must include an IP address to block"); + + let config_var_list = heroku_client(ctx).request(&config_vars::AppConfigVarDetails { app_id: &app_name }).unwrap(); + println!("config_var_list {:?}", config_var_list); + + let mut blocked_ips = config_var_list.get(&"BLOCKED_IPS".to_string()).unwrap().as_ref().unwrap().to_string(); + println!("blocked_ips prior to update {:?}", blocked_ips); + + let to_block_ip = format!(",{}", ip_addr); + + blocked_ips.push_str(&to_block_ip); + + println!("blocked_ips after update {:?}", blocked_ips); + Ok(()) +} + #[command] #[num_args(4)] pub fn scale_app(ctx: &mut Context, msg: &Message, mut args: Args) -> CommandResult { diff --git a/src/config.rs b/src/config.rs index c59c815..a71e9ee 100644 --- a/src/config.rs +++ b/src/config.rs @@ -1,6 +1,7 @@ use serenity::prelude::TypeMapKey; use std::collections::HashSet; use std::sync::Arc; +use crate::utilities::*; #[derive(Debug, Clone)] pub struct Config { @@ -21,31 +22,4 @@ impl Config { impl TypeMapKey for Config { type Value = Arc; -} - -fn parse_config_value_set(config_value: String) -> HashSet { - let mut value_set = HashSet::new(); - - let split_string = config_value.split(','); - - for string in split_string { - value_set.insert(String::from(string)); - } - - value_set -} - -#[cfg(test)] -mod tests { - use super::*; - - #[test] - fn create_authorized_users_hashset() { - let test_string = String::from("123,456,789"); - let users_set = parse_config_value_set(test_string); - - assert!(users_set.contains("123")); - assert!(users_set.contains("456")); - assert!(users_set.contains("789")); - } -} +} \ No newline at end of file diff --git a/src/lib.rs b/src/lib.rs index 1bb92ff..ed3c5c4 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -15,6 +15,8 @@ mod authorizations; pub mod config; +pub mod utilities; + use crate::config::Config; use crate::authorizations::users::*; @@ -30,7 +32,8 @@ use crate::authorizations::users::*; scale_app, update_app_config, get_app_releases, - rollback_app + rollback_app, + block_ip )] struct General; diff --git a/src/utilities.rs b/src/utilities.rs new file mode 100644 index 0000000..d82a0e3 --- /dev/null +++ b/src/utilities.rs @@ -0,0 +1,28 @@ +use std::collections::HashSet; + +pub fn parse_config_value_set(config_value: String) -> HashSet { + let mut value_set = HashSet::new(); + + let split_string = config_value.split(','); + + for string in split_string { + value_set.insert(String::from(string)); + } + + value_set +} + +#[cfg(test)] +mod tests { + use super::*; + + #[test] + fn create_authorized_users_hashset() { + let test_string = String::from("123,456,789"); + let users_set = parse_config_value_set(test_string); + + assert!(users_set.contains("123")); + assert!(users_set.contains("456")); + assert!(users_set.contains("789")); + } +} From a70071ec5670e8a65e76dd72e7b86ba57af9d695 Mon Sep 17 00:00:00 2001 From: Nell Shamrell Date: Tue, 7 Apr 2020 15:38:47 -0700 Subject: [PATCH 02/18] returns notice if the ip address has already been blocked Signed-off-by: Nell Shamrell wip Signed-off-by: Nell Shamrell --- src/commands/heroku.rs | 23 ++++++++++++++--------- src/utilities.rs | 15 +++++++++++++++ 2 files changed, 29 insertions(+), 9 deletions(-) diff --git a/src/commands/heroku.rs b/src/commands/heroku.rs index a87b63c..42e0810 100644 --- a/src/commands/heroku.rs +++ b/src/commands/heroku.rs @@ -9,6 +9,9 @@ use serenity::model::prelude::*; use serenity::prelude::*; use std::collections::HashMap; +use std::collections::HashSet; + +use crate::utilities::*; #[derive(Debug, Deserialize)] struct HerokuApp { @@ -55,9 +58,7 @@ pub fn get_app(ctx: &mut Context, msg: &Message, mut args: Args) -> CommandResul Ok(()) } -// Config variables that can be updated through Discord -// Set only as "FOO" until we fill this in with the real config vars -// for our Heroku account that we want to allow to be updated +// App config variables that can be updated through Discord const AUTHORIZED_CONFIG_VARS: &[&str] = &["BLOCKED_IPS"]; // Get app by name or id @@ -122,16 +123,20 @@ pub fn block_ip(ctx: &mut Context, msg: &Message, mut args: Args) -> CommandResu .expect("You must include an IP address to block"); let config_var_list = heroku_client(ctx).request(&config_vars::AppConfigVarDetails { app_id: &app_name }).unwrap(); - println!("config_var_list {:?}", config_var_list); - let mut blocked_ips = config_var_list.get(&"BLOCKED_IPS".to_string()).unwrap().as_ref().unwrap().to_string(); - println!("blocked_ips prior to update {:?}", blocked_ips); + let blocked_ips = config_var_list.get(&"BLOCKED_IPS".to_string()).unwrap().as_ref().unwrap().to_string(); - let to_block_ip = format!(",{}", ip_addr); + let mut blocked_ips_set = parse_config_value_set(blocked_ips); - blocked_ips.push_str(&to_block_ip); + if blocked_ips_set.contains(&ip_addr) { + msg.reply( + &ctx, + format!("That IP address is already blocked for {}", app_name), + )?; + } else { + blocked_ips_set.insert(ip_addr); + }; - println!("blocked_ips after update {:?}", blocked_ips); Ok(()) } diff --git a/src/utilities.rs b/src/utilities.rs index d82a0e3..72a0857 100644 --- a/src/utilities.rs +++ b/src/utilities.rs @@ -12,6 +12,10 @@ pub fn parse_config_value_set(config_value: String) -> HashSet { value_set } +pub fn parse_config_value_string(config_value: HashSet) -> String { + String::from("wheee"); +} + #[cfg(test)] mod tests { use super::*; @@ -25,4 +29,15 @@ mod tests { assert!(users_set.contains("456")); assert!(users_set.contains("789")); } + + #[test] + fn create_authorized_users_string() { + let users_hash_set = HashSet::new(); + users_hash_set.insert("123".to_string()); + users_hash_set.insert("456".to_string()); + users_hash_set.insert("789".to_string()); + + let users_string = parse_config_value_string(users_hash_set); + assert_eq!(users_string, "123,456,789"); + } } From 1eff9c7c8f72e6def3c8c96d208001417e71c683 Mon Sep 17 00:00:00 2001 From: Nell Shamrell Date: Wed, 8 Apr 2020 10:23:35 -0700 Subject: [PATCH 03/18] adds ability to parse a hashset into a string Signed-off-by: Nell Shamrell --- src/utilities.rs | 14 ++++++++++++-- 1 file changed, 12 insertions(+), 2 deletions(-) diff --git a/src/utilities.rs b/src/utilities.rs index 72a0857..fb28e3d 100644 --- a/src/utilities.rs +++ b/src/utilities.rs @@ -13,7 +13,17 @@ pub fn parse_config_value_set(config_value: String) -> HashSet { } pub fn parse_config_value_string(config_value: HashSet) -> String { - String::from("wheee"); + let mut combined_string = String::new(); + + for item in config_value.iter() { + let item_string = format!("{},", item); + combined_string.push_str(&item_string); + } + + // Remove last comma + combined_string.pop(); + + combined_string } #[cfg(test)] @@ -32,7 +42,7 @@ mod tests { #[test] fn create_authorized_users_string() { - let users_hash_set = HashSet::new(); + let mut users_hash_set = HashSet::new(); users_hash_set.insert("123".to_string()); users_hash_set.insert("456".to_string()); users_hash_set.insert("789".to_string()); From 220b1425d3f09b08d2fe4df111573f8a9fd17a34 Mon Sep 17 00:00:00 2001 From: Nell Shamrell Date: Wed, 8 Apr 2020 10:33:49 -0700 Subject: [PATCH 04/18] adds ability to block ip addresses Signed-off-by: Nell Shamrell refactor Signed-off-by: Nell Shamrell more refactoring Signed-off-by: Nell Shamrell --- src/commands/heroku.rs | 48 +++++++++++++++++++++++++++++++++++++----- 1 file changed, 43 insertions(+), 5 deletions(-) diff --git a/src/commands/heroku.rs b/src/commands/heroku.rs index 42e0810..74d14df 100644 --- a/src/commands/heroku.rs +++ b/src/commands/heroku.rs @@ -122,11 +122,9 @@ pub fn block_ip(ctx: &mut Context, msg: &Message, mut args: Args) -> CommandResu .single::() .expect("You must include an IP address to block"); - let config_var_list = heroku_client(ctx).request(&config_vars::AppConfigVarDetails { app_id: &app_name }).unwrap(); - - let blocked_ips = config_var_list.get(&"BLOCKED_IPS".to_string()).unwrap().as_ref().unwrap().to_string(); + let blocked_ips_value = block_ips_value(heroku_app_config_vars(&ctx, &app_name)); - let mut blocked_ips_set = parse_config_value_set(blocked_ips); + let mut blocked_ips_set = parse_config_value_set(blocked_ips_value); if blocked_ips_set.contains(&ip_addr) { msg.reply( @@ -134,7 +132,26 @@ pub fn block_ip(ctx: &mut Context, msg: &Message, mut args: Args) -> CommandResu format!("That IP address is already blocked for {}", app_name), )?; } else { - blocked_ips_set.insert(ip_addr); + blocked_ips_set.insert(ip_addr.clone()); + + let updated_config_var = blocked_ips_config_var(blocked_ips_set); + + let response = heroku_client(ctx).request(&config_vars::AppConfigVarUpdate { + app_id: &app_name, + params: updated_config_var, + }); + + msg.reply( + ctx, + match response { + Ok(_response) => format!("IP address {} has been blocked", ip_addr.clone()), + Err(e) => format!( + "An error occurred when trying to block the IP address: {}\n{}", + ip_addr, + e + ), + }, + )?; }; Ok(()) @@ -352,3 +369,24 @@ fn heroku_client(ctx: &Context) -> std::sync::Arc HashMap> { + let config_var_list = heroku_client(ctx).request(&config_vars::AppConfigVarDetails { app_id: &app_name }).unwrap(); + config_var_list +} + +fn block_ips_value(config_vars: HashMap>) -> String { + config_vars.get(&"BLOCKED_IPS".to_string()).unwrap().as_ref().unwrap().to_string() +} + +fn blocked_ips_config_var(blocked_ips_set: HashSet) -> HashMap { + let blocked_ips_set_string = parse_config_value_string(blocked_ips_set); + let blocked_ips_config_var = config_var(blocked_ips_set_string); + blocked_ips_config_var +} + +fn config_var(updated_blocked_ips_value: String) -> HashMap { + let mut config_var = HashMap::new(); + config_var.insert("BLOCKED_IPS".to_string(), updated_blocked_ips_value); + config_var +} \ No newline at end of file From e583f9278665c183d6d14b4317cdf94241be0390 Mon Sep 17 00:00:00 2001 From: Nell Shamrell Date: Wed, 8 Apr 2020 12:12:02 -0700 Subject: [PATCH 05/18] adds command to unblock an ip address Signed-off-by: Nell Shamrell --- src/commands/heroku.rs | 56 +++++++++++++++++++++++++++++++++++++++--- src/lib.rs | 3 ++- 2 files changed, 54 insertions(+), 5 deletions(-) diff --git a/src/commands/heroku.rs b/src/commands/heroku.rs index 74d14df..035514b 100644 --- a/src/commands/heroku.rs +++ b/src/commands/heroku.rs @@ -122,14 +122,12 @@ pub fn block_ip(ctx: &mut Context, msg: &Message, mut args: Args) -> CommandResu .single::() .expect("You must include an IP address to block"); - let blocked_ips_value = block_ips_value(heroku_app_config_vars(&ctx, &app_name)); - - let mut blocked_ips_set = parse_config_value_set(blocked_ips_value); + let mut blocked_ips_set = current_blocked_ip_addresses(&ctx, &app_name); if blocked_ips_set.contains(&ip_addr) { msg.reply( &ctx, - format!("That IP address is already blocked for {}", app_name), + format!("{} is already blocked for {}", &ip_addr, app_name), )?; } else { blocked_ips_set.insert(ip_addr.clone()); @@ -157,6 +155,49 @@ pub fn block_ip(ctx: &mut Context, msg: &Message, mut args: Args) -> CommandResu Ok(()) } +#[command] +#[num_args(2)] +pub fn unblock_ip(ctx: &mut Context, msg: &Message, mut args: Args) -> CommandResult { + let app_name = args + .single::() + .expect("You must include an app name"); + + let ip_addr = args + .single::() + .expect("You must include an IP address to unblock"); + + let mut blocked_ips_set = current_blocked_ip_addresses(&ctx, &app_name); + + if !blocked_ips_set.contains(&ip_addr) { + msg.reply( + &ctx, + format!("{} is not currently blocked for {}", &ip_addr, app_name), + )?; + } else { + blocked_ips_set.remove(&ip_addr); + let updated_config_var = blocked_ips_config_var(blocked_ips_set); + + let response = heroku_client(ctx).request(&config_vars::AppConfigVarUpdate { + app_id: &app_name, + params: updated_config_var, + }); + + msg.reply( + ctx, + match response { + Ok(_response) => format!("IP address {} has been unblocked", ip_addr.clone()), + Err(e) => format!( + "An error occurred when trying to unblock the IP address: {}\n{}", + ip_addr, + e + ), + }, + )?; + } + + Ok(()) +} + #[command] #[num_args(4)] pub fn scale_app(ctx: &mut Context, msg: &Message, mut args: Args) -> CommandResult { @@ -389,4 +430,11 @@ fn config_var(updated_blocked_ips_value: String) -> HashMap { let mut config_var = HashMap::new(); config_var.insert("BLOCKED_IPS".to_string(), updated_blocked_ips_value); config_var +} + +fn current_blocked_ip_addresses(ctx: &Context, app_name: &str) -> HashSet { + let blocked_ips_value = block_ips_value(heroku_app_config_vars(&ctx, &app_name)); + + let blocked_ips_set = parse_config_value_set(blocked_ips_value); + blocked_ips_set } \ No newline at end of file diff --git a/src/lib.rs b/src/lib.rs index ed3c5c4..dcd540e 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -33,7 +33,8 @@ use crate::authorizations::users::*; update_app_config, get_app_releases, rollback_app, - block_ip + block_ip, + unblock_ip, )] struct General; From c60fd34557f19f905e06c9bc770c6def90a1b63b Mon Sep 17 00:00:00 2001 From: Nell Shamrell Date: Wed, 8 Apr 2020 12:12:43 -0700 Subject: [PATCH 06/18] apply formmatting Signed-off-by: Nell Shamrell wip Signed-off-by: Nell Shamrell Revert "wip" This reverts commit 95a47e6bf2dea959916f2118a6f88a3595f69aec. wip Signed-off-by: Nell Shamrell wip Signed-off-by: Nell Shamrell Revert "wip" This reverts commit 79030729397656039b1b1470f55c38028edecb01. Revert "wip" This reverts commit 5344822ce13524d811a29f1d904d0bc35ad986bb. --- src/commands/heroku.rs | 25 +++++++++++++++---------- src/config.rs | 4 ++-- src/lib.rs | 2 +- 3 files changed, 18 insertions(+), 13 deletions(-) diff --git a/src/commands/heroku.rs b/src/commands/heroku.rs index 035514b..e7eeda6 100644 --- a/src/commands/heroku.rs +++ b/src/commands/heroku.rs @@ -133,7 +133,7 @@ pub fn block_ip(ctx: &mut Context, msg: &Message, mut args: Args) -> CommandResu blocked_ips_set.insert(ip_addr.clone()); let updated_config_var = blocked_ips_config_var(blocked_ips_set); - + let response = heroku_client(ctx).request(&config_vars::AppConfigVarUpdate { app_id: &app_name, params: updated_config_var, @@ -145,8 +145,7 @@ pub fn block_ip(ctx: &mut Context, msg: &Message, mut args: Args) -> CommandResu Ok(_response) => format!("IP address {} has been blocked", ip_addr.clone()), Err(e) => format!( "An error occurred when trying to block the IP address: {}\n{}", - ip_addr, - e + ip_addr, e ), }, )?; @@ -188,8 +187,7 @@ pub fn unblock_ip(ctx: &mut Context, msg: &Message, mut args: Args) -> CommandRe Ok(_response) => format!("IP address {} has been unblocked", ip_addr.clone()), Err(e) => format!( "An error occurred when trying to unblock the IP address: {}\n{}", - ip_addr, - e + ip_addr, e ), }, )?; @@ -197,7 +195,7 @@ pub fn unblock_ip(ctx: &mut Context, msg: &Message, mut args: Args) -> CommandRe Ok(()) } - + #[command] #[num_args(4)] pub fn scale_app(ctx: &mut Context, msg: &Message, mut args: Args) -> CommandResult { @@ -412,15 +410,22 @@ fn heroku_client(ctx: &Context) -> std::sync::Arc HashMap> { - let config_var_list = heroku_client(ctx).request(&config_vars::AppConfigVarDetails { app_id: &app_name }).unwrap(); + let config_var_list = heroku_client(ctx) + .request(&config_vars::AppConfigVarDetails { app_id: &app_name }) + .unwrap(); config_var_list } fn block_ips_value(config_vars: HashMap>) -> String { - config_vars.get(&"BLOCKED_IPS".to_string()).unwrap().as_ref().unwrap().to_string() + config_vars + .get(&"BLOCKED_IPS".to_string()) + .unwrap() + .as_ref() + .unwrap() + .to_string() } -fn blocked_ips_config_var(blocked_ips_set: HashSet) -> HashMap { +fn blocked_ips_config_var(blocked_ips_set: HashSet) -> HashMap { let blocked_ips_set_string = parse_config_value_string(blocked_ips_set); let blocked_ips_config_var = config_var(blocked_ips_set_string); blocked_ips_config_var @@ -437,4 +442,4 @@ fn current_blocked_ip_addresses(ctx: &Context, app_name: &str) -> HashSet; -} \ No newline at end of file +} diff --git a/src/lib.rs b/src/lib.rs index dcd540e..3bff33e 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -34,7 +34,7 @@ use crate::authorizations::users::*; get_app_releases, rollback_app, block_ip, - unblock_ip, + unblock_ip )] struct General; From 62fdc3c3f5cf5133892d1e114e8f886e82b040e3 Mon Sep 17 00:00:00 2001 From: Nell Shamrell Date: Wed, 8 Apr 2020 17:24:32 -0700 Subject: [PATCH 07/18] removes BLOCKED_IPs config variable if there are no more blocked ips Signed-off-by: Nell Shamrell --- src/commands/heroku.rs | 60 +++++++++++++++++++++++++++++++----------- 1 file changed, 44 insertions(+), 16 deletions(-) diff --git a/src/commands/heroku.rs b/src/commands/heroku.rs index e7eeda6..bbb0a02 100644 --- a/src/commands/heroku.rs +++ b/src/commands/heroku.rs @@ -174,23 +174,45 @@ pub fn unblock_ip(ctx: &mut Context, msg: &Message, mut args: Args) -> CommandRe )?; } else { blocked_ips_set.remove(&ip_addr); - let updated_config_var = blocked_ips_config_var(blocked_ips_set); + if blocked_ips_set.is_empty() { + let config_var_to_delete = null_blocked_ips_config_var(); + + let response = heroku_client(ctx).request(&config_vars::AppConfigVarDelete { + app_id: &app_name, + params: config_var_to_delete, + }); + + msg.reply( + ctx, + match response { + Ok(_response) => format!("IP address {} has been unblocked, there are now no unblocked IP addresses", ip_addr.clone()), + Err(e) => format!( + "An error occurred when trying to unblock the IP address: {}\n{}", + ip_addr, e + ), + }, + )?; + + } else { + let updated_config_var = blocked_ips_config_var(blocked_ips_set); + + let response = heroku_client(ctx).request(&config_vars::AppConfigVarUpdate { + app_id: &app_name, + params: updated_config_var, + }); + + msg.reply( + ctx, + match response { + Ok(_response) => format!("IP address {} has been unblocked", ip_addr.clone()), + Err(e) => format!( + "An error occurred when trying to unblock the IP address: {}\n{}", + ip_addr, e + ), + }, + )?; + }; - let response = heroku_client(ctx).request(&config_vars::AppConfigVarUpdate { - app_id: &app_name, - params: updated_config_var, - }); - - msg.reply( - ctx, - match response { - Ok(_response) => format!("IP address {} has been unblocked", ip_addr.clone()), - Err(e) => format!( - "An error occurred when trying to unblock the IP address: {}\n{}", - ip_addr, e - ), - }, - )?; } Ok(()) @@ -443,3 +465,9 @@ fn current_blocked_ip_addresses(ctx: &Context, app_name: &str) -> HashSet HashMap> { + let mut config_var = HashMap::new(); + config_var.insert("BLOCKED_IPS".to_string(), None); + config_var +} From df3ee3cd4c194d4ba41131530d66bb869c25d46f Mon Sep 17 00:00:00 2001 From: Nell Shamrell Date: Wed, 8 Apr 2020 17:26:30 -0700 Subject: [PATCH 08/18] slight refactoring Signed-off-by: Nell Shamrell --- src/commands/heroku.rs | 11 +++++------ 1 file changed, 5 insertions(+), 6 deletions(-) diff --git a/src/commands/heroku.rs b/src/commands/heroku.rs index bbb0a02..4199688 100644 --- a/src/commands/heroku.rs +++ b/src/commands/heroku.rs @@ -174,12 +174,13 @@ pub fn unblock_ip(ctx: &mut Context, msg: &Message, mut args: Args) -> CommandRe )?; } else { blocked_ips_set.remove(&ip_addr); - if blocked_ips_set.is_empty() { - let config_var_to_delete = null_blocked_ips_config_var(); + // Removes config variable from the Heroku application + // if there are no more blocked ip addresses + if blocked_ips_set.is_empty() { let response = heroku_client(ctx).request(&config_vars::AppConfigVarDelete { app_id: &app_name, - params: config_var_to_delete, + params: null_blocked_ips_config_var(), }); msg.reply( @@ -194,11 +195,9 @@ pub fn unblock_ip(ctx: &mut Context, msg: &Message, mut args: Args) -> CommandRe )?; } else { - let updated_config_var = blocked_ips_config_var(blocked_ips_set); - let response = heroku_client(ctx).request(&config_vars::AppConfigVarUpdate { app_id: &app_name, - params: updated_config_var, + params: blocked_ips_config_var(blocked_ips_set), }); msg.reply( From b20202e7297260d69208c368e7c964eb12f2534d Mon Sep 17 00:00:00 2001 From: Nell Shamrell Date: Thu, 9 Apr 2020 14:03:48 -0700 Subject: [PATCH 09/18] successfully creates BLOCKED_IPS env var if it does not already exist Signed-off-by: Nell Shamrell modifies parsing a hashset into a string so that it does not create an empty string at the beginning Signed-off-by: Nell Shamrell --- src/commands/heroku.rs | 38 +++++++++++++++++++++++++++++++++++--- src/utilities.rs | 8 ++++++-- 2 files changed, 41 insertions(+), 5 deletions(-) diff --git a/src/commands/heroku.rs b/src/commands/heroku.rs index 4199688..f681746 100644 --- a/src/commands/heroku.rs +++ b/src/commands/heroku.rs @@ -122,6 +122,31 @@ pub fn block_ip(ctx: &mut Context, msg: &Message, mut args: Args) -> CommandResu .single::() .expect("You must include an IP address to block"); + let current_config_vars = heroku_app_config_vars(&ctx, &app_name); + + // If the BLOCKED_IPS environmental variable does not + // currently exist, create it + if current_config_vars + .get(&"BLOCKED_IPS".to_string()) + .is_none() + { + let response = heroku_client(&ctx).request(&config_vars::AppConfigVarUpdate { + app_id: &app_name, + params: empty_config_var(), + }); + + msg.reply( + &ctx, + match response { + Ok(_response) => format!("The BLOCKED_IPS environmental variable has been created for {}", app_name), + Err(e) => format!( + "The BLOCKED_IPS environmetal variable does not current exist for {}.\n There was an error when trying to create it: {}", + app_name, e + ), + }, + )?; + } + let mut blocked_ips_set = current_blocked_ip_addresses(&ctx, &app_name); if blocked_ips_set.contains(&ip_addr) { @@ -186,14 +211,16 @@ pub fn unblock_ip(ctx: &mut Context, msg: &Message, mut args: Args) -> CommandRe msg.reply( ctx, match response { - Ok(_response) => format!("IP address {} has been unblocked, there are now no unblocked IP addresses", ip_addr.clone()), + Ok(_response) => format!( + "IP address {} has been unblocked, there are now no unblocked IP addresses", + ip_addr.clone() + ), Err(e) => format!( "An error occurred when trying to unblock the IP address: {}\n{}", ip_addr, e ), }, )?; - } else { let response = heroku_client(ctx).request(&config_vars::AppConfigVarUpdate { app_id: &app_name, @@ -211,7 +238,6 @@ pub fn unblock_ip(ctx: &mut Context, msg: &Message, mut args: Args) -> CommandRe }, )?; }; - } Ok(()) @@ -458,6 +484,12 @@ fn config_var(updated_blocked_ips_value: String) -> HashMap { config_var } +fn empty_config_var() -> HashMap { + let mut config_var = HashMap::new(); + config_var.insert("BLOCKED_IPS".to_string(), "".to_string()); + config_var +} + fn current_blocked_ip_addresses(ctx: &Context, app_name: &str) -> HashSet { let blocked_ips_value = block_ips_value(heroku_app_config_vars(&ctx, &app_name)); diff --git a/src/utilities.rs b/src/utilities.rs index fb28e3d..0634c9e 100644 --- a/src/utilities.rs +++ b/src/utilities.rs @@ -16,8 +16,12 @@ pub fn parse_config_value_string(config_value: HashSet) -> String { let mut combined_string = String::new(); for item in config_value.iter() { - let item_string = format!("{},", item); - combined_string.push_str(&item_string); + if item.is_empty() { + continue; + } else { + let item_string = format!("{},", item); + combined_string.push_str(&item_string); + } } // Remove last comma From 74dcbce6e94ab1667c33fea4c0d31528e1f0864e Mon Sep 17 00:00:00 2001 From: Nell Shamrell Date: Thu, 9 Apr 2020 14:32:52 -0700 Subject: [PATCH 10/18] update README with documentation of block_ip and unblock_ip commands Signed-off-by: Nell Shamrell --- README.md | 27 +++++++++++++++++++++++++++ 1 file changed, 27 insertions(+) diff --git a/README.md b/README.md index 91d3b4c..4a436a8 100644 --- a/README.md +++ b/README.md @@ -241,6 +241,33 @@ Quantity: 2 Size: standard-2X ``` +**~block_ip** + +If you wish to block an IP address from accessing your application, you can do so with the ~block_ip command. + +``` +you: ~block_ip you_app_name ip_address_to_block +``` + +``` +you: ~block_ip testing-nell-bot 123.456.68 +crates-io-bot: @you IP address 123.456.789 +``` + +**~unblock_ip** + +If you wish to unblock an IP address that was previously +blocked for your application you can do so with the ~unblock_ip command: + +``` +you: ~unblock_ip you_app_name ip_address_to_unblock +``` + +``` +you: ~unblock_ip testing-nell-bot 123.456.68 +crates-io-bot: @you IP address 123.456.789 has been unblocked +``` + ## Setup To setup this Discord bot, you need: From 53b113f0f15996468ebfd3aae6f19b5f693608c3 Mon Sep 17 00:00:00 2001 From: Nell Shamrell Date: Thu, 9 Apr 2020 14:40:54 -0700 Subject: [PATCH 11/18] fixes failing test Signed-off-by: Nell Shamrell --- src/utilities.rs | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/src/utilities.rs b/src/utilities.rs index 0634c9e..a7b580b 100644 --- a/src/utilities.rs +++ b/src/utilities.rs @@ -52,6 +52,8 @@ mod tests { users_hash_set.insert("789".to_string()); let users_string = parse_config_value_string(users_hash_set); - assert_eq!(users_string, "123,456,789"); + assert!(users_string.contains("123")); + assert!(users_string.contains("456")); + assert!(users_string.contains("789")); } } From dc5fd35ff13969d970fb2d89ba57b9d6d3f55899 Mon Sep 17 00:00:00 2001 From: Nell Shamrell Date: Fri, 10 Apr 2020 10:12:31 -0700 Subject: [PATCH 12/18] remove BLOCKED_IPS from list of authorized config vars for the update_app_config command Signed-off-by: Nell Shamrell --- src/commands/heroku.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/commands/heroku.rs b/src/commands/heroku.rs index f681746..19a0c41 100644 --- a/src/commands/heroku.rs +++ b/src/commands/heroku.rs @@ -59,7 +59,7 @@ pub fn get_app(ctx: &mut Context, msg: &Message, mut args: Args) -> CommandResul } // App config variables that can be updated through Discord -const AUTHORIZED_CONFIG_VARS: &[&str] = &["BLOCKED_IPS"]; +const AUTHORIZED_CONFIG_VARS: &[&str] = &["FOO"]; // Get app by name or id #[command] From 6f731f0d276dd4f3ca0038886a8653d3a2ae1afb Mon Sep 17 00:00:00 2001 From: Nell Shamrell Date: Fri, 10 Apr 2020 10:20:39 -0700 Subject: [PATCH 13/18] refactors BLOCKED_IPS env var key to a constant Signed-off-by: Nell Shamrell --- src/commands/heroku.rs | 18 ++++++++++-------- 1 file changed, 10 insertions(+), 8 deletions(-) diff --git a/src/commands/heroku.rs b/src/commands/heroku.rs index 19a0c41..0026986 100644 --- a/src/commands/heroku.rs +++ b/src/commands/heroku.rs @@ -111,6 +111,8 @@ pub fn update_app_config(ctx: &mut Context, msg: &Message, mut args: Args) -> Co Ok(()) } +const BLOCKED_IPS_ENV_VAR : &str = "BLOCKED_IPS"; + #[command] #[num_args(2)] pub fn block_ip(ctx: &mut Context, msg: &Message, mut args: Args) -> CommandResult { @@ -127,7 +129,7 @@ pub fn block_ip(ctx: &mut Context, msg: &Message, mut args: Args) -> CommandResu // If the BLOCKED_IPS environmental variable does not // currently exist, create it if current_config_vars - .get(&"BLOCKED_IPS".to_string()) + .get(&BLOCKED_IPS_ENV_VAR.to_string()) .is_none() { let response = heroku_client(&ctx).request(&config_vars::AppConfigVarUpdate { @@ -138,10 +140,10 @@ pub fn block_ip(ctx: &mut Context, msg: &Message, mut args: Args) -> CommandResu msg.reply( &ctx, match response { - Ok(_response) => format!("The BLOCKED_IPS environmental variable has been created for {}", app_name), + Ok(_response) => format!("The {} environmental variable has been created for {}", BLOCKED_IPS_ENV_VAR, app_name), Err(e) => format!( - "The BLOCKED_IPS environmetal variable does not current exist for {}.\n There was an error when trying to create it: {}", - app_name, e + "The {} environmetal variable does not current exist for {}.\n There was an error when trying to create it: {}", + BLOCKED_IPS_ENV_VAR, app_name, e ), }, )?; @@ -465,7 +467,7 @@ fn heroku_app_config_vars(ctx: &Context, app_name: &str) -> HashMap>) -> String { config_vars - .get(&"BLOCKED_IPS".to_string()) + .get(&BLOCKED_IPS_ENV_VAR.to_string()) .unwrap() .as_ref() .unwrap() @@ -480,13 +482,13 @@ fn blocked_ips_config_var(blocked_ips_set: HashSet) -> HashMap HashMap { let mut config_var = HashMap::new(); - config_var.insert("BLOCKED_IPS".to_string(), updated_blocked_ips_value); + config_var.insert(BLOCKED_IPS_ENV_VAR.to_string(), updated_blocked_ips_value); config_var } fn empty_config_var() -> HashMap { let mut config_var = HashMap::new(); - config_var.insert("BLOCKED_IPS".to_string(), "".to_string()); + config_var.insert(BLOCKED_IPS_ENV_VAR.to_string(), "".to_string()); config_var } @@ -499,6 +501,6 @@ fn current_blocked_ip_addresses(ctx: &Context, app_name: &str) -> HashSet HashMap> { let mut config_var = HashMap::new(); - config_var.insert("BLOCKED_IPS".to_string(), None); + config_var.insert(BLOCKED_IPS_ENV_VAR.to_string(), None); config_var } From 4151d88b2a55c857a21778562702770d792c9cb2 Mon Sep 17 00:00:00 2001 From: Nell Shamrell Date: Fri, 10 Apr 2020 10:51:19 -0700 Subject: [PATCH 14/18] returns from block_ip function when there is an error creating the BLOCKED_IPS env var Signed-off-by: Nell Shamrell --- src/commands/heroku.rs | 9 ++++++++- 1 file changed, 8 insertions(+), 1 deletion(-) diff --git a/src/commands/heroku.rs b/src/commands/heroku.rs index 0026986..6e483d6 100644 --- a/src/commands/heroku.rs +++ b/src/commands/heroku.rs @@ -137,16 +137,23 @@ pub fn block_ip(ctx: &mut Context, msg: &Message, mut args: Args) -> CommandResu params: empty_config_var(), }); + let response_err = response.is_err(); + msg.reply( &ctx, match response { Ok(_response) => format!("The {} environmental variable has been created for {}", BLOCKED_IPS_ENV_VAR, app_name), Err(e) => format!( - "The {} environmetal variable does not current exist for {}.\n There was an error when trying to create it: {}", + "The {} environmental variable does not current exist for {}.\n There was an error when trying to create it: {}", BLOCKED_IPS_ENV_VAR, app_name, e ), }, )?; + + if response_err { + return Ok(()) + } + } let mut blocked_ips_set = current_blocked_ip_addresses(&ctx, &app_name); From 251e52cbc2c19e92e45ca4264f6c02ed3939f050 Mon Sep 17 00:00:00 2001 From: Nell Shamrell Date: Fri, 10 Apr 2020 11:31:16 -0700 Subject: [PATCH 15/18] partial refactor - only get current config variables from Heroku once per command Signed-off-by: Nell Shamrell --- src/commands/heroku.rs | 21 ++++++++++++--------- 1 file changed, 12 insertions(+), 9 deletions(-) diff --git a/src/commands/heroku.rs b/src/commands/heroku.rs index 6e483d6..08ea69f 100644 --- a/src/commands/heroku.rs +++ b/src/commands/heroku.rs @@ -128,10 +128,7 @@ pub fn block_ip(ctx: &mut Context, msg: &Message, mut args: Args) -> CommandResu // If the BLOCKED_IPS environmental variable does not // currently exist, create it - if current_config_vars - .get(&BLOCKED_IPS_ENV_VAR.to_string()) - .is_none() - { + if !blocked_ips_exist(¤t_config_vars) { let response = heroku_client(&ctx).request(&config_vars::AppConfigVarUpdate { app_id: &app_name, params: empty_config_var(), @@ -153,10 +150,9 @@ pub fn block_ip(ctx: &mut Context, msg: &Message, mut args: Args) -> CommandResu if response_err { return Ok(()) } - } - let mut blocked_ips_set = current_blocked_ip_addresses(&ctx, &app_name); + let mut blocked_ips_set = current_blocked_ip_addresses(current_config_vars); if blocked_ips_set.contains(&ip_addr) { msg.reply( @@ -199,7 +195,9 @@ pub fn unblock_ip(ctx: &mut Context, msg: &Message, mut args: Args) -> CommandRe .single::() .expect("You must include an IP address to unblock"); - let mut blocked_ips_set = current_blocked_ip_addresses(&ctx, &app_name); + let current_config_vars = heroku_app_config_vars(&ctx, &app_name); + + let mut blocked_ips_set = current_blocked_ip_addresses(current_config_vars); if !blocked_ips_set.contains(&ip_addr) { msg.reply( @@ -499,8 +497,8 @@ fn empty_config_var() -> HashMap { config_var } -fn current_blocked_ip_addresses(ctx: &Context, app_name: &str) -> HashSet { - let blocked_ips_value = block_ips_value(heroku_app_config_vars(&ctx, &app_name)); +fn current_blocked_ip_addresses(config_vars: HashMap>) -> HashSet { + let blocked_ips_value = block_ips_value(config_vars); let blocked_ips_set = parse_config_value_set(blocked_ips_value); blocked_ips_set @@ -511,3 +509,8 @@ fn null_blocked_ips_config_var() -> HashMap> { config_var.insert(BLOCKED_IPS_ENV_VAR.to_string(), None); config_var } + +fn blocked_ips_exist(config_vars: &HashMap>) -> bool { + let exists = config_vars.get(&BLOCKED_IPS_ENV_VAR.to_string()).is_some(); + exists +} \ No newline at end of file From 53d58e58f5dc77e49e85cae65bc6b6a459b4a833 Mon Sep 17 00:00:00 2001 From: Nell Shamrell Date: Fri, 10 Apr 2020 11:40:07 -0700 Subject: [PATCH 16/18] handles situation where someone is trying to unblock an ip when no IPs are currently blocked Signed-off-by: Nell Shamrell --- src/commands/heroku.rs | 9 +++++++++ 1 file changed, 9 insertions(+) diff --git a/src/commands/heroku.rs b/src/commands/heroku.rs index 08ea69f..b029c04 100644 --- a/src/commands/heroku.rs +++ b/src/commands/heroku.rs @@ -197,6 +197,15 @@ pub fn unblock_ip(ctx: &mut Context, msg: &Message, mut args: Args) -> CommandRe let current_config_vars = heroku_app_config_vars(&ctx, &app_name); + if !blocked_ips_exist(¤t_config_vars) { + msg.reply( + &ctx, + format!("No IP addresses are currently blocked for {}", &app_name), + )?; + + return Ok(()) + } + let mut blocked_ips_set = current_blocked_ip_addresses(current_config_vars); if !blocked_ips_set.contains(&ip_addr) { From dc03042092fb0f69e48f983b48977040794fa77d Mon Sep 17 00:00:00 2001 From: Nell Shamrell Date: Fri, 10 Apr 2020 11:41:33 -0700 Subject: [PATCH 17/18] corrects formatting Signed-off-by: Nell Shamrell --- src/commands/heroku.rs | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/src/commands/heroku.rs b/src/commands/heroku.rs index b029c04..4f4fcd3 100644 --- a/src/commands/heroku.rs +++ b/src/commands/heroku.rs @@ -111,7 +111,7 @@ pub fn update_app_config(ctx: &mut Context, msg: &Message, mut args: Args) -> Co Ok(()) } -const BLOCKED_IPS_ENV_VAR : &str = "BLOCKED_IPS"; +const BLOCKED_IPS_ENV_VAR: &str = "BLOCKED_IPS"; #[command] #[num_args(2)] @@ -148,7 +148,7 @@ pub fn block_ip(ctx: &mut Context, msg: &Message, mut args: Args) -> CommandResu )?; if response_err { - return Ok(()) + return Ok(()); } } @@ -203,7 +203,7 @@ pub fn unblock_ip(ctx: &mut Context, msg: &Message, mut args: Args) -> CommandRe format!("No IP addresses are currently blocked for {}", &app_name), )?; - return Ok(()) + return Ok(()); } let mut blocked_ips_set = current_blocked_ip_addresses(current_config_vars); @@ -522,4 +522,4 @@ fn null_blocked_ips_config_var() -> HashMap> { fn blocked_ips_exist(config_vars: &HashMap>) -> bool { let exists = config_vars.get(&BLOCKED_IPS_ENV_VAR.to_string()).is_some(); exists -} \ No newline at end of file +} From b7ed4c87f6164166fa7c7c5f10c04f9811abe2fa Mon Sep 17 00:00:00 2001 From: Nell Shamrell Date: Tue, 14 Apr 2020 10:16:11 -0700 Subject: [PATCH 18/18] more refinements Signed-off-by: Nell Shamrell --- README.md | 2 +- src/utilities.rs | 27 +++------------------------ 2 files changed, 4 insertions(+), 25 deletions(-) diff --git a/README.md b/README.md index 4a436a8..2cfe000 100644 --- a/README.md +++ b/README.md @@ -251,7 +251,7 @@ you: ~block_ip you_app_name ip_address_to_block ``` you: ~block_ip testing-nell-bot 123.456.68 -crates-io-bot: @you IP address 123.456.789 +crates-io-bot: @you IP address 123.456.68 ``` **~unblock_ip** diff --git a/src/utilities.rs b/src/utilities.rs index a7b580b..85fce9b 100644 --- a/src/utilities.rs +++ b/src/utilities.rs @@ -1,33 +1,12 @@ use std::collections::HashSet; pub fn parse_config_value_set(config_value: String) -> HashSet { - let mut value_set = HashSet::new(); - - let split_string = config_value.split(','); - - for string in split_string { - value_set.insert(String::from(string)); - } - - value_set + config_value.split(',').map(String::from).collect() } pub fn parse_config_value_string(config_value: HashSet) -> String { - let mut combined_string = String::new(); - - for item in config_value.iter() { - if item.is_empty() { - continue; - } else { - let item_string = format!("{},", item); - combined_string.push_str(&item_string); - } - } - - // Remove last comma - combined_string.pop(); - - combined_string + let non_empty: Vec = config_value.into_iter().filter(|s| !s.is_empty()).collect(); + non_empty.join(",") } #[cfg(test)]