Remove the code for the old schema. As the only user of this password manager I don't need to worry about backwards compatibility.
This commit is contained in:
parent
2bd0c77bdc
commit
b89b4ed329
129
src/db.rs
129
src/db.rs
@ -1,6 +1,6 @@
|
||||
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;
|
||||
@ -18,14 +18,6 @@ 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,
|
||||
@ -197,123 +189,4 @@ impl DbHandle {
|
||||
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
|
||||
}
|
||||
|
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
|
||||
|
34
src/main.rs
34
src/main.rs
@ -21,7 +21,6 @@ Usage:
|
||||
foil set [--namespace=<ns>] [--db=<db>]
|
||||
foil get [--namespace=<ns>] [--db=<db>]
|
||||
foil list [--namespace=<ns>] [--db=<db>]
|
||||
foil transfer [--namespace=<ns>] [--db=<db>] [--src=<db>]
|
||||
foil dump [--db=<db>]
|
||||
foil generate <spec>
|
||||
foil (-h | --help)
|
||||
@ -40,7 +39,6 @@ struct Args {
|
||||
cmd_get: bool,
|
||||
cmd_list: bool,
|
||||
cmd_generate: bool,
|
||||
cmd_transfer: bool,
|
||||
cmd_dump: bool,
|
||||
flag_db: Option<String>,
|
||||
flag_src: Option<String>,
|
||||
@ -158,28 +156,6 @@ fn dump(mut db_conn: db::DbHandle, master_key: [u8; 32]) {
|
||||
}
|
||||
}
|
||||
|
||||
fn transfer(
|
||||
mut db_conn_src: db::DbHandle,
|
||||
mut db_conn_dest: db::DbHandle,
|
||||
master_key_src: [u8; 32],
|
||||
master_key_dest: [u8; 32],
|
||||
namespace: &str,
|
||||
) {
|
||||
for account in db_conn_src.list_accounts(master_key_src).into_iter() {
|
||||
let new_note = db::Note {
|
||||
id: 0,
|
||||
namespace: namespace.to_string(),
|
||||
category: "account".to_owned(),
|
||||
title: account.host,
|
||||
value: format!(
|
||||
"username: {}\npassword: {}\n",
|
||||
account.user, account.password
|
||||
),
|
||||
};
|
||||
db_conn_dest.write_note(master_key_dest, new_note);
|
||||
}
|
||||
}
|
||||
|
||||
fn main() -> Result<(), Box<dyn Error>> {
|
||||
pretty_env_logger::init();
|
||||
let args: Args = Docopt::new(USAGE)
|
||||
@ -202,16 +178,6 @@ fn main() -> Result<(), Box<dyn Error>> {
|
||||
get(db_conn, master_key, &args.flag_namespace);
|
||||
} else if args.cmd_list {
|
||||
list(db_conn, master_key, &args.flag_namespace);
|
||||
} else if args.cmd_transfer {
|
||||
let mut db_conn_src: db::DbHandle = db::DbHandle::new(&args.flag_src);
|
||||
let master_key_src: [u8; 32] = get_master_key(&mut db_conn_src);
|
||||
transfer(
|
||||
db_conn_src,
|
||||
db_conn,
|
||||
master_key_src,
|
||||
master_key,
|
||||
&args.flag_namespace,
|
||||
);
|
||||
} else if args.cmd_dump {
|
||||
dump(db_conn, master_key);
|
||||
}
|
||||
|
Loading…
x
Reference in New Issue
Block a user