diff --git a/src/db.rs b/src/db.rs index 4df284e..2f0b2e8 100644 --- a/src/db.rs +++ b/src/db.rs @@ -1,14 +1,23 @@ use base64::prelude::*; +use once_cell::sync::Lazy; + use std::collections::HashSet; use std::hash::{Hash, Hasher}; use std::fs; +use std::path::Path; use std::io::{self, Write, BufRead}; use std::fmt; use std::cmp::{PartialEq, Ordering}; +static STORAGE_FOLDER: Lazy = Lazy::new(|| "storage".to_string() ); +static STORAGE_PATH: Lazy = Lazy::new(|| { + format!("{}/db.mps", &*STORAGE_FOLDER) +}); + + pub struct Item { pub id: String, pub content: String @@ -84,15 +93,15 @@ impl Encoder { pub struct DB { pub items: HashSet::, - path: String, encoder: Encoder } impl DB { - pub fn new(path: &str, password: String) -> io::Result { + // TODO: make path as String too + pub fn new(password: String) -> io::Result { let encoder = Encoder::from(password); // TODO: throw error is password is incorrect - let file = fs::File::open(path)?; + let file = fs::File::open(&*STORAGE_PATH)?; let reader = io::BufReader::new(file); let mut items = HashSet::::new(); let mut id: Option = None; @@ -114,12 +123,38 @@ impl DB { } let result = DB { items: items, - path: String::from(path), encoder: encoder }; Ok(result) } + pub fn init(_passphrase: String) -> io::Result<()> { + // TODO: use pasphrase + fs::create_dir(&*STORAGE_FOLDER)?; + println!("Storage folder created"); + //let mut db = DB::init(&*STORAGE_PATH, pass)?; + + fs::File::create(&*STORAGE_PATH)?; + println!("Storage db created."); + println!("Initialization complete."); + println!(""); + println!("Now it's required to add folder `{}` under git manually.", &*STORAGE_FOLDER); + println!("Don't worry it's going to be encrypted."); + Ok(()) + } + + pub fn print_init_hint() { + println!("mps can work only when storage inited."); + println!("Hint: you can restore your storage if you have it already:"); + println!(" git clone {}", &*STORAGE_FOLDER); + println!("to init manually your storage and config") + } + + pub fn is_inited() -> bool { + let path = Path::new(&*STORAGE_FOLDER); + return path.exists(); + } + pub fn contains(&self, id: &String) -> bool { let item = Item::from_empty(id.clone()); self.items.contains(&item) @@ -129,7 +164,7 @@ impl DB { let mut file = fs::OpenOptions::new() .write(true) .append(false) - .open(&self.path)?; + .open(&*STORAGE_PATH)?; for item in self.items.iter() { writeln!(file, "{}", item.id)?; diff --git a/src/main.rs b/src/main.rs index b13cd1f..9872ed0 100644 --- a/src/main.rs +++ b/src/main.rs @@ -7,20 +7,10 @@ use db::{DB, Item}; use clap::{Parser, Subcommand}; use rpassword; -use once_cell::sync::Lazy; - -use std::fs; use std::io::{self, Write}; -use std::path::Path; use std::process; -static STORAGE_FOLDER: &str = "storage"; -static STORAGE_PATH: Lazy = Lazy::new(|| { - format!("{}/db.mps", STORAGE_FOLDER) -}); - - #[derive(Parser)] #[command(name = "mps", version = "0.0.1", about = "MyPasswordStorage: Tool for storing your passwords locally with git synchronization")] struct Cli { @@ -70,56 +60,43 @@ fn get_prompt(question: &str) -> io::Result { } // TODO: change password functionality - fn login() -> io::Result { - println!("Enter passphrase: "); + // TODO: check if inited + print!("Enter passphrase for storage: "); + io::stdout().flush()?; // TODO: check in db // TODO: return error if db is not inited let password = rpassword::read_password()?; if password != "pass" { - return Err(io::Error::new(io::ErrorKind::InvalidData, "Wrong password")); + return Err(io::Error::new(io::ErrorKind::InvalidData, "Wrong passphrase")); } Ok(String::from(password)) } -fn is_inited() -> bool { - let path = Path::new(STORAGE_FOLDER); - return path.exists(); -} - fn init() -> io::Result<()> { - if is_inited() { + if db::DB::is_inited() { return Err(io::Error::new(io::ErrorKind::AlreadyExists, "Reinitialization attempted")); } - print!("Enter passphrase for db: "); + print!("Enter passphrase for storage: "); io::stdout().flush()?; + // TODO: rename to passphrase let password = rpassword::read_password()?; print!("Reenter passphrase: "); io::stdout().flush()?; let password2 = rpassword::read_password()?; if password != password2 { - return Err(io::Error::new(io::ErrorKind::InvalidInput, "Passwords should be equal")); + return Err(io::Error::new(io::ErrorKind::InvalidInput, "Passwords must be equal")); } - fs::create_dir(STORAGE_FOLDER)?; - println!("Storage folder created"); - //let mut db = DB::init(&*STORAGE_PATH, pass)?; - - // TODO: enter password - // TODO: dont create storate if master password hasn't entered + db::DB::init(password)?; - fs::File::create(&*STORAGE_PATH)?; - println!("Storage db created."); - println!("Initialization complete."); - println!(""); - println!("Now it's required to add folder `{}` under git manually.", STORAGE_FOLDER); - println!("Don't worry it's going to be encrypted."); Ok(()) } fn add(id: &String) -> io::Result<()> { - let mut db = DB::new(&*STORAGE_PATH, String::from(""))?; + // TODO: get login passphrase + let mut db = DB::new(String::from(""))?; if db.contains(id) { // TODO: ask to edit existing in outer function which invoked this one return Err(io::Error::new( @@ -131,12 +108,12 @@ fn add(id: &String) -> io::Result<()> { let content = editor::open_to_edit()?; db.items.insert(Item::from(id.clone(), content)); db.dump()?; - + Ok(()) } fn list() -> io:: Result<()> { - let db = DB::new(&STORAGE_PATH, String::from(""))?; + let db = DB::new(String::from(""))?; let mut vec: Vec<_> = db.items.iter().collect(); vec.sort(); for item in &vec { @@ -158,18 +135,14 @@ fn run_command() -> io::Result<()> { list()?; } None => { - if !is_inited() { + if !db::DB::is_inited() { match get_prompt("Do you want to init your storage?")? { PROMPT::YES => init()?, - PROMPT::NO => { - println!("mps can work only when storage inited."); - println!("Hint: you can restore your storage if you have it already:"); - println!(" git clone {}", STORAGE_FOLDER); - println!("to init manually your storage and config") - }, - } + PROMPT::NO => db::DB::print_init_hint(), + } } else { login()?; + // TODO: list() } } } @@ -184,5 +157,5 @@ fn main() { process::exit(2); // TODO: better codes for different errors } } - } +