diff --git a/Cargo.lock b/Cargo.lock index a437247..2b925e6 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -153,7 +153,7 @@ version = "1.0.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "5ca11d4be1bab0c8bc8734a9aa7bf4ee8316d462a08c6ac5052f888fef5b494b" dependencies = [ - "windows-sys", + "windows-sys 0.48.0", ] [[package]] @@ -163,7 +163,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "180abfa45703aebe0093f79badacc01b8fd4ea2e35118747e5811127f926e188" dependencies = [ "anstyle", - "windows-sys", + "windows-sys 0.48.0", ] [[package]] @@ -324,7 +324,7 @@ dependencies = [ "futures-lite", "rustix", "signal-hook", - "windows-sys", + "windows-sys 0.48.0", ] [[package]] @@ -1335,7 +1335,7 @@ checksum = "4bcfec3a70f97c962c307b2d2c56e358cf1d00b558d74262b5f929ee8cc7e73a" dependencies = [ "errno-dragonfly", "libc", - "windows-sys", + "windows-sys 0.48.0", ] [[package]] @@ -2131,6 +2131,19 @@ dependencies = [ "want", ] +[[package]] +name = "hyper-tls" +version = "0.5.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d6183ddfa99b85da61a140bea0efc93fdf56ceaa041b37d553518030827f9905" +dependencies = [ + "bytes", + "hyper", + "native-tls", + "tokio", + "tokio-native-tls", +] + [[package]] name = "iana-time-zone" version = "0.1.57" @@ -2251,7 +2264,7 @@ checksum = "eae7b9aee968036d54dce06cebaefd919e4472e753296daccd6d344e3e2df0c2" dependencies = [ "hermit-abi 0.3.1", "libc", - "windows-sys", + "windows-sys 0.48.0", ] [[package]] @@ -2269,7 +2282,7 @@ dependencies = [ "hermit-abi 0.3.1", "io-lifetimes", "rustix", - "windows-sys", + "windows-sys 0.48.0", ] [[package]] @@ -2580,7 +2593,7 @@ checksum = "927a765cd3fc26206e66b296465fa9d3e5ab003e651c1b3c060e7956d96b19d2" dependencies = [ "libc", "wasi 0.11.0+wasi-snapshot-preview1", - "windows-sys", + "windows-sys 0.48.0", ] [[package]] @@ -2610,6 +2623,24 @@ dependencies = [ "getrandom 0.2.10", ] +[[package]] +name = "native-tls" +version = "0.2.11" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "07226173c32f2926027b63cce4bcd8076c3552846cbe7925f3aaffeac0a3b92e" +dependencies = [ + "lazy_static", + "libc", + "log", + "openssl", + "openssl-probe", + "openssl-sys", + "schannel", + "security-framework", + "security-framework-sys", + "tempfile", +] + [[package]] name = "ndk" version = "0.6.0" @@ -2959,6 +2990,50 @@ version = "0.3.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "624a8340c38c1b80fd549087862da4ba43e08858af025b236e509b6649fc13d5" +[[package]] +name = "openssl" +version = "0.10.55" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "345df152bc43501c5eb9e4654ff05f794effb78d4efe3d53abc158baddc0703d" +dependencies = [ + "bitflags", + "cfg-if", + "foreign-types", + "libc", + "once_cell", + "openssl-macros", + "openssl-sys", +] + +[[package]] +name = "openssl-macros" +version = "0.1.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a948666b637a0f465e8564c73e89d4dde00d72d4d473cc972f390fc3dcee7d9c" +dependencies = [ + "proc-macro2", + "quote", + "syn 2.0.18", +] + +[[package]] +name = "openssl-probe" +version = "0.1.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ff011a302c396a5197692431fc1948019154afc178baf7d8e37367442a4601cf" + +[[package]] +name = "openssl-sys" +version = "0.9.90" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "374533b0e45f3a7ced10fcaeccca020e66656bc03dac384f852e4e5a7a8104a6" +dependencies = [ + "cc", + "libc", + "pkg-config", + "vcpkg", +] + [[package]] name = "ordered-float" version = "3.7.0" @@ -3044,10 +3119,12 @@ dependencies = [ "num_enum", "once_cell", "p2p-repo", + "reqwest", "serde", "serde_bare", "serde_bytes", "unique_id", + "url", "wasm-bindgen", ] @@ -3368,7 +3445,7 @@ dependencies = [ "libc", "log", "pin-project-lite", - "windows-sys", + "windows-sys 0.48.0", ] [[package]] @@ -3710,10 +3787,12 @@ dependencies = [ "http", "http-body", "hyper", + "hyper-tls", "ipnet", "js-sys", "log", "mime", + "native-tls", "once_cell", "percent-encoding", "pin-project-lite", @@ -3721,6 +3800,7 @@ dependencies = [ "serde_json", "serde_urlencoded", "tokio", + "tokio-native-tls", "tokio-util", "tower-service", "url", @@ -3808,7 +3888,7 @@ dependencies = [ "io-lifetimes", "libc", "linux-raw-sys", - "windows-sys", + "windows-sys 0.48.0", ] [[package]] @@ -3853,6 +3933,15 @@ dependencies = [ "winapi-util", ] +[[package]] +name = "schannel" +version = "0.1.21" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "713cfb06c7059f3588fb8044c0fad1d09e3c01d225e25b9220dbfdcf16dbb1b3" +dependencies = [ + "windows-sys 0.42.0", +] + [[package]] name = "scoped-tls" version = "1.0.1" @@ -3865,6 +3954,29 @@ version = "1.1.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "d29ab0c6d3fc0ee92fe66e2d99f700eab17a8d57d1c1d3b748380fb20baa78cd" +[[package]] +name = "security-framework" +version = "2.9.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1fc758eb7bffce5b308734e9b0c1468893cae9ff70ebf13e7090be8dcbcc83a8" +dependencies = [ + "bitflags", + "core-foundation", + "core-foundation-sys", + "libc", + "security-framework-sys", +] + +[[package]] +name = "security-framework-sys" +version = "2.9.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f51d0c0d83bec45f16480d0ce0058397a69e48fcdc52d1dc8855fb68acbd31a7" +dependencies = [ + "core-foundation-sys", + "libc", +] + [[package]] name = "selectors" version = "0.22.0" @@ -4605,7 +4717,7 @@ dependencies = [ "fastrand", "redox_syscall 0.3.5", "rustix", - "windows-sys", + "windows-sys 0.48.0", ] [[package]] @@ -4739,7 +4851,7 @@ dependencies = [ "signal-hook-registry", "socket2", "tokio-macros", - "windows-sys", + "windows-sys 0.48.0", ] [[package]] @@ -4753,6 +4865,16 @@ dependencies = [ "syn 2.0.18", ] +[[package]] +name = "tokio-native-tls" +version = "0.3.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "bbae76ab933c85776efabc971569dd6119c580d8f5d448769dec1764bf796ef2" +dependencies = [ + "native-tls", + "tokio", +] + [[package]] name = "tokio-stream" version = "0.1.14" @@ -5059,6 +5181,12 @@ version = "1.4.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "a4d330786735ea358f3bc09eea4caa098569c1c93f342d9aca0514915022fe7e" +[[package]] +name = "vcpkg" +version = "0.2.15" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "accd4ea62f7bb7a82fe23066fb0957d48ef677f6eeb8215f372f52e48bb32426" + [[package]] name = "version-compare" version = "0.1.1" @@ -5480,6 +5608,21 @@ version = "0.44.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "ee78911e3f4ce32c1ad9d3c7b0bd95389662ad8d8f1a3155688fed70bd96e2b6" +[[package]] +name = "windows-sys" +version = "0.42.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5a3e1820f08b8513f676f7ab6c1f99ff312fb97b553d30ff4dd86f9f15728aa7" +dependencies = [ + "windows_aarch64_gnullvm 0.42.2", + "windows_aarch64_msvc 0.42.2", + "windows_i686_gnu 0.42.2", + "windows_i686_msvc 0.42.2", + "windows_x86_64_gnu 0.42.2", + "windows_x86_64_gnullvm 0.42.2", + "windows_x86_64_msvc 0.42.2", +] + [[package]] name = "windows-sys" version = "0.48.0" diff --git a/ng-app/src/routes/WalletCreate.svelte b/ng-app/src/routes/WalletCreate.svelte index 7ca449b..f7c8990 100644 --- a/ng-app/src/routes/WalletCreate.svelte +++ b/ng-app/src/routes/WalletCreate.svelte @@ -701,12 +701,13 @@

Do you trust this device?
If you do, if this device is yours or is used by few trusted persons of your - family or workplace, then you can save your wallet in this device. To the - contrary, if this device is public and shared by strangers, do not save your - wallet here. {#if !import.meta.env.TAURI_PLATFORM}By selecting this - option, you agree to save some cookies on your browser.{/if}
+ family or workplace, and you would like to login again from this device in + the future, then you can save your wallet on this device. To the contrary, + if this device is public and shared by strangers, do not save your wallet + here. {#if !import.meta.env.TAURI_PLATFORM}By selecting this option, you + agree to save some cookies on your browser.{/if}
Save your wallet here?Save your wallet on this device?

diff --git a/ng-sdk-js/src/lib.rs b/ng-sdk-js/src/lib.rs index c6cad78..0ad84bb 100644 --- a/ng-sdk-js/src/lib.rs +++ b/ng-sdk-js/src/lib.rs @@ -234,8 +234,8 @@ pub async fn start() { let x_from_ed = keys.1.to_dh_from_ed(); log_info!("Pub from X {}", x_from_ed); - let (client_priv_key, client_pub_key) = generate_keypair(); - let (user_priv_key, user_pub_key) = generate_keypair(); + let (client_priv, client) = generate_keypair(); + let (user_priv, user) = generate_keypair(); log_info!("start connecting"); @@ -244,16 +244,15 @@ pub async fn start() { .await .connect( Box::new(ConnectionWebSocket {}), - IP::try_from(&IpAddr::from_str("127.0.0.1").unwrap()).unwrap(), - WS_PORT, - None, keys.0, keys.1, server_key, StartConfig::Client(ClientConfig { - user: user_pub_key, - client: client_pub_key, - client_priv: client_priv_key, + url: format!("ws://127.0.0.1:{}", WS_PORT), + user, + user_priv, + client, + client_priv, }), ) .await; diff --git a/p2p-broker/src/server_ws.rs b/p2p-broker/src/server_ws.rs index 8525664..57005b5 100644 --- a/p2p-broker/src/server_ws.rs +++ b/p2p-broker/src/server_ws.rs @@ -276,10 +276,6 @@ fn upgrade_ws_or_serve_app( Err(make_error(StatusCode::FORBIDDEN)) } -const LOCAL_HOSTS: [&str; 3] = ["localhost", "127.0.0.1", "[::1]"]; -const LOCAL_URLS: [&str; 3] = ["http://localhost", "http://127.0.0.1", "http://[::1]"]; -//const APP_NG_ONE_URL: &str = "https://app.nextgraph.one"; - impl Callback for SecurityCallback { fn on_request(self, request: &Request) -> Result<(), ErrorResponse> { let local_urls = LOCAL_URLS diff --git a/p2p-client-ws/src/remote_ws.rs b/p2p-client-ws/src/remote_ws.rs index aea4f34..95c8926 100644 --- a/p2p-client-ws/src/remote_ws.rs +++ b/p2p-client-ws/src/remote_ws.rs @@ -43,8 +43,7 @@ pub struct ConnectionWebSocket {} impl IConnect for ConnectionWebSocket { async fn open( &self, - ip: IP, - port: u16, + url: String, peer_privk: Sensitive<[u8; 32]>, peer_pubk: PubKey, remote_peer: DirectPeerId, @@ -52,8 +51,6 @@ impl IConnect for ConnectionWebSocket { ) -> Result { let mut cnx = ConnectionBase::new(ConnectionDir::Client, TransportProtocol::WS); - let url = format!("ws://{}:{}", ip, port); - let res = connect_async(url).await; match res { @@ -66,6 +63,7 @@ impl IConnect for ConnectionWebSocket { let s = cnx.take_sender(); let r = cnx.take_receiver(); let mut shutdown = cnx.set_shutdown(); + cnx.release_shutdown(); let join = task::spawn(async move { log_debug!("START of WS loop"); @@ -103,6 +101,7 @@ impl IConnect for ConnectionWebSocket { let s = cnx.take_sender(); let r = cnx.take_receiver(); let mut shutdown = cnx.set_shutdown(); + cnx.release_shutdown(); let join = task::spawn(async move { log_debug!("START of WS loop"); @@ -324,8 +323,8 @@ mod test { let x_from_ed = keys.1.to_dh_from_ed(); log_info!("Pub from X {}", x_from_ed); - let (client_priv_key, client_pub_key) = generate_keypair(); - let (user_priv_key, user_pub_key) = generate_keypair(); + let (client_priv, client) = generate_keypair(); + let (user_priv, user) = generate_keypair(); log_info!("start connecting"); { @@ -334,13 +333,16 @@ mod test { .await .connect( Box::new(ConnectionWebSocket {}), - IP::try_from(&IpAddr::from_str("127.0.0.1").unwrap()).unwrap(), - WS_PORT, - None, keys.0, keys.1, server_key, - StartConfig::Probe, + StartConfig::Client(ClientConfig { + url: format!("ws://localhost:{}", WS_PORT), + user, + user_priv, + client, + client_priv, + }), ) .await; log_info!("broker.connect : {:?}", res); diff --git a/p2p-client-ws/src/remote_ws_wasm.rs b/p2p-client-ws/src/remote_ws_wasm.rs index 337faa7..bdecd13 100644 --- a/p2p-client-ws/src/remote_ws_wasm.rs +++ b/p2p-client-ws/src/remote_ws_wasm.rs @@ -37,8 +37,7 @@ pub struct ConnectionWebSocket {} impl IConnect for ConnectionWebSocket { async fn open( &self, - ip: IP, - port: u16, + url: String, peer_privk: Sensitive<[u8; 32]>, peer_pubk: PubKey, remote_peer: DirectPeerId, @@ -46,8 +45,6 @@ impl IConnect for ConnectionWebSocket { ) -> Result { let mut cnx = ConnectionBase::new(ConnectionDir::Client, TransportProtocol::WS); - let url = format!("ws://{}:{}", ip, port); - let (mut ws, wsio) = WsMeta::connect(url, None).await.map_err(|e| { //log_info!("{:?}", e); NetError::ConnectionError diff --git a/p2p-net/Cargo.toml b/p2p-net/Cargo.toml index b57c1ba..e6960f4 100644 --- a/p2p-net/Cargo.toml +++ b/p2p-net/Cargo.toml @@ -25,6 +25,8 @@ noise-protocol = "0.2.0-rc1" noise-rust-crypto = "0.6.0-rc.1" ed25519-dalek = "1.0.1" either = "1.8.1" +reqwest = { version = "0.11.18", features = ["json"] } +url = "2.4.0" [target.'cfg(target_arch = "wasm32")'.dependencies.getrandom] version = "0.2.7" diff --git a/p2p-net/src/actor.rs b/p2p-net/src/actor.rs index 3df7978..aee3c37 100644 --- a/p2p-net/src/actor.rs +++ b/p2p-net/src/actor.rs @@ -121,7 +121,7 @@ impl< match receiver.next().await { Some(ConnectionCommand::Msg(msg)) => { if let ProtocolMessage::BrokerMessage(ref bm) = msg { - if bm.result() == ProtocolError::PartialContent.into() + if bm.result() == Into::::into(ProtocolError::PartialContent) && TypeId::of::() != TypeId::of::<()>() { let (mut b_sender, b_receiver) = mpsc::unbounded::(); @@ -141,7 +141,9 @@ impl< actor_receiver.next().await { if let ProtocolMessage::BrokerMessage(ref bm) = msg { - if bm.result() == ProtocolError::EndOfStream.into() { + if bm.result() + == Into::::into(ProtocolError::EndOfStream) + { break; } let response = msg.try_into(); diff --git a/p2p-net/src/broker.rs b/p2p-net/src/broker.rs index bd21132..b9be363 100644 --- a/p2p-net/src/broker.rs +++ b/p2p-net/src/broker.rs @@ -63,7 +63,7 @@ pub static BROKER: Lazy>> = Lazy::new(|| Arc::new(RwLock::new pub struct Broker { direct_connections: HashMap, - peers: HashMap, + peers: HashMap, /// (local,remote) -> ConnectionBase anonymous_connections: HashMap<(BindAddress, BindAddress), ConnectionBase>, #[cfg(not(target_arch = "wasm32"))] @@ -248,7 +248,7 @@ impl Broker { } pub fn reconnecting(&mut self, peer_id: &DirectPeerId) { - let peerinfo = self.peers.get_mut(peer_id); + let peerinfo = self.peers.get_mut(&peer_id.to_dh_slice()); match peerinfo { Some(info) => match &info.connected { PeerConnection::NONE => {} @@ -264,7 +264,7 @@ impl Broker { } } pub fn remove_peer_id(&mut self, peer_id: &DirectPeerId) { - let removed = self.peers.remove(peer_id); + let removed = self.peers.remove(&peer_id.to_dh_slice()); match removed { Some(info) => match info.connected { PeerConnection::NONE => {} @@ -285,6 +285,9 @@ impl Broker { let removed = self .anonymous_connections .remove(&(local_bind_address, remote_bind_address)); + if removed.is_some() { + removed.unwrap().release_shutdown(); + } } pub fn test(&self) -> u32 { @@ -363,7 +366,7 @@ impl Broker { anonymous = Vec::from_iter(broker.anonymous_connections.keys().cloned()); } for peer_id in peer_ids { - BROKER.write().await.close_peer_connection(&peer_id).await; + BROKER.write().await.close_peer_connection_x(&peer_id).await; } for anon in anonymous { BROKER.write().await.close_anonymous(anon.1, anon.0).await; @@ -475,7 +478,7 @@ impl Broker { lastPeerAdvert: None, connected, }; - self.peers.insert(remote_peer_id, bpi); + self.peers.insert(remote_peer_id.to_dh_slice(), bpi); Ok(()) } @@ -495,9 +498,6 @@ impl Broker { pub async fn connect( &mut self, cnx: Box, - ip: IP, - port: u16, - core: Option, // the interface used as egress for this connection peer_privk: Sensitive<[u8; 32]>, peer_pubk: PubKey, remote_peer_id: DirectPeerId, @@ -513,44 +513,46 @@ impl Broker { log_info!("CONNECTING"); let mut connection = cnx .open( - ip, - port, + config.get_url(), Sensitive::<[u8; 32]>::from_slice(peer_privk.deref()), peer_pubk, remote_peer_id, - config, + config.clone(), ) .await?; let join = connection.take_shutdown(); - let connected = if core.is_some() { - let dc = DirectConnection { - ip, - interface: core.clone().unwrap(), - remote_peer_id, - tp: connection.transport_protocol(), - cnx: connection, - }; - self.direct_connections.insert(ip, dc); - PeerConnection::Core(ip) - } else { - PeerConnection::Client(connection) + let connected = match &config { + StartConfig::Core(config) => { + let ip = config.addr.ip.clone(); + let dc = DirectConnection { + ip, + interface: config.interface.clone(), + remote_peer_id, + tp: connection.transport_protocol(), + cnx: connection, + }; + self.direct_connections.insert(ip, dc); + PeerConnection::Core(ip) + } + StartConfig::Client(config) => PeerConnection::Client(connection), + _ => unimplemented!(), }; + let bpi = BrokerPeerInfo { lastPeerAdvert: None, connected, }; - self.peers.insert(remote_peer_id, bpi); + self.peers.insert(remote_peer_id.to_dh_slice(), bpi); async fn watch_close( mut join: Receiver>, cnx: Box, - ip: IP, - core: Option, // the interface used as egress for this connection peer_privk: Sensitive<[u8; 32]>, peer_pubkey: PubKey, remote_peer_id: DirectPeerId, + config: StartConfig, ) -> ResultSend<()> { async move { let res = join.next().await; @@ -579,16 +581,15 @@ impl Broker { spawn_and_log_error(watch_close( join, cnx, - ip, - core, peer_privk, peer_pubk, remote_peer_id, + config, )); Ok(()) } - pub async fn close_peer_connection(&mut self, peer_id: &DirectPeerId) { + pub async fn close_peer_connection_x(&mut self, peer_id: &X25519PubKey) { if let Some(peer) = self.peers.get_mut(peer_id) { match &mut peer.connected { PeerConnection::Core(_) => { @@ -604,6 +605,10 @@ impl Broker { } } + pub async fn close_peer_connection(&mut self, peer_id: &DirectPeerId) { + self.close_peer_connection_x(&peer_id.to_dh_slice()).await + } + pub async fn close_anonymous( &mut self, remote_bind_address: BindAddress, diff --git a/p2p-net/src/connection.rs b/p2p-net/src/connection.rs index bb464dd..e8479e7 100644 --- a/p2p-net/src/connection.rs +++ b/p2p-net/src/connection.rs @@ -52,8 +52,7 @@ pub enum ConnectionCommand { pub trait IConnect: Send + Sync { async fn open( &self, - ip: IP, - port: u16, + url: String, peer_privk: Sensitive<[u8; 32]>, peer_pubk: PubKey, remote_peer: DirectPeerId, @@ -144,18 +143,28 @@ pub enum StepReply { CloseNow, } +#[derive(PartialEq, Debug, Clone)] pub struct ClientConfig { + pub url: String, pub user: PubKey, + pub user_priv: PrivKey, pub client: PubKey, pub client_priv: PrivKey, } +#[derive(PartialEq, Debug, Clone)] pub struct ExtConfig {} -pub struct CoreConfig {} +#[derive(PartialEq, Debug, Clone)] +pub struct CoreConfig { + pub addr: BindAddress, + pub interface: String, +} +#[derive(PartialEq, Debug, Clone)] pub struct AdminConfig {} +#[derive(PartialEq, Debug, Clone)] pub enum StartConfig { Probe, Relay(BindAddress), @@ -165,6 +174,16 @@ pub enum StartConfig { Admin(AdminConfig), } +impl StartConfig { + pub fn get_url(&self) -> String { + match self { + Self::Client(config) => config.url.clone(), + Self::Core(config) => format!("ws://{}:{}", config.addr.ip, config.addr.port), + _ => unimplemented!(), + } + } +} + impl NoiseFSM { pub fn new( bind_addresses: Option<(BindAddress, BindAddress)>, @@ -703,10 +722,11 @@ impl ConnectionBase { } } - pub async fn release_shutdown(&mut self) { + pub fn release_shutdown(&mut self) { self.shutdown_sender = None; } + // only used by accept pub async fn reset_shutdown(&mut self, remote_peer_id: PubKey) { let _ = self .shutdown_sender diff --git a/p2p-net/src/types.rs b/p2p-net/src/types.rs index 635fa96..99013eb 100644 --- a/p2p-net/src/types.rs +++ b/p2p-net/src/types.rs @@ -88,6 +88,16 @@ pub struct BindAddress { pub ip: IP, } +impl BindAddress { + pub fn to_ws_url(&self) -> String { + format!( + "ws://{}:{}", + self.ip, + if self.port == 0 { 80 } else { self.port } + ) + } +} + impl From<&SocketAddr> for BindAddress { #[inline] fn from(addr: &SocketAddr) -> BindAddress { @@ -118,6 +128,162 @@ pub struct BrokerServerV0 { pub peer_id: PubKey, } +pub const APP_NG_ONE_URL: &str = "https://app.nextgraph.one"; + +pub const APP_NG_ONE_WS_URL: &str = "wss://app.nextgraph.one"; + +fn api_dyn_peer_url(peer_id: &PubKey) -> String { + format!("https://nextgraph.one/api/v1/dynpeer/{}", peer_id) +} + +pub const LOCAL_HOSTS: [&str; 3] = ["localhost", "127.0.0.1", "[::1]"]; + +fn local_ws_url(port: &u16) -> String { + format!("ws://localhost:{}", if *port == 0 { 80 } else { *port }) +} + +pub const LOCAL_URLS: [&str; 3] = ["http://localhost", "http://127.0.0.1", "http://[::1]"]; +use url::{Host, Url}; + +impl BrokerServerTypeV0 { + pub fn find_first_ipv4(&self) -> Option<&BindAddress> { + match self { + Self::BoxPrivate(addrs) => { + for addr in addrs { + if addr.ip.is_v4() { + return Some(addr); + } + } + return None; + } + _ => None, + } + } + pub fn find_first_ipv6(&self) -> Option<&BindAddress> { + match self { + Self::BoxPrivate(addrs) => { + for addr in addrs { + if addr.ip.is_v6() { + return Some(addr); + } + } + return None; + } + _ => None, + } + } +} +impl BrokerServerV0 { + fn first_ipv4(&self) -> Option<(String, Vec)> { + self.server_type.find_first_ipv4().map_or(None, |bindaddr| { + Some((format!("ws://{}:{}", bindaddr.ip, bindaddr.port), vec![])) + }) + } + + fn first_ipv6(&self) -> Option<(String, Vec)> { + self.server_type.find_first_ipv6().map_or(None, |bindaddr| { + Some((format!("ws://{}:{}", bindaddr.ip, bindaddr.port), vec![])) + }) + } + + /// on web browser, returns the connection URL and an optional list of BindAddress if a relay is needed + /// filtered by the current location url of the webpage + /// on native apps, returns or the connection URL without optional BindAddress or an empty string with + /// several BindAddresses to try to connect to with .to_ws_url() + pub async fn get_url(&self, location: Option) -> Option<(String, Vec)> { + if location.is_some() { + let location = location.unwrap(); + if location.starts_with(APP_NG_ONE_URL) { + match &self.server_type { + BrokerServerTypeV0::BoxPublic(addrs) => { + Some((APP_NG_ONE_WS_URL.to_string(), addrs.clone())) + } + BrokerServerTypeV0::BoxPublicDyn(addrs) => { + let resp = reqwest::get(api_dyn_peer_url(&self.peer_id)).await; + if resp.is_ok() { + let resp = resp.unwrap().json::>().await; + if resp.is_ok() { + return Some((APP_NG_ONE_WS_URL.to_string(), resp.unwrap())); + } + } + if addrs.len() > 0 { + Some((APP_NG_ONE_WS_URL.to_string(), addrs.clone())) + } else { + None + } + } + _ => None, + } + } else if let BrokerServerTypeV0::Domain(domain) = &self.server_type { + let url = format!("https://{}", domain); + if location.starts_with(&url) { + let wss_url = format!("wss://{}", domain); + Some((wss_url, vec![])) + } else { + None + } + } else { + // localhost + if location.starts_with(LOCAL_URLS[0]) + || location.starts_with(LOCAL_URLS[1]) + || location.starts_with(LOCAL_URLS[2]) + { + if let BrokerServerTypeV0::Localhost(port) = self.server_type { + Some((local_ws_url(&port), vec![])) + } else { + None + } + } + // a private address + else if location.starts_with("http://") { + let url = Url::parse(&location).unwrap(); + match url.host() { + Some(Host::Ipv4(ip)) => { + if is_ipv4_private(&ip) { + self.first_ipv4() + } else { + None + } + } + Some(Host::Ipv6(ip)) => { + if is_ipv6_private(&ip) { + self.first_ipv6() + } else { + None + } + } + _ => None, + } + } else { + None + } + } + } else { + // From native / tauri app + match &self.server_type { + BrokerServerTypeV0::Localhost(port) => Some((local_ws_url(port), vec![])), + BrokerServerTypeV0::BoxPrivate(addrs) => Some((String::new(), addrs.clone())), + BrokerServerTypeV0::BoxPublic(addrs) => Some((String::new(), addrs.clone())), + BrokerServerTypeV0::BoxPublicDyn(addrs) => { + let resp = reqwest::get(api_dyn_peer_url(&self.peer_id)).await; + if resp.is_ok() { + let resp = resp.unwrap().json::>().await; + if resp.is_ok() { + return Some((String::new(), resp.unwrap())); + } + } + if addrs.len() > 0 { + Some((String::new(), addrs.clone())) + } else { + None + } + } + BrokerServerTypeV0::Domain(domain) => Some((format!("wss://{}", domain), vec![])), + } + } + } +} + /// Bootstrap content Version 0 #[derive(Clone, Debug, Serialize, Deserialize)] pub struct BootstrapContentV0 { @@ -358,9 +524,11 @@ impl ListenerV0 { } } AcceptForwardForV0::PublicDomain(_) | AcceptForwardForV0::PublicDomainPeer(_) => { - res.push(BrokerServerTypeV0::Domain( - self.accept_forward_for.get_domain().to_string(), - )); + if !self.refuse_clients { + res.push(BrokerServerTypeV0::Domain( + self.accept_forward_for.get_domain().to_string(), + )); + } if self.accept_direct { if self.if_type == InterfaceType::Private { res.push(BrokerServerTypeV0::BoxPrivate(addrs)); @@ -500,6 +668,20 @@ impl IP { let t: &IpAddr = &self.into(); t.is_loopback() } + pub fn is_v6(&self) -> bool { + if let Self::IPv6(_) = self { + true + } else { + false + } + } + pub fn is_v4(&self) -> bool { + if let Self::IPv4(_) = self { + true + } else { + false + } + } } impl fmt::Display for IP { diff --git a/p2p-repo/src/types.rs b/p2p-repo/src/types.rs index dd648cc..26ea068 100644 --- a/p2p-repo/src/types.rs +++ b/p2p-repo/src/types.rs @@ -14,7 +14,9 @@ //! Corresponds to the BARE schema use crate::errors::NgError; -use crate::utils::{decode_key, dh_pubkey_from_ed_slice, ed_privkey_to_pubkey}; +use crate::utils::{ + decode_key, dh_pubkey_from_ed_slice, dh_slice_from_ed_slice, ed_privkey_to_pubkey, +}; use core::fmt; use serde::{Deserialize, Serialize}; use serde_bare::to_vec; @@ -92,6 +94,9 @@ impl PubKey { pub fn dh_from_ed_slice(slice: &[u8]) -> PubKey { dh_pubkey_from_ed_slice(slice) } + pub fn to_dh_slice(&self) -> [u8; 32] { + dh_slice_from_ed_slice(self.slice()) + } } impl fmt::Display for PubKey { diff --git a/p2p-repo/src/utils.rs b/p2p-repo/src/utils.rs index da6b56f..6b21f40 100644 --- a/p2p-repo/src/utils.rs +++ b/p2p-repo/src/utils.rs @@ -60,12 +60,16 @@ pub fn generate_null_keypair() -> (PrivKey, PubKey) { } pub fn dh_pubkey_from_ed_slice(public: &[u8]) -> PubKey { + PubKey::X25519PubKey(dh_slice_from_ed_slice(public)) +} + +pub fn dh_slice_from_ed_slice(public: &[u8]) -> X25519PubKey { let mut bits: [u8; 32] = [0u8; 32]; bits.copy_from_slice(public); let compressed = CompressedEdwardsY(bits); let ed_point: EdwardsPoint = compressed.decompress().unwrap(); let mon_point = ed_point.to_montgomery(); - PubKey::X25519PubKey(mon_point.to_bytes()) + mon_point.to_bytes() } pub fn sign(