diff --git a/Cargo.toml b/Cargo.toml index ad2fec4..9060133 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -15,20 +15,20 @@ edition = "2018" [dependencies] anyhow = "1.0" -base64 = "0.21" -lazy_static = "1.4" +base64 = "0.22" +lazy_static = "1" log = "0.4" openssl = "0.10" -serde = { version = "1.0", features = ["derive"] } -serde_json = "1.0" +serde = { version = "1", features = ["derive"] } +serde_json = "1" time = { version = "0.3", features = ["local-offset"] } time-fmt = "0.3" time-tz = "1" -ureq = "1" +ureq = "2" [dev-dependencies] doc-comment = "0.3" -env_logger = { version = "0.10", default-features = false } +env_logger = { version = "0.11", default-features = false } futures = "0.1.25" hyper = "0.12" regex = "1.4" diff --git a/src/cert.rs b/src/cert.rs index ccd9c23..eedb6d6 100644 --- a/src/cert.rs +++ b/src/cert.rs @@ -59,15 +59,12 @@ pub(crate) fn create_csr(pkey: &PKey, domains: &[&str]) -> Result // set all domains as alt names let mut stack = Stack::new()?; let ctx = req_bld.x509v3_context(None); - let as_lst = domains - .iter() - .map(|&e| format!("DNS:{}", e)) - .collect::>() - .join(", "); - let as_lst = as_lst[4..].to_string(); let mut an = SubjectAlternativeName::new(); - an.dns(&as_lst); - let ext = an.build(&ctx)?; + for d in domains { + an.dns(d); + } + + let ext = an.build(&ctx).context("SubjectAlternativeName::build")?; stack.push(ext).expect("Stack::push"); req_bld.add_extensions(&stack)?; diff --git a/src/req.rs b/src/req.rs index b093b66..6b0dd5e 100644 --- a/src/req.rs +++ b/src/req.rs @@ -3,39 +3,43 @@ use crate::error::*; pub(crate) type ReqResult = std::result::Result; -pub(crate) fn req_get(url: &str) -> ureq::Response { - let mut req = ureq::get(url); - req_configure(&mut req); +const TIMEOUT_DURATION: std::time::Duration = std::time::Duration::from_secs(30); + +pub(crate) fn req_get(url: &str) -> Result { + let req = ureq::get(url).timeout(TIMEOUT_DURATION); trace!("{:?}", req); req.call() } -pub(crate) fn req_head(url: &str) -> ureq::Response { - let mut req = ureq::head(url); - req_configure(&mut req); +pub(crate) fn req_head(url: &str) -> Result { + let req = ureq::head(url).timeout(TIMEOUT_DURATION); trace!("{:?}", req); req.call() } -pub(crate) fn req_post(url: &str, body: &str) -> ureq::Response { - let mut req = ureq::post(url); - req.set("content-type", "application/jose+json"); - req_configure(&mut req); +pub(crate) fn req_post(url: &str, body: &str) -> Result { + let req = ureq::post(url) + .set("content-type", "application/jose+json") + .timeout(TIMEOUT_DURATION); trace!("{:?} {}", req, body); req.send_string(body) } -fn req_configure(req: &mut ureq::Request) { - req.timeout_connect(30_000); - req.timeout_read(30_000); - req.timeout_write(30_000); -} - -pub(crate) fn req_handle_error(res: ureq::Response) -> ReqResult { - // ok responses pass through - if res.ok() { - return Ok(res); - } +pub(crate) fn req_handle_error( + res: Result, +) -> ReqResult { + let res = match res { + // ok responses pass through + Ok(res) => return Ok(res), + Err(ureq::Error::Status(_, res)) => res, + Err(ureq::Error::Transport(_)) => { + return Err(ApiProblem { + _type: "httpReqError".into(), + detail: Some("Transport error".into()), + subproblems: None, + }) + } + }; let problem = if res.content_type() == "application/problem+json" { // if we were sent a problem+json, deserialize it diff --git a/src/test/mod.rs b/src/test/mod.rs index 1e528f4..797d6ba 100644 --- a/src/test/mod.rs +++ b/src/test/mod.rs @@ -212,5 +212,5 @@ pub fn with_directory_server() -> TestServer { pub fn test_make_directory() { let server = with_directory_server(); let res = ureq::get(&server.dir_url).call(); - assert!(res.ok()); + assert!(res.is_ok()); } diff --git a/src/trans.rs b/src/trans.rs index 58d0eeb..8665ed7 100644 --- a/src/trans.rs +++ b/src/trans.rs @@ -115,7 +115,13 @@ impl NoncePool { } } - fn extract_nonce(&self, res: &ureq::Response) { + fn extract_nonce(&self, res: &std::result::Result) { + let res = match res { + Ok(res) => res, + Err(ureq::Error::Status(_, res)) => res, + Err(ureq::Error::Transport(_)) => return, + }; + if let Some(nonce) = res.header("replay-nonce") { trace!("Extract nonce"); let mut pool = self.pool.lock().unwrap(); @@ -136,6 +142,15 @@ impl NoncePool { } debug!("Request new nonce"); let res = req_head(&self.nonce_url); + + let res = match res { + Ok(res) => res, + Err(ureq::Error::Status(_, res)) => res, + Err(ureq::Error::Transport(err)) => { + return Err(Error::new(err).context("Transport error during request")) + } + }; + Ok(req_expect_header(&res, "replay-nonce")?) } } diff --git a/src/util.rs b/src/util.rs index b4d54a5..c883dc8 100644 --- a/src/util.rs +++ b/src/util.rs @@ -1,17 +1,11 @@ -use base64::engine::Engine; -use lazy_static::lazy_static; +use base64::Engine; use serde::de::DeserializeOwned; use crate::error::*; use crate::req::req_safe_read_body; -lazy_static! { - static ref BASE64_CONFIG: base64::engine::general_purpose::GeneralPurpose = - base64::engine::general_purpose::URL_SAFE; -} - pub(crate) fn base64url>(input: &T) -> String { - BASE64_CONFIG.encode(input) + base64::prelude::BASE64_URL_SAFE_NO_PAD.encode(input) } pub(crate) fn read_json(res: ureq::Response) -> Result {