Add proxy support (#272)

* Add proxy support
This commit is contained in:
David Caseria
2024-08-07 08:53:05 -04:00
committed by GitHub
parent 6adf3267c0
commit 0945b3540a
7 changed files with 54 additions and 5 deletions

View File

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

View File

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

View File

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

View File

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

View File

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

View File

@@ -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] /// Get Active Mint Keys [NUT-01]
#[instrument(skip(self), fields(mint_url = %mint_url))] #[instrument(skip(self), fields(mint_url = %mint_url))]
pub async fn get_mint_keys(&self, mint_url: Url) -> Result<Vec<KeySet>, Error> { pub async fn get_mint_keys(&self, mint_url: Url) -> Result<Vec<KeySet>, Error> {

View File

@@ -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 /// Fee required for proof set
#[instrument(skip_all)] #[instrument(skip_all)]
pub async fn get_proofs_fee(&self, proofs: &Proofs) -> Result<Amount, Error> { pub async fn get_proofs_fee(&self, proofs: &Proofs) -> Result<Amount, Error> {