Skip to content
19 changes: 15 additions & 4 deletions sdk/src/builder.rs
Original file line number Diff line number Diff line change
Expand Up @@ -37,7 +37,7 @@ use crate::{
},
claim::Claim,
error::{Error, Result},
http::{AsyncGenericResolver, SyncGenericResolver},
http::{restricted::RestrictedResolver, AsyncGenericResolver, SyncGenericResolver},
jumbf_io,
resource_store::{ResourceRef, ResourceResolver, ResourceStore},
settings::{self, Settings},
Expand Down Expand Up @@ -617,6 +617,13 @@ impl Builder {
R: Read + Seek + Send,
{
let settings = crate::settings::get_settings().unwrap_or_default();
let http_resolver = if _sync {
SyncGenericResolver::new()
} else {
AsyncGenericResolver::new()
};
let mut http_resolver = RestrictedResolver::new(http_resolver);
http_resolver.set_allowed_hosts(settings.core.allowed_network_hosts.clone());

let ingredient: Ingredient = Ingredient::from_json(&ingredient_json.into())?;

Expand All @@ -632,10 +639,10 @@ impl Builder {
}

let ingredient = if _sync {
ingredient.with_stream(format, stream, &SyncGenericResolver::new(), &settings)?
ingredient.with_stream(format, stream, &http_resolver, &settings)?
} else {
ingredient
.with_stream_async(format, stream, &AsyncGenericResolver::new(), &settings)
.with_stream_async(format, stream, &http_resolver, &settings)
.await?
};

Expand Down Expand Up @@ -862,6 +869,8 @@ impl Builder {
// so we will read the store directly here
//crate::Reader::from_stream("application/c2pa", stream).and_then(|r| r.into_builder())
let settings = crate::settings::get_settings().unwrap_or_default();
let mut http_resolver = RestrictedResolver::new(SyncGenericResolver::new());
http_resolver.set_allowed_hosts(settings.core.allowed_network_hosts.clone());

let mut validation_log = crate::status_tracker::StatusTracker::default();
stream.rewind()?; // Ensure stream is at the start
Expand All @@ -871,7 +880,7 @@ impl Builder {
&mut stream,
false,
&mut validation_log,
&SyncGenericResolver::new(),
&http_resolver,
&settings,
)?;
let reader = Reader::from_store(store, &mut validation_log, &settings)?;
Expand Down Expand Up @@ -1581,6 +1590,8 @@ impl Builder {
} else {
AsyncGenericResolver::new()
};
let mut http_resolver = RestrictedResolver::new(http_resolver);
http_resolver.set_allowed_hosts(settings.core.allowed_network_hosts.clone());

let format = format_to_mime(format);
self.definition.format.clone_from(&format);
Expand Down
37 changes: 37 additions & 0 deletions sdk/src/http/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,32 @@
// specific language governing permissions and limitations under
// each license.

//! HTTP abstraction layer.
//!
//! This module defines generic traits and helpers for performing HTTP requests
//! without hard-wiring a specific HTTP client. It allows host applications to
//! plug in their own HTTP implementation, restrict where the SDK may connect,
//! or disable networking entirely.
//!
//! # When do outbound network requests occur?
//!
//! The SDK may issue outbound HTTP/S requests in the following scenarios:
//! - [`Reader`]:
//! - Fetching remote manifests
//! - Validating CAWG identity assertions
//! - Fetching OCSP revocation status
//! - [`Builder`]:
//! - Fetching ingredient remote manifests
//! - Fetching timestamps
//! - Fetching [`TimeStamp`] assertions
//! - Fetching OCSP staples
//! - Fetching [`CertificateStatus`] assertions
//!
//! [`Reader`]: crate::Reader
//! [`Builder`]: crate::Builder
//! [`TimeStamp`]: crate::assertions::TimeStamp
//! [`CertificateStatus`]: crate::assertions::CertificateStatus

use std::io::{self, Read};

use async_trait::async_trait;
Expand All @@ -22,6 +48,9 @@ mod reqwest;
mod ureq;
mod wasi;

/// Structs for restricting outbound network requests.
pub mod restricted;

// Since we use `http::Request` and `http::Response` we also expose the `http` crate.
pub use http;

Expand Down Expand Up @@ -150,6 +179,14 @@ pub enum HttpResolverError {
#[error("the async http resolver is not implemented")]
AsyncHttpResolverNotImplemented,

/// The remote URI is blocked by the allowed list.
///
/// The allowed list is normally set in a [`RestrictedResolver`].
///
/// [`RestrictedResolver`]: restricted::RestrictedResolver
#[error("remote URI \"{uri}\" is not permitted by the allowed list")]
UriDisallowed { uri: String },

/// An error occured from the underlying HTTP resolver.
#[error("an error occurred from the underlying http resolver")]
Other(Box<dyn std::error::Error + Send + Sync>),
Expand Down
Loading
Loading