1use crate::identity::Role;
2pub use geohash::Coord;
3use geohash::GeohashError;
4pub use libp2p::identity::{Keypair, PublicKey};
5use libp2p::multiaddr::Protocol;
6pub use libp2p::Multiaddr;
7use libp2p::PeerId;
8use std::sync::Arc;
9use std::{collections::HashSet, io::Error, net::Ipv4Addr};
10
11pub mod serializable;
12use crate::net::ProtectSocketFn;
13use serializable::SerializableConfig;
14
15#[derive(Debug, Clone)]
16pub struct AddrInfo {
17 pub peer_id: PeerId,
18 pub multiaddrs: Vec<Multiaddr>,
19}
20
21#[derive(Debug, Default, Clone)]
22pub struct Hop {
23 pub addr_info: Vec<AddrInfo>,
24 pub policy: String,
25 pub user: String,
26}
27
28#[derive(Debug, Clone)]
29pub struct RouteDescriptor {
30 pub id: String,
31 pub name: String,
32 pub path: Vec<Hop>,
33 pub ttl: i32,
34 pub reference: Option<u32>,
35}
36
37#[derive(Debug, Clone)]
38pub struct Config {
39 pub privacy_level: isize,
48
49 pub location: Option<String>,
51
52 pub roles: HashSet<Role>,
54
55 pub entry_peers: Vec<Multiaddr>,
57
58 pub keypair: Keypair,
60
61 pub listen_on: Vec<Multiaddr>,
63
64 pub namespace: String,
66
67 pub discovery_ttl: Option<u64>,
69
70 pub static_exits: Vec<Multiaddr>,
73
74 pub static_routes: Vec<RouteDescriptor>,
76
77 pub sserver_listen_addr: String,
79
80 pub sclient_listen_addr: String,
82
83 pub fdlimit: bool,
85
86 pub external_addrs: Vec<Multiaddr>,
88
89 pub outbound_addrs: Vec<Multiaddr>,
91
92 pub is_fly_io: bool,
94
95 pub protect_socket_fn: Option<ProtectSocketFn>,
97
98 pub token: Option<String>,
100
101 pub device_id: Option<String>,
103
104 pub route_auth_enabled: bool,
107}
108
109impl Default for Config {
110 fn default() -> Self {
111 let address_tcp = Multiaddr::from(Ipv4Addr::UNSPECIFIED).with(Protocol::Tcp(0));
112
113 let address_quic = Multiaddr::from(Ipv4Addr::UNSPECIFIED)
114 .with(Protocol::Udp(0))
115 .with(Protocol::QuicV1);
116
117 let address_webrtc = Multiaddr::from(Ipv4Addr::UNSPECIFIED)
118 .with(Protocol::Udp(0))
119 .with(Protocol::WebRTCDirect);
120
121 Config {
122 privacy_level: 0,
123 location: None,
124 roles: HashSet::new(),
125 keypair: Keypair::generate_ed25519(),
126 entry_peers: Vec::new(),
127 listen_on: vec![address_tcp, address_quic, address_webrtc],
128 namespace: "snowstorm".to_string(),
129 discovery_ttl: Some(60 * 60 * 12),
130 static_exits: Vec::new(),
131 static_routes: Vec::new(),
132 sserver_listen_addr: if cfg!(any(target_os = "macos", target_os = "ios")) { "127.0.0.1:0".to_string() } else { "0.0.0.0:0".to_string() } ,
134 sclient_listen_addr: "127.0.0.1:0".to_string(),
135 fdlimit: true,
136 external_addrs: Vec::new(),
137 outbound_addrs: Vec::new(),
138 is_fly_io: false,
139 protect_socket_fn: None,
140 token: None,
141 device_id: None,
142 route_auth_enabled: false,
143 }
144 }
145}
146
147impl Config {
148 fn apply_privacy_level(&mut self) {
149 if self.privacy_level <= 0 {
150 self.location = None;
151 self.privacy_level = 0;
152 return;
153 }
154
155 if let Some(location) = &self.location {
156 self.location = Some(location[..self.privacy_level as usize].to_string());
157 }
158 }
159
160 pub fn has_entry(&self, id: &PeerId) -> bool {
161 self.entry_peers.iter().any(|multiaddr| {
162 multiaddr
163 .iter()
164 .any(|proto| matches!(proto, Protocol::P2p(peer_id) if peer_id == *id))
165 })
166 }
167
168 pub fn has_static_exit(&self, id: &PeerId) -> bool {
169 let has_exit = self.static_exits.iter().any(|multiaddr| {
170 multiaddr
171 .iter()
172 .any(|proto| matches!(proto, Protocol::P2p(peer_id) if peer_id == *id))
173 });
174
175 if has_exit {
176 return true;
177 }
178
179 let has_route = self.static_routes.iter().any(|route| {
180 route.path.iter().any(|hop| {
181 hop.addr_info
182 .iter()
183 .any(|addr_info| addr_info.peer_id == *id)
184 })
185 });
186
187 return has_route;
188 }
189
190 pub fn with_role(&mut self, role: Role) {
191 self.roles.insert(role);
193 }
194
195 pub fn with_privacy_level(mut self, privacy_level: isize) -> Result<Self, Error> {
196 if privacy_level > 12 {
197 return Err(Error::new(
198 std::io::ErrorKind::InvalidInput,
199 "Privacy level must be between 0 and 12",
200 ));
201 }
202
203 self.privacy_level = privacy_level;
204 self.apply_privacy_level();
205
206 Ok(self)
207 }
208
209 pub fn with_location(mut self, location: String) -> Self {
210 self.location = Some(location);
211 self.apply_privacy_level();
212 self
213 }
214
215 pub fn with_coordinates(mut self, coord: geohash::Coord) -> Result<Self, GeohashError> {
216 self.location = Some(geohash::encode(coord, self.privacy_level as usize)?);
217 Ok(self)
218 }
219
220 pub fn with_first_hops(mut self, first_hops: Vec<Multiaddr>) -> Self {
221 self.entry_peers = first_hops;
222 self
223 }
224
225 pub fn with_first_hop(mut self, first_hop: Multiaddr) -> Self {
226 self.entry_peers.push(first_hop);
227 self
228 }
229
230 pub fn with_roles(mut self, roles: HashSet<Role>) -> Self {
231 for role in roles {
232 self.with_role(role);
233 }
234
235 self
236 }
237
238 pub fn with_keypair(mut self, keypair: Keypair) -> Self {
239 self.keypair = keypair;
240 self
241 }
242
243 pub fn with_sserver_listen_addr(mut self, listen_addr: String) -> Self {
244 self.sserver_listen_addr = listen_addr;
245 self
246 }
247
248 pub fn with_sclient_listen_addr(mut self, listen_addr: String) -> Self {
249 self.sclient_listen_addr = listen_addr;
250 self
251 }
252
253 pub fn with_external_addrs(mut self, external_addrs: Vec<Multiaddr>) -> Self {
254 self.external_addrs = external_addrs;
255 self
256 }
257
258 pub fn with_outbound_addrs(mut self, outbound_addrs: Vec<Multiaddr>) -> Self {
259 self.outbound_addrs = outbound_addrs;
260 if self.outbound_addrs.len() == 0 {
261 return self;
262 }
263
264 let mut ln_addrs: Vec<Multiaddr> = Vec::new();
269 for out_addr in &self.outbound_addrs {
270 let is_ip4 = matches!(out_addr.iter().next(), Some(Protocol::Ip4(_)));
271
272 let tcp_addr = out_addr.clone().with(Protocol::Tcp(0));
273 let quic_addr = out_addr
274 .clone()
275 .with(Protocol::Udp(0))
276 .with(Protocol::QuicV1);
277 let webrtc_addr = out_addr
278 .clone()
279 .with(Protocol::Udp(0))
280 .with(Protocol::WebRTCDirect);
281 ln_addrs.push(tcp_addr);
282 ln_addrs.push(quic_addr);
283 if is_ip4 {
284 ln_addrs.push(webrtc_addr);
287 }
288 }
289
290 self.listen_on = ln_addrs;
291 self
292 }
293
294 pub fn with_fly_io(mut self, is_fly_io: bool) -> Self {
295 self.is_fly_io = is_fly_io;
296 self
297 }
298
299 pub fn with_protect_socket_fn(
300 mut self,
301 protect_socket_fn: Arc<dyn Fn(i32) -> () + Send + Sync>,
302 ) -> Self {
303 self.protect_socket_fn = Some(ProtectSocketFn(protect_socket_fn));
304 self
305 }
306
307 pub fn with_token(mut self, token: String) -> Self {
308 self.token = Some(token);
309 self
310 }
311
312 pub fn with_route_auth_enabled(mut self, route_auth_enabled: bool) -> Self {
313 self.route_auth_enabled = route_auth_enabled;
314 self
315 }
316
317 pub fn seal(self) -> Result<Vec<u8>, Error> {
318 let config = SerializableConfig::from(self);
319 let data =
320 serde_cbor::to_vec(&config).map_err(|e| Error::new(std::io::ErrorKind::Other, e))?;
321
322 Ok(data)
325 }
326
327 pub fn unseal(data: Vec<u8>) -> Result<Self, Error> {
328 let sc: SerializableConfig =
331 serde_cbor::from_slice(&data).map_err(|e| Error::new(std::io::ErrorKind::Other, e))?;
332
333 Ok(Config::from(sc))
334 }
335}