Merge pull request #179 from AleoHQ/login_command

Add initial version of the login command
This commit is contained in:
Sergey Isaev 2020-08-11 18:25:52 +03:00 committed by GitHub
commit 3980ff8e1e
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
8 changed files with 181 additions and 3 deletions

View File

@ -32,9 +32,11 @@ clap = { version = "2.33.0" }
colored = { version = "2.0" }
env_logger = { version = "0.7" }
from-pest = { version = "0.3.1" }
lazy_static = { version = "1.4.0" }
log = { version = "0.4" }
rand = { version = "0.7" }
rand_core = { version = "0.5.1" }
reqwest = { version = "0.10.7", features = ["blocking", "json"] }
serde = { version = "1.0", features = ["derive"] }
serde_json = { version = "1.0" }
toml = { version = "0.5" }

View File

@ -14,6 +14,8 @@ pub type ArgumentType = (NameType, DescriptionType, RequiredType, IndexType);
pub type FlagType = &'static str;
// Format
// (argument, conflicts, possible_values, requires)
pub type OptionType = (
&'static str,
&'static [&'static str],

143
leo/commands/login.rs Normal file
View File

@ -0,0 +1,143 @@
//
// Usege:
//
// leo login <token>
// leo login -u username -p password
// leo login // not yet implemented
//
use crate::{
cli::CLI,
cli_types::*,
errors::{
CLIError::LoginError,
LoginError::{CannotGetToken, ConnectionUnavalaible, WrongLoginOrPassword},
},
};
use lazy_static::lazy_static;
use std::{
collections::HashMap,
fs::{create_dir, File},
io,
io::prelude::*,
path::Path,
};
const PACKAGE_MANAGER_URL: &str = "https://apm-backend-dev.herokuapp.com/";
const LOGIN_URL: &str = "api/account/login";
const LEO_CREDENTIALS_DIR: &str = ".leo";
const LEO_CREDENTIALS_FILE: &str = "credentials";
lazy_static! {
static ref LEO_CREDENTIALS_PATH: String = format!("{}/{}", LEO_CREDENTIALS_DIR, LEO_CREDENTIALS_FILE);
}
#[derive(Debug)]
pub struct LoginCommand;
impl LoginCommand {
fn write_token(token: &str) -> Result<(), io::Error> {
let mut credentials = File::create(LEO_CREDENTIALS_PATH.as_str())?;
credentials.write_all(&token.as_bytes())?;
Ok(())
}
pub fn read_token() -> Result<String, io::Error> {
let mut credentials = File::open(LEO_CREDENTIALS_PATH.as_str())?;
let mut buf = String::new();
credentials.read_to_string(&mut buf)?;
Ok(buf)
}
}
impl CLI for LoginCommand {
// Format: token, username, password
type Options = (Option<String>, Option<String>, Option<String>);
type Output = ();
const ABOUT: AboutType = "Login to the package manager (*)";
const ARGUMENTS: &'static [ArgumentType] = &[
// (name, description, required, index)
("NAME", "Sets token for login to the package manager", false, 1u64),
];
const FLAGS: &'static [FlagType] = &[];
const NAME: NameType = "login";
const OPTIONS: &'static [OptionType] = &[
// (argument, conflicts, possible_values, requires)
("[username] -u --user=[username] 'Sets a username'", &[], &[], &[]),
("[password] -p --password=[password] 'Sets a password'", &[], &[], &[]),
];
const SUBCOMMANDS: &'static [SubCommandType] = &[];
fn parse(arguments: &clap::ArgMatches) -> Result<Self::Options, crate::errors::CLIError> {
if arguments.is_present("username") && arguments.is_present("password") {
return Ok((
None,
Some(arguments.value_of("username").unwrap().to_string()),
Some(arguments.value_of("password").unwrap().to_string()),
));
}
match arguments.value_of("NAME") {
Some(name) => Ok((Some(name.to_string()), None, None)),
None => {
// TODO implement JWT
Ok((None, None, None))
}
}
}
fn output(options: Self::Options) -> Result<Self::Output, crate::errors::CLIError> {
let token = match options {
// Login using existing token
(Some(token), _, _) => token,
// Login using username and password
(None, Some(username), Some(password)) => {
let client = reqwest::blocking::Client::new();
let url = format!("{}{}", PACKAGE_MANAGER_URL, LOGIN_URL);
let mut json = HashMap::new();
json.insert("email_username", username);
json.insert("password", password);
let response: HashMap<String, String> = match client.post(&url).json(&json).send() {
Ok(result) => match result.json() {
Ok(json) => json,
Err(_error) => {
log::error!("Wrong login or password");
return Err(LoginError(WrongLoginOrPassword("Wrong login or password".into())));
}
},
//Cannot connect to the server
Err(_error) => {
return Err(LoginError(ConnectionUnavalaible(
"Could not connect to the package manager".into(),
)));
}
};
match response.get("token") {
Some(token) => token.clone(),
None => return Err(LoginError(CannotGetToken("There is no token".into()))),
}
}
// Login using JWT
(_, _, _) => {
// TODO JWT
unimplemented!()
}
};
// Create Leo credentials directory if it not exists
if !Path::new(LEO_CREDENTIALS_DIR).exists() {
create_dir(LEO_CREDENTIALS_DIR)?;
}
LoginCommand::write_token(token.as_str())?;
log::info!("Successfully logged in");
Ok(())
}
}

View File

@ -16,6 +16,9 @@ pub use self::lint::*;
pub mod load;
pub use self::load::*;
pub mod login;
pub use self::login::*;
pub mod new;
pub use self::new::*;

View File

@ -30,6 +30,9 @@ pub enum CLIError {
#[error("{}", _0)]
LibFileError(LibFileError),
#[error("{}", _0)]
LoginError(LoginError),
#[error("{}", _0)]
MainFileError(MainFileError),
@ -123,6 +126,13 @@ impl From<LibFileError> for CLIError {
}
}
impl From<LoginError> for CLIError {
fn from(error: LoginError) -> Self {
log::error!("{}\n", error);
CLIError::LoginError(error)
}
}
impl From<MainFileError> for CLIError {
fn from(error: MainFileError) -> Self {
log::error!("{}\n", error);

View File

@ -0,0 +1,13 @@
use std::ffi::OsString;
#[derive(Debug, Error)]
pub enum LoginError {
#[error("{:?}", _0)]
CannotGetToken(OsString),
#[error("connectin unavalaible {:?}", _0)]
ConnectionUnavalaible(OsString),
#[error("wrong login or password {:?}", _0)]
WrongLoginOrPassword(OsString),
}

View File

@ -4,6 +4,9 @@ pub use self::build::*;
pub mod init;
pub use self::init::*;
pub mod login;
pub use self::login::*;
pub mod new;
pub use self::new::*;

View File

@ -30,9 +30,10 @@ fn main() -> Result<(), CLIError> {
SetupCommand::new().display_order(7),
ProveCommand::new().display_order(8),
RunCommand::new().display_order(9),
PublishCommand::new().display_order(10),
DeployCommand::new().display_order(11),
CleanCommand::new().display_order(12),
LoginCommand::new().display_order(10),
PublishCommand::new().display_order(11),
DeployCommand::new().display_order(12),
CleanCommand::new().display_order(13),
])
.set_term_width(0)
.get_matches();
@ -48,6 +49,7 @@ fn main() -> Result<(), CLIError> {
("setup", Some(arguments)) => SetupCommand::process(arguments),
("prove", Some(arguments)) => ProveCommand::process(arguments),
("run", Some(arguments)) => RunCommand::process(arguments),
("login", Some(arguments)) => LoginCommand::process(arguments),
("publish", Some(arguments)) => PublishCommand::process(arguments),
("deploy", Some(arguments)) => DeployCommand::process(arguments),
("clean", Some(arguments)) => CleanCommand::process(arguments),