104 lines
3.1 KiB
Rust
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);
|
|
}
|