commit d6195b54ba3e3524b3792ecc0e76e14191e4eb9a
parent 38cd58812019951fbd096905c9d6752c7ccf51cd
Author: Antoine A <>
Date: Tue, 22 Mar 2022 17:40:08 +0100
Check unsupported URI scheme in metadata
Diffstat:
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)?;