summaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
authorLars Wirzenius <liw@liw.fi>2021-01-04 18:57:49 +0200
committerLars Wirzenius <liw@liw.fi>2021-01-04 20:02:06 +0200
commit8efabc60f87e5462b01f4832d575f68382929624 (patch)
tree422b3941b6867871486df2198aef0e431c6b95ac /src
parent650b7cee5700eae9ab6c300fbdb816dead6f01f5 (diff)
downloadobnam2-8efabc60f87e5462b01f4832d575f68382929624.tar.gz
feat: verify checksum of chunks downloaded from server
Diffstat (limited to 'src')
-rw-r--r--src/bin/obnam.rs7
-rw-r--r--src/chunkid.rs8
-rw-r--r--src/client.rs19
-rw-r--r--src/cmd/get_chunk.rs15
-rw-r--r--src/cmd/mod.rs3
-rw-r--r--src/error.rs6
6 files changed, 54 insertions, 4 deletions
diff --git a/src/bin/obnam.rs b/src/bin/obnam.rs
index f31884b..e5703ed 100644
--- a/src/bin/obnam.rs
+++ b/src/bin/obnam.rs
@@ -2,7 +2,7 @@ use log::{debug, error, info, LevelFilter};
use log4rs::append::file::FileAppender;
use log4rs::config::{Appender, Config, Logger, Root};
use obnam::client::ClientConfig;
-use obnam::cmd::{backup, list, list_files, restore};
+use obnam::cmd::{backup, get_chunk, list, list_files, restore};
use std::path::{Path, PathBuf};
use structopt::StructOpt;
@@ -23,6 +23,7 @@ fn main() -> anyhow::Result<()> {
Command::List => list(&config),
Command::ListFiles { gen_id } => list_files(&config, &gen_id),
Command::Restore { gen_id, to } => restore(&config, &gen_id, &to),
+ Command::GetChunk { chunk_id } => get_chunk(&config, &chunk_id),
};
if let Err(ref e) = result {
@@ -60,6 +61,10 @@ enum Command {
#[structopt(parse(from_os_str))]
to: PathBuf,
},
+ GetChunk {
+ #[structopt()]
+ chunk_id: String,
+ },
}
fn setup_logging(filename: &Path) -> anyhow::Result<()> {
diff --git a/src/chunkid.rs b/src/chunkid.rs
index 9eec41f..3933d4b 100644
--- a/src/chunkid.rs
+++ b/src/chunkid.rs
@@ -37,6 +37,10 @@ impl ChunkId {
}
}
+ pub fn from_str(s: &str) -> Self {
+ ChunkId { id: s.to_string() }
+ }
+
pub fn as_bytes(&self) -> &[u8] {
self.id.as_bytes()
}
@@ -81,7 +85,7 @@ impl FromStr for ChunkId {
type Err = ();
fn from_str(s: &str) -> Result<Self, Self::Err> {
- Ok(ChunkId { id: s.to_string() })
+ Ok(ChunkId::from_str(s))
}
}
@@ -113,6 +117,6 @@ mod test {
fn survives_round_trip() {
let id = ChunkId::new();
let id_str = id.to_string();
- assert_eq!(id, id_str.parse().unwrap());
+ assert_eq!(id, ChunkId::from_str(&id_str))
}
}
diff --git a/src/client.rs b/src/client.rs
index 616ceef..6b1bb80 100644
--- a/src/client.rs
+++ b/src/client.rs
@@ -4,6 +4,7 @@ use crate::chunk::GenerationChunk;
use crate::chunker::Chunker;
use crate::chunkid::ChunkId;
use crate::chunkmeta::ChunkMeta;
+use crate::error::ObnamError;
use crate::fsentry::{FilesystemEntry, FilesystemKind};
use crate::generation::{FinishedGeneration, LocalGeneration};
use crate::genlist::GenerationList;
@@ -212,8 +213,24 @@ impl BackupClient {
return Err(ClientError::ChunkNotFound(chunk_id.to_string()).into());
}
+ let headers = res.headers();
+ let meta = headers.get("chunk-meta");
+ if meta.is_none() {
+ return Err(ObnamError::NoChunkMeta(chunk_id.to_string()).into());
+ }
+ let meta = meta.unwrap().to_str()?;
+ let meta: ChunkMeta = serde_json::from_str(meta)?;
+
let body = res.bytes()?;
- Ok(DataChunk::new(body.to_vec()))
+ let body = body.to_vec();
+ let actual = sha256(&body);
+ if actual != meta.sha256() {
+ return Err(ObnamError::WrongChecksum(chunk_id.to_string()).into());
+ }
+
+ let chunk: DataChunk = DataChunk::new(body);
+
+ Ok(chunk)
}
fn fetch_generation_chunk(&self, gen_id: &str) -> anyhow::Result<GenerationChunk> {
diff --git a/src/cmd/get_chunk.rs b/src/cmd/get_chunk.rs
new file mode 100644
index 0000000..bf653ff
--- /dev/null
+++ b/src/cmd/get_chunk.rs
@@ -0,0 +1,15 @@
+use crate::chunkid::ChunkId;
+use crate::client::BackupClient;
+use crate::client::ClientConfig;
+use std::io::{stdout, Write};
+
+pub fn get_chunk(config: &ClientConfig, chunk_id: &str) -> anyhow::Result<()> {
+ let client = BackupClient::new(&config.server_url)?;
+ let chunk_id: ChunkId = chunk_id.parse().unwrap();
+ let chunk = client.fetch_chunk(&chunk_id)?;
+
+ let stdout = stdout();
+ let mut handle = stdout.lock();
+ handle.write_all(chunk.data())?;
+ Ok(())
+}
diff --git a/src/cmd/mod.rs b/src/cmd/mod.rs
index 2919d88..c3cebe2 100644
--- a/src/cmd/mod.rs
+++ b/src/cmd/mod.rs
@@ -9,3 +9,6 @@ pub use list_files::list_files;
pub mod restore;
pub use restore::restore;
+
+pub mod get_chunk;
+pub use get_chunk::get_chunk;
diff --git a/src/error.rs b/src/error.rs
index 3b3f573..360e62d 100644
--- a/src/error.rs
+++ b/src/error.rs
@@ -9,4 +9,10 @@ pub enum ObnamError {
#[error("Generation has more than one file with the name {0}")]
TooManyFiles(PathBuf),
+
+ #[error("Server response did not have a 'chunk-meta' header for chunk {0}")]
+ NoChunkMeta(String),
+
+ #[error("Wrong checksum for chunk {0}")]
+ WrongChecksum(String),
}