Pārlūkot izejas kodu

fi: add ws resource to ProtectedEndpoints (#1178)

* feat: add ws resource to ProtectedEndpoints
asmo 3 nedēļas atpakaļ
vecāks
revīzija
5fc38d5980
1 mainītis faili ar 337 papildinājumiem un 0 dzēšanām
  1. 337 0
      crates/cdk-ffi/src/types/mint.rs

+ 337 - 0
crates/cdk-ffi/src/types/mint.rs

@@ -440,6 +440,7 @@ impl TryFrom<ProtectedEndpoint> for cdk::nuts::ProtectedEndpoint {
             "/v1/melt/quote/bolt11" => cdk::nuts::RoutePath::MeltQuoteBolt11,
             "/v1/melt/bolt11" => cdk::nuts::RoutePath::MeltBolt11,
             "/v1/swap" => cdk::nuts::RoutePath::Swap,
+            "/v1/ws" => cdk::nuts::RoutePath::Ws,
             "/v1/checkstate" => cdk::nuts::RoutePath::Checkstate,
             "/v1/restore" => cdk::nuts::RoutePath::Restore,
             "/v1/auth/blind/mint" => cdk::nuts::RoutePath::MintBlindAuth,
@@ -673,3 +674,339 @@ pub fn decode_mint_info(json: String) -> Result<MintInfo, FfiError> {
 pub fn encode_mint_info(info: MintInfo) -> Result<String, FfiError> {
     Ok(serde_json::to_string(&info)?)
 }
+#[cfg(test)]
+mod tests {
+    use super::*;
+
+    /// Helper function to create a sample cdk::nuts::Nuts for testing
+    fn create_sample_cdk_nuts() -> cdk::nuts::Nuts {
+        cdk::nuts::Nuts {
+            nut04: cdk::nuts::nut04::Settings {
+                methods: vec![cdk::nuts::nut04::MintMethodSettings {
+                    method: cdk::nuts::PaymentMethod::Bolt11,
+                    unit: cdk::nuts::CurrencyUnit::Sat,
+                    min_amount: Some(cdk::Amount::from(1)),
+                    max_amount: Some(cdk::Amount::from(100000)),
+                    options: Some(cdk::nuts::nut04::MintMethodOptions::Bolt11 {
+                        description: true,
+                    }),
+                }],
+                disabled: false,
+            },
+            nut05: cdk::nuts::nut05::Settings {
+                methods: vec![cdk::nuts::nut05::MeltMethodSettings {
+                    method: cdk::nuts::PaymentMethod::Bolt11,
+                    unit: cdk::nuts::CurrencyUnit::Sat,
+                    min_amount: Some(cdk::Amount::from(1)),
+                    max_amount: Some(cdk::Amount::from(100000)),
+                    options: Some(cdk::nuts::nut05::MeltMethodOptions::Bolt11 { amountless: true }),
+                }],
+                disabled: false,
+            },
+            nut07: cdk::nuts::nut06::SupportedSettings { supported: true },
+            nut08: cdk::nuts::nut06::SupportedSettings { supported: true },
+            nut09: cdk::nuts::nut06::SupportedSettings { supported: false },
+            nut10: cdk::nuts::nut06::SupportedSettings { supported: true },
+            nut11: cdk::nuts::nut06::SupportedSettings { supported: true },
+            nut12: cdk::nuts::nut06::SupportedSettings { supported: true },
+            nut14: cdk::nuts::nut06::SupportedSettings { supported: false },
+            nut15: Default::default(),
+            nut17: Default::default(),
+            nut19: Default::default(),
+            nut20: cdk::nuts::nut06::SupportedSettings { supported: true },
+            nut21: Some(cdk::nuts::ClearAuthSettings {
+                openid_discovery: "https://example.com/.well-known/openid-configuration"
+                    .to_string(),
+                client_id: "test-client".to_string(),
+                protected_endpoints: vec![cdk::nuts::ProtectedEndpoint::new(
+                    cdk::nuts::Method::Post,
+                    cdk::nuts::RoutePath::Swap,
+                )],
+            }),
+            nut22: Some(cdk::nuts::BlindAuthSettings {
+                bat_max_mint: 100,
+                protected_endpoints: vec![cdk::nuts::ProtectedEndpoint::new(
+                    cdk::nuts::Method::Post,
+                    cdk::nuts::RoutePath::MintBolt11,
+                )],
+            }),
+        }
+    }
+
+    #[test]
+    fn test_nuts_from_cdk_to_ffi() {
+        let cdk_nuts = create_sample_cdk_nuts();
+        let ffi_nuts: Nuts = cdk_nuts.clone().into();
+
+        // Verify NUT04 settings
+        assert_eq!(ffi_nuts.nut04.disabled, false);
+        assert_eq!(ffi_nuts.nut04.methods.len(), 1);
+        assert_eq!(ffi_nuts.nut04.methods[0].description, Some(true));
+
+        // Verify NUT05 settings
+        assert_eq!(ffi_nuts.nut05.disabled, false);
+        assert_eq!(ffi_nuts.nut05.methods.len(), 1);
+        assert_eq!(ffi_nuts.nut05.methods[0].amountless, Some(true));
+
+        // Verify supported flags
+        assert!(ffi_nuts.nut07_supported);
+        assert!(ffi_nuts.nut08_supported);
+        assert!(!ffi_nuts.nut09_supported);
+        assert!(ffi_nuts.nut10_supported);
+        assert!(ffi_nuts.nut11_supported);
+        assert!(ffi_nuts.nut12_supported);
+        assert!(!ffi_nuts.nut14_supported);
+        assert!(ffi_nuts.nut20_supported);
+
+        // Verify auth settings
+        assert!(ffi_nuts.nut21.is_some());
+        let nut21 = ffi_nuts.nut21.as_ref().unwrap();
+        assert_eq!(
+            nut21.openid_discovery,
+            "https://example.com/.well-known/openid-configuration"
+        );
+        assert_eq!(nut21.client_id, "test-client");
+        assert_eq!(nut21.protected_endpoints.len(), 1);
+
+        assert!(ffi_nuts.nut22.is_some());
+        let nut22 = ffi_nuts.nut22.as_ref().unwrap();
+        assert_eq!(nut22.bat_max_mint, 100);
+        assert_eq!(nut22.protected_endpoints.len(), 1);
+
+        // Verify units
+        assert!(!ffi_nuts.mint_units.is_empty());
+        assert!(!ffi_nuts.melt_units.is_empty());
+    }
+
+    #[test]
+    fn test_nuts_round_trip_conversion() {
+        let original_cdk_nuts = create_sample_cdk_nuts();
+
+        // Convert cdk -> ffi -> cdk
+        let ffi_nuts: Nuts = original_cdk_nuts.clone().into();
+        let converted_back: cdk::nuts::Nuts = ffi_nuts.try_into().unwrap();
+
+        // Verify all supported flags match
+        assert_eq!(
+            original_cdk_nuts.nut07.supported,
+            converted_back.nut07.supported
+        );
+        assert_eq!(
+            original_cdk_nuts.nut08.supported,
+            converted_back.nut08.supported
+        );
+        assert_eq!(
+            original_cdk_nuts.nut09.supported,
+            converted_back.nut09.supported
+        );
+        assert_eq!(
+            original_cdk_nuts.nut10.supported,
+            converted_back.nut10.supported
+        );
+        assert_eq!(
+            original_cdk_nuts.nut11.supported,
+            converted_back.nut11.supported
+        );
+        assert_eq!(
+            original_cdk_nuts.nut12.supported,
+            converted_back.nut12.supported
+        );
+        assert_eq!(
+            original_cdk_nuts.nut14.supported,
+            converted_back.nut14.supported
+        );
+        assert_eq!(
+            original_cdk_nuts.nut20.supported,
+            converted_back.nut20.supported
+        );
+
+        // Verify NUT04 settings
+        assert_eq!(
+            original_cdk_nuts.nut04.disabled,
+            converted_back.nut04.disabled
+        );
+        assert_eq!(
+            original_cdk_nuts.nut04.methods.len(),
+            converted_back.nut04.methods.len()
+        );
+
+        // Verify NUT05 settings
+        assert_eq!(
+            original_cdk_nuts.nut05.disabled,
+            converted_back.nut05.disabled
+        );
+        assert_eq!(
+            original_cdk_nuts.nut05.methods.len(),
+            converted_back.nut05.methods.len()
+        );
+
+        // Verify auth settings presence
+        assert_eq!(
+            original_cdk_nuts.nut21.is_some(),
+            converted_back.nut21.is_some()
+        );
+        assert_eq!(
+            original_cdk_nuts.nut22.is_some(),
+            converted_back.nut22.is_some()
+        );
+    }
+
+    #[test]
+    fn test_nuts_without_auth() {
+        let cdk_nuts = cdk::nuts::Nuts {
+            nut04: Default::default(),
+            nut05: Default::default(),
+            nut07: cdk::nuts::nut06::SupportedSettings { supported: true },
+            nut08: cdk::nuts::nut06::SupportedSettings { supported: false },
+            nut09: cdk::nuts::nut06::SupportedSettings { supported: false },
+            nut10: cdk::nuts::nut06::SupportedSettings { supported: false },
+            nut11: cdk::nuts::nut06::SupportedSettings { supported: false },
+            nut12: cdk::nuts::nut06::SupportedSettings { supported: false },
+            nut14: cdk::nuts::nut06::SupportedSettings { supported: false },
+            nut15: Default::default(),
+            nut17: Default::default(),
+            nut19: Default::default(),
+            nut20: cdk::nuts::nut06::SupportedSettings { supported: false },
+            nut21: None,
+            nut22: None,
+        };
+
+        let ffi_nuts: Nuts = cdk_nuts.into();
+
+        assert!(ffi_nuts.nut21.is_none());
+        assert!(ffi_nuts.nut22.is_none());
+        assert!(ffi_nuts.nut07_supported);
+        assert!(!ffi_nuts.nut08_supported);
+    }
+
+    #[test]
+    fn test_ffi_nuts_to_cdk_with_defaults() {
+        let ffi_nuts = Nuts {
+            nut04: Nut04Settings {
+                methods: vec![],
+                disabled: true,
+            },
+            nut05: Nut05Settings {
+                methods: vec![],
+                disabled: true,
+            },
+            nut07_supported: false,
+            nut08_supported: false,
+            nut09_supported: false,
+            nut10_supported: false,
+            nut11_supported: false,
+            nut12_supported: false,
+            nut14_supported: false,
+            nut20_supported: false,
+            nut21: None,
+            nut22: None,
+            mint_units: vec![],
+            melt_units: vec![],
+        };
+
+        let cdk_nuts: Result<cdk::nuts::Nuts, _> = ffi_nuts.try_into();
+        assert!(cdk_nuts.is_ok());
+
+        let cdk_nuts = cdk_nuts.unwrap();
+        assert!(!cdk_nuts.nut07.supported);
+        assert!(!cdk_nuts.nut08.supported);
+        assert!(cdk_nuts.nut21.is_none());
+        assert!(cdk_nuts.nut22.is_none());
+
+        // Verify default values for nuts not included in FFI
+        assert_eq!(cdk_nuts.nut17.supported.len(), 0);
+    }
+
+    #[test]
+    fn test_nuts_serialization() {
+        let cdk_nuts = create_sample_cdk_nuts();
+        let ffi_nuts: Nuts = cdk_nuts.into();
+
+        // Test JSON serialization
+        let json = ffi_nuts.to_json();
+        assert!(json.is_ok());
+
+        let json_str = json.unwrap();
+        assert!(json_str.contains("nut04"));
+        assert!(json_str.contains("nut05"));
+
+        // Test deserialization
+        let decoded: Result<Nuts, _> = serde_json::from_str(&json_str);
+        assert!(decoded.is_ok());
+
+        let decoded_nuts = decoded.unwrap();
+        assert_eq!(decoded_nuts.nut07_supported, ffi_nuts.nut07_supported);
+        assert_eq!(decoded_nuts.nut08_supported, ffi_nuts.nut08_supported);
+    }
+
+    #[test]
+    fn test_nuts_multiple_units() {
+        let mut cdk_nuts = create_sample_cdk_nuts();
+
+        // Add multiple payment methods to test unit collection
+        cdk_nuts
+            .nut04
+            .methods
+            .push(cdk::nuts::nut04::MintMethodSettings {
+                method: cdk::nuts::PaymentMethod::Bolt11,
+                unit: cdk::nuts::CurrencyUnit::Msat,
+                min_amount: Some(cdk::Amount::from(1)),
+                max_amount: Some(cdk::Amount::from(100000)),
+                options: None,
+            });
+
+        cdk_nuts
+            .nut05
+            .methods
+            .push(cdk::nuts::nut05::MeltMethodSettings {
+                method: cdk::nuts::PaymentMethod::Bolt11,
+                unit: cdk::nuts::CurrencyUnit::Usd,
+                min_amount: None,
+                max_amount: None,
+                options: None,
+            });
+
+        let ffi_nuts: Nuts = cdk_nuts.into();
+
+        // Should have collected multiple units
+        assert!(ffi_nuts.mint_units.len() >= 1);
+        assert!(ffi_nuts.melt_units.len() >= 1);
+    }
+
+    #[test]
+    fn test_protected_endpoint_conversion() {
+        let cdk_endpoint =
+            cdk::nuts::ProtectedEndpoint::new(cdk::nuts::Method::Post, cdk::nuts::RoutePath::Swap);
+
+        let ffi_endpoint: ProtectedEndpoint = cdk_endpoint.into();
+
+        assert_eq!(ffi_endpoint.method, "POST");
+        assert_eq!(ffi_endpoint.path, "/v1/swap");
+
+        // Test round-trip
+        let converted_back: Result<cdk::nuts::ProtectedEndpoint, _> = ffi_endpoint.try_into();
+        assert!(converted_back.is_ok());
+    }
+
+    #[test]
+    fn test_invalid_protected_endpoint_method() {
+        let invalid_endpoint = ProtectedEndpoint {
+            method: "INVALID".to_string(),
+            path: "/v1/swap".to_string(),
+        };
+
+        let result: Result<cdk::nuts::ProtectedEndpoint, _> = invalid_endpoint.try_into();
+        assert!(result.is_err());
+    }
+
+    #[test]
+    fn test_invalid_protected_endpoint_path() {
+        let invalid_endpoint = ProtectedEndpoint {
+            method: "POST".to_string(),
+            path: "/invalid/path".to_string(),
+        };
+
+        let result: Result<cdk::nuts::ProtectedEndpoint, _> = invalid_endpoint.try_into();
+        assert!(result.is_err());
+    }
+}