Compare commits
	
		
			10 Commits
		
	
	
		
			cf15339712
			...
			d0486f8d82
		
	
	| Author | SHA1 | Date | |
|---|---|---|---|
| 
						 | 
					d0486f8d82 | ||
| 
						 | 
					ce003c18fb | ||
| 
						 | 
					a3c6655db1 | ||
| 
						 | 
					d2efce722e | ||
| 
						 | 
					1cd0dd2ca7 | ||
| 
						 | 
					b89b4ed329 | ||
| 
						 | 
					2bd0c77bdc | ||
| 
						 | 
					d9fd4be5d7 | ||
| 
						 | 
					1504f38141 | ||
| 
						 | 
					2fabbe8789 | 
@ -165,7 +165,7 @@ pub fn encrypt_value(value: &str, master_key: [u8; 32]) -> EncryptedValue {
 | 
			
		||||
    hmac.input(&output[..]);
 | 
			
		||||
    EncryptedValue {
 | 
			
		||||
        ciphertext: output,
 | 
			
		||||
        iv: iv,
 | 
			
		||||
        iv,
 | 
			
		||||
        mac: hmac.result(),
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
							
								
								
									
										175
									
								
								src/db.rs
									
									
									
									
									
								
							
							
						
						
									
										175
									
								
								src/db.rs
									
									
									
									
									
								
							@ -1,12 +1,13 @@
 | 
			
		||||
use super::crypt;
 | 
			
		||||
use crate::crypt::EncryptedValue;
 | 
			
		||||
use rusqlite::{params, Connection, NO_PARAMS};
 | 
			
		||||
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");
 | 
			
		||||
static DB_INIT_QUERY: &str = include_str!("init.sql");
 | 
			
		||||
 | 
			
		||||
pub struct DbHandle {
 | 
			
		||||
    conn: Connection,
 | 
			
		||||
@ -18,19 +19,16 @@ struct DbProperty {
 | 
			
		||||
    value: Option<String>,
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
#[derive(Debug)]
 | 
			
		||||
pub struct Account {
 | 
			
		||||
    pub id: i64,
 | 
			
		||||
    pub host: String,
 | 
			
		||||
    pub user: String,
 | 
			
		||||
    pub password: String,
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
pub struct DbNamespace {
 | 
			
		||||
    pub id: i64,
 | 
			
		||||
    pub name: EncryptedValue,
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
pub struct Namespace {
 | 
			
		||||
    pub id: i64,
 | 
			
		||||
    pub name: String,
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
pub struct DbNote {
 | 
			
		||||
    pub id: i64,
 | 
			
		||||
    pub namespace: DbNamespace,
 | 
			
		||||
@ -52,13 +50,13 @@ impl DbHandle {
 | 
			
		||||
    pub fn new(db_path: &Option<String>) -> DbHandle {
 | 
			
		||||
        let path: PathBuf = db_path
 | 
			
		||||
            .as_ref()
 | 
			
		||||
            .map(|path: &String| PathBuf::from(path))
 | 
			
		||||
            .map(PathBuf::from)
 | 
			
		||||
            .unwrap_or_else(|| dirs::home_dir().unwrap().join(".foil").to_path_buf());
 | 
			
		||||
        let mut conn: Connection = Connection::open(path).unwrap();
 | 
			
		||||
        let tx = conn.transaction().unwrap();
 | 
			
		||||
        tx.execute_batch(DB_INIT_QUERY).unwrap();
 | 
			
		||||
        tx.commit().unwrap();
 | 
			
		||||
        DbHandle { conn: conn }
 | 
			
		||||
        DbHandle { conn }
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    pub fn get_namespace_id(
 | 
			
		||||
@ -95,7 +93,7 @@ impl DbHandle {
 | 
			
		||||
        )
 | 
			
		||||
        .unwrap();
 | 
			
		||||
        let rowid: i64 = tx.last_insert_rowid();
 | 
			
		||||
        let _ = tx.commit().unwrap();
 | 
			
		||||
        tx.commit().unwrap();
 | 
			
		||||
        Ok(rowid)
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
@ -127,7 +125,7 @@ impl DbHandle {
 | 
			
		||||
        )
 | 
			
		||||
        .unwrap();
 | 
			
		||||
 | 
			
		||||
        let _ = tx.commit().unwrap();
 | 
			
		||||
        tx.commit().unwrap();
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    pub fn read_notes(&mut self, master_key: [u8; 32]) -> rusqlite::Result<Vec<Note>> {
 | 
			
		||||
@ -154,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<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>> {
 | 
			
		||||
        let mut stmt = self
 | 
			
		||||
            .conn
 | 
			
		||||
@ -193,127 +215,14 @@ impl DbHandle {
 | 
			
		||||
            .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);
 | 
			
		||||
        self.set_db_property(name, &b64value);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    pub fn list_accounts(&mut self, master_key: [u8; 32]) -> Vec<Account> {
 | 
			
		||||
        let mut stmt = self.conn
 | 
			
		||||
            .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
 | 
			
		||||
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) {
 | 
			
		||||
    let (len, rest) = {
 | 
			
		||||
        let mut separated = spec.splitn(2, ",");
 | 
			
		||||
        let mut separated = spec.splitn(2, ',');
 | 
			
		||||
        let len = separated.next().unwrap();
 | 
			
		||||
        let rest = separated.next().unwrap();
 | 
			
		||||
        (len, rest)
 | 
			
		||||
 | 
			
		||||
							
								
								
									
										19
									
								
								src/init.sql
									
									
									
									
									
								
							
							
						
						
									
										19
									
								
								src/init.sql
									
									
									
									
									
								
							@ -1,29 +1,10 @@
 | 
			
		||||
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(
 | 
			
		||||
       name TEXT NOT NULL PRIMARY KEY,
 | 
			
		||||
       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(
 | 
			
		||||
       id INTEGER PRIMARY KEY AUTOINCREMENT,
 | 
			
		||||
       name BLOB NOT NULL
 | 
			
		||||
 | 
			
		||||
							
								
								
									
										120
									
								
								src/main.rs
									
									
									
									
									
								
							
							
						
						
									
										120
									
								
								src/main.rs
									
									
									
									
									
								
							@ -1,7 +1,9 @@
 | 
			
		||||
#![warn(clippy::all)]
 | 
			
		||||
 | 
			
		||||
use crypto::hmac::Hmac;
 | 
			
		||||
use crypto::mac::{Mac, MacResult};
 | 
			
		||||
use crypto::sha2::Sha256;
 | 
			
		||||
use dialoguer::{theme::ColorfulTheme, Input, PasswordInput};
 | 
			
		||||
use dialoguer::{theme::ColorfulTheme, Input, PasswordInput, Select};
 | 
			
		||||
use docopt::Docopt;
 | 
			
		||||
use log::debug;
 | 
			
		||||
use rand::rngs::OsRng;
 | 
			
		||||
@ -14,20 +16,21 @@ pub mod crypt;
 | 
			
		||||
pub mod db;
 | 
			
		||||
pub mod generate;
 | 
			
		||||
 | 
			
		||||
static USAGE: &'static str = "
 | 
			
		||||
static USAGE: &str = "
 | 
			
		||||
foil
 | 
			
		||||
 | 
			
		||||
Usage:
 | 
			
		||||
  foil set [--namespace=<ns>] [--db=<db>]
 | 
			
		||||
  foil get [--namespace=<ns>] [--db=<db>]
 | 
			
		||||
  foil list [--db=<db>]
 | 
			
		||||
  foil transfer [--db=<db>]
 | 
			
		||||
  foil list [--namespace=<ns>] [--db=<db>]
 | 
			
		||||
  foil shell [--namespace=<ns>] [--db=<db>]
 | 
			
		||||
  foil dump [--db=<db>]
 | 
			
		||||
  foil generate <spec>
 | 
			
		||||
  foil (-h | --help)
 | 
			
		||||
 | 
			
		||||
Options:
 | 
			
		||||
  --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]
 | 
			
		||||
  -h, --help               Show this screen.
 | 
			
		||||
  --version                Show version.
 | 
			
		||||
@ -39,9 +42,10 @@ struct Args {
 | 
			
		||||
    cmd_get: bool,
 | 
			
		||||
    cmd_list: bool,
 | 
			
		||||
    cmd_generate: bool,
 | 
			
		||||
    cmd_transfer: bool,
 | 
			
		||||
    cmd_dump: bool,
 | 
			
		||||
    cmd_shell: bool,
 | 
			
		||||
    flag_db: Option<String>,
 | 
			
		||||
    flag_src: Option<String>,
 | 
			
		||||
    flag_namespace: String,
 | 
			
		||||
    arg_spec: Option<String>,
 | 
			
		||||
}
 | 
			
		||||
@ -92,17 +96,15 @@ fn get_master_key(db_conn: &mut db::DbHandle) -> [u8; 32] {
 | 
			
		||||
    master_key
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
fn list(mut db_conn: db::DbHandle, master_key: [u8; 32]) {
 | 
			
		||||
    for host in db_conn
 | 
			
		||||
        .list_accounts(master_key)
 | 
			
		||||
        .into_iter()
 | 
			
		||||
        .map(|account: db::Account| account.host)
 | 
			
		||||
    {
 | 
			
		||||
        println!("{}", host);
 | 
			
		||||
fn list(db_conn: &mut db::DbHandle, master_key: [u8; 32], namespace: &str) {
 | 
			
		||||
    for note in db_conn.read_notes(master_key).unwrap() {
 | 
			
		||||
        if note.namespace == namespace && note.category == "account" {
 | 
			
		||||
            println!("{}", note.title);
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
fn get(mut db_conn: db::DbHandle, master_key: [u8; 32], namespace: &str) {
 | 
			
		||||
fn get(db_conn: &mut db::DbHandle, master_key: [u8; 32], namespace: &str) {
 | 
			
		||||
    println!("Reading a site from the database");
 | 
			
		||||
    let host: String = Input::with_theme(&ColorfulTheme::default())
 | 
			
		||||
        .with_prompt("hostname")
 | 
			
		||||
@ -120,7 +122,7 @@ fn get(mut db_conn: db::DbHandle, master_key: [u8; 32], namespace: &str) {
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
fn set(mut db_conn: db::DbHandle, master_key: [u8; 32], namespace: &str) {
 | 
			
		||||
fn set(db_conn: &mut db::DbHandle, master_key: [u8; 32], namespace: &str) {
 | 
			
		||||
    println!("Adding a site to the database");
 | 
			
		||||
    let host: String = Input::with_theme(&ColorfulTheme::default())
 | 
			
		||||
        .with_prompt("hostname")
 | 
			
		||||
@ -148,7 +150,7 @@ fn set(mut db_conn: db::DbHandle, master_key: [u8; 32], namespace: &str) {
 | 
			
		||||
    println!("Successfully added password");
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
fn dump(mut db_conn: db::DbHandle, master_key: [u8; 32]) {
 | 
			
		||||
fn dump(db_conn: &mut db::DbHandle, master_key: [u8; 32]) {
 | 
			
		||||
    for note in db_conn.read_notes(master_key).unwrap() {
 | 
			
		||||
        println!("===== note =====");
 | 
			
		||||
        println!("namespace: {}", note.namespace);
 | 
			
		||||
@ -158,19 +160,71 @@ fn dump(mut db_conn: db::DbHandle, master_key: [u8; 32]) {
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
fn transfer(mut db_conn: db::DbHandle, master_key: [u8; 32]) {
 | 
			
		||||
    for account in db_conn.list_accounts(master_key).into_iter() {
 | 
			
		||||
        let new_note = db::Note {
 | 
			
		||||
            id: 0,
 | 
			
		||||
            namespace: "main".to_owned(),
 | 
			
		||||
            category: "account".to_owned(),
 | 
			
		||||
            title: account.host,
 | 
			
		||||
            value: format!(
 | 
			
		||||
                "username: {}\npassword: {}\n",
 | 
			
		||||
                account.user, account.password
 | 
			
		||||
            ),
 | 
			
		||||
fn shell_generate() {
 | 
			
		||||
    let spec: String = Input::with_theme(&ColorfulTheme::default())
 | 
			
		||||
        .with_prompt("Password Spec")
 | 
			
		||||
        .default("30,AAAa111..".to_owned())
 | 
			
		||||
        .interact()
 | 
			
		||||
        .unwrap();
 | 
			
		||||
 | 
			
		||||
    generate::generate(&spec);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
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);
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
@ -191,15 +245,15 @@ fn main() -> Result<(), Box<dyn Error>> {
 | 
			
		||||
    let master_key: [u8; 32] = get_master_key(&mut db_conn);
 | 
			
		||||
 | 
			
		||||
    if args.cmd_set {
 | 
			
		||||
        set(db_conn, master_key, &args.flag_namespace);
 | 
			
		||||
        set(&mut db_conn, master_key, &args.flag_namespace);
 | 
			
		||||
    } else if args.cmd_get {
 | 
			
		||||
        get(db_conn, master_key, &args.flag_namespace);
 | 
			
		||||
        get(&mut db_conn, master_key, &args.flag_namespace);
 | 
			
		||||
    } else if args.cmd_list {
 | 
			
		||||
        list(db_conn, master_key);
 | 
			
		||||
    } else if args.cmd_transfer {
 | 
			
		||||
        transfer(db_conn, master_key);
 | 
			
		||||
        list(&mut db_conn, master_key, &args.flag_namespace);
 | 
			
		||||
    } else if args.cmd_dump {
 | 
			
		||||
        dump(db_conn, master_key);
 | 
			
		||||
        dump(&mut db_conn, master_key);
 | 
			
		||||
    } else if args.cmd_shell {
 | 
			
		||||
        shell(&mut db_conn, master_key, &args.flag_namespace);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    Ok(())
 | 
			
		||||
 | 
			
		||||
		Loading…
	
	
			
			x
			
			
		
	
		Reference in New Issue
	
	Block a user