Skip to content

Commit

Permalink
feat(folders): Folders and AccPacket to accept an encryption key for …
Browse files Browse the repository at this point in the history
…metadata chunks
  • Loading branch information
bochaco committed Mar 18, 2024
1 parent 7596739 commit e21312b
Show file tree
Hide file tree
Showing 2 changed files with 65 additions and 20 deletions.
43 changes: 30 additions & 13 deletions sn_cli/src/subcommands/acc_packet.rs
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@

mod change_tracking;

use bls::PublicKey;
use change_tracking::*;

use super::files::ChunkManager;
Expand Down Expand Up @@ -58,6 +59,8 @@ pub struct AccountPacket {

impl AccountPacket {
/// Initialise directory as a fresh new packet with the given/random address for its root Folder.
// TODO: receive a SK which will be used for encrypting the files/folders metadata chunks. Currently,

Check notice

Code scanning / devskim

A "TODO" or similar was left in source code, possibly indicating incomplete functionality Note

Suspicious comment
// when the user requests to encrypt data, the provided Client's signer key is used.
pub fn init(
client: Client,
wallet_dir: &Path,
Expand Down Expand Up @@ -180,7 +183,7 @@ impl AccountPacket {
/// both pushing and pulling changes to/form the network.
pub async fn sync(&mut self, options: FilesUploadOptions) -> Result<()> {
let ChangesToApply { folders, mutations } =
self.scan_files_and_folders_for_changes(false)?;
self.scan_files_and_folders_for_changes(options.make_data_public)?;

if mutations.is_empty() {
println!("No local changes made to files/folders to be pushed to network.");
Expand Down Expand Up @@ -368,16 +371,20 @@ impl AccountPacket {

// Scan existing files and folders on disk, generating a report of all the detected
// changes based on the tracking info kept locally.
// TODO: encrypt the data-map and metadata if make_data_public is false.
fn scan_files_and_folders_for_changes(
&self,
_make_data_public: bool,
) -> Result<ChangesToApply> {
// If make_data_public is false the metadata chunks are encrypted.
fn scan_files_and_folders_for_changes(&self, make_data_public: bool) -> Result<ChangesToApply> {
// we don't use the local cache in order to realise of any changes made to files content.
let mut chunk_manager = ChunkManager::new(&self.tracking_info_dir);
chunk_manager.chunk_with_iter(self.iter_only_files(), false, false)?;

let mut changes = self.read_folders_hierarchy_from_disk()?;
// encrypt the metadata chunk if make_data_public is false.
let encryption_pk = if make_data_public {
None
} else {
Some(self.client.signer_pk())
};

let mut changes = self.read_folders_hierarchy_from_disk(encryption_pk)?;

// add chunked files to the corresponding Folders
let folders = &mut changes.folders;
Expand All @@ -392,13 +399,14 @@ impl AccountPacket {
Ok(Some(tracking_info)) => match &tracking_info.metadata.content {
FolderEntry::File(chunk) => {
if chunk.address() != &chunked_file.head_chunk_address {
// TODO: we need to encrypt the data-map and metadata if make_data_public is false.
let (entry_hash, meta_xorname, metadata) = replace_item_in_folder(
&mut parent_folder,
tracking_info.entry_hash,
chunked_file.file_name.clone(),
chunked_file.data_map.clone(),
encryption_pk,
)?;

changes.mutations.push(Mutation::FileContentChanged((
tracking_info.meta_xorname,
MetadataTrackingInfo {
Expand All @@ -412,12 +420,12 @@ impl AccountPacket {
}
FolderEntry::Folder(_) => {
// New file found where there used to be a folder
// TODO: we need to encrypt the data-map and metadata if make_data_public is false.
let (entry_hash, meta_xorname, metadata) = replace_item_in_folder(
&mut parent_folder,
tracking_info.entry_hash,
chunked_file.file_name.clone(),
chunked_file.data_map.clone(),
encryption_pk,
)?;
changes
.mutations
Expand All @@ -430,11 +438,11 @@ impl AccountPacket {
}
},
Ok(None) => {
// TODO: we need to encrypt the data-map and metadata if make_data_public is false.
let (entry_hash, meta_xorname, metadata) =
parent_folder.get_mut().0.add_file(
chunked_file.file_name.clone(),
chunked_file.data_map.clone(),
encryption_pk,
)?;
parent_folder.get_mut().1.has_new_entries();

Expand Down Expand Up @@ -486,7 +494,10 @@ impl AccountPacket {
}

// Build Folders hierarchy from the set files dir
fn read_folders_hierarchy_from_disk(&self) -> Result<ChangesToApply> {
fn read_folders_hierarchy_from_disk(
&self,
encryption_pk: Option<PublicKey>,
) -> Result<ChangesToApply> {
let mut changes = ChangesToApply::default();
for (dir_path, depth, parent, dir_name) in self.iter_only_dirs().filter_map(|entry| {
entry.path().parent().map(|parent| {
Expand All @@ -513,7 +524,7 @@ impl AccountPacket {

if folder_change.is_new_folder() {
let (entry_hash, meta_xorname, metadata) =
parent_folder.add_folder(dir_name, curr_folder_addr)?;
parent_folder.add_folder(dir_name, curr_folder_addr, encryption_pk)?;
parent_folder_change.has_new_entries();

changes
Expand Down Expand Up @@ -786,10 +797,16 @@ fn replace_item_in_folder(
entry_hash: EntryHash,
file_name: OsString,
data_map: Chunk,
encryption_pk: Option<PublicKey>,
) -> Result<(EntryHash, XorName, Metadata)> {
let (ref mut folders_api, ref mut folder_change) = folder.get_mut();
folder_change.has_new_entries();
let res = folders_api.replace_file(entry_hash, file_name.clone(), data_map.clone())?;
let res = folders_api.replace_file(
entry_hash,
file_name.clone(),
data_map.clone(),
encryption_pk,
)?;
Ok(res)
}

Expand Down
42 changes: 35 additions & 7 deletions sn_client/src/folders.rs
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@ use crate::FilesApi;

use super::{error::Result, Client, ClientRegister, WalletClient};

use bls::{Ciphertext, PublicKey};
use self_encryption::MAX_CHUNK_SIZE;
use sn_protocol::{
storage::{Chunk, ChunkAddress, RegisterAddress, RetryStrategy},
Expand Down Expand Up @@ -106,29 +107,31 @@ impl FoldersApi {
&mut self,
file_name: OsString,
data_map_chunk: Chunk,
encryption_pk: Option<PublicKey>,
) -> Result<(EntryHash, XorName, Metadata)> {
// create metadata Chunk for this entry
let metadata = Metadata {
name: file_name.to_str().unwrap_or("unknown").to_string(),
content: FolderEntry::File(data_map_chunk),
};

self.add_entry(metadata, &BTreeSet::default())
self.add_entry(metadata, &BTreeSet::default(), encryption_pk)
}

/// Add subfolder as entry of this Folder (locally).
pub fn add_folder(
&mut self,
folder_name: OsString,
address: RegisterAddress,
encryption_pk: Option<PublicKey>,
) -> Result<(EntryHash, XorName, Metadata)> {
// create metadata Chunk for this entry
let metadata = Metadata {
name: folder_name.to_str().unwrap_or("unknown").to_string(),
content: FolderEntry::Folder(address),
};

self.add_entry(metadata, &BTreeSet::default())
self.add_entry(metadata, &BTreeSet::default(), encryption_pk)
}

/// Replace an existing file with the provided one (locally).
Expand All @@ -137,14 +140,19 @@ impl FoldersApi {
existing_entry: EntryHash,
file_name: OsString,
data_map_chunk: Chunk,
encryption_pk: Option<PublicKey>,
) -> Result<(EntryHash, XorName, Metadata)> {
// create metadata Chunk for this entry
let metadata = Metadata {
name: file_name.to_str().unwrap_or("unknown").to_string(),
content: FolderEntry::File(data_map_chunk),
};

self.add_entry(metadata, &vec![existing_entry].into_iter().collect())
self.add_entry(
metadata,
&vec![existing_entry].into_iter().collect(),
encryption_pk,
)
}

/// Remove a file/folder item from this Folder (locally).
Expand Down Expand Up @@ -207,7 +215,7 @@ impl FoldersApi {
.register
.read()
.iter()
.map(|(_, meta_xorname)| xorname_from_entry(meta_xorname))
.map(|(_, meta_xorname_entry)| xorname_from_entry(meta_xorname_entry))
.collect();

self.metadata
Expand Down Expand Up @@ -240,7 +248,16 @@ impl FoldersApi {
.client
.get_chunk(ChunkAddress::new(meta_xorname), false, None)
.await?;
let metadata: Metadata = rmp_serde::from_slice(chunk.value())?;

let metadata: Metadata = match rmp_serde::from_slice(chunk.value()) {
Ok(metadata) => metadata,
Err(_) => {
// let's try to decrypt it then
let cipher = Ciphertext::from_bytes(chunk.value()).unwrap();
let data = self.client.signer().decrypt(&cipher).unwrap();
rmp_serde::from_slice(&data)?
}
};
self.metadata.insert(meta_xorname, (metadata.clone(), None));
metadata
}
Expand All @@ -265,14 +282,25 @@ impl FoldersApi {
})
}

// Add the given entry to the underlying Register as well as creating the metadata Chunk
// Add the given entry to the underlying Register as well as creating the metadata Chunk.
// If an encryption key is given, the metadata chunk will be encrpyted with it.
fn add_entry(
&mut self,
metadata: Metadata,
children: &BTreeSet<EntryHash>,
encryption_pk: Option<PublicKey>,
) -> Result<(EntryHash, XorName, Metadata)> {
let mut bytes = BytesMut::with_capacity(MAX_CHUNK_SIZE);
bytes.put(rmp_serde::to_vec(&metadata)?.as_slice());
let serialised_metadata = rmp_serde::to_vec(&metadata)?;
if let Some(pk) = encryption_pk {
bytes.put(
pk.encrypt(serialised_metadata.as_slice())
.to_bytes()
.as_slice(),
);
} else {
bytes.put(serialised_metadata.as_slice());
}
let meta_chunk = Chunk::new(bytes.freeze());
let meta_xorname = *meta_chunk.name();

Expand Down

0 comments on commit e21312b

Please sign in to comment.