#[cfg(feature = "paid-exit")]
#[test]
fn paid_route_admissions_seed_configured_endpoint_peers() {
use nostr_vpn_core::fips_mesh::FipsPaidRouteAdmission;
let buyer_keys = Keys::generate();
let buyer_pubkey = buyer_keys.public_key().to_hex();
let buyer_npub = buyer_keys.public_key().to_bech32().expect("buyer npub");
let endpoint_peers = super::fips_endpoint_peers_with_paid_route_admissions(
Vec::new(),
&[FipsPaidRouteAdmission {
participant_pubkey: buyer_pubkey,
session_id: "seller-session-1".to_string(),
allowed_ips: vec!["10.44.1.2/32".to_string()],
destination_allowed_ips: vec!["0.0.0.0/0".to_string()],
allow_routing: true,
state: nostr_vpn_core::paid_routes::PaidRouteAccessState::Paid,
amount_due_msat: 1_000,
paid_msat: 1_000,
unpaid_msat: 0,
expires_at_unix: 200,
updated_at_unix: 100,
}],
);
assert_eq!(endpoint_peers.len(), 1);
assert_eq!(endpoint_peers[0].npub, buyer_npub);
assert!(endpoint_peers[0].addresses.is_empty());
assert!(endpoint_peers[0].auto_reconnect);
assert!(!endpoint_peers[0].discovery_fallback_transit);
}
#[cfg(feature = "paid-exit")]
#[cfg(any(target_os = "linux", target_os = "macos"))]
#[test]
fn paid_route_admissions_install_buyer_return_routes() {
use nostr_vpn_core::config::PaidExitSellerEgress;
use nostr_vpn_core::fips_mesh::FipsPaidRouteAdmission;
let seller_keys = Keys::generate();
let seller_pubkey = seller_keys.public_key().to_hex();
let mut app = AppConfig::default();
app.nostr.secret_key = seller_keys.secret_key().to_bech32().expect("seller nsec");
app.networks[0].enabled = true;
app.networks[0].network_id = "paid-exit-seller".to_string();
let mut config = FipsPrivateTunnelConfig::from_app(
&app,
"paid-exit-seller",
"nvpn-paid",
Some(&seller_pubkey),
None,
&[],
)
.expect("seller tunnel config");
config.paid_route_admissions = vec![FipsPaidRouteAdmission {
participant_pubkey: Keys::generate().public_key().to_hex(),
session_id: "seller-session-1".to_string(),
allowed_ips: vec!["10.44.133.173/32".to_string()],
destination_allowed_ips: vec!["0.0.0.0/0".to_string()],
allow_routing: true,
state: nostr_vpn_core::paid_routes::PaidRouteAccessState::FreeProbe,
amount_due_msat: 0,
paid_msat: 0,
unpaid_msat: 0,
expires_at_unix: 200,
updated_at_unix: 100,
}];
assert!(
config
.interface_route_targets(Vec::new())
.contains(&"10.44.133.173/32".to_string())
);
assert!(super::paid_route_admissions_for_egress(&config, true)[0].allow_routing);
config.local_exit_seller_egress = Some(PaidExitSellerEgress::WireGuard);
assert!(!super::paid_route_admissions_for_egress(&config, false)[0].allow_routing);
let upstream = Keys::generate().public_key().to_hex();
config.local_exit_seller_egress = Some(PaidExitSellerEgress::PrivatePeer {
pubkey: upstream.clone(),
});
config.peers.push(
FipsMeshPeerConfig::from_participant_pubkey(
&upstream,
vec!["0.0.0.0/0".to_string()],
)
.expect("private upstream"),
);
let connected = HashSet::from([upstream.as_str()]);
assert!(!super::local_exit_seller_egress_ready(
&config, &connected, false, None
));
assert!(super::local_exit_seller_egress_ready(
&config,
&connected,
false,
Some(config.listen_port)
));
config.paid_route_admissions[0].participant_pubkey = upstream;
assert!(!super::paid_route_admissions_for_egress(&config, true)[0].allow_routing);
}
async fn bind_listener_test_runtime(port: u16) -> FipsPrivateMeshRuntime {
let keys = Keys::generate();
let endpoint_peers = Vec::new();
let transport = FipsEndpointTransportConfig {
listen_port: port,
bind_interface: None,
advertised_endpoint: format!("8.8.8.8:{port}"),
advertise_public_endpoint: true,
nostr_discovery_enabled: false,
advertise_on_nostr: false,
webrtc_enabled: false,
stun_servers: Vec::new(),
nostr_relays: Vec::new(),
websocket: Default::default(),
share_local_candidates: false,
};
let config = super::fips_endpoint_config_with_open_discovery_limit(
&endpoint_peers,
Some(&transport),
super::private_mesh_mtu_from_app(None),
NostrDiscoveryPolicy::ConfiguredOnly,
0,
);
FipsPrivateMeshRuntime::bind_with_config_scoped(
keys.secret_key().to_bech32().expect("nsec"),
None,
Vec::new(),
config,
Vec::new(),
Vec::new(),
Vec::new(),
)
.await
.expect("FIPS bind")
}
#[tokio::test]
async fn production_fips_bind_confirms_its_udp_listener() {
let port = available_udp_port();
let runtime = bind_listener_test_runtime(port).await;
assert_eq!(
runtime
.confirmed_udp_listen_port(port, None)
.await
.expect("listener snapshot"),
Some(port)
);
runtime.endpoint().shutdown().await.expect("shutdown");
}
#[tokio::test]
async fn production_fips_bind_does_not_claim_an_occupied_udp_port() {
let reservation = UdpSocket::bind("0.0.0.0:0").expect("reserve UDP port");
let port = reservation.local_addr().expect("reserved address").port();
let runtime = bind_listener_test_runtime(port).await;
assert_eq!(
runtime
.confirmed_udp_listen_port(port, Some(false))
.await
.expect("listener snapshot"),
None
);
runtime.endpoint().shutdown().await.expect("shutdown");
}
#[test]
fn seller_outbound_interface_follows_the_derived_egress() {
use nostr_vpn_core::config::PaidExitSellerEgress;
let private = PaidExitSellerEgress::PrivatePeer {
pubkey: "private-upstream".to_string(),
};
assert_eq!(
super::local_exit_outbound_interface(
Some(&PaidExitSellerEgress::Direct),
"nvpn0",
Some("wg0"),
Some("en0")
)
.as_deref(),
Some("en0")
);
assert_eq!(
super::local_exit_outbound_interface(
Some(&PaidExitSellerEgress::WireGuard),
"nvpn0",
Some("wg0"),
Some("en0")
)
.as_deref(),
Some("wg0")
);
assert_eq!(
super::local_exit_outbound_interface(
Some(&private),
"nvpn0",
Some("wg0"),
Some("en0")
)
.as_deref(),
Some("nvpn0")
);
}
#[test]
fn open_discovery_does_not_loosen_tun_roster_gate() {
let roster_peer = Keys::generate();
let stranger = Keys::generate();
let roster_pubkey = roster_peer.public_key().to_hex();
let roster_npub = roster_peer.public_key().to_bech32().expect("roster npub");
let stranger_npub = stranger.public_key().to_bech32().expect("stranger npub");
let roster_node_addr = *PeerIdentity::from_npub(&roster_npub)
.expect("roster endpoint identity")
.node_addr()
.as_bytes();
let stranger_node_addr = *PeerIdentity::from_npub(&stranger_npub)
.expect("stranger endpoint identity")
.node_addr()
.as_bytes();
let mesh_peer = FipsMeshPeerConfig::from_participant_pubkey(
&roster_pubkey,
vec!["10.44.1.2/32".to_string()],
)
.expect("roster peer config");
let endpoint_peers =
fips_endpoint_peers_from_mesh(std::slice::from_ref(&mesh_peer), Vec::new(), Vec::new());
let config = fips_endpoint_config_with_open_discovery_limit(
&endpoint_peers,
None,
super::resolve_private_mesh_mtu(None, None, None),
NostrDiscoveryPolicy::Open,
FIPS_NOSTR_OPEN_DISCOVERY_MAX_PENDING,
);
assert_eq!(
config.node.discovery.nostr.policy,
fips_endpoint::NostrDiscoveryPolicy::Open,
"open FIPS discovery must not loosen private roster traffic admission",
);
let mesh = FipsMeshRuntime::new(vec![mesh_peer.clone()]);
let mut packet = vec![0_u8; 28];
packet[0] = 0x45;
packet[2..4].copy_from_slice(&28_u16.to_be_bytes());
packet[8] = 64;
packet[9] = 17;
packet[12..16].copy_from_slice(&[10, 44, 1, 2]);
packet[16..20].copy_from_slice(&[10, 44, 1, 1]);
assert!(
mesh.receive_endpoint_data_owned_with_source_node_addr(
&roster_node_addr,
packet.clone()
)
.is_some(),
"roster peer's owned source IP must be admitted",
);
assert!(
mesh.endpoint_source_admitter(&stranger_node_addr).is_none(),
"non-roster peer must not inject packets onto the tun",
);
let mut spoofed = packet.clone();
spoofed[12..16].copy_from_slice(&[203, 0, 113, 9]);
assert!(
mesh.receive_endpoint_data_owned_with_source_node_addr(&stranger_node_addr, spoofed)
.is_none(),
"non-roster peer must not inject packets onto the tun (spoofed source)",
);
}