Browse Source

Add proxy support (#272)

* Add proxy support
David Caseria 7 months ago
parent
commit
0945b3540a

+ 1 - 0
Cargo.toml

@@ -48,6 +48,7 @@ uuid = { version = "1", features = ["v4"] }
 lightning-invoice = { version = "0.31", features = ["serde"] }
 home = "0.5.9"
 rand = "0.8.5"
+url = "2.3"
 
 [profile]
 

+ 1 - 0
crates/cdk-cli/Cargo.toml

@@ -29,3 +29,4 @@ nostr-sdk = { version = "0.33.0", default-features = false, features = [
     "nip04",
     "nip44"
 ]}
+url.workspace = true

+ 10 - 2
crates/cdk-cli/src/main.rs

@@ -7,6 +7,7 @@ use anyhow::{bail, Result};
 use bip39::Mnemonic;
 use cdk::cdk_database;
 use cdk::cdk_database::WalletDatabase;
+use cdk::wallet::client::HttpClient;
 use cdk::wallet::{MultiMintWallet, Wallet};
 use cdk_redb::WalletRedbDatabase;
 use cdk_sqlite::WalletSqliteDatabase;
@@ -14,6 +15,7 @@ use clap::{Parser, Subcommand};
 use rand::Rng;
 use tracing::Level;
 use tracing_subscriber::EnvFilter;
+use url::Url;
 
 mod sub_commands;
 
@@ -35,6 +37,9 @@ struct Cli {
     /// Logging level
     #[arg(short, long, default_value = "error")]
     log_level: Level,
+    /// NWS Proxy
+    #[arg(short, long)]
+    proxy: Option<Url>,
     #[command(subcommand)]
     command: Commands,
 }
@@ -130,13 +135,16 @@ async fn main() -> Result<()> {
     let mints = localstore.get_mints().await?;
 
     for (mint, _) in mints {
-        let wallet = Wallet::new(
+        let mut wallet = Wallet::new(
             &mint.to_string(),
             cdk::nuts::CurrencyUnit::Sat,
             localstore.clone(),
             &mnemonic.to_seed_normalized(""),
             None,
         );
+        if let Some(proxy_url) = args.proxy.as_ref() {
+            wallet.set_client(HttpClient::with_proxy(proxy_url.clone(), None, true)?);
+        }
 
         wallets.push(wallet);
     }
@@ -167,7 +175,7 @@ async fn main() -> Result<()> {
             sub_commands::check_spent::check_spent(&multi_mint_wallet).await
         }
         Commands::MintInfo(sub_command_args) => {
-            sub_commands::mint_info::mint_info(sub_command_args).await
+            sub_commands::mint_info::mint_info(args.proxy, sub_command_args).await
         }
         Commands::Mint(sub_command_args) => {
             sub_commands::mint::mint(

+ 6 - 2
crates/cdk-cli/src/sub_commands/mint_info.rs

@@ -2,6 +2,7 @@ use anyhow::Result;
 use cdk::url::UncheckedUrl;
 use cdk::HttpClient;
 use clap::Args;
+use url::Url;
 
 #[derive(Args)]
 pub struct MintInfoSubcommand {
@@ -9,8 +10,11 @@ pub struct MintInfoSubcommand {
     mint_url: UncheckedUrl,
 }
 
-pub async fn mint_info(sub_command_args: &MintInfoSubcommand) -> Result<()> {
-    let client = HttpClient::default();
+pub async fn mint_info(proxy: Option<Url>, sub_command_args: &MintInfoSubcommand) -> Result<()> {
+    let client = match proxy {
+        Some(proxy) => HttpClient::with_proxy(proxy, None, true)?,
+        None => HttpClient::new(),
+    };
 
     let info = client
         .get_mint_info(sub_command_args.mint_url.clone().try_into()?)

+ 2 - 1
crates/cdk/Cargo.toml

@@ -28,6 +28,7 @@ bitcoin = { workspace = true, features = [
 ciborium = { version = "0.2.2", default-features = false, features = ["std"] }
 lightning-invoice.workspace = true
 once_cell = "1.19"
+regex = "1"
 reqwest = { version = "0.12", default-features = false, features = [
     "json",
     "rustls-tls",
@@ -40,7 +41,7 @@ serde_with = "3.4"
 tracing.workspace = true
 thiserror.workspace = true
 futures = { workspace = true, optional = true }
-url = "2.3"
+url.workspace = true
 uuid.workspace = true
 
 [target.'cfg(not(target_arch = "wasm32"))'.dependencies]

+ 29 - 0
crates/cdk/src/wallet/client.rs

@@ -56,6 +56,35 @@ impl HttpClient {
         }
     }
 
+    #[cfg(not(target_arch = "wasm32"))]
+    /// Create new [`HttpClient`] with a proxy for specific TLDs.
+    /// Specifying `None` for `host_matcher` will use the proxy for all requests.
+    pub fn with_proxy(
+        proxy: Url,
+        host_matcher: Option<&str>,
+        accept_invalid_certs: bool,
+    ) -> Result<Self, Error> {
+        let regex = host_matcher
+            .map(regex::Regex::new)
+            .transpose()
+            .map_err(|e| Error::Custom(e.to_string()))?;
+        let client = reqwest::Client::builder()
+            .proxy(reqwest::Proxy::custom(move |url| {
+                if let Some(matcher) = regex.as_ref() {
+                    if let Some(host) = url.host_str() {
+                        if matcher.is_match(host) {
+                            return Some(proxy.clone());
+                        }
+                    }
+                }
+                None
+            }))
+            .danger_accept_invalid_certs(accept_invalid_certs) // Allow self-signed certs
+            .build()?;
+
+        Ok(Self { inner: client })
+    }
+
     /// Get Active Mint Keys [NUT-01]
     #[instrument(skip(self), fields(mint_url = %mint_url))]
     pub async fn get_mint_keys(&self, mint_url: Url) -> Result<Vec<KeySet>, Error> {

+ 5 - 0
crates/cdk/src/wallet/mod.rs

@@ -75,6 +75,11 @@ impl Wallet {
         }
     }
 
+    /// Change HTTP client
+    pub fn set_client(&mut self, client: HttpClient) {
+        self.client = client;
+    }
+
     /// Fee required for proof set
     #[instrument(skip_all)]
     pub async fn get_proofs_fee(&self, proofs: &Proofs) -> Result<Amount, Error> {