Web request helper and other stuff.

This commit is contained in:
Adam Ierymenko 2021-03-19 17:21:16 -04:00
parent 6df6a955ba
commit 1b9ec2d9c3
No known key found for this signature in database
GPG key ID: C8877CF2D7A5D7F3
14 changed files with 263 additions and 233 deletions

View file

@ -134,12 +134,6 @@ void lockDownFile(const char *path, int isDir)
void getSecureRandom(void *buf, unsigned int len)
{ ZeroTier::Utils::getSecureRandom(buf, len); }
void sha384(const void *in, unsigned int len, void *out)
{ ZeroTier::SHA384(out, in, len); }
void sha512(const void *in, unsigned int len, void *out)
{ ZeroTier::SHA512(out, in, len); }
static ZT_INLINE ZeroTier::AES _makeHttpAuthCipher() noexcept
{
uint8_t key[32];

View file

@ -102,15 +102,28 @@ extern const unsigned long c_SIOCAUTOCONF_STOP;
extern "C" {
#endif
// Get the default home path for this platform.
extern const char *platformDefaultHomePath();
// This ms-since-epoch function may be faster than the one in Rust's stdlib.
extern int64_t msSinceEpoch();
// Rust glue to C code to lock down a file, which is simple on Unix-like OSes
// and horrible on Windows.
extern void lockDownFile(const char *path, int isDir);
// Rust glue to ZeroTier's secure random PRNG.
extern void getSecureRandom(void *buf, unsigned int len);
extern void sha384(const void *in, unsigned int len, void *out);
extern void sha512(const void *in, unsigned int len, void *out);
// These AES encrypt and decrypt a single block using a key that is randomly
// generated at process init and never exported. It's used to generate HTTP
// digest authentication tokens that can just be decrypted to get and check
// a timestamp to prevent replay attacks.
extern void encryptHttpAuthNonce(void *block);
extern void decryptHttpAuthNonce(void *block);
#ifdef __cplusplus
}
#endif
/********************************************************************************************************************/

248
service/Cargo.lock generated
View file

@ -26,15 +26,6 @@ version = "1.0.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "cdb031dd78e28731d87d56cc8ffef4a8f36ca26c38fe2de700543e627f8a464a"
[[package]]
name = "base64"
version = "0.10.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "0b25d992356d2eb0ed82172f5248873db5560c4721f564b13cb5193bda5e668e"
dependencies = [
"byteorder",
]
[[package]]
name = "base64"
version = "0.13.0"
@ -47,7 +38,7 @@ version = "0.6.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "2e964e3e0a930303c7c0bdb28ebf691dd98d9eee4b8b68019d2c995710b58a18"
dependencies = [
"base64 0.13.0",
"base64",
"serde",
]
@ -58,19 +49,12 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "cf1de2fe8c75bc145a2f577add951f8134889b4795d47466a54a5c846d691693"
[[package]]
name = "byteorder"
version = "1.4.3"
name = "block-buffer"
version = "0.9.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "14c189c53d098945499cdfa7ecc63567cf3886b3332b312a5b4585d8d3a6a610"
[[package]]
name = "bytes"
version = "0.4.12"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "206fdffcfa2df7cbe15601ef46c813fce0965eb3286db6b56c583b814b51c81c"
checksum = "4152116fd6e9dadb291ae18fc1ec3575ed6d84c29642d97890f4b4a3417297e4"
dependencies = [
"byteorder",
"iovec",
"generic-array",
]
[[package]]
@ -136,6 +120,12 @@ dependencies = [
"winapi-util",
]
[[package]]
name = "cpuid-bool"
version = "0.1.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "8aebca1129a03dc6dc2b127edd729435bbc4a37e1d5f4d7513165089ceb02634"
[[package]]
name = "dialoguer"
version = "0.7.1"
@ -148,6 +138,28 @@ dependencies = [
"zeroize",
]
[[package]]
name = "digest"
version = "0.9.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "d3dd60d1080a57a05ab032377049e0591415d2b31afd7028356dbf3cc6dcb066"
dependencies = [
"generic-array",
]
[[package]]
name = "digest_auth"
version = "0.2.4"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "12fd5e24649b07f360f59a1e0a522d775540e2bc4b88f8d2657bcf8ca0360d74"
dependencies = [
"digest",
"hex",
"md-5",
"rand",
"sha2",
]
[[package]]
name = "encode_unicode"
version = "0.3.6"
@ -255,6 +267,16 @@ dependencies = [
"slab",
]
[[package]]
name = "generic-array"
version = "0.14.4"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "501466ecc8a30d1d3b7fc9229b122b2ce8ed6e9d9223f1138d4babb253e51817"
dependencies = [
"typenum",
"version_check",
]
[[package]]
name = "getrandom"
version = "0.2.2"
@ -281,24 +303,13 @@ version = "0.4.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "644f9158b2f133fd50f5fb3242878846d9eb792e445c893805ff0e3824006e35"
[[package]]
name = "http"
version = "0.1.21"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "d6ccf5ede3a895d8856620237b2f02972c1bbc78d2965ad7fe8838d4a0ed41f0"
dependencies = [
"bytes 0.4.12",
"fnv",
"itoa",
]
[[package]]
name = "http"
version = "0.2.3"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "7245cd7449cc792608c3c8a9eaf69bd4eabbabf802713748fd739c98b82f0747"
dependencies = [
"bytes 1.0.1",
"bytes",
"fnv",
"itoa",
]
@ -309,8 +320,8 @@ version = "0.4.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "2861bd27ee074e5ee891e8b539837a9430012e249d7f0ca2d795650f579c1994"
dependencies = [
"bytes 1.0.1",
"http 0.2.3",
"bytes",
"http",
]
[[package]]
@ -331,11 +342,11 @@ version = "0.14.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "12219dc884514cb4a6a03737f4413c0e01c23a1b059b0156004b23f1e19dccbe"
dependencies = [
"bytes 1.0.1",
"bytes",
"futures-channel",
"futures-core",
"futures-util",
"http 0.2.3",
"http",
"http-body",
"httparse",
"httpdate",
@ -348,56 +359,12 @@ dependencies = [
"want",
]
[[package]]
name = "hyperx"
version = "0.13.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "e4a94cbc2c6f63028e5736ca4e811ae36d3990059c384cbe68298c66728a9776"
dependencies = [
"base64 0.10.1",
"bytes 0.4.12",
"http 0.1.21",
"httparse",
"language-tags",
"log",
"mime",
"percent-encoding",
"time",
"unicase 2.6.0",
]
[[package]]
name = "idna"
version = "0.1.5"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "38f09e0f0b1fb55fdee1f17470ad800da77af5186a1a76c026b679358b7e844e"
dependencies = [
"matches",
"unicode-bidi",
"unicode-normalization",
]
[[package]]
name = "iovec"
version = "0.1.4"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "b2b3ea6ff95e175473f8ffe6a7eb7c00d054240321b84c57051175fe3c1e075e"
dependencies = [
"libc",
]
[[package]]
name = "itoa"
version = "0.4.7"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "dd25036021b0de88a0aff6b850051563c6516d0bf53f8638938edbb9de732736"
[[package]]
name = "language-tags"
version = "0.2.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "a91d884b6667cd606bb5a69aa0c99ba811a115fc68915e7056ec08a46e93199a"
[[package]]
name = "lazy_static"
version = "1.4.0"
@ -420,10 +387,15 @@ dependencies = [
]
[[package]]
name = "matches"
version = "0.1.8"
name = "md-5"
version = "0.9.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "7ffc5c5338469d4d3ea17d269fa8ea3512ad247247c30bd2df69e68309ed0a08"
checksum = "7b5a279bb9607f9f53c22d496eade00d138d1bdcccd07d74650387cf94942a15"
dependencies = [
"block-buffer",
"digest",
"opaque-debug",
]
[[package]]
name = "memchr"
@ -431,12 +403,6 @@ version = "2.3.4"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "0ee1c47aaa256ecabcaea351eae4a9b01ef39ed810004e298d2511ed284b1525"
[[package]]
name = "mime"
version = "0.3.16"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "2a60c7ce501c71e03a9c9c0d35b861413ae925bd979cc7a4e30d060069aaac8d"
[[package]]
name = "mio"
version = "0.7.7"
@ -516,10 +482,10 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "13bd41f508810a131401606d54ac32a467c97172d74ba7662562ebba5ad07fa0"
[[package]]
name = "percent-encoding"
version = "1.0.1"
name = "opaque-debug"
version = "0.3.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "31010dd2e1ac33d5b46a5b413495239882813e0369f8ed8a5e266f173602f831"
checksum = "624a8340c38c1b80fd549087862da4ba43e08858af025b236e509b6649fc13d5"
[[package]]
name = "pin-project"
@ -699,6 +665,19 @@ dependencies = [
"serde",
]
[[package]]
name = "sha2"
version = "0.9.3"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "fa827a14b29ab7f44778d14a88d3cb76e949c45083f7dbfa507d0cb699dc12de"
dependencies = [
"block-buffer",
"cfg-if 1.0.0",
"cpuid-bool",
"digest",
"opaque-debug",
]
[[package]]
name = "signal-hook-registry"
version = "1.3.0"
@ -796,21 +775,6 @@ dependencies = [
"winapi",
]
[[package]]
name = "tinyvec"
version = "1.1.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "317cca572a0e89c3ce0ca1f1bdc9369547fe318a683418e42ac8f59d14701023"
dependencies = [
"tinyvec_macros",
]
[[package]]
name = "tinyvec_macros"
version = "0.1.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "cda74da7e1a664f795bb1f8a87ec406fb89a02522cf6e50620d016add6dbbf5c"
[[package]]
name = "tokio"
version = "1.0.2"
@ -871,40 +835,10 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "59547bce71d9c38b83d9c0e92b6066c4253371f15005def0c30d9657f50c7642"
[[package]]
name = "unicase"
version = "1.4.2"
name = "typenum"
version = "1.13.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "7f4765f83163b74f957c797ad9253caf97f103fb064d3999aea9568d09fc8a33"
dependencies = [
"version_check 0.1.5",
]
[[package]]
name = "unicase"
version = "2.6.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "50f37be617794602aabbeee0be4f259dc1778fabe05e2d67ee8f79326d5cb4f6"
dependencies = [
"version_check 0.9.3",
]
[[package]]
name = "unicode-bidi"
version = "0.3.4"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "49f2bd0c6468a8230e1db229cff8029217cf623c767ea5d60bfbd42729ea54d5"
dependencies = [
"matches",
]
[[package]]
name = "unicode-normalization"
version = "0.1.17"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "07fbfce1c8a97d547e8b5334978438d9d6ec8c20e38f56d4a4374d181493eaef"
dependencies = [
"tinyvec",
]
checksum = "879f6906492a7cd215bfa4cf595b600146ccfac0c79bcbd1f3000162af5e8b06"
[[package]]
name = "unicode-width"
@ -918,29 +852,12 @@ version = "0.2.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "f7fe0bb3479651439c9112f72b6c505038574c9fbb575ed1bf3b797fa39dd564"
[[package]]
name = "url"
version = "1.7.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "dd4e7c0d531266369519a4aa4f399d748bd37043b00bde1e4ff1f60a120b355a"
dependencies = [
"idna",
"matches",
"percent-encoding",
]
[[package]]
name = "vec_map"
version = "0.8.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "f1bddf1187be692e79c5ffeab891132dfb0f236ed36a43c7ed39f1165ee20191"
[[package]]
name = "version_check"
version = "0.1.5"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "914b1a6776c4c929a602fafd8bc742e06365d4bcbe48c30f9cca5824f70dc9dd"
[[package]]
name = "version_check"
version = "0.9.3"
@ -994,17 +911,6 @@ version = "0.4.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "712e227841d057c1ee1cd2fb22fa7e5a5461ae8e48fa2ca79ec42cfc1931183f"
[[package]]
name = "www-authenticate"
version = "0.3.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "8c62efb8259cda4e4c732287397701237b78daa4c43edcf3e613c8503a6c07dd"
dependencies = [
"hyperx",
"unicase 1.4.2",
"url",
]
[[package]]
name = "zeroize"
version = "0.9.3"
@ -1015,7 +921,7 @@ checksum = "45af6a010d13e4cf5b54c94ba5a2b2eba5596b9e46bf5875612d332a1f2b3f86"
name = "zerotier-core"
version = "0.1.0"
dependencies = [
"base64 0.13.0",
"base64",
"base64-serde",
"hex",
"num-derive",
@ -1031,6 +937,7 @@ dependencies = [
"chrono",
"clap",
"dialoguer",
"digest_auth",
"futures",
"hex",
"hyper",
@ -1043,6 +950,5 @@ dependencies = [
"socket2",
"tokio",
"winapi",
"www-authenticate",
"zerotier-core",
]

View file

@ -23,7 +23,7 @@ num-derive = "0"
hyper = { version = "0", features = ["http1", "runtime", "server", "client", "tcp", "stream"] }
socket2 = { version = "0", features = ["reuseport", "unix", "pair"] }
dialoguer = "0"
www-authenticate = "0"
digest_auth = "0"
[target."cfg(windows)".dependencies]
winapi = { version = "0.3.9", features = ["handleapi", "ws2ipdef", "ws2tcpip"] }

View file

@ -0,0 +1,13 @@
/*
* Copyright (c)2013-2021 ZeroTier, Inc.
*
* Use of this software is governed by the Business Source License included
* in the LICENSE.TXT file in the project's root directory.
*
* Change Date: 2026-01-01
*
* On the date above, in accordance with the Business Source License, use
* of this software will be governed by version 2.0 of the Apache License.
*/
/****/

View file

@ -0,0 +1,13 @@
/*
* Copyright (c)2013-2021 ZeroTier, Inc.
*
* Use of this software is governed by the Business Source License included
* in the LICENSE.TXT file in the project's root directory.
*
* Change Date: 2026-01-01
*
* On the date above, in accordance with the Business Source License, use
* of this software will be governed by version 2.0 of the Apache License.
*/
/****/

View file

@ -0,0 +1,13 @@
/*
* Copyright (c)2013-2021 ZeroTier, Inc.
*
* Use of this software is governed by the Business Source License included
* in the LICENSE.TXT file in the project's root directory.
*
* Change Date: 2026-01-01
*
* On the date above, in accordance with the Business Source License, use
* of this software will be governed by version 2.0 of the Apache License.
*/
/****/

View file

@ -0,0 +1,13 @@
/*
* Copyright (c)2013-2021 ZeroTier, Inc.
*
* Use of this software is governed by the Business Source License included
* in the LICENSE.TXT file in the project's root directory.
*
* Change Date: 2026-01-01
*
* On the date above, in accordance with the Business Source License, use
* of this software will be governed by version 2.0 of the Apache License.
*/
/****/

View file

@ -0,0 +1,13 @@
/*
* Copyright (c)2013-2021 ZeroTier, Inc.
*
* Use of this software is governed by the Business Source License included
* in the LICENSE.TXT file in the project's root directory.
*
* Change Date: 2026-01-01
*
* On the date above, in accordance with the Business Source License, use
* of this software will be governed by version 2.0 of the Apache License.
*/
/****/

View file

@ -0,0 +1,13 @@
/*
* Copyright (c)2013-2021 ZeroTier, Inc.
*
* Use of this software is governed by the Business Source License included
* in the LICENSE.TXT file in the project's root directory.
*
* Change Date: 2026-01-01
*
* On the date above, in accordance with the Business Source License, use
* of this software will be governed by version 2.0 of the Apache License.
*/
/****/

View file

@ -11,22 +11,17 @@
*/
/****/
use std::rc::Rc;
use std::str::FromStr;
use std::sync::Arc;
use hyper::Uri;
use crate::store::Store;
pub(crate) fn run(store: Arc<Store>) -> i32 {
crate::webclient::command(store.clone(), move |client, uri| {
async move {
let mut res = client.get(uri).await?;
println!("status: {}", res.status().as_str());
let body = hyper::body::to_bytes(res.body_mut()).await?;
String::from_utf8(body.to_vec()).map(|body| {
println!("body: {}", body.as_str());
});
Ok(0)
}
})
use crate::store::Store;
use crate::webclient::HttpClient;
pub(crate) async fn run(store: Arc<Store>, client: HttpClient, api_base_uri: Uri, auth_token: String) -> hyper::Result<i32> {
let mut res = client.get(api_base_uri).await?;
let body = hyper::body::to_bytes(res.body_mut()).await?;
Ok(0)
}

View file

@ -28,9 +28,7 @@ mod weblistener;
#[allow(non_snake_case, non_upper_case_globals, non_camel_case_types, dead_code, improper_ctypes)]
mod osdep; // bindgen generated
use std::boxed::Box;
use std::io::Write;
use std::rc::Rc;
use std::sync::Arc;
use std::str::FromStr;
@ -315,7 +313,7 @@ fn main() {
println!("{}.{}.{}", ver.0, ver.1, ver.2);
0
}
("status", _) => crate::commands::status::run(make_store(&cli_args)),
("status", _) => crate::webclient::run_command(make_store(&cli_args), crate::commands::status::run),
("set", Some(sub_cli_args)) => { 0 }
("peer", Some(sub_cli_args)) => { 0 }
("network", Some(sub_cli_args)) => { 0 }
@ -323,7 +321,7 @@ fn main() {
("leave", Some(sub_cli_args)) => { 0 }
("service", _) => {
let store = make_store(&cli_args);
drop(cli_args); // free memory
drop(cli_args); // free no longer needed memory before entering service
service::run(store)
},
("controller", Some(sub_cli_args)) => { 0 }

View file

@ -23,26 +23,6 @@ use zerotier_core::{Identity, Locator};
use crate::osdep;
use crate::osdep::time;
#[inline(always)]
pub(crate) fn sha512<T: AsRef<[u8]>>(data: T) -> [u8; 64] {
let mut r: MaybeUninit<[u8; 64]> = MaybeUninit::uninit();
let d = data.as_ref();
unsafe {
osdep::sha512(d.as_ptr().cast(), d.len() as c_uint, r.as_mut_ptr().cast());
r.assume_init()
}
}
#[inline(always)]
pub(crate) fn sha384<T: AsRef<[u8]>>(data: T) -> [u8; 48] {
let mut r: MaybeUninit<[u8; 48]> = MaybeUninit::uninit();
let d = data.as_ref();
unsafe {
osdep::sha384(d.as_ptr().cast(), d.len() as c_uint, r.as_mut_ptr().cast());
r.assume_init()
}
}
#[inline(always)]
pub(crate) fn ms_since_epoch() -> i64 {
// This is easy to do in the Rust stdlib, but the version in OSUtils is probably faster.

View file

@ -11,34 +11,100 @@
*/
/****/
use std::error::Error;
use std::future::Future;
use std::str::FromStr;
use std::time::Duration;
use hyper::Uri;
use std::rc::Rc;
use std::sync::Arc;
use crate::store::Store;
use std::future::Future;
/// Launch the supplied function inside the tokio runtime.
/// The return value of this function should be the process exit code.
/// This is for implementation of commands that query the HTTP API, not HTTP
/// requests from a running server.
pub(crate) fn command<'a, R: Future<Output = hyper::Result<i32>>, F: FnOnce(Arc<hyper::Client<hyper::client::HttpConnector, hyper::Body>>, hyper::Uri) -> R>(store: Arc<Store>, func: F) -> i32 {
use hyper::{Uri, Response, Body, Method, Request, StatusCode};
use crate::store::Store;
pub(crate) type HttpClient = Rc<hyper::Client<hyper::client::HttpConnector, Body>>;
/// Launch the supplied function with a ready to go HTTP client, the auth token, and the API URI.
/// This is boilerplate code for CLI commands that invoke the HTTP API. Since it instantiates and
/// then kills a tokio runtime, it's not for use in the service code that runs in a long-running
/// tokio runtime.
pub(crate) fn run_command<
R: Future<Output = hyper::Result<i32>>,
F: FnOnce(Arc<Store>, HttpClient, Uri, String) -> R
>(store: Arc<Store>, func: F) -> i32 {
let rt = tokio::runtime::Builder::new_current_thread().enable_all().build().unwrap();
let code = rt.block_on(async move {
let uri = store.load_uri();
if uri.is_err() {
println!("ERROR: unable to read 'zerotier.uri' to get local HTTP API address.");
println!("ERROR: 'zerotier.uri' not found in '{}', unable to get service API endpoint.", store.base_path.to_str().unwrap());
1
} else {
let f = func(Arc::new(hyper::Client::new()), uri.unwrap());
f.await.map_or_else(|e| {
println!("ERROR: HTTP request failed: {}", e.to_string());
let auth_token = store.auth_token(false);
if auth_token.is_err() {
println!("ERROR: unable to read API authorization token from '{}': {}", store.base_path.to_str().unwrap(), auth_token.err().unwrap().to_string());
1
}, |code| {
code
})
} else {
let uri = uri.unwrap();
let uri_str = uri.to_string();
func(store, Rc::new(hyper::Client::new()), uri, auth_token.unwrap()).await.map_or_else(|e| {
println!("ERROR: service API HTTP request failed: {}", e.to_string());
println!("ZeroTier service may not be running or '{}' may be unreachable.", uri_str);
1
}, |code| {
code
})
}
}
});
rt.shutdown_timeout(Duration::from_millis(10));
rt.shutdown_timeout(Duration::from_millis(1)); // all tasks should be done in a command anyway, this is just a sanity check
code
}
/// Send a request to the API with support for HTTP digest authentication.
/// The data option is for PUT and POST requests. For GET it is ignored. Errors indicate total
/// failure such as connection refused. A returned result must still have its status checked. If
/// it's 401 (unauthorized) it likely means the auth_token is wrong.
pub(crate) async fn request<D: AsRef<[u8]>>(client: &HttpClient, method: Method, uri: Uri, data: D, auth_token: String) -> Result<Response<Body>, Box<dyn Error>> {
let body = data.as_ref().to_vec();
let req = Request::builder().method(&method).version(hyper::Version::HTTP_11).uri(&uri).body(Body::from(body.clone()));
if req.is_err() {
return Err(Box::new(req.err().unwrap()));
}
let res = client.request(req.unwrap()).await;
if res.is_err() {
return Err(Box::new(res.err().unwrap()));
}
let res = res.unwrap();
if res.status() == StatusCode::UNAUTHORIZED {
let auth = res.headers().get(hyper::header::WWW_AUTHENTICATE);
if auth.is_none() {
return Ok(res); // return the 401 reply
}
let auth = auth.unwrap().to_str();
if auth.is_err() {
return Err(Box::new(auth.err().unwrap()));
}
let mut auth = digest_auth::parse(auth.unwrap());
if auth.is_err() {
return Err(Box::new(auth.err().unwrap()));
}
let ac = digest_auth::AuthContext::new("zerotier", auth_token, uri.to_string());
let auth = auth.unwrap().respond(&ac);
if auth.is_err() {
return Err(Box::new(auth.err().unwrap()));
}
let req = Request::builder().method(&method).version(hyper::Version::HTTP_11).uri(&uri).header(hyper::header::WWW_AUTHENTICATE, auth.unwrap().to_header_string()).body(Body::from(body));
if req.is_err() {
return Err(Box::new(req.err().unwrap()));
}
let res = client.request(req.unwrap()).await;
if res.is_err() {
return Err(Box::new(res.err().unwrap()));
}
return Ok(res.unwrap());
}
return Ok(res);
}