Compare commits
No commits in common. "d0486f8d824d0426582d910220a39a43cc69c717" and "cf153397129604912b7017a8fbcc96bd61117a7c" have entirely different histories.
d0486f8d82
...
cf15339712
@ -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(),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
175
src/db.rs
175
src/db.rs
@ -1,13 +1,12 @@
|
|||||||
use super::crypt;
|
use super::crypt;
|
||||||
use crate::crypt::EncryptedValue;
|
use crate::crypt::EncryptedValue;
|
||||||
use rusqlite::{params, Connection};
|
use rusqlite::{params, Connection, NO_PARAMS};
|
||||||
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: &str = include_str!("init.sql");
|
static DB_INIT_QUERY: &'static str = include_str!("init.sql");
|
||||||
|
|
||||||
pub struct DbHandle {
|
pub struct DbHandle {
|
||||||
conn: Connection,
|
conn: Connection,
|
||||||
@ -19,16 +18,19 @@ struct DbProperty {
|
|||||||
value: Option<String>,
|
value: Option<String>,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[derive(Debug)]
|
||||||
|
pub struct Account {
|
||||||
|
pub id: i64,
|
||||||
|
pub host: String,
|
||||||
|
pub user: String,
|
||||||
|
pub password: String,
|
||||||
|
}
|
||||||
|
|
||||||
pub struct DbNamespace {
|
pub struct DbNamespace {
|
||||||
pub id: i64,
|
pub id: i64,
|
||||||
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,
|
||||||
@ -50,13 +52,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(PathBuf::from)
|
.map(|path: &String| PathBuf::from(path))
|
||||||
.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 }
|
DbHandle { conn: conn }
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn get_namespace_id(
|
pub fn get_namespace_id(
|
||||||
@ -93,7 +95,7 @@ impl DbHandle {
|
|||||||
)
|
)
|
||||||
.unwrap();
|
.unwrap();
|
||||||
let rowid: i64 = tx.last_insert_rowid();
|
let rowid: i64 = tx.last_insert_rowid();
|
||||||
tx.commit().unwrap();
|
let _ = tx.commit().unwrap();
|
||||||
Ok(rowid)
|
Ok(rowid)
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -125,7 +127,7 @@ impl DbHandle {
|
|||||||
)
|
)
|
||||||
.unwrap();
|
.unwrap();
|
||||||
|
|
||||||
tx.commit().unwrap();
|
let _ = 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>> {
|
||||||
@ -152,37 +154,13 @@ 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) => Err(e),
|
Err(e) => return 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
|
||||||
@ -215,14 +193,127 @@ 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: &[u8]) {
|
pub fn set_db_property_bytes(&self, name: &str, value: &Vec<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 {
|
pub fn list_accounts(&mut self, master_key: [u8; 32]) -> Vec<Account> {
|
||||||
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
|
let mut stmt = self.conn
|
||||||
write!(f, "{}", self.name)
|
.prepare("SELECT h.iv, h.ciphertext, h.mac, u.iv, u.ciphertext, u.mac, p.iv, p.ciphertext, p.mac, a.id FROM accounts a \
|
||||||
|
LEFT JOIN encrypted_values h ON a.server=h.id \
|
||||||
|
LEFT JOIN encrypted_values u ON a.user=u.id \
|
||||||
|
LEFT JOIN encrypted_values p ON a.password=p.id")
|
||||||
|
.unwrap();
|
||||||
|
let result: Vec<Account> = {
|
||||||
|
let props = stmt
|
||||||
|
.query_map(NO_PARAMS, |row| {
|
||||||
|
let host: String = String::from_utf8(decrypt_base64(
|
||||||
|
row.get(0).unwrap(),
|
||||||
|
row.get(1).unwrap(),
|
||||||
|
row.get(2).unwrap(),
|
||||||
|
master_key,
|
||||||
|
))
|
||||||
|
.unwrap();
|
||||||
|
let user: String = String::from_utf8(decrypt_base64(
|
||||||
|
row.get(3).unwrap(),
|
||||||
|
row.get(4).unwrap(),
|
||||||
|
row.get(5).unwrap(),
|
||||||
|
master_key,
|
||||||
|
))
|
||||||
|
.unwrap();
|
||||||
|
let password: String = String::from_utf8(decrypt_base64(
|
||||||
|
row.get(6).unwrap(),
|
||||||
|
row.get(7).unwrap(),
|
||||||
|
row.get(8).unwrap(),
|
||||||
|
master_key,
|
||||||
|
))
|
||||||
|
.unwrap();
|
||||||
|
Ok(Account {
|
||||||
|
id: row.get(9).unwrap(),
|
||||||
|
host: host,
|
||||||
|
user: user,
|
||||||
|
password: password,
|
||||||
|
})
|
||||||
|
})
|
||||||
|
.unwrap();
|
||||||
|
|
||||||
|
props.map(move |x| x.unwrap()).collect()
|
||||||
|
};
|
||||||
|
result
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn write_encrypted_value(&mut self, val: EncryptedValue) -> i64 {
|
||||||
|
let b64ciphertext: String = val.ciphertext.to_base64(base64::STANDARD);
|
||||||
|
let b64iv: String = val.iv.to_base64(base64::STANDARD);
|
||||||
|
let b64mac: String = val.mac.code().to_base64(base64::STANDARD);
|
||||||
|
let tx = self.conn.transaction().unwrap();
|
||||||
|
tx.execute(
|
||||||
|
"INSERT INTO encrypted_values (iv, ciphertext, mac) VALUES ($1, $2, $3)",
|
||||||
|
&[&b64iv, &b64ciphertext, &b64mac],
|
||||||
|
)
|
||||||
|
.unwrap();
|
||||||
|
let rowid: i64 = tx.last_insert_rowid();
|
||||||
|
let _ = tx.commit().unwrap();
|
||||||
|
rowid
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn write_account(
|
||||||
|
&mut self,
|
||||||
|
host: EncryptedValue,
|
||||||
|
username: EncryptedValue,
|
||||||
|
password: EncryptedValue,
|
||||||
|
) -> i64 {
|
||||||
|
// TODO: This should be a transaction
|
||||||
|
let host_id = self.write_encrypted_value(host);
|
||||||
|
let user_id = self.write_encrypted_value(username);
|
||||||
|
let password_id = self.write_encrypted_value(password);
|
||||||
|
self.conn
|
||||||
|
.execute(
|
||||||
|
"INSERT INTO accounts (server, user, password) VALUES ($1, $2, $3)",
|
||||||
|
&[&host_id, &user_id, &password_id],
|
||||||
|
)
|
||||||
|
.unwrap();
|
||||||
|
self.conn.last_insert_rowid()
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn delete_account_with_host(&mut self, master_key: [u8; 32], host: &str) {
|
||||||
|
let accounts: Vec<Account> = self.list_accounts(master_key);
|
||||||
|
let tx = self.conn.transaction().unwrap();
|
||||||
|
|
||||||
|
for account in accounts {
|
||||||
|
if account.host == host {
|
||||||
|
tx.execute(
|
||||||
|
"DELETE FROM encrypted_values WHERE exists \
|
||||||
|
(SELECT 1 FROM accounts WHERE \
|
||||||
|
(accounts.server = encrypted_values.id OR \
|
||||||
|
accounts.user = encrypted_values.id OR \
|
||||||
|
accounts.password = encrypted_values.id) AND \
|
||||||
|
accounts.id=$1);",
|
||||||
|
&[&account.id],
|
||||||
|
)
|
||||||
|
.unwrap();
|
||||||
|
tx.execute("DELETE FROM accounts WHERE id=$1;", &[&account.id])
|
||||||
|
.unwrap();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
let _ = tx.commit().unwrap();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fn decrypt_base64(iv: String, ciphertext: String, mac: String, master_key: [u8; 32]) -> Vec<u8> {
|
||||||
|
let mut iv_bytes: [u8; 32] = [0; 32];
|
||||||
|
let mut mac_bytes: [u8; 32] = [0; 32];
|
||||||
|
|
||||||
|
iv_bytes.clone_from_slice(&iv.from_base64().unwrap());
|
||||||
|
mac_bytes.clone_from_slice(&mac.from_base64().unwrap());
|
||||||
|
|
||||||
|
let decrypted: Vec<u8> = crypt::decrypt_value(
|
||||||
|
ciphertext.from_base64().unwrap(),
|
||||||
|
master_key,
|
||||||
|
iv_bytes,
|
||||||
|
mac_bytes,
|
||||||
|
);
|
||||||
|
decrypted
|
||||||
|
}
|
||||||
|
@ -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)
|
||||||
|
19
src/init.sql
19
src/init.sql
@ -1,10 +1,29 @@
|
|||||||
PRAGMA foreign_keys = ON;
|
PRAGMA foreign_keys = ON;
|
||||||
|
|
||||||
|
CREATE TABLE IF NOT EXISTS encrypted_values (
|
||||||
|
id INTEGER PRIMARY KEY AUTOINCREMENT,
|
||||||
|
iv TEXT,
|
||||||
|
ciphertext TEXT,
|
||||||
|
mac TEXT
|
||||||
|
);
|
||||||
|
|
||||||
CREATE TABLE IF NOT EXISTS props(
|
CREATE TABLE IF NOT EXISTS props(
|
||||||
name TEXT NOT NULL PRIMARY KEY,
|
name TEXT NOT NULL PRIMARY KEY,
|
||||||
value TEXT
|
value TEXT
|
||||||
);
|
);
|
||||||
|
|
||||||
|
CREATE TABLE IF NOT EXISTS encrypted_props(
|
||||||
|
name TEXT NOT NULL PRIMARY KEY,
|
||||||
|
encrypted_value INTEGER NOT NULL
|
||||||
|
);
|
||||||
|
|
||||||
|
CREATE TABLE IF NOT EXISTS accounts(
|
||||||
|
id INTEGER PRIMARY KEY AUTOINCREMENT,
|
||||||
|
server INTEGER NOT NULL,
|
||||||
|
user INTEGER NOT NULL,
|
||||||
|
password INTEGER NOT NULL
|
||||||
|
);
|
||||||
|
|
||||||
CREATE TABLE IF NOT EXISTS namespaces(
|
CREATE TABLE IF NOT EXISTS namespaces(
|
||||||
id INTEGER PRIMARY KEY AUTOINCREMENT,
|
id INTEGER PRIMARY KEY AUTOINCREMENT,
|
||||||
name BLOB NOT NULL
|
name BLOB NOT NULL
|
||||||
|
120
src/main.rs
120
src/main.rs
@ -1,9 +1,7 @@
|
|||||||
#![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;
|
||||||
use dialoguer::{theme::ColorfulTheme, Input, PasswordInput, Select};
|
use dialoguer::{theme::ColorfulTheme, Input, PasswordInput};
|
||||||
use docopt::Docopt;
|
use docopt::Docopt;
|
||||||
use log::debug;
|
use log::debug;
|
||||||
use rand::rngs::OsRng;
|
use rand::rngs::OsRng;
|
||||||
@ -16,21 +14,20 @@ pub mod crypt;
|
|||||||
pub mod db;
|
pub mod db;
|
||||||
pub mod generate;
|
pub mod generate;
|
||||||
|
|
||||||
static USAGE: &str = "
|
static USAGE: &'static str = "
|
||||||
foil
|
foil
|
||||||
|
|
||||||
Usage:
|
Usage:
|
||||||
foil set [--namespace=<ns>] [--db=<db>]
|
foil set [--namespace=<ns>] [--db=<db>]
|
||||||
foil get [--namespace=<ns>] [--db=<db>]
|
foil get [--namespace=<ns>] [--db=<db>]
|
||||||
foil list [--namespace=<ns>] [--db=<db>]
|
foil list [--db=<db>]
|
||||||
foil shell [--namespace=<ns>] [--db=<db>]
|
foil transfer [--db=<db>]
|
||||||
foil dump [--db=<db>]
|
foil dump [--db=<db>]
|
||||||
foil generate <spec>
|
foil generate <spec>
|
||||||
foil (-h | --help)
|
foil (-h | --help)
|
||||||
|
|
||||||
Options:
|
Options:
|
||||||
--db=<db> The path to the sqlite database [default: db.sqlite3].
|
--db=<db> The path to the sqlite database [default: db.sqlite3].
|
||||||
--src=<db> The path to the old sqlite database [default: db.sqlite3].
|
|
||||||
-n DB, --namespace=<db> An identifier for a group of secrets [default: main]
|
-n DB, --namespace=<db> An identifier for a group of secrets [default: main]
|
||||||
-h, --help Show this screen.
|
-h, --help Show this screen.
|
||||||
--version Show version.
|
--version Show version.
|
||||||
@ -42,10 +39,9 @@ struct Args {
|
|||||||
cmd_get: bool,
|
cmd_get: bool,
|
||||||
cmd_list: bool,
|
cmd_list: bool,
|
||||||
cmd_generate: bool,
|
cmd_generate: bool,
|
||||||
|
cmd_transfer: bool,
|
||||||
cmd_dump: bool,
|
cmd_dump: bool,
|
||||||
cmd_shell: bool,
|
|
||||||
flag_db: Option<String>,
|
flag_db: Option<String>,
|
||||||
flag_src: Option<String>,
|
|
||||||
flag_namespace: String,
|
flag_namespace: String,
|
||||||
arg_spec: Option<String>,
|
arg_spec: Option<String>,
|
||||||
}
|
}
|
||||||
@ -96,15 +92,17 @@ fn get_master_key(db_conn: &mut db::DbHandle) -> [u8; 32] {
|
|||||||
master_key
|
master_key
|
||||||
}
|
}
|
||||||
|
|
||||||
fn list(db_conn: &mut db::DbHandle, master_key: [u8; 32], namespace: &str) {
|
fn list(mut db_conn: db::DbHandle, master_key: [u8; 32]) {
|
||||||
for note in db_conn.read_notes(master_key).unwrap() {
|
for host in db_conn
|
||||||
if note.namespace == namespace && note.category == "account" {
|
.list_accounts(master_key)
|
||||||
println!("{}", note.title);
|
.into_iter()
|
||||||
}
|
.map(|account: db::Account| account.host)
|
||||||
|
{
|
||||||
|
println!("{}", host);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fn get(db_conn: &mut db::DbHandle, master_key: [u8; 32], namespace: &str) {
|
fn get(mut db_conn: db::DbHandle, master_key: [u8; 32], namespace: &str) {
|
||||||
println!("Reading a site from the database");
|
println!("Reading a site from the database");
|
||||||
let host: String = Input::with_theme(&ColorfulTheme::default())
|
let host: String = Input::with_theme(&ColorfulTheme::default())
|
||||||
.with_prompt("hostname")
|
.with_prompt("hostname")
|
||||||
@ -122,7 +120,7 @@ fn get(db_conn: &mut db::DbHandle, master_key: [u8; 32], namespace: &str) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fn set(db_conn: &mut db::DbHandle, master_key: [u8; 32], namespace: &str) {
|
fn set(mut db_conn: db::DbHandle, master_key: [u8; 32], namespace: &str) {
|
||||||
println!("Adding a site to the database");
|
println!("Adding a site to the database");
|
||||||
let host: String = Input::with_theme(&ColorfulTheme::default())
|
let host: String = Input::with_theme(&ColorfulTheme::default())
|
||||||
.with_prompt("hostname")
|
.with_prompt("hostname")
|
||||||
@ -150,7 +148,7 @@ fn set(db_conn: &mut db::DbHandle, master_key: [u8; 32], namespace: &str) {
|
|||||||
println!("Successfully added password");
|
println!("Successfully added password");
|
||||||
}
|
}
|
||||||
|
|
||||||
fn dump(db_conn: &mut db::DbHandle, master_key: [u8; 32]) {
|
fn dump(mut db_conn: db::DbHandle, master_key: [u8; 32]) {
|
||||||
for note in db_conn.read_notes(master_key).unwrap() {
|
for note in db_conn.read_notes(master_key).unwrap() {
|
||||||
println!("===== note =====");
|
println!("===== note =====");
|
||||||
println!("namespace: {}", note.namespace);
|
println!("namespace: {}", note.namespace);
|
||||||
@ -160,71 +158,19 @@ fn dump(db_conn: &mut db::DbHandle, master_key: [u8; 32]) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fn shell_generate() {
|
fn transfer(mut db_conn: db::DbHandle, master_key: [u8; 32]) {
|
||||||
let spec: String = Input::with_theme(&ColorfulTheme::default())
|
for account in db_conn.list_accounts(master_key).into_iter() {
|
||||||
.with_prompt("Password Spec")
|
let new_note = db::Note {
|
||||||
.default("30,AAAa111..".to_owned())
|
id: 0,
|
||||||
.interact()
|
namespace: "main".to_owned(),
|
||||||
.unwrap();
|
category: "account".to_owned(),
|
||||||
|
title: account.host,
|
||||||
generate::generate(&spec);
|
value: format!(
|
||||||
}
|
"username: {}\npassword: {}\n",
|
||||||
|
account.user, account.password
|
||||||
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 {
|
|
||||||
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())
|
|
||||||
.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),
|
|
||||||
"generate" => shell_generate(),
|
|
||||||
"change namespace" => {
|
|
||||||
namespace = change_namespace(db_conn, master_key);
|
|
||||||
}
|
|
||||||
"create namespace" => {
|
|
||||||
namespace = create_namespace(db_conn, master_key);
|
|
||||||
}
|
|
||||||
"exit" => break,
|
|
||||||
_ => panic!("Unrecognized command"),
|
|
||||||
};
|
};
|
||||||
|
db_conn.write_note(master_key, new_note);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -245,15 +191,15 @@ fn main() -> Result<(), Box<dyn Error>> {
|
|||||||
let master_key: [u8; 32] = get_master_key(&mut db_conn);
|
let master_key: [u8; 32] = get_master_key(&mut db_conn);
|
||||||
|
|
||||||
if args.cmd_set {
|
if args.cmd_set {
|
||||||
set(&mut db_conn, master_key, &args.flag_namespace);
|
set(db_conn, master_key, &args.flag_namespace);
|
||||||
} else if args.cmd_get {
|
} else if args.cmd_get {
|
||||||
get(&mut db_conn, master_key, &args.flag_namespace);
|
get(db_conn, master_key, &args.flag_namespace);
|
||||||
} else if args.cmd_list {
|
} else if args.cmd_list {
|
||||||
list(&mut db_conn, master_key, &args.flag_namespace);
|
list(db_conn, master_key);
|
||||||
|
} else if args.cmd_transfer {
|
||||||
|
transfer(db_conn, master_key);
|
||||||
} else if args.cmd_dump {
|
} else if args.cmd_dump {
|
||||||
dump(&mut db_conn, master_key);
|
dump(db_conn, master_key);
|
||||||
} else if args.cmd_shell {
|
|
||||||
shell(&mut db_conn, master_key, &args.flag_namespace);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
Ok(())
|
Ok(())
|
||||||
|
Loading…
x
Reference in New Issue
Block a user