diff --git a/src/db.rs b/src/db.rs index 72e0e61..73bd05c 100644 --- a/src/db.rs +++ b/src/db.rs @@ -4,6 +4,7 @@ use rusqlite::{params, Connection}; use rustc_serialize::base64; use rustc_serialize::base64::{FromBase64, ToBase64}; use std::error::Error; +use std::fmt; use std::path::PathBuf; static DB_INIT_QUERY: &'static str = include_str!("init.sql"); @@ -23,6 +24,11 @@ pub struct DbNamespace { pub name: EncryptedValue, } +pub struct Namespace { + pub id: i64, + pub name: String, +} + pub struct DbNote { pub id: i64, pub namespace: DbNamespace, @@ -146,13 +152,37 @@ impl DbHandle { title: note.title.decrypt_to_string(master_key).unwrap(), value: note.value.decrypt_to_string(master_key).unwrap(), }), - Err(e) => return Err(e), + Err(e) => Err(e), }) .collect(); notes } + pub fn list_namespaces(&mut self, master_key: [u8; 32]) -> rusqlite::Result> { + let mut stmt = self + .conn + .prepare("SELECT id, name FROM namespaces") + .unwrap(); + let rows = stmt.query_map(params![], |row| { + Ok(DbNamespace { + id: row.get(0)?, + name: row.get(1)?, + }) + })?; + + let namespaces: Result, _> = rows + .map(|namespace_result| match namespace_result { + Ok(namespace) => Ok(Namespace { + id: namespace.id, + name: namespace.name.decrypt_to_string(master_key).unwrap(), + }), + Err(e) => Err(e), + }) + .collect(); + namespaces + } + pub fn get_db_property(&self, name: &str) -> Result, Box> { let mut stmt = self .conn @@ -190,3 +220,9 @@ impl DbHandle { self.set_db_property(name, &b64value); } } + +impl fmt::Display for Namespace { + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + write!(f, "{}", self.name) + } +} diff --git a/src/main.rs b/src/main.rs index 1e2be17..57f0306 100644 --- a/src/main.rs +++ b/src/main.rs @@ -1,3 +1,5 @@ +#![warn(clippy::all)] + use crypto::hmac::Hmac; use crypto::mac::{Mac, MacResult}; use crypto::sha2::Sha256; @@ -168,21 +170,38 @@ fn shell_generate() { generate::generate(&spec); } -fn shell(db_conn: &mut db::DbHandle, master_key: [u8; 32], namespace: &str) { +fn change_namespace(db_conn: &mut db::DbHandle, master_key: [u8; 32]) -> String { + let namespaces = db_conn.list_namespaces(master_key).unwrap(); + let selection = Select::with_theme(&ColorfulTheme::default()) + .with_prompt("Change Namespace") + .default(0) + .items(&namespaces[..]) + .interact() + .unwrap(); + namespaces[selection].name.to_owned() +} + +fn shell(db_conn: &mut db::DbHandle, master_key: [u8; 32], _namespace: &str) { + let mut namespace: String = _namespace.to_owned(); + loop { - let selections = &["get", "list", "set", "generate", "exit"]; + let selections = &["get", "list", "set", "generate", "change namespace", "exit"]; + let main_menu_prompt = format!("Main Menu ({})", namespace); let selection = Select::with_theme(&ColorfulTheme::default()) - .with_prompt("Main Menu") + .with_prompt(&main_menu_prompt) .default(0) .items(&selections[..]) .interact() .unwrap(); match selections[selection] { - "get" => get(db_conn, master_key, namespace), - "list" => list(db_conn, master_key, namespace), - "set" => set(db_conn, master_key, namespace), + "get" => get(db_conn, master_key, &namespace), + "list" => list(db_conn, master_key, &namespace), + "set" => set(db_conn, master_key, &namespace), "generate" => shell_generate(), + "change namespace" => { + namespace = change_namespace(db_conn, master_key); + } "exit" => break, _ => panic!("Unrecognized command"), };