mirror of https://github.com/dswd/zvault
Encrypted bundle info
This commit is contained in:
parent
014c456fd0
commit
883c4c1c24
|
@ -103,10 +103,6 @@ Recommended: Brotli/2-7
|
||||||
- File attributes
|
- File attributes
|
||||||
- xattrs https://crates.io/crates/xattr
|
- xattrs https://crates.io/crates/xattr
|
||||||
|
|
||||||
### Formats
|
|
||||||
- Bundles
|
|
||||||
- Encrypted bundle header
|
|
||||||
|
|
||||||
### CLI functionality
|
### CLI functionality
|
||||||
- list --tree
|
- list --tree
|
||||||
|
|
||||||
|
|
|
@ -66,7 +66,7 @@ pub fn bundle_path(bundle: &BundleId, mut folder: PathBuf, mut count: usize) ->
|
||||||
(folder, file.into())
|
(folder, file.into())
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn load_bundles<P: AsRef<Path>>(path: P, bundles: &mut HashMap<BundleId, StoredBundle>) -> Result<(Vec<StoredBundle>, Vec<StoredBundle>), BundleDbError> {
|
pub fn load_bundles<P: AsRef<Path>>(path: P, bundles: &mut HashMap<BundleId, StoredBundle>, crypto: Arc<Mutex<Crypto>>) -> Result<(Vec<StoredBundle>, Vec<StoredBundle>), BundleDbError> {
|
||||||
let mut paths = vec![path.as_ref().to_path_buf()];
|
let mut paths = vec![path.as_ref().to_path_buf()];
|
||||||
let mut bundle_paths = HashSet::new();
|
let mut bundle_paths = HashSet::new();
|
||||||
while let Some(path) = paths.pop() {
|
while let Some(path) = paths.pop() {
|
||||||
|
@ -91,7 +91,7 @@ pub fn load_bundles<P: AsRef<Path>>(path: P, bundles: &mut HashMap<BundleId, Sto
|
||||||
let mut new = vec![];
|
let mut new = vec![];
|
||||||
for path in bundle_paths {
|
for path in bundle_paths {
|
||||||
let bundle = StoredBundle {
|
let bundle = StoredBundle {
|
||||||
info: try!(BundleReader::load_info(&path)),
|
info: try!(BundleReader::load_info(&path, crypto.clone())),
|
||||||
path: path
|
path: path
|
||||||
};
|
};
|
||||||
let id = bundle.info.id.clone();
|
let id = bundle.info.id.clone();
|
||||||
|
@ -149,12 +149,12 @@ impl BundleDb {
|
||||||
self.remote_bundles.insert(bundle.id(), bundle);
|
self.remote_bundles.insert(bundle.id(), bundle);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
let (new, gone) = try!(load_bundles(&self.local_bundles_path, &mut self.local_bundles));
|
let (new, gone) = try!(load_bundles(&self.local_bundles_path, &mut self.local_bundles, self.crypto.clone()));
|
||||||
if !new.is_empty() || !gone.is_empty() {
|
if !new.is_empty() || !gone.is_empty() {
|
||||||
let bundles: Vec<_> = self.local_bundles.values().cloned().collect();
|
let bundles: Vec<_> = self.local_bundles.values().cloned().collect();
|
||||||
try!(StoredBundle::save_list_to(&bundles, &local_cache_path));
|
try!(StoredBundle::save_list_to(&bundles, &local_cache_path));
|
||||||
}
|
}
|
||||||
let (new, gone) = try!(load_bundles(&self.remote_path, &mut self.remote_bundles));
|
let (new, gone) = try!(load_bundles(&self.remote_path, &mut self.remote_bundles, self.crypto.clone()));
|
||||||
if !new.is_empty() || !gone.is_empty() {
|
if !new.is_empty() || !gone.is_empty() {
|
||||||
let bundles: Vec<_> = self.remote_bundles.values().cloned().collect();
|
let bundles: Vec<_> = self.remote_bundles.values().cloned().collect();
|
||||||
try!(StoredBundle::save_list_to(&bundles, &remote_cache_path));
|
try!(StoredBundle::save_list_to(&bundles, &remote_cache_path));
|
||||||
|
|
|
@ -71,6 +71,17 @@ serde_impl!(BundleMode(u8) {
|
||||||
});
|
});
|
||||||
|
|
||||||
|
|
||||||
|
#[derive(Default, Debug, Clone)]
|
||||||
|
pub struct BundleHeader {
|
||||||
|
pub encryption: Option<Encryption>,
|
||||||
|
pub info_size: usize
|
||||||
|
}
|
||||||
|
serde_impl!(BundleHeader(u8) {
|
||||||
|
encryption: Option<Encryption> => 0,
|
||||||
|
info_size: usize => 1
|
||||||
|
});
|
||||||
|
|
||||||
|
|
||||||
#[derive(Clone)]
|
#[derive(Clone)]
|
||||||
pub struct BundleInfo {
|
pub struct BundleInfo {
|
||||||
pub id: BundleId,
|
pub id: BundleId,
|
||||||
|
@ -87,7 +98,7 @@ serde_impl!(BundleInfo(u64?) {
|
||||||
id: BundleId => 0,
|
id: BundleId => 0,
|
||||||
mode: BundleMode => 1,
|
mode: BundleMode => 1,
|
||||||
compression: Option<Compression> => 2,
|
compression: Option<Compression> => 2,
|
||||||
encryption: Option<Encryption> => 3,
|
//encryption: already in the header
|
||||||
hash_method: HashMethod => 4,
|
hash_method: HashMethod => 4,
|
||||||
raw_size: usize => 6,
|
raw_size: usize => 6,
|
||||||
encoded_size: usize => 7,
|
encoded_size: usize => 7,
|
||||||
|
|
|
@ -84,7 +84,7 @@ impl BundleReader {
|
||||||
self.info.id.clone()
|
self.info.id.clone()
|
||||||
}
|
}
|
||||||
|
|
||||||
fn load_header<P: AsRef<Path>>(path: P) -> Result<(BundleInfo, u8, usize), BundleReaderError> {
|
fn load_header<P: AsRef<Path>>(path: P, crypto: Arc<Mutex<Crypto>>) -> Result<(BundleInfo, u8, usize), BundleReaderError> {
|
||||||
let path = path.as_ref();
|
let path = path.as_ref();
|
||||||
let mut file = BufReader::new(try!(File::open(path).context(path)));
|
let mut file = BufReader::new(try!(File::open(path).context(path)));
|
||||||
let mut header = [0u8; 8];
|
let mut header = [0u8; 8];
|
||||||
|
@ -96,20 +96,28 @@ impl BundleReader {
|
||||||
if version != HEADER_VERSION {
|
if version != HEADER_VERSION {
|
||||||
return Err(BundleReaderError::UnsupportedVersion(path.to_path_buf(), version))
|
return Err(BundleReaderError::UnsupportedVersion(path.to_path_buf(), version))
|
||||||
}
|
}
|
||||||
let header: BundleInfo = try!(msgpack::decode_from_stream(&mut file).context(path));
|
let header: BundleHeader = try!(msgpack::decode_from_stream(&mut file).context(path));
|
||||||
debug!("Load bundle {}", header.id);
|
let mut info_data = Vec::with_capacity(header.info_size);
|
||||||
let content_start = file.seek(SeekFrom::Current(0)).unwrap() as usize + header.chunk_info_size;
|
info_data.resize(header.info_size, 0);
|
||||||
Ok((header, version, content_start))
|
try!(file.read_exact(&mut info_data).context(path));
|
||||||
|
if let Some(ref encryption) = header.encryption {
|
||||||
|
info_data = try!(crypto.lock().unwrap().decrypt(&encryption, &info_data).context(path));
|
||||||
|
}
|
||||||
|
let mut info: BundleInfo = try!(msgpack::decode(&info_data).context(path));
|
||||||
|
info.encryption = header.encryption;
|
||||||
|
debug!("Load bundle {}", info.id);
|
||||||
|
let content_start = file.seek(SeekFrom::Current(0)).unwrap() as usize + info.chunk_info_size;
|
||||||
|
Ok((info, version, content_start))
|
||||||
}
|
}
|
||||||
|
|
||||||
#[inline]
|
#[inline]
|
||||||
pub fn load_info<P: AsRef<Path>>(path: P) -> Result<BundleInfo, BundleReaderError> {
|
pub fn load_info<P: AsRef<Path>>(path: P, crypto: Arc<Mutex<Crypto>>) -> Result<BundleInfo, BundleReaderError> {
|
||||||
Self::load_header(path).map(|b| b.0)
|
Self::load_header(path, crypto).map(|b| b.0)
|
||||||
}
|
}
|
||||||
|
|
||||||
#[inline]
|
#[inline]
|
||||||
pub fn load(path: PathBuf, crypto: Arc<Mutex<Crypto>>) -> Result<Self, BundleReaderError> {
|
pub fn load(path: PathBuf, crypto: Arc<Mutex<Crypto>>) -> Result<Self, BundleReaderError> {
|
||||||
let (header, version, content_start) = try!(Self::load_header(&path));
|
let (header, version, content_start) = try!(Self::load_header(&path, crypto.clone()));
|
||||||
Ok(BundleReader::new(path, version, content_start, crypto, header))
|
Ok(BundleReader::new(path, version, content_start, crypto, header))
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -105,21 +105,30 @@ impl BundleWriter {
|
||||||
let mut file = BufWriter::new(try!(File::create(&path).context(&path as &Path)));
|
let mut file = BufWriter::new(try!(File::create(&path).context(&path as &Path)));
|
||||||
try!(file.write_all(&HEADER_STRING).context(&path as &Path));
|
try!(file.write_all(&HEADER_STRING).context(&path as &Path));
|
||||||
try!(file.write_all(&[HEADER_VERSION]).context(&path as &Path));
|
try!(file.write_all(&[HEADER_VERSION]).context(&path as &Path));
|
||||||
let header = BundleInfo {
|
let info = BundleInfo {
|
||||||
mode: self.mode,
|
mode: self.mode,
|
||||||
hash_method: self.hash_method,
|
hash_method: self.hash_method,
|
||||||
compression: self.compression,
|
compression: self.compression,
|
||||||
encryption: self.encryption,
|
encryption: self.encryption.clone(),
|
||||||
chunk_count: self.chunk_count,
|
chunk_count: self.chunk_count,
|
||||||
id: id.clone(),
|
id: id.clone(),
|
||||||
raw_size: self.raw_size,
|
raw_size: self.raw_size,
|
||||||
encoded_size: encoded_size,
|
encoded_size: encoded_size,
|
||||||
chunk_info_size: chunk_data.len()
|
chunk_info_size: chunk_data.len()
|
||||||
};
|
};
|
||||||
|
let mut info_data = try!(msgpack::encode(&info).context(&path as &Path));
|
||||||
|
if let Some(ref encryption) = self.encryption {
|
||||||
|
info_data = try!(self.crypto.lock().unwrap().encrypt(&encryption, &info_data));
|
||||||
|
}
|
||||||
|
let header = BundleHeader {
|
||||||
|
encryption: self.encryption,
|
||||||
|
info_size: info_data.len()
|
||||||
|
};
|
||||||
try!(msgpack::encode_to_stream(&header, &mut file).context(&path as &Path));
|
try!(msgpack::encode_to_stream(&header, &mut file).context(&path as &Path));
|
||||||
|
try!(file.write_all(&info_data).context(&path as &Path));
|
||||||
try!(file.write_all(&chunk_data).context(&path as &Path));
|
try!(file.write_all(&chunk_data).context(&path as &Path));
|
||||||
try!(file.write_all(&self.data).context(&path as &Path));
|
try!(file.write_all(&self.data).context(&path as &Path));
|
||||||
Ok(StoredBundle { path: path, info: header })
|
Ok(StoredBundle { path: path, info: info })
|
||||||
}
|
}
|
||||||
|
|
||||||
#[inline]
|
#[inline]
|
||||||
|
|
Loading…
Reference in New Issue