Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Proper Disk Space Validation #1309

Merged
merged 12 commits into from
Nov 29, 2022
2 changes: 1 addition & 1 deletion docs/community/get_involved/local_dev_setup.md
Original file line number Diff line number Diff line change
Expand Up @@ -140,7 +140,7 @@ You can use the Pyrsia CLI to ensure that the peers are connected.
$ ./pyrsia -s
Connected Peers Count: 1
Artifacts Count: 3 {"manifests": 1, "blobs": 2}
Total Disk Space Allocated: 5.84 GB
Total Disk Space Allocated: 10 GB
Disk Space Used: 0.0002%
fishseabowl marked this conversation as resolved.
Show resolved Hide resolved
```

Expand Down
2 changes: 1 addition & 1 deletion docs/developers/build_from_source_maven.md
Original file line number Diff line number Diff line change
Expand Up @@ -171,7 +171,7 @@ cd $PYRSIA_HOME/target/debug
./pyrsia config --show
host = 'localhost'
port = '7888'
disk_allocated = '5.84 GB'
disk_allocated = '10 GB'
```

If you're not using the default port for your Pyrsia node, make sure to configure
Expand Down
117 changes: 79 additions & 38 deletions pyrsia_cli/src/cli/handlers.rs
Original file line number Diff line number Diff line change
Expand Up @@ -65,26 +65,35 @@ pub fn config_edit(
let mut errors: Vec<&str> = Vec::new();

if host_name.is_some() {
if valid_host(host_name.clone().unwrap_or_default().as_str()) {
updated_cli_config.host = host_name.unwrap();
} else {
errors.push("Invalid value for Hostname");
match valid_host(host_name.clone().unwrap_or_default().as_str()) {
Ok(validated_str) => {
updated_cli_config.host = validated_str;
}
Err(_) => {
errors.push("Invalid value for Hostname");
}
}
}

if port.is_some() {
if valid_port(port.clone().unwrap_or_default().as_str()) {
updated_cli_config.port = port.unwrap();
} else {
errors.push("Invalid value for Port Number");
match valid_port(port.clone().unwrap_or_default().as_str()) {
Ok(validated_str) => {
updated_cli_config.port = validated_str;
}
Err(_) => {
errors.push("Invalid value for Port Number");
}
}
}

if diskspace.is_some() {
if valid_disk_space(diskspace.clone().unwrap_or_default().as_str()) {
updated_cli_config.disk_allocated = diskspace.unwrap();
} else {
errors.push("Invalid value for Disk Allocation");
match valid_disk_space(diskspace.clone().unwrap_or_default().as_str()) {
Ok(validated_str) => {
updated_cli_config.disk_allocated = validated_str;
}
Err(_) => {
errors.push("Invalid value for Disk Allocation");
}
}
}

Expand Down Expand Up @@ -246,23 +255,27 @@ fn print_logs(logs: String) {
}

/// Read user input interactively until the validation passed
fn read_interactive_input(cli_prompt: &str, validation_func: &dyn Fn(&str) -> bool) -> String {
fn read_interactive_input(
cli_prompt: &str,
validation_func: &dyn Fn(&str) -> Result<String, Error>,
) -> String {
loop {
println!("{}", cli_prompt);
let mut buffer = String::new();
if let Ok(bytes_read) = io::stdin().lock().read_line(&mut buffer) {
if bytes_read > 0 {
let input = buffer.lines().next().unwrap();
if validation_func(input) {
break input.to_string();
let r = validation_func(input);
if r.is_ok() {
break r.unwrap();
}
}
}
}
}

/// Returns true if input is a valid hostname or a valid IPv4 address
fn valid_host(input: &str) -> bool {
fn valid_host(input: &str) -> Result<String, Error> {
/// Returns true if input is a valid hostname as per the definition
/// at https://man7.org/linux/man-pages/man7/hostname.7.html, otherwise false
fn valid_hostname(input: &str) -> bool {
Expand All @@ -274,37 +287,52 @@ fn valid_host(input: &str) -> bool {
}
HOSTNAME_REGEX.is_match(input)
}

/// Returns true if input is a valid IPv4 address, otherwise false
fn valid_ipv4_address(input: &str) -> bool {
input.parse::<Ipv4Addr>().is_ok()
}

valid_ipv4_address(input) || valid_hostname(input)
if valid_ipv4_address(input) || valid_hostname(input) {
Ok(input.to_string())
} else {
Err(anyhow!("Invalid value for Hostname"))
}
}

fn valid_port(input: &str) -> bool {
input.parse::<u16>().is_ok()
fn valid_port(input: &str) -> Result<String, Error> {
match input.parse::<u16>() {
Ok(_) => Ok(input.to_string()),
Err(_) => Err(anyhow!("Invalid value for Port Number")),
}
}

fn valid_disk_space(input: &str) -> bool {
/// Disk space will only accept integer values. Currently we it will accept value greater than 0 GB till 4096 GB
fn valid_disk_space(input: &str) -> Result<String, Error> {
const DISK_SPACE_NUM_MIN: u16 = 0;
const DISK_SPACE_NUM_MAX: u16 = 4096;
lazy_static! {
static ref DISK_SPACE_RE: Regex = Regex::new(r"^([0-9]{1,4})\s+(GB)$").unwrap();
static ref DISK_SPACE_RE: Regex = Regex::new(r"^([0-9,\.]+)\s+(GB)$").unwrap();
dasmanas marked this conversation as resolved.
Show resolved Hide resolved
}
// let disk_space_re: Regex = Regex::new(r"^([0-9]{1,4})(\s*)(GB)$").unwrap();
if DISK_SPACE_RE.is_match(input) {
let captured_groups = DISK_SPACE_RE.captures(input).unwrap();
let disk_space_num = captured_groups
.get(1)
.unwrap()
.as_str()
.parse::<u16>()
.unwrap();
DISK_SPACE_NUM_MIN < disk_space_num && disk_space_num <= DISK_SPACE_NUM_MAX
//Group 1 is numeric part including decimal & Group 2 is metric part
let float_parsed_rslt = captured_groups.get(1).unwrap().as_str().parse::<u16>();
if float_parsed_rslt.is_ok() {
let disk_space_num = float_parsed_rslt.unwrap();
if DISK_SPACE_NUM_MIN < disk_space_num && disk_space_num <= DISK_SPACE_NUM_MAX {
Ok(format!(
"{} {}",
disk_space_num.to_string(),
captured_groups.get(2).unwrap().as_str()
))
} else {
Err(anyhow!("Invalid value for Disk Allocation"))
}
} else {
Err(anyhow!("Invalid value for Disk Allocation"))
}
} else {
false
Err(anyhow!("Invalid value for Disk Allocation"))
dasmanas marked this conversation as resolved.
Show resolved Hide resolved
}
}

Expand All @@ -320,7 +348,7 @@ mod tests {
#[test]
fn test_valid_host() {
let valid_hosts = vec!["pyrsia.io", "localhost", "10.10.10.255"];
assert!(valid_hosts.into_iter().all(valid_host));
assert!(valid_hosts.into_iter().all(|x| valid_host(x).is_ok()));
}

#[test]
Expand All @@ -330,31 +358,44 @@ mod tests {
"@localhost",
"%*%*%*%*NO_SENSE_AS_HOST@#$*@#$*@#$*",
];
assert!(!invalid_hosts.into_iter().any(valid_host));
assert!(!invalid_hosts.into_iter().any(|x| valid_host(x).is_ok()));
}

#[test]
fn test_valid_port() {
let valid_ports = vec!["0", "8988", "65535"];
assert!(valid_ports.into_iter().all(valid_port));
assert!(valid_ports.into_iter().all(|x| valid_port(x).is_ok()));
}

#[test]
fn test_invalid_port() {
let invalid_ports = vec!["-1", "65536"];
assert!(!invalid_ports.into_iter().any(valid_port));
assert!(!invalid_ports.into_iter().any(|x| valid_port(x).is_ok()));
}

#[test]
fn test_valid_disk_space() {
let valid_disk_space_list = vec!["100 GB", "1 GB", "4096 GB"];
assert!(valid_disk_space_list.into_iter().all(valid_disk_space));
assert!(valid_disk_space_list
.into_iter()
.all(|x| valid_disk_space(x).is_ok()));
}

#[test]
fn test_invalid_disk_space() {
let invalid_disk_space_list = vec!["0 GB", "4097 GB", "100GB", "100gb"];
assert!(!invalid_disk_space_list.into_iter().any(valid_disk_space));
let invalid_disk_space_list = vec![
"0 GB",
"4097 GB",
"100GB",
"100gb",
"5.84 GB",
"5..84 GB",
"5..84 GB",
"5.84.22 GB",
];
assert!(!invalid_disk_space_list
.into_iter()
.any(|x| valid_disk_space(x).is_ok()));
}

#[test]
Expand Down
2 changes: 1 addition & 1 deletion src/cli_commands/config.rs
Original file line number Diff line number Diff line change
Expand Up @@ -34,7 +34,7 @@ impl Default for CliConfig {
CliConfig {
host: "localhost".to_string(),
port: "7888".to_string(),
disk_allocated: "5.84 GB".to_string(),
disk_allocated: "10 GB".to_string(),
}
}
}
Expand Down