Skip to content

Commit

Permalink
Merge pull request #13 from Lissy93/FEAT/version-check
Browse files Browse the repository at this point in the history
[Fix] Adds a check to ensure using a compatible version of AdGuard API
  • Loading branch information
Lissy93 authored Jun 3, 2023
2 parents 9c89fa2 + 7c5d566 commit aa6110d
Show file tree
Hide file tree
Showing 4 changed files with 97 additions and 14 deletions.
3 changes: 2 additions & 1 deletion .github/CHANGELOG.md
Original file line number Diff line number Diff line change
@@ -1 +1,2 @@
Enables support for HTTPS, via optional user-defined protocol (#7)
Adds a check to ensure that the users version of AdGuard Home is recent enough to support the required API calls (#5)
Allows for graceful exit, instead of panicking
10 changes: 9 additions & 1 deletion Cargo.lock

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

8 changes: 6 additions & 2 deletions Cargo.toml
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
[package]
name = "adguardian"
version = "1.3.0"
version = "1.4.0"
edition = "2021"
authors = ["Alicia Sykes"]
description = "Terminal-based, real-time traffic monitoring and statistics for your AdGuard Home instance "
Expand All @@ -25,8 +25,12 @@ crossterm = { version = "0.22.0", features = ["serde"] }
futures = "0.3"
# HTTP client
reqwest = { version = "0.11", default-features = false, features = ["blocking", "json", "rustls-tls"] }
# Decerilization of JSON responses
# Decerilization of responses
serde = { version = "1.0", features = ["derive"] }
# Decerilization of JSON responses
serde_json = "1.0"
# Read and calculate semantic version numbers
semver = "1.0"
# Date + time manipulation
tokio = { version = "1", features = ["full"] }
# Terminal UI library
Expand Down
90 changes: 80 additions & 10 deletions src/welcome.rs
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,10 @@ use std::{
use reqwest::{Client, Error};
use colored::*;

use serde_json::Value;
use semver::{Version};

/// Reusable function that just prints success messages to the console
fn print_info(text: &str, is_secondary: bool) {
if is_secondary {
println!("{}", text.green().italic().dimmed());
Expand All @@ -14,7 +18,7 @@ fn print_info(text: &str, is_secondary: bool) {
};
}


/// Prints the AdGuardian ASCII art to console
fn print_ascii_art() {
let art = r"
█████╗ ██████╗ ██████╗ ██╗ ██╗ █████╗ ██████╗ ██████╗ ██╗ █████╗ ███╗ ██╗
Expand All @@ -30,19 +34,22 @@ fn print_ascii_art() {
print_info("For documentation and support, please visit: https://github.com/lissy93/adguardian-term\n", true);
}

fn print_error(address: &str, error: Option<&Error>) {
/// Print error message, along with (optional) stack trace, then exit
fn print_error(message: &str, sub_message: &str, error: Option<&Error>) {
eprintln!(
"{}{}",
format!("Failed to connect to AdGuard at {}", address).red(),
"{}{}{}",
format!("{}", message).red(),
match error {
Some(err) => format!("\n{}", err).red().dimmed(),
None => "".red().dimmed(),
},
format!("\n{}", sub_message).yellow(),
);
eprintln!("{}\n{}", "\nPlease check your environmental variables and try again.".yellow(), "Exiting...".blue());
}

std::process::exit(1);
}

/// Given a key, get the value from the environmental variables, and print it to the console
fn get_env(key: &str) -> Result<String, env::VarError> {
env::var(key).map(|v| {
println!(
Expand All @@ -58,6 +65,39 @@ fn get_env(key: &str) -> Result<String, env::VarError> {
})
}

/// Given a possibly undefined version number, check if it's present and supported
fn check_version(version: Option<&str>) {
let min_version = Version::parse("0.107.29").unwrap();

match version {
Some(version_str) => {
let adguard_version = Version::parse(&version_str[1..]).unwrap();

if adguard_version < min_version {
print_error(
"AdGuard Home version is too old, and is now unsupported",
format!("You're running AdGuard {}. Please upgrade to v{} or later.", version_str, min_version.to_string()).as_str(),
None,
);
}
},
None => {
print_error(
"Unsupported AdGuard Home version",
format!(
concat!(
"Failed to get the version number of your AdGuard Home instance.\n",
"This usually means you're running an old, and unsupported version.\n",
"Please upgrade to v{} or later."
), min_version.to_string()
).as_str(),
None,
);
}
}
}

/// With the users specified AdGuard details, verify the connection (exit on fail)
async fn verify_connection(
client: &Client,
ip: String,
Expand All @@ -82,16 +122,44 @@ async fn verify_connection(
.send()
.await {
Ok(res) if res.status().is_success() => {
println!("{}", "AdGuard connection successful!\n".green());
// Get version string (if present), and check if valid - exit if not
let body: Value = res.json().await?;
check_version(body["version"].as_str());
// All good! Print success message :)
let safe_version = body["version"].as_str().unwrap_or("mystery version");
println!("{}", format!("AdGuard ({}) connection successful!\n", safe_version).green());
Ok(())
}
Ok(_) | Err(_) => {
print_error(&format!("{}:{}", ip, port), None);
std::process::exit(1);
// Connection failed to authenticate. Print error and exit
Ok(_) => {
print_error(
&format!("Authentication with AdGuard at {}:{} failed", ip, port),
"Please check your environmental variables and try again.",
None,
);
Ok(())
},
// Connection failed to establish. Print error and exit
Err(e) => {
print_error(
&format!("Failed to connect to AdGuard at: {}:{}", ip, port),
"Please check your environmental variables and try again.",
Some(&e),
);
Ok(())
}
}
}

/// Initiate the welcome script
/// This function will:
/// - Print the AdGuardian ASCII art
/// - Check for the required environmental variables
/// - Prompt the user to enter any missing variables
/// - Verify the connection to the AdGuard instance
/// - Verify authentication is successful
/// - Verify the AdGuard Home version is supported
/// - Then either print a success message, or show instructions to fix and exit
pub async fn welcome() -> Result<(), Box<dyn std::error::Error>> {
print_ascii_art();
println!("{}", "Starting initialization checks...".blue());
Expand Down Expand Up @@ -138,11 +206,13 @@ pub async fn welcome() -> Result<(), Box<dyn std::error::Error>> {
}
}

// Grab the values of the (now set) environmental variables
let ip = get_env("ADGUARD_IP")?;
let port = get_env("ADGUARD_PORT")?;
let protocol = get_env("ADGUARD_PROTOCOL")?;
let username = get_env("ADGUARD_USERNAME")?;
let password = get_env("ADGUARD_PASSWORD")?;

// Verify that we can connect, authenticate, and that version is supported (exit on failure)
verify_connection(&client, ip, port, protocol, username, password).await
}

0 comments on commit aa6110d

Please sign in to comment.