From 73059c724fc8335e8c6c4c6e1d48b98d97838374 Mon Sep 17 00:00:00 2001 From: landrigun Date: Thu, 29 Sep 2022 16:27:45 +0000 Subject: [PATCH] feat: #8 parse store file content and add test --- Cargo.toml | 3 ++ src/stores/file.rs | 85 +++++++++++++++++++++++++++++++------------- src/stores/store.rs | 6 ++-- tests/data/store.txt | 4 +++ 4 files changed, 70 insertions(+), 28 deletions(-) create mode 100644 tests/data/store.txt diff --git a/Cargo.toml b/Cargo.toml index 30c9f67..8dfcac0 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -12,6 +12,9 @@ regex = "1" tokio = { version = "1.21.1", features = ["full"] } async-trait = "0.1.57" +# useful for tests (embedded files should be delete in release ?) +#rust-embed="6.4.1" + [dependencies.async-std] version = "1.6" features = ["attributes"] diff --git a/src/stores/file.rs b/src/stores/file.rs index a9e7837..73dcf36 100644 --- a/src/stores/file.rs +++ b/src/stores/file.rs @@ -11,30 +11,65 @@ use super::store::{Credentials, Store}; /// FileStore references a `store` file pub struct FileStore { path: String, + credentials: Vec, } impl FileStore { fn new(path: String) -> Self { - FileStore { path } + FileStore { + path, + credentials: vec![], + } } - async fn parse_contents(&self, mut file: File) -> Vec { - let mut contents = vec![]; - let byte_read = file.read_to_end(&mut contents).await; - if byte_read.is_err() { - eprintln!( - "error occurred while reading store file: {}, err={:?}", - self.path, - byte_read.err() - ); + /// parse_contents loads and reads the file asynchonously + /// parses the file line by line to retrieve the credentials + async fn parse_contents(&mut self) { + let contents = tokio::fs::read_to_string(&self.path).await; + let mut credentials: Vec = vec![]; + match contents { + Ok(c) => { + let lines: Vec<&str> = c.split("\n").collect(); + for line in lines { + if line.starts_with("#") { + continue; + } + let line_split: Vec<&str> = line.split(":").collect(); + if line_split.len() != 2 { + continue; + } + credentials.push(Credentials::new( + line_split[0].to_string(), + line_split[1].to_string(), + )); + } + } + Err(e) => { + eprintln!( + "error occurred while reading store file: {}, err={:?}", + self.path, e + ); + } } - contents + self.credentials = credentials; + } + + fn auth(&self, username: String, password: String) -> bool { + let credentials: Vec<&Credentials> = self + .credentials + .iter() + .filter(|x| x.username == username && x.password == password) + .collect(); + if credentials.len() == 1 { + return true; + } + false } } #[async_trait] impl Store for FileStore { - async fn is_auth(&self, data: &json::JsonValue) -> bool { + async fn is_auth(&mut self, data: &json::JsonValue) -> bool { // ensure that the store file already exists even after its instanciation if !Path::new(&self.path).is_file() { eprintln!("{} path referencing file store does not exist", self.path); @@ -47,22 +82,22 @@ impl Store for FileStore { return false; } - let store = File::open(&self.path).await; - match store { - Ok(f) => { - let contents = self.parse_contents(f).await; - println!("file contents : {:?}", contents.len()); - return true; - } - Err(e) => eprintln!("error while opening the file {}, err={:?}", self.path, e), - } - false + let contents = self.parse_contents().await; + + self.auth(credentials.username, credentials.password) } } #[tokio::test] async fn test_store() { - let store = FileStore::new("/tmp/thegux.pid".to_string()); - let data = json::parse(r#"{"access_token": "toto", "refresh_token": "tutu"}"#).unwrap(); - assert_eq!(store.is_auth(&data).await, false); + use std::env; + + let root_path = env::var("CARGO_MANIFEST_DIR").unwrap(); + // TODO: path::Path should be better + let store_path = format!("{}/{}/{}/{}", root_path, "tests", "data", "store.txt"); + + let mut store = FileStore::new(store_path); + + let data = json::parse(r#"{"username": "toto", "password": "tata"}"#).unwrap(); + assert_eq!(store.is_auth(&data).await, true); } diff --git a/src/stores/store.rs b/src/stores/store.rs index a444225..50e679b 100644 --- a/src/stores/store.rs +++ b/src/stores/store.rs @@ -4,7 +4,7 @@ use json::object::Object; #[async_trait] pub trait Store { - async fn is_auth(&self, data: &json::JsonValue) -> bool; + async fn is_auth(&mut self, data: &json::JsonValue) -> bool; } /// extract_json_value extracts String json value from a key @@ -18,14 +18,14 @@ fn extract_json_value(data: &Object, key: &str) -> String { "".to_string() } -#[derive(Default)] +#[derive(Default, Debug)] pub struct Credentials { pub username: String, pub password: String, } impl Credentials { - fn new(username: String, password: String) -> Self { + pub fn new(username: String, password: String) -> Self { Credentials { username, password } } diff --git a/tests/data/store.txt b/tests/data/store.txt new file mode 100644 index 0000000..a9b0316 --- /dev/null +++ b/tests/data/store.txt @@ -0,0 +1,4 @@ +# this a test password storage with password in clear +# need to be updated in the future to encrypt or hash the password +# : +toto:tata