From 11320ba04aa7a32d474eecc9da4d699c0a64ae5e Mon Sep 17 00:00:00 2001 From: core Date: Wed, 21 Jun 2023 21:03:11 -0400 Subject: [PATCH 01/17] forgot about config overrides for a second there --- tfcli/src/host.rs | 228 +++++++++++++- tfcli/src/main.rs | 34 ++ trifid-api/src/main.rs | 2 + trifid-api/src/routes/v1/hosts.rs | 495 +++++++++++++++++++++++++++++- 4 files changed, 756 insertions(+), 3 deletions(-) diff --git a/tfcli/src/host.rs b/tfcli/src/host.rs index 8e611ba..57a1ac7 100644 --- a/tfcli/src/host.rs +++ b/tfcli/src/host.rs @@ -4,7 +4,7 @@ use std::net::{Ipv4Addr, SocketAddrV4}; use serde::{Deserialize, Serialize}; use url::{Url}; use crate::api::APIErrorResponse; -use crate::{HostCommands}; +use crate::{HostCommands, HostOverrideCommands}; pub async fn host_main(command: HostCommands, server: Url) -> Result<(), Box> { match command { @@ -14,7 +14,12 @@ pub async fn host_main(command: HostCommands, server: Url) -> Result<(), Box delete_host(id, server).await, HostCommands::Update { id, listen_port, static_address, name, ip, role } => update_host(id, listen_port, static_address, name, ip, role, server).await, HostCommands::Block { id } => block_host(id, server).await, - HostCommands::Enroll { id } => enroll_host(id, server).await + HostCommands::Enroll { id } => enroll_host(id, server).await, + HostCommands::Overrides { command } => match command { + HostOverrideCommands::List { id } => list_overrides(id, server).await, + HostOverrideCommands::Set { id, key, boolean, string, numeric } => set_override(id, key, boolean, numeric, string, server).await, + HostOverrideCommands::Unset { id, key } => unset_override(id, key, server).await + } } } @@ -412,5 +417,224 @@ pub async fn block_host(id: String, server: Url) -> Result<(), Box> { std::process::exit(1); } + Ok(()) +} + +#[derive(Serialize, Deserialize)] +pub struct HostConfigOverrideResponse { + pub data: HostConfigOverrideData +} + +#[derive(Serialize, Deserialize)] +pub struct HostConfigOverrideData { + pub overrides: Vec +} + +#[derive(Serialize, Deserialize)] +pub struct HostConfigOverrideDataOverride { + pub key: String, + pub value: HostConfigOverrideDataOverrideValue +} + +#[derive(Serialize, Deserialize)] +#[serde(untagged)] +pub enum HostConfigOverrideDataOverrideValue { + Boolean(bool), + Numeric(i64), + Other(String) +} + +pub async fn list_overrides(id: String, server: Url) -> Result<(), Box> { + let client = reqwest::Client::new(); + + // load session token + let sess_token_store = dirs::config_dir().unwrap().join("tfcli-session.token"); + let session_token = fs::read_to_string(&sess_token_store)?; + let auth_token_store = dirs::config_dir().unwrap().join("tfcli-auth.token"); + let auth_token = fs::read_to_string(&auth_token_store)?; + + let token = format!("{} {}", session_token, auth_token); + + let res = client.get(server.join(&format!("/v1/hosts/{}/config-overrides", id))?).bearer_auth(token).send().await?; + + if res.status().is_success() { + let resp: HostConfigOverrideResponse = res.json().await?; + + for c_override in &resp.data.overrides { + println!(" Key: {}", c_override.key); + println!("Value: {}", match &c_override.value { + HostConfigOverrideDataOverrideValue::Boolean(v) => format!("bool:{}", v), + HostConfigOverrideDataOverrideValue::Numeric(v) => format!("numeric:{}", v), + HostConfigOverrideDataOverrideValue::Other(v) => format!("string:{}", v) + }); + } + + if resp.data.overrides.is_empty() { + println!("No overrides found"); + } + } else { + let resp: APIErrorResponse = res.json().await?; + + eprintln!("[error] Error looking up config overrides: {} {}", resp.errors[0].code, resp.errors[0].message); + + std::process::exit(1); + } + + Ok(()) +} + +#[derive(Serialize, Deserialize)] +pub struct SetOverrideRequest { + pub overrides: Vec +} + +pub async fn set_override(id: String, key: String, boolean: Option, numeric: Option, other: Option, server: Url) -> Result<(), Box> { + if boolean.is_none() && numeric.is_none() && other.is_none() { + eprintln!("[error] no value provided: you must provide at least --boolean, --numeric, or --string"); + std::process::exit(1); + } else if boolean.is_some() && numeric.is_some() || boolean.is_some() && other.is_some() || numeric.is_some() && other.is_some() { + eprintln!("[error] multiple values provided: you must provide only one of --boolean, --numeric, or --string"); + std::process::exit(1); + } + + let val; + + if let Some(v) = boolean { + val = HostConfigOverrideDataOverrideValue::Boolean(v); + } else if let Some(v) = numeric { + val = HostConfigOverrideDataOverrideValue::Numeric(v); + } else if let Some(v) = other { + val = HostConfigOverrideDataOverrideValue::Other(v); + } else { + unreachable!(); + } + + let client = reqwest::Client::new(); + + // load session token + let sess_token_store = dirs::config_dir().unwrap().join("tfcli-session.token"); + let session_token = fs::read_to_string(&sess_token_store)?; + let auth_token_store = dirs::config_dir().unwrap().join("tfcli-auth.token"); + let auth_token = fs::read_to_string(&auth_token_store)?; + + let token = format!("{} {}", session_token, auth_token); + + let res = client.get(server.join(&format!("/v1/hosts/{}/config-overrides", id))?).bearer_auth(token.clone()).send().await?; + + if res.status().is_success() { + let resp: HostConfigOverrideResponse = res.json().await?; + + let mut others: Vec = vec![]; + + for c_override in resp.data.overrides { + if c_override.key != key { + others.push(c_override); + } + } + + others.push(HostConfigOverrideDataOverride { + key, + value: val, + }); + + let res = client.put(server.join(&format!("/v1/hosts/{}/config-overrides", id))?).bearer_auth(token.clone()).json(&SetOverrideRequest { + overrides: others, + }).send().await?; + + if res.status().is_success() { + let resp: HostConfigOverrideResponse = res.json().await?; + + for c_override in &resp.data.overrides { + println!(" Key: {}", c_override.key); + println!("Value: {}", match &c_override.value { + HostConfigOverrideDataOverrideValue::Boolean(v) => format!("bool:{}", v), + HostConfigOverrideDataOverrideValue::Numeric(v) => format!("numeric:{}", v), + HostConfigOverrideDataOverrideValue::Other(v) => format!("string:{}", v) + }); + } + + if resp.data.overrides.is_empty() { + println!("No overrides found"); + } + + println!("Override set successfully"); + } else { + let resp: APIErrorResponse = res.json().await?; + + eprintln!("[error] Error setting config overrides: {} {}", resp.errors[0].code, resp.errors[0].message); + + std::process::exit(1); + } + } else { + let resp: APIErrorResponse = res.json().await?; + + eprintln!("[error] Error setting config overrides: {} {}", resp.errors[0].code, resp.errors[0].message); + + std::process::exit(1); + } + + Ok(()) +} + +pub async fn unset_override(id: String, key: String, server: Url) -> Result<(), Box> { + let client = reqwest::Client::new(); + + // load session token + let sess_token_store = dirs::config_dir().unwrap().join("tfcli-session.token"); + let session_token = fs::read_to_string(&sess_token_store)?; + let auth_token_store = dirs::config_dir().unwrap().join("tfcli-auth.token"); + let auth_token = fs::read_to_string(&auth_token_store)?; + + let token = format!("{} {}", session_token, auth_token); + + let res = client.get(server.join(&format!("/v1/hosts/{}/config-overrides", id))?).bearer_auth(token.clone()).send().await?; + + if res.status().is_success() { + let resp: HostConfigOverrideResponse = res.json().await?; + + let mut others: Vec = vec![]; + + for c_override in resp.data.overrides { + if c_override.key != key { + others.push(c_override); + } + } + + let res = client.put(server.join(&format!("/v1/hosts/{}/config-overrides", id))?).bearer_auth(token.clone()).json(&SetOverrideRequest { + overrides: others, + }).send().await?; + + if res.status().is_success() { + let resp: HostConfigOverrideResponse = res.json().await?; + + for c_override in &resp.data.overrides { + println!(" Key: {}", c_override.key); + println!("Value: {}", match &c_override.value { + HostConfigOverrideDataOverrideValue::Boolean(v) => format!("bool:{}", v), + HostConfigOverrideDataOverrideValue::Numeric(v) => format!("numeric:{}", v), + HostConfigOverrideDataOverrideValue::Other(v) => format!("string:{}", v) + }); + } + + if resp.data.overrides.is_empty() { + println!("No overrides found"); + } + + println!("Override unset successfully"); + } else { + let resp: APIErrorResponse = res.json().await?; + + eprintln!("[error] Error unsetting config overrides: {} {}", resp.errors[0].code, resp.errors[0].message); + + std::process::exit(1); + } + } else { + let resp: APIErrorResponse = res.json().await?; + + eprintln!("[error] Error unsetting config overrides: {} {}", resp.errors[0].code, resp.errors[0].message); + + std::process::exit(1); + } + Ok(()) } \ No newline at end of file diff --git a/tfcli/src/main.rs b/tfcli/src/main.rs index 2c834ab..adb6529 100644 --- a/tfcli/src/main.rs +++ b/tfcli/src/main.rs @@ -203,6 +203,40 @@ pub enum HostCommands { Enroll { #[clap(short, long)] id: String + }, + /// Manage config overrides set on the host + Overrides { + #[command(subcommand)] + command: HostOverrideCommands + } +} + +#[derive(Subcommand, Debug)] +pub enum HostOverrideCommands { + /// List the config overrides set on the host + List { + #[clap(short, long)] + id: String + }, + /// Set a config override on the host + Set { + #[clap(short, long)] + id: String, + #[clap(short, long)] + key: String, + #[clap(short, long)] + boolean: Option, + #[clap(short, long)] + numeric: Option, + #[clap(short, long)] + string: Option + }, + /// Unset a config override on the host + Unset { + #[clap(short, long)] + id: String, + #[clap(short, long)] + key: String } } diff --git a/trifid-api/src/main.rs b/trifid-api/src/main.rs index 263b90d..583c122 100644 --- a/trifid-api/src/main.rs +++ b/trifid-api/src/main.rs @@ -119,6 +119,8 @@ async fn main() -> Result<(), Box> { .service(routes::v2::enroll::enroll) .service(routes::v1::dnclient::dnclient) .service(routes::v2::whoami::whoami) + .service(routes::v1::hosts::get_host_overrides) + .service(routes::v1::hosts::update_host_overrides) }) .bind(CONFIG.server.bind)? .run() diff --git a/trifid-api/src/routes/v1/hosts.rs b/trifid-api/src/routes/v1/hosts.rs index 38568fb..f6fd78e 100644 --- a/trifid-api/src/routes/v1/hosts.rs +++ b/trifid-api/src/routes/v1/hosts.rs @@ -76,7 +76,8 @@ use serde::{Deserialize, Serialize}; use std::net::{Ipv4Addr, SocketAddrV4}; use std::str::FromStr; use std::time::{SystemTime, UNIX_EPOCH}; -use trifid_api_entities::entity::{host, host_static_address, network, organization}; +use trifid_api_entities::entity::{host, host_config_override, host_static_address, network, organization}; +use trifid_api_entities::entity::prelude::HostConfigOverride; #[derive(Serialize, Deserialize)] pub struct ListHostsRequestOpts { @@ -2328,3 +2329,495 @@ pub async fn create_host_and_enrollment_code( metadata: CreateHostAndCodeResponseMetadata {}, }) } + +#[derive(Serialize, Deserialize)] +pub struct HostConfigOverrideResponse { + pub data: HostConfigOverrideData +} + +#[derive(Serialize, Deserialize)] +pub struct HostConfigOverrideData { + pub overrides: Vec +} + +#[derive(Serialize, Deserialize)] +pub struct HostConfigOverrideDataOverride { + pub key: String, + pub value: HostConfigOverrideDataOverrideValue +} + +#[derive(Serialize, Deserialize)] +#[serde(untagged)] +pub enum HostConfigOverrideDataOverrideValue { + Boolean(bool), + Numeric(i64), + Other(String) +} + +#[get("/v1/hosts/{host_id}/config-overrides")] +pub async fn get_host_overrides(id: Path, req_info: HttpRequest, db: Data) -> HttpResponse { + // For this endpoint, you either need to be a fully authenticated user OR a token with hosts:read + let session_info = enforce_2fa(&req_info, &db.conn) + .await + .unwrap_or(TokenInfo::NotPresent); + let api_token_info = enforce_api_token(&req_info, &["hosts:read"], &db.conn) + .await + .unwrap_or(TokenInfo::NotPresent); + + // If neither are present, throw an error + if matches!(session_info, TokenInfo::NotPresent) + && matches!(api_token_info, TokenInfo::NotPresent) + { + return HttpResponse::Unauthorized().json(APIErrorsResponse { + errors: vec![ + APIError { + code: "ERR_UNAUTHORIZED".to_string(), + message: "This endpoint requires either a fully authenticated user or a token with the hosts:read scope".to_string(), + path: None, + } + ], + }); + } + + // If both are present, throw an error + if matches!(session_info, TokenInfo::AuthToken(_)) + && matches!(api_token_info, TokenInfo::ApiToken(_)) + { + return HttpResponse::BadRequest().json(APIErrorsResponse { + errors: vec![ + APIError { + code: "ERR_AMBIGUOUS_AUTHENTICATION".to_string(), + message: "Both a user token and an API token with the proper scope was provided. Please only provide one.".to_string(), + path: None + } + ], + }); + } + + let org_id = match api_token_info { + TokenInfo::ApiToken(tkn) => tkn.organization, + _ => { + // we have a session token, which means we have to do a db request to get the organization that this user owns + let user = match session_info { + TokenInfo::AuthToken(tkn) => tkn.session_info.user, + _ => unreachable!(), + }; + + let org = match organization::Entity::find() + .filter(organization::Column::Owner.eq(user.id)) + .one(&db.conn) + .await + { + Ok(r) => r, + Err(e) => { + error!("database error: {}", e); + return HttpResponse::InternalServerError().json(APIErrorsResponse { + errors: vec![ + APIError { + code: "ERR_DB_ERROR".to_string(), + message: "There was an error performing the database request, please try again later.".to_string(), + path: None, + } + ], + }); + } + }; + + if let Some(org) = org { + org.id + } else { + return HttpResponse::Unauthorized().json(APIErrorsResponse { + errors: vec![ + APIError { + code: "ERR_NO_ORG".to_string(), + message: "This user does not own any organizations. Try using an API token instead.".to_string(), + path: None + } + ], + }); + } + } + }; + + let net_id; + + let net = match network::Entity::find() + .filter(network::Column::Organization.eq(&org_id)) + .one(&db.conn) + .await + { + Ok(r) => r, + Err(e) => { + error!("database error: {}", e); + return HttpResponse::InternalServerError().json(APIErrorsResponse { + errors: vec![ + APIError { + code: "ERR_DB_ERROR".to_string(), + message: "There was an error performing the database request, please try again later.".to_string(), + path: None, + } + ], + }); + } + }; + + if let Some(net) = net { + net_id = net.id; + } else { + return HttpResponse::Unauthorized().json(APIErrorsResponse { + errors: vec![APIError { + code: "ERR_NO_NET".to_string(), + message: "This user does not own any networks. Try using an API token instead." + .to_string(), + path: None, + }], + }); + } + + let host = match host::Entity::find() + .filter(host::Column::Id.eq(id.into_inner())) + .one(&db.conn) + .await + { + Ok(h) => h, + Err(e) => { + error!("Database error: {}", e); + return HttpResponse::InternalServerError().json(APIErrorsResponse { + errors: vec![APIError { + code: "ERR_DB_ERROR".to_string(), + message: "There was an error with the database query. Please try again later." + .to_string(), + path: None, + }], + }); + } + }; + + let host = match host { + Some(h) => h, + None => { + return HttpResponse::Unauthorized().json(APIErrorsResponse { + errors: vec![APIError { + code: "ERR_UNAUTHORIZED".to_string(), + message: + "This resource does not exist or you do not have permission to access it." + .to_string(), + path: None, + }], + }) + } + }; + + if host.network != net_id { + return HttpResponse::Unauthorized().json(APIErrorsResponse { + errors: vec![APIError { + code: "ERR_UNAUTHORIZED".to_string(), + message: "This resource does not exist or you do not have permission to access it." + .to_string(), + path: None, + }], + }); + } + + let config_overrides = match trifid_api_entities::entity::host_config_override::Entity::find().filter(host_config_override::Column::Host.eq(host.id)).all(&db.conn).await { + Ok(h) => h, + Err(e) => { + error!("Database error: {}", e); + return HttpResponse::InternalServerError().json(APIErrorsResponse { + errors: vec![APIError { + code: "ERR_DB_ERROR".to_string(), + message: "There was an error with the database query. Please try again later." + .to_string(), + path: None, + }], + }); + } + }; + + let overrides: Vec = config_overrides.iter().map(|u| { + let val; + if u.value == "true" || u.value == "false" { + val = HostConfigOverrideDataOverrideValue::Boolean(u.value == "true"); + } else if u.value.chars().all(|c| c.is_numeric()) { + val = HostConfigOverrideDataOverrideValue::Numeric(u.value.parse().unwrap()); + } else { + val = HostConfigOverrideDataOverrideValue::Other(u.value.clone()); + } + HostConfigOverrideDataOverride { + key: u.key.clone(), + value: val, + } + }).collect(); + + HttpResponse::Ok().json(HostConfigOverrideResponse { + data: HostConfigOverrideData { + overrides, + }, + }) +} + +#[derive(Serialize, Deserialize)] +pub struct UpdateOverridesRequest { + pub overrides: Vec +} + +#[put("/v1/hosts/{host_id}/config-overrides")] +pub async fn update_host_overrides(id: Path, req: Json, req_info: HttpRequest, db: Data) -> HttpResponse { + // For this endpoint, you either need to be a fully authenticated user OR a token with hosts:read + let session_info = enforce_2fa(&req_info, &db.conn) + .await + .unwrap_or(TokenInfo::NotPresent); + let api_token_info = enforce_api_token(&req_info, &["hosts:read"], &db.conn) + .await + .unwrap_or(TokenInfo::NotPresent); + + // If neither are present, throw an error + if matches!(session_info, TokenInfo::NotPresent) + && matches!(api_token_info, TokenInfo::NotPresent) + { + return HttpResponse::Unauthorized().json(APIErrorsResponse { + errors: vec![ + APIError { + code: "ERR_UNAUTHORIZED".to_string(), + message: "This endpoint requires either a fully authenticated user or a token with the hosts:read scope".to_string(), + path: None, + } + ], + }); + } + + // If both are present, throw an error + if matches!(session_info, TokenInfo::AuthToken(_)) + && matches!(api_token_info, TokenInfo::ApiToken(_)) + { + return HttpResponse::BadRequest().json(APIErrorsResponse { + errors: vec![ + APIError { + code: "ERR_AMBIGUOUS_AUTHENTICATION".to_string(), + message: "Both a user token and an API token with the proper scope was provided. Please only provide one.".to_string(), + path: None + } + ], + }); + } + + let org_id = match api_token_info { + TokenInfo::ApiToken(tkn) => tkn.organization, + _ => { + // we have a session token, which means we have to do a db request to get the organization that this user owns + let user = match session_info { + TokenInfo::AuthToken(tkn) => tkn.session_info.user, + _ => unreachable!(), + }; + + let org = match organization::Entity::find() + .filter(organization::Column::Owner.eq(user.id)) + .one(&db.conn) + .await + { + Ok(r) => r, + Err(e) => { + error!("database error: {}", e); + return HttpResponse::InternalServerError().json(APIErrorsResponse { + errors: vec![ + APIError { + code: "ERR_DB_ERROR".to_string(), + message: "There was an error performing the database request, please try again later.".to_string(), + path: None, + } + ], + }); + } + }; + + if let Some(org) = org { + org.id + } else { + return HttpResponse::Unauthorized().json(APIErrorsResponse { + errors: vec![ + APIError { + code: "ERR_NO_ORG".to_string(), + message: "This user does not own any organizations. Try using an API token instead.".to_string(), + path: None + } + ], + }); + } + } + }; + + let net_id; + + let net = match network::Entity::find() + .filter(network::Column::Organization.eq(&org_id)) + .one(&db.conn) + .await + { + Ok(r) => r, + Err(e) => { + error!("database error: {}", e); + return HttpResponse::InternalServerError().json(APIErrorsResponse { + errors: vec![ + APIError { + code: "ERR_DB_ERROR".to_string(), + message: "There was an error performing the database request, please try again later.".to_string(), + path: None, + } + ], + }); + } + }; + + if let Some(net) = net { + net_id = net.id; + } else { + return HttpResponse::Unauthorized().json(APIErrorsResponse { + errors: vec![APIError { + code: "ERR_NO_NET".to_string(), + message: "This user does not own any networks. Try using an API token instead." + .to_string(), + path: None, + }], + }); + } + + let host = match host::Entity::find() + .filter(host::Column::Id.eq(id.into_inner())) + .one(&db.conn) + .await + { + Ok(h) => h, + Err(e) => { + error!("Database error: {}", e); + return HttpResponse::InternalServerError().json(APIErrorsResponse { + errors: vec![APIError { + code: "ERR_DB_ERROR".to_string(), + message: "There was an error with the database query. Please try again later." + .to_string(), + path: None, + }], + }); + } + }; + + let host = match host { + Some(h) => h, + None => { + return HttpResponse::Unauthorized().json(APIErrorsResponse { + errors: vec![APIError { + code: "ERR_UNAUTHORIZED".to_string(), + message: + "This resource does not exist or you do not have permission to access it." + .to_string(), + path: None, + }], + }) + } + }; + + if host.network != net_id { + return HttpResponse::Unauthorized().json(APIErrorsResponse { + errors: vec![APIError { + code: "ERR_UNAUTHORIZED".to_string(), + message: "This resource does not exist or you do not have permission to access it." + .to_string(), + path: None, + }], + }); + } + + let config_overrides = match trifid_api_entities::entity::host_config_override::Entity::find().filter(host_config_override::Column::Host.eq(&host.id)).all(&db.conn).await { + Ok(h) => h, + Err(e) => { + error!("Database error: {}", e); + return HttpResponse::InternalServerError().json(APIErrorsResponse { + errors: vec![APIError { + code: "ERR_DB_ERROR".to_string(), + message: "There was an error with the database query. Please try again later." + .to_string(), + path: None, + }], + }); + } + }; + + for c_override in config_overrides { + match c_override.delete(&db.conn).await { + Ok(_) => (), + Err(e) => { + error!("Database error: {}", e); + return HttpResponse::InternalServerError().json(APIErrorsResponse { + errors: vec![APIError { + code: "ERR_DB_ERROR".to_string(), + message: "There was an error with the database query. Please try again later." + .to_string(), + path: None, + }], + }); + } + } + } + + for c_override in &req.overrides { + let db_override = host_config_override::Model { + id: random_id("override"), + key: c_override.key.clone(), + value: match &c_override.value { + HostConfigOverrideDataOverrideValue::Boolean(v) => v.to_string(), + HostConfigOverrideDataOverrideValue::Numeric(v) => v.to_string(), + HostConfigOverrideDataOverrideValue::Other(v) => v.clone(), + }, + host: host.id.clone(), + }; + match db_override.into_active_model().insert(&db.conn).await { + Ok(_) => (), + Err(e) => { + error!("Database error: {}", e); + return HttpResponse::InternalServerError().json(APIErrorsResponse { + errors: vec![APIError { + code: "ERR_DB_ERROR".to_string(), + message: "There was an error with the database query. Please try again later." + .to_string(), + path: None, + }], + }); + } + } + } + + let config_overrides = match trifid_api_entities::entity::host_config_override::Entity::find().filter(host_config_override::Column::Host.eq(&host.id)).all(&db.conn).await { + Ok(h) => h, + Err(e) => { + error!("Database error: {}", e); + return HttpResponse::InternalServerError().json(APIErrorsResponse { + errors: vec![APIError { + code: "ERR_DB_ERROR".to_string(), + message: "There was an error with the database query. Please try again later." + .to_string(), + path: None, + }], + }); + } + }; + + let overrides: Vec = config_overrides.iter().map(|u| { + let val; + if u.value == "true" || u.value == "false" { + val = HostConfigOverrideDataOverrideValue::Boolean(u.value == "true"); + } else if u.value.chars().all(|c| c.is_numeric()) || u.value.starts_with('-') && u.value.chars().collect::>()[1..].iter().all(|c| c.is_numeric()) { + val = HostConfigOverrideDataOverrideValue::Numeric(u.value.parse().unwrap()); + } else { + val = HostConfigOverrideDataOverrideValue::Other(u.value.clone()); + } + HostConfigOverrideDataOverride { + key: u.key.clone(), + value: val, + } + }).collect(); + + HttpResponse::Ok().json(HostConfigOverrideResponse { + data: HostConfigOverrideData { + overrides, + }, + }) +} \ No newline at end of file From 5ca223da71a0f73a7e4e5c560fd0f0cfc2699054 Mon Sep 17 00:00:00 2001 From: core Date: Wed, 21 Jun 2023 21:05:50 -0400 Subject: [PATCH 02/17] hotfix tfclient version --- tfclient/Cargo.toml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/tfclient/Cargo.toml b/tfclient/Cargo.toml index 6cbb715..08f4cca 100644 --- a/tfclient/Cargo.toml +++ b/tfclient/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "tfclient" -version = "0.1.8" +version = "0.1.9" edition = "2021" description = "An open-source reimplementation of a Defined Networking-compatible client" license = "GPL-3.0-or-later" @@ -39,4 +39,4 @@ flate2 = "1.0.25" tar = "0.4.38" hex = "0.4.3" tempfile = "3.4.0" -sha2 = "0.10.6" \ No newline at end of file +sha2 = "0.10.6" From 7084501fb545f01934c399037032c708486703d0 Mon Sep 17 00:00:00 2001 From: core Date: Wed, 21 Jun 2023 21:06:36 -0400 Subject: [PATCH 03/17] upd lockfile --- Cargo.lock | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Cargo.lock b/Cargo.lock index 13d30af..93dd36c 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -3330,7 +3330,7 @@ dependencies = [ [[package]] name = "tfclient" -version = "0.1.8" +version = "0.1.9" dependencies = [ "base64 0.21.0", "base64-serde", From bc41810230f74d2cfeffcdacc8c3ed36f065a31e Mon Sep 17 00:00:00 2001 From: core Date: Wed, 21 Jun 2023 21:08:28 -0400 Subject: [PATCH 04/17] upd tfcli cargo manifest --- tfcli/Cargo.toml | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/tfcli/Cargo.toml b/tfcli/Cargo.toml index 673a357..c94d529 100644 --- a/tfcli/Cargo.toml +++ b/tfcli/Cargo.toml @@ -2,6 +2,11 @@ name = "tfcli" version = "0.1.0" edition = "2021" +description = "Command-line client for managing trifid-api" +license = "GPL-3.0-or-later" +documentation = "https://git.e3t.cc/~core/trifid" +homepage = "https://git.e3t.cc/~core/trifid" +repository = "https://git.e3t.cc/~core/trifid" # See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html From 2598a8efe0d9316f6147be2e181c1dd2bb144099 Mon Sep 17 00:00:00 2001 From: core Date: Wed, 21 Jun 2023 21:09:47 -0400 Subject: [PATCH 05/17] upd tfapi cargo manifest --- trifid-api/Cargo.toml | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/trifid-api/Cargo.toml b/trifid-api/Cargo.toml index 711bce2..56f9ffb 100644 --- a/trifid-api/Cargo.toml +++ b/trifid-api/Cargo.toml @@ -2,6 +2,11 @@ name = "trifid-api" version = "0.1.0" edition = "2021" +description = "Pure-rust Defined Networking compatible management server" +license = "GPL-3.0-or-later" +documentation = "https://git.e3t.cc/~core/trifid" +homepage = "https://git.e3t.cc/~core/trifid" +repository = "https://git.e3t.cc/~core/trifid" # See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html From 0637b4bad3eb2bcb40aca79f676a5fd07f8f8f68 Mon Sep 17 00:00:00 2001 From: core Date: Wed, 21 Jun 2023 21:11:56 -0400 Subject: [PATCH 06/17] publish _entities and _migration --- trifid-api/trifid_api_entities/Cargo.toml | 5 +++++ trifid-api/trifid_api_migration/Cargo.toml | 6 +++++- 2 files changed, 10 insertions(+), 1 deletion(-) diff --git a/trifid-api/trifid_api_entities/Cargo.toml b/trifid-api/trifid_api_entities/Cargo.toml index 73b20f4..141303c 100644 --- a/trifid-api/trifid_api_entities/Cargo.toml +++ b/trifid-api/trifid_api_entities/Cargo.toml @@ -2,6 +2,11 @@ name = "trifid_api_entities" version = "0.1.0" edition = "2021" +description = "Database entities for trifid-api" +license = "GPL-3.0-or-later" +documentation = "https://git.e3t.cc/~core/trifid" +homepage = "https://git.e3t.cc/~core/trifid" +repository = "https://git.e3t.cc/~core/trifid" # See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html diff --git a/trifid-api/trifid_api_migration/Cargo.toml b/trifid-api/trifid_api_migration/Cargo.toml index f090efb..b760105 100644 --- a/trifid-api/trifid_api_migration/Cargo.toml +++ b/trifid-api/trifid_api_migration/Cargo.toml @@ -2,7 +2,11 @@ name = "trifid_api_migration" version = "0.1.0" edition = "2021" -publish = false +description = "Database migrations for trifid-api" +license = "GPL-3.0-or-later" +documentation = "https://git.e3t.cc/~core/trifid" +homepage = "https://git.e3t.cc/~core/trifid" +repository = "https://git.e3t.cc/~core/trifid" [lib] name = "trifid_api_migration" From e9b54f08b13282c0dbd24a723e7aa1298e8c05e0 Mon Sep 17 00:00:00 2001 From: core Date: Thu, 22 Jun 2023 10:53:17 -0400 Subject: [PATCH 07/17] trifid-api 0.1.1, fix config generation --- trifid-api/Cargo.toml | 2 +- trifid-api/src/codegen/mod.rs | 74 +++++-- trifid-api/trifid_data/tfks.toml | 361 ------------------------------- 3 files changed, 54 insertions(+), 383 deletions(-) delete mode 100644 trifid-api/trifid_data/tfks.toml diff --git a/trifid-api/Cargo.toml b/trifid-api/Cargo.toml index 56f9ffb..fa3c0a2 100644 --- a/trifid-api/Cargo.toml +++ b/trifid-api/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "trifid-api" -version = "0.1.0" +version = "0.1.1" edition = "2021" description = "Pure-rust Defined Networking compatible management server" license = "GPL-3.0-or-later" diff --git a/trifid-api/src/codegen/mod.rs b/trifid-api/src/codegen/mod.rs index 101a046..05579c8 100644 --- a/trifid-api/src/codegen/mod.rs +++ b/trifid-api/src/codegen/mod.rs @@ -17,7 +17,8 @@ use crate::AppState; use ed25519_dalek::SigningKey; use ipnet::Ipv4Net; use log::{debug, error}; -use sea_orm::{ColumnTrait, EntityTrait, QueryFilter}; +use sea_orm::{ColumnTrait, Condition, EntityTrait, QueryFilter}; +use serde_yaml::{Mapping, Value}; use trifid_api_entities::entity::{ firewall_rule, host, host_config_override, host_static_address, network, organization, signing_ca, @@ -156,7 +157,7 @@ pub async fn generate_config( punchy: Some(NebulaConfigPunchy { punch: true, respond: true, - delay: "".to_string(), + delay: "1s".to_string(), }), cipher: NebulaConfigCipher::Aes, preferred_ranges: vec![], @@ -191,36 +192,68 @@ pub async fn generate_config( cidr: None, }]), }), - routines: 0, + routines: 1, stats: None, local_range: None, }; - // Merge with config overrides and re-parse - let config_str = serde_yaml::to_string(&nebula_config)?; - let mut value: serde_yaml::Value = serde_yaml::from_str(&config_str)?; + let mut val = Mapping::new(); - for (key, kv_value) in &info.config_overrides { - // split up the key - // a.b.c.d = ['a']['b']['c']['d'] = value - let key_split = key.split('.'); + for (k, v) in &info.config_overrides { + let key_split = k.split('.').collect::>(); - let mut current_val = &mut value; + let mut value = &mut val; - for key_iter in key_split { - current_val = current_val.get_mut(key_iter).ok_or("Invalid key-value override")?; + for ks_k in &key_split[..key_split.len()-1] { + if !value.contains_key(ks_k) { + value.insert(Value::String(ks_k.to_string()), Value::Mapping(Mapping::new())); + } + + value = value.get_mut(ks_k).ok_or("Invalid key-value pair")?.as_mapping_mut().unwrap(); } - *current_val = serde_yaml::from_str(kv_value)?; + value.insert(Value::String(key_split[key_split.len()-1].to_string()), serde_yaml::from_str(&v)?); } - let config_str_merged = serde_yaml::to_string(&value)?; + let overrides_value = Value::Mapping(val); - let nebula_config = serde_yaml::from_str(&config_str_merged)?; + debug!("{:?}", overrides_value); + + let mut value = serde_yaml::to_value(nebula_config)?; + + debug!("{:?}", value); + + merge_yaml(&mut value, overrides_value); + + debug!("{:?}", value); + + let nebula_config = serde_yaml::from_value(value)?; Ok((nebula_config, cert)) } +// This cursed abomination credit https://stackoverflow.com/questions/67727239/how-to-combine-including-nested-array-values-two-serde-yamlvalue-objects +fn merge_yaml(a: &mut serde_yaml::Value, b: serde_yaml::Value) { + match (a, b) { + (a @ &mut serde_yaml::Value::Mapping(_), serde_yaml::Value::Mapping(b)) => { + let a = a.as_mapping_mut().unwrap(); + for (k, v) in b { + if v.is_sequence() && a.contains_key(&k) && a[&k].is_sequence() { + let mut _b = a.get(&k).unwrap().as_sequence().unwrap().to_owned(); + _b.append(&mut v.as_sequence().unwrap().to_owned()); + a[&k] = serde_yaml::Value::from(_b); + continue; + } + if !a.contains_key(&k) {a.insert(k.to_owned(), v.to_owned());} + else { merge_yaml(&mut a[&k], v); } + + } + + } + (a, b) => *a = b, + } +} + pub async fn collect_info<'a>( db: &'a Data, host: &'a str, @@ -237,12 +270,12 @@ pub async fn collect_info<'a>( }; let host_config_overrides = trifid_api_entities::entity::host_config_override::Entity::find() - .filter(host_config_override::Column::Id.eq(&host.id)) + .filter(host_config_override::Column::Host.eq(&host.id)) .all(&db.conn) .await?; let _host_static_addresses = trifid_api_entities::entity::host_static_address::Entity::find() - .filter(host_static_address::Column::Id.eq(&host.id)) + .filter(host_static_address::Column::Host.eq(&host.id)) .all(&db.conn) .await?; @@ -267,8 +300,7 @@ pub async fn collect_info<'a>( let hosts = trifid_api_entities::entity::host::Entity::find() .filter(host::Column::Network.eq(&network.id)) - .filter(host::Column::IsRelay.eq(true)) - .filter(host::Column::IsLighthouse.eq(true)) + .filter(Condition::any().add(host::Column::IsRelay.eq(true)).add(host::Column::IsLighthouse.eq(true))) .all(&db.conn) .await?; @@ -356,7 +388,7 @@ pub async fn collect_info<'a>( } else { format!("{}-{}", u.port_range_from, u.port_range_to) }), - proto: Some(u.protocol.clone()), + proto: Some(u.protocol.clone().to_lowercase()), ca_name: None, ca_sha: None, host: if u.allowed_role_id.is_some() { diff --git a/trifid-api/trifid_data/tfks.toml b/trifid-api/trifid_data/tfks.toml deleted file mode 100644 index e527be7..0000000 --- a/trifid-api/trifid_data/tfks.toml +++ /dev/null @@ -1,361 +0,0 @@ -[[hosts]] -id = "host-IPNHZ2XBXJDY2WYOYG7709CBJ8" -current_signing_key = 1 -current_client_key = 2 -current_config = 2 -current_cert = 2 - -[[hosts.certs]] -id = 1 - -[hosts.certs.cert] -signature = [112, 198, 103, 65, 58, 33, 254, 185, 255, 1, 204, 111, 236, 234, 55, 143, 24, 27, 104, 53, 89, 106, 209, 53, 201, 35, 248, 55, 109, 120, 219, 26, 171, 234, 181, 70, 174, 177, 12, 121, 190, 67, 73, 104, 218, 2, 139, 120, 116, 174, 106, 120, 56, 162, 143, 162, 143, 199, 237, 151, 215, 129, 245, 8] - -[hosts.certs.cert.details] -name = "asd" -ips = ["10.17.2.3/15"] -subnets = [] -groups = ["role:role-A4YTNBOMCFJNK5OAKHQCUUVIL8"] -public_key = [10, 175, 118, 186, 191, 43, 172, 0, 152, 238, 83, 31, 38, 79, 189, 76, 149, 38, 157, 84, 200, 210, 0, 95, 37, 169, 196, 77, 214, 209, 91, 10] -is_ca = false -issuer = "9a4dd7cb5c3a086b0173f126bbf20b85ac7886a2129d2f8573acc2e20f09ec1f" - -[hosts.certs.cert.details.not_before] -secs_since_epoch = 1684171628 -nanos_since_epoch = 68795993 - -[hosts.certs.cert.details.not_after] -secs_since_epoch = 1716312428 -nanos_since_epoch = 68796023 - -[[hosts.certs]] -id = 2 - -[hosts.certs.cert] -signature = [134, 249, 92, 208, 133, 181, 164, 230, 242, 79, 132, 140, 164, 28, 159, 165, 55, 176, 140, 73, 208, 50, 53, 184, 178, 242, 62, 90, 55, 187, 245, 231, 22, 89, 161, 9, 181, 56, 135, 163, 93, 102, 69, 34, 51, 139, 158, 181, 5, 207, 2, 87, 100, 236, 215, 116, 109, 43, 186, 148, 200, 235, 99, 7] - -[hosts.certs.cert.details] -name = "addsd" -ips = ["10.17.2.3/15"] -subnets = [] -groups = ["role:role-A4YTNBOMCFJNK5OAKHQCUUVIL8"] -public_key = [78, 139, 195, 146, 198, 211, 251, 196, 238, 154, 134, 158, 111, 25, 198, 228, 195, 108, 242, 146, 16, 45, 98, 155, 152, 116, 114, 218, 226, 137, 182, 11] -is_ca = false -issuer = "9a4dd7cb5c3a086b0173f126bbf20b85ac7886a2129d2f8573acc2e20f09ec1f" - -[hosts.certs.cert.details.not_before] -secs_since_epoch = 1684171718 -nanos_since_epoch = 140841799 - -[hosts.certs.cert.details.not_after] -secs_since_epoch = 1716312518 -nanos_since_epoch = 140841859 - -[[hosts.config]] -id = 1 - -[hosts.config.config] -routines = 0 - -[hosts.config.config.pki] -ca = """ ------BEGIN NEBULA CERTIFICATE-----\r -Cl0KK2NvcmVAY29yZWRvZXMuZGV2J3MgT3JnYW5pemF0aW9uIFNpZ25pbmcgQ0Eo\r -y7iEowYwy+2S0AY6II2RV3kVBopKoTe3j+aT1LbZuWTR/5oQGra185GB5W63QAES\r -QGRgfmRuJOzhtWwwU4BGMo47uoncMGV41sz1NYcvwmruwhJDaYYJ51DLz3v5bYZV\r -LCxfFB661cvoq1OZ7G5ZcgY=\r ------END NEBULA CERTIFICATE-----\r -""" -cert = """ ------BEGIN NEBULA CERTIFICATE-----\r -CoYBCgNhc2QSCYOExFCAgPj/DyIkcm9sZTpyb2xlLUE0WVROQk9NQ0ZKTks1T0FL\r -SFFDVVVWSUw4KOzWiaMGMOyys7IGOiAKr3a6vyusAJjuUx8mT71MlSadVMjSAF8l\r -qcRN1tFbCkogmk3Xy1w6CGsBc/Emu/ILhax4hqISnS+Fc6zC4g8J7B8SQHDGZ0E6\r -If65/wHMb+zqN48YG2g1WWrRNckj+DdteNsaq+q1Rq6xDHm+Q0lo2gKLeHSuang4\r -oo+ij8ftl9eB9Qg=\r ------END NEBULA CERTIFICATE-----\r -""" -disconnect_invalid = true - -[hosts.config.config.lighthouse] -interval = 60 - -[hosts.config.config.listen] -host = "[::]" -read_buffer = 10485760 -write_buffer = 10485760 - -[hosts.config.config.punchy] -punch = true -respond = true -delay = "" - -[hosts.config.config.relay] - -[hosts.config.config.tun] -dev = "trifid1" -drop_local_broadcast = true -drop_multicast = true - -[hosts.config.config.firewall] -inbound = [] - -[[hosts.config.config.firewall.outbound]] -port = "any" -proto = "any" -host = "any" - -[[hosts.config]] -id = 2 - -[hosts.config.config] -routines = 0 - -[hosts.config.config.pki] -ca = """ ------BEGIN NEBULA CERTIFICATE-----\r -Cl0KK2NvcmVAY29yZWRvZXMuZGV2J3MgT3JnYW5pemF0aW9uIFNpZ25pbmcgQ0Eo\r -y7iEowYwy+2S0AY6II2RV3kVBopKoTe3j+aT1LbZuWTR/5oQGra185GB5W63QAES\r -QGRgfmRuJOzhtWwwU4BGMo47uoncMGV41sz1NYcvwmruwhJDaYYJ51DLz3v5bYZV\r -LCxfFB661cvoq1OZ7G5ZcgY=\r ------END NEBULA CERTIFICATE-----\r -""" -cert = """ ------BEGIN NEBULA CERTIFICATE-----\r -CogBCgVhZGRzZBIJg4TEUICA+P8PIiRyb2xlOnJvbGUtQTRZVE5CT01DRkpOSzVP\r -QUtIUUNVVVZJTDgoxteJowYwxrOzsgY6IE6Lw5LG0/vE7pqGnm8ZxuTDbPKSEC1i\r -m5h0ctriibYLSiCaTdfLXDoIawFz8Sa78guFrHiGohKdL4VzrMLiDwnsHxJAhvlc\r -0IW1pObyT4SMpByfpTewjEnQMjW4svI+Wje79ecWWaEJtTiHo11mRSIzi561Bc8C\r -V2Ts13RtK7qUyOtjBw==\r ------END NEBULA CERTIFICATE-----\r -""" -disconnect_invalid = true - -[hosts.config.config.lighthouse] -interval = 60 - -[hosts.config.config.listen] -host = "[::]" -read_buffer = 10485760 -write_buffer = 10485760 - -[hosts.config.config.punchy] -punch = true -respond = true -delay = "" - -[hosts.config.config.relay] - -[hosts.config.config.tun] -dev = "trifid1" -drop_local_broadcast = true -drop_multicast = true - -[hosts.config.config.firewall] -inbound = [] - -[[hosts.config.config.firewall.outbound]] -port = "any" -proto = "any" -host = "any" - -[[hosts.signing_keys]] -id = 0 -key = [108, 174, 65, 117, 166, 239, 62, 150, 81, 111, 185, 79, 158, 206, 104, 43, 163, 224, 206, 219, 147, 71, 158, 88, 103, 149, 113, 152, 123, 41, 78, 255] - -[[hosts.signing_keys]] -id = 1 -key = [119, 226, 183, 227, 53, 121, 14, 141, 125, 165, 249, 103, 28, 60, 102, 111, 242, 63, 26, 52, 87, 29, 29, 114, 11, 62, 138, 121, 213, 245, 193, 212] - -[[hosts.client_keys]] -id = 1 -dh_pub = [10, 175, 118, 186, 191, 43, 172, 0, 152, 238, 83, 31, 38, 79, 189, 76, 149, 38, 157, 84, 200, 210, 0, 95, 37, 169, 196, 77, 214, 209, 91, 10] -ed_pub = [135, 237, 110, 71, 189, 155, 246, 66, 50, 229, 80, 254, 93, 99, 35, 29, 87, 138, 132, 193, 118, 216, 218, 60, 142, 178, 42, 126, 182, 25, 31, 103] - -[[hosts.client_keys]] -id = 2 -dh_pub = [78, 139, 195, 146, 198, 211, 251, 196, 238, 154, 134, 158, 111, 25, 198, 228, 195, 108, 242, 146, 16, 45, 98, 155, 152, 116, 114, 218, 226, 137, 182, 11] -ed_pub = [178, 77, 253, 159, 81, 137, 20, 14, 184, 230, 73, 111, 130, 129, 15, 184, 114, 90, 133, 147, 178, 252, 197, 75, 82, 33, 21, 5, 38, 238, 57, 84] - -[[hosts]] -id = "host-2PXIOHLPQA3CQL8O7XD6CXMMRM" -current_signing_key = 1 -current_client_key = 2 -current_config = 2 -current_cert = 2 - -[[hosts.certs]] -id = 1 - -[hosts.certs.cert] -signature = [160, 205, 80, 112, 16, 205, 155, 249, 221, 26, 47, 128, 2, 59, 15, 102, 153, 174, 61, 35, 207, 233, 42, 242, 212, 28, 133, 40, 189, 1, 234, 67, 24, 109, 152, 248, 130, 96, 48, 104, 69, 0, 178, 30, 103, 76, 33, 179, 216, 92, 191, 89, 6, 236, 136, 216, 9, 208, 189, 16, 140, 132, 209, 2] - -[hosts.certs.cert.details] -name = "testhost4" -ips = ["10.17.4.2/15"] -subnets = [] -groups = ["role:role-A4YTNBOMCFJNK5OAKHQCUUVIL8"] -public_key = [40, 175, 28, 13, 183, 102, 108, 21, 53, 79, 113, 191, 101, 74, 77, 151, 66, 146, 250, 155, 196, 38, 178, 44, 41, 186, 71, 1, 152, 237, 245, 93] -is_ca = false -issuer = "9a4dd7cb5c3a086b0173f126bbf20b85ac7886a2129d2f8573acc2e20f09ec1f" - -[hosts.certs.cert.details.not_before] -secs_since_epoch = 1684172253 -nanos_since_epoch = 219759539 - -[hosts.certs.cert.details.not_after] -secs_since_epoch = 1716313053 -nanos_since_epoch = 219759579 - -[[hosts.certs]] -id = 2 - -[hosts.certs.cert] -signature = [54, 210, 5, 3, 189, 187, 221, 142, 238, 142, 175, 248, 12, 128, 6, 58, 99, 44, 248, 198, 51, 3, 152, 118, 113, 46, 41, 191, 138, 15, 120, 103, 170, 24, 229, 27, 241, 182, 236, 220, 51, 117, 224, 118, 191, 25, 84, 111, 100, 15, 53, 234, 132, 214, 213, 66, 95, 8, 44, 162, 212, 60, 151, 13] - -[hosts.certs.cert.details] -name = "testhost4" -ips = ["10.17.4.2/15"] -subnets = [] -groups = ["role:role-A4YTNBOMCFJNK5OAKHQCUUVIL8"] -public_key = [4, 249, 63, 6, 25, 145, 63, 132, 106, 48, 243, 192, 249, 159, 185, 160, 196, 146, 24, 7, 241, 160, 121, 122, 212, 249, 19, 213, 158, 105, 142, 86] -is_ca = false -issuer = "9a4dd7cb5c3a086b0173f126bbf20b85ac7886a2129d2f8573acc2e20f09ec1f" - -[hosts.certs.cert.details.not_before] -secs_since_epoch = 1684172313 -nanos_since_epoch = 739770378 - -[hosts.certs.cert.details.not_after] -secs_since_epoch = 1716313113 -nanos_since_epoch = 739770429 - -[[hosts.config]] -id = 1 - -[hosts.config.config] -routines = 0 - -[hosts.config.config.pki] -ca = """ ------BEGIN NEBULA CERTIFICATE-----\r -Cl0KK2NvcmVAY29yZWRvZXMuZGV2J3MgT3JnYW5pemF0aW9uIFNpZ25pbmcgQ0Eo\r -y7iEowYwy+2S0AY6II2RV3kVBopKoTe3j+aT1LbZuWTR/5oQGra185GB5W63QAES\r -QGRgfmRuJOzhtWwwU4BGMo47uoncMGV41sz1NYcvwmruwhJDaYYJ51DLz3v5bYZV\r -LCxfFB661cvoq1OZ7G5ZcgY=\r ------END NEBULA CERTIFICATE-----\r -""" -cert = """ ------BEGIN NEBULA CERTIFICATE-----\r -CowBCgl0ZXN0aG9zdDQSCYKIxFCAgPj/DyIkcm9sZTpyb2xlLUE0WVROQk9NQ0ZK\r -Tks1T0FLSFFDVVVWSUw4KN3biaMGMN23s7IGOiAorxwNt2ZsFTVPcb9lSk2XQpL6\r -m8QmsiwpukcBmO31XUogmk3Xy1w6CGsBc/Emu/ILhax4hqISnS+Fc6zC4g8J7B8S\r -QKDNUHAQzZv53RovgAI7D2aZrj0jz+kq8tQchSi9AepDGG2Y+IJgMGhFALIeZ0wh\r -s9hcv1kG7IjYCdC9EIyE0QI=\r ------END NEBULA CERTIFICATE-----\r -""" -disconnect_invalid = true - -[hosts.config.config.lighthouse] -am_lighthouse = true -interval = 60 - -[hosts.config.config.listen] -host = "[::]" -port = 5679 -read_buffer = 10485760 -write_buffer = 10485760 - -[hosts.config.config.punchy] -punch = true -respond = true -delay = "" - -[hosts.config.config.relay] - -[hosts.config.config.tun] -dev = "trifid1" -drop_local_broadcast = true -drop_multicast = true - -[hosts.config.config.firewall] -inbound = [] - -[[hosts.config.config.firewall.outbound]] -port = "any" -proto = "any" -host = "any" - -[[hosts.config]] -id = 2 - -[hosts.config.config] -routines = 0 - -[hosts.config.config.pki] -ca = """ ------BEGIN NEBULA CERTIFICATE-----\r -Cl0KK2NvcmVAY29yZWRvZXMuZGV2J3MgT3JnYW5pemF0aW9uIFNpZ25pbmcgQ0Eo\r -y7iEowYwy+2S0AY6II2RV3kVBopKoTe3j+aT1LbZuWTR/5oQGra185GB5W63QAES\r -QGRgfmRuJOzhtWwwU4BGMo47uoncMGV41sz1NYcvwmruwhJDaYYJ51DLz3v5bYZV\r -LCxfFB661cvoq1OZ7G5ZcgY=\r ------END NEBULA CERTIFICATE-----\r -""" -cert = """ ------BEGIN NEBULA CERTIFICATE-----\r -CowBCgl0ZXN0aG9zdDQSCYKIxFCAgPj/DyIkcm9sZTpyb2xlLUE0WVROQk9NQ0ZK\r -Tks1T0FLSFFDVVVWSUw4KJnciaMGMJm4s7IGOiAE+T8GGZE/hGow88D5n7mgxJIY\r -B/GgeXrU+RPVnmmOVkogmk3Xy1w6CGsBc/Emu/ILhax4hqISnS+Fc6zC4g8J7B8S\r -QDbSBQO9u92O7o6v+AyABjpjLPjGMwOYdnEuKb+KD3hnqhjlG/G27NwzdeB2vxlU\r -b2QPNeqE1tVCXwgsotQ8lw0=\r ------END NEBULA CERTIFICATE-----\r -""" -disconnect_invalid = true - -[hosts.config.config.lighthouse] -am_lighthouse = true -interval = 60 - -[hosts.config.config.listen] -host = "[::]" -port = 5677 -read_buffer = 10485760 -write_buffer = 10485760 - -[hosts.config.config.punchy] -punch = true -respond = true -delay = "" - -[hosts.config.config.relay] - -[hosts.config.config.tun] -dev = "trifid1" -drop_local_broadcast = true -drop_multicast = true - -[hosts.config.config.firewall] -inbound = [] - -[[hosts.config.config.firewall.outbound]] -port = "any" -proto = "any" -host = "any" - -[[hosts.signing_keys]] -id = 0 -key = [255, 84, 221, 121, 87, 225, 7, 12, 236, 8, 209, 175, 98, 20, 119, 146, 92, 177, 79, 121, 24, 243, 247, 113, 106, 212, 183, 155, 208, 55, 219, 135] - -[[hosts.signing_keys]] -id = 1 -key = [98, 159, 193, 58, 183, 156, 75, 17, 70, 103, 112, 6, 71, 197, 167, 152, 99, 210, 199, 40, 49, 13, 101, 72, 57, 34, 221, 237, 142, 29, 144, 175] - -[[hosts.client_keys]] -id = 1 -dh_pub = [40, 175, 28, 13, 183, 102, 108, 21, 53, 79, 113, 191, 101, 74, 77, 151, 66, 146, 250, 155, 196, 38, 178, 44, 41, 186, 71, 1, 152, 237, 245, 93] -ed_pub = [247, 172, 97, 223, 43, 24, 248, 133, 118, 219, 227, 72, 95, 25, 167, 179, 115, 225, 73, 211, 161, 216, 95, 140, 151, 59, 118, 39, 122, 136, 144, 245] - -[[hosts.client_keys]] -id = 2 -dh_pub = [4, 249, 63, 6, 25, 145, 63, 132, 106, 48, 243, 192, 249, 159, 185, 160, 196, 146, 24, 7, 241, 160, 121, 122, 212, 249, 19, 213, 158, 105, 142, 86] -ed_pub = [55, 82, 153, 75, 220, 207, 87, 221, 50, 200, 77, 9, 242, 136, 64, 91, 60, 96, 31, 100, 58, 162, 150, 147, 109, 109, 117, 188, 164, 217, 248, 140] From 8d4d2d42643566c02d18b76d737f5c46b0cacc72 Mon Sep 17 00:00:00 2001 From: core Date: Thu, 22 Jun 2023 10:59:33 -0400 Subject: [PATCH 08/17] its at least a functional mess --- Cargo.lock | 2 +- trifid-api/src/codegen/mod.rs | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index 93dd36c..9a1a78c 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -3633,7 +3633,7 @@ dependencies = [ [[package]] name = "trifid-api" -version = "0.1.0" +version = "0.1.1" dependencies = [ "actix-cors", "actix-request-identifier", diff --git a/trifid-api/src/codegen/mod.rs b/trifid-api/src/codegen/mod.rs index 05579c8..fd6ea04 100644 --- a/trifid-api/src/codegen/mod.rs +++ b/trifid-api/src/codegen/mod.rs @@ -212,7 +212,7 @@ pub async fn generate_config( value = value.get_mut(ks_k).ok_or("Invalid key-value pair")?.as_mapping_mut().unwrap(); } - value.insert(Value::String(key_split[key_split.len()-1].to_string()), serde_yaml::from_str(&v)?); + value.insert(Value::String(key_split[key_split.len()-1].to_string()), serde_yaml::from_str(v)?); } let overrides_value = Value::Mapping(val); From e6e646b8883d5e4be5bbd85af68bb9aaac48e3ff Mon Sep 17 00:00:00 2001 From: core Date: Thu, 22 Jun 2023 11:09:59 -0400 Subject: [PATCH 09/17] a way better config merge system --- trifid-api/Cargo.toml | 2 +- trifid-api/src/codegen/mod.rs | 58 ++++++++--------------------------- 2 files changed, 14 insertions(+), 46 deletions(-) diff --git a/trifid-api/Cargo.toml b/trifid-api/Cargo.toml index fa3c0a2..8aee703 100644 --- a/trifid-api/Cargo.toml +++ b/trifid-api/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "trifid-api" -version = "0.1.1" +version = "0.1.2" edition = "2021" description = "Pure-rust Defined Networking compatible management server" license = "GPL-3.0-or-later" diff --git a/trifid-api/src/codegen/mod.rs b/trifid-api/src/codegen/mod.rs index fd6ea04..1b8df99 100644 --- a/trifid-api/src/codegen/mod.rs +++ b/trifid-api/src/codegen/mod.rs @@ -197,63 +197,31 @@ pub async fn generate_config( local_range: None, }; - let mut val = Mapping::new(); + // Merge with config overrides and re-parse + let config_str = serde_yaml::to_string(&nebula_config)?; + let mut value: serde_yaml::Value = serde_yaml::from_str(&config_str)?; - for (k, v) in &info.config_overrides { - let key_split = k.split('.').collect::>(); + for (key, kv_value) in &info.config_overrides { + // split up the key + // a.b.c.d = ['a']['b']['c']['d'] = value + let key_split = key.split('.').collect::>(); - let mut value = &mut val; + let mut current_val = &mut value; - for ks_k in &key_split[..key_split.len()-1] { - if !value.contains_key(ks_k) { - value.insert(Value::String(ks_k.to_string()), Value::Mapping(Mapping::new())); - } - - value = value.get_mut(ks_k).ok_or("Invalid key-value pair")?.as_mapping_mut().unwrap(); + for key_iter in &key_split[..key_split.len()-1] { + current_val = current_val.as_mapping_mut().unwrap().entry(Value::String(key_iter.to_string())).or_insert(Value::Mapping(Mapping::new())); } - value.insert(Value::String(key_split[key_split.len()-1].to_string()), serde_yaml::from_str(v)?); + current_val.as_mapping_mut().unwrap().insert(Value::String(key_split[key_split.len()-1].to_string()), serde_yaml::from_str(kv_value)?); } - let overrides_value = Value::Mapping(val); + let config_str_merged = serde_yaml::to_string(&value)?; - debug!("{:?}", overrides_value); - - let mut value = serde_yaml::to_value(nebula_config)?; - - debug!("{:?}", value); - - merge_yaml(&mut value, overrides_value); - - debug!("{:?}", value); - - let nebula_config = serde_yaml::from_value(value)?; + let nebula_config = serde_yaml::from_str(&config_str_merged)?; Ok((nebula_config, cert)) } -// This cursed abomination credit https://stackoverflow.com/questions/67727239/how-to-combine-including-nested-array-values-two-serde-yamlvalue-objects -fn merge_yaml(a: &mut serde_yaml::Value, b: serde_yaml::Value) { - match (a, b) { - (a @ &mut serde_yaml::Value::Mapping(_), serde_yaml::Value::Mapping(b)) => { - let a = a.as_mapping_mut().unwrap(); - for (k, v) in b { - if v.is_sequence() && a.contains_key(&k) && a[&k].is_sequence() { - let mut _b = a.get(&k).unwrap().as_sequence().unwrap().to_owned(); - _b.append(&mut v.as_sequence().unwrap().to_owned()); - a[&k] = serde_yaml::Value::from(_b); - continue; - } - if !a.contains_key(&k) {a.insert(k.to_owned(), v.to_owned());} - else { merge_yaml(&mut a[&k], v); } - - } - - } - (a, b) => *a = b, - } -} - pub async fn collect_info<'a>( db: &'a Data, host: &'a str, From f06a725d9b0fa1a77ceb09d699204531a8f274fe Mon Sep 17 00:00:00 2001 From: core Date: Thu, 22 Jun 2023 11:12:53 -0400 Subject: [PATCH 10/17] test keystore --- trifid-api/trifiddata/tfks.toml | 98 +++++++++++++++++++++++++++++++++ 1 file changed, 98 insertions(+) create mode 100644 trifid-api/trifiddata/tfks.toml diff --git a/trifid-api/trifiddata/tfks.toml b/trifid-api/trifiddata/tfks.toml new file mode 100644 index 0000000..05aaf7a --- /dev/null +++ b/trifid-api/trifiddata/tfks.toml @@ -0,0 +1,98 @@ +[[hosts]] +id = "host-CAJDSM36900G2MFGFNIODZUG2G" +current_signing_key = 0 +current_client_key = 1 +current_config = 1 +current_cert = 1 + +[[hosts.certs]] +id = 1 + +[hosts.certs.cert] +signature = [254, 145, 36, 202, 32, 234, 248, 2, 147, 188, 207, 151, 147, 246, 100, 22, 114, 174, 221, 91, 62, 0, 48, 23, 106, 196, 75, 27, 116, 203, 68, 41, 110, 118, 85, 76, 230, 19, 128, 163, 134, 96, 121, 9, 227, 100, 174, 173, 144, 145, 149, 79, 189, 252, 126, 4, 113, 231, 141, 69, 77, 108, 48, 4] + +[hosts.certs.cert.details] +name = "Test Host" +ips = ["10.16.1.1/15"] +subnets = [] +groups = ["role:role-IRN57I1D5L3EOI3CDDU2TNBS5W"] +public_key = [43, 106, 145, 119, 55, 49, 4, 83, 171, 182, 60, 167, 213, 135, 126, 129, 148, 82, 15, 219, 155, 146, 132, 112, 141, 147, 46, 131, 207, 175, 199, 15] +is_ca = false +issuer = "90e0d7de2b241f3cdd7005e392f5c9e45277e2735edf90602424cbec786b6f32" + +[hosts.certs.cert.details.not_before] +secs_since_epoch = 1687446533 +nanos_since_epoch = 957200472 + +[hosts.certs.cert.details.not_after] +secs_since_epoch = 1719587333 +nanos_since_epoch = 957200502 + +[[hosts.config]] +id = 1 + +[hosts.config.config.pki] +ca = """ +-----BEGIN NEBULA CERTIFICATE-----\r +Cl0KK2NvcmVAY29yZWRvZXMuZGV2J3MgT3JnYW5pemF0aW9uIFNpZ25pbmcgQ0Eo\r +sN2upAYwsJK90QY6IHetWlUyvE9ka3Q4OFRaJGeOLH98I5uqEwO0temq88RJQAES\r +QG7FI2jb0M83FUYpqX70a4DlQA4EvsyjuOiDp2gm0jn5lgaPe3rZbuYuJ114zSO4\r +9QZKdFiTpeGoZkaikJJz0ws=\r +-----END NEBULA CERTIFICATE-----\r +""" +cert = """ +-----BEGIN NEBULA CERTIFICATE-----\r +CowBCglUZXN0IEhvc3QSCYGCwFCAgPj/DyIkcm9sZTpyb2xlLUlSTjU3STFENUwz\r +RU9JM0NERFUyVE5CUzVXKIXI0aQGMIWk+7MGOiArapF3NzEEU6u2PKfVh36BlFIP\r +25uShHCNky6Dz6/HD0ogkODX3iskHzzdcAXjkvXJ5FJ34nNe35BgJCTL7HhrbzIS\r +QP6RJMog6vgCk7zPl5P2ZBZyrt1bPgAwF2rESxt0y0QpbnZVTOYTgKOGYHkJ42Su\r +rZCRlU+9/H4EceeNRU1sMAQ=\r +-----END NEBULA CERTIFICATE-----\r +""" +disconnect_invalid = true + +[hosts.config.config.lighthouse] +interval = 60 + +[hosts.config.config.listen] +host = "[::]" +read_buffer = 10485760 +write_buffer = 10485760 + +[hosts.config.config.punchy] +punch = true +respond = true + +[hosts.config.config.relay] + +[hosts.config.config.tun] +dev = "trifid1" +drop_local_broadcast = true +drop_multicast = true + +[[hosts.config.config.firewall.inbound]] +port = "any" +proto = "icmp" +host = "any" + +[[hosts.config.config.firewall.outbound]] +port = "any" +proto = "any" +host = "any" + +[hosts.config.config.stats] +type = "prometheus" +listen = "0.0.0.0:8788" +path = "/metrics" +interval = "10s" +message_metrics = true +lighthouse_metrics = true + +[[hosts.signing_keys]] +id = 0 +key = [23, 88, 206, 16, 216, 58, 12, 80, 3, 178, 254, 16, 93, 137, 109, 69, 27, 111, 30, 32, 27, 194, 171, 200, 109, 69, 29, 45, 199, 174, 119, 46] + +[[hosts.client_keys]] +id = 1 +dh_pub = [43, 106, 145, 119, 55, 49, 4, 83, 171, 182, 60, 167, 213, 135, 126, 129, 148, 82, 15, 219, 155, 146, 132, 112, 141, 147, 46, 131, 207, 175, 199, 15] +ed_pub = [62, 181, 68, 68, 230, 78, 207, 233, 92, 252, 148, 118, 38, 84, 233, 54, 98, 220, 174, 146, 240, 37, 197, 19, 254, 137, 181, 241, 240, 83, 14, 74] From d90e1f1d53aed922d87c7c72d04925448a777644 Mon Sep 17 00:00:00 2001 From: core Date: Fri, 23 Jun 2023 19:13:16 -0400 Subject: [PATCH 11/17] docker --- Dockerfile | 9 +++++++++ 1 file changed, 9 insertions(+) create mode 100644 Dockerfile diff --git a/Dockerfile b/Dockerfile new file mode 100644 index 0000000..8a4b58f --- /dev/null +++ b/Dockerfile @@ -0,0 +1,9 @@ +FROM rust:latest + +COPY trifid-pki /trifid-pki +COPY dnapi-rs /dnapi-rs +COPY trifid-api /trifid-api + +RUN cd /trifid-api && cargo build --release && cp target/release/trifid-api /bin/trifid-api + +CMD ["/bin/trifid-api"] From 47fd5b2d934d33aa73485cd943a102f599a29074 Mon Sep 17 00:00:00 2001 From: core Date: Fri, 23 Jun 2023 19:21:01 -0400 Subject: [PATCH 12/17] update readme --- README.md | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) diff --git a/README.md b/README.md index 2fbff0d..581a97f 100644 --- a/README.md +++ b/README.md @@ -19,8 +19,9 @@ trifid-api feature table: | Feature | trifid-api | api.defined.net | |---------------------------------------------|--------------|-----------------| | Enroll in sites with dnclient | Yes | Yes | -| Automatic config update polling by dnclient | Not yet | Yes | -| Group-based firewalling | Not yet | Yes | +| Automatic config update polling by dnclient | Yes | Yes | +| Group-based firewalling | Yes | Yes | +| All config features | Yes | Not officially | | SSO authentication | Not yet | Yes | | Open-source server | Yes | No | @@ -33,3 +34,6 @@ tfclient feature table: | Poll the API server for config updates | Yes | Yes | | Secure Ed25519 signing for API communication | Yes | Yes | +# Documentation + +Documentation work is underway. You can find a link to all documentation on the main project page [here](https://hub.e3t.cc/~core/trifid). From e7828df6eaa1dc67fd07152c221a692cef7fe186 Mon Sep 17 00:00:00 2001 From: core Date: Fri, 23 Jun 2023 20:10:19 -0400 Subject: [PATCH 13/17] hotfix: 0-length POST request on enrollment --- Cargo.lock | 2 +- tfcli/Cargo.toml | 4 ++-- tfcli/src/host.rs | 4 ++-- 3 files changed, 5 insertions(+), 5 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index 9a1a78c..9436ea5 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -3633,7 +3633,7 @@ dependencies = [ [[package]] name = "trifid-api" -version = "0.1.1" +version = "0.1.2" dependencies = [ "actix-cors", "actix-request-identifier", diff --git a/tfcli/Cargo.toml b/tfcli/Cargo.toml index c94d529..fbebddd 100644 --- a/tfcli/Cargo.toml +++ b/tfcli/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "tfcli" -version = "0.1.0" +version = "0.1.1" edition = "2021" description = "Command-line client for managing trifid-api" license = "GPL-3.0-or-later" @@ -19,4 +19,4 @@ tokio = { version = "1", features = ["full"] } dirs = "5.0.1" qr2term = "0.3.1" ipnet = "2.7.2" -serde_json = "1.0.96" \ No newline at end of file +serde_json = "1.0.96" diff --git a/tfcli/src/host.rs b/tfcli/src/host.rs index 57a1ac7..d550f80 100644 --- a/tfcli/src/host.rs +++ b/tfcli/src/host.rs @@ -375,7 +375,7 @@ pub async fn enroll_host(id: String, server: Url) -> Result<(), Box> let token = format!("{} {}", session_token, auth_token); - let res = client.post(server.join(&format!("/v1/hosts/{}/enrollment-code", id))?).bearer_auth(token).send().await?; + let res = client.post(server.join(&format!("/v1/hosts/{}/enrollment-code", id))?).header("content-length", 0).bearer_auth(token).send().await?; if res.status().is_success() { let resp: EnrollmentResponse = res.json().await?; @@ -637,4 +637,4 @@ pub async fn unset_override(id: String, key: String, server: Url) -> Result<(), } Ok(()) -} \ No newline at end of file +} From 170d84526e813c1c04b8d2fd63c9ad262e8e51e4 Mon Sep 17 00:00:00 2001 From: core Date: Fri, 23 Jun 2023 21:01:13 -0400 Subject: [PATCH 14/17] docs update --- Cargo.lock | 2 +- docs/tfclient/index.md | 3 +++ docs/tfclient/untested_os.md | 13 +++++++++++++ docs/tfclient/why_not_this_os.md | 9 +++++++++ index.md | 27 +++++++++++++++++++++++++++ 5 files changed, 53 insertions(+), 1 deletion(-) create mode 100644 docs/tfclient/index.md create mode 100644 docs/tfclient/untested_os.md create mode 100644 docs/tfclient/why_not_this_os.md diff --git a/Cargo.lock b/Cargo.lock index 9436ea5..7013956 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -3315,7 +3315,7 @@ checksum = "222a222a5bfe1bba4a77b45ec488a741b3cb8872e5e499451fd7d0129c9c7c3d" [[package]] name = "tfcli" -version = "0.1.0" +version = "0.1.1" dependencies = [ "clap 4.2.7", "dirs 5.0.1", diff --git a/docs/tfclient/index.md b/docs/tfclient/index.md new file mode 100644 index 0000000..4777063 --- /dev/null +++ b/docs/tfclient/index.md @@ -0,0 +1,3 @@ +# tfclient - a Rust DNClient alternative + +TODO \ No newline at end of file diff --git a/docs/tfclient/untested_os.md b/docs/tfclient/untested_os.md new file mode 100644 index 0000000..9227cf8 --- /dev/null +++ b/docs/tfclient/untested_os.md @@ -0,0 +1,13 @@ +# Help us out - test tfclient on new platforms + +There are [lots](index.md#Where_does_trifid_work?) of operating systems in which `tfclient` *should* work, but due to a lack of devices, it cannot be tested. If you have a system running one of these devices and want to help out the project, please test tfclient for functionality on your device! + +
+ Notice: While tfclient is almost always perfectly safe, there are always risks to running untested software on production machines. Be careful out there! +
+ +Any findings, positive or negative, can be posted straight to [trifid-devel](https://lists.e3t.cc/~core/trifid-devel). + +Thanks! + +[Return home](index.md) \ No newline at end of file diff --git a/docs/tfclient/why_not_this_os.md b/docs/tfclient/why_not_this_os.md new file mode 100644 index 0000000..d34e562 --- /dev/null +++ b/docs/tfclient/why_not_this_os.md @@ -0,0 +1,9 @@ +# Why cant tfclient support XXXXX? + +There are limits to what operating systems and architectures tfclient can support. As you may know, tfclient is based upon the [Nebula](https://github.com/slackhq/nebula) project, maintained by Slack. tfclient can only support architectures and operating systems that [Nebula itself supports](https://github.com/slackhq/nebula/releases/). + +In addition, tfclient, being written in Rust, can only function in environments [where Rust compiles well](https://doc.rust-lang.org/nightly/rustc/platform-support.html). For example, this rules out MIPS - `rustc` currently does not function correctly on that architecture, and thus tfclient cannot, and likely never will support that architecture. + +Did Nebula add a new architecture, and we missed it? Rust supports a new architecture in a new release? [Let us know!](https://lists.e3t.cc/~core/trifid-devel) We love adding support for new systems whenever we can. + +Did we miss an architecture? If your architecture is supported by BOTH Nebula and Rust, but you still get `This architecture is not supported yet :(` when trying to build tfclient, we might have missed you - [get in touch](https://lists.e3t.cc/~core/trifid-devel) and we will work with you to get your system supported :D \ No newline at end of file diff --git a/index.md b/index.md index c1da8bc..5460e67 100644 --- a/index.md +++ b/index.md @@ -15,15 +15,42 @@ The API implementation is tested with the official dnclient implementation, and - [tfcli documentation](./docs/tfcli/index.md) - [tfclient documentation](./docs/tfclient/index.md) - [trifid-api documentation](./docs/trifid-api/index.md) + + - [dnapi-rs documentation](https://docs.rs/dnapi-rs) - [dnapi-rs on crates.io](https://crates.io/crates/dnapi-rs) + + - [trifid-pki documentation](https://docs.rs/trifid-pki) - [trifid-pki on crates.io](https://crates.io/crates/trifid-pki) + + - [trifid git repository](https://git.e3t.cc/~core/trifid) + + - [trifid announcements mailing list](https://lists.e3t.cc/~core/trifid-announce) - [trifid patch mailing list](https://lists.e3t.cc/~core/trifid-devel) - [trifid discussion mailing list](https://lists.e3t.cc/~core/trifid-discuss) +# Where does trifid work? + +| Operating System | trifid-api? | +|-------------------------|-----------------------------------------------------------------------------------------| +| Windows amd64 | [Yes](docs/tfclient/index.md) [(untested - help wanted!)](docs/tfclient/untested_os.md) | +| Windows arm64 | [Yes](docs/tfclient/index.md) [(untested - help wanted!)](docs/tfclient/untested_os.md) | +| Darwin (macOS) | [Yes](docs/tfclient/index.md) [(untested - help wanted!)](docs/tfclient/untested_os.md) | +| FreeBSD amd64 | [Yes](docs/tfclient/index.md) [(untested - help wanted!)](docs/tfclient/untested_os.md) | +| Linux i386 | [Yes](docs/tfclient/index.md) | +| Linux amd64 | [Yes](docs/tfclient/index.md) | +| Linux armv5 | [Yes](docs/tfclient/index.md) | +| Linux armv6 | [Yes](docs/tfclient/index.md) | +| Linux armv7 | [Yes](docs/tfclient/index.md) | +| Linux aarch64 | [Yes](docs/tfclient/index.md) | +| Android | Almost [(help wanted!)](docs/trifid_mobile/help.md) | +| iOS | Almost [(help wanted!)](docs/trifid_mobile/help.md) | +| Other operating systems | No, and [likely never will be](docs/tfclient/why_not_this_os.md) | + + # Get in touch Have a question about trifid? Check out the [discussion mailing list](https://lists.e3t.cc/~core/trifid-discuss)! `trifid-discuss` is a mailing list for end-user discussion and questions related to the trifid project. From c69ef348c204d3db71d748df5a2c972af059a77c Mon Sep 17 00:00:00 2001 From: core Date: Fri, 23 Jun 2023 21:04:58 -0400 Subject: [PATCH 15/17] fix interlink --- docs/tfclient/untested_os.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/tfclient/untested_os.md b/docs/tfclient/untested_os.md index 9227cf8..8685001 100644 --- a/docs/tfclient/untested_os.md +++ b/docs/tfclient/untested_os.md @@ -1,6 +1,6 @@ # Help us out - test tfclient on new platforms -There are [lots](index.md#Where_does_trifid_work?) of operating systems in which `tfclient` *should* work, but due to a lack of devices, it cannot be tested. If you have a system running one of these devices and want to help out the project, please test tfclient for functionality on your device! +There are [lots](index.md#where-does-trifid-work) of operating systems in which `tfclient` *should* work, but due to a lack of devices, it cannot be tested. If you have a system running one of these devices and want to help out the project, please test tfclient for functionality on your device!
Notice: While tfclient is almost always perfectly safe, there are always risks to running untested software on production machines. Be careful out there! From e4d71fd62f406e5d4918509eb2b19d734f283091 Mon Sep 17 00:00:00 2001 From: core Date: Sat, 24 Jun 2023 10:54:52 -0400 Subject: [PATCH 16/17] hotfix response signing --- trifid-api/Cargo.toml | 2 +- trifid-api/src/routes/v1/dnclient.rs | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/trifid-api/Cargo.toml b/trifid-api/Cargo.toml index 8aee703..60e8d89 100644 --- a/trifid-api/Cargo.toml +++ b/trifid-api/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "trifid-api" -version = "0.1.2" +version = "0.1.3" edition = "2021" description = "Pure-rust Defined Networking compatible management server" license = "GPL-3.0-or-later" diff --git a/trifid-api/src/routes/v1/dnclient.rs b/trifid-api/src/routes/v1/dnclient.rs index 07f9b5e..1af1773 100644 --- a/trifid-api/src/routes/v1/dnclient.rs +++ b/trifid-api/src/routes/v1/dnclient.rs @@ -322,7 +322,7 @@ pub async fn dnclient( let signing_key = host_in_ks .signing_keys .iter() - .find(|u| u.id == (req.counter as u64) - 1) + .find(|u| u.id == (req.counter as u64)) .unwrap(); let msg = DoUpdateResponse { From 408d76f8419fd9eb231ca7e52c5bf55b2f0c6825 Mon Sep 17 00:00:00 2001 From: core Date: Sat, 24 Jun 2023 12:04:20 -0400 Subject: [PATCH 17/17] static api signing keys per-host because dealing with them is turning out to be an absolute nightmare --- Cargo.lock | 2 +- trifid-api/Cargo.toml | 2 +- trifid-api/src/routes/v1/dnclient.rs | 2 +- 3 files changed, 3 insertions(+), 3 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index 7013956..aba578a 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -3633,7 +3633,7 @@ dependencies = [ [[package]] name = "trifid-api" -version = "0.1.2" +version = "0.1.3" dependencies = [ "actix-cors", "actix-request-identifier", diff --git a/trifid-api/Cargo.toml b/trifid-api/Cargo.toml index 60e8d89..48723ea 100644 --- a/trifid-api/Cargo.toml +++ b/trifid-api/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "trifid-api" -version = "0.1.3" +version = "0.1.4" edition = "2021" description = "Pure-rust Defined Networking compatible management server" license = "GPL-3.0-or-later" diff --git a/trifid-api/src/routes/v1/dnclient.rs b/trifid-api/src/routes/v1/dnclient.rs index 1af1773..87cea0b 100644 --- a/trifid-api/src/routes/v1/dnclient.rs +++ b/trifid-api/src/routes/v1/dnclient.rs @@ -266,7 +266,7 @@ pub async fn dnclient( ks.signing_keys.push(KSSigningKey { id: ks.current_signing_key + 1, - key: SigningKey::generate(&mut OsRng), + key: ks.signing_keys[0].key.clone(), }); ks.current_signing_key += 1;