From 6a11bb494b090195893b1b2ff9887ec69650aa3c Mon Sep 17 00:00:00 2001 From: grimhilt Date: Tue, 20 Feb 2024 21:24:22 +0100 Subject: [PATCH] feat(credential): allow to add credential --- src/commands/config.rs | 40 +++++++++++++++++++++----- src/commands/credential.rs | 53 +++++++++++++++++++++++++++++++++++ src/main.rs | 2 ++ src/services/login.rs | 12 +++++++- src/subcommands.rs | 1 + src/subcommands/credential.rs | 39 ++++++++++++++++++++++++++ 6 files changed, 139 insertions(+), 8 deletions(-) create mode 100644 src/commands/credential.rs create mode 100644 src/subcommands/credential.rs diff --git a/src/commands/config.rs b/src/commands/config.rs index edf6153..71f48cf 100644 --- a/src/commands/config.rs +++ b/src/commands/config.rs @@ -7,7 +7,7 @@ pub fn add_remote(name: &str, url: &str) -> io::Result<()> { root.push("config"); // check if there is already a remote with this name - if get_remote(name) + if get_remote(name).is_some() { eprintln!("error: remote {} already exists.", name); std::process::exit(3); @@ -26,24 +26,50 @@ pub fn add_remote(name: &str, url: &str) -> io::Result<()> { Ok(()) } -pub fn get_remote(name: &str) -> bool { +pub fn get_remote(name: &str) -> Option { let mut root = path::nextsync(); root.push("config"); let target = String::from(format!("[remote \"{}\"]", name)); - if let Ok(lines) = read::read_lines(root) { - for line_result in lines { - if let Ok(line) = line_result { + if let Ok(mut lines) = read::read_lines(root) { + while let Some(line_res) = lines.next() { + if let Ok(line) = line_res { if line == target { - return true; + // get the first line starting with 'url = ' + while let Some(line_res) = lines.next() { + if let Ok(line) = line_res { + let mut splitted_res = line.split("="); + if let Some(splitted) = splitted_res.next() { + if splitted == "\turl " { + return Some(splitted_res.next().unwrap().to_owned()); + } + } + } + } } } } } - return false; + return None; +} +pub fn add_core(name: &str, value: &str) -> io::Result<()> { + let mut root = path::nextsync(); + root.push("config"); + + let mut file = OpenOptions::new() + .read(true) + .write(true) + .create(true) + .append(true) + .open(root)?; + + writeln!(file, "[core]")?; + writeln!(file, "\t{} = {}", name, value)?; + + Ok(()) } pub fn set(var: &str, val: &str) -> io::Result<()> { diff --git a/src/commands/credential.rs b/src/commands/credential.rs new file mode 100644 index 0000000..0922523 --- /dev/null +++ b/src/commands/credential.rs @@ -0,0 +1,53 @@ +use clap::Values; +use crate::commands::clone::get_url_props; +use crate::services::api::ApiError::RequestError; + +use crate::services::login::Login; +use crate::services::api_call::ApiCall; +use crate::commands::config; + +pub struct CredentialArgs<'a> { + pub username: Option>, + pub password: Option>, +} + +pub fn credential_add(args: CredentialArgs) { + let username = args.username.unwrap().next().unwrap(); + + let password = match args.password { + Some(mut pwd) => pwd.next().unwrap().to_owned(), + None => { + println!("Please enter the password for {}: ", username); + rpassword::read_password().unwrap() + } + }; + + let remote = match config::get_remote("origin") { + None => { + eprintln!("fatal: No remote origin, impossible to send request to get token"); + std::process::exit(1); + }, + Some(remote) => remote + }; + + let (host, _, _) = get_url_props(&remote); + + let get_token = Login::new() + .set_auth(username, &password) + .set_host(Some(host)) + .send_login(); + + + if let Err(err) = get_token { + if let RequestError(err) = err { + eprintln!("fatal: Failed to get token for these credential. ({})", err); + } + else { + eprintln!("fatal: Failed to get token for these credential."); + } + std::process::exit(1); + } + + let _ = config::add_core(username, get_token.unwrap().as_str()); +} + diff --git a/src/main.rs b/src/main.rs index 54bb9e0..ff10cbf 100644 --- a/src/main.rs +++ b/src/main.rs @@ -24,6 +24,7 @@ fn main() { .subcommand(subcommands::config::create()) .subcommand(subcommands::remote_diff::create()) .subcommand(subcommands::pull::create()) + .subcommand(subcommands::credential::create()) .subcommand( SubCommand::with_name("test") ); @@ -41,6 +42,7 @@ fn main() { ("remote-diff", Some(args)) => subcommands::remote_diff::handler(args), ("pull", Some(args)) => subcommands::pull::handler(args), ("remote", Some(args)) => subcommands::remote::handler(args), + ("credential", Some(args)) => subcommands::credential::handler(args), (_, _) => {}, }; diff --git a/src/services/login.rs b/src/services/login.rs index 135d270..f447d06 100644 --- a/src/services/login.rs +++ b/src/services/login.rs @@ -28,7 +28,11 @@ impl ApiCall for Login { let url = match self.host.clone() { Some(h) => { - let mut u = String::from("https://"); + let mut u = if &h[0..8] == "https://" || &h[0..7] == "http://" { + String::new() + } else { + String::from("https://") + }; u.push_str(&h); u.push_str("/ocs/v2.php/core/getapppassword"); u @@ -53,6 +57,12 @@ impl Login { self } + pub fn set_auth(&mut self, username: &str, password: &str) -> &mut Login { + self.login = username.to_owned(); + self.password = password.to_owned(); + self + } + pub fn set_host(&mut self, host: Option) -> &mut Login { self.host = host; self diff --git a/src/subcommands.rs b/src/subcommands.rs index fe0cef4..766a407 100644 --- a/src/subcommands.rs +++ b/src/subcommands.rs @@ -8,3 +8,4 @@ pub mod config; pub mod remote_diff; pub mod pull; pub mod remote; +pub mod credential; diff --git a/src/subcommands/credential.rs b/src/subcommands/credential.rs new file mode 100644 index 0000000..651e049 --- /dev/null +++ b/src/subcommands/credential.rs @@ -0,0 +1,39 @@ +use clap::{App, Arg, SubCommand, ArgMatches}; + +use crate::commands; +use crate::commands::credential::CredentialArgs; + +pub fn create() -> App<'static, 'static> { + SubCommand::with_name("credential") + .about("Manage set of credentials") + .subcommand( + SubCommand::with_name("add") + .arg( + Arg::with_name("username") + .required(true) + .takes_value(true) + .value_name("NAME") + .help("The username used to connect to nextcloud"), + ) + .arg( + Arg::with_name("password") + .required(false) + .takes_value(true) + .value_name("PASSWORD") + .help("The passowd used to connect to nextcloud (optional)"), + ) + .about("Add a new set of credential") + ) +} + +pub fn handler(args: &ArgMatches<'_>) { + match args.subcommand() { + ("add", Some(add_matches)) => { + commands::credential::credential_add(CredentialArgs { + username: add_matches.values_of("username"), + password: add_matches.values_of("password"), + }); + } + _ => println!("Invalid or missing subcommand for 'credential'"), + } +}