rings_node/onion/tcp/
config.rs1use std::collections::BTreeSet;
4
5use reqwest::Url;
6
7use crate::error::Error;
8use crate::error::Result;
9use crate::onion::OnionExitPolicy;
10use crate::onion::OnionExitService;
11use crate::onion::OnionExitTransport;
12use crate::onion::OnionServiceName;
13
14#[derive(Clone, Debug, Eq, PartialEq)]
19pub struct NativeOnionTcpExitConfig {
20 services: Vec<OnionServiceName>,
21 policy: OnionExitPolicy,
22 https_proxy: Option<String>,
23}
24
25impl NativeOnionTcpExitConfig {
26 pub fn new(
28 services: impl IntoIterator<Item = OnionExitService>,
29 policy: OnionExitPolicy,
30 ) -> Result<Self> {
31 let mut service_names = BTreeSet::new();
32 for service in services {
33 if service.transport != OnionExitTransport::Tcp {
34 return Err(Error::InvalidConfig(format!(
35 "native onion TCP exit cannot serve {:?} over {:?}",
36 service.name, service.transport
37 )));
38 }
39 service_names.insert(service.name);
40 }
41 if service_names.is_empty() {
42 return Err(Error::InvalidConfig(
43 "native onion TCP exit requires at least one TCP service".to_string(),
44 ));
45 }
46 Ok(Self {
47 services: service_names.into_iter().collect(),
48 policy,
49 https_proxy: None,
50 })
51 }
52
53 pub fn tcp(policy: OnionExitPolicy) -> Self {
55 Self {
56 services: vec![OnionServiceName::tcp()],
57 policy,
58 https_proxy: None,
59 }
60 }
61
62 pub fn with_https_proxy(mut self, proxy: impl AsRef<str>) -> Result<Self> {
67 let proxy = proxy.as_ref().trim();
68 let parsed = Url::parse(proxy).map_err(|_| {
69 Error::InvalidConfig("native onion HTTPS proxy must be an absolute URL".to_string())
70 })?;
71 if !matches!(parsed.scheme(), "http" | "https") || parsed.host_str().is_none() {
72 return Err(Error::InvalidConfig(
73 "native onion HTTPS proxy must use http or https with a host".to_string(),
74 ));
75 }
76 self.https_proxy = Some(proxy.to_string());
77 Ok(self)
78 }
79
80 pub fn allows_service(&self, service: &OnionServiceName) -> bool {
82 self.services.iter().any(|candidate| candidate == service)
83 }
84
85 pub(super) fn policy(&self) -> &OnionExitPolicy {
86 &self.policy
87 }
88
89 pub(super) fn https_proxy(&self) -> Option<&str> {
90 self.https_proxy.as_deref()
91 }
92}