Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

refactor(autonomi): pass vault key as parameter #2165

Merged
merged 1 commit into from
Oct 1, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
29 changes: 20 additions & 9 deletions autonomi/src/client/files.rs
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,23 @@ pub struct Root {
pub map: HashMap<PathBuf, FilePointer>,
}

impl Root {
/// Deserialize from bytes.
pub fn from_bytes(data: Bytes) -> Result<Root, rmp_serde::decode::Error> {
let root: Root = rmp_serde::from_slice(&data[..])?;

Ok(root)
}

/// Serialize to bytes.
pub fn into_bytes(&self) -> Result<Bytes, rmp_serde::encode::Error> {
let root_serialized = rmp_serde::to_vec(&self)?;
let root_serialized = Bytes::from(root_serialized);

Ok(root_serialized)
}
}

/// Structure that describes a file on the network. The actual data is stored in
/// chunks, to be constructed with the address pointing to the data map.
///
Expand Down Expand Up @@ -46,13 +63,7 @@ impl Client {
pub async fn fetch_root(&mut self, address: XorName) -> Result<Root, UploadError> {
let data = self.get(address).await?;

Self::deserialize_root(data)
}

pub fn deserialize_root(data: Bytes) -> Result<Root, UploadError> {
let root: Root = rmp_serde::from_slice(&data[..]).expect("TODO");

Ok(root)
Ok(Root::from_bytes(data)?)
}

/// Fetch the file pointed to by the given pointer.
Expand Down Expand Up @@ -85,9 +96,9 @@ impl Client {
}

let root = Root { map };
let root_serialized = rmp_serde::to_vec(&root).expect("TODO");
let root_serialized = root.into_bytes()?;

let xor_name = self.put(Bytes::from(root_serialized), wallet).await?;
let xor_name = self.put(root_serialized, wallet).await?;

Ok((root, xor_name))
}
Expand Down
10 changes: 1 addition & 9 deletions autonomi/src/client/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -9,8 +9,6 @@ pub mod vault;

use std::{collections::HashSet, time::Duration};

#[cfg(feature = "vault")]
use bls::SecretKey;
use libp2p::{identity::Keypair, Multiaddr};
use sn_networking::{multiaddr_is_global, Network, NetworkBuilder, NetworkEvent};
use sn_protocol::{version::IDENTIFY_PROTOCOL_STR, CLOSE_GROUP_SIZE};
Expand All @@ -37,8 +35,6 @@ pub const CONNECT_TIMEOUT_SECS: u64 = 20;
#[derive(Clone)]
pub struct Client {
pub(crate) network: Network,
#[cfg(feature = "vault")]
pub(crate) vault_secret_key: Option<SecretKey>,
}

/// Error returned by [`Client::connect`].
Expand Down Expand Up @@ -88,11 +84,7 @@ impl Client {

receiver.await.expect("sender should not close")?;

Ok(Self {
network,
#[cfg(feature = "vault")]
vault_secret_key: None,
})
Ok(Self { network })
}
}

Expand Down
59 changes: 18 additions & 41 deletions autonomi/src/client/vault.rs
Original file line number Diff line number Diff line change
Expand Up @@ -17,8 +17,6 @@ use tracing::info;
pub enum VaultError {
#[error("Could not generate Vault secret key from entropy: {0:?}")]
Bls(#[from] bls::Error),
#[error("No Vault has been defined. Use `client.with_vault_entropy` to define one.")]
NoVaultPacketDefined,
#[error("Scratchpad found at {0:?} was not a valid record.")]
CouldNotDeserializeVaultScratchPad(ScratchpadAddress),
#[error("Protocol: {0}")]
Expand All @@ -28,37 +26,22 @@ pub enum VaultError {
}

impl Client {
/// Add a vault secret key to the client
///
/// The secret key is derived from the supplied entropy bytes.
pub fn with_vault_entropy(mut self, bytes: Bytes) -> Result<Self, VaultError> {
// simple hash as XORNAME_LEN == SK_LENs
let xorname = xor_name::XorName::from_content(&bytes);
// before generating the sk from these bytes.
self.vault_secret_key = Some(SecretKey::from_bytes(xorname.0)?);

Ok(self)
}

/// Retrieves and returns a decrypted vault if one exists.
pub async fn fetch_and_decrypt_vault(&self) -> Result<Option<Bytes>, VaultError> {
let Some(vault_secret_key) = self.vault_secret_key.as_ref() else {
return Err(VaultError::NoVaultPacketDefined);
};

let pad = self.get_vault_from_network().await?;
pub async fn fetch_and_decrypt_vault(
&self,
secret_key: &SecretKey,
) -> Result<Option<Bytes>, VaultError> {
let pad = self.get_vault_from_network(secret_key).await?;

Ok(pad.decrypt_data(vault_secret_key)?)
Ok(pad.decrypt_data(secret_key)?)
}

/// Gets the vault Scratchpad from a provided client public key
async fn get_vault_from_network(&self) -> Result<Scratchpad, VaultError> {
// let vault = self.vault.as_ref()?;
let Some(vault_secret_key) = self.vault_secret_key.as_ref() else {
return Err(VaultError::NoVaultPacketDefined);
};

let client_pk = vault_secret_key.public_key();
async fn get_vault_from_network(
&self,
secret_key: &SecretKey,
) -> Result<Scratchpad, VaultError> {
let client_pk = secret_key.public_key();

let scratch_address = ScratchpadAddress::new(client_pk);
let network_address = NetworkAddress::from_scratchpad_address(scratch_address);
Expand All @@ -85,23 +68,17 @@ impl Client {

/// Put data into the client's VaultPacket
///
/// Returns Ok(None) early if no vault packet is defined.
///
/// Pays for a new VaultPacket if none yet created for the client. Returns the current version
/// of the data on success.
pub async fn write_bytes_to_vault_if_defined(
pub async fn write_bytes_to_vault(
&mut self,
data: Bytes,
wallet: &mut Wallet,
) -> Result<Option<u64>, PutError> {
// Exit early if no vault packet defined
let Some(client_sk) = self.vault_secret_key.as_ref() else {
return Ok(None);
};

let client_pk = client_sk.public_key();
secret_key: &SecretKey,
) -> Result<u64, PutError> {
let client_pk = secret_key.public_key();

let pad_res = self.get_vault_from_network().await;
let pad_res = self.get_vault_from_network(secret_key).await;
let mut is_new = true;

let mut scratch = if let Ok(existing_data) = pad_res {
Expand All @@ -119,7 +96,7 @@ impl Client {
Scratchpad::new(client_pk)
};

let next_count = scratch.update_and_sign(data, client_sk);
let next_count = scratch.update_and_sign(data, secret_key);
let scratch_address = scratch.network_address();
let scratch_key = scratch_address.to_record_key();

Expand Down Expand Up @@ -172,6 +149,6 @@ impl Client {

self.network.put_record(record, &put_cfg).await?;

Ok(Some(next_count))
Ok(next_count)
}
}
28 changes: 10 additions & 18 deletions autonomi/tests/file.rs
Original file line number Diff line number Diff line change
Expand Up @@ -2,10 +2,6 @@ mod common;

use crate::common::{evm_network_from_env, evm_wallet_from_env_or_default};
use autonomi::Client;
#[cfg(feature = "vault")]
use bytes::Bytes;
#[cfg(feature = "vault")]
use eyre::bail;
use std::time::Duration;
use tokio::time::sleep;

Expand All @@ -18,9 +14,6 @@ async fn file() -> Result<(), Box<dyn std::error::Error>> {
let mut client = Client::connect(&[]).await.unwrap();
let wallet = evm_wallet_from_env_or_default(network);

// let data = common::gen_random_data(1024 * 1024 * 1000);
// let user_key = common::gen_random_data(32);

let (root, addr) = client
.upload_from_dir("tests/file/test_dir".into(), &wallet)
.await?;
Expand All @@ -44,38 +37,37 @@ async fn file_into_vault() -> eyre::Result<()> {

let network = evm_network_from_env();

let mut client = Client::connect(&[])
.await?
.with_vault_entropy(Bytes::from("at least 32 bytes of entropy here"))?;

let wallet = evm_wallet_from_env_or_default(network);
let mut client = Client::connect(&[]).await?;
let mut wallet = evm_wallet_from_env_or_default(network);
let client_sk = bls::SecretKey::random();

let (root, addr) = client
.upload_from_dir("tests/file/test_dir".into(), &wallet)
.await?;
sleep(Duration::from_secs(2)).await;

let root_fetched = client.fetch_root(addr).await?;
client
.write_bytes_to_vault(root.into_bytes()?, &mut wallet, &client_sk)
.await?;

assert_eq!(
root.map, root_fetched.map,
"root fetched should match root put"
);

// now assert over the stored account packet
let new_client = Client::connect(&[])
.await?
.with_vault_entropy(Bytes::from("at least 32 bytes of entropy here"))?;
let new_client = Client::connect(&[]).await?;

if let Some(ap) = new_client.fetch_and_decrypt_vault().await? {
let ap_root_fetched = Client::deserialize_root(ap)?;
if let Some(ap) = new_client.fetch_and_decrypt_vault(&client_sk).await? {
let ap_root_fetched = autonomi::client::files::Root::from_bytes(ap)?;

assert_eq!(
root.map, ap_root_fetched.map,
"root fetched should match root put"
);
} else {
bail!("No account packet found");
eyre::bail!("No account packet found");
}

Ok(())
Expand Down
Loading