• Home
  • Features
  • Pricing
  • Docs
  • Announcements
  • Sign In

payjoin / rust-payjoin / 15302576773

28 May 2025 02:17PM UTC coverage: 84.136% (-0.4%) from 84.553%
15302576773

Pull #705

github

web-flow
Merge 900d509fa into 87042266d
Pull Request #705: Adjust _danger-local-https to be the default to prevent dangerous cert vulnerability when building with --all-features

11 of 24 new or added lines in 3 files covered. (45.83%)

37 existing lines in 3 files now uncovered.

6518 of 7747 relevant lines covered (84.14%)

597.88 hits per line

Source File
Press 'n' to go to next uncovered line, 'b' for previous

25.0
/payjoin-cli/src/app/v2/ohttp.rs
1
use std::sync::{Arc, Mutex};
2

3
use anyhow::{anyhow, Result};
4

5
use super::Config;
6

7
#[derive(Debug, Clone)]
8
pub struct RelayManager {
9
    selected_relay: Option<payjoin::Url>,
10
    failed_relays: Vec<payjoin::Url>,
11
}
12

13
impl RelayManager {
14
    pub fn new() -> Self { RelayManager { selected_relay: None, failed_relays: Vec::new() } }
4✔
15

UNCOV
16
    pub fn set_selected_relay(&mut self, relay: payjoin::Url) { self.selected_relay = Some(relay); }
×
17

18
    pub fn get_selected_relay(&self) -> Option<payjoin::Url> { self.selected_relay.clone() }
6✔
19

UNCOV
20
    pub fn add_failed_relay(&mut self, relay: payjoin::Url) { self.failed_relays.push(relay); }
×
21

UNCOV
22
    pub fn get_failed_relays(&self) -> Vec<payjoin::Url> { self.failed_relays.clone() }
×
23
}
24

25
pub(crate) async fn unwrap_ohttp_keys_or_else_fetch(
1✔
26
    config: &Config,
1✔
27
    relay_manager: Arc<Mutex<RelayManager>>,
1✔
28
) -> Result<payjoin::OhttpKeys> {
1✔
29
    if let Some(keys) = config.v2()?.ohttp_keys.clone() {
1✔
30
        println!("Using OHTTP Keys from config");
1✔
31
        Ok(keys)
1✔
32
    } else {
33
        println!("Bootstrapping private network transport over Oblivious HTTP");
×
34

×
NEW
35
        fetch_keys(config, relay_manager.clone())
×
36
            .await
×
37
            .and_then(|keys| keys.ok_or_else(|| anyhow::anyhow!("No OHTTP keys found")))
×
38
    }
39
}
1✔
40

UNCOV
41
async fn fetch_keys(
×
UNCOV
42
    config: &Config,
×
NEW
43
    relay_manager: Arc<Mutex<RelayManager>>,
×
UNCOV
44
) -> Result<Option<payjoin::OhttpKeys>> {
×
45
    use payjoin::bitcoin::secp256k1::rand::prelude::SliceRandom;
UNCOV
46
    let payjoin_directory = config.v2()?.pj_directory.clone();
×
UNCOV
47
    let relays = config.v2()?.ohttp_relays.clone();
×
48

UNCOV
49
    loop {
×
UNCOV
50
        let failed_relays =
×
NEW
51
            relay_manager.lock().expect("Lock should not be poisoned").get_failed_relays();
×
UNCOV
52

×
UNCOV
53
        let remaining_relays: Vec<_> =
×
UNCOV
54
            relays.iter().filter(|r| !failed_relays.contains(r)).cloned().collect();
×
UNCOV
55

×
UNCOV
56
        if remaining_relays.is_empty() {
×
UNCOV
57
            return Err(anyhow!("No valid relays available"));
×
UNCOV
58
        }
×
59

UNCOV
60
        let selected_relay =
×
UNCOV
61
            match remaining_relays.choose(&mut payjoin::bitcoin::key::rand::thread_rng()) {
×
UNCOV
62
                Some(relay) => relay.clone(),
×
UNCOV
63
                None => return Err(anyhow!("Failed to select from remaining relays")),
×
64
            };
65

NEW
66
        relay_manager
×
UNCOV
67
            .lock()
×
UNCOV
68
            .expect("Lock should not be poisoned")
×
UNCOV
69
            .set_selected_relay(selected_relay.clone());
×
70

71
        #[cfg(not(feature = "pki-https"))]
NEW
72
        let ohttp_keys = {
×
NEW
73
            let cert_der = crate::app::read_local_cert()?;
×
NEW
74
            payjoin::io::fetch_ohttp_keys_with_cert(
×
NEW
75
                selected_relay.clone(),
×
NEW
76
                payjoin_directory.clone(),
×
NEW
77
                cert_der,
×
NEW
78
            )
×
NEW
79
            .await
×
80
        };
81

82
        #[cfg(feature = "pki-https")]
83
        let ohttp_keys = {
84
            payjoin::io::fetch_ohttp_keys(selected_relay.clone(), payjoin_directory.clone()).await
85
        };
86

UNCOV
87
        match ohttp_keys {
×
UNCOV
88
            Ok(keys) => return Ok(Some(keys)),
×
UNCOV
89
            Err(payjoin::io::Error::UnexpectedStatusCode(e)) => {
×
UNCOV
90
                return Err(payjoin::io::Error::UnexpectedStatusCode(e).into());
×
91
            }
UNCOV
92
            Err(e) => {
×
UNCOV
93
                log::debug!("Failed to connect to relay: {selected_relay}, {e:?}");
×
NEW
94
                relay_manager
×
UNCOV
95
                    .lock()
×
UNCOV
96
                    .expect("Lock should not be poisoned")
×
UNCOV
97
                    .add_failed_relay(selected_relay);
×
98
            }
99
        }
100
    }
UNCOV
101
}
×
102

103
//#[cfg(feature = "pki-https")]
104
pub(crate) async fn validate_relay(
6✔
105
    config: &Config,
6✔
106
    _relay_manager: Arc<Mutex<RelayManager>>,
6✔
107
) -> Result<payjoin::Url> {
6✔
108
    #[cfg(not(feature = "pki-https"))]
109
    {
110
        let relay = config.v2()?.ohttp_relays.first().expect("no OHTTP relay set").clone();
6✔
111
        Ok(relay)
6✔
112
    }
113

114
    #[cfg(feature = "pki-https")]
115
    {
116
        use payjoin::bitcoin::secp256k1::rand::prelude::SliceRandom;
117
        let payjoin_directory = config.v2()?.pj_directory.clone();
118
        let relays = config.v2()?.ohttp_relays.clone();
119

120
        loop {
121
            let failed_relays =
122
                _relay_manager.lock().expect("Lock should not be poisoned").get_failed_relays();
123

124
            let remaining_relays: Vec<_> =
125
                relays.iter().filter(|r| !failed_relays.contains(r)).cloned().collect();
126

127
            if remaining_relays.is_empty() {
128
                return Err(anyhow!("No valid relays available"));
129
            }
130

131
            let selected_relay =
132
                match remaining_relays.choose(&mut payjoin::bitcoin::key::rand::thread_rng()) {
133
                    Some(relay) => relay.clone(),
134
                    None => return Err(anyhow!("Failed to select from remaining relays")),
135
                };
136

137
            _relay_manager
138
                .lock()
139
                .expect("Lock should not be poisoned")
140
                .set_selected_relay(selected_relay.clone());
141

142
            let ohttp_keys =
143
                payjoin::io::fetch_ohttp_keys(selected_relay.clone(), payjoin_directory.clone())
144
                    .await;
145

146
            match ohttp_keys {
147
                Ok(_) => return Ok(selected_relay),
148
                Err(payjoin::io::Error::UnexpectedStatusCode(e)) => {
149
                    return Err(payjoin::io::Error::UnexpectedStatusCode(e).into());
150
                }
151
                Err(e) => {
152
                    log::debug!("Failed to connect to relay: {selected_relay}, {e:?}");
153
                    _relay_manager
154
                        .lock()
155
                        .expect("Lock should not be poisoned")
156
                        .add_failed_relay(selected_relay);
157
                }
158
            }
159
        }
160
    }
161
}
6✔
STATUS · Troubleshooting · Open an Issue · Sales · Support · CAREERS · ENTERPRISE · START FREE · SCHEDULE DEMO
ANNOUNCEMENTS · TWITTER · TOS & SLA · Supported CI Services · What's a CI service? · Automated Testing

© 2026 Coveralls, Inc