Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Remove reqwest dependency #354

Draft
wants to merge 12 commits into
base: main
Choose a base branch
from
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,6 @@ FROM --platform=linux/amd64 alpine:latest
RUN apk add --no-cache \
build-base \
musl-dev \
openssl-dev \
linux-headers \
rustup \
libgcc \
Expand All @@ -13,21 +12,12 @@ RUN apk add --no-cache \
git \
perl \
make \
bash \
openssl-libs-static
bash

# Install rust
RUN curl --proto '=https' --tlsv1.2 -sSf https://sh.rustup.rs | bash -s -- -y --no-modify-path --default-toolchain 1.74.0
ENV PATH="/root/.cargo/bin:${PATH}"

# Set environment variables to ensure vendored OpenSSL is used
ENV OPENSSL_STATIC=1
ENV OPENSSL_LIB_DIR=/usr/lib
ENV OPENSSL_INCLUDE_DIR=/usr/include
ENV PKG_CONFIG_ALLOW_CROSS=1
ENV PKG_CONFIG_PATH=/usr/lib/pkgconfig
ENV LIBRARY_PATH="/usr/lib:/usr/local/lib"

# Copy the source code to the container
WORKDIR /usr/src/myapp
COPY Cargo.toml ./
Expand All @@ -44,7 +34,7 @@ RUN cargo build --release --package web5_uniffi
# Compile as a dynamic lib (.so) from our static lib (.a) while keeping dependencies self-contained
RUN gcc -shared -o target/release/libweb5_uniffi.so -Wl,--whole-archive \
target/release/libweb5_uniffi.a -Wl,--no-whole-archive -static-libgcc \
-L/usr/lib -lssl -lcrypto -Wl,-Bdynamic -fPIC
-Wl,-Bdynamic -fPIC

# Set the entrypoint, so that we can `docker cp` the build output
CMD tail -f /dev/null
3 changes: 2 additions & 1 deletion crates/web5/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -18,7 +18,6 @@ k256 = { version = "0.13.3", features = ["ecdsa", "jwk"] }
tokio = "1.38.0"
rand = { workspace = true }
regex = "1.10.4"
reqwest = { version = "0.12.4", features = ["json", "blocking"] }
serde = { workspace = true }
serde_json = { workspace = true }
sha2 = "0.10.8"
Expand All @@ -30,6 +29,8 @@ x25519-dalek = { version = "2.0.1", features = ["getrandom", "static_secrets"] }
zbase32 = "0.1.2"
lazy_static = "1.5.0"
flate2 = "1.0.33"
rustls = { version = "0.23.13", default-features = false, features = ["std", "tls12"] }
webpki-roots = "0.26.5"

[dev-dependencies]
mockito = "1.5.0"
Expand Down
16 changes: 10 additions & 6 deletions crates/web5/src/credentials/create.rs
Original file line number Diff line number Diff line change
Expand Up @@ -627,7 +627,7 @@ mod tests {
fn test_schema_resolve_network_issue() {
TEST_SUITE.include(test_name!());

let url = "invalid url".to_string(); // here
let url = "http://local".to_string(); // here

let result = create_vc(
issuer(),
Expand All @@ -640,7 +640,11 @@ mod tests {

match result {
Err(Web5Error::Network(err_msg)) => {
assert!(err_msg.contains("unable to resolve json schema"))
assert!(
err_msg.contains("failed to connect to host"),
"Error message is: {}",
err_msg
)
}
_ => panic!(
"expected Web5Error::Network with specific message but got {:?}",
Expand Down Expand Up @@ -671,8 +675,8 @@ mod tests {
);

match result {
Err(Web5Error::JsonSchema(err_msg)) => {
assert!(err_msg.contains("non-200 response when resolving json schema"))
Err(Web5Error::Http(err_msg)) => {
assert_eq!("non-successful response code 500", err_msg)
}
_ => panic!(
"expected Web5Error::JsonSchema with specific message but got {:?}",
Expand Down Expand Up @@ -705,8 +709,8 @@ mod tests {
);

match result {
Err(Web5Error::JsonSchema(err_msg)) => {
assert!(err_msg.contains("unable to parse json schema from response body"))
Err(Web5Error::Http(err_msg)) => {
assert!(err_msg.contains("unable to parse json response body"))
}
_ => panic!(
"expected Web5Error::JsonSchema with specific message but got {:?}",
Expand Down
25 changes: 6 additions & 19 deletions crates/web5/src/credentials/credential_schema.rs
Original file line number Diff line number Diff line change
@@ -1,7 +1,9 @@
use super::verifiable_credential_1_1::VerifiableCredential;
use crate::errors::{Result, Web5Error};
use crate::{
errors::{Result, Web5Error},
http::get_json,
};
use jsonschema::{Draft, JSONSchema};
use reqwest::blocking::get;
use serde::{Deserialize, Serialize};

pub const CREDENTIAL_SCHEMA_TYPE: &str = "JsonSchema";
Expand All @@ -28,23 +30,8 @@ pub(crate) fn validate_credential_schema(
}

let url = &credential_schema.id;
let response = get(url).map_err(|err| {
Web5Error::Network(format!("unable to resolve json schema {} {}", url, err))
})?;
if !response.status().is_success() {
return Err(Web5Error::JsonSchema(format!(
"non-200 response when resolving json schema {} {}",
url,
response.status()
)));
}
let schema_json = response.json::<serde_json::Value>().map_err(|err| {
Web5Error::JsonSchema(format!(
"unable to parse json schema from response body {} {}",
url, err
))
})?;
let compiled_schema = JSONSchema::options().compile(&schema_json).map_err(|err| {
let json_schema = get_json::<serde_json::Value>(url)?;
let compiled_schema = JSONSchema::options().compile(&json_schema).map_err(|err| {
Web5Error::JsonSchema(format!("unable to compile json schema {} {}", url, err))
})?;

Expand Down
16 changes: 10 additions & 6 deletions crates/web5/src/credentials/verifiable_credential_1_1.rs
Original file line number Diff line number Diff line change
Expand Up @@ -764,13 +764,17 @@ mod tests {
fn test_schema_resolve_network_issue() {
TEST_SUITE.include(test_name!());

let vc_jwt_with_invalid_url = r#"eyJ0eXAiOiJKV1QiLCJhbGciOiJFZERTQSIsImtpZCI6ImRpZDpqd2s6ZXlKaGJHY2lPaUpGWkRJMU5URTVJaXdpYTNSNUlqb2lUMHRRSWl3aVkzSjJJam9pUldReU5UVXhPU0lzSW5naU9pSmZYelYxVEU1bWNVWTRRbTB6ZVhnMmJVRndMVlJJV25sSk5WcDJWQzFmYVVKbExWZDJiMHRuTTFwakluMCMwIn0.eyJ2YyI6eyJAY29udGV4dCI6WyJodHRwczovL3d3dy53My5vcmcvMjAxOC9jcmVkZW50aWFscy92MSJdLCJpZCI6InVybjp1dWlkOmRlNDY2N2YxLTMzM2ItNDg4OC1hMDc5LTdkMGU1N2JiZmFlZiIsInR5cGUiOlsiVmVyaWZpYWJsZUNyZWRlbnRpYWwiXSwiaXNzdWVyIjoiZGlkOmp3azpleUpoYkdjaU9pSkZaREkxTlRFNUlpd2lhM1I1SWpvaVQwdFFJaXdpWTNKMklqb2lSV1F5TlRVeE9TSXNJbmdpT2lKZlh6VjFURTVtY1VZNFFtMHplWGcyYlVGd0xWUklXbmxKTlZwMlZDMWZhVUpsTFZkMmIwdG5NMXBqSW4wIiwiaXNzdWFuY2VEYXRlIjoiMjAyNC0wOC0zMFQxNTowNToyMC43NjQ0MDgrMDA6MDAiLCJleHBpcmF0aW9uRGF0ZSI6bnVsbCwiY3JlZGVudGlhbFN1YmplY3QiOnsiaWQiOiJkaWQ6ZGh0OnFnbW1weWp3NWh3bnFmZ3puN3dtcm0zM2FkeThnYjh6OWlkZWliNm05Z2o0eXM2d255OHkifSwiY3JlZGVudGlhbFNjaGVtYSI6eyJpZCI6ImludmFsaWQgdXJsIiwidHlwZSI6Ikpzb25TY2hlbWEifX0sImlzcyI6ImRpZDpqd2s6ZXlKaGJHY2lPaUpGWkRJMU5URTVJaXdpYTNSNUlqb2lUMHRRSWl3aVkzSjJJam9pUldReU5UVXhPU0lzSW5naU9pSmZYelYxVEU1bWNVWTRRbTB6ZVhnMmJVRndMVlJJV25sSk5WcDJWQzFmYVVKbExWZDJiMHRuTTFwakluMCIsImp0aSI6InVybjp1dWlkOmRlNDY2N2YxLTMzM2ItNDg4OC1hMDc5LTdkMGU1N2JiZmFlZiIsInN1YiI6ImRpZDpkaHQ6cWdtbXB5anc1aHducWZnem43d21ybTMzYWR5OGdiOHo5aWRlaWI2bTlnajR5czZ3bnk4eSIsIm5iZiI6MTcyNTAzMDMyMCwiaWF0IjoxNzI1MDMwMzIwfQ.3sH7qzI7QrQMdkWIvqf7k8Mr2dMGjWBLrv4QB8gEz0t83RSFMtG-fWT-YVkUlo1qMvC4gNjT2Jc0eObCAA7VDQ"#;
let vc_jwt_with_invalid_url = r#"eyJ0eXAiOiJKV1QiLCJhbGciOiJFZDI1NTE5Iiwia2lkIjoiZGlkOmp3azpleUpoYkdjaU9pSkZaREkxTlRFNUlpd2lhM1I1SWpvaVQwdFFJaXdpWTNKMklqb2lSV1F5TlRVeE9TSXNJbmdpT2lKTmEycDVaRlo1ZFhaU1psaExRMDVWYm0wNVVWRnJVbkUwY0doWVdYRTBObUpFVjJGemFHOW5kbXhWSW4wIzAifQ.eyJpc3MiOiJkaWQ6andrOmV5SmhiR2NpT2lKRlpESTFOVEU1SWl3aWEzUjVJam9pVDB0UUlpd2lZM0oySWpvaVJXUXlOVFV4T1NJc0luZ2lPaUpOYTJwNVpGWjVkWFpTWmxoTFEwNVZibTA1VVZGclVuRTBjR2hZV1hFME5tSkVWMkZ6YUc5bmRteFZJbjAiLCJqdGkiOiJ1cm46dXVpZDo2YzM2YzU0Zi02M2VhLTRiY2MtOTgxOS0zYmNmMGIyYmUxMDgiLCJzdWIiOiJkaWQ6ZGh0OnFnbW1weWp3NWh3bnFmZ3puN3dtcm0zM2FkeThnYjh6OWlkZWliNm05Z2o0eXM2d255OHkiLCJuYmYiOjE3MjYwODk0NDIsImlhdCI6MTcyNjA4OTQ0MiwidmMiOnsiQGNvbnRleHQiOlsiaHR0cHM6Ly93d3cudzMub3JnLzIwMTgvY3JlZGVudGlhbHMvdjEiXSwiY3JlZGVudGlhbFNjaGVtYSI6eyJpZCI6Imh0dHA6Ly9sb2NhbC9zY2hlbWFzL2VtYWlsLmpzb24iLCJ0eXBlIjoiSnNvblNjaGVtYSJ9LCJpZCI6InVybjp1dWlkOjZjMzZjNTRmLTYzZWEtNGJjYy05ODE5LTNiY2YwYjJiZTEwOCIsImlzc3VlciI6ImRpZDpqd2s6ZXlKaGJHY2lPaUpGWkRJMU5URTVJaXdpYTNSNUlqb2lUMHRRSWl3aVkzSjJJam9pUldReU5UVXhPU0lzSW5naU9pSk5hMnA1WkZaNWRYWlNabGhMUTA1VmJtMDVVVkZyVW5FMGNHaFlXWEUwTm1KRVYyRnphRzluZG14VkluMCIsImlzc3VhbmNlRGF0ZSI6IjIwMjQtMDktMTFUMjE6MTc6MjJaIiwidHlwZSI6WyJWZXJpZmlhYmxlQ3JlZGVudGlhbCJdLCJjcmVkZW50aWFsU3ViamVjdCI6eyJpZCI6ImRpZDpkaHQ6cWdtbXB5anc1aHducWZnem43d21ybTMzYWR5OGdiOHo5aWRlaWI2bTlnajR5czZ3bnk4eSJ9fX0.eZfQZdkDB2D2QMs6BPaxjU-FCJLIGMlCz0sF5FjhHkaizItfv3zGXqWVEjc8f-SRiLSmujlEKgwfw22cCvnDAQ"#;

let result = VerifiableCredential::from_vc_jwt(vc_jwt_with_invalid_url, true);

match result {
Err(Web5Error::Network(err_msg)) => {
assert!(err_msg.contains("unable to resolve json schema"))
assert!(
err_msg.contains("failed to connect to host"),
"Error message is: {}",
err_msg
)
}
_ => panic!(
"expected Web5Error::Network with specific message but got {:?}",
Expand All @@ -797,8 +801,8 @@ mod tests {

let result = VerifiableCredential::from_vc_jwt(vc_jwt_at_port, true);
match result {
Err(Web5Error::JsonSchema(err_msg)) => {
assert!(err_msg.contains("non-200 response when resolving json schema"))
Err(Web5Error::Http(err_msg)) => {
assert_eq!("non-successful response code 500", err_msg)
}
_ => panic!(
"expected Web5Error::JsonSchema with specific message but got {:?}",
Expand Down Expand Up @@ -827,8 +831,8 @@ mod tests {

let result = VerifiableCredential::from_vc_jwt(vc_jwt_at_port, true);
match result {
Err(Web5Error::JsonSchema(err_msg)) => {
assert!(err_msg.contains("unable to parse json schema from response body"))
Err(Web5Error::Http(err_msg)) => {
assert!(err_msg.contains("unable to parse json response body"))
}
_ => panic!(
"expected Web5Error::JsonSchema with specific message but got {:?}",
Expand Down
43 changes: 9 additions & 34 deletions crates/web5/src/dids/methods/did_dht/mod.rs
Original file line number Diff line number Diff line change
@@ -1,5 +1,4 @@
use bep44::Bep44Message;
use reqwest::blocking::Client;
use simple_dns::Packet;

use crate::{
Expand All @@ -19,6 +18,7 @@ use crate::{
},
},
errors::{Result, Web5Error},
http::{get_bytes_as_http_response, put_bytes_as_http_response},
};
use std::sync::Arc;

Expand Down Expand Up @@ -130,15 +130,8 @@ impl DidDht {
bearer_did.did.id.trim_start_matches('/')
);

let client = Client::new();
let response = client
.put(url)
.header("Content-Type", "application/octet-stream")
.body(body)
.send()
.map_err(|_| Web5Error::Network("failed to publish DID to mainline".to_string()))?;

if response.status() != 200 {
let response = put_bytes_as_http_response(&url, &body)?;
if response.status_code != 200 {
return Err(Web5Error::Network(
"failed to PUT DID to mainline".to_string(),
));
Expand Down Expand Up @@ -170,35 +163,17 @@ impl DidDht {
did.id.trim_start_matches('/')
);

let client = Client::new();

// Make the GET request
let response = client
.get(url)
.send()
let response = get_bytes_as_http_response(&url)
.map_err(|_| ResolutionMetadataError::InternalError)?;

// Check if the status is not 200
let status = response.status();
if status == 404 {
return Err(ResolutionMetadataError::NotFound)?;
} else if status != 200 {
return Err(ResolutionMetadataError::InternalError)?;
}

// check http response status is 200 and body is nonempty
let body = response
.bytes()
.map_err(|_| ResolutionMetadataError::NotFound)?;

// Check if the body is empty
if body.is_empty() {
return Err(ResolutionMetadataError::NotFound)?;
if response.status_code == 404 {
return Err(ResolutionMetadataError::NotFound);
} else if response.status_code != 200 {
return Err(ResolutionMetadataError::InternalError);
}

// bep44 decode and verify response body bytes
let body: Vec<u8> = body.into();
let bep44_message = Bep44Message::decode(&body)
let bep44_message = Bep44Message::decode(&response.body)
.map_err(|_| ResolutionMetadataError::InvalidDidDocument)?;
bep44_message
.verify(&Ed25519Verifier::new(identity_key))
Expand Down
46 changes: 14 additions & 32 deletions crates/web5/src/dids/methods/did_web/resolver.rs
Original file line number Diff line number Diff line change
@@ -1,11 +1,13 @@
use crate::dids::{
data_model::document::Document,
did::Did,
resolution::{
resolution_metadata::ResolutionMetadataError, resolution_result::ResolutionResult,
use crate::{
dids::{
data_model::document::Document,
did::Did,
resolution::{
resolution_metadata::ResolutionMetadataError, resolution_result::ResolutionResult,
},
},
http::get_json,
};
use reqwest::header::HeaderMap;
use std::{
future::{Future, IntoFuture},
pin::Pin,
Expand Down Expand Up @@ -48,32 +50,12 @@ impl Resolver {
}

async fn resolve(url: String) -> Result<ResolutionResult, ResolutionMetadataError> {
let headers = HeaderMap::new();

let client = reqwest::Client::builder()
.default_headers(headers)
.build()
.map_err(|_| ResolutionMetadataError::InternalError)?;

let response = client
.get(&url)
.send()
.await
.map_err(|_| ResolutionMetadataError::InternalError)?;

if response.status().is_success() {
let did_document = response
.json::<Document>()
.await
.map_err(|_| ResolutionMetadataError::RepresentationNotSupported)?;

Ok(ResolutionResult {
document: Some(did_document),
..Default::default()
})
} else {
Err(ResolutionMetadataError::NotFound)
}
let document =
get_json::<Document>(&url).map_err(|_| ResolutionMetadataError::InternalError)?;
Ok(ResolutionResult {
document: Some(document),
..Default::default()
})
}
}

Expand Down
2 changes: 2 additions & 0 deletions crates/web5/src/errors.rs
Original file line number Diff line number Diff line change
Expand Up @@ -29,6 +29,8 @@ pub enum Web5Error {
Network(String),
#[error("datetime error {0}")]
DateTime(String),
#[error("http error {0}")]
Http(String),

#[error(transparent)]
Resolution(#[from] ResolutionMetadataError),
Expand Down
Loading
Loading