depolymerization

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

commit d6195b54ba3e3524b3792ecc0e76e14191e4eb9a
parent 38cd58812019951fbd096905c9d6752c7ccf51cd
Author: Antoine A <>
Date:   Tue, 22 Mar 2022 17:40:08 +0100

Check unsupported URI scheme in metadata

Diffstat:
Mbtc-wire/src/loops/worker.rs | 25++++++++++++++++---------
Mcommon/src/metadata.rs | 44++++++++++++++++++++++++++++++++++----------
Meth-wire/src/lib.rs | 4++--
3 files changed, 52 insertions(+), 21 deletions(-)

diff --git a/btc-wire/src/loops/worker.rs b/btc-wire/src/loops/worker.rs @@ -29,7 +29,10 @@ use btc_wire::{ }; use common::{ api_common::base32, - log::log::{error, info, warn}, + log::{ + log::{error, info, warn}, + OrFail, + }, metadata::OutMetadata, postgres, reconnect::AutoReconnectDb, @@ -392,12 +395,7 @@ fn sync_chain_debit( DebitStatus::Requested => { let nb_row = db.execute( "UPDATE tx_out SET status=$1, txid=$2 WHERE id=$3 AND status=$4", - &[ - &(DebitStatus::Sent as i16), - &id.as_ref(), - &row_id, - &status, - ], + &[&(DebitStatus::Sent as i16), &id.as_ref(), &row_id, &status], )?; if nb_row > 0 { warn!( @@ -565,7 +563,12 @@ fn debit(db: &mut Client, rpc: &mut Rpc, state: &WireState) -> LoopResult<bool> let url = sql_url(row, 4); let metadata = OutMetadata::Debit { wtid, url }; - let tx_id = rpc.send(&addr, &amount, Some(&metadata.encode()), false)?; + let tx_id = rpc.send( + &addr, + &amount, + Some(&metadata.encode().or_fail(|e| format!("{}", e))), + false, + )?; fail_point("(injected) fail debit", 0.3)?; db.execute( "UPDATE tx_out SET status=$1, txid=$2 WHERE id=$3", @@ -591,7 +594,11 @@ fn bounce(db: &mut Client, rpc: &mut Rpc, fee: &BtcAmount) -> LoopResult<bool> { bounced: *bounced.as_inner(), }; - match rpc.bounce(&bounced, fee, Some(&metadata.encode())) { + match rpc.bounce( + &bounced, + fee, + Some(&metadata.encode().or_fail(|e| format!("{}", e))), + ) { Ok(it) => { fail_point("(injected) fail bounce", 0.3)?; db.execute( diff --git a/common/src/metadata.rs b/common/src/metadata.rs @@ -28,6 +28,12 @@ pub enum DecodeErr { UnexpectedEOF, } +#[derive(Debug, Clone, thiserror::Error)] +pub enum EncodeErr { + #[error("Unsupported URI scheme {0}")] + UnsupportedScheme(String), +} + /// Encoded metadata for outgoing transaction #[derive(Debug, Clone, PartialEq, Eq)] pub enum OutMetadata { @@ -39,11 +45,16 @@ pub enum OutMetadata { const BOUNCE_BYTE: u8 = u8::MAX - 1; impl OutMetadata { - pub fn encode(&self) -> Vec<u8> { + pub fn encode(&self) -> Result<Vec<u8>, EncodeErr> { let mut buffer = Vec::new(); match self { OutMetadata::Debit { wtid, url } => { - buffer.push(if url.scheme() == "http" { 1 } else { 0 }); + let scheme_id = match url.scheme() { + "https" => 0, + "http" => 1, + scheme => return Err(EncodeErr::UnsupportedScheme(scheme.to_string())), + }; + buffer.push(scheme_id); buffer.extend_from_slice(wtid); let parts = format!("{}{}", url.domain().unwrap_or(""), url.path()); let packed = uri_pack::pack_uri(&parts).unwrap(); @@ -54,7 +65,7 @@ impl OutMetadata { buffer.extend_from_slice(bounced.as_slice()); } } - return buffer; + return Ok(buffer); } pub fn decode(bytes: &[u8]) -> Result<Self, DecodeErr> { @@ -66,11 +77,12 @@ impl OutMetadata { if bytes.len() < 33 { return Err(DecodeErr::UnexpectedEOF); } - let packed = format!( - "http{}://{}", - if bytes[0] == 0 { "s" } else { "" }, - uri_pack::unpack_uri(&bytes[33..])?, - ); + let scheme = match bytes[0] { + 0 => "https", + 1 => "http", + _ => unreachable!(), + }; + let packed = format!("{}://{}", scheme, uri_pack::unpack_uri(&bytes[33..])?,); let url = Url::parse(&packed).unwrap(); Ok(OutMetadata::Debit { wtid: bytes[1..33].try_into().unwrap(), @@ -160,18 +172,30 @@ mod test { let wtid = rand_slice(); let url = Url::parse(url).unwrap(); let metadata = OutMetadata::Debit { wtid, url }; - let encoded = metadata.encode(); + let encoded = metadata.encode().unwrap(); let decoded = OutMetadata::decode(&encoded).unwrap(); assert_eq!(decoded, metadata); } } #[test] + fn encode_unknown_scheme() { + let url = "https+wtf://git.taler.net"; + let url = Url::parse(url).unwrap(); + let metadata = OutMetadata::Debit { + wtid: rand_slice(), + url, + }; + let encoded = metadata.encode(); + assert!(encoded.is_err()) + } + + #[test] fn decode_encode_bounce() { for _ in 0..4 { let id: [u8; 32] = rand_slice(); let info = OutMetadata::Bounce { bounced: id }; - let encoded = info.encode(); + let encoded = info.encode().unwrap(); let decoded = OutMetadata::decode(&encoded).unwrap(); assert_eq!(decoded, info); } diff --git a/eth-wire/src/lib.rs b/eth-wire/src/lib.rs @@ -77,7 +77,7 @@ pub trait RpcExtended: RpcClient { value, nonce: None, gas_price: None, - data: Hex(metadata.encode()), + data: Hex(metadata.encode().or_fail(|e| format!("{}", e))), }) } @@ -94,7 +94,7 @@ pub trait RpcExtended: RpcClient { value: bounce_value, nonce: None, gas_price: None, - data: Hex(metadata.encode()), + data: Hex(metadata.encode().or_fail(|e| format!("{}", e))), }; // Estimate fee price using node let fill = self.fill_transaction(&request)?;