118 lines
3.4 KiB
Rust
118 lines
3.4 KiB
Rust
#[cfg(feature = "admin")]
|
|
// This module defines a tiny async interface for the "database" that this
|
|
// project uses for interfacing with the key store
|
|
|
|
// WARN: at the moment there are no guarantees as far as data integrity is
|
|
// concerned. This means there are no real transactions
|
|
use std::env;
|
|
use std::fs::OpenOptions;
|
|
use std::io::{BufWriter, BufReader};
|
|
use std::path::PathBuf;
|
|
use std::collections::HashMap;
|
|
use rocket::serde::{Serialize, Deserialize};
|
|
|
|
lazy_static! {
|
|
pub static ref DB_PATH: String = {
|
|
env::var("DB_PATH").unwrap_or("keys.db".into())
|
|
};
|
|
}
|
|
|
|
#[derive(Debug, Serialize, Deserialize)]
|
|
pub struct Database {
|
|
// uid's while random are fine to release as public as the key is more
|
|
// important however ideally neither should be release. Furthermore
|
|
// the frontend assists in keeping these secret by treating both as
|
|
// password fields as they are both randomly generated via a script
|
|
|
|
// uid -> key
|
|
users: HashMap<String,String>,
|
|
#[serde(skip)]
|
|
path: PathBuf
|
|
}
|
|
|
|
impl Database {
|
|
// Opens a handle to a database file
|
|
// if none is found then one is created with the new path
|
|
// if there is one then the existing database is used
|
|
// any thing else is invalid and causes this to return Err
|
|
pub fn new(path: PathBuf) -> Result<Self, std::io::Error> {
|
|
let file = OpenOptions::new()
|
|
.write(true)
|
|
.create(true)
|
|
.open(&path)?;
|
|
let writer = BufWriter::new(&file);
|
|
|
|
// Dummy value to write in place
|
|
let empty = Database { users: HashMap::new(), path: "".into() };
|
|
serde_json::to_writer(writer, &empty)?;
|
|
|
|
Ok(empty)
|
|
}
|
|
|
|
pub fn load(path: PathBuf) -> Result<Self, std::io::Error> {
|
|
let file = OpenOptions::new()
|
|
.read(true)
|
|
.open(&path)?;
|
|
let reader = BufReader::new(&file);
|
|
let mut data: Database = serde_json::from_reader(reader)?;
|
|
|
|
data.path = path;
|
|
return Ok(data);
|
|
}
|
|
|
|
pub fn get(&self, uid: &str) -> Option<&String> {
|
|
return self.users.get(uid);
|
|
}
|
|
|
|
fn write(&self) -> Result<(), std::io::Error> {
|
|
let file = OpenOptions::new()
|
|
.write(true)
|
|
.open(&self.path)?;
|
|
let writer = BufWriter::new(file);
|
|
serde_json::to_writer(writer, &self.path)?;
|
|
return Ok(())
|
|
}
|
|
|
|
pub fn remove(&mut self, uid: &str) -> Result<(), std::io::Error> {
|
|
self.users.remove_entry(uid);
|
|
self.write()
|
|
}
|
|
pub fn add(&mut self, key: &str, value: &str) -> Result<(), std::io::Error> {
|
|
println!("{:?}", self.path);
|
|
self.users.insert(key.into(), value.into());
|
|
self.write()
|
|
}
|
|
}
|
|
|
|
|
|
#[cfg(test)]
|
|
mod db_tests {
|
|
use super::Database;
|
|
|
|
const DB: &'static str = "new.db";
|
|
|
|
#[test]
|
|
fn load_db() {
|
|
match Database::new(DB.into()) {
|
|
Ok(db) => println!("Loaded new sample.db: {:?}", db),
|
|
Err(e) => panic!("Error fetching database: {}", e)
|
|
}
|
|
}
|
|
|
|
#[test]
|
|
fn add_simple_entries() {
|
|
match Database::load(DB.into()) {
|
|
Ok(mut db) => db.add("key", "value").unwrap(),
|
|
Err(e) => println!("Error adding entries: {}", e)
|
|
}
|
|
}
|
|
|
|
#[test]
|
|
fn remove_simple_entries() {
|
|
match Database::load(DB.into()) {
|
|
Ok(mut db) => db.remove("key").unwrap(),
|
|
Err(e) => println!("Error removing simple entries: {}", e)
|
|
}
|
|
}
|
|
}
|