From b1003e7f5d47e068040f9b5ad9fb481ade327a6e Mon Sep 17 00:00:00 2001 From: Ross Savage Date: Thu, 11 Jul 2024 10:28:22 +0200 Subject: [PATCH 1/2] Remove URL validation and set matches_callback_domain flag --- libs/sdk-bindings/src/breez_sdk.udl | 1 + libs/sdk-common/src/lnurl/specs/pay.rs | 59 +++-- libs/sdk-common/src/utils/mod.rs | 4 + .../main/java/com/breezsdk/BreezSDKMapper.kt | 4 + .../sdk-react-native/ios/BreezSDKMapper.swift | 221 +++++++++--------- libs/sdk-react-native/src/index.ts | 1 + 6 files changed, 160 insertions(+), 130 deletions(-) diff --git a/libs/sdk-bindings/src/breez_sdk.udl b/libs/sdk-bindings/src/breez_sdk.udl index 862d23e35..01272bc4e 100644 --- a/libs/sdk-bindings/src/breez_sdk.udl +++ b/libs/sdk-bindings/src/breez_sdk.udl @@ -293,6 +293,7 @@ dictionary MessageSuccessActionData { dictionary UrlSuccessActionData { string description; string url; + boolean matches_callback_domain; }; [Enum] diff --git a/libs/sdk-common/src/lnurl/specs/pay.rs b/libs/sdk-common/src/lnurl/specs/pay.rs index 8ff1e5579..612de833e 100644 --- a/libs/sdk-common/src/lnurl/specs/pay.rs +++ b/libs/sdk-common/src/lnurl/specs/pay.rs @@ -31,12 +31,15 @@ pub async fn validate_lnurl_pay( if let Ok(err) = serde_json::from_str::(&callback_resp_text) { Ok(ValidatedCallbackResponse::EndpointError { data: err }) } else { - let callback_resp: CallbackResponse = serde_json::from_str(&callback_resp_text)?; + let mut callback_resp: CallbackResponse = serde_json::from_str(&callback_resp_text)?; if let Some(ref sa) = callback_resp.success_action { match sa { SuccessAction::Aes(data) => data.validate()?, SuccessAction::Message(data) => data.validate()?, - SuccessAction::Url(data) => data.validate(req_data)?, + SuccessAction::Url(data) => { + callback_resp.success_action = + Some(SuccessAction::Url(data.validate(req_data)?)); + } } } @@ -115,6 +118,7 @@ pub mod model { use anyhow::Result; use serde::{Deserialize, Serialize}; use thiserror::Error; + use utils::default_true; use crate::prelude::specs::pay::{Aes256CbcDec, Aes256CbcEnc}; use crate::prelude::*; @@ -194,8 +198,17 @@ pub mod model { #[derive(PartialEq, Eq, Debug, Clone, Deserialize, Serialize)] pub struct UrlSuccessActionData { + /// Contents description, up to 144 characters pub description: String, + + /// URL of the success action pub url: String, + + /// Indicates the success URL domain matches the LNURL callback domain. + /// + /// See + #[serde(default = "default_true")] + pub matches_callback_domain: bool, } /// [SuccessAction] where contents are ready to be consumed by the caller @@ -308,7 +321,8 @@ pub mod model { } impl UrlSuccessActionData { - pub fn validate(&self, data: &LnUrlPayRequestData) -> LnUrlResult<()> { + pub fn validate(&self, data: &LnUrlPayRequestData) -> LnUrlResult { + let mut validated_data = self.clone(); match self.description.len() <= 144 { true => Ok(()), false => Err(LnUrlError::generic( @@ -328,12 +342,8 @@ pub mod model { LnUrlError::invalid_uri("Could not determine Success Action URL domain") })?; - match req_domain == action_res_domain { - true => Ok(()), - false => Err(LnUrlError::generic( - "Success Action URL has different domain than the callback domain", - )), - } + validated_data.matches_callback_domain = req_domain == action_res_domain; + Ok(validated_data) }) } } @@ -605,25 +615,30 @@ pub(crate) mod tests { fn test_lnurl_pay_validate_success_url() -> Result<()> { let pay_req_data = get_test_pay_req_data(0, 100_000, 100); - assert!(UrlSuccessActionData { + let validated_data1 = UrlSuccessActionData { description: "short msg".into(), - url: pay_req_data.callback.clone() + url: pay_req_data.callback.clone(), + matches_callback_domain: true, } - .validate(&pay_req_data) - .is_ok()); + .validate(&pay_req_data); + assert!(validated_data1.is_ok()); + assert!(validated_data1.unwrap().matches_callback_domain); - // Too long description - assert!(UrlSuccessActionData { - description: rand_string(150), - url: pay_req_data.callback.clone() + // Different Success Action domain than in the callback URL + let validated_data2 = UrlSuccessActionData { + description: "short msg".into(), + url: "https://new-domain.com/test-url".into(), + matches_callback_domain: true, } - .validate(&pay_req_data) - .is_err()); + .validate(&pay_req_data); + assert!(validated_data2.is_ok()); + assert!(!validated_data2.unwrap().matches_callback_domain); - // Different Success Action domain than in the callback URL + // Too long description assert!(UrlSuccessActionData { - description: "short msg".into(), - url: "https://new-domain.com/test-url".into() + description: rand_string(150), + url: pay_req_data.callback.clone(), + matches_callback_domain: true, } .validate(&pay_req_data) .is_err()); diff --git a/libs/sdk-common/src/utils/mod.rs b/libs/sdk-common/src/utils/mod.rs index dfc203baf..0b8883280 100644 --- a/libs/sdk-common/src/utils/mod.rs +++ b/libs/sdk-common/src/utils/mod.rs @@ -8,3 +8,7 @@ macro_rules! ensure_sdk { } }; } + +pub(crate) fn default_true() -> bool { + true +} diff --git a/libs/sdk-react-native/android/src/main/java/com/breezsdk/BreezSDKMapper.kt b/libs/sdk-react-native/android/src/main/java/com/breezsdk/BreezSDKMapper.kt index fa4c04fff..8f45d2952 100644 --- a/libs/sdk-react-native/android/src/main/java/com/breezsdk/BreezSDKMapper.kt +++ b/libs/sdk-react-native/android/src/main/java/com/breezsdk/BreezSDKMapper.kt @@ -3717,6 +3717,7 @@ fun asUrlSuccessActionData(urlSuccessActionData: ReadableMap): UrlSuccessActionD arrayOf( "description", "url", + "matchesCallbackDomain", ), ) ) { @@ -3724,9 +3725,11 @@ fun asUrlSuccessActionData(urlSuccessActionData: ReadableMap): UrlSuccessActionD } val description = urlSuccessActionData.getString("description")!! val url = urlSuccessActionData.getString("url")!! + val matchesCallbackDomain = urlSuccessActionData.getBoolean("matchesCallbackDomain") return UrlSuccessActionData( description, url, + matchesCallbackDomain, ) } @@ -3734,6 +3737,7 @@ fun readableMapOf(urlSuccessActionData: UrlSuccessActionData): ReadableMap = readableMapOf( "description" to urlSuccessActionData.description, "url" to urlSuccessActionData.url, + "matchesCallbackDomain" to urlSuccessActionData.matchesCallbackDomain, ) fun asUrlSuccessActionDataList(arr: ReadableArray): List { diff --git a/libs/sdk-react-native/ios/BreezSDKMapper.swift b/libs/sdk-react-native/ios/BreezSDKMapper.swift index 9da47264a..bafa135fa 100644 --- a/libs/sdk-react-native/ios/BreezSDKMapper.swift +++ b/libs/sdk-react-native/ios/BreezSDKMapper.swift @@ -37,7 +37,7 @@ enum BreezSDKMapper { } static func arrayOf(aesSuccessActionDataDecryptedList: [AesSuccessActionDataDecrypted]) -> [Any] { - return aesSuccessActionDataDecryptedList.map { v -> [String: Any?] in dictionaryOf(aesSuccessActionDataDecrypted: v) } + return aesSuccessActionDataDecryptedList.map { v -> [String: Any?] in return dictionaryOf(aesSuccessActionDataDecrypted: v) } } static func asBackupFailedData(backupFailedData: [String: Any?]) throws -> BackupFailedData { @@ -69,7 +69,7 @@ enum BreezSDKMapper { } static func arrayOf(backupFailedDataList: [BackupFailedData]) -> [Any] { - return backupFailedDataList.map { v -> [String: Any?] in dictionaryOf(backupFailedData: v) } + return backupFailedDataList.map { v -> [String: Any?] in return dictionaryOf(backupFailedData: v) } } static func asBackupStatus(backupStatus: [String: Any?]) throws -> BackupStatus { @@ -111,7 +111,7 @@ enum BreezSDKMapper { } static func arrayOf(backupStatusList: [BackupStatus]) -> [Any] { - return backupStatusList.map { v -> [String: Any?] in dictionaryOf(backupStatus: v) } + return backupStatusList.map { v -> [String: Any?] in return dictionaryOf(backupStatus: v) } } static func asBitcoinAddressData(bitcoinAddressData: [String: Any?]) throws -> BitcoinAddressData { @@ -178,7 +178,7 @@ enum BreezSDKMapper { } static func arrayOf(bitcoinAddressDataList: [BitcoinAddressData]) -> [Any] { - return bitcoinAddressDataList.map { v -> [String: Any?] in dictionaryOf(bitcoinAddressData: v) } + return bitcoinAddressDataList.map { v -> [String: Any?] in return dictionaryOf(bitcoinAddressData: v) } } static func asBuyBitcoinRequest(buyBitcoinRequest: [String: Any?]) throws -> BuyBitcoinRequest { @@ -219,7 +219,7 @@ enum BreezSDKMapper { } static func arrayOf(buyBitcoinRequestList: [BuyBitcoinRequest]) -> [Any] { - return buyBitcoinRequestList.map { v -> [String: Any?] in dictionaryOf(buyBitcoinRequest: v) } + return buyBitcoinRequestList.map { v -> [String: Any?] in return dictionaryOf(buyBitcoinRequest: v) } } static func asBuyBitcoinResponse(buyBitcoinResponse: [String: Any?]) throws -> BuyBitcoinResponse { @@ -258,7 +258,7 @@ enum BreezSDKMapper { } static func arrayOf(buyBitcoinResponseList: [BuyBitcoinResponse]) -> [Any] { - return buyBitcoinResponseList.map { v -> [String: Any?] in dictionaryOf(buyBitcoinResponse: v) } + return buyBitcoinResponseList.map { v -> [String: Any?] in return dictionaryOf(buyBitcoinResponse: v) } } static func asCheckMessageRequest(checkMessageRequest: [String: Any?]) throws -> CheckMessageRequest { @@ -301,7 +301,7 @@ enum BreezSDKMapper { } static func arrayOf(checkMessageRequestList: [CheckMessageRequest]) -> [Any] { - return checkMessageRequestList.map { v -> [String: Any?] in dictionaryOf(checkMessageRequest: v) } + return checkMessageRequestList.map { v -> [String: Any?] in return dictionaryOf(checkMessageRequest: v) } } static func asCheckMessageResponse(checkMessageResponse: [String: Any?]) throws -> CheckMessageResponse { @@ -333,7 +333,7 @@ enum BreezSDKMapper { } static func arrayOf(checkMessageResponseList: [CheckMessageResponse]) -> [Any] { - return checkMessageResponseList.map { v -> [String: Any?] in dictionaryOf(checkMessageResponse: v) } + return checkMessageResponseList.map { v -> [String: Any?] in return dictionaryOf(checkMessageResponse: v) } } static func asClosedChannelPaymentDetails(closedChannelPaymentDetails: [String: Any?]) throws -> ClosedChannelPaymentDetails { @@ -391,7 +391,7 @@ enum BreezSDKMapper { } static func arrayOf(closedChannelPaymentDetailsList: [ClosedChannelPaymentDetails]) -> [Any] { - return closedChannelPaymentDetailsList.map { v -> [String: Any?] in dictionaryOf(closedChannelPaymentDetails: v) } + return closedChannelPaymentDetailsList.map { v -> [String: Any?] in return dictionaryOf(closedChannelPaymentDetails: v) } } static func asConfig(config: [String: Any?]) throws -> Config { @@ -489,7 +489,7 @@ enum BreezSDKMapper { } static func arrayOf(configList: [Config]) -> [Any] { - return configList.map { v -> [String: Any?] in dictionaryOf(config: v) } + return configList.map { v -> [String: Any?] in return dictionaryOf(config: v) } } static func asConfigureNodeRequest(configureNodeRequest: [String: Any?]) throws -> ConfigureNodeRequest { @@ -525,7 +525,7 @@ enum BreezSDKMapper { } static func arrayOf(configureNodeRequestList: [ConfigureNodeRequest]) -> [Any] { - return configureNodeRequestList.map { v -> [String: Any?] in dictionaryOf(configureNodeRequest: v) } + return configureNodeRequestList.map { v -> [String: Any?] in return dictionaryOf(configureNodeRequest: v) } } static func asConnectRequest(connectRequest: [String: Any?]) throws -> ConnectRequest { @@ -574,7 +574,7 @@ enum BreezSDKMapper { } static func arrayOf(connectRequestList: [ConnectRequest]) -> [Any] { - return connectRequestList.map { v -> [String: Any?] in dictionaryOf(connectRequest: v) } + return connectRequestList.map { v -> [String: Any?] in return dictionaryOf(connectRequest: v) } } static func asCurrencyInfo(currencyInfo: [String: Any?]) throws -> CurrencyInfo { @@ -648,7 +648,7 @@ enum BreezSDKMapper { } static func arrayOf(currencyInfoList: [CurrencyInfo]) -> [Any] { - return currencyInfoList.map { v -> [String: Any?] in dictionaryOf(currencyInfo: v) } + return currencyInfoList.map { v -> [String: Any?] in return dictionaryOf(currencyInfo: v) } } static func asFiatCurrency(fiatCurrency: [String: Any?]) throws -> FiatCurrency { @@ -687,7 +687,7 @@ enum BreezSDKMapper { } static func arrayOf(fiatCurrencyList: [FiatCurrency]) -> [Any] { - return fiatCurrencyList.map { v -> [String: Any?] in dictionaryOf(fiatCurrency: v) } + return fiatCurrencyList.map { v -> [String: Any?] in return dictionaryOf(fiatCurrency: v) } } static func asGreenlightCredentials(greenlightCredentials: [String: Any?]) throws -> GreenlightCredentials { @@ -725,7 +725,7 @@ enum BreezSDKMapper { } static func arrayOf(greenlightCredentialsList: [GreenlightCredentials]) -> [Any] { - return greenlightCredentialsList.map { v -> [String: Any?] in dictionaryOf(greenlightCredentials: v) } + return greenlightCredentialsList.map { v -> [String: Any?] in return dictionaryOf(greenlightCredentials: v) } } static func asGreenlightDeviceCredentials(greenlightDeviceCredentials: [String: Any?]) throws -> GreenlightDeviceCredentials { @@ -757,7 +757,7 @@ enum BreezSDKMapper { } static func arrayOf(greenlightDeviceCredentialsList: [GreenlightDeviceCredentials]) -> [Any] { - return greenlightDeviceCredentialsList.map { v -> [String: Any?] in dictionaryOf(greenlightDeviceCredentials: v) } + return greenlightDeviceCredentialsList.map { v -> [String: Any?] in return dictionaryOf(greenlightDeviceCredentials: v) } } static func asGreenlightNodeConfig(greenlightNodeConfig: [String: Any?]) throws -> GreenlightNodeConfig { @@ -801,7 +801,7 @@ enum BreezSDKMapper { } static func arrayOf(greenlightNodeConfigList: [GreenlightNodeConfig]) -> [Any] { - return greenlightNodeConfigList.map { v -> [String: Any?] in dictionaryOf(greenlightNodeConfig: v) } + return greenlightNodeConfigList.map { v -> [String: Any?] in return dictionaryOf(greenlightNodeConfig: v) } } static func asInvoicePaidDetails(invoicePaidDetails: [String: Any?]) throws -> InvoicePaidDetails { @@ -845,7 +845,7 @@ enum BreezSDKMapper { } static func arrayOf(invoicePaidDetailsList: [InvoicePaidDetails]) -> [Any] { - return invoicePaidDetailsList.map { v -> [String: Any?] in dictionaryOf(invoicePaidDetails: v) } + return invoicePaidDetailsList.map { v -> [String: Any?] in return dictionaryOf(invoicePaidDetails: v) } } static func asLnInvoice(lnInvoice: [String: Any?]) throws -> LnInvoice { @@ -949,7 +949,7 @@ enum BreezSDKMapper { } static func arrayOf(lnInvoiceList: [LnInvoice]) -> [Any] { - return lnInvoiceList.map { v -> [String: Any?] in dictionaryOf(lnInvoice: v) } + return lnInvoiceList.map { v -> [String: Any?] in return dictionaryOf(lnInvoice: v) } } static func asListPaymentsRequest(listPaymentsRequest: [String: Any?]) throws -> ListPaymentsRequest { @@ -1036,7 +1036,7 @@ enum BreezSDKMapper { } static func arrayOf(listPaymentsRequestList: [ListPaymentsRequest]) -> [Any] { - return listPaymentsRequestList.map { v -> [String: Any?] in dictionaryOf(listPaymentsRequest: v) } + return listPaymentsRequestList.map { v -> [String: Any?] in return dictionaryOf(listPaymentsRequest: v) } } static func asLnPaymentDetails(lnPaymentDetails: [String: Any?]) throws -> LnPaymentDetails { @@ -1178,7 +1178,7 @@ enum BreezSDKMapper { } static func arrayOf(lnPaymentDetailsList: [LnPaymentDetails]) -> [Any] { - return lnPaymentDetailsList.map { v -> [String: Any?] in dictionaryOf(lnPaymentDetails: v) } + return lnPaymentDetailsList.map { v -> [String: Any?] in return dictionaryOf(lnPaymentDetails: v) } } static func asLnUrlAuthRequestData(lnUrlAuthRequestData: [String: Any?]) throws -> LnUrlAuthRequestData { @@ -1230,7 +1230,7 @@ enum BreezSDKMapper { } static func arrayOf(lnUrlAuthRequestDataList: [LnUrlAuthRequestData]) -> [Any] { - return lnUrlAuthRequestDataList.map { v -> [String: Any?] in dictionaryOf(lnUrlAuthRequestData: v) } + return lnUrlAuthRequestDataList.map { v -> [String: Any?] in return dictionaryOf(lnUrlAuthRequestData: v) } } static func asLnUrlErrorData(lnUrlErrorData: [String: Any?]) throws -> LnUrlErrorData { @@ -1262,7 +1262,7 @@ enum BreezSDKMapper { } static func arrayOf(lnUrlErrorDataList: [LnUrlErrorData]) -> [Any] { - return lnUrlErrorDataList.map { v -> [String: Any?] in dictionaryOf(lnUrlErrorData: v) } + return lnUrlErrorDataList.map { v -> [String: Any?] in return dictionaryOf(lnUrlErrorData: v) } } static func asLnUrlPayErrorData(lnUrlPayErrorData: [String: Any?]) throws -> LnUrlPayErrorData { @@ -1300,7 +1300,7 @@ enum BreezSDKMapper { } static func arrayOf(lnUrlPayErrorDataList: [LnUrlPayErrorData]) -> [Any] { - return lnUrlPayErrorDataList.map { v -> [String: Any?] in dictionaryOf(lnUrlPayErrorData: v) } + return lnUrlPayErrorDataList.map { v -> [String: Any?] in return dictionaryOf(lnUrlPayErrorData: v) } } static func asLnUrlPayRequest(lnUrlPayRequest: [String: Any?]) throws -> LnUrlPayRequest { @@ -1358,7 +1358,7 @@ enum BreezSDKMapper { } static func arrayOf(lnUrlPayRequestList: [LnUrlPayRequest]) -> [Any] { - return lnUrlPayRequestList.map { v -> [String: Any?] in dictionaryOf(lnUrlPayRequest: v) } + return lnUrlPayRequestList.map { v -> [String: Any?] in return dictionaryOf(lnUrlPayRequest: v) } } static func asLnUrlPayRequestData(lnUrlPayRequestData: [String: Any?]) throws -> LnUrlPayRequestData { @@ -1439,7 +1439,7 @@ enum BreezSDKMapper { } static func arrayOf(lnUrlPayRequestDataList: [LnUrlPayRequestData]) -> [Any] { - return lnUrlPayRequestDataList.map { v -> [String: Any?] in dictionaryOf(lnUrlPayRequestData: v) } + return lnUrlPayRequestDataList.map { v -> [String: Any?] in return dictionaryOf(lnUrlPayRequestData: v) } } static func asLnUrlPaySuccessData(lnUrlPaySuccessData: [String: Any?]) throws -> LnUrlPaySuccessData { @@ -1480,7 +1480,7 @@ enum BreezSDKMapper { } static func arrayOf(lnUrlPaySuccessDataList: [LnUrlPaySuccessData]) -> [Any] { - return lnUrlPaySuccessDataList.map { v -> [String: Any?] in dictionaryOf(lnUrlPaySuccessData: v) } + return lnUrlPaySuccessDataList.map { v -> [String: Any?] in return dictionaryOf(lnUrlPaySuccessData: v) } } static func asLnUrlWithdrawRequest(lnUrlWithdrawRequest: [String: Any?]) throws -> LnUrlWithdrawRequest { @@ -1529,7 +1529,7 @@ enum BreezSDKMapper { } static func arrayOf(lnUrlWithdrawRequestList: [LnUrlWithdrawRequest]) -> [Any] { - return lnUrlWithdrawRequestList.map { v -> [String: Any?] in dictionaryOf(lnUrlWithdrawRequest: v) } + return lnUrlWithdrawRequestList.map { v -> [String: Any?] in return dictionaryOf(lnUrlWithdrawRequest: v) } } static func asLnUrlWithdrawRequestData(lnUrlWithdrawRequestData: [String: Any?]) throws -> LnUrlWithdrawRequestData { @@ -1582,7 +1582,7 @@ enum BreezSDKMapper { } static func arrayOf(lnUrlWithdrawRequestDataList: [LnUrlWithdrawRequestData]) -> [Any] { - return lnUrlWithdrawRequestDataList.map { v -> [String: Any?] in dictionaryOf(lnUrlWithdrawRequestData: v) } + return lnUrlWithdrawRequestDataList.map { v -> [String: Any?] in return dictionaryOf(lnUrlWithdrawRequestData: v) } } static func asLnUrlWithdrawSuccessData(lnUrlWithdrawSuccessData: [String: Any?]) throws -> LnUrlWithdrawSuccessData { @@ -1615,7 +1615,7 @@ enum BreezSDKMapper { } static func arrayOf(lnUrlWithdrawSuccessDataList: [LnUrlWithdrawSuccessData]) -> [Any] { - return lnUrlWithdrawSuccessDataList.map { v -> [String: Any?] in dictionaryOf(lnUrlWithdrawSuccessData: v) } + return lnUrlWithdrawSuccessDataList.map { v -> [String: Any?] in return dictionaryOf(lnUrlWithdrawSuccessData: v) } } static func asLocaleOverrides(localeOverrides: [String: Any?]) throws -> LocaleOverrides { @@ -1663,7 +1663,7 @@ enum BreezSDKMapper { } static func arrayOf(localeOverridesList: [LocaleOverrides]) -> [Any] { - return localeOverridesList.map { v -> [String: Any?] in dictionaryOf(localeOverrides: v) } + return localeOverridesList.map { v -> [String: Any?] in return dictionaryOf(localeOverrides: v) } } static func asLocalizedName(localizedName: [String: Any?]) throws -> LocalizedName { @@ -1701,7 +1701,7 @@ enum BreezSDKMapper { } static func arrayOf(localizedNameList: [LocalizedName]) -> [Any] { - return localizedNameList.map { v -> [String: Any?] in dictionaryOf(localizedName: v) } + return localizedNameList.map { v -> [String: Any?] in return dictionaryOf(localizedName: v) } } static func asLogEntry(logEntry: [String: Any?]) throws -> LogEntry { @@ -1739,7 +1739,7 @@ enum BreezSDKMapper { } static func arrayOf(logEntryList: [LogEntry]) -> [Any] { - return logEntryList.map { v -> [String: Any?] in dictionaryOf(logEntry: v) } + return logEntryList.map { v -> [String: Any?] in return dictionaryOf(logEntry: v) } } static func asLspInformation(lspInformation: [String: Any?]) throws -> LspInformation { @@ -1823,7 +1823,7 @@ enum BreezSDKMapper { } static func arrayOf(lspInformationList: [LspInformation]) -> [Any] { - return lspInformationList.map { v -> [String: Any?] in dictionaryOf(lspInformation: v) } + return lspInformationList.map { v -> [String: Any?] in return dictionaryOf(lspInformation: v) } } static func asMaxReverseSwapAmountResponse(maxReverseSwapAmountResponse: [String: Any?]) throws -> MaxReverseSwapAmountResponse { @@ -1855,7 +1855,7 @@ enum BreezSDKMapper { } static func arrayOf(maxReverseSwapAmountResponseList: [MaxReverseSwapAmountResponse]) -> [Any] { - return maxReverseSwapAmountResponseList.map { v -> [String: Any?] in dictionaryOf(maxReverseSwapAmountResponse: v) } + return maxReverseSwapAmountResponseList.map { v -> [String: Any?] in return dictionaryOf(maxReverseSwapAmountResponse: v) } } static func asMessageSuccessActionData(messageSuccessActionData: [String: Any?]) throws -> MessageSuccessActionData { @@ -1887,7 +1887,7 @@ enum BreezSDKMapper { } static func arrayOf(messageSuccessActionDataList: [MessageSuccessActionData]) -> [Any] { - return messageSuccessActionDataList.map { v -> [String: Any?] in dictionaryOf(messageSuccessActionData: v) } + return messageSuccessActionDataList.map { v -> [String: Any?] in return dictionaryOf(messageSuccessActionData: v) } } static func asMetadataFilter(metadataFilter: [String: Any?]) throws -> MetadataFilter { @@ -1925,7 +1925,7 @@ enum BreezSDKMapper { } static func arrayOf(metadataFilterList: [MetadataFilter]) -> [Any] { - return metadataFilterList.map { v -> [String: Any?] in dictionaryOf(metadataFilter: v) } + return metadataFilterList.map { v -> [String: Any?] in return dictionaryOf(metadataFilter: v) } } static func asMetadataItem(metadataItem: [String: Any?]) throws -> MetadataItem { @@ -1963,7 +1963,7 @@ enum BreezSDKMapper { } static func arrayOf(metadataItemList: [MetadataItem]) -> [Any] { - return metadataItemList.map { v -> [String: Any?] in dictionaryOf(metadataItem: v) } + return metadataItemList.map { v -> [String: Any?] in return dictionaryOf(metadataItem: v) } } static func asNodeState(nodeState: [String: Any?]) throws -> NodeState { @@ -2053,7 +2053,7 @@ enum BreezSDKMapper { } static func arrayOf(nodeStateList: [NodeState]) -> [Any] { - return nodeStateList.map { v -> [String: Any?] in dictionaryOf(nodeState: v) } + return nodeStateList.map { v -> [String: Any?] in return dictionaryOf(nodeState: v) } } static func asOnchainPaymentLimitsResponse(onchainPaymentLimitsResponse: [String: Any?]) throws -> OnchainPaymentLimitsResponse { @@ -2091,7 +2091,7 @@ enum BreezSDKMapper { } static func arrayOf(onchainPaymentLimitsResponseList: [OnchainPaymentLimitsResponse]) -> [Any] { - return onchainPaymentLimitsResponseList.map { v -> [String: Any?] in dictionaryOf(onchainPaymentLimitsResponse: v) } + return onchainPaymentLimitsResponseList.map { v -> [String: Any?] in return dictionaryOf(onchainPaymentLimitsResponse: v) } } static func asOpenChannelFeeRequest(openChannelFeeRequest: [String: Any?]) throws -> OpenChannelFeeRequest { @@ -2137,7 +2137,7 @@ enum BreezSDKMapper { } static func arrayOf(openChannelFeeRequestList: [OpenChannelFeeRequest]) -> [Any] { - return openChannelFeeRequestList.map { v -> [String: Any?] in dictionaryOf(openChannelFeeRequest: v) } + return openChannelFeeRequestList.map { v -> [String: Any?] in return dictionaryOf(openChannelFeeRequest: v) } } static func asOpenChannelFeeResponse(openChannelFeeResponse: [String: Any?]) throws -> OpenChannelFeeResponse { @@ -2180,7 +2180,7 @@ enum BreezSDKMapper { } static func arrayOf(openChannelFeeResponseList: [OpenChannelFeeResponse]) -> [Any] { - return openChannelFeeResponseList.map { v -> [String: Any?] in dictionaryOf(openChannelFeeResponse: v) } + return openChannelFeeResponseList.map { v -> [String: Any?] in return dictionaryOf(openChannelFeeResponse: v) } } static func asOpeningFeeParams(openingFeeParams: [String: Any?]) throws -> OpeningFeeParams { @@ -2238,7 +2238,7 @@ enum BreezSDKMapper { } static func arrayOf(openingFeeParamsList: [OpeningFeeParams]) -> [Any] { - return openingFeeParamsList.map { v -> [String: Any?] in dictionaryOf(openingFeeParams: v) } + return openingFeeParamsList.map { v -> [String: Any?] in return dictionaryOf(openingFeeParams: v) } } static func asOpeningFeeParamsMenu(openingFeeParamsMenu: [String: Any?]) throws -> OpeningFeeParamsMenu { @@ -2271,7 +2271,7 @@ enum BreezSDKMapper { } static func arrayOf(openingFeeParamsMenuList: [OpeningFeeParamsMenu]) -> [Any] { - return openingFeeParamsMenuList.map { v -> [String: Any?] in dictionaryOf(openingFeeParamsMenu: v) } + return openingFeeParamsMenuList.map { v -> [String: Any?] in return dictionaryOf(openingFeeParamsMenu: v) } } static func asPayOnchainRequest(payOnchainRequest: [String: Any?]) throws -> PayOnchainRequest { @@ -2310,7 +2310,7 @@ enum BreezSDKMapper { } static func arrayOf(payOnchainRequestList: [PayOnchainRequest]) -> [Any] { - return payOnchainRequestList.map { v -> [String: Any?] in dictionaryOf(payOnchainRequest: v) } + return payOnchainRequestList.map { v -> [String: Any?] in return dictionaryOf(payOnchainRequest: v) } } static func asPayOnchainResponse(payOnchainResponse: [String: Any?]) throws -> PayOnchainResponse { @@ -2343,7 +2343,7 @@ enum BreezSDKMapper { } static func arrayOf(payOnchainResponseList: [PayOnchainResponse]) -> [Any] { - return payOnchainResponseList.map { v -> [String: Any?] in dictionaryOf(payOnchainResponse: v) } + return payOnchainResponseList.map { v -> [String: Any?] in return dictionaryOf(payOnchainResponse: v) } } static func asPayment(payment: [String: Any?]) throws -> Payment { @@ -2439,7 +2439,7 @@ enum BreezSDKMapper { } static func arrayOf(paymentList: [Payment]) -> [Any] { - return paymentList.map { v -> [String: Any?] in dictionaryOf(payment: v) } + return paymentList.map { v -> [String: Any?] in return dictionaryOf(payment: v) } } static func asPaymentFailedData(paymentFailedData: [String: Any?]) throws -> PaymentFailedData { @@ -2493,7 +2493,7 @@ enum BreezSDKMapper { } static func arrayOf(paymentFailedDataList: [PaymentFailedData]) -> [Any] { - return paymentFailedDataList.map { v -> [String: Any?] in dictionaryOf(paymentFailedData: v) } + return paymentFailedDataList.map { v -> [String: Any?] in return dictionaryOf(paymentFailedData: v) } } static func asPrepareOnchainPaymentRequest(prepareOnchainPaymentRequest: [String: Any?]) throws -> PrepareOnchainPaymentRequest { @@ -2538,7 +2538,7 @@ enum BreezSDKMapper { } static func arrayOf(prepareOnchainPaymentRequestList: [PrepareOnchainPaymentRequest]) -> [Any] { - return prepareOnchainPaymentRequestList.map { v -> [String: Any?] in dictionaryOf(prepareOnchainPaymentRequest: v) } + return prepareOnchainPaymentRequestList.map { v -> [String: Any?] in return dictionaryOf(prepareOnchainPaymentRequest: v) } } static func asPrepareOnchainPaymentResponse(prepareOnchainPaymentResponse: [String: Any?]) throws -> PrepareOnchainPaymentResponse { @@ -2601,7 +2601,7 @@ enum BreezSDKMapper { } static func arrayOf(prepareOnchainPaymentResponseList: [PrepareOnchainPaymentResponse]) -> [Any] { - return prepareOnchainPaymentResponseList.map { v -> [String: Any?] in dictionaryOf(prepareOnchainPaymentResponse: v) } + return prepareOnchainPaymentResponseList.map { v -> [String: Any?] in return dictionaryOf(prepareOnchainPaymentResponse: v) } } static func asPrepareRedeemOnchainFundsRequest(prepareRedeemOnchainFundsRequest: [String: Any?]) throws -> PrepareRedeemOnchainFundsRequest { @@ -2639,7 +2639,7 @@ enum BreezSDKMapper { } static func arrayOf(prepareRedeemOnchainFundsRequestList: [PrepareRedeemOnchainFundsRequest]) -> [Any] { - return prepareRedeemOnchainFundsRequestList.map { v -> [String: Any?] in dictionaryOf(prepareRedeemOnchainFundsRequest: v) } + return prepareRedeemOnchainFundsRequestList.map { v -> [String: Any?] in return dictionaryOf(prepareRedeemOnchainFundsRequest: v) } } static func asPrepareRedeemOnchainFundsResponse(prepareRedeemOnchainFundsResponse: [String: Any?]) throws -> PrepareRedeemOnchainFundsResponse { @@ -2677,7 +2677,7 @@ enum BreezSDKMapper { } static func arrayOf(prepareRedeemOnchainFundsResponseList: [PrepareRedeemOnchainFundsResponse]) -> [Any] { - return prepareRedeemOnchainFundsResponseList.map { v -> [String: Any?] in dictionaryOf(prepareRedeemOnchainFundsResponse: v) } + return prepareRedeemOnchainFundsResponseList.map { v -> [String: Any?] in return dictionaryOf(prepareRedeemOnchainFundsResponse: v) } } static func asPrepareRefundRequest(prepareRefundRequest: [String: Any?]) throws -> PrepareRefundRequest { @@ -2720,7 +2720,7 @@ enum BreezSDKMapper { } static func arrayOf(prepareRefundRequestList: [PrepareRefundRequest]) -> [Any] { - return prepareRefundRequestList.map { v -> [String: Any?] in dictionaryOf(prepareRefundRequest: v) } + return prepareRefundRequestList.map { v -> [String: Any?] in return dictionaryOf(prepareRefundRequest: v) } } static func asPrepareRefundResponse(prepareRefundResponse: [String: Any?]) throws -> PrepareRefundResponse { @@ -2758,7 +2758,7 @@ enum BreezSDKMapper { } static func arrayOf(prepareRefundResponseList: [PrepareRefundResponse]) -> [Any] { - return prepareRefundResponseList.map { v -> [String: Any?] in dictionaryOf(prepareRefundResponse: v) } + return prepareRefundResponseList.map { v -> [String: Any?] in return dictionaryOf(prepareRefundResponse: v) } } static func asRate(rate: [String: Any?]) throws -> Rate { @@ -2796,7 +2796,7 @@ enum BreezSDKMapper { } static func arrayOf(rateList: [Rate]) -> [Any] { - return rateList.map { v -> [String: Any?] in dictionaryOf(rate: v) } + return rateList.map { v -> [String: Any?] in return dictionaryOf(rate: v) } } static func asReceiveOnchainRequest(receiveOnchainRequest: [String: Any?]) throws -> ReceiveOnchainRequest { @@ -2829,7 +2829,7 @@ enum BreezSDKMapper { } static func arrayOf(receiveOnchainRequestList: [ReceiveOnchainRequest]) -> [Any] { - return receiveOnchainRequestList.map { v -> [String: Any?] in dictionaryOf(receiveOnchainRequest: v) } + return receiveOnchainRequestList.map { v -> [String: Any?] in return dictionaryOf(receiveOnchainRequest: v) } } static func asReceivePaymentRequest(receivePaymentRequest: [String: Any?]) throws -> ReceivePaymentRequest { @@ -2910,7 +2910,7 @@ enum BreezSDKMapper { } static func arrayOf(receivePaymentRequestList: [ReceivePaymentRequest]) -> [Any] { - return receivePaymentRequestList.map { v -> [String: Any?] in dictionaryOf(receivePaymentRequest: v) } + return receivePaymentRequestList.map { v -> [String: Any?] in return dictionaryOf(receivePaymentRequest: v) } } static func asReceivePaymentResponse(receivePaymentResponse: [String: Any?]) throws -> ReceivePaymentResponse { @@ -2961,7 +2961,7 @@ enum BreezSDKMapper { } static func arrayOf(receivePaymentResponseList: [ReceivePaymentResponse]) -> [Any] { - return receivePaymentResponseList.map { v -> [String: Any?] in dictionaryOf(receivePaymentResponse: v) } + return receivePaymentResponseList.map { v -> [String: Any?] in return dictionaryOf(receivePaymentResponse: v) } } static func asRecommendedFees(recommendedFees: [String: Any?]) throws -> RecommendedFees { @@ -3014,7 +3014,7 @@ enum BreezSDKMapper { } static func arrayOf(recommendedFeesList: [RecommendedFees]) -> [Any] { - return recommendedFeesList.map { v -> [String: Any?] in dictionaryOf(recommendedFees: v) } + return recommendedFeesList.map { v -> [String: Any?] in return dictionaryOf(recommendedFees: v) } } static func asRedeemOnchainFundsRequest(redeemOnchainFundsRequest: [String: Any?]) throws -> RedeemOnchainFundsRequest { @@ -3052,7 +3052,7 @@ enum BreezSDKMapper { } static func arrayOf(redeemOnchainFundsRequestList: [RedeemOnchainFundsRequest]) -> [Any] { - return redeemOnchainFundsRequestList.map { v -> [String: Any?] in dictionaryOf(redeemOnchainFundsRequest: v) } + return redeemOnchainFundsRequestList.map { v -> [String: Any?] in return dictionaryOf(redeemOnchainFundsRequest: v) } } static func asRedeemOnchainFundsResponse(redeemOnchainFundsResponse: [String: Any?]) throws -> RedeemOnchainFundsResponse { @@ -3084,7 +3084,7 @@ enum BreezSDKMapper { } static func arrayOf(redeemOnchainFundsResponseList: [RedeemOnchainFundsResponse]) -> [Any] { - return redeemOnchainFundsResponseList.map { v -> [String: Any?] in dictionaryOf(redeemOnchainFundsResponse: v) } + return redeemOnchainFundsResponseList.map { v -> [String: Any?] in return dictionaryOf(redeemOnchainFundsResponse: v) } } static func asRefundRequest(refundRequest: [String: Any?]) throws -> RefundRequest { @@ -3127,7 +3127,7 @@ enum BreezSDKMapper { } static func arrayOf(refundRequestList: [RefundRequest]) -> [Any] { - return refundRequestList.map { v -> [String: Any?] in dictionaryOf(refundRequest: v) } + return refundRequestList.map { v -> [String: Any?] in return dictionaryOf(refundRequest: v) } } static func asRefundResponse(refundResponse: [String: Any?]) throws -> RefundResponse { @@ -3159,7 +3159,7 @@ enum BreezSDKMapper { } static func arrayOf(refundResponseList: [RefundResponse]) -> [Any] { - return refundResponseList.map { v -> [String: Any?] in dictionaryOf(refundResponse: v) } + return refundResponseList.map { v -> [String: Any?] in return dictionaryOf(refundResponse: v) } } static func asReportPaymentFailureDetails(reportPaymentFailureDetails: [String: Any?]) throws -> ReportPaymentFailureDetails { @@ -3201,7 +3201,7 @@ enum BreezSDKMapper { } static func arrayOf(reportPaymentFailureDetailsList: [ReportPaymentFailureDetails]) -> [Any] { - return reportPaymentFailureDetailsList.map { v -> [String: Any?] in dictionaryOf(reportPaymentFailureDetails: v) } + return reportPaymentFailureDetailsList.map { v -> [String: Any?] in return dictionaryOf(reportPaymentFailureDetails: v) } } static func asReverseSwapFeesRequest(reverseSwapFeesRequest: [String: Any?]) throws -> ReverseSwapFeesRequest { @@ -3247,7 +3247,7 @@ enum BreezSDKMapper { } static func arrayOf(reverseSwapFeesRequestList: [ReverseSwapFeesRequest]) -> [Any] { - return reverseSwapFeesRequestList.map { v -> [String: Any?] in dictionaryOf(reverseSwapFeesRequest: v) } + return reverseSwapFeesRequestList.map { v -> [String: Any?] in return dictionaryOf(reverseSwapFeesRequest: v) } } static func asReverseSwapInfo(reverseSwapInfo: [String: Any?]) throws -> ReverseSwapInfo { @@ -3314,7 +3314,7 @@ enum BreezSDKMapper { } static func arrayOf(reverseSwapInfoList: [ReverseSwapInfo]) -> [Any] { - return reverseSwapInfoList.map { v -> [String: Any?] in dictionaryOf(reverseSwapInfo: v) } + return reverseSwapInfoList.map { v -> [String: Any?] in return dictionaryOf(reverseSwapInfo: v) } } static func asReverseSwapPairInfo(reverseSwapPairInfo: [String: Any?]) throws -> ReverseSwapPairInfo { @@ -3381,7 +3381,7 @@ enum BreezSDKMapper { } static func arrayOf(reverseSwapPairInfoList: [ReverseSwapPairInfo]) -> [Any] { - return reverseSwapPairInfoList.map { v -> [String: Any?] in dictionaryOf(reverseSwapPairInfo: v) } + return reverseSwapPairInfoList.map { v -> [String: Any?] in return dictionaryOf(reverseSwapPairInfo: v) } } static func asRouteHint(routeHint: [String: Any?]) throws -> RouteHint { @@ -3414,7 +3414,7 @@ enum BreezSDKMapper { } static func arrayOf(routeHintList: [RouteHint]) -> [Any] { - return routeHintList.map { v -> [String: Any?] in dictionaryOf(routeHint: v) } + return routeHintList.map { v -> [String: Any?] in return dictionaryOf(routeHint: v) } } static func asRouteHintHop(routeHintHop: [String: Any?]) throws -> RouteHintHop { @@ -3485,7 +3485,7 @@ enum BreezSDKMapper { } static func arrayOf(routeHintHopList: [RouteHintHop]) -> [Any] { - return routeHintHopList.map { v -> [String: Any?] in dictionaryOf(routeHintHop: v) } + return routeHintHopList.map { v -> [String: Any?] in return dictionaryOf(routeHintHop: v) } } static func asSendOnchainRequest(sendOnchainRequest: [String: Any?]) throws -> SendOnchainRequest { @@ -3533,7 +3533,7 @@ enum BreezSDKMapper { } static func arrayOf(sendOnchainRequestList: [SendOnchainRequest]) -> [Any] { - return sendOnchainRequestList.map { v -> [String: Any?] in dictionaryOf(sendOnchainRequest: v) } + return sendOnchainRequestList.map { v -> [String: Any?] in return dictionaryOf(sendOnchainRequest: v) } } static func asSendOnchainResponse(sendOnchainResponse: [String: Any?]) throws -> SendOnchainResponse { @@ -3566,7 +3566,7 @@ enum BreezSDKMapper { } static func arrayOf(sendOnchainResponseList: [SendOnchainResponse]) -> [Any] { - return sendOnchainResponseList.map { v -> [String: Any?] in dictionaryOf(sendOnchainResponse: v) } + return sendOnchainResponseList.map { v -> [String: Any?] in return dictionaryOf(sendOnchainResponse: v) } } static func asSendPaymentRequest(sendPaymentRequest: [String: Any?]) throws -> SendPaymentRequest { @@ -3617,7 +3617,7 @@ enum BreezSDKMapper { } static func arrayOf(sendPaymentRequestList: [SendPaymentRequest]) -> [Any] { - return sendPaymentRequestList.map { v -> [String: Any?] in dictionaryOf(sendPaymentRequest: v) } + return sendPaymentRequestList.map { v -> [String: Any?] in return dictionaryOf(sendPaymentRequest: v) } } static func asSendPaymentResponse(sendPaymentResponse: [String: Any?]) throws -> SendPaymentResponse { @@ -3650,7 +3650,7 @@ enum BreezSDKMapper { } static func arrayOf(sendPaymentResponseList: [SendPaymentResponse]) -> [Any] { - return sendPaymentResponseList.map { v -> [String: Any?] in dictionaryOf(sendPaymentResponse: v) } + return sendPaymentResponseList.map { v -> [String: Any?] in return dictionaryOf(sendPaymentResponse: v) } } static func asSendSpontaneousPaymentRequest(sendSpontaneousPaymentRequest: [String: Any?]) throws -> SendSpontaneousPaymentRequest { @@ -3704,7 +3704,7 @@ enum BreezSDKMapper { } static func arrayOf(sendSpontaneousPaymentRequestList: [SendSpontaneousPaymentRequest]) -> [Any] { - return sendSpontaneousPaymentRequestList.map { v -> [String: Any?] in dictionaryOf(sendSpontaneousPaymentRequest: v) } + return sendSpontaneousPaymentRequestList.map { v -> [String: Any?] in return dictionaryOf(sendSpontaneousPaymentRequest: v) } } static func asServiceHealthCheckResponse(serviceHealthCheckResponse: [String: Any?]) throws -> ServiceHealthCheckResponse { @@ -3737,7 +3737,7 @@ enum BreezSDKMapper { } static func arrayOf(serviceHealthCheckResponseList: [ServiceHealthCheckResponse]) -> [Any] { - return serviceHealthCheckResponseList.map { v -> [String: Any?] in dictionaryOf(serviceHealthCheckResponse: v) } + return serviceHealthCheckResponseList.map { v -> [String: Any?] in return dictionaryOf(serviceHealthCheckResponse: v) } } static func asSignMessageRequest(signMessageRequest: [String: Any?]) throws -> SignMessageRequest { @@ -3769,7 +3769,7 @@ enum BreezSDKMapper { } static func arrayOf(signMessageRequestList: [SignMessageRequest]) -> [Any] { - return signMessageRequestList.map { v -> [String: Any?] in dictionaryOf(signMessageRequest: v) } + return signMessageRequestList.map { v -> [String: Any?] in return dictionaryOf(signMessageRequest: v) } } static func asSignMessageResponse(signMessageResponse: [String: Any?]) throws -> SignMessageResponse { @@ -3801,7 +3801,7 @@ enum BreezSDKMapper { } static func arrayOf(signMessageResponseList: [SignMessageResponse]) -> [Any] { - return signMessageResponseList.map { v -> [String: Any?] in dictionaryOf(signMessageResponse: v) } + return signMessageResponseList.map { v -> [String: Any?] in return dictionaryOf(signMessageResponse: v) } } static func asStaticBackupRequest(staticBackupRequest: [String: Any?]) throws -> StaticBackupRequest { @@ -3833,7 +3833,7 @@ enum BreezSDKMapper { } static func arrayOf(staticBackupRequestList: [StaticBackupRequest]) -> [Any] { - return staticBackupRequestList.map { v -> [String: Any?] in dictionaryOf(staticBackupRequest: v) } + return staticBackupRequestList.map { v -> [String: Any?] in return dictionaryOf(staticBackupRequest: v) } } static func asStaticBackupResponse(staticBackupResponse: [String: Any?]) throws -> StaticBackupResponse { @@ -3869,7 +3869,7 @@ enum BreezSDKMapper { } static func arrayOf(staticBackupResponseList: [StaticBackupResponse]) -> [Any] { - return staticBackupResponseList.map { v -> [String: Any?] in dictionaryOf(staticBackupResponse: v) } + return staticBackupResponseList.map { v -> [String: Any?] in return dictionaryOf(staticBackupResponse: v) } } static func asSwapInfo(swapInfo: [String: Any?]) throws -> SwapInfo { @@ -4033,7 +4033,7 @@ enum BreezSDKMapper { } static func arrayOf(swapInfoList: [SwapInfo]) -> [Any] { - return swapInfoList.map { v -> [String: Any?] in dictionaryOf(swapInfo: v) } + return swapInfoList.map { v -> [String: Any?] in return dictionaryOf(swapInfo: v) } } static func asSymbol(symbol: [String: Any?]) throws -> Symbol { @@ -4097,7 +4097,7 @@ enum BreezSDKMapper { } static func arrayOf(symbolList: [Symbol]) -> [Any] { - return symbolList.map { v -> [String: Any?] in dictionaryOf(symbol: v) } + return symbolList.map { v -> [String: Any?] in return dictionaryOf(symbol: v) } } static func asTlvEntry(tlvEntry: [String: Any?]) throws -> TlvEntry { @@ -4135,7 +4135,7 @@ enum BreezSDKMapper { } static func arrayOf(tlvEntryList: [TlvEntry]) -> [Any] { - return tlvEntryList.map { v -> [String: Any?] in dictionaryOf(tlvEntry: v) } + return tlvEntryList.map { v -> [String: Any?] in return dictionaryOf(tlvEntry: v) } } static func asUnspentTransactionOutput(unspentTransactionOutput: [String: Any?]) throws -> UnspentTransactionOutput { @@ -4188,7 +4188,7 @@ enum BreezSDKMapper { } static func arrayOf(unspentTransactionOutputList: [UnspentTransactionOutput]) -> [Any] { - return unspentTransactionOutputList.map { v -> [String: Any?] in dictionaryOf(unspentTransactionOutput: v) } + return unspentTransactionOutputList.map { v -> [String: Any?] in return dictionaryOf(unspentTransactionOutput: v) } } static func asUrlSuccessActionData(urlSuccessActionData: [String: Any?]) throws -> UrlSuccessActionData { @@ -4198,10 +4198,14 @@ enum BreezSDKMapper { guard let url = urlSuccessActionData["url"] as? String else { throw SdkError.Generic(message: errMissingMandatoryField(fieldName: "url", typeName: "UrlSuccessActionData")) } + guard let matchesCallbackDomain = urlSuccessActionData["matchesCallbackDomain"] as? Bool else { + throw SdkError.Generic(message: errMissingMandatoryField(fieldName: "matchesCallbackDomain", typeName: "UrlSuccessActionData")) + } return UrlSuccessActionData( description: description, - url: url + url: url, + matchesCallbackDomain: matchesCallbackDomain ) } @@ -4209,6 +4213,7 @@ enum BreezSDKMapper { return [ "description": urlSuccessActionData.description, "url": urlSuccessActionData.url, + "matchesCallbackDomain": urlSuccessActionData.matchesCallbackDomain, ] } @@ -4226,7 +4231,7 @@ enum BreezSDKMapper { } static func arrayOf(urlSuccessActionDataList: [UrlSuccessActionData]) -> [Any] { - return urlSuccessActionDataList.map { v -> [String: Any?] in dictionaryOf(urlSuccessActionData: v) } + return urlSuccessActionDataList.map { v -> [String: Any?] in return dictionaryOf(urlSuccessActionData: v) } } static func asAesSuccessActionDataResult(aesSuccessActionDataResult: [String: Any?]) throws -> AesSuccessActionDataResult { @@ -4270,7 +4275,7 @@ enum BreezSDKMapper { } static func arrayOf(aesSuccessActionDataResultList: [AesSuccessActionDataResult]) -> [Any] { - return aesSuccessActionDataResultList.map { v -> [String: Any?] in dictionaryOf(aesSuccessActionDataResult: v) } + return aesSuccessActionDataResultList.map { v -> [String: Any?] in return dictionaryOf(aesSuccessActionDataResult: v) } } static func asAesSuccessActionDataResultList(arr: [Any]) throws -> [AesSuccessActionDataResult] { @@ -4431,7 +4436,7 @@ enum BreezSDKMapper { } static func arrayOf(breezEventList: [BreezEvent]) -> [Any] { - return breezEventList.map { v -> [String: Any?] in dictionaryOf(breezEvent: v) } + return breezEventList.map { v -> [String: Any?] in return dictionaryOf(breezEvent: v) } } static func asBreezEventList(arr: [Any]) throws -> [BreezEvent] { @@ -4464,7 +4469,7 @@ enum BreezSDKMapper { } static func arrayOf(buyBitcoinProviderList: [BuyBitcoinProvider]) -> [String] { - return buyBitcoinProviderList.map { v -> String in valueOf(buyBitcoinProvider: v) } + return buyBitcoinProviderList.map { v -> String in return valueOf(buyBitcoinProvider: v) } } static func asBuyBitcoinProviderList(arr: [Any]) throws -> [BuyBitcoinProvider] { @@ -4515,7 +4520,7 @@ enum BreezSDKMapper { } static func arrayOf(channelStateList: [ChannelState]) -> [String] { - return channelStateList.map { v -> String in valueOf(channelState: v) } + return channelStateList.map { v -> String in return valueOf(channelState: v) } } static func asChannelStateList(arr: [Any]) throws -> [ChannelState] { @@ -4554,7 +4559,7 @@ enum BreezSDKMapper { } static func arrayOf(environmentTypeList: [EnvironmentType]) -> [String] { - return environmentTypeList.map { v -> String in valueOf(environmentType: v) } + return environmentTypeList.map { v -> String in return valueOf(environmentType: v) } } static func asEnvironmentTypeList(arr: [Any]) throws -> [EnvironmentType] { @@ -4599,7 +4604,7 @@ enum BreezSDKMapper { } static func arrayOf(feeratePresetList: [FeeratePreset]) -> [String] { - return feeratePresetList.map { v -> String in valueOf(feeratePreset: v) } + return feeratePresetList.map { v -> String in return valueOf(feeratePreset: v) } } static func asFeeratePresetList(arr: [Any]) throws -> [FeeratePreset] { @@ -4644,7 +4649,7 @@ enum BreezSDKMapper { } static func arrayOf(healthCheckStatusList: [HealthCheckStatus]) -> [String] { - return healthCheckStatusList.map { v -> String in valueOf(healthCheckStatus: v) } + return healthCheckStatusList.map { v -> String in return valueOf(healthCheckStatus: v) } } static func asHealthCheckStatusList(arr: [Any]) throws -> [HealthCheckStatus] { @@ -4795,7 +4800,7 @@ enum BreezSDKMapper { } static func arrayOf(inputTypeList: [InputType]) -> [Any] { - return inputTypeList.map { v -> [String: Any?] in dictionaryOf(inputType: v) } + return inputTypeList.map { v -> [String: Any?] in return dictionaryOf(inputType: v) } } static func asInputTypeList(arr: [Any]) throws -> [InputType] { @@ -4846,7 +4851,7 @@ enum BreezSDKMapper { } static func arrayOf(lnUrlCallbackStatusList: [LnUrlCallbackStatus]) -> [Any] { - return lnUrlCallbackStatusList.map { v -> [String: Any?] in dictionaryOf(lnUrlCallbackStatus: v) } + return lnUrlCallbackStatusList.map { v -> [String: Any?] in return dictionaryOf(lnUrlCallbackStatus: v) } } static func asLnUrlCallbackStatusList(arr: [Any]) throws -> [LnUrlCallbackStatus] { @@ -4921,7 +4926,7 @@ enum BreezSDKMapper { } static func arrayOf(lnUrlPayResultList: [LnUrlPayResult]) -> [Any] { - return lnUrlPayResultList.map { v -> [String: Any?] in dictionaryOf(lnUrlPayResult: v) } + return lnUrlPayResultList.map { v -> [String: Any?] in return dictionaryOf(lnUrlPayResult: v) } } static func asLnUrlPayResultList(arr: [Any]) throws -> [LnUrlPayResult] { @@ -4996,7 +5001,7 @@ enum BreezSDKMapper { } static func arrayOf(lnUrlWithdrawResultList: [LnUrlWithdrawResult]) -> [Any] { - return lnUrlWithdrawResultList.map { v -> [String: Any?] in dictionaryOf(lnUrlWithdrawResult: v) } + return lnUrlWithdrawResultList.map { v -> [String: Any?] in return dictionaryOf(lnUrlWithdrawResult: v) } } static func asLnUrlWithdrawResultList(arr: [Any]) throws -> [LnUrlWithdrawResult] { @@ -5047,7 +5052,7 @@ enum BreezSDKMapper { } static func arrayOf(networkList: [Network]) -> [String] { - return networkList.map { v -> String in valueOf(network: v) } + return networkList.map { v -> String in return valueOf(network: v) } } static func asNetworkList(arr: [Any]) throws -> [Network] { @@ -5090,7 +5095,7 @@ enum BreezSDKMapper { } static func arrayOf(nodeConfigList: [NodeConfig]) -> [Any] { - return nodeConfigList.map { v -> [String: Any?] in dictionaryOf(nodeConfig: v) } + return nodeConfigList.map { v -> [String: Any?] in return dictionaryOf(nodeConfig: v) } } static func asNodeConfigList(arr: [Any]) throws -> [NodeConfig] { @@ -5133,7 +5138,7 @@ enum BreezSDKMapper { } static func arrayOf(nodeCredentialsList: [NodeCredentials]) -> [Any] { - return nodeCredentialsList.map { v -> [String: Any?] in dictionaryOf(nodeCredentials: v) } + return nodeCredentialsList.map { v -> [String: Any?] in return dictionaryOf(nodeCredentials: v) } } static func asNodeCredentialsList(arr: [Any]) throws -> [NodeCredentials] { @@ -5192,7 +5197,7 @@ enum BreezSDKMapper { } static func arrayOf(paymentDetailsList: [PaymentDetails]) -> [Any] { - return paymentDetailsList.map { v -> [String: Any?] in dictionaryOf(paymentDetails: v) } + return paymentDetailsList.map { v -> [String: Any?] in return dictionaryOf(paymentDetails: v) } } static func asPaymentDetailsList(arr: [Any]) throws -> [PaymentDetails] { @@ -5237,7 +5242,7 @@ enum BreezSDKMapper { } static func arrayOf(paymentStatusList: [PaymentStatus]) -> [String] { - return paymentStatusList.map { v -> String in valueOf(paymentStatus: v) } + return paymentStatusList.map { v -> String in return valueOf(paymentStatus: v) } } static func asPaymentStatusList(arr: [Any]) throws -> [PaymentStatus] { @@ -5282,7 +5287,7 @@ enum BreezSDKMapper { } static func arrayOf(paymentTypeList: [PaymentType]) -> [String] { - return paymentTypeList.map { v -> String in valueOf(paymentType: v) } + return paymentTypeList.map { v -> String in return valueOf(paymentType: v) } } static func asPaymentTypeList(arr: [Any]) throws -> [PaymentType] { @@ -5327,7 +5332,7 @@ enum BreezSDKMapper { } static func arrayOf(paymentTypeFilterList: [PaymentTypeFilter]) -> [String] { - return paymentTypeFilterList.map { v -> String in valueOf(paymentTypeFilter: v) } + return paymentTypeFilterList.map { v -> String in return valueOf(paymentTypeFilter: v) } } static func asPaymentTypeFilterList(arr: [Any]) throws -> [PaymentTypeFilter] { @@ -5370,7 +5375,7 @@ enum BreezSDKMapper { } static func arrayOf(reportIssueRequestList: [ReportIssueRequest]) -> [Any] { - return reportIssueRequestList.map { v -> [String: Any?] in dictionaryOf(reportIssueRequest: v) } + return reportIssueRequestList.map { v -> [String: Any?] in return dictionaryOf(reportIssueRequest: v) } } static func asReportIssueRequestList(arr: [Any]) throws -> [ReportIssueRequest] { @@ -5427,7 +5432,7 @@ enum BreezSDKMapper { } static func arrayOf(reverseSwapStatusList: [ReverseSwapStatus]) -> [String] { - return reverseSwapStatusList.map { v -> String in valueOf(reverseSwapStatus: v) } + return reverseSwapStatusList.map { v -> String in return valueOf(reverseSwapStatus: v) } } static func asReverseSwapStatusList(arr: [Any]) throws -> [ReverseSwapStatus] { @@ -5502,7 +5507,7 @@ enum BreezSDKMapper { } static func arrayOf(successActionProcessedList: [SuccessActionProcessed]) -> [Any] { - return successActionProcessedList.map { v -> [String: Any?] in dictionaryOf(successActionProcessed: v) } + return successActionProcessedList.map { v -> [String: Any?] in return dictionaryOf(successActionProcessed: v) } } static func asSuccessActionProcessedList(arr: [Any]) throws -> [SuccessActionProcessed] { @@ -5541,7 +5546,7 @@ enum BreezSDKMapper { } static func arrayOf(swapAmountTypeList: [SwapAmountType]) -> [String] { - return swapAmountTypeList.map { v -> String in valueOf(swapAmountType: v) } + return swapAmountTypeList.map { v -> String in return valueOf(swapAmountType: v) } } static func asSwapAmountTypeList(arr: [Any]) throws -> [SwapAmountType] { @@ -5604,7 +5609,7 @@ enum BreezSDKMapper { } static func arrayOf(swapStatusList: [SwapStatus]) -> [String] { - return swapStatusList.map { v -> String in valueOf(swapStatus: v) } + return swapStatusList.map { v -> String in return valueOf(swapStatus: v) } } static func asSwapStatusList(arr: [Any]) throws -> [SwapStatus] { diff --git a/libs/sdk-react-native/src/index.ts b/libs/sdk-react-native/src/index.ts index d6b455bd0..530b306c0 100644 --- a/libs/sdk-react-native/src/index.ts +++ b/libs/sdk-react-native/src/index.ts @@ -579,6 +579,7 @@ export interface UnspentTransactionOutput { export interface UrlSuccessActionData { description: string url: string + matchesCallbackDomain: boolean } export enum AesSuccessActionDataResultVariant { From ef63ea4273c4b666378d40aa3dac4c36086d14b6 Mon Sep 17 00:00:00 2001 From: Ross Savage Date: Mon, 15 Jul 2024 14:25:04 +0200 Subject: [PATCH 2/2] Add an option to not validate the success action url --- libs/sdk-bindings/src/breez_sdk.udl | 1 + libs/sdk-common/src/lnurl/specs/pay.rs | 38 +++++- libs/sdk-core/src/binding.rs | 1 + libs/sdk-core/src/breez_services.rs | 1 + libs/sdk-core/src/bridge_generated.io.rs | 3 + libs/sdk-core/src/lnurl/pay.rs | 124 ++++++++++++++++-- .../ios/Classes/bridge_generated.h | 1 + libs/sdk-flutter/lib/bridge_generated.dart | 5 + .../main/java/com/breezsdk/BreezSDKMapper.kt | 12 ++ .../sdk-react-native/ios/BreezSDKMapper.swift | 11 +- libs/sdk-react-native/src/index.ts | 1 + tools/sdk-cli/src/command_handlers.rs | 7 +- tools/sdk-cli/src/commands.rs | 4 + 13 files changed, 192 insertions(+), 17 deletions(-) diff --git a/libs/sdk-bindings/src/breez_sdk.udl b/libs/sdk-bindings/src/breez_sdk.udl index 01272bc4e..0563159b5 100644 --- a/libs/sdk-bindings/src/breez_sdk.udl +++ b/libs/sdk-bindings/src/breez_sdk.udl @@ -626,6 +626,7 @@ dictionary LnUrlPayRequest { u64 amount_msat; string? comment = null; string? payment_label = null; + boolean? validate_success_action_url = null; }; dictionary LnUrlPayRequestData { diff --git a/libs/sdk-common/src/lnurl/specs/pay.rs b/libs/sdk-common/src/lnurl/specs/pay.rs index 612de833e..358e36e34 100644 --- a/libs/sdk-common/src/lnurl/specs/pay.rs +++ b/libs/sdk-common/src/lnurl/specs/pay.rs @@ -14,6 +14,7 @@ pub async fn validate_lnurl_pay( comment: &Option, req_data: &LnUrlPayRequestData, network: Network, + validate_success_action_url: Option, ) -> LnUrlResult { validate_user_input( user_amount_msat, @@ -37,8 +38,9 @@ pub async fn validate_lnurl_pay( SuccessAction::Aes(data) => data.validate()?, SuccessAction::Message(data) => data.validate()?, SuccessAction::Url(data) => { - callback_resp.success_action = - Some(SuccessAction::Url(data.validate(req_data)?)); + callback_resp.success_action = Some(SuccessAction::Url( + data.validate(req_data, validate_success_action_url.unwrap_or(true))?, + )); } } } @@ -134,6 +136,9 @@ pub mod model { pub comment: Option, /// The external label or identifier of the [Payment] pub payment_label: Option, + /// Validates that, if there is a URL success action, the URL domain matches + /// the LNURL callback domain. Defaults to `true` + pub validate_success_action_url: Option, } pub enum ValidatedCallbackResponse { @@ -321,7 +326,11 @@ pub mod model { } impl UrlSuccessActionData { - pub fn validate(&self, data: &LnUrlPayRequestData) -> LnUrlResult { + pub fn validate( + &self, + data: &LnUrlPayRequestData, + validate_url: bool, + ) -> LnUrlResult { let mut validated_data = self.clone(); match self.description.len() <= 144 { true => Ok(()), @@ -342,6 +351,12 @@ pub mod model { LnUrlError::invalid_uri("Could not determine Success Action URL domain") })?; + if validate_url && req_domain != action_res_domain { + return Err(LnUrlError::generic( + "Success Action URL has different domain than the callback domain", + )); + } + validated_data.matches_callback_domain = req_domain == action_res_domain; Ok(validated_data) }) @@ -620,17 +635,26 @@ pub(crate) mod tests { url: pay_req_data.callback.clone(), matches_callback_domain: true, } - .validate(&pay_req_data); + .validate(&pay_req_data, true); assert!(validated_data1.is_ok()); assert!(validated_data1.unwrap().matches_callback_domain); - // Different Success Action domain than in the callback URL + // Different Success Action domain than in the callback URL with validation + assert!(UrlSuccessActionData { + description: "short msg".into(), + url: "https://new-domain.com/test-url".into(), + matches_callback_domain: true, + } + .validate(&pay_req_data, true) + .is_err()); + + // Different Success Action domain than in the callback URL without validation let validated_data2 = UrlSuccessActionData { description: "short msg".into(), url: "https://new-domain.com/test-url".into(), matches_callback_domain: true, } - .validate(&pay_req_data); + .validate(&pay_req_data, false); assert!(validated_data2.is_ok()); assert!(!validated_data2.unwrap().matches_callback_domain); @@ -640,7 +664,7 @@ pub(crate) mod tests { url: pay_req_data.callback.clone(), matches_callback_domain: true, } - .validate(&pay_req_data) + .validate(&pay_req_data, true) .is_err()); Ok(()) diff --git a/libs/sdk-core/src/binding.rs b/libs/sdk-core/src/binding.rs index 320408914..13420a054 100644 --- a/libs/sdk-core/src/binding.rs +++ b/libs/sdk-core/src/binding.rs @@ -125,6 +125,7 @@ pub struct _LnUrlPayRequest { pub amount_msat: u64, pub comment: Option, pub payment_label: Option, + pub validate_success_action_url: Option, } #[frb(mirror(LnUrlPayRequestData))] diff --git a/libs/sdk-core/src/breez_services.rs b/libs/sdk-core/src/breez_services.rs index 39a79866a..4d31f4276 100644 --- a/libs/sdk-core/src/breez_services.rs +++ b/libs/sdk-core/src/breez_services.rs @@ -339,6 +339,7 @@ impl BreezServices { &req.comment, &req.data, self.config.network, + req.validate_success_action_url, ) .await? { diff --git a/libs/sdk-core/src/bridge_generated.io.rs b/libs/sdk-core/src/bridge_generated.io.rs index f2313d99c..05c3c5579 100644 --- a/libs/sdk-core/src/bridge_generated.io.rs +++ b/libs/sdk-core/src/bridge_generated.io.rs @@ -869,6 +869,7 @@ impl Wire2Api for wire_LnUrlPayRequest { amount_msat: self.amount_msat.wire2api(), comment: self.comment.wire2api(), payment_label: self.payment_label.wire2api(), + validate_success_action_url: self.validate_success_action_url.wire2api(), } } } @@ -1237,6 +1238,7 @@ pub struct wire_LnUrlPayRequest { amount_msat: u64, comment: *mut wire_uint_8_list, payment_label: *mut wire_uint_8_list, + validate_success_action_url: *mut bool, } #[repr(C)] @@ -1644,6 +1646,7 @@ impl NewWithNullPtr for wire_LnUrlPayRequest { amount_msat: Default::default(), comment: core::ptr::null_mut(), payment_label: core::ptr::null_mut(), + validate_success_action_url: core::ptr::null_mut(), } } } diff --git a/libs/sdk-core/src/lnurl/pay.rs b/libs/sdk-core/src/lnurl/pay.rs index 5d6c62a04..d90842f95 100644 --- a/libs/sdk-core/src/lnurl/pay.rs +++ b/libs/sdk-core/src/lnurl/pay.rs @@ -195,6 +195,7 @@ pub(crate) mod tests { /// Mock an LNURL-pay endpoint that responds with a Success Action of type URL fn mock_lnurl_pay_callback_endpoint_url_success_action( callback_params: LnurlPayCallbackParams, + success_action_url: Option<&str>, ) -> Result { let LnurlPayCallbackParams { pay_req, @@ -215,7 +216,7 @@ pub(crate) mod tests { "successAction": { "tag":"url", "description":"test description", - "url":"http://localhost:8080/test-url" + "url":"success-action-url" } } "# @@ -223,6 +224,10 @@ pub(crate) mod tests { .replace( "token-invoice", &pr.unwrap_or_else(|| "token-invoice".to_string()), + ) + .replace( + "success-action-url", + success_action_url.unwrap_or("http://localhost:8080/test-url"), ); let response_body = match error { @@ -399,6 +404,7 @@ pub(crate) mod tests { amount_msat: user_amount_msat, comment: Some(comment), payment_label: None, + validate_success_action_url: None, }) .await? { @@ -443,6 +449,7 @@ pub(crate) mod tests { amount_msat: user_amount_msat, comment: Some(comment), payment_label: None, + validate_success_action_url: None, }) .await; // An unsupported Success Action results in an error @@ -473,6 +480,7 @@ pub(crate) mod tests { amount_msat: user_amount_msat, comment: Some(comment), payment_label: None, + validate_success_action_url: None, }) .await? { @@ -506,6 +514,7 @@ pub(crate) mod tests { amount_msat: user_amount_msat, comment: Some(comment), payment_label: None, + validate_success_action_url: None, }) .await? { @@ -554,6 +563,7 @@ pub(crate) mod tests { amount_msat: user_amount_msat, comment: Some(comment), payment_label: None, + validate_success_action_url: None, }) .await .is_err()); @@ -584,6 +594,7 @@ pub(crate) mod tests { amount_msat: user_amount_msat, comment: Some(comment), payment_label: None, + validate_success_action_url: None, }) .await; assert!(matches!(res, Ok(LnUrlPayResult::EndpointError { data: _ }))); @@ -606,13 +617,16 @@ pub(crate) mod tests { let temp_desc = pay_req.metadata_str.clone(); let inv = rand_invoice_with_description_hash(temp_desc)?; let user_amount_msat = inv.amount_milli_satoshis().unwrap(); - let _m = mock_lnurl_pay_callback_endpoint_url_success_action(LnurlPayCallbackParams { - pay_req: &pay_req, - user_amount_msat, - error: None, - pr: Some(inv.to_string()), - comment: comment.clone(), - })?; + let _m = mock_lnurl_pay_callback_endpoint_url_success_action( + LnurlPayCallbackParams { + pay_req: &pay_req, + user_amount_msat, + error: None, + pr: Some(inv.to_string()), + comment: comment.clone(), + }, + None, + )?; let mock_breez_services = crate::breez_services::tests::breez_services().await?; match mock_breez_services @@ -621,6 +635,7 @@ pub(crate) mod tests { amount_msat: user_amount_msat, comment: Some(comment), payment_label: None, + validate_success_action_url: None, }) .await? { @@ -652,6 +667,97 @@ pub(crate) mod tests { } } + #[tokio::test] + async fn test_lnurl_pay_url_success_action_validate_url_invalid() -> Result<()> { + let comment = rand_string(COMMENT_LENGTH as usize); + let pay_req = get_test_pay_req_data(0, 100_000, COMMENT_LENGTH); + let temp_desc = pay_req.metadata_str.clone(); + let inv = rand_invoice_with_description_hash(temp_desc)?; + let user_amount_msat = inv.amount_milli_satoshis().unwrap(); + let _m = mock_lnurl_pay_callback_endpoint_url_success_action( + LnurlPayCallbackParams { + pay_req: &pay_req, + user_amount_msat, + error: None, + pr: Some(inv.to_string()), + comment: comment.clone(), + }, + Some("http://different.localhost:8080/test-url"), + )?; + + let mock_breez_services = crate::breez_services::tests::breez_services().await?; + let r = mock_breez_services + .lnurl_pay(LnUrlPayRequest { + data: pay_req, + amount_msat: user_amount_msat, + comment: Some(comment), + payment_label: None, + validate_success_action_url: Some(true), + }) + .await; + // An invalid Success Action URL results in an error + assert!(r.is_err()); + + Ok(()) + } + + #[tokio::test] + async fn test_lnurl_pay_url_success_action_validate_url_valid() -> Result<()> { + let comment = rand_string(COMMENT_LENGTH as usize); + let pay_req = get_test_pay_req_data(0, 100_000, COMMENT_LENGTH); + let temp_desc = pay_req.metadata_str.clone(); + let inv = rand_invoice_with_description_hash(temp_desc)?; + let user_amount_msat = inv.amount_milli_satoshis().unwrap(); + let _m = mock_lnurl_pay_callback_endpoint_url_success_action( + LnurlPayCallbackParams { + pay_req: &pay_req, + user_amount_msat, + error: None, + pr: Some(inv.to_string()), + comment: comment.clone(), + }, + Some("http://different.localhost:8080/test-url"), + )?; + + let mock_breez_services = crate::breez_services::tests::breez_services().await?; + match mock_breez_services + .lnurl_pay(LnUrlPayRequest { + data: pay_req, + amount_msat: user_amount_msat, + comment: Some(comment), + payment_label: None, + validate_success_action_url: Some(false), + }) + .await? + { + LnUrlPayResult::EndpointSuccess { + data: + LnUrlPaySuccessData { + success_action: Some(SuccessActionProcessed::Url { data: url }), + .. + }, + } => { + if url.url == "http://different.localhost:8080/test-url" + && url.description == "test description" + { + Ok(()) + } else { + Err(anyhow!("Unexpected success action content")) + } + } + LnUrlPayResult::EndpointSuccess { + data: + LnUrlPaySuccessData { + success_action: None, + .. + }, + } => Err(anyhow!( + "Expected success action in callback, but none provided" + )), + _ => Err(anyhow!("Unexpected success action type")), + } + } + #[tokio::test] async fn test_lnurl_pay_aes_success_action() -> Result<()> { // Expected fields in the AES payload @@ -707,6 +813,7 @@ pub(crate) mod tests { amount_msat: user_amount_msat, comment: Some(comment), payment_label: None, + validate_success_action_url: None, }) .await? { @@ -791,6 +898,7 @@ pub(crate) mod tests { amount_msat: user_amount_msat, comment: Some(comment), payment_label: None, + validate_success_action_url: None, }) .await? { diff --git a/libs/sdk-flutter/ios/Classes/bridge_generated.h b/libs/sdk-flutter/ios/Classes/bridge_generated.h index 7408bf1ed..b022e0a7d 100644 --- a/libs/sdk-flutter/ios/Classes/bridge_generated.h +++ b/libs/sdk-flutter/ios/Classes/bridge_generated.h @@ -171,6 +171,7 @@ typedef struct wire_LnUrlPayRequest { uint64_t amount_msat; struct wire_uint_8_list *comment; struct wire_uint_8_list *payment_label; + bool *validate_success_action_url; } wire_LnUrlPayRequest; typedef struct wire_LnUrlWithdrawRequestData { diff --git a/libs/sdk-flutter/lib/bridge_generated.dart b/libs/sdk-flutter/lib/bridge_generated.dart index ddd06d9ed..fff6cf212 100644 --- a/libs/sdk-flutter/lib/bridge_generated.dart +++ b/libs/sdk-flutter/lib/bridge_generated.dart @@ -858,12 +858,14 @@ class LnUrlPayRequest { final int amountMsat; final String? comment; final String? paymentLabel; + final bool? validateSuccessActionUrl; const LnUrlPayRequest({ required this.data, required this.amountMsat, this.comment, this.paymentLabel, + this.validateSuccessActionUrl, }); } @@ -4825,6 +4827,7 @@ class BreezSdkCorePlatform extends FlutterRustBridgeBase { wireObj.amount_msat = api2wire_u64(apiObj.amountMsat); wireObj.comment = api2wire_opt_String(apiObj.comment); wireObj.payment_label = api2wire_opt_String(apiObj.paymentLabel); + wireObj.validate_success_action_url = api2wire_opt_box_autoadd_bool(apiObj.validateSuccessActionUrl); } void _api_fill_to_wire_ln_url_pay_request_data( @@ -6656,6 +6659,8 @@ final class wire_LnUrlPayRequest extends ffi.Struct { external ffi.Pointer comment; external ffi.Pointer payment_label; + + external ffi.Pointer validate_success_action_url; } final class wire_LnUrlWithdrawRequestData extends ffi.Struct { diff --git a/libs/sdk-react-native/android/src/main/java/com/breezsdk/BreezSDKMapper.kt b/libs/sdk-react-native/android/src/main/java/com/breezsdk/BreezSDKMapper.kt index 8f45d2952..f628b0712 100644 --- a/libs/sdk-react-native/android/src/main/java/com/breezsdk/BreezSDKMapper.kt +++ b/libs/sdk-react-native/android/src/main/java/com/breezsdk/BreezSDKMapper.kt @@ -1156,11 +1156,22 @@ fun asLnUrlPayRequest(lnUrlPayRequest: ReadableMap): LnUrlPayRequest? { val amountMsat = lnUrlPayRequest.getDouble("amountMsat").toULong() val comment = if (hasNonNullKey(lnUrlPayRequest, "comment")) lnUrlPayRequest.getString("comment") else null val paymentLabel = if (hasNonNullKey(lnUrlPayRequest, "paymentLabel")) lnUrlPayRequest.getString("paymentLabel") else null + val validateSuccessActionUrl = + if (hasNonNullKey( + lnUrlPayRequest, + "validateSuccessActionUrl", + ) + ) { + lnUrlPayRequest.getBoolean("validateSuccessActionUrl") + } else { + null + } return LnUrlPayRequest( data, amountMsat, comment, paymentLabel, + validateSuccessActionUrl, ) } @@ -1170,6 +1181,7 @@ fun readableMapOf(lnUrlPayRequest: LnUrlPayRequest): ReadableMap = "amountMsat" to lnUrlPayRequest.amountMsat, "comment" to lnUrlPayRequest.comment, "paymentLabel" to lnUrlPayRequest.paymentLabel, + "validateSuccessActionUrl" to lnUrlPayRequest.validateSuccessActionUrl, ) fun asLnUrlPayRequestList(arr: ReadableArray): List { diff --git a/libs/sdk-react-native/ios/BreezSDKMapper.swift b/libs/sdk-react-native/ios/BreezSDKMapper.swift index bafa135fa..1b0b3cd84 100644 --- a/libs/sdk-react-native/ios/BreezSDKMapper.swift +++ b/libs/sdk-react-native/ios/BreezSDKMapper.swift @@ -1326,12 +1326,20 @@ enum BreezSDKMapper { } paymentLabel = paymentLabelTmp } + var validateSuccessActionUrl: Bool? + if hasNonNilKey(data: lnUrlPayRequest, key: "validateSuccessActionUrl") { + guard let validateSuccessActionUrlTmp = lnUrlPayRequest["validateSuccessActionUrl"] as? Bool else { + throw SdkError.Generic(message: errUnexpectedValue(fieldName: "validateSuccessActionUrl")) + } + validateSuccessActionUrl = validateSuccessActionUrlTmp + } return LnUrlPayRequest( data: data, amountMsat: amountMsat, comment: comment, - paymentLabel: paymentLabel + paymentLabel: paymentLabel, + validateSuccessActionUrl: validateSuccessActionUrl ) } @@ -1341,6 +1349,7 @@ enum BreezSDKMapper { "amountMsat": lnUrlPayRequest.amountMsat, "comment": lnUrlPayRequest.comment == nil ? nil : lnUrlPayRequest.comment, "paymentLabel": lnUrlPayRequest.paymentLabel == nil ? nil : lnUrlPayRequest.paymentLabel, + "validateSuccessActionUrl": lnUrlPayRequest.validateSuccessActionUrl == nil ? nil : lnUrlPayRequest.validateSuccessActionUrl, ] } diff --git a/libs/sdk-react-native/src/index.ts b/libs/sdk-react-native/src/index.ts index 530b306c0..f07a07a65 100644 --- a/libs/sdk-react-native/src/index.ts +++ b/libs/sdk-react-native/src/index.ts @@ -192,6 +192,7 @@ export interface LnUrlPayRequest { amountMsat: number comment?: string paymentLabel?: string + validateSuccessActionUrl?: boolean } export interface LnUrlPayRequestData { diff --git a/tools/sdk-cli/src/command_handlers.rs b/tools/sdk-cli/src/command_handlers.rs index db9e8873f..53175bd07 100644 --- a/tools/sdk-cli/src/command_handlers.rs +++ b/tools/sdk-cli/src/command_handlers.rs @@ -466,7 +466,11 @@ pub(crate) async fn handle_command( let res = sdk()?.check_message(req).await?; Ok(format!("Message was signed by node: {}", res.is_valid)) } - Commands::LnurlPay { lnurl, label } => match parse(&lnurl).await? { + Commands::LnurlPay { + lnurl, + label, + validate_success_url, + } => match parse(&lnurl).await? { LnUrlPay { data: pd } => { let prompt = format!( "Amount to pay in millisatoshi (min {} msat, max {} msat: ", @@ -480,6 +484,7 @@ pub(crate) async fn handle_command( amount_msat: amount_msat.parse::()?, comment: None, payment_label: label, + validate_success_action_url: validate_success_url, }) .await?; //show_results(pay_res); diff --git a/tools/sdk-cli/src/commands.rs b/tools/sdk-cli/src/commands.rs index ff2c19ab6..ef8cbc4a4 100644 --- a/tools/sdk-cli/src/commands.rs +++ b/tools/sdk-cli/src/commands.rs @@ -93,6 +93,10 @@ pub(crate) enum Commands { /// The external label or identifier of the payment #[clap(name = "label", short = 'l', long = "label")] label: Option, + + /// Validates the success action URL + #[clap(name = "validate_success_url", short = 'v', long = "validate")] + validate_success_url: Option, }, /// [lnurl] Withdraw using lnurl withdraw