diff --git a/tuftool/src/download_root.rs b/tuftool/src/download_root.rs new file mode 100644 index 00000000..3c7e2419 --- /dev/null +++ b/tuftool/src/download_root.rs @@ -0,0 +1,51 @@ +// Copyright 2019 Amazon.com, Inc. or its affiliates. All Rights Reserved. +// SPDX-License-Identifier: MIT OR Apache-2.0 +//! The `download_root` module owns the logic for downloading a given version of `root.json`. + +use crate::error::{self, Result}; +use snafu::ResultExt; +use std::fs::File; +use std::num::NonZeroU64; +use std::path::{Path, PathBuf}; +use url::Url; + +/// Download the given version of `root.json` +/// This is an unsafe operation, and doesn't establish trust. It should only be used for testing! +pub(crate) fn download_root

( + metadata_base_url: &Url, + version: NonZeroU64, + outdir: P, +) -> Result +where + P: AsRef, +{ + let name = format!("{}.root.json", version); + + let path = outdir.as_ref().join(&name); + let url = metadata_base_url.join(&name).context(error::UrlParse { + url: format!("{}/{}", metadata_base_url.as_str(), name), + })?; + root_warning(&path); + + let mut root_request = reqwest::blocking::get(url.as_str()) + .context(error::ReqwestGet)? + .error_for_status() + .context(error::BadResponse { url })?; + + let mut f = File::create(&path).context(error::OpenFile { path: &path })?; + root_request.copy_to(&mut f).context(error::ReqwestCopy)?; + + Ok(path) +} + +/// Print a very noticeable warning message about the unsafe nature of downloading `root.json` +/// without verification +fn root_warning>(path: P) { + #[rustfmt::skip] + eprintln!("\ +================================================================= +WARNING: Downloading root.json to {} +This is unsafe and will not establish trust, use only for testing +=================================================================", + path.as_ref().display()); +} diff --git a/tuftool/src/error.rs b/tuftool/src/error.rs index 8dba29a5..494c0552 100644 --- a/tuftool/src/error.rs +++ b/tuftool/src/error.rs @@ -243,6 +243,13 @@ pub(crate) enum Error { backtrace: Backtrace, }, + #[snafu(display("Response '{}' from '{}': {}", get_status_code(source), url, source))] + BadResponse { + url: String, + source: reqwest::Error, + backtrace: Backtrace, + }, + #[snafu(display("Failed to sign repository: {}", source))] SignRepo { source: tough::error::Error, @@ -357,3 +364,12 @@ pub(crate) enum Error { backtrace: Backtrace, }, } + +// Extracts the status code from a reqwest::Error and converts it to a string to be displayed +fn get_status_code(source: &reqwest::Error) -> String { + source + .status() + .as_ref() + .map_or("Unknown", |i| i.as_str()) + .to_string() +}