Skip to content

Commit

Permalink
Refactor vault trait (#25)
Browse files Browse the repository at this point in the history
* Change Vault's unlock signature + remove get_root

* Update vault implementations to match updated trait
  • Loading branch information
olanod committed Nov 29, 2022
1 parent 3247709 commit 7cef383
Show file tree
Hide file tree
Showing 6 changed files with 60 additions and 57 deletions.
2 changes: 1 addition & 1 deletion Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -31,7 +31,7 @@ path = "examples/account_generation.rs"
# name = "persisted_in_keyring"
# path = "examples/persisted_in_keyring.rs"

# needs feature vault_pass dirs
# needs feature vault_pass
# [[example]]
# name = "persisted_in_pass"
# path = "examples/persisted_in_pass.rs"
Expand Down
18 changes: 5 additions & 13 deletions examples/persisted_in_pass.rs
Original file line number Diff line number Diff line change
@@ -1,26 +1,18 @@
use libwallet::{
self,
vault::{Pass, PassCreds},
Language,
};
use dirs::home_dir;
use std::{error::Error};
use libwallet::{self, vault::Pass, Language};
use std::error::Error;
type Wallet = libwallet::Wallet<Pass>;

const SECRET_PATH: &str = "pandres95";

#[async_std::main]
async fn main() -> Result<(), Box<dyn Error>> {
// first argument is used as account
let account = std::env::args().skip(1).next().unwrap_or("default".into());
let mut store_path = home_dir().expect("Could not find home path");
store_path.push(".password-store");

let vault = Pass::new(store_path.to_str().unwrap(), Language::default());
let mut wallet = Wallet::new(vault);
wallet
.unlock(PassCreds {
secret_path: String::from(SECRET_PATH),
})
.await?;
wallet.unlock(account).await?;

let account = wallet.default_account();
println!("Default account: {}", account);
Expand Down
30 changes: 19 additions & 11 deletions src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -37,12 +37,12 @@ pub trait Vault {

/// Use a set of credentials to make the guarded keys available to the user.
/// It returns a `Future` to allow for vaults that might take an arbitrary amount
/// of time getting the secret ready like waiting for some user phisical interaction.
async fn unlock(&mut self, cred: impl Into<Self::Credentials>) -> Result<(), Self::Error>;

/// Get the root account container of the supported private key pairs
/// if the vault hasn't been unlocked it should return `None`
fn get_root(&self) -> Option<&RootAccount>;
/// of time getting the secret ready like waiting for some user physical interaction.
async fn unlock<T>(
&mut self,
cred: &Self::Credentials,
cb: impl FnMut(&RootAccount) -> T,
) -> Result<T, Self::Error>;
}

/// The root account is a container of the key pairs stored in the vault and cannot be
Expand Down Expand Up @@ -90,8 +90,9 @@ impl<'a> Derive for &'a RootAccount {
///
/// Wallets also support queuing and bulk signing of messages in case transactions need to be reviewed before signing.
#[derive(Debug)]
pub struct Wallet<V, const A: usize = 5, const M: usize = A> {
pub struct Wallet<V: Vault, const A: usize = 5, const M: usize = A> {
vault: V,
cached_creeds: Option<V::Credentials>,
default_account: Account,
accounts: ArrayVec<Account, A>,
pending_sign: ArrayVec<(Message, Option<u8>), M>, // message -> account index or default
Expand All @@ -108,6 +109,7 @@ where
default_account: Account::new(None),
accounts: ArrayVec::new_const(),
pending_sign: ArrayVec::new(),
cached_creeds: None,
}
}

Expand Down Expand Up @@ -138,18 +140,24 @@ where
credentials: impl Into<V::Credentials>,
) -> Result<(), Error<V::Error>> {
if self.is_locked() {
self.vault
.unlock(credentials)
let vault = &mut self.vault;
let def = &mut self.default_account;
let creds = credentials.into();

vault
.unlock(&creds, |root| {
def.unlock(root);
})
.await
.map_err(|e| Error::Vault(e))?;
self.default_account.unlock(self.vault.get_root().unwrap());
self.cached_creeds = Some(creds);
}
Ok(())
}

/// Check if the vault has been unlocked.
pub fn is_locked(&self) -> bool {
self.vault.get_root().is_none()
self.cached_creeds.is_none()
}

/// Sign a message with the default account and return the signature.
Expand Down
18 changes: 8 additions & 10 deletions src/vault/os.rs
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,6 @@ use crate::{
util::Pin,
RootAccount, Vault,
};
use core::future::Ready;
use keyring;

const SERVICE: &str = "libwallet_account";
Expand Down Expand Up @@ -93,21 +92,20 @@ impl Vault for OSKeyring {
type Credentials = Pin;
type Error = Error;

async fn unlock(&mut self, pin: impl Into<Self::Credentials>) -> Result<(), Self::Error> {
let pin = pin.into();
self.get_key(&pin)
async fn unlock<T>(
&mut self,
pin: &Self::Credentials,
mut cb: impl FnMut(&RootAccount) -> T,
) -> Result<T, Self::Error> {
self.get_key(pin)
.or_else(|err| {
self.auto_generate
.ok_or(err)
.and_then(|l| self.generate(&pin, l))
})
.and_then(move |r| {
.and_then(|r| {
self.root = Some(r);
Ok(())
Ok(cb(self.root.as_ref().unwrap()))
})
}

fn get_root(&self) -> Option<&RootAccount> {
self.root.as_ref()
}
}
36 changes: 20 additions & 16 deletions src/vault/pass.rs
Original file line number Diff line number Diff line change
@@ -1,4 +1,3 @@
use core::future::Ready;
use mnemonic::Language;
use prs_lib::{
crypto::{self, IsContext, Proto},
Expand All @@ -15,7 +14,7 @@ pub struct Pass {
auto_generate: Option<Language>,
}

const SERVICE_NAME: &str = "libwallet_service/";
const DEFAULT_DIR: &str = "libwallet_accounts/";

impl Pass {
/// Create a new `Pass` vault in the given location.
Expand All @@ -32,8 +31,8 @@ impl Pass {
}

fn get_key(&self, credentials: &PassCreds) -> Result<RootAccount, Error> {
let mut secret_path = String::from(SERVICE_NAME);
secret_path.push_str(&credentials.secret_path);
let mut secret_path = String::from(DEFAULT_DIR);
secret_path.push_str(&credentials.account);

let secret = match self.store.find(Some(secret_path)) {
FindSecret::Exact(secret) => Some(secret),
Expand Down Expand Up @@ -63,8 +62,8 @@ impl Pass {

let phrase = crate::util::gen_phrase(&mut rand_core::OsRng, lang);

let mut secret_path = String::from(SERVICE_NAME);
secret_path.push_str(&credentials.secret_path);
let mut secret_path = String::from(DEFAULT_DIR);
secret_path.push_str(&credentials.account);
let secret_path = self
.store
.normalize_secret_path(secret_path, None, true)
Expand Down Expand Up @@ -112,28 +111,33 @@ impl core::fmt::Display for Error {
impl std::error::Error for Error {}

pub struct PassCreds {
pub secret_path: String,
account: String,
}

impl From<String> for PassCreds {
fn from(account: String) -> Self {
PassCreds { account }
}
}

impl Vault for Pass {
type Credentials = PassCreds;
type Error = Error;

async fn unlock(&mut self, creds: impl Into<Self::Credentials>) -> Result<(), Self::Error> {
let creds = creds.into();
self.get_key(&creds)
async fn unlock<T>(
&mut self,
creds: &Self::Credentials,
mut cb: impl FnMut(&RootAccount) -> T,
) -> Result<T, Self::Error> {
self.get_key(creds)
.or_else(|err| {
self.auto_generate
.ok_or(err)
.and_then(|l| self.generate(&creds, l))
})
.and_then(move |r| {
.and_then(|r| {
self.root = Some(r);
Ok(())
Ok(cb(self.root.as_ref().unwrap()))
})
}

fn get_root(&self) -> Option<&RootAccount> {
self.root.as_ref()
}
}
13 changes: 7 additions & 6 deletions src/vault/simple.rs
Original file line number Diff line number Diff line change
Expand Up @@ -79,12 +79,13 @@ impl Vault for Simple {
type Credentials = ();
type Error = Error;

async fn unlock(&mut self, _cred: impl Into<Self::Credentials>) -> Result<(), Self::Error> {
async fn unlock<T>(
&mut self,
_cred: &Self::Credentials,
mut cb: impl FnMut(&RootAccount) -> T,
) -> Result<T, Self::Error> {
self.unlocked = self.locked.take();
Ok(())
}

fn get_root(&self) -> Option<&RootAccount> {
self.unlocked.as_ref()
let root_account = &self.unlocked.as_ref().unwrap();
Ok(cb(root_account))
}
}

0 comments on commit 7cef383

Please sign in to comment.