Skip to content

Commit

Permalink
Adapted the CLI consuming the HTTP/JSON network API (#1178)
Browse files Browse the repository at this point in the history
## Problem

Ideally, the CLI and the web UI should use the same interface to
interact with Agama. As it is a time that may take some time lets start
updating the network configuration as it stopped to work once we moved
to the HTTP/JSON API.

-
[*Trello*](https://trello.com/c/R0kSx0OP/3649-8-adapt-the-auto-installation-process-to-use-the-http-api-networking)

## Solution

Adapted the CLI using the HTTP/JSON API. For authentication the stored
JWT token or the agama-live token will be used when exist. Cookires are
enabled just in case in the future we wanted to save them to a file and
restoring when the client is obtained.

Last but not least, rpassword was added for hidding the password when it
is entered for authentication.

## Testing

- *Added a new unit test*
- *Tested manually*
  • Loading branch information
teclator authored May 8, 2024
2 parents 259b625 + 47952af commit 4641c2e
Show file tree
Hide file tree
Showing 18 changed files with 425 additions and 559 deletions.
186 changes: 180 additions & 6 deletions rust/Cargo.lock

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

1 change: 1 addition & 0 deletions rust/agama-cli/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -27,6 +27,7 @@ tokio = { version = "1.33.0", features = ["macros", "rt-multi-thread"] }
async-trait = "0.1.77"
reqwest = { version = "0.11", features = ["json"] }
home = "0.5.9"
rpassword = "7.3.1"

[[bin]]
name = "agama"
Expand Down
27 changes: 20 additions & 7 deletions rust/agama-cli/src/auth.rs
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@ use std::os::unix::fs::PermissionsExt;
use std::path::{Path, PathBuf};

const DEFAULT_JWT_FILE: &str = ".agama/agama-jwt";
const DEFAULT_AGAMA_TOKEN_FILE: &str = "/run/agama/token";
const DEFAULT_AUTH_URL: &str = "http://localhost:3000/api/auth";
const DEFAULT_FILE_MODE: u32 = 0o600;

Expand All @@ -33,8 +34,19 @@ pub async fn run(subcommand: AuthCommands) -> anyhow::Result<()> {
}
}

/// Returns the stored Agama token.
pub fn agama_token() -> anyhow::Result<String> {
if let Some(file) = agama_token_file() {
if let Ok(token) = read_line_from_file(file.as_path()) {
return Ok(token);
}
}

Err(anyhow::anyhow!("Authentication token not available"))
}

/// Reads stored token and returns it
fn jwt() -> anyhow::Result<String> {
pub fn jwt() -> anyhow::Result<String> {
if let Some(file) = jwt_file() {
if let Ok(token) = read_line_from_file(file.as_path()) {
return Ok(token);
Expand Down Expand Up @@ -109,6 +121,10 @@ impl Credentials for MissingCredentials {
fn jwt_file() -> Option<PathBuf> {
Some(home::home_dir()?.join(DEFAULT_JWT_FILE))
}
/// Path to agama-live token file.
fn agama_token_file() -> Option<PathBuf> {
home::home_dir().map(|p| p.join(DEFAULT_AGAMA_TOKEN_FILE))
}

/// Reads first line from given file
fn read_line_from_file(path: &Path) -> io::Result<String> {
Expand Down Expand Up @@ -137,12 +153,9 @@ fn read_line_from_file(path: &Path) -> io::Result<String> {

/// Asks user to provide a line of input. Displays a prompt.
fn read_credential(caption: String) -> io::Result<String> {
let mut cred = String::new();

println!("{}: ", caption);

io::stdin().read_line(&mut cred)?;
if cred.pop().is_none() || cred.is_empty() {
let caption = format!("{}: ", caption);
let cred = rpassword::prompt_password(caption.clone()).unwrap();
if cred.is_empty() {
return Err(io::Error::new(
io::ErrorKind::Other,
format!("Failed to read {}", caption),
Expand Down
Loading

0 comments on commit 4641c2e

Please sign in to comment.