deploy 2.0.0-dev-8

This commit is contained in:
mbecker20
2025-09-27 14:22:48 -07:00
parent 37ca4ca986
commit 8d2d180398
26 changed files with 312 additions and 238 deletions
Generated
+81 -18
View File
@@ -296,9 +296,9 @@ dependencies = [
[[package]]
name = "aws-sdk-ec2"
version = "1.169.0"
version = "1.170.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "59150a709c121fb7caffe6c4303d7c5f4d802a35d320f7df1a86abcb7a5e4d66"
checksum = "1c2d25783bbe5577c6b67cb019e3890174fedc4ee436bbb7cc0256ccbeebfd63"
dependencies = [
"aws-credential-types",
"aws-runtime",
@@ -341,9 +341,9 @@ dependencies = [
[[package]]
name = "aws-sdk-ssooidc"
version = "1.85.0"
version = "1.86.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "67e05f33b6c9026fecfe9b3b6740f34d41bc6ff641a6a32dabaab60209245b75"
checksum = "9d1cc7fb324aa12eb4404210e6381195c5b5e9d52c2682384f295f38716dd3c7"
dependencies = [
"aws-credential-types",
"aws-runtime",
@@ -948,6 +948,7 @@ name = "cache"
<<<<<<< HEAD
<<<<<<< HEAD
<<<<<<< HEAD
<<<<<<< HEAD
version = "1.19.5"
=======
version = "2.0.0-dev-0"
@@ -973,6 +974,9 @@ version = "2.0.0-dev-6"
=======
version = "2.0.0-dev-7"
>>>>>>> fc28dbeb (deploy 2.0.0-dev-7)
=======
version = "2.0.0-dev-8"
>>>>>>> 0779afdc (deploy 2.0.0-dev-8)
dependencies = [
"anyhow",
"tokio",
@@ -1172,6 +1176,7 @@ name = "command"
<<<<<<< HEAD
<<<<<<< HEAD
<<<<<<< HEAD
<<<<<<< HEAD
version = "1.19.5"
=======
version = "2.0.0-dev-0"
@@ -1197,6 +1202,9 @@ version = "2.0.0-dev-6"
=======
version = "2.0.0-dev-7"
>>>>>>> fc28dbeb (deploy 2.0.0-dev-7)
=======
version = "2.0.0-dev-8"
>>>>>>> 0779afdc (deploy 2.0.0-dev-8)
dependencies = [
"komodo_client",
"run_command",
@@ -1230,6 +1238,7 @@ name = "config"
<<<<<<< HEAD
<<<<<<< HEAD
<<<<<<< HEAD
<<<<<<< HEAD
version = "1.19.5"
=======
version = "2.0.0-dev-0"
@@ -1255,6 +1264,9 @@ version = "2.0.0-dev-6"
=======
version = "2.0.0-dev-7"
>>>>>>> fc28dbeb (deploy 2.0.0-dev-7)
=======
version = "2.0.0-dev-8"
>>>>>>> 0779afdc (deploy 2.0.0-dev-8)
dependencies = [
"colored",
"indexmap 2.11.4",
@@ -1547,6 +1559,7 @@ name = "database"
<<<<<<< HEAD
<<<<<<< HEAD
<<<<<<< HEAD
<<<<<<< HEAD
version = "1.19.5"
=======
version = "2.0.0-dev-0"
@@ -1572,6 +1585,9 @@ version = "2.0.0-dev-6"
=======
version = "2.0.0-dev-7"
>>>>>>> fc28dbeb (deploy 2.0.0-dev-7)
=======
version = "2.0.0-dev-8"
>>>>>>> 0779afdc (deploy 2.0.0-dev-8)
dependencies = [
"anyhow",
"async-compression",
@@ -1887,6 +1903,7 @@ name = "environment"
<<<<<<< HEAD
<<<<<<< HEAD
<<<<<<< HEAD
<<<<<<< HEAD
version = "1.19.5"
=======
version = "2.0.0-dev-0"
@@ -1912,6 +1929,9 @@ version = "2.0.0-dev-6"
=======
version = "2.0.0-dev-7"
>>>>>>> fc28dbeb (deploy 2.0.0-dev-7)
=======
version = "2.0.0-dev-8"
>>>>>>> 0779afdc (deploy 2.0.0-dev-8)
dependencies = [
"anyhow",
"formatting",
@@ -1929,6 +1949,7 @@ name = "environment_file"
<<<<<<< HEAD
<<<<<<< HEAD
<<<<<<< HEAD
<<<<<<< HEAD
version = "1.19.5"
=======
version = "2.0.0-dev-0"
@@ -1954,6 +1975,9 @@ version = "2.0.0-dev-6"
=======
version = "2.0.0-dev-7"
>>>>>>> fc28dbeb (deploy 2.0.0-dev-7)
=======
version = "2.0.0-dev-8"
>>>>>>> 0779afdc (deploy 2.0.0-dev-8)
dependencies = [
"thiserror 2.0.16",
]
@@ -2057,6 +2081,7 @@ name = "formatting"
<<<<<<< HEAD
<<<<<<< HEAD
<<<<<<< HEAD
<<<<<<< HEAD
version = "1.19.5"
=======
version = "2.0.0-dev-0"
@@ -2082,6 +2107,9 @@ version = "2.0.0-dev-6"
=======
version = "2.0.0-dev-7"
>>>>>>> fc28dbeb (deploy 2.0.0-dev-7)
=======
version = "2.0.0-dev-8"
>>>>>>> 0779afdc (deploy 2.0.0-dev-8)
dependencies = [
"serror",
]
@@ -2261,6 +2289,7 @@ name = "git"
<<<<<<< HEAD
<<<<<<< HEAD
<<<<<<< HEAD
<<<<<<< HEAD
version = "1.19.5"
=======
version = "2.0.0-dev-0"
@@ -2286,6 +2315,9 @@ version = "2.0.0-dev-6"
=======
version = "2.0.0-dev-7"
>>>>>>> fc28dbeb (deploy 2.0.0-dev-7)
=======
version = "2.0.0-dev-8"
>>>>>>> 0779afdc (deploy 2.0.0-dev-8)
dependencies = [
"anyhow",
"cache",
@@ -2893,6 +2925,7 @@ name = "interpolate"
<<<<<<< HEAD
<<<<<<< HEAD
<<<<<<< HEAD
<<<<<<< HEAD
version = "1.19.5"
=======
version = "2.0.0-dev-0"
@@ -2918,6 +2951,9 @@ version = "2.0.0-dev-6"
=======
version = "2.0.0-dev-7"
>>>>>>> fc28dbeb (deploy 2.0.0-dev-7)
=======
version = "2.0.0-dev-8"
>>>>>>> 0779afdc (deploy 2.0.0-dev-8)
dependencies = [
"anyhow",
"komodo_client",
@@ -3056,6 +3092,7 @@ name = "komodo_cli"
<<<<<<< HEAD
<<<<<<< HEAD
<<<<<<< HEAD
<<<<<<< HEAD
version = "1.19.5"
=======
version = "2.0.0-dev-0"
@@ -3081,6 +3118,9 @@ version = "2.0.0-dev-6"
=======
version = "2.0.0-dev-7"
>>>>>>> fc28dbeb (deploy 2.0.0-dev-7)
=======
version = "2.0.0-dev-8"
>>>>>>> 0779afdc (deploy 2.0.0-dev-8)
dependencies = [
"anyhow",
"chrono",
@@ -3114,6 +3154,7 @@ name = "komodo_client"
<<<<<<< HEAD
<<<<<<< HEAD
<<<<<<< HEAD
<<<<<<< HEAD
version = "1.19.5"
=======
version = "2.0.0-dev-0"
@@ -3139,6 +3180,9 @@ version = "2.0.0-dev-6"
=======
version = "2.0.0-dev-7"
>>>>>>> fc28dbeb (deploy 2.0.0-dev-7)
=======
version = "2.0.0-dev-8"
>>>>>>> 0779afdc (deploy 2.0.0-dev-8)
dependencies = [
"anyhow",
"async_timing_util",
@@ -3182,6 +3226,7 @@ name = "komodo_core"
<<<<<<< HEAD
<<<<<<< HEAD
<<<<<<< HEAD
<<<<<<< HEAD
version = "1.19.5"
=======
version = "2.0.0-dev-0"
@@ -3207,6 +3252,9 @@ version = "2.0.0-dev-6"
=======
version = "2.0.0-dev-7"
>>>>>>> fc28dbeb (deploy 2.0.0-dev-7)
=======
version = "2.0.0-dev-8"
>>>>>>> 0779afdc (deploy 2.0.0-dev-8)
dependencies = [
"anyhow",
"arc-swap",
@@ -3272,7 +3320,6 @@ dependencies = [
"tracing",
"transport",
"typeshare",
"url",
"urlencoding",
"uuid",
"wildcard",
@@ -3288,6 +3335,7 @@ name = "komodo_periphery"
<<<<<<< HEAD
<<<<<<< HEAD
<<<<<<< HEAD
<<<<<<< HEAD
version = "1.19.5"
=======
version = "2.0.0-dev-0"
@@ -3313,6 +3361,9 @@ version = "2.0.0-dev-6"
=======
version = "2.0.0-dev-7"
>>>>>>> fc28dbeb (deploy 2.0.0-dev-7)
=======
version = "2.0.0-dev-8"
>>>>>>> 0779afdc (deploy 2.0.0-dev-8)
dependencies = [
"anyhow",
"arc-swap",
@@ -3356,7 +3407,6 @@ dependencies = [
"tokio-util",
"tracing",
"transport",
"url",
"urlencoding",
"uuid",
]
@@ -3372,18 +3422,18 @@ dependencies = [
[[package]]
name = "libc"
version = "0.2.175"
version = "0.2.176"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "6a82ae493e598baaea5209805c49bbf2ea7de956d50d7da0da1164f9c6d28543"
checksum = "58f929b4d672ea937a23a1ab494143d968337a5f47e56d0815df1e0890ddf174"
[[package]]
name = "libloading"
version = "0.8.8"
version = "0.8.9"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "07033963ba89ebaf1584d767badaa2e8fcec21aedea6b8c0346d487d49c28667"
checksum = "d7c4b02199fee7c5d21a5ae7d8cfa79a6ef5bb2fc834d6e9058e89c825efdc55"
dependencies = [
"cfg-if",
"windows-targets 0.53.3",
"windows-link 0.2.0",
]
[[package]]
@@ -3445,6 +3495,7 @@ name = "logger"
<<<<<<< HEAD
<<<<<<< HEAD
<<<<<<< HEAD
<<<<<<< HEAD
version = "1.19.5"
=======
version = "2.0.0-dev-0"
@@ -3470,6 +3521,9 @@ version = "2.0.0-dev-6"
=======
version = "2.0.0-dev-7"
>>>>>>> fc28dbeb (deploy 2.0.0-dev-7)
=======
version = "2.0.0-dev-8"
>>>>>>> 0779afdc (deploy 2.0.0-dev-8)
dependencies = [
"anyhow",
"komodo_client",
@@ -3741,7 +3795,7 @@ dependencies = [
[[package]]
name = "noise"
version = "2.0.0-dev-7"
version = "2.0.0-dev-8"
dependencies = [
"anyhow",
"base64 0.22.1",
@@ -4247,6 +4301,7 @@ name = "periphery_client"
<<<<<<< HEAD
<<<<<<< HEAD
<<<<<<< HEAD
<<<<<<< HEAD
version = "1.19.5"
=======
version = "2.0.0-dev-0"
@@ -4272,6 +4327,9 @@ version = "2.0.0-dev-6"
=======
version = "2.0.0-dev-7"
>>>>>>> fc28dbeb (deploy 2.0.0-dev-7)
=======
version = "2.0.0-dev-8"
>>>>>>> 0779afdc (deploy 2.0.0-dev-8)
dependencies = [
"komodo_client",
"resolver_api",
@@ -4826,6 +4884,7 @@ name = "response"
<<<<<<< HEAD
<<<<<<< HEAD
<<<<<<< HEAD
<<<<<<< HEAD
version = "1.19.5"
=======
version = "2.0.0-dev-0"
@@ -4851,6 +4910,9 @@ version = "2.0.0-dev-6"
=======
version = "2.0.0-dev-7"
>>>>>>> fc28dbeb (deploy 2.0.0-dev-7)
=======
version = "2.0.0-dev-8"
>>>>>>> 0779afdc (deploy 2.0.0-dev-8)
dependencies = [
"anyhow",
"axum",
@@ -5014,7 +5076,7 @@ dependencies = [
"openssl-probe",
"rustls-pki-types",
"schannel",
"security-framework 3.4.0",
"security-framework 3.5.0",
]
[[package]]
@@ -5185,9 +5247,9 @@ dependencies = [
[[package]]
name = "security-framework"
version = "3.4.0"
version = "3.5.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "60b369d18893388b345804dc0007963c99b7d665ae71d275812d828c6f089640"
checksum = "cc198e42d9b7510827939c9a15f5062a0c913f3371d765977e586d2fe6c16f4a"
dependencies = [
"bitflags 2.9.4",
"core-foundation 0.10.1",
@@ -5397,9 +5459,9 @@ dependencies = [
[[package]]
name = "serial2"
version = "0.2.32"
version = "0.2.33"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "349bb79c63bd2690fe4ca8ef7072a6d9ca36b3a1687a08393e733ea56d573911"
checksum = "8cc76fa68e25e771492ca1e3c53d447ef0be3093e05cd3b47f4b712ba10c6f3c"
dependencies = [
"cfg-if",
"libc",
@@ -6198,7 +6260,7 @@ dependencies = [
[[package]]
name = "transport"
version = "2.0.0-dev-7"
version = "2.0.0-dev-8"
dependencies = [
"anyhow",
"axum",
@@ -6214,6 +6276,7 @@ dependencies = [
"tokio",
"tokio-tungstenite 0.27.0",
"tracing",
"url",
"uuid",
]
+1 -1
View File
@@ -8,7 +8,7 @@ members = [
]
[workspace.package]
version = "2.0.0-dev-7"
version = "2.0.0-dev-8"
edition = "2024"
authors = ["mbecker20 <becker.maxh@gmail.com>"]
license = "GPL-3.0-or-later"
-1
View File
@@ -84,4 +84,3 @@ rand.workspace = true
hmac.workspace = true
sha2.workspace = true
hex.workspace = true
url.workspace = true
+2 -2
View File
@@ -436,8 +436,8 @@ async fn get_on_host_periphery(
ObjectId::new().to_hex(),
PeripheryConnectionArgs {
address: &config.address,
private_key: &config.private_key,
expected_public_key: &config.public_key,
core_private_key: &config.core_private_key,
periphery_public_key: &config.periphery_public_key,
},
)
.await?;
+2 -2
View File
@@ -84,8 +84,8 @@ pub async fn launch_ec2_instance(
assign_public_ip,
use_public_ip,
user_data,
private_key: _,
public_key: _,
core_private_key: _,
periphery_public_key: _,
port: _,
use_https: _,
git_providers: _,
+5 -13
View File
@@ -6,7 +6,7 @@ use periphery_client::CONNECTION_RETRY_SECONDS;
use rustls::{ClientConfig, client::danger::ServerCertVerifier};
use tokio_tungstenite::Connector;
use transport::{
auth::{ClientLoginFlow, ConnectionIdentifiers},
auth::{AddressConnectionIdentifiers, ClientLoginFlow},
fix_ws_address,
websocket::tungstenite::TungsteniteWebsocket,
};
@@ -29,13 +29,8 @@ impl PeripheryConnectionArgs<'_> {
let address = fix_ws_address(self.address);
let url = ::url::Url::parse(&address)
.context("Failed to parse server address")?;
let mut host = url.host().context("url has no host")?.to_string();
if let Some(port) = url.port() {
host.push(':');
host.push_str(&port.to_string());
}
let identifiers =
AddressConnectionIdentifiers::extract(&address)?;
let (connection, mut write_receiver) =
periphery_connections().insert(server_id, self).await;
@@ -65,11 +60,8 @@ impl PeripheryConnectionArgs<'_> {
let handler = super::WebsocketHandler {
socket,
connection_identifiers: ConnectionIdentifiers {
host: host.as_bytes(),
accept: accept.as_bytes(),
query: &[],
},
connection_identifiers: identifiers
.build(accept.as_bytes(), &[]),
write_receiver: &mut write_receiver,
connection: &connection,
};
+12 -12
View File
@@ -46,17 +46,17 @@ impl<W: Websocket> WebsocketHandler<'_, W> {
connection,
} = self;
let private_key = if connection.private_key.is_empty() {
let private_key = if connection.core_private_key.is_empty() {
&core_config().private_key
} else {
&connection.private_key
&connection.core_private_key
};
let expected_public_key = if !connection
.expected_public_key
.periphery_public_key
.is_empty()
{
Some(connection.expected_public_key.as_str())
Some(connection.periphery_public_key.as_str())
} else if connection.address.is_empty() {
// Only force periphery public key for Periphery -> Core connections
Some(
@@ -221,15 +221,15 @@ impl PeripheryConnections {
#[derive(Clone, Copy)]
pub struct PeripheryConnectionArgs<'a> {
pub address: &'a str,
pub private_key: &'a str,
pub expected_public_key: &'a str,
pub core_private_key: &'a str,
pub periphery_public_key: &'a str,
}
impl PeripheryConnectionArgs<'_> {
pub fn matches(&self, connection: &PeripheryConnection) -> bool {
self.address == connection.address
&& self.private_key == connection.private_key
&& self.expected_public_key == connection.expected_public_key
&& self.core_private_key == connection.core_private_key
&& self.periphery_public_key == connection.periphery_public_key
}
}
@@ -239,10 +239,10 @@ pub struct PeripheryConnection {
/// Inbound connections have this as empty string
pub address: String,
/// The private key to use, or empty for core private key
pub private_key: String,
pub core_private_key: String,
/// The public key to expect Periphery to have.
/// Required non-empty for inbound connection.
pub expected_public_key: String,
pub periphery_public_key: String,
/// Whether Periphery is currently connected.
pub connected: AtomicBool,
/// Stores latest connection error
@@ -266,8 +266,8 @@ impl PeripheryConnection {
(
PeripheryConnection {
address: args.address.to_string(),
private_key: args.private_key.to_string(),
expected_public_key: args.expected_public_key.to_string(),
core_private_key: args.core_private_key.to_string(),
periphery_public_key: args.periphery_public_key.to_string(),
sender,
channels,
connected: AtomicBool::new(false),
+6 -5
View File
@@ -8,7 +8,7 @@ use komodo_client::entities::server::Server;
use serror::{AddStatusCode, AddStatusCodeError};
use transport::{
PeripheryConnectionQuery,
auth::{ServerHeaderIdentifiers, ServerLoginFlow},
auth::{HeaderConnectionIdentifiers, ServerLoginFlow},
websocket::axum::AxumWebsocket,
};
@@ -23,8 +23,9 @@ pub async fn handler(
mut headers: HeaderMap,
ws: WebSocketUpgrade,
) -> serror::Result<Response> {
let identifiers = ServerHeaderIdentifiers::extract(&mut headers)
.status_code(StatusCode::UNAUTHORIZED)?;
let identifiers =
HeaderConnectionIdentifiers::extract(&mut headers)
.status_code(StatusCode::UNAUTHORIZED)?;
let server = crate::resource::get::<Server>(&_server)
.await
@@ -60,8 +61,8 @@ pub async fn handler(
server.id.clone(),
PeripheryConnectionArgs {
address: "",
private_key: &server.config.private_key,
expected_public_key: &server.config.public_key,
core_private_key: &server.config.core_private_key,
periphery_public_key: &server.config.periphery_public_key,
},
)
.await;
+4 -4
View File
@@ -52,8 +52,8 @@ pub async fn get_builder_periphery(
ObjectId::new().to_hex(),
PeripheryConnectionArgs {
address: &config.address,
private_key: &config.private_key,
expected_public_key: &config.public_key,
core_private_key: &config.core_private_key,
periphery_public_key: &config.periphery_public_key,
},
)
.await?;
@@ -113,8 +113,8 @@ async fn get_aws_builder(
ObjectId::new().to_hex(),
PeripheryConnectionArgs {
address: &periphery_address,
private_key: &config.private_key,
expected_public_key: &config.public_key,
core_private_key: &config.core_private_key,
periphery_public_key: &config.periphery_public_key,
},
)
.await?;
+2 -2
View File
@@ -196,8 +196,8 @@ pub async fn periphery_client(
server.id.clone(),
PeripheryConnectionArgs {
address: &server.config.address,
private_key: &server.config.private_key,
expected_public_key: &server.config.public_key,
core_private_key: &server.config.core_private_key,
periphery_public_key: &server.config.periphery_public_key,
},
)
.await
+2 -2
View File
@@ -157,8 +157,8 @@ impl super::KomodoResource for Server {
updated.id.clone(),
PeripheryConnectionArgs {
address: &updated.config.address,
private_key: &updated.config.private_key,
expected_public_key: &updated.config.public_key,
core_private_key: &updated.config.core_private_key,
periphery_public_key: &updated.config.periphery_public_key,
},
)
.await;
-1
View File
@@ -61,4 +61,3 @@ axum.workspace = true
clap.workspace = true
envy.workspace = true
uuid.workspace = true
url.workspace = true
+3 -1
View File
@@ -74,7 +74,9 @@ pub fn periphery_config() -> &'static PeripheryConfig {
core_public_key: env
.periphery_core_public_key
.or(config.core_public_key),
core_host: env.periphery_core_host.or(config.core_host),
core_address: env
.periphery_core_address
.or(config.core_address),
connect_as: env.periphery_connect_as.or(config.connect_as),
port: env.periphery_port.unwrap_or(config.port),
bind_ip: env.periphery_bind_ip.unwrap_or(config.bind_ip),
+32 -42
View File
@@ -4,16 +4,15 @@ use anyhow::Context;
use axum::http::HeaderValue;
use periphery_client::CONNECTION_RETRY_SECONDS;
use transport::{
auth::{ClientLoginFlow, ConnectionIdentifiers},
auth::{AddressConnectionIdentifiers, ClientLoginFlow},
fix_ws_address,
websocket::tungstenite::TungsteniteWebsocket,
};
use url::Url;
use crate::connection::ws_receiver;
pub async fn handler(
core_host: &str,
address: &str,
connect_as: &str,
) -> anyhow::Result<()> {
if let Err(e) =
@@ -27,41 +26,34 @@ pub async fn handler(
.try_lock()
.context("Websocket handler called more than once.")?;
let core_host = fix_ws_address(core_host);
let core_endpoint = format!(
"{core_host}/ws/periphery?server={}",
urlencoding::encode(connect_as)
);
let url =
Url::parse(&core_endpoint).context("Failed to parse ws url")?;
let host: Vec<u8> =
url.host().context("Url has no host")?.to_string().into();
let query = url.query().context("Url has no query")?.as_bytes();
let address = fix_ws_address(address);
let identifiers = AddressConnectionIdentifiers::extract(&address)?;
let query = format!("server={}", urlencoding::encode(connect_as));
let endpoint = format!("{address}/ws/periphery?{query}");
info!("Initiating outbound connection to {url}");
info!("Initiating outbound connection to {endpoint}");
let mut already_logged_connection_error = false;
let mut already_logged_login_error = false;
loop {
let (socket, accept) =
match connect_websocket(&core_endpoint).await {
Ok(res) => res,
Err(e) => {
if !already_logged_connection_error {
warn!("{e:#}");
already_logged_connection_error = true;
// If error transitions from login to connection,
// set to false to see login error after reconnect.
already_logged_login_error = false;
}
tokio::time::sleep(Duration::from_secs(
CONNECTION_RETRY_SECONDS,
))
.await;
continue;
let (socket, accept) = match connect_websocket(&endpoint).await {
Ok(res) => res,
Err(e) => {
if !already_logged_connection_error {
warn!("{e:#}");
already_logged_connection_error = true;
// If error transitions from login to connection,
// set to false to see login error after reconnect.
already_logged_login_error = false;
}
};
tokio::time::sleep(Duration::from_secs(
CONNECTION_RETRY_SECONDS,
))
.await;
continue;
}
};
already_logged_connection_error = false;
@@ -69,20 +61,14 @@ pub async fn handler(
info!("Connected to core connection websocket");
}
let connection_identifiers = ConnectionIdentifiers {
host: &host,
accept: accept.as_bytes(),
query,
};
let handler = super::WebsocketHandler {
let mut handler = super::WebsocketHandler {
socket,
connection_identifiers,
connection_identifiers: identifiers
.build(accept.as_bytes(), query.as_bytes()),
write_receiver: &mut write_receiver,
on_login_success: || already_logged_login_error = false,
};
if let Err(e) = handler.handle::<ClientLoginFlow>().await {
if let Err(e) = handler.login::<ClientLoginFlow>().await {
if !already_logged_login_error {
warn!("Failed to login | {e:#}");
already_logged_login_error = true;
@@ -92,7 +78,11 @@ pub async fn handler(
))
.await;
continue;
};
}
already_logged_login_error = false;
handler.handle().await
}
}
+13 -22
View File
@@ -58,35 +58,28 @@ pub fn init_response_channel() {
.expect("response_receiver initialized more than once");
}
pub struct WebsocketHandler<'a, W, S> {
pub struct WebsocketHandler<'a, W> {
pub socket: W,
pub connection_identifiers: ConnectionIdentifiers<'a>,
pub write_receiver: &'a mut BufferedReceiver<Bytes>,
pub on_login_success: S,
}
impl<W: Websocket, S: FnMut()> WebsocketHandler<'_, W, S> {
async fn handle<L: LoginFlow>(self) -> anyhow::Result<()> {
let WebsocketHandler {
mut socket,
connection_identifiers,
write_receiver,
mut on_login_success,
} = self;
impl<W: Websocket> WebsocketHandler<'_, W> {
async fn login<L: LoginFlow>(&mut self) -> anyhow::Result<()> {
L::login(
&mut socket,
connection_identifiers,
&mut self.socket,
self.connection_identifiers,
&periphery_config().private_key,
&CorePublicKeyValidator,
)
.await?;
on_login_success();
.await
}
async fn handle(self) {
let config = periphery_config();
info!(
"Logged in to Core connection websocket{}",
if config.core_host.is_some()
if config.core_address.is_some()
&& let Some(connect_as) = &config.connect_as
{
format!(" as Server {connect_as}")
@@ -95,11 +88,11 @@ impl<W: Websocket, S: FnMut()> WebsocketHandler<'_, W, S> {
}
);
let (mut ws_write, mut ws_read) = socket.split();
let (mut ws_write, mut ws_read) = self.socket.split();
let forward_writes = async {
loop {
let msg = match write_receiver.recv().await {
let msg = match self.write_receiver.recv().await {
// Sender Dropped (shouldn't happen, it is static).
None => break,
// This has to copy the bytes to follow ownership rules.
@@ -108,7 +101,7 @@ impl<W: Websocket, S: FnMut()> WebsocketHandler<'_, W, S> {
match ws_write.send(msg).await {
// Clears the stored message from receiver buffer.
// TODO: Move after response ack.
Ok(_) => write_receiver.clear_buffer(),
Ok(_) => self.write_receiver.clear_buffer(),
Err(e) => {
warn!("Failed to send response | {e:?}");
let _ = ws_write.close(None).await;
@@ -143,9 +136,7 @@ impl<W: Websocket, S: FnMut()> WebsocketHandler<'_, W, S> {
tokio::select! {
_ = forward_writes => {},
_ = handle_reads => {},
};
Ok(())
}
}
}
+13 -9
View File
@@ -20,7 +20,7 @@ use axum::{
use axum_server::tls_rustls::RustlsConfig;
use serror::{AddStatusCode, AddStatusCodeError};
use transport::{
auth::{ServerHeaderIdentifiers, ServerLoginFlow},
auth::{HeaderConnectionIdentifiers, ServerLoginFlow},
websocket::axum::AxumWebsocket,
};
@@ -78,26 +78,30 @@ async fn handler(
.try_lock()
.status_code(StatusCode::FORBIDDEN)?;
let identifiers = ServerHeaderIdentifiers::extract(&mut headers)
.status_code(StatusCode::UNAUTHORIZED)?;
let identifiers =
HeaderConnectionIdentifiers::extract(&mut headers)
.status_code(StatusCode::UNAUTHORIZED)?;
Ok(ws.on_upgrade(|socket| async move {
let handler = super::WebsocketHandler {
let mut handler = super::WebsocketHandler {
socket: AxumWebsocket(socket),
connection_identifiers: identifiers.build(&[]),
write_receiver: &mut write_receiver,
on_login_success: || {
already_logged_login_error()
.store(false, atomic::Ordering::Relaxed);
},
};
if let Err(e) = handler.handle::<ServerLoginFlow>().await {
if let Err(e) = handler.login::<ServerLoginFlow>().await {
let already_logged = already_logged_login_error();
if !already_logged.load(atomic::Ordering::Relaxed) {
warn!("Core failed to login to connection | {e:#}");
already_logged.store(true, atomic::Ordering::Relaxed);
}
return;
}
already_logged_login_error()
.store(false, atomic::Ordering::Relaxed);
handler.handle().await
}))
}
+1 -1
View File
@@ -32,7 +32,7 @@ async fn app() -> anyhow::Result<()> {
docker::stats::spawn_polling_thread();
connection::init_response_channel();
match (&config.core_host, &config.connect_as) {
match (&config.core_address, &config.connect_as) {
(Some(core_host), Some(connect_as)) => {
connection::client::handler(core_host, connect_as).await
}
+23 -22
View File
@@ -247,12 +247,12 @@ impl MergePartial for BuilderConfig {
BuilderConfig::Url(config) => {
let config = UrlBuilderConfig {
address: partial.address.unwrap_or(config.address),
private_key: partial
.private_key
.unwrap_or(config.private_key),
public_key: partial
.public_key
.unwrap_or(config.public_key),
core_private_key: partial
.core_private_key
.unwrap_or(config.core_private_key),
periphery_public_key: partial
.periphery_public_key
.unwrap_or(config.periphery_public_key),
};
BuilderConfig::Url(config)
}
@@ -291,12 +291,12 @@ impl MergePartial for BuilderConfig {
.unwrap_or(config.use_public_ip),
port: partial.port.unwrap_or(config.port),
use_https: partial.use_https.unwrap_or(config.use_https),
private_key: partial
.private_key
.unwrap_or(config.private_key),
public_key: partial
.public_key
.unwrap_or(config.public_key),
core_private_key: partial
.core_private_key
.unwrap_or(config.core_private_key),
periphery_public_key: partial
.periphery_public_key
.unwrap_or(config.periphery_public_key),
user_data: partial.user_data.unwrap_or(config.user_data),
git_providers: partial
.git_providers
@@ -326,13 +326,14 @@ pub struct UrlBuilderConfig {
/// The address of the Periphery agent
#[serde(default = "default_address")]
pub address: String,
/// A custom private key to use. Otherwise, use the default private key.
/// A custom private key to use to authenticate with the Periphery agent.
/// Otherwise, use the default Core private key.
#[serde(default)]
pub private_key: String,
pub core_private_key: String,
/// An expected public key associated with Periphery private key.
/// If empty, doesn't validate Periphery public key.
#[serde(default)]
pub public_key: String,
pub periphery_public_key: String,
}
fn default_address() -> String {
@@ -343,8 +344,8 @@ impl Default for UrlBuilderConfig {
fn default() -> Self {
Self {
address: default_address(),
private_key: Default::default(),
public_key: Default::default(),
core_private_key: Default::default(),
periphery_public_key: Default::default(),
}
}
}
@@ -455,14 +456,14 @@ pub struct AwsBuilderConfig {
#[builder(default)]
pub user_data: String,
/// A custom private key to use to authenticate with agent.
/// A custom private key to use to authenticate with the Periphery agent.
/// Otherwise, use the default Core private key.
#[serde(default)]
pub private_key: String,
pub core_private_key: String,
/// An expected public key associated with Periphery private key.
/// If empty, doesn't validate Periphery public key.
#[serde(default)]
pub public_key: String,
pub periphery_public_key: String,
/// Which git providers are available on the AMI
#[serde(default)]
@@ -497,8 +498,8 @@ impl Default for AwsBuilderConfig {
assign_public_ip: Default::default(),
use_public_ip: Default::default(),
user_data: Default::default(),
private_key: Default::default(),
public_key: Default::default(),
core_private_key: Default::default(),
periphery_public_key: Default::default(),
git_providers: Default::default(),
docker_registries: Default::default(),
secrets: Default::default(),
@@ -127,8 +127,8 @@ pub struct Env {
pub periphery_private_key_file: Option<PathBuf>,
/// Override `core_public_key`
pub periphery_core_public_key: Option<String>,
/// Override `core_host`
pub periphery_core_host: Option<String>,
/// Override `core_address`
pub periphery_core_address: Option<String>,
/// Override `connect_as`
pub periphery_connect_as: Option<String>,
/// Override `port`
@@ -204,10 +204,9 @@ pub struct PeripheryConfig {
// ============================
/// Address of Komodo Core when connecting outbound
#[serde(skip_serializing_if = "Option::is_none")]
pub core_host: Option<String>,
pub core_address: Option<String>,
/// Server name / id to connect as
/// TODO: explore using device identifier like MAC
#[serde(skip_serializing_if = "Option::is_none")]
pub connect_as: Option<String>,
@@ -376,7 +375,7 @@ impl Default for PeripheryConfig {
Self {
private_key: default_private_key(),
core_public_key: None,
core_host: None,
core_address: None,
connect_as: None,
port: default_periphery_port(),
bind_ip: default_periphery_bind_ip(),
@@ -410,7 +409,7 @@ impl PeripheryConfig {
PeripheryConfig {
private_key: empty_or_redacted(&self.private_key),
core_public_key: self.core_public_key.clone(),
core_host: self.core_host.clone(),
core_address: self.core_address.clone(),
connect_as: self.connect_as.clone(),
port: self.port,
bind_ip: self.bind_ip.clone(),
+7 -7
View File
@@ -91,18 +91,18 @@ pub struct ServerConfig {
pub enabled: bool,
/// An optional override private key to use
/// to authenticate with periphery agent.
/// to authenticate with Periphery agent.
/// If this is empty, will use private key in core config.
#[serde(default)]
#[builder(default)]
pub private_key: String,
pub core_private_key: String,
/// The accepted public key associated with
/// The expected public key associated with
/// private key of the periphery agent.
/// If this is empty, will not validate the Periphery public key.
/// If this is empty, falls back to 'periphery_public_key'
#[serde(default)]
#[builder(default)]
pub public_key: String,
pub periphery_public_key: String,
/// Sometimes the system stats reports a mount path that is not desired.
/// Use this field to filter it out from the report.
@@ -271,8 +271,8 @@ impl Default for ServerConfig {
send_disk_alerts: default_send_alerts(),
send_version_mismatch_alerts: default_send_alerts(),
region: Default::default(),
private_key: Default::default(),
public_key: Default::default(),
core_private_key: Default::default(),
periphery_public_key: Default::default(),
cpu_warning: default_cpu_warning(),
cpu_critical: default_cpu_critical(),
mem_warning: default_mem_warning(),
+14 -11
View File
@@ -2017,16 +2017,16 @@ export interface ServerConfig {
enabled: boolean;
/**
* An optional override private key to use
* to authenticate with periphery agent.
* to authenticate with Periphery agent.
* If this is empty, will use private key in core config.
*/
private_key?: string;
core_private_key?: string;
/**
* The accepted public key associated with
* The expected public key associated with
* private key of the periphery agent.
* If this is empty, will not validate the Periphery public key.
* If this is empty, falls back to 'periphery_public_key'
*/
public_key?: string;
periphery_public_key?: string;
/**
* Sometimes the system stats reports a mount path that is not desired.
* Use this field to filter it out from the report.
@@ -4213,15 +4213,15 @@ export interface AwsBuilderConfig {
/** The user data to deploy the instance with. */
user_data?: string;
/**
* A custom private key to use to authenticate with agent.
* A custom private key to use to authenticate with the Periphery agent.
* Otherwise, use the default Core private key.
*/
private_key?: string;
core_private_key?: string;
/**
* An expected public key associated with Periphery private key.
* If empty, doesn't validate Periphery public key.
*/
public_key?: string;
periphery_public_key?: string;
/** Which git providers are available on the AMI */
git_providers?: GitProvider[];
/** Which docker registries are available on the AMI. */
@@ -8451,13 +8451,16 @@ export interface UpdateVariableValue {
export interface UrlBuilderConfig {
/** The address of the Periphery agent */
address: string;
/** A custom private key to use. Otherwise, use the default private key. */
private_key?: string;
/**
* A custom private key to use to authenticate with the Periphery agent.
* Otherwise, use the default Core private key.
*/
core_private_key?: string;
/**
* An expected public key associated with Periphery private key.
* If empty, doesn't validate Periphery public key.
*/
public_key?: string;
periphery_public_key?: string;
}
/** Update dockerfile contents in Files on Server or Git Repo mode. Response: [Update]. */
+14 -11
View File
@@ -2149,16 +2149,16 @@ export interface ServerConfig {
enabled: boolean;
/**
* An optional override private key to use
* to authenticate with periphery agent.
* to authenticate with Periphery agent.
* If this is empty, will use private key in core config.
*/
private_key?: string;
core_private_key?: string;
/**
* The accepted public key associated with
* The expected public key associated with
* private key of the periphery agent.
* If this is empty, will not validate the Periphery public key.
* If this is empty, falls back to 'periphery_public_key'
*/
public_key?: string;
periphery_public_key?: string;
/**
* Sometimes the system stats reports a mount path that is not desired.
* Use this field to filter it out from the report.
@@ -4120,15 +4120,15 @@ export interface AwsBuilderConfig {
/** The user data to deploy the instance with. */
user_data?: string;
/**
* A custom private key to use to authenticate with agent.
* A custom private key to use to authenticate with the Periphery agent.
* Otherwise, use the default Core private key.
*/
private_key?: string;
core_private_key?: string;
/**
* An expected public key associated with Periphery private key.
* If empty, doesn't validate Periphery public key.
*/
public_key?: string;
periphery_public_key?: string;
/** Which git providers are available on the AMI */
git_providers?: GitProvider[];
/** Which docker registries are available on the AMI. */
@@ -7988,13 +7988,16 @@ export interface UpdateVariableValue {
export interface UrlBuilderConfig {
/** The address of the Periphery agent */
address: string;
/** A custom private key to use. Otherwise, use the default private key. */
private_key?: string;
/**
* A custom private key to use to authenticate with the Periphery agent.
* Otherwise, use the default Core private key.
*/
core_private_key?: string;
/**
* An expected public key associated with Periphery private key.
* If empty, doesn't validate Periphery public key.
*/
public_key?: string;
periphery_public_key?: string;
}
/** Update dockerfile contents in Files on Server or Git Repo mode. Response: [Update]. */
export interface WriteBuildFileContents {
@@ -135,18 +135,18 @@ const AwsBuilderConfig = ({ id }: { id: string }) => {
label: "Auth",
labelHidden: true,
components: {
public_key: {
label: "Periphery Public Key",
description:
"If provided, the associated private key must be set as Periphery 'private_key'. For Periphery -> Core connection, either this or using 'periphery_public_key' in Core config is required for Periphery to be able to connect.",
placeholder: "custom-public-key",
},
private_key: {
core_private_key: {
label: "Core Private Key",
description:
"Optional. A custom private key used to authenticate Periphery connection. The associated public key must match Periphery 'core_public_key'. If not provided, will use 'private_key' in Core config. Max length of 32 characters.",
placeholder: "custom-private-key",
},
periphery_public_key: {
label: "Periphery Public Key",
description:
"If provided, the associated private key must be set as Periphery 'private_key'. For Periphery -> Core connection, either this or using 'periphery_public_key' in Core config is required for Periphery to be able to connect.",
placeholder: "custom-public-key",
},
},
},
{
@@ -353,18 +353,18 @@ const UrlBuilderConfig = ({ id }: { id: string }) => {
label: "Auth",
labelHidden: true,
components: {
public_key: {
label: "Periphery Public Key",
description:
"If provided, the associated private key must be set as Periphery 'private_key'. For Periphery -> Core connection, either this or using 'periphery_public_key' in Core config is required for Periphery to be able to connect.",
placeholder: "custom-public-key",
},
private_key: {
core_private_key: {
label: "Core Private Key",
description:
"Optional. A custom private key used to authenticate Periphery connection. The associated public key must match Periphery 'core_public_key'. If not provided, will use 'private_key' in Core config. Max length of 32 characters.",
placeholder: "custom-private-key",
},
periphery_public_key: {
label: "Periphery Public Key",
description:
"If provided, the associated private key must be set as Periphery 'private_key'. For Periphery -> Core connection, either this or using 'periphery_public_key' in Core config is required for Periphery to be able to connect.",
placeholder: "custom-public-key",
},
},
},
],
@@ -63,18 +63,18 @@ export const ServerConfig = ({
label: "Auth",
labelHidden: true,
components: {
public_key: {
label: "Periphery Public Key",
description:
"If provided, the associated private key must be set as Periphery 'private_key'. For Periphery -> Core connection, either this or using 'periphery_public_key' in Core config is required for Periphery to be able to connect.",
placeholder: "custom-public-key",
},
private_key: {
core_private_key: {
label: "Core Private Key",
description:
"Optional. A custom private key used to authenticate Periphery connection. The associated public key must match Periphery 'core_public_key'. If not provided, will use 'private_key' in Core config. Max length of 32 characters.",
placeholder: "custom-private-key",
},
periphery_public_key: {
label: "Periphery Public Key",
description:
"If provided, the associated private key must be set as Periphery 'private_key'. For Periphery -> Core connection, either this or using 'periphery_public_key' in Core config is required for Periphery to be able to connect.",
placeholder: "custom-public-key",
},
},
},
{
+2 -1
View File
@@ -23,4 +23,5 @@ axum.workspace = true
rand.workspace = true
sha1.workspace = true
sha2.workspace = true
uuid.workspace = true
uuid.workspace = true
url.workspace = true
+47 -21
View File
@@ -18,15 +18,6 @@ use tracing::warn;
use crate::{MessageState, websocket::Websocket};
pub struct ConnectionIdentifiers<'a> {
/// Server hostname
pub host: &'a [u8],
/// Query: 'server=<SERVER>'
pub query: &'a [u8],
/// Sec-Websocket-Accept, unique for each connection
pub accept: &'a [u8],
}
pub trait PublicKeyValidator {
fn validate(&self, public_key: String) -> anyhow::Result<()>;
}
@@ -259,6 +250,16 @@ fn nonce() -> [u8; 32] {
out
}
#[derive(Clone, Copy)]
pub struct ConnectionIdentifiers<'a> {
/// Server hostname
pub host: &'a [u8],
/// Query: 'server=<SERVER>'
pub query: &'a [u8],
/// Sec-Websocket-Accept, unique for each connection
pub accept: &'a [u8],
}
impl ConnectionIdentifiers<'_> {
/// nonce: Server computed random connection nonce, sent to client before auth handshake
pub fn hash(&self, nonce: &[u8]) -> [u8; 32] {
@@ -275,17 +276,46 @@ impl ConnectionIdentifiers<'_> {
}
}
/// Used to extract owned connection identifier
/// in server side connection handler.
pub struct ServerHeaderIdentifiers {
pub host: HeaderValue,
pub accept: String,
pub struct AddressConnectionIdentifiers {
host: String,
}
impl ServerHeaderIdentifiers {
impl AddressConnectionIdentifiers {
pub fn extract(address: &str) -> anyhow::Result<Self> {
let url = ::url::Url::parse(&address)
.context("Failed to parse server address")?;
let mut host = url.host().context("url has no host")?.to_string();
if let Some(port) = url.port() {
host.push(':');
host.push_str(&port.to_string());
};
Ok(Self { host })
}
pub fn build<'a>(
&'a self,
accept: &'a [u8],
query: &'a [u8],
) -> ConnectionIdentifiers<'a> {
ConnectionIdentifiers {
host: self.host.as_bytes(),
query,
accept,
}
}
}
/// Used to extract owned connection identifier
/// in server side connection handler.
pub struct HeaderConnectionIdentifiers {
host: HeaderValue,
accept: String,
}
impl HeaderConnectionIdentifiers {
pub fn extract(
headers: &mut HeaderMap,
) -> anyhow::Result<ServerHeaderIdentifiers> {
) -> anyhow::Result<HeaderConnectionIdentifiers> {
let host = headers
.remove("x-forwarded-host")
.or(headers.remove("host"))
@@ -294,7 +324,7 @@ impl ServerHeaderIdentifiers {
.remove("sec-websocket-key")
.context("Headers do not contain Sec-Websocket-Key")?;
let accept = compute_accept(key.as_bytes());
Ok(ServerHeaderIdentifiers { host, accept })
Ok(HeaderConnectionIdentifiers { host, accept })
}
pub fn build<'a>(
@@ -309,10 +339,6 @@ impl ServerHeaderIdentifiers {
}
}
// pub fn extract_server_identifiers(headers: &mut HeaderMap) -> anyhow::Result<(Head)> {
// }
pub fn compute_accept(sec_websocket_key: &[u8]) -> String {
// This is standard GUID to compute Sec-Websocket-Accept
const GUID: &[u8] = b"258EAFA5-E914-47DA-95CA-C5AB0DC85B11";