104 lines
3.1 KiB
Rust

use async_trait::async_trait;
use json;
use json::object::Object;
use std::path::Path;
use tokio::fs::File;
use tokio::io::AsyncReadExt; // for read_to_end()
use super::store::{Credentials, Store};
/// FileStore references a `store` file
pub struct FileStore {
path: String,
credentials: Vec<Credentials>,
}
impl FileStore {
fn new(path: String) -> Self {
FileStore {
path,
credentials: vec![],
}
}
/// 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<Credentials> = 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
);
}
}
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(&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);
return false;
}
let credentials = Credentials::from(data);
if credentials.is_empty() {
eprintln!("unable to parse the credentials correctly from the incoming request");
return false;
}
let contents = self.parse_contents().await;
self.auth(credentials.username, credentials.password)
}
}
#[tokio::test]
async fn test_store() {
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);
}