Merge branch 'change_namespace'
This commit is contained in:
commit
d0486f8d82
@ -165,7 +165,7 @@ pub fn encrypt_value(value: &str, master_key: [u8; 32]) -> EncryptedValue {
|
|||||||
hmac.input(&output[..]);
|
hmac.input(&output[..]);
|
||||||
EncryptedValue {
|
EncryptedValue {
|
||||||
ciphertext: output,
|
ciphertext: output,
|
||||||
iv: iv,
|
iv,
|
||||||
mac: hmac.result(),
|
mac: hmac.result(),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
50
src/db.rs
50
src/db.rs
@ -4,9 +4,10 @@ use rusqlite::{params, Connection};
|
|||||||
use rustc_serialize::base64;
|
use rustc_serialize::base64;
|
||||||
use rustc_serialize::base64::{FromBase64, ToBase64};
|
use rustc_serialize::base64::{FromBase64, ToBase64};
|
||||||
use std::error::Error;
|
use std::error::Error;
|
||||||
|
use std::fmt;
|
||||||
use std::path::PathBuf;
|
use std::path::PathBuf;
|
||||||
|
|
||||||
static DB_INIT_QUERY: &'static str = include_str!("init.sql");
|
static DB_INIT_QUERY: &str = include_str!("init.sql");
|
||||||
|
|
||||||
pub struct DbHandle {
|
pub struct DbHandle {
|
||||||
conn: Connection,
|
conn: Connection,
|
||||||
@ -23,6 +24,11 @@ pub struct DbNamespace {
|
|||||||
pub name: EncryptedValue,
|
pub name: EncryptedValue,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub struct Namespace {
|
||||||
|
pub id: i64,
|
||||||
|
pub name: String,
|
||||||
|
}
|
||||||
|
|
||||||
pub struct DbNote {
|
pub struct DbNote {
|
||||||
pub id: i64,
|
pub id: i64,
|
||||||
pub namespace: DbNamespace,
|
pub namespace: DbNamespace,
|
||||||
@ -44,13 +50,13 @@ impl DbHandle {
|
|||||||
pub fn new(db_path: &Option<String>) -> DbHandle {
|
pub fn new(db_path: &Option<String>) -> DbHandle {
|
||||||
let path: PathBuf = db_path
|
let path: PathBuf = db_path
|
||||||
.as_ref()
|
.as_ref()
|
||||||
.map(|path: &String| PathBuf::from(path))
|
.map(PathBuf::from)
|
||||||
.unwrap_or_else(|| dirs::home_dir().unwrap().join(".foil").to_path_buf());
|
.unwrap_or_else(|| dirs::home_dir().unwrap().join(".foil").to_path_buf());
|
||||||
let mut conn: Connection = Connection::open(path).unwrap();
|
let mut conn: Connection = Connection::open(path).unwrap();
|
||||||
let tx = conn.transaction().unwrap();
|
let tx = conn.transaction().unwrap();
|
||||||
tx.execute_batch(DB_INIT_QUERY).unwrap();
|
tx.execute_batch(DB_INIT_QUERY).unwrap();
|
||||||
tx.commit().unwrap();
|
tx.commit().unwrap();
|
||||||
DbHandle { conn: conn }
|
DbHandle { conn }
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn get_namespace_id(
|
pub fn get_namespace_id(
|
||||||
@ -87,7 +93,7 @@ impl DbHandle {
|
|||||||
)
|
)
|
||||||
.unwrap();
|
.unwrap();
|
||||||
let rowid: i64 = tx.last_insert_rowid();
|
let rowid: i64 = tx.last_insert_rowid();
|
||||||
let _ = tx.commit().unwrap();
|
tx.commit().unwrap();
|
||||||
Ok(rowid)
|
Ok(rowid)
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -119,7 +125,7 @@ impl DbHandle {
|
|||||||
)
|
)
|
||||||
.unwrap();
|
.unwrap();
|
||||||
|
|
||||||
let _ = tx.commit().unwrap();
|
tx.commit().unwrap();
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn read_notes(&mut self, master_key: [u8; 32]) -> rusqlite::Result<Vec<Note>> {
|
pub fn read_notes(&mut self, master_key: [u8; 32]) -> rusqlite::Result<Vec<Note>> {
|
||||||
@ -146,13 +152,37 @@ impl DbHandle {
|
|||||||
title: note.title.decrypt_to_string(master_key).unwrap(),
|
title: note.title.decrypt_to_string(master_key).unwrap(),
|
||||||
value: note.value.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();
|
.collect();
|
||||||
|
|
||||||
notes
|
notes
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub fn list_namespaces(&mut self, master_key: [u8; 32]) -> rusqlite::Result<Vec<Namespace>> {
|
||||||
|
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<Vec<Namespace>, _> = 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<Option<String>, Box<dyn Error>> {
|
pub fn get_db_property(&self, name: &str) -> Result<Option<String>, Box<dyn Error>> {
|
||||||
let mut stmt = self
|
let mut stmt = self
|
||||||
.conn
|
.conn
|
||||||
@ -185,8 +215,14 @@ impl DbHandle {
|
|||||||
.map(|option| option.map(|prop| prop.from_base64().unwrap()))
|
.map(|option| option.map(|prop| prop.from_base64().unwrap()))
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn set_db_property_bytes(&self, name: &str, value: &Vec<u8>) {
|
pub fn set_db_property_bytes(&self, name: &str, value: &[u8]) {
|
||||||
let b64value: String = value.to_base64(base64::STANDARD);
|
let b64value: String = value.to_base64(base64::STANDARD);
|
||||||
self.set_db_property(name, &b64value);
|
self.set_db_property(name, &b64value);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
impl fmt::Display for Namespace {
|
||||||
|
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
|
||||||
|
write!(f, "{}", self.name)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
@ -5,7 +5,7 @@ use std::iter::FromIterator;
|
|||||||
|
|
||||||
pub fn generate(spec: &str) {
|
pub fn generate(spec: &str) {
|
||||||
let (len, rest) = {
|
let (len, rest) = {
|
||||||
let mut separated = spec.splitn(2, ",");
|
let mut separated = spec.splitn(2, ',');
|
||||||
let len = separated.next().unwrap();
|
let len = separated.next().unwrap();
|
||||||
let rest = separated.next().unwrap();
|
let rest = separated.next().unwrap();
|
||||||
(len, rest)
|
(len, rest)
|
||||||
|
53
src/main.rs
53
src/main.rs
@ -1,3 +1,5 @@
|
|||||||
|
#![warn(clippy::all)]
|
||||||
|
|
||||||
use crypto::hmac::Hmac;
|
use crypto::hmac::Hmac;
|
||||||
use crypto::mac::{Mac, MacResult};
|
use crypto::mac::{Mac, MacResult};
|
||||||
use crypto::sha2::Sha256;
|
use crypto::sha2::Sha256;
|
||||||
@ -14,7 +16,7 @@ pub mod crypt;
|
|||||||
pub mod db;
|
pub mod db;
|
||||||
pub mod generate;
|
pub mod generate;
|
||||||
|
|
||||||
static USAGE: &'static str = "
|
static USAGE: &str = "
|
||||||
foil
|
foil
|
||||||
|
|
||||||
Usage:
|
Usage:
|
||||||
@ -168,21 +170,58 @@ fn shell_generate() {
|
|||||||
generate::generate(&spec);
|
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 create_namespace(db_conn: &mut db::DbHandle, master_key: [u8; 32]) -> String {
|
||||||
|
let namespace: String = Input::with_theme(&ColorfulTheme::default())
|
||||||
|
.with_prompt("Namespace")
|
||||||
|
.default("main".to_owned())
|
||||||
|
.interact()
|
||||||
|
.unwrap();
|
||||||
|
namespace
|
||||||
|
}
|
||||||
|
|
||||||
|
fn shell(db_conn: &mut db::DbHandle, master_key: [u8; 32], _namespace: &str) {
|
||||||
|
let mut namespace: String = _namespace.to_owned();
|
||||||
|
|
||||||
loop {
|
loop {
|
||||||
let selections = &["get", "list", "set", "generate", "exit"];
|
let selections = &[
|
||||||
|
"get",
|
||||||
|
"list",
|
||||||
|
"set",
|
||||||
|
"generate",
|
||||||
|
"change namespace",
|
||||||
|
"create namespace",
|
||||||
|
"exit",
|
||||||
|
];
|
||||||
|
let main_menu_prompt = format!("Main Menu ({})", namespace);
|
||||||
|
|
||||||
let selection = Select::with_theme(&ColorfulTheme::default())
|
let selection = Select::with_theme(&ColorfulTheme::default())
|
||||||
.with_prompt("Main Menu")
|
.with_prompt(&main_menu_prompt)
|
||||||
.default(0)
|
.default(0)
|
||||||
.items(&selections[..])
|
.items(&selections[..])
|
||||||
.interact()
|
.interact()
|
||||||
.unwrap();
|
.unwrap();
|
||||||
match selections[selection] {
|
match selections[selection] {
|
||||||
"get" => get(db_conn, master_key, namespace),
|
"get" => get(db_conn, master_key, &namespace),
|
||||||
"list" => list(db_conn, master_key, namespace),
|
"list" => list(db_conn, master_key, &namespace),
|
||||||
"set" => set(db_conn, master_key, namespace),
|
"set" => set(db_conn, master_key, &namespace),
|
||||||
"generate" => shell_generate(),
|
"generate" => shell_generate(),
|
||||||
|
"change namespace" => {
|
||||||
|
namespace = change_namespace(db_conn, master_key);
|
||||||
|
}
|
||||||
|
"create namespace" => {
|
||||||
|
namespace = create_namespace(db_conn, master_key);
|
||||||
|
}
|
||||||
"exit" => break,
|
"exit" => break,
|
||||||
_ => panic!("Unrecognized command"),
|
_ => panic!("Unrecognized command"),
|
||||||
};
|
};
|
||||||
|
Loading…
Reference in New Issue
Block a user