Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Make _danger-local-https feature additive #430

Draft
wants to merge 1 commit into
base: master
Choose a base branch
from
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
17 changes: 9 additions & 8 deletions payjoin-cli/src/app/v2.rs
Original file line number Diff line number Diff line change
Expand Up @@ -362,14 +362,15 @@ async fn unwrap_ohttp_keys_or_else_fetch(config: &AppConfig) -> Result<payjoin::
let ohttp_relay = config.ohttp_relay.clone();
let payjoin_directory = config.pj_directory.clone();
#[cfg(feature = "_danger-local-https")]
let cert_der = crate::app::read_local_cert()?;
Ok(payjoin::io::fetch_ohttp_keys(
ohttp_relay,
payjoin_directory,
#[cfg(feature = "_danger-local-https")]
cert_der,
)
.await?)
let ohttp_keys = {
let cert_der = crate::app::read_local_cert()?;
payjoin::io::fetch_ohttp_keys_with_cert(ohttp_relay, payjoin_directory, cert_der)
.await?
};
#[cfg(not(feature = "_danger-local-https"))]
let ohttp_keys =
payjoin::io::fetch_ohttp_keys(ohttp_relay, payjoin_directory, cert_der).await?;
Ok(ohttp_keys)
}
}

Expand Down
9 changes: 6 additions & 3 deletions payjoin-cli/tests/e2e.rs
Original file line number Diff line number Diff line change
Expand Up @@ -240,9 +240,12 @@ mod e2e {

// fetch for setup here since ohttp_relay doesn't know the certificate for the directory
// so payjoin-cli is set up with the mock_ohttp_relay which is the directory
let ohttp_keys =
payjoin::io::fetch_ohttp_keys(ohttp_relay.clone(), directory.clone(), cert.clone())
.await?;
let ohttp_keys = payjoin::io::fetch_ohttp_keys_with_cert(
ohttp_relay.clone(),
directory.clone(),
cert.clone(),
)
.await?;
let ohttp_keys_path = temp_dir.join("ohttp_keys");
tokio::fs::write(&ohttp_keys_path, ohttp_keys.encode()?).await?;

Expand Down
4 changes: 2 additions & 2 deletions payjoin/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -20,8 +20,8 @@ send = []
receive = ["bitcoin/rand"]
base64 = ["bitcoin/base64"]
v2 = ["bitcoin/rand", "bitcoin/serde", "hpke", "dep:http", "bhttp", "ohttp", "serde", "url/serde" ]
io = ["reqwest/rustls-tls"]
_danger-local-https = ["io", "reqwest/rustls-tls", "rustls"]
io = ["v2", "reqwest/rustls-tls"]
_danger-local-https = ["reqwest/rustls-tls", "rustls"]

[dependencies]
bitcoin = { version = "0.32.5", features = ["base64"] }
Expand Down
38 changes: 25 additions & 13 deletions payjoin/src/io.rs
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
#[cfg(feature = "v2")]
use reqwest::{Client, Proxy};

use crate::{OhttpKeys, Url};

/// Fetch the ohttp keys from the specified payjoin directory via proxy.
Expand All @@ -9,22 +10,36 @@ use crate::{OhttpKeys, Url};
///
/// * `payjoin_directory`: The payjoin directory from which to fetch the ohttp keys. This
/// directory stores and forwards payjoin client payloads.
///
/// * `cert_der` (optional): The DER-encoded certificate to use for local HTTPS connections. This
/// parameter is only available when the "_danger-local-https" feature is enabled.
#[cfg(feature = "v2")]
pub async fn fetch_ohttp_keys(
ohttp_relay: Url,
payjoin_directory: Url,
#[cfg(feature = "_danger-local-https")] cert_der: Vec<u8>,
) -> Result<OhttpKeys, Error> {
use reqwest::{Client, Proxy};

let ohttp_keys_url = payjoin_directory.join("/ohttp-keys")?;
let proxy = Proxy::all(ohttp_relay.as_str())?;
#[cfg(not(feature = "_danger-local-https"))]
let client = Client::builder().proxy(proxy).build()?;
#[cfg(feature = "_danger-local-https")]
let res = client.get(ohttp_keys_url).send().await?;
let body = res.bytes().await?.to_vec();
OhttpKeys::decode(&body).map_err(|e| Error(InternalError::InvalidOhttpKeys(e.to_string())))
}

/// Fetch the ohttp keys from the specified payjoin directory via proxy.
///
/// * `ohttp_relay`: The http CONNNECT method proxy to request the ohttp keys from a payjoin
/// directory. Proxying requests for ohttp keys ensures a client IP address is never revealed to
/// the payjoin directory.
///
/// * `payjoin_directory`: The payjoin directory from which to fetch the ohttp keys. This
/// directory stores and forwards payjoin client payloads.
///
/// * `cert_der`: The DER-encoded certificate to use for local HTTPS connections.
#[cfg(feature = "_danger-local-https")]
pub async fn fetch_ohttp_keys_with_cert(
ohttp_relay: Url,
payjoin_directory: Url,
cert_der: Vec<u8>,
) -> Result<OhttpKeys, Error> {
let ohttp_keys_url = payjoin_directory.join("/ohttp-keys")?;
let proxy = Proxy::all(ohttp_relay.as_str())?;
let client = Client::builder()
.danger_accept_invalid_certs(true)
.use_rustls_tls()
Expand All @@ -46,7 +61,6 @@ enum InternalError {
Io(std::io::Error),
#[cfg(feature = "_danger-local-https")]
Rustls(rustls::Error),
#[cfg(feature = "v2")]
InvalidOhttpKeys(String),
}

Expand All @@ -72,7 +86,6 @@ impl std::fmt::Display for Error {
Reqwest(e) => e.fmt(f),
ParseUrl(e) => e.fmt(f),
Io(e) => e.fmt(f),
#[cfg(feature = "v2")]
InvalidOhttpKeys(e) => {
write!(f, "Invalid ohttp keys returned from payjoin directory: {}", e)
}
Expand All @@ -90,7 +103,6 @@ impl std::error::Error for Error {
Reqwest(e) => Some(e),
ParseUrl(e) => Some(e),
Io(e) => Some(e),
#[cfg(feature = "v2")]
InvalidOhttpKeys(_) => None,
#[cfg(feature = "_danger-local-https")]
Rustls(e) => Some(e),
Expand Down
41 changes: 26 additions & 15 deletions payjoin/tests/integration.rs
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
#[cfg(all(feature = "send", feature = "receive"))]
#[cfg(all(feature = "send", feature = "receive", feature = "_danger-local-https"))]
mod integration {
use std::collections::HashMap;
use std::env;
Expand Down Expand Up @@ -171,8 +171,7 @@ mod integration {
}
}

#[cfg(feature = "_danger-local-https")]
#[cfg(feature = "v2")]
#[cfg(all(feature = "io", feature = "v2"))]
mod v2 {
use std::sync::Arc;
use std::time::Duration;
Expand Down Expand Up @@ -252,9 +251,12 @@ mod integration {
let agent = Arc::new(http_agent(cert_der.clone())?);
wait_for_service_ready(ohttp_relay.clone(), agent.clone()).await.unwrap();
wait_for_service_ready(directory.clone(), agent.clone()).await.unwrap();
let ohttp_keys =
payjoin::io::fetch_ohttp_keys(ohttp_relay, directory.clone(), cert_der.clone())
.await?;
let ohttp_keys = payjoin::io::fetch_ohttp_keys_with_cert(
ohttp_relay,
directory.clone(),
cert_der,
)
.await?;

// **********************
// Inside the Receiver:
Expand Down Expand Up @@ -321,9 +323,12 @@ mod integration {
let agent = Arc::new(http_agent(cert_der.clone())?);
wait_for_service_ready(ohttp_relay.clone(), agent.clone()).await.unwrap();
wait_for_service_ready(directory.clone(), agent.clone()).await.unwrap();
let ohttp_keys =
payjoin::io::fetch_ohttp_keys(ohttp_relay, directory.clone(), cert_der.clone())
.await?;
let ohttp_keys = payjoin::io::fetch_ohttp_keys_with_cert(
ohttp_relay,
directory.clone(),
cert_der.clone(),
)
.await?;
// **********************
// Inside the Receiver:
let address = receiver.get_new_address(None, None)?.assume_checked();
Expand Down Expand Up @@ -450,9 +455,12 @@ mod integration {
let agent = Arc::new(http_agent(cert_der.clone())?);
wait_for_service_ready(ohttp_relay.clone(), agent.clone()).await.unwrap();
wait_for_service_ready(directory.clone(), agent.clone()).await.unwrap();
let ohttp_keys =
payjoin::io::fetch_ohttp_keys(ohttp_relay, directory.clone(), cert_der.clone())
.await?;
let ohttp_keys = payjoin::io::fetch_ohttp_keys_with_cert(
ohttp_relay,
directory.clone(),
cert_der,
)
.await?;
// **********************
// Inside the Receiver:
// make utxos with different script types
Expand Down Expand Up @@ -662,9 +670,12 @@ mod integration {
let agent: Arc<Client> = Arc::new(http_agent(cert_der.clone())?);
wait_for_service_ready(ohttp_relay.clone(), agent.clone()).await?;
wait_for_service_ready(directory.clone(), agent.clone()).await?;
let ohttp_keys =
payjoin::io::fetch_ohttp_keys(ohttp_relay, directory.clone(), cert_der.clone())
.await?;
let ohttp_keys = payjoin::io::fetch_ohttp_keys_with_cert(
ohttp_relay,
directory.clone(),
cert_der.clone(),
)
.await?;
let address = receiver.get_new_address(None, None)?.assume_checked();

let mut session = initialize_session(address, directory, ohttp_keys.clone(), None);
Expand Down
Loading