Use kvstore as backing
Signed-off-by: Lee Smet <lee.smet@hotmail.com>
This commit is contained in:
parent
e9b867a36e
commit
7b1908b676
@ -3,6 +3,10 @@ name = "vault"
|
||||
version = "0.1.0"
|
||||
edition = "2024"
|
||||
|
||||
[features]
|
||||
native = ["kv/native"]
|
||||
wasm = ["kv/web"]
|
||||
|
||||
[dependencies]
|
||||
getrandom = { version = "0.3.3", features = ["wasm_js"] }
|
||||
rand = "0.9.1"
|
||||
@ -13,3 +17,4 @@ serde_json = "1.0.140"
|
||||
chacha20poly1305 = "0.10.1"
|
||||
k256 = { version = "0.13.4", features = ["ecdh"] }
|
||||
sha2 = "0.10.9"
|
||||
kv = { git = "https://git.ourworld.tf/samehabouelsaad/sal-modular", package = "kvstore", rev = "9dce815daa" }
|
||||
|
@ -7,6 +7,8 @@ pub enum Error {
|
||||
IOError(std::io::Error),
|
||||
/// A corrupt keyspace is returned if a keyspace can't be decrypted
|
||||
CorruptKeyspace,
|
||||
/// An error in the used key value store
|
||||
KV(kv::error::KVError),
|
||||
}
|
||||
|
||||
impl core::fmt::Display for Error {
|
||||
@ -15,6 +17,7 @@ impl core::fmt::Display for Error {
|
||||
Error::Crypto(e) => f.write_fmt(format_args!("crypto: {e}")),
|
||||
Error::IOError(e) => f.write_fmt(format_args!("io: {e}")),
|
||||
Error::CorruptKeyspace => f.write_str("corrupt keyspace"),
|
||||
Error::KV(e) => f.write_fmt(format_args!("kv: {e}")),
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -68,3 +71,9 @@ impl From<std::io::Error> for Error {
|
||||
Self::IOError(value)
|
||||
}
|
||||
}
|
||||
|
||||
impl From<kv::error::KVError> for Error {
|
||||
fn from(value: kv::error::KVError) -> Self {
|
||||
Self::KV(value)
|
||||
}
|
||||
}
|
||||
|
@ -1,21 +1,39 @@
|
||||
#[cfg(target_arch = "wasm32")]
|
||||
mod wasm;
|
||||
// #[cfg(not(target_arch = "wasm32"))]
|
||||
// mod fallback;
|
||||
// #[cfg(target_arch = "wasm32")]
|
||||
// mod wasm;
|
||||
|
||||
use std::{collections::HashMap, path::Path};
|
||||
|
||||
use crate::{
|
||||
error::Error,
|
||||
key::{Key, symmetric::SymmetricKey},
|
||||
};
|
||||
|
||||
// #[cfg(not(target_arch = "wasm32"))]
|
||||
// use fallback::KeySpace as Ks;
|
||||
// #[cfg(target_arch = "wasm32")]
|
||||
// use wasm::KeySpace as Ks;
|
||||
|
||||
#[cfg(not(target_arch = "wasm32"))]
|
||||
mod fallback;
|
||||
|
||||
use kv::native::NativeStore;
|
||||
#[cfg(target_arch = "wasm32")]
|
||||
use wasm::KeySpace as Ks;
|
||||
use kv::wasm::WasmStore;
|
||||
|
||||
#[cfg(not(target_arch = "wasm32"))]
|
||||
use fallback::KeySpace as Ks;
|
||||
|
||||
use crate::{error::Error, key::Key};
|
||||
const KEYSPACE_NAME: &str = "vault_keyspace";
|
||||
|
||||
/// A keyspace represents a group of stored cryptographic keys. The storage is encrypted, a
|
||||
/// password must be provided when opening the KeySpace to decrypt the keys.
|
||||
pub struct KeySpace {
|
||||
store: Ks,
|
||||
// store: Ks,
|
||||
#[cfg(not(target_arch = "wasm32"))]
|
||||
store: NativeStore,
|
||||
#[cfg(target_arch = "wasm32")]
|
||||
store: WasmStore,
|
||||
/// A collection of all keys stored in the KeySpace, in decrypted form.
|
||||
keys: HashMap<String, Key>,
|
||||
/// The encryption key used to encrypt/decrypt this keyspace.
|
||||
encryption_key: SymmetricKey,
|
||||
}
|
||||
|
||||
/// Wasm32 constructor
|
||||
@ -24,27 +42,71 @@ impl KeySpace {}
|
||||
|
||||
/// Non-wasm constructor
|
||||
#[cfg(not(target_arch = "wasm32"))]
|
||||
impl KeySpace {}
|
||||
impl KeySpace {
|
||||
/// Open the keyspace at the provided path using the given key for encryption.
|
||||
pub fn open(path: &Path, encryption_key: SymmetricKey) -> Result<Self, Error> {
|
||||
let store = NativeStore::open(&path.display().to_string())?;
|
||||
let mut ks = Self {
|
||||
store,
|
||||
keys: HashMap::new(),
|
||||
encryption_key,
|
||||
};
|
||||
ks.load_keyspace()?;
|
||||
Ok(ks)
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(target_arch = "wasm32")]
|
||||
impl KeySpace {
|
||||
pub async fn open(name: &str, encryption_key: SymmetricKey) -> Result<Self, Error> {
|
||||
let store = WasmStore::open(name).await?;
|
||||
todo!();
|
||||
// Ok(Self { store })
|
||||
}
|
||||
}
|
||||
|
||||
/// Exposed methods, platform independant
|
||||
impl KeySpace {
|
||||
/// Get a [`Key`] previously stored under the provided name.
|
||||
async fn get(&self, key: &str) -> Result<Option<Key>, Error> {
|
||||
todo!();
|
||||
pub async fn get(&self, key: &str) -> Result<Option<Key>, Error> {
|
||||
Ok(self.keys.get(key).cloned())
|
||||
}
|
||||
|
||||
/// Store a [`Key`] under the provided name.
|
||||
async fn set(&self, key: &str, value: Key) -> Result<(), Error> {
|
||||
todo!();
|
||||
///
|
||||
/// This overwrites the existing key if one is already stored with the same name.
|
||||
pub async fn set(&mut self, key: String, value: Key) -> Result<(), Error> {
|
||||
self.keys.insert(key, value);
|
||||
self.save_keyspace()
|
||||
}
|
||||
|
||||
/// Delete the [`Key`] stored under the provided name.
|
||||
async fn delete(&self, key: &str) -> Result<(), Error> {
|
||||
todo!();
|
||||
pub async fn delete(&mut self, key: &str) -> Result<(), Error> {
|
||||
self.keys.remove(key);
|
||||
self.save_keyspace()
|
||||
}
|
||||
|
||||
/// Iterate over all stored [`keys`](Key) in the KeySpace
|
||||
async fn iter(&self) -> Result<impl Iterator<Item = (String, Key)>, Error> {
|
||||
todo!()
|
||||
pub async fn iter(&self) -> Result<impl Iterator<Item = (&String, &Key)>, Error> {
|
||||
Ok(self.keys.iter())
|
||||
}
|
||||
|
||||
/// Encrypt all keys and save them to the underlying store
|
||||
async fn save_keyspace(&self) -> Result<(), Error> {
|
||||
// Bincode encode keys
|
||||
//
|
||||
// Put in store
|
||||
}
|
||||
|
||||
/// Loads the encrypted keyspace from the underlying storage
|
||||
async fn load_keyspace(&mut self) -> Result<(), Error> {
|
||||
let Some(ks) = self.store.get(KEYSPACE_NAME).await? else {
|
||||
// Keyspace doesn't exist yet, nothing to do here
|
||||
return Ok(());
|
||||
};
|
||||
|
||||
// TODO: bincode decode
|
||||
|
||||
todo!();
|
||||
}
|
||||
}
|
||||
|
Loading…
Reference in New Issue
Block a user