From 3fcfaa6bfd145dfa45bf47abdcd58939d31a41e0 Mon Sep 17 00:00:00 2001 From: Thomas Eizinger Date: Thu, 5 Oct 2023 15:15:51 +1100 Subject: [PATCH] refactor(connlib): create `login_url` utility (#2237) --- rust/Cargo.lock | 4 --- rust/connlib/clients/shared/Cargo.toml | 2 -- rust/connlib/clients/shared/src/lib.rs | 14 ++------ rust/connlib/gateway-shared/Cargo.toml | 2 -- rust/connlib/gateway-shared/src/lib.rs | 15 ++------- rust/connlib/shared/src/lib.rs | 45 ++++++++++++++++++++++++-- 6 files changed, 48 insertions(+), 34 deletions(-) diff --git a/rust/Cargo.lock b/rust/Cargo.lock index 557343480..8a131f570 100644 --- a/rust/Cargo.lock +++ b/rust/Cargo.lock @@ -794,11 +794,9 @@ version = "1.20231001.0" dependencies = [ "async-trait", "backoff", - "boringtun", "chrono", "connlib-shared", "firezone-tunnel", - "rand", "reqwest", "secrecy", "serde", @@ -822,11 +820,9 @@ version = "1.20231001.0" dependencies = [ "async-trait", "backoff", - "boringtun", "chrono", "connlib-shared", "firezone-tunnel", - "rand", "secrecy", "serde", "serde_json", diff --git a/rust/connlib/clients/shared/Cargo.toml b/rust/connlib/clients/shared/Cargo.toml index a42ac2688..064c77877 100644 --- a/rust/connlib/clients/shared/Cargo.toml +++ b/rust/connlib/clients/shared/Cargo.toml @@ -19,13 +19,11 @@ async-trait = { version = "0.1", default-features = false } connlib-shared = { workspace = true } firezone-tunnel = { workspace = true } serde = { version = "1.0", default-features = false, features = ["std", "derive"] } -boringtun = { workspace = true } backoff = { workspace = true } webrtc = "0.8" url = { version = "2.4.1", features = ["serde"] } time = { version = "0.3.29", features = ["formatting"] } reqwest = { version = "0.11.20", default-features = false, features = ["stream", "rustls-tls"] } -rand = { version = "0.8", default-features = false, features = ["std"] } tokio-tungstenite = { version = "0.20", default-features = false, features = ["connect", "handshake", "rustls-tls-webpki-roots"] } [target.'cfg(target_os = "android")'.dependencies] diff --git a/rust/connlib/clients/shared/src/lib.rs b/rust/connlib/clients/shared/src/lib.rs index 6f65d0236..99fb4913f 100644 --- a/rust/connlib/clients/shared/src/lib.rs +++ b/rust/connlib/clients/shared/src/lib.rs @@ -5,17 +5,13 @@ pub use tracing_appender::non_blocking::WorkerGuard; use crate::control::ControlSignaler; use backoff::{backoff::Backoff, ExponentialBackoffBuilder}; -use boringtun::x25519::{PublicKey, StaticSecret}; use connlib_shared::control::SecureUrl; -use connlib_shared::{ - control::PhoenixChannel, get_websocket_path, messages::Key, sha256, CallbackErrorFacade, Result, -}; +use connlib_shared::{control::PhoenixChannel, login_url, CallbackErrorFacade, Mode, Result}; use control::ControlPlane; use firezone_tunnel::Tunnel; use messages::IngressMessages; use messages::Messages; use messages::ReplyMessages; -use rand::{distributions::Alphanumeric, thread_rng, Rng}; use secrecy::{Secret, SecretString}; use std::sync::Arc; use std::time::Duration; @@ -128,12 +124,8 @@ where callbacks: CallbackErrorFacade, ) { runtime.spawn(async move { - let private_key = StaticSecret::random_from_rng(rand::rngs::OsRng); - let name_suffix: String = thread_rng().sample_iter(&Alphanumeric).take(8).map(char::from).collect(); - let external_id = sha256(device_id); - - let connect_url = fatal_error!( - get_websocket_path(portal_url, token, "client", &Key(PublicKey::from(&private_key).to_bytes()), &external_id, &name_suffix), + let (connect_url, private_key) = fatal_error!( + login_url(Mode::Client, portal_url, token, device_id), runtime_stopper, &callbacks ); diff --git a/rust/connlib/gateway-shared/Cargo.toml b/rust/connlib/gateway-shared/Cargo.toml index ff1eec0b8..036fd5efc 100644 --- a/rust/connlib/gateway-shared/Cargo.toml +++ b/rust/connlib/gateway-shared/Cargo.toml @@ -12,12 +12,10 @@ firezone-tunnel = { workspace = true } tokio = { version = "1.32", default-features = false, features = ["sync"] } tracing = { workspace = true } serde = { version = "1.0", default-features = false, features = ["std", "derive"] } -boringtun = { workspace = true } chrono = { workspace = true } backoff = { workspace = true } webrtc = "0.8" url = { version = "2.4.1", default-features = false } -rand = { version = "0.8", default-features = false, features = ["std"] } tokio-tungstenite = { version = "0.20", default-features = false, features = ["connect", "handshake", "rustls-tls-webpki-roots"] } [dev-dependencies] diff --git a/rust/connlib/gateway-shared/src/lib.rs b/rust/connlib/gateway-shared/src/lib.rs index 59be0ac86..017a16d87 100644 --- a/rust/connlib/gateway-shared/src/lib.rs +++ b/rust/connlib/gateway-shared/src/lib.rs @@ -3,15 +3,11 @@ pub use connlib_shared::{get_device_id, messages::ResourceDescription, Callbacks use crate::control::ControlSignaler; use backoff::{backoff::Backoff, ExponentialBackoffBuilder}; -use boringtun::x25519::{PublicKey, StaticSecret}; use connlib_shared::control::SecureUrl; -use connlib_shared::{ - control::PhoenixChannel, get_websocket_path, messages::Key, sha256, CallbackErrorFacade, Result, -}; +use connlib_shared::{control::PhoenixChannel, login_url, CallbackErrorFacade, Mode, Result}; use control::ControlPlane; use firezone_tunnel::Tunnel; use messages::IngressMessages; -use rand::{distributions::Alphanumeric, thread_rng, Rng}; use secrecy::{Secret, SecretString}; use std::sync::Arc; use std::time::Duration; @@ -122,17 +118,12 @@ where callbacks: CallbackErrorFacade, ) { runtime.spawn(async move { - let private_key = StaticSecret::random_from_rng(rand::rngs::OsRng); - let name_suffix: String = thread_rng().sample_iter(&Alphanumeric).take(8).map(char::from).collect(); - let external_id = sha256(device_id); - - let connect_url = fatal_error!( - get_websocket_path(portal_url, token, "gateway", &Key(PublicKey::from(&private_key).to_bytes()), &external_id, &name_suffix), + let (connect_url, private_key) = fatal_error!( + login_url(Mode::Gateway, portal_url, token, device_id), runtime_stopper, &callbacks ); - // This is kinda hacky, the buffer size is 1 so that we make sure that we // process one message at a time, blocking if a previous message haven't been processed // to force queue ordering. diff --git a/rust/connlib/shared/src/lib.rs b/rust/connlib/shared/src/lib.rs index bd62b00a1..996017329 100644 --- a/rust/connlib/shared/src/lib.rs +++ b/rust/connlib/shared/src/lib.rs @@ -14,7 +14,10 @@ pub use callbacks_error_facade::CallbackErrorFacade; pub use error::ConnlibError as Error; pub use error::Result; +use boringtun::x25519::{PublicKey, StaticSecret}; use messages::Key; +use rand::distributions::Alphanumeric; +use rand::{thread_rng, Rng}; use ring::digest::{Context, SHA256}; use secrecy::{ExposeSecret, SecretString}; use std::net::Ipv4Addr; @@ -25,6 +28,42 @@ pub const DNS_SENTINEL: Ipv4Addr = Ipv4Addr::new(100, 100, 111, 1); const VERSION: &str = env!("CARGO_PKG_VERSION"); const LIB_NAME: &str = "connlib"; +/// Creates a new login URL to use with the portal. +pub fn login_url( + mode: Mode, + portal_url: Url, + portal_token: SecretString, + device_id: String, +) -> Result<(Url, StaticSecret)> { + let private_key = StaticSecret::random_from_rng(rand::rngs::OsRng); + let name_suffix: String = thread_rng() + .sample_iter(&Alphanumeric) + .take(8) + .map(char::from) + .collect(); + let external_id = sha256(device_id); + + let url = get_websocket_path( + portal_url, + portal_token, + match mode { + Mode::Client => "client", + Mode::Gateway => "gateway", + }, + &Key(PublicKey::from(&private_key).to_bytes()), + &external_id, + &name_suffix, + )?; + + Ok((url, private_key)) +} + +// FIXME: This is a terrible name :( +pub enum Mode { + Client, + Gateway, +} + pub fn get_user_agent() -> String { let info = os_info::get(); let os_type = info.os_type(); @@ -64,7 +103,7 @@ pub fn get_device_id() -> String { uuid::Uuid::new_v4().to_string() } -pub fn set_ws_scheme(url: &mut Url) -> Result<()> { +fn set_ws_scheme(url: &mut Url) -> Result<()> { let scheme = match url.scheme() { "http" | "ws" => "ws", "https" | "wss" => "wss", @@ -75,7 +114,7 @@ pub fn set_ws_scheme(url: &mut Url) -> Result<()> { Ok(()) } -pub fn sha256(input: String) -> String { +fn sha256(input: String) -> String { let mut ctx = Context::new(&SHA256); ctx.update(input.as_bytes()); let digest = ctx.finish(); @@ -87,7 +126,7 @@ pub fn sha256(input: String) -> String { .collect() } -pub fn get_websocket_path( +fn get_websocket_path( mut url: Url, secret: SecretString, mode: &str,