diff --git a/libs/sdk-core/src/breez_services.rs b/libs/sdk-core/src/breez_services.rs index bb089a905..a91d1f7b4 100644 --- a/libs/sdk-core/src/breez_services.rs +++ b/libs/sdk-core/src/breez_services.rs @@ -36,8 +36,8 @@ use crate::greenlight::{GLBackupTransport, Greenlight}; use crate::lnurl::pay::*; use crate::lsp::LspInformation; use crate::models::{ - parse_short_channel_id, ChannelState, ClosedChannelPaymentDetails, Config, EnvironmentType, - LspAPI, NodeState, Payment, PaymentDetails, PaymentType, ReverseSwapPairInfo, + parse_short_channel_id, sanitize::*, ChannelState, ClosedChannelPaymentDetails, Config, + EnvironmentType, LspAPI, NodeState, Payment, PaymentDetails, PaymentType, ReverseSwapPairInfo, ReverseSwapServiceAPI, SwapInfo, SwapperAPI, INVOICE_PAYMENT_FEE_EXPIRY_SECONDS, }; use crate::node_api::{CreateInvoiceRequest, NodeAPI}; @@ -2095,8 +2095,14 @@ impl BreezServices { )?; let channels = serde_json::to_string_pretty(&self.persister.list_channels()?)?; let settings = serde_json::to_string_pretty(&self.persister.list_settings()?)?; - let reverse_swaps = serde_json::to_string_pretty(&self.persister.list_reverse_swaps()?)?; - let swaps = serde_json::to_string_pretty(&self.persister.list_swaps()?)?; + let reverse_swaps = self + .persister + .list_reverse_swaps() + .map(sanitize_vec_pretty_print)??; + let swaps = self + .persister + .list_swaps() + .map(sanitize_vec_pretty_print)??; let lsp_id = serde_json::to_string_pretty(&self.persister.get_lsp_id()?)?; let res = format!( diff --git a/libs/sdk-core/src/models.rs b/libs/sdk-core/src/models.rs index 60f0c87ce..951556ecf 100644 --- a/libs/sdk-core/src/models.rs +++ b/libs/sdk-core/src/models.rs @@ -1589,6 +1589,54 @@ impl PaymentPathEdge { } } +pub(crate) mod sanitize { + use anyhow::Result; + use serde::Serialize; + + use crate::{FullReverseSwapInfo, SwapInfo}; + + pub(crate) trait Sanitize { + /// Sanitizes a raw struct to a clone of itself where sensitive fields are blanked + fn sanitize(self) -> Self; + } + + pub(crate) fn sanitize_vec(vals: Vec) -> Vec + where + T: Sanitize, + { + vals.into_iter() + .map(|val| val.sanitize()) + .collect::>() + } + + pub(crate) fn sanitize_vec_pretty_print(vals: Vec) -> Result + where + T: Sanitize + Serialize, + { + serde_json::to_string_pretty(&sanitize_vec(vals)).map_err(anyhow::Error::new) + } + + impl Sanitize for FullReverseSwapInfo { + fn sanitize(self) -> FullReverseSwapInfo { + FullReverseSwapInfo { + preimage: vec![], + private_key: vec![], + ..self.clone() + } + } + } + + impl Sanitize for SwapInfo { + fn sanitize(self) -> SwapInfo { + SwapInfo { + preimage: vec![], + private_key: vec![], + ..self.clone() + } + } + } +} + #[cfg(test)] mod tests { use anyhow::Result; @@ -1596,8 +1644,12 @@ mod tests { use rand::random; use sdk_common::grpc; - use crate::test_utils::{get_test_ofp, rand_vec_u8}; - use crate::{OpeningFeeParams, PaymentPath, PaymentPathEdge}; + use crate::models::sanitize::Sanitize; + use crate::test_utils::{get_test_ofp, get_test_ofp_48h, rand_string, rand_vec_u8}; + use crate::{ + FullReverseSwapInfo, OpeningFeeParams, PaymentPath, PaymentPathEdge, ReverseSwapInfoCached, + ReverseSwapStatus, SwapInfo, + }; #[test] fn test_route_fees() -> Result<()> { @@ -1757,4 +1809,62 @@ mod tests { ofp.valid_until = "2023-08-03T00:30:35.117Z".to_string(); ofp.valid_until_date().map(|_| ()) } + + /// Tests whether sanitization works for key structures used in the diagnostic data output + #[test] + fn test_sanitization() -> Result<()> { + let rev_swap_info_sanitized = FullReverseSwapInfo { + id: "rev_swap_id".to_string(), + created_at_block_height: 0, + preimage: rand_vec_u8(32), + private_key: vec![], + claim_pubkey: "claim_pubkey".to_string(), + timeout_block_height: 600_000, + invoice: "645".to_string(), + redeem_script: "redeem_script".to_string(), + onchain_amount_sat: 250, + sat_per_vbyte: Some(50), + receive_amount_sat: None, + cache: ReverseSwapInfoCached { + status: ReverseSwapStatus::CompletedConfirmed, + lockup_txid: Some("lockup_txid".to_string()), + claim_txid: Some("claim_txid".to_string()), + }, + } + .sanitize(); + assert_eq!(rev_swap_info_sanitized.preimage, Vec::::new()); + assert_eq!(rev_swap_info_sanitized.private_key, Vec::::new()); + + let swap_info_sanitized = SwapInfo { + bitcoin_address: rand_string(10), + created_at: 10, + lock_height: random(), + payment_hash: rand_vec_u8(32), + preimage: rand_vec_u8(32), + private_key: rand_vec_u8(32), + public_key: rand_vec_u8(10), + swapper_public_key: rand_vec_u8(10), + script: rand_vec_u8(10), + bolt11: None, + paid_msat: 0, + unconfirmed_sats: 0, + confirmed_sats: 0, + total_incoming_txs: 0, + status: crate::models::SwapStatus::Initial, + refund_tx_ids: Vec::new(), + unconfirmed_tx_ids: Vec::new(), + confirmed_tx_ids: Vec::new(), + min_allowed_deposit: 0, + max_allowed_deposit: 100, + max_swapper_payable: 200, + last_redeem_error: None, + channel_opening_fees: Some(get_test_ofp_48h(random(), random()).into()), + confirmed_at: None, + } + .sanitize(); + assert_eq!(swap_info_sanitized.preimage, Vec::::new()); + assert_eq!(swap_info_sanitized.private_key, Vec::::new()); + + Ok(()) + } }