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 super::crypt;
|
||||||
use crate::crypt::EncryptedValue;
|
use crate::crypt::EncryptedValue;
|
||||||
use rusqlite::{params, Connection, NO_PARAMS};
|
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;
|
||||||
@ -18,14 +18,6 @@ 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,
|
||||||
@ -197,123 +189,4 @@ impl DbHandle {
|
|||||||
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);
|
||||||
}
|
}
|
||||||
|
|
||||||
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;
|
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
|
||||||
|
34
src/main.rs
34
src/main.rs
@ -21,7 +21,6 @@ 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 [--namespace=<ns>] [--db=<db>]
|
||||||
foil transfer [--namespace=<ns>] [--db=<db>] [--src=<db>]
|
|
||||||
foil dump [--db=<db>]
|
foil dump [--db=<db>]
|
||||||
foil generate <spec>
|
foil generate <spec>
|
||||||
foil (-h | --help)
|
foil (-h | --help)
|
||||||
@ -40,7 +39,6 @@ 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,
|
||||||
flag_db: Option<String>,
|
flag_db: Option<String>,
|
||||||
flag_src: 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>> {
|
fn main() -> Result<(), Box<dyn Error>> {
|
||||||
pretty_env_logger::init();
|
pretty_env_logger::init();
|
||||||
let args: Args = Docopt::new(USAGE)
|
let args: Args = Docopt::new(USAGE)
|
||||||
@ -202,16 +178,6 @@ fn main() -> Result<(), Box<dyn Error>> {
|
|||||||
get(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(db_conn, master_key, &args.flag_namespace);
|
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 {
|
} else if args.cmd_dump {
|
||||||
dump(db_conn, master_key);
|
dump(db_conn, master_key);
|
||||||
}
|
}
|
||||||
|
Loading…
x
Reference in New Issue
Block a user