depolymerization

wire gateway for Bitcoin/Ethereum
Log | Files | Refs | Submodules | README | LICENSE

commit 3d6220f5a2e60230a92d460154eb2b3565852dc2
parent 643cd6cf56acd87de54d2278ecfcf8c0266e3235
Author: Antoine A <>
Date:   Tue,  8 Mar 2022 16:19:58 +0100

wire-gateway: support auth

Diffstat:
MREADME.md | 12+++++++-----
Mbtc-wire/src/btc_config.rs | 4++--
Mbtc-wire/src/lib.rs | 2+-
Mcommon/src/config.rs | 41++++++++++++++++++++++++++---------------
Adocs/taler-btc-full.conf | 20++++++++++++++++++++
Adocs/taler-btc-min.conf | 11+++++++++++
Ddocs/taler-btc.conf | 17-----------------
Adocs/taler-eth-full.conf | 20++++++++++++++++++++
Adocs/taler-eth-min.conf | 11+++++++++++
Ddocs/taler-eth.conf | 17-----------------
Meth-wire/src/lib.rs | 2+-
Mmakefile | 3++-
Mtest/common.sh | 2+-
Mtest/conf/taler_btc.conf | 1+
Atest/conf/taler_btc_auth.conf | 19+++++++++++++++++++
Mtest/conf/taler_btc_bump.conf | 5+++--
Mtest/conf/taler_btc_lifetime.conf | 5+++--
Mtest/conf/taler_eth.conf | 5+++--
Mtest/conf/taler_eth_bump.conf | 5+++--
Mtest/conf/taler_eth_lifetime.conf | 5+++--
Mtest/gateway/api.sh | 15+++++++--------
Atest/gateway/auth.sh | 31+++++++++++++++++++++++++++++++
Mwire-gateway/src/main.rs | 22+++++++++++++++++++++-
23 files changed, 196 insertions(+), 79 deletions(-)

diff --git a/README.md b/README.md @@ -35,12 +35,14 @@ The configuration is based on You can find filled configurations for each implementation: -- [btc-wire](docs/taler-btc.conf) -- [eth-wire](docs/taler-eth.conf) +- btc-wire: [minimal](docs/taler-btc-min.conf) or + [full](docs/taler-btc-full.conf) +- eth-wire: [minimal](docs/taler-eth-min.conf) or + [full](docs/taler-eth-full.conf) ### Initialization -This is the minimal required config for initialization. +This is the required configuration for initialization. ```ini # taler.conf - (fill all ___) @@ -55,8 +57,6 @@ BASE_URL = ___ [depolymerizer-___] # Postgres connection URL DB_URL = ___ -# Wire payto URL -# PAYTO = ___ ``` `PAYTO` is to be added after wallet initialization. @@ -100,6 +100,8 @@ BOUNCE_FEE = 0.00001 PORT = 8080 # Path on which the server listen (replace port) UNIXPATH = +# HTTP Authentication Scheme (basic or none) +AUTH_METHOD = ``` ### Process lifetime diff --git a/btc-wire/src/btc_config.rs b/btc-wire/src/btc_config.rs @@ -87,14 +87,14 @@ impl BitcoinConfig { let port = if let Some(addr) = section.and_then(|s| s.get("rpcport")) { addr.parse() - .or_fail(|_| "bitcoin config value 'rpcport' is not a valid port number".into()) + .or_fail(|_| "bitcoin config 'rpcport' is not a valid port number".into()) } else { rpc_port(network) }; let addr = if let Some(addr) = section.and_then(|s| s.get("rpcbind")) { SocketAddr::from_str(addr) - .or_fail(|_| "bitcoin config value 'rpcbind' is not a valid socket address".into()) + .or_fail(|_| "bitcoin config 'rpcbind' is not a valid socket address".into()) } else { ([127, 0, 0, 1], port).into() }; diff --git a/btc-wire/src/lib.rs b/btc-wire/src/lib.rs @@ -202,7 +202,7 @@ fn config_bounce_fee(bounce_fee: &Option<String>, currency: CurrencyBtc) -> Amou .and_then(|a| taler_to_btc(&a, currency)) .or_fail(|a| { format!( - "config value BOUNCE_FEE={} is not a valid bitcoin amount: {}", + "config BOUNCE_FEE={} is not a valid bitcoin amount: {}", config, a ) }) diff --git a/common/src/config.rs b/common/src/config.rs @@ -57,12 +57,8 @@ impl TalerConfig { .expect("Failed to parse config"); let taler = section(&conf, "taler"); let currency = required(taler, "CURRENCY", string); - let currency = Currency::from_str(&currency).or_fail(|_| { - format!( - "config value CURRENCY={} is an unsupported currency", - currency - ) - }); + let currency = Currency::from_str(&currency) + .or_fail(|_| format!("config CURRENCY={} is an unsupported currency", currency)); let section_name = match currency { Currency::BTC(_) => "depolymerizer-bitcoin", Currency::ETH(_) => "depolymerizer-ethereum", @@ -115,6 +111,18 @@ impl TalerConfig { self.non_zero_option("HTTP_LIFETIME") } + pub fn auth_method(&self) -> AuthMethod { + let section = self.section(); + match required(section, "AUTH_METHOD", string).as_str() { + "none" => AuthMethod::None, + "basic" => AuthMethod::Basic(required(section, "AUTH_TOKEN", string)), + it => fail(format!( + "unknown config auth method AUTH_METHOD={} expected 'none' or 'basic'", + it + )), + } + } + /* ----- Wire Common ----- */ pub fn confirmation(&self) -> Option<u16> { @@ -140,6 +148,13 @@ impl TalerConfig { } } +/* ----- Auth Method ----- */ + +pub enum AuthMethod { + Basic(String), + None, +} + /* ----- Helper parsing functions ----- */ pub fn section<'a>(ini: &'a Ini, name: &str) -> &'a Properties { @@ -165,30 +180,26 @@ pub fn string(properties: &Properties, name: &str) -> Option<String> { pub fn path(properties: &Properties, name: &str) -> Option<PathBuf> { properties.get(name).map(|s| { - PathBuf::from_str(s).or_fail(|_| format!("config value {}={} is not a valid path", name, s)) + PathBuf::from_str(s).or_fail(|_| format!("config {}={} is not a valid path", name, s)) }) } pub fn nb<T: FromStr>(properties: &Properties, name: &str) -> Option<T> { properties.get(name).map(|s| { s.parse() - .or_fail(|_| format!("config value {}={} is not a number", name, s)) + .or_fail(|_| format!("config {}={} is not a number", name, s)) }) } pub fn url(properties: &Properties, name: &str) -> Option<Url> { properties.get(name).map(|s| { - Url::parse(s).or_fail(|e| format!("config value {}={} is not a valid url: {}", name, s, e)) + Url::parse(s).or_fail(|e| format!("config {}={} is not a valid url: {}", name, s, e)) }) } pub fn postgres(properties: &Properties, name: &str) -> Option<postgres::Config> { properties.get(name).map(|s| { - postgres::Config::from_str(s).or_fail(|e| { - format!( - "config value {}={} is not a valid postgres url: {}", - name, s, e - ) - }) + postgres::Config::from_str(s) + .or_fail(|e| format!("config {}={} is not a valid postgres url: {}", name, s, e)) }) } diff --git a/docs/taler-btc-full.conf b/docs/taler-btc-full.conf @@ -0,0 +1,20 @@ +# Full btc-wire configuration +[taler] +CURRENCY = BITCOINBTC + +[exchange] +BASE_URL = http://test.com + +[depolymerizer-bitcoin] +DB_URL = postgres://%2Fvar%2Frun%2Fpostgresql/btc-wire +PAYTO = payto://bitcoin/bc1qcr40fzphnh4mcwlv65kvdam4dxq977t2rn54qx +AUTH_METHOD = basic +AUTH_TOKEN = YWRtaW46cGFzc3dvcmQ= +PORT = 8080 +UNIX_PATH = +CONF_PATH = ~/.bitcoin +CONFIRMATION = 6 +BOUNCE_FEE = 0.00001 +HTTP_LIFETIME = 0 +WIRE_LIFETIME = 0 +BUMP_DELAY = 0 diff --git a/docs/taler-btc-min.conf b/docs/taler-btc-min.conf @@ -0,0 +1,11 @@ +# Minimal btc-wire configuration +[taler] +CURRENCY = BITCOINBTC + +[exchange] +BASE_URL = http://test.com + +[depolymerizer-bitcoin] +DB_URL = postgres://%2Fvar%2Frun%2Fpostgresql/btc-wire +PAYTO = payto://bitcoin/bc1qcr40fzphnh4mcwlv65kvdam4dxq977t2rn54qx +AUTH_METHOD = none diff --git a/docs/taler-btc.conf b/docs/taler-btc.conf @@ -1,17 +0,0 @@ -# Full btc-wire configuration -[taler] -CURRENCY = BITCOINBTC - -[exchange] -BASE_URL = http://test.com - -[depolymerizer-bitcoin] -DB_URL = postgres://%2Fvar%2Frun%2Fpostgresql/btc-wire -PAYTO = payto://bitcoin/bc1qcr40fzphnh4mcwlv65kvdam4dxq977t2rn54qx -PORT = 8080 -CONF_PATH = ~/.bitcoin -CONFIRMATION = 6 -BOUNCE_FEE = 0.00001 -HTTP_LIFETIME = 0 -WIRE_LIFETIME = 0 -BUMP_DELAY = 0 diff --git a/docs/taler-eth-full.conf b/docs/taler-eth-full.conf @@ -0,0 +1,20 @@ +# Full eth-wire configuration +[taler] +CURRENCY = ETHEREUMETH + +[exchange] +BASE_URL = http://test.com + +[depolymerizer-ethereum] +DB_URL = postgres://%2Fvar%2Frun%2Fpostgresql/eth-wire +PAYTO = payto://ethereum/425870d7b77ad5665ca982ff85c398222a70fe7c +AUTH_METHOD = basic +AUTH_TOKEN = YWRtaW46cGFzc3dvcmQ= +PORT = 8080 +UNIX_PATH = +IPC_PATH = ~/.ethereum/geth/geth.ipc +CONFIRMATION = 24 +BOUNCE_FEE = 0.00001 +HTTP_LIFETIME = 0 +WIRE_LIFETIME = 0 +BUMP_DELAY = 0 diff --git a/docs/taler-eth-min.conf b/docs/taler-eth-min.conf @@ -0,0 +1,11 @@ +# Minimal eth-wire configuration +[taler] +CURRENCY = ETHEREUMETH + +[exchange] +BASE_URL = http://test.com + +[depolymerizer-ethereum] +DB_URL = postgres://%2Fvar%2Frun%2Fpostgresql/eth-wire +PAYTO = payto://ethereum/425870d7b77ad5665ca982ff85c398222a70fe7c +AUTH_METHOD = none diff --git a/docs/taler-eth.conf b/docs/taler-eth.conf @@ -1,17 +0,0 @@ -# Full eth-wire configuration -[taler] -CURRENCY = ETHEREUMETH - -[exchange] -BASE_URL = http://test.com - -[depolymerizer-ethereum] -DB_URL = postgres://%2Fvar%2Frun%2Fpostgresql/eth-wire -PAYTO = payto://ethereum/425870d7b77ad5665ca982ff85c398222a70fe7c -PORT = 8080 -IPC_PATH = ~/.ethereum/geth/geth.ipc -CONFIRMATION = 24 -BOUNCE_FEE = 0.00001 -HTTP_LIFETIME = 0 -WIRE_LIFETIME = 0 -BUMP_DELAY = 0 diff --git a/eth-wire/src/lib.rs b/eth-wire/src/lib.rs @@ -274,7 +274,7 @@ fn config_bounce_fee(bounce_fee: &Option<String>, currency: CurrencyEth) -> U256 .and_then(|a| taler_to_eth(&a, currency)) .or_fail(|a| { format!( - "config value BOUNCE_FEE={} is not a valid ethereum amount: {}", + "config BOUNCE_FEE={} is not a valid ethereum amount: {}", config, a ) }) diff --git a/makefile b/makefile @@ -10,6 +10,7 @@ install_test: install test_gateway: install_test test/gateway/api.sh + test/gateway/auth.sh test_btc: install_test test/btc/wire.sh @@ -35,7 +36,7 @@ test_eth: install_test test/eth/bumpfee.sh test/eth/maxfee.sh -test: test_gateway test_btc test_eth +test: test_gateway test_eth test_btc segwit_demo: cargo run --release --bin segwit-demo \ No newline at end of file diff --git a/test/common.sh b/test/common.sh @@ -50,7 +50,7 @@ function load_config() { echo -e "\nCONF_PATH = ${WIRE_DIR}" >> $CONF echo -e "IPC_PATH = ${WIRE_DIR}" >> $CONF source <(grep = $CONF | sed 's/ *= */=/' | sed 's/=\(.*\)/="\1"/g1') - BANK_ENDPOINT=http://127.0.0.1:$PORT/ + BANK_ENDPOINT=http://127.0.0.1:${PORT:-8080}/ if [[ "$CURRENCY" =~ "BTC" ]]; then WIRE_CLI="btc-wire -c $CONF" WIRE_UTILS="btc-wire-utils -c $CONF" diff --git a/test/conf/taler_btc.conf b/test/conf/taler_btc.conf @@ -9,3 +9,4 @@ DB_URL = postgres://localhost:5454/postgres?user=postgres&password=passwor PORT = 8060 PAYTO = payto://bitcoin/bcrt1qgkgxkjj27g3f7s87mcvjjsghay7gh34cx39prj CONFIRMATION = 3 +AUTH_METHOD = none diff --git a/test/conf/taler_btc_auth.conf b/test/conf/taler_btc_auth.conf @@ -0,0 +1,19 @@ +[taler] +CURRENCY = DEVBTC + +[exchange] +BASE_URL = http://test.com + +[exchange-accountcredentials-admin] +WIRE_GATEWAY_URL = http://localhost:8060/ +WIRE_GATEWAY_AUTH_METHOD = basic +USERNAME = admin +PASSWORD = password + +[depolymerizer-bitcoin] +DB_URL = postgres://localhost:5454/postgres?user=postgres&password=password +PORT = 8060 +PAYTO = payto://bitcoin/bcrt1qgkgxkjj27g3f7s87mcvjjsghay7gh34cx39prj +AUTH_METHOD = basic +AUTH_TOKEN = YWRtaW46cGFzc3dvcmQ= + diff --git a/test/conf/taler_btc_bump.conf b/test/conf/taler_btc_bump.conf @@ -10,4 +10,5 @@ PORT = 8060 PAYTO = payto://bitcoin/bcrt1qgkgxkjj27g3f7s87mcvjjsghay7gh34cx39prj CONFIRMATION = 3 BUMP_DELAY = 5 -BOUNCE_FEE = 0.00001 -\ No newline at end of file +BOUNCE_FEE = 0.00001 +AUTH_METHOD = none +\ No newline at end of file diff --git a/test/conf/taler_btc_lifetime.conf b/test/conf/taler_btc_lifetime.conf @@ -10,4 +10,5 @@ PORT = 8060 PAYTO = payto://bitcoin/bcrt1qgkgxkjj27g3f7s87mcvjjsghay7gh34cx39prj CONFIRMATION = 3 HTTP_LIFETIME = 10 -WIRE_LIFETIME = 10 -\ No newline at end of file +WIRE_LIFETIME = 10 +AUTH_METHOD = none +\ No newline at end of file diff --git a/test/conf/taler_eth.conf b/test/conf/taler_eth.conf @@ -7,4 +7,5 @@ BASE_URL = http://test.com [depolymerizer-ethereum] DB_URL = postgres://localhost:5454/postgres?user=postgres&password=password PORT = 8060 -CONFIRMATION = 3 -\ No newline at end of file +CONFIRMATION = 3 +AUTH_METHOD = none +\ No newline at end of file diff --git a/test/conf/taler_eth_bump.conf b/test/conf/taler_eth_bump.conf @@ -8,4 +8,5 @@ BASE_URL = http://test.com DB_URL = postgres://localhost:5454/postgres?user=postgres&password=password PORT = 8060 CONFIRMATION = 3 -BUMP_DELAY = 5 -\ No newline at end of file +BUMP_DELAY = 5 +AUTH_METHOD = none +\ No newline at end of file diff --git a/test/conf/taler_eth_lifetime.conf b/test/conf/taler_eth_lifetime.conf @@ -9,4 +9,5 @@ DB_URL = postgres://localhost:5454/postgres?user=postgres&password=passwo PORT = 8060 CONFIRMATION = 3 HTTP_LIFETIME = 10 -WIRE_LIFETIME = 10 -\ No newline at end of file +WIRE_LIFETIME = 10 +AUTH_METHOD = none +\ No newline at end of file diff --git a/test/gateway/api.sh b/test/gateway/api.sh @@ -17,7 +17,6 @@ function cleanup() { trap cleanup EXIT source "${BASH_SOURCE%/*}/../common.sh" -ADDRESS=mpTJZxWPerz1Gife6mQSdHT8mMuJK6FP85 CONFIG=taler_btc.conf echo "----- Setup -----" @@ -35,7 +34,7 @@ echo -n "Making wire transfer to exchange:" for n in `seq 1 9`; do taler-exchange-wire-gateway-client \ -b $BANK_ENDPOINT \ - -D payto://bitcoin/$ADDRESS \ + -D payto://bitcoin/$CLIENT \ -a $CURRENCY:0.0000$n > /dev/null done echo " OK" @@ -51,7 +50,7 @@ echo -n "Making wire transfer from exchange:" for n in `seq 1 9`; do taler-exchange-wire-gateway-client \ -b $BANK_ENDPOINT \ - -C payto://bitcoin/$ADDRESS \ + -C payto://bitcoin/$CLIENT \ -a $CURRENCY:0.0000$n > /dev/null done @@ -75,16 +74,16 @@ test `curl -w %{http_code} -s -o /dev/null ${BANK_ENDPOINT}transfer` -eq 405 && echo "----- Request format -----" echo -n "Bad payto url:" -for bad_payto in http://bitcoin/$ADDRESS payto://btc/$ADDRESS payto://bitcoin/$ADDRESS?id=admin payto://bitcoin/$ADDRESS#admin; do +for bad_payto in http://bitcoin/$CLIENT payto://btc/$CLIENT payto://bitcoin/$CLIENT?id=admin payto://bitcoin/$CLIENT#admin; do taler-exchange-wire-gateway-client -b $BANK_ENDPOINT -C $bad_payto -a $CURRENCY:0.00042 2>&1 | grep -q "(400/24)" && echo -n " OK" || echo " Failed" done echo "" echo -n "Bad bitcoin address:" -taler-exchange-wire-gateway-client -b $BANK_ENDPOINT -C payto://bitcoin/42$ADDRESS -a $CURRENCY:0.00042 2>&1 | grep -q "(400/24)" && echo " OK" || echo " Failed" +taler-exchange-wire-gateway-client -b $BANK_ENDPOINT -C payto://bitcoin/42$CLIENT -a $CURRENCY:0.00042 2>&1 | grep -q "(400/24)" && echo " OK" || echo " Failed" echo -n "Bad transaction amount:" -taler-exchange-wire-gateway-client -b $BANK_ENDPOINT -C payto://bitcoin/$ADDRESS -a ATC:0.00042 2>&1 | grep -q "(400/26)" && echo " OK" || echo " Failed" +taler-exchange-wire-gateway-client -b $BANK_ENDPOINT -C payto://bitcoin/$CLIENT -a ATC:0.00042 2>&1 | grep -q "(400/26)" && echo " OK" || echo " Failed" echo -n "Bad history delta:" for bad_delta in incoming outgoing incoming?delta=0 outgoing?delta=0; do @@ -106,12 +105,12 @@ for endpoint in incoming outgoing; do done echo "----- Transfer idempotence -----" -DATA="{\"request_uid\":\"0ZSX8SH0M30KHX8K3Y1DAMVGDQV82XEF9DG1HC4QMQ3QWYT4AF00ZSX8SH0M30KHX8K3Y1DAMVGDQV82XEF9DG1HC4QMQ3QWYT4AF00\",\"amount\":\"$CURRENCY:0.000034\",\"exchange_base_url\":\"$BASE_URL\",\"wtid\":\"0ZSX8SH0M30KHX8K3Y1DAMVGDQV82XEF9DG1HC4QMQ3QWYT4AF00\",\"credit_account\":\"payto://bitcoin/$ADDRESS\"}" +DATA="{\"request_uid\":\"0ZSX8SH0M30KHX8K3Y1DAMVGDQV82XEF9DG1HC4QMQ3QWYT4AF00ZSX8SH0M30KHX8K3Y1DAMVGDQV82XEF9DG1HC4QMQ3QWYT4AF00\",\"amount\":\"$CURRENCY:0.000034\",\"exchange_base_url\":\"$BASE_URL\",\"wtid\":\"0ZSX8SH0M30KHX8K3Y1DAMVGDQV82XEF9DG1HC4QMQ3QWYT4AF00\",\"credit_account\":\"payto://bitcoin/$CLIENT\"}" echo -n "Same:" test `curl -w %{http_code} -s -o /dev/null -H "Content-Type: application/json" -d $DATA ${BANK_ENDPOINT}transfer` -eq 200 && echo -n " OK" || echo -n " Failed" test `curl -w %{http_code} -s -o /dev/null -H "Content-Type: application/json" -d $DATA ${BANK_ENDPOINT}transfer` -eq 200 && echo " OK" || echo " Failed" echo -n "Collision:" -DATA="{\"request_uid\":\"0ZSX8SH0M30KHX8K3Y1DAMVGDQV82XEF9DG1HC4QMQ3QWYT4AF00ZSX8SH0M30KHX8K3Y1DAMVGDQV82XEF9DG1HC4QMQ3QWYT4AF00\",\"amount\":\"$CURRENCY:0.000042\",\"exchange_base_url\":\"$BASE_URL\",\"wtid\":\"0ZSX8SH0M30KHX8K3Y1DAMVGDQV82XEF9DG1HC4QMQ3QWYT4AF00\",\"credit_account\":\"payto://bitcoin/$ADDRESS\"}" +DATA="{\"request_uid\":\"0ZSX8SH0M30KHX8K3Y1DAMVGDQV82XEF9DG1HC4QMQ3QWYT4AF00ZSX8SH0M30KHX8K3Y1DAMVGDQV82XEF9DG1HC4QMQ3QWYT4AF00\",\"amount\":\"$CURRENCY:0.000042\",\"exchange_base_url\":\"$BASE_URL\",\"wtid\":\"0ZSX8SH0M30KHX8K3Y1DAMVGDQV82XEF9DG1HC4QMQ3QWYT4AF00\",\"credit_account\":\"payto://bitcoin/$CLIENT\"}" test `curl -w %{http_code} -s -o /dev/null -H "Content-Type: application/json" -d $DATA ${BANK_ENDPOINT}transfer` -eq 409 && echo " OK" || echo " Failed" echo "----- Security -----" diff --git a/test/gateway/auth.sh b/test/gateway/auth.sh @@ -0,0 +1,31 @@ +#!/bin/bash + +## Test wire-gateway authentication + +set -eu + +source "${BASH_SOURCE%/*}/../common.sh" +CONFIG=taler_btc_auth.conf + +echo "----- Setup -----" +echo "Load config file" +load_config +echo "Start bitcoin node" +init_btc +echo "Start gateway" +gateway +echo "" + +echo "----- Authentication -----" + +echo -n "Check 401:" +test `curl -w %{http_code} -s -o /dev/null ${BANK_ENDPOINT}history/outgoing` -eq 401 && echo " OK" || echo " Failed" + +echo -n "Check auth:" +taler-exchange-wire-gateway-client \ + --config $CONF -s exchange-accountcredentials-admin \ + -C payto://bitcoin/$CLIENT \ + -a $CURRENCY:0.0000$n > /dev/null +echo " OK" + +echo "All tests passed!" diff --git a/wire-gateway/src/main.rs b/wire-gateway/src/main.rs @@ -20,7 +20,7 @@ use common::{ HistoryParams, IncomingBankTransaction, IncomingHistory, OutgoingBankTransaction, OutgoingHistory, TransferRequest, TransferResponse, }, - config::TalerConfig, + config::{AuthMethod, TalerConfig}, currency::Currency, error_codes::ErrorCode, log::{ @@ -61,6 +61,7 @@ struct ServerState { notify: Notify, lifetime: Option<AtomicU32>, status: AtomicBool, + auth: AuthMethod, } impl ServerState { @@ -143,6 +144,7 @@ async fn main() { db_config, payto, currency: taler_config.currency, + auth: taler_config.auth_method(), }; let state: &'static ServerState = Box::leak(Box::new(state)); std::thread::spawn(move || status_watcher(state)); @@ -301,6 +303,24 @@ async fn router( .unwrap()); } + // Check auth method + match &state.auth { + AuthMethod::Basic(auth) => { + if !matches!(parts.headers + .get(hyper::header::AUTHORIZATION) + .and_then(|h| h.to_str().ok()) + .and_then(|s| s.strip_prefix("Basic ")), + Some(token) if token == auth ) + { + return Ok(Response::builder() + .status(StatusCode::UNAUTHORIZED) + .body(Body::empty()) + .unwrap()); + } + } + AuthMethod::None => {} + } + let response = match parts.uri.path() { "/transfer" => { assert_method(parts, Method::POST)?;