Added the logout subcommand and show by default the app help when no subcommand is provided
Signed-off-by: Louis Vallat <louis@louis-vallat.xyz>
This commit is contained in:
parent
41b78b3bdb
commit
901ef7818d
32
src/main.rs
32
src/main.rs
@ -1,8 +1,9 @@
|
|||||||
use std::{fs::{File, create_dir}, io::{Read, Write}};
|
use std::{fs::{File, create_dir_all}, io::{Read, Write}, path::PathBuf};
|
||||||
|
|
||||||
use hyper_tls::HttpsConnector;
|
use hyper_tls::HttpsConnector;
|
||||||
use hyper::{Body, Client, body, client::HttpConnector};
|
use hyper::{Body, Client, body, client::HttpConnector};
|
||||||
use clap::{Arg, App, SubCommand};
|
use clap::{Arg, App, SubCommand};
|
||||||
|
use session::logout;
|
||||||
use crate::session::login;
|
use crate::session::login;
|
||||||
|
|
||||||
use dotenv::dotenv;
|
use dotenv::dotenv;
|
||||||
@ -19,18 +20,18 @@ pub async fn body_to_str(res: Body) -> String {
|
|||||||
return String::from_utf8(body::to_bytes(res).await.unwrap().to_vec()).unwrap();
|
return String::from_utf8(body::to_bytes(res).await.unwrap().to_vec()).unwrap();
|
||||||
}
|
}
|
||||||
|
|
||||||
fn get_config_folder() -> String {
|
fn get_config_folder() -> PathBuf {
|
||||||
let mut p = dirs::config_dir().unwrap();
|
let mut p = dirs::config_dir().unwrap();
|
||||||
p.push("Lychee_CLIent");
|
p.push("Lychee_CLIent");
|
||||||
return p.to_str().unwrap().to_string();
|
return p;
|
||||||
}
|
}
|
||||||
|
|
||||||
fn write_to_file(d: String, p: String) {
|
fn write_to_file(d: &str, p: &str) {
|
||||||
let mut o = File::create(p).expect("Cannot create file.");
|
let mut o = File::create(p).expect("Cannot create file.");
|
||||||
o.write_all(d.as_bytes()).expect("Cannot write to file.");
|
o.write_all(d.as_bytes()).expect("Cannot write to file.");
|
||||||
}
|
}
|
||||||
|
|
||||||
fn read_from_file(p: String) -> String {
|
fn read_from_file(p: &str) -> String {
|
||||||
let mut d = String::new();
|
let mut d = String::new();
|
||||||
let mut ifile = File::open(p).expect("Cannot open file.");
|
let mut ifile = File::open(p).expect("Cannot open file.");
|
||||||
ifile.read_to_string(&mut d).expect("Cannot read file.");
|
ifile.read_to_string(&mut d).expect("Cannot read file.");
|
||||||
@ -39,8 +40,8 @@ fn read_from_file(p: String) -> String {
|
|||||||
|
|
||||||
#[tokio::main]
|
#[tokio::main]
|
||||||
async fn main() -> Result<(), Box<dyn std::error::Error + Send + Sync>> {
|
async fn main() -> Result<(), Box<dyn std::error::Error + Send + Sync>> {
|
||||||
create_dir(get_config_folder()).expect("Cannot create folder.");
|
create_dir_all(get_config_folder()).expect("Cannot create folder.");
|
||||||
let matches = App::new("Lychee CLIent")
|
let mut app = App::new("Lychee CLIent")
|
||||||
.version("0.1.0")
|
.version("0.1.0")
|
||||||
.author("Louis Vallat <contact@louis-vallat.xyz>")
|
.author("Louis Vallat <contact@louis-vallat.xyz>")
|
||||||
.about("An Lychee CLI client written in Rust.")
|
.about("An Lychee CLI client written in Rust.")
|
||||||
@ -60,7 +61,11 @@ async fn main() -> Result<(), Box<dyn std::error::Error + Send + Sync>> {
|
|||||||
.value_name("PASSWORD")
|
.value_name("PASSWORD")
|
||||||
.help("Provide the password for the lychee account."))
|
.help("Provide the password for the lychee account."))
|
||||||
)
|
)
|
||||||
.get_matches();
|
.subcommand(
|
||||||
|
SubCommand::with_name("logout")
|
||||||
|
.about("Logout using the stored session cookie.")
|
||||||
|
);
|
||||||
|
let matches = app.clone().get_matches();
|
||||||
|
|
||||||
dotenv().ok();
|
dotenv().ok();
|
||||||
|
|
||||||
@ -71,12 +76,21 @@ async fn main() -> Result<(), Box<dyn std::error::Error + Send + Sync>> {
|
|||||||
};
|
};
|
||||||
|
|
||||||
|
|
||||||
|
let mut session_path = get_config_folder();
|
||||||
|
session_path.push("session");
|
||||||
|
|
||||||
if let Some(matches) = matches.subcommand_matches("login") {
|
if let Some(matches) = matches.subcommand_matches("login") {
|
||||||
let username = matches.value_of("username").unwrap();
|
let username = matches.value_of("username").unwrap();
|
||||||
let password = matches.value_of("password").unwrap();
|
let password = matches.value_of("password").unwrap();
|
||||||
let lychee_session = login(&client, username, password).await;
|
let lychee_session = login(&client, username, password).await;
|
||||||
write_to_file(lychee_session, get_config_folder() + "/session");
|
write_to_file(lychee_session.as_str(), session_path.to_str().unwrap());
|
||||||
|
} else if let Some(_) = matches.subcommand_matches("logout") {
|
||||||
|
let lychee_session = read_from_file(session_path.to_str().unwrap());
|
||||||
|
logout(&client, lychee_session.as_str()).await;
|
||||||
|
} else {
|
||||||
|
App::print_long_help(&mut app).unwrap();
|
||||||
}
|
}
|
||||||
|
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1,4 +1,4 @@
|
|||||||
use hyper::{Body, Method, Request, header::{AUTHORIZATION, CONTENT_TYPE, COOKIE, HeaderValue, SET_COOKIE}};
|
use hyper::{Body, Method, Request, header::{AUTHORIZATION, CONTENT_TYPE, COOKIE, SET_COOKIE}};
|
||||||
use json::object;
|
use json::object;
|
||||||
use crate::{LycheeClient, body_to_str};
|
use crate::{LycheeClient, body_to_str};
|
||||||
|
|
||||||
@ -12,7 +12,7 @@ pub async fn login(client: &LycheeClient, login: &str, password: &str) -> String
|
|||||||
.header(AUTHORIZATION, client.api_key.clone())
|
.header(AUTHORIZATION, client.api_key.clone())
|
||||||
.header(CONTENT_TYPE, "application/json")
|
.header(CONTENT_TYPE, "application/json")
|
||||||
.body(Body::from(login_data.dump()))
|
.body(Body::from(login_data.dump()))
|
||||||
.expect("error");
|
.expect("Cannot request Session::login.");
|
||||||
let res = client.client.request(req).await.unwrap();
|
let res = client.client.request(req).await.unwrap();
|
||||||
let headers = res.headers().get_all(SET_COOKIE)
|
let headers = res.headers().get_all(SET_COOKIE)
|
||||||
.iter().find(|&x| x.to_str().unwrap().starts_with("lychee_session")).unwrap().clone();
|
.iter().find(|&x| x.to_str().unwrap().starts_with("lychee_session")).unwrap().clone();
|
||||||
@ -22,22 +22,23 @@ pub async fn login(client: &LycheeClient, login: &str, password: &str) -> String
|
|||||||
return headers.to_str().unwrap().to_string();
|
return headers.to_str().unwrap().to_string();
|
||||||
}
|
}
|
||||||
|
|
||||||
pub async fn logout(client: &LycheeClient, lychee_session: &HeaderValue) {
|
pub async fn logout(client: &LycheeClient, lychee_session: &str) {
|
||||||
let req = Request::builder()
|
let req = Request::builder()
|
||||||
.method(Method::POST)
|
.method(Method::POST)
|
||||||
.uri(client.endpoint.clone() + "/api/Session::logout")
|
.uri(client.endpoint.clone() + "/api/Session::logout")
|
||||||
.header(COOKIE.as_str(), lychee_session)
|
.header(COOKIE, lychee_session)
|
||||||
.header(AUTHORIZATION, client.api_key.clone())
|
.header(AUTHORIZATION, client.api_key.clone())
|
||||||
.body(Body::empty())
|
.body(Body::empty())
|
||||||
.expect("error");
|
.expect("Cannot request Session::logout.");
|
||||||
let res = client.client.request(req).await.unwrap();
|
let res = client.client.request(req).await.unwrap();
|
||||||
assert!(json::parse(body_to_str(res.into_body()).await.as_str()).unwrap().as_bool().unwrap());
|
let body = body_to_str(res.into_body()).await;
|
||||||
|
if body != "true" { panic!("Error while logging in, expected true, server returned: {}", body); }
|
||||||
}
|
}
|
||||||
|
|
||||||
#[cfg(test)]
|
#[cfg(test)]
|
||||||
mod session_tests {
|
mod session_tests {
|
||||||
use hyper_tls::HttpsConnector;
|
use hyper_tls::HttpsConnector;
|
||||||
use hyper::{Client, header::HeaderValue};
|
use hyper::Client;
|
||||||
use json::object;
|
use json::object;
|
||||||
use mockito::mock;
|
use mockito::mock;
|
||||||
use crate::{LycheeClient, session::{login, logout}};
|
use crate::{LycheeClient, session::{login, logout}};
|
||||||
@ -61,7 +62,7 @@ mod session_tests {
|
|||||||
.match_header("cookie", "cookie value")
|
.match_header("cookie", "cookie value")
|
||||||
.create();
|
.create();
|
||||||
|
|
||||||
tokio_test::block_on(logout(&client, &HeaderValue::from_str("cookie value").unwrap()));
|
tokio_test::block_on(logout(&client, "cookie value"));
|
||||||
m.assert();
|
m.assert();
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -74,7 +75,7 @@ mod session_tests {
|
|||||||
.match_header("cookie", "cookie value")
|
.match_header("cookie", "cookie value")
|
||||||
.create();
|
.create();
|
||||||
|
|
||||||
tokio_test::block_on(logout(&client, &HeaderValue::from_str("cookie value").unwrap()));
|
tokio_test::block_on(logout(&client, "cookie value"));
|
||||||
m.assert();
|
m.assert();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Loading…
Reference in New Issue
Block a user