double validate downloaded demo

This commit is contained in:
Robin Appelman 2022-05-09 23:30:01 +02:00
commit 1887843fe2
5 changed files with 42 additions and 3 deletions

1
Cargo.lock generated
View file

@ -34,6 +34,7 @@ dependencies = [
"dotenv", "dotenv",
"futures-util", "futures-util",
"main_error", "main_error",
"md5",
"thiserror", "thiserror",
"tokio", "tokio",
"tracing", "tracing",

View file

@ -13,6 +13,7 @@ tokio = { version = "1.17.0", features = ["rt-multi-thread", "macros"] }
tracing = "0.1.33" tracing = "0.1.33"
tracing-subscriber = "0.3.11" tracing-subscriber = "0.3.11"
futures-util = "0.3.21" futures-util = "0.3.21"
md5 = "0.7.0"
[profile.release] [profile.release]
lto = true lto = true

View file

@ -20,10 +20,21 @@ impl Backup {
async fn backup_demo(&self, name: &str, demo: &Demo) -> Result<(), Error> { async fn backup_demo(&self, name: &str, demo: &Demo) -> Result<(), Error> {
info!("backing up"); info!("backing up");
let mut file = self.store.create(name).await?; {
let file = self.store.create(name).await?;
demo.save(&self.client, file).await?;
}
demo.save(&self.client, &mut file).await?; let digest = self.store.hash(name)?;
Ok(()) if digest == demo.hash || digest == [0; 16] {
Ok(())
} else {
let _ = self.store.remove(name);
Err(Error::DigestMismatch {
expected: demo.hash,
got: digest,
})
}
} }
#[instrument(skip(self))] #[instrument(skip(self))]

View file

@ -16,6 +16,8 @@ pub enum Error {
Request(#[from] std::io::Error), Request(#[from] std::io::Error),
#[error(transparent)] #[error(transparent)]
Api(#[from] demostf_client::Error), Api(#[from] demostf_client::Error),
#[error("MD5 digest mismatch for downloaded demo, expected {expected:?}, received {got:?}")]
DigestMismatch { expected: [u8; 16], got: [u8; 16] },
} }
#[tokio::main] #[tokio::main]

View file

@ -1,6 +1,8 @@
use crate::Error; use crate::Error;
use md5::Context;
use std::fs; use std::fs;
use std::fs::{File, Permissions}; use std::fs::{File, Permissions};
use std::io::Read;
use std::os::unix::fs::PermissionsExt; use std::os::unix::fs::PermissionsExt;
use std::path::{Path, PathBuf}; use std::path::{Path, PathBuf};
@ -33,6 +35,28 @@ impl Store {
fs::remove_file(self.generate_path(name)) fs::remove_file(self.generate_path(name))
} }
pub fn hash(&self, name: &str) -> Result<[u8; 16], Error> {
let path = self.generate_path(name);
let mut file = File::open(path)?;
let mut hash = Context::new();
let mut buff = vec![0; 1024 * 1024];
loop {
let read = file.read(&mut buff)?;
if read == 0 {
break;
}
let data = &buff[0..read];
hash.consume(&data);
}
Ok(hash.compute().0)
}
fn generate_path(&self, name: &str) -> PathBuf { fn generate_path(&self, name: &str) -> PathBuf {
let mut path = self.basedir.clone(); let mut path = self.basedir.clone();
path.push(&name[0..2]); path.push(&name[0..2]);