|
diff --git a/client/examples/dump/main.rs b/client/examples/dump/main.rs |
|
new file mode 100644 |
|
index 00000000..3f57ee0f |
|
--- /dev/null |
|
+++ b/client/examples/dump/main.rs |
|
@@ -0,0 +1,25 @@ |
|
+use std::env; |
|
+use crypto::hashes::{blake2b::Blake2b256, Digest}; |
|
+use iota_stronghold as stronghold; |
|
+use stronghold::{KeyProvider, SnapshotPath, Stronghold}; |
|
+use zeroize::Zeroizing; |
|
+ |
|
+fn hash_blake2b(input: String) -> Zeroizing<Vec<u8>> { |
|
+ let mut hasher = Blake2b256::new(); |
|
+ hasher.update(input.as_bytes()); |
|
+ let mut hash = Zeroizing::new(vec![0_u8; Blake2b256::output_size()]); |
|
+ hasher.finalize_into((&mut hash[..]).into()); |
|
+ hash |
|
+} |
|
+ |
|
+#[tokio::main] |
|
+async fn main() { |
|
+ let args: Vec<String> = env::args().collect(); |
|
+ let stronghold = Stronghold::default(); |
|
+ let snapshot_path = SnapshotPath::from_path(args[1].to_string()); |
|
+ let key = hash_blake2b(args[2].to_string()); |
|
+ let keyprovider = KeyProvider::try_from(key).expect("Failed to load key"); |
|
+ print!("Loading snapshot from {}\n", &snapshot_path); |
|
+ stronghold.load_snapshot(&keyprovider, &snapshot_path).expect("Failed to load snapshot"); |
|
+ stronghold.dump(); |
|
+} |
|
diff --git a/client/src/types/stronghold.rs b/client/src/types/stronghold.rs |
|
index 33ff9ded..cfa5acc6 100644 |
|
--- a/client/src/types/stronghold.rs |
|
+++ b/client/src/types/stronghold.rs |
|
@@ -8,7 +8,7 @@ use crate::{ |
|
Snapshot, SnapshotPath, Store, UseKey, |
|
}; |
|
use crypto::keys::x25519; |
|
-use engine::vault::ClientId; |
|
+use engine::vault::{ClientId, types::DataTransaction}; |
|
use std::{ |
|
collections::{hash_map::Entry, HashMap}, |
|
ops::Deref, |
|
@@ -381,4 +381,83 @@ impl Stronghold { |
|
} |
|
Ok(()) |
|
} |
|
+ |
|
+ fn print_hex(prefix: &str, data: &[u8]) { |
|
+ let mut pfx = prefix; |
|
+ for line in 0 .. (data.len() + 15) / 16 { |
|
+ print!("{:25} ", pfx); |
|
+ let len = std::cmp::min(16, data.len() - line * 16); |
|
+ |
|
+ for i in 0 .. len { |
|
+ let mut ch = data[line * 16 + i]; |
|
+ if ch < 32 || ch > 126 { |
|
+ ch = b'.'; |
|
+ } |
|
+ print!("{}", ch as char); |
|
+ } |
|
+ for i in len .. 16 { |
|
+ print!(" "); |
|
+ } |
|
+ print!(" "); |
|
+ for i in 0 .. len { |
|
+ print!("{:02x} ", data[line * 16 + i]); |
|
+ } |
|
+ pfx = ""; |
|
+ println!(); |
|
+ } |
|
+ } |
|
+ |
|
+ pub fn dump(&self) { |
|
+ println!("Dumping clients..."); |
|
+ for key in self.snapshot.read().unwrap().deref().clients() { |
|
+ Self::print_hex("Client:", &key.0.as_ref()); |
|
+ let state = self.snapshot.read().unwrap().deref().get_state(key).unwrap(); |
|
+ for vaultid in state.0.keys() { |
|
+ Self::print_hex(" Key Vault:", &vaultid.0.as_ref()); |
|
+ let boxed = &state.0.get(vaultid).unwrap().key.boxed; |
|
+ boxed.unlock(); |
|
+ Self::print_hex(" Key:", boxed.as_slice()); |
|
+ boxed.lock(); |
|
+ } |
|
+ for vaultid in state.1.vaults.keys() { |
|
+ Self::print_hex(" DB Vault:", &vaultid.0.as_ref()); |
|
+ let vault = &state.1.vaults.get(vaultid).unwrap(); |
|
+ let key = &vault.key.key.boxed; |
|
+ key.unlock(); |
|
+ Self::print_hex(" Key:", key.as_slice()); |
|
+ key.lock(); |
|
+ for entry in vault.entries.clone() { |
|
+ Self::print_hex(" ChainID:", entry.0.as_ref()); |
|
+ let record = &entry.1; |
|
+ Self::print_hex(" Record ID:", record.id.as_ref()); |
|
+ Self::print_hex(" Record Data:", record.data.as_ref()); |
|
+ if entry.1.revoke.is_some() { |
|
+ Self::print_hex(" Record Revoke:", &record.revoke.as_ref().unwrap().as_ref()); |
|
+ } |
|
+ Self::print_hex(" Record Blob:", record.blob.as_ref()); |
|
+ println!(" Decrypted data transaction metadata:"); |
|
+ let ttxn = record.get_transaction(&vault.key).unwrap(); |
|
+ let txn = ttxn.typed::<DataTransaction>().unwrap(); |
|
+ Self::print_hex(" Type ID:", &u64::to_be_bytes(txn.type_id.u64())); |
|
+ Self::print_hex(" Len:", &u64::to_be_bytes(txn.len.u64())); |
|
+ Self::print_hex(" ID:", txn.id.as_ref()); |
|
+ Self::print_hex(" Blob ID:", txn.blob.as_ref()); |
|
+ Self::print_hex(" Record hint:", txn.record_hint.as_ref()); |
|
+ let blob = &entry.1.get_blob(&vault.key, entry.0).unwrap().boxed; |
|
+ blob.unlock(); |
|
+ Self::print_hex(" Decrypted data:", blob.as_slice()); |
|
+ if blob.as_slice().len() == 64 { |
|
+ println!(" (!!! MIGHT BE BIP39 SEED !!!)"); |
|
+ } |
|
+ blob.lock(); |
|
+ } |
|
+ let cache = state.clone().2; |
|
+ for cache_key in cache.keys() { |
|
+ Self::print_hex(" Cache key:", &cache_key); |
|
+ Self::print_hex(" Value:", cache.get(&cache_key).unwrap()); |
|
+ } |
|
+ } |
|
+ } |
|
+ println!("Done."); |
|
+ } |
|
} |
|
diff --git a/engine/runtime/src/boxed.rs b/engine/runtime/src/boxed.rs |
|
index 160cf7af..7bd48ca4 100644 |
|
--- a/engine/runtime/src/boxed.rs |
|
+++ b/engine/runtime/src/boxed.rs |
|
@@ -28,7 +28,7 @@ type RefCount = u8; |
|
|
|
/// A protected piece of memory. |
|
#[derive(Eq)] |
|
-pub(crate) struct Boxed<T: Bytes> { |
|
+pub struct Boxed<T: Bytes> { |
|
// the pointer to the underlying protected memory |
|
ptr: NonNull<T>, |
|
// The number of elements of type `T` that can be stored in the pointer. |
|
@@ -92,7 +92,7 @@ impl<T: Bytes> Boxed<T> { |
|
self.len * T::size() |
|
} |
|
|
|
- pub(crate) fn unlock(&self) -> &Self { |
|
+ pub fn unlock(&self) -> &Self { |
|
self.retain(Prot::ReadOnly); |
|
self |
|
} |
|
@@ -102,7 +102,7 @@ impl<T: Bytes> Boxed<T> { |
|
self |
|
} |
|
|
|
- pub(crate) fn lock(&self) { |
|
+ pub fn lock(&self) { |
|
self.release() |
|
} |
|
|
|
@@ -126,7 +126,7 @@ impl<T: Bytes> Boxed<T> { |
|
unsafe { self.ptr.as_mut() } |
|
} |
|
|
|
- pub(crate) fn as_slice(&self) -> &[T] { |
|
+ pub fn as_slice(&self) -> &[T] { |
|
assert!(self.prot.get() != Prot::NoAccess, "May not call Boxed while locked"); |
|
|
|
unsafe { slice::from_raw_parts(self.ptr.as_ptr(), self.len) } |
|
diff --git a/engine/runtime/src/memories/buffer.rs b/engine/runtime/src/memories/buffer.rs |
|
index a7599713..c7dbd0a7 100644 |
|
--- a/engine/runtime/src/memories/buffer.rs |
|
+++ b/engine/runtime/src/memories/buffer.rs |
|
@@ -23,7 +23,7 @@ use serde::{ |
|
/// This shall always be short lived |
|
#[derive(Clone, Eq)] |
|
pub struct Buffer<T: Bytes> { |
|
- boxed: Boxed<T>, // the boxed type of current GuardedVec, |
|
+ pub boxed: Boxed<T>, // the boxed type of current GuardedVec, |
|
} |
|
|
|
pub struct Ref<'a, T: Bytes> { |
|
diff --git a/engine/src/vault.rs b/engine/src/vault.rs |
|
index cfbc0c04..b2a834f2 100644 |
|
--- a/engine/src/vault.rs |
|
+++ b/engine/src/vault.rs |
|
@@ -18,7 +18,7 @@ |
|
|
|
mod base64; |
|
mod crypto_box; |
|
-mod types; |
|
+pub mod types; |
|
pub mod view; |
|
|
|
pub use crate::vault::{ |
|
diff --git a/engine/src/vault/view.rs b/engine/src/vault/view.rs |
|
index 3dc178c0..c914fc35 100644 |
|
--- a/engine/src/vault/view.rs |
|
+++ b/engine/src/vault/view.rs |
|
@@ -60,21 +60,21 @@ pub struct DbView<P: BoxProvider> { |
|
/// A enclave of data that is encrypted under one [`Key`]. |
|
#[derive(Deserialize, Serialize, Clone)] |
|
pub struct Vault<P: BoxProvider> { |
|
- key: Key<P>, |
|
- entries: HashMap<ChainId, Record>, |
|
+ pub key: Key<P>, |
|
+ pub entries: HashMap<ChainId, Record>, |
|
} |
|
|
|
/// A bit of data inside of a [`Vault`]. |
|
#[derive(Deserialize, Serialize, Clone)] |
|
pub struct Record { |
|
/// record id. |
|
- id: ChainId, |
|
+ pub id: ChainId, |
|
/// data transaction metadata. |
|
- data: SealedTransaction, |
|
+ pub data: SealedTransaction, |
|
/// revocation transaction metadata. |
|
- revoke: Option<SealedTransaction>, |
|
+ pub revoke: Option<SealedTransaction>, |
|
/// encrypted data in blob format. |
|
- blob: SealedBlob, |
|
+ pub blob: SealedBlob, |
|
} |
|
|
|
impl<P: BoxProvider> DbView<P> { |
|
@@ -464,7 +464,7 @@ impl Record { |
|
}) |
|
} |
|
|
|
- fn get_transaction<P: BoxProvider>(&self, key: &Key<P>) -> Result<Transaction, RecordError<P::Error>> { |
|
+ pub fn get_transaction<P: BoxProvider>(&self, key: &Key<P>) -> Result<Transaction, RecordError<P::Error>> { |
|
// check if a revocation transaction exists. |
|
if self.revoke.is_none() { |
|
// decrypt data transaction. |
|
@@ -500,7 +500,7 @@ impl Record { |
|
} |
|
|
|
/// Get the blob from this [`Record`]. |
|
- fn get_blob<P: BoxProvider>(&self, key: &Key<P>, id: ChainId) -> Result<Buffer<u8>, RecordError<P::Error>> { |
|
+ pub fn get_blob<P: BoxProvider>(&self, key: &Key<P>, id: ChainId) -> Result<Buffer<u8>, RecordError<P::Error>> { |
|
// check if ids match |
|
if self.id != id { |
|
return Err(RecordError::RecordNotFound(id)); |
|
-- |
|
2.41.0.windows.1 |
|
|