bugfix alpha1

This commit is contained in:
core 2023-12-27 01:57:17 -05:00
parent a5fb79288b
commit 057e9e3ce3
Signed by: core
GPG Key ID: FDBF740DADDCEECF
14 changed files with 80 additions and 20 deletions

View File

@ -1,7 +1,7 @@
<?xml version="1.0" encoding="UTF-8"?> <?xml version="1.0" encoding="UTF-8"?>
<project version="4"> <project version="4">
<component name="DataSourceManagerImpl" format="xml" multifile-model="true"> <component name="DataSourceManagerImpl" format="xml" multifile-model="true">
<data-source source="LOCAL" name="trifidapi@localhost" uuid="39c81b89-3fc4-493f-b203-7a00527cffe6"> <data-source source="LOCAL" name="trifid@localhost" uuid="39c81b89-3fc4-493f-b203-7a00527cffe6">
<driver-ref>postgresql</driver-ref> <driver-ref>postgresql</driver-ref>
<synchronize>true</synchronize> <synchronize>true</synchronize>
<jdbc-driver>org.postgresql.Driver</jdbc-driver> <jdbc-driver>org.postgresql.Driver</jdbc-driver>

2
Cargo.lock generated
View File

@ -1025,7 +1025,7 @@ dependencies = [
[[package]] [[package]]
name = "dnapi-rs" name = "dnapi-rs"
version = "0.2.2" version = "0.2.3"
dependencies = [ dependencies = [
"base64 0.21.5", "base64 0.21.5",
"base64-serde", "base64-serde",

View File

@ -1,6 +1,6 @@
[package] [package]
name = "dnapi-rs" name = "dnapi-rs"
version = "0.2.2" version = "0.2.3"
edition = "2021" edition = "2021"
description = "A rust client for the Defined Networking API" description = "A rust client for the Defined Networking API"
license = "AGPL-3.0-or-later" license = "AGPL-3.0-or-later"

View File

@ -13,6 +13,7 @@ use log::{debug, error};
use reqwest::StatusCode; use reqwest::StatusCode;
use serde::{Deserialize, Serialize}; use serde::{Deserialize, Serialize};
use std::error::Error; use std::error::Error;
use reqwest::header::HeaderValue;
use trifid_pki::cert::serialize_ed25519_public; use trifid_pki::cert::serialize_ed25519_public;
use trifid_pki::ed25519_dalek::{Signature, Signer, SigningKey, Verifier}; use trifid_pki::ed25519_dalek::{Signature, Signer, SigningKey, Verifier};
use url::Url; use url::Url;
@ -89,10 +90,15 @@ impl Client {
.send() .send()
.await?; .await?;
let empty_hval;
#[allow(clippy::unwrap_used)] {
empty_hval = HeaderValue::from_str("").unwrap();
};
let req_id = resp let req_id = resp
.headers() .headers()
.get("X-Request-ID") .get("X-Request-ID")
.ok_or("Response missing X-Request-ID")? .unwrap_or(&empty_hval)
.to_str()?; .to_str()?;
debug!("enrollment request complete {{req_id: {}}}", req_id); debug!("enrollment request complete {{req_id: {}}}", req_id);

View File

@ -13,6 +13,7 @@ use log::{debug, error, trace};
use reqwest::StatusCode; use reqwest::StatusCode;
use serde::{Deserialize, Serialize}; use serde::{Deserialize, Serialize};
use std::error::Error; use std::error::Error;
use reqwest::header::HeaderValue;
use trifid_pki::cert::serialize_ed25519_public; use trifid_pki::cert::serialize_ed25519_public;
use trifid_pki::ed25519_dalek::{Signature, Signer, SigningKey, Verifier}; use trifid_pki::ed25519_dalek::{Signature, Signer, SigningKey, Verifier};
use url::Url; use url::Url;
@ -90,10 +91,15 @@ impl Client {
.body(req_json) .body(req_json)
.send()?; .send()?;
let empty_hval;
#[allow(clippy::unwrap_used)] {
empty_hval = HeaderValue::from_str("").unwrap();
};
let req_id = resp let req_id = resp
.headers() .headers()
.get("X-Request-ID") .get("X-Request-ID")
.ok_or("Response missing X-Request-ID")? .unwrap_or(&empty_hval)
.to_str()?; .to_str()?;
debug!("enrollment request complete {{req_id: {}}}", req_id); debug!("enrollment request complete {{req_id: {}}}", req_id);

View File

@ -28,7 +28,7 @@ fn insert_private_key(instance: &str) -> Result<(), Box<dyn Error>> {
config.pki.key = Some(String::from_utf8(key)?); config.pki.key = Some(String::from_utf8(key)?);
debug!("inserted private key into config: {:?}", config); debug!("inserted private key into config");
let config_str = serde_yaml::to_string(&config)?; let config_str = serde_yaml::to_string(&config)?;
fs::write(nebula_yml(instance), config_str)?; fs::write(nebula_yml(instance), config_str)?;

View File

@ -1,8 +1,8 @@
use crate::models::SessionToken; use crate::models::{AuthToken, SessionToken};
pub struct AuthInfo { pub struct AuthInfo {
pub session_token: Option<SessionToken>, pub session_token: Option<SessionToken>,
pub auth_token: Option<()>, pub auth_token: Option<AuthToken>,
} }
#[macro_export] #[macro_export]
@ -52,7 +52,24 @@ macro_rules! auth {
auth_info.session_token = Some(real_token.clone()); auth_info.session_token = Some(real_token.clone());
} else if token.starts_with("auth-") { } else if token.starts_with("auth-") {
// parse auth token // parse auth token
todo!()
use $crate::schema::auth_tokens::dsl::*;
let tokens = $crate::handle_error!(
auth_tokens
.filter(id.eq(token))
.select($crate::models::AuthToken::as_select())
.load(&mut $c)
.await
);
let real_token = match tokens.get(0) {
Some(tok) => tok,
None => $crate::err!(
actix_web::http::StatusCode::UNAUTHORIZED,
$crate::make_err!("ERR_UNAUTHORIZED", "unauthorized")
),
};
auth_info.auth_token = Some(real_token.clone());
} }
} }
auth_info auth_info

View File

@ -65,7 +65,7 @@ pub async fn generate_config(
let mut ca_string = String::new(); let mut ca_string = String::new();
for ca in cas { for ca in cas {
if ca.expires_at < SystemTime::now() { if ca.expires_at > SystemTime::now() {
let ca_cert: NebulaCertificate = let ca_cert: NebulaCertificate =
serde_json::from_value(ca.cert.clone()).map_err(ConfigGenError::InvalidCACert)?; serde_json::from_value(ca.cert.clone()).map_err(ConfigGenError::InvalidCACert)?;
ca_string += &String::from_utf8_lossy( ca_string += &String::from_utf8_lossy(

View File

@ -2,6 +2,7 @@ use crate::config::Config;
use crate::error::APIErrorResponse; use crate::error::APIErrorResponse;
use actix_web::middleware::Logger; use actix_web::middleware::Logger;
use actix_web::web::{Data, JsonConfig}; use actix_web::web::{Data, JsonConfig};
use actix_web::dev::Service;
use actix_web::{App, Error, HttpResponse, HttpServer}; use actix_web::{App, Error, HttpResponse, HttpServer};
use diesel::Connection; use diesel::Connection;
use diesel_async::async_connection_wrapper::AsyncConnectionWrapper; use diesel_async::async_connection_wrapper::AsyncConnectionWrapper;
@ -12,6 +13,8 @@ use diesel_migrations::{embed_migrations, EmbeddedMigrations, MigrationHarness};
use log::{error, info}; use log::{error, info};
use std::fs; use std::fs;
use std::path::PathBuf; use std::path::PathBuf;
use actix_web::http::header::{HeaderName, HeaderValue};
use std::str::FromStr;
pub mod error; pub mod error;
#[macro_use] #[macro_use]
@ -138,10 +141,22 @@ async fn main() {
.service(routes::v1::auth::verify_magic_link::verify_link_req) .service(routes::v1::auth::verify_magic_link::verify_link_req)
.service(routes::v1::auth::magic_link::login_req) .service(routes::v1::auth::magic_link::login_req)
.service(routes::v1::totp_authenticators::create_totp_auth_req) .service(routes::v1::totp_authenticators::create_totp_auth_req)
.service(routes::v1::verify_totp_authenticator::verify_totp_req) .service(routes::v1::verify_totp_authenticators::verify_totp_req)
.service(routes::v1::auth::totp::totp_req) .service(routes::v1::auth::totp::totp_req)
.service(routes::v1::dnclient::dnclient_req)
.service(routes::v1::networks::create_network_req)
.service(routes::v2::enroll::enroll_req)
.wrap(Logger::default()) .wrap(Logger::default())
.wrap(actix_cors::Cors::permissive()) .wrap(actix_cors::Cors::permissive())
.wrap_fn(|req, srv| {
let fut = srv.call(req);
async {
let mut res = fut.await?;
res.headers_mut()
.insert(HeaderName::from_str("X-Request-ID").unwrap(), HeaderValue::from_str(&randid!(id "")).unwrap());
Ok(res)
}
})
.app_data(app_state.clone()) .app_data(app_state.clone())
}) })
.bind((local_config.server.bind.ip, local_config.server.bind.port)) .bind((local_config.server.bind.ip, local_config.server.bind.port))

View File

@ -16,18 +16,22 @@ use dnapi_rs::message::{
use log::warn; use log::warn;
use serde::Serialize; use serde::Serialize;
use std::time::SystemTime; use std::time::SystemTime;
use actix_web::post;
use trifid_pki::cert::{ use trifid_pki::cert::{
deserialize_ed25519_public, deserialize_x25519_public, serialize_ed25519_public, deserialize_ed25519_public, deserialize_x25519_public, serialize_ed25519_public,
}; };
use trifid_pki::ed25519_dalek::{Signature, Verifier, VerifyingKey}; use trifid_pki::ed25519_dalek::{Signature, Verifier, VerifyingKey};
use trifid_pki::x25519_dalek::PublicKey; use trifid_pki::x25519_dalek::PublicKey;
use crate::crypt::DnclientKeyLockbox;
#[derive(Serialize, Debug)] #[derive(Serialize, Debug)]
#[serde(untagged)]
pub enum DnclientResponse { pub enum DnclientResponse {
CheckForUpdateResp(CheckForUpdateResponseWrapper), CheckForUpdateResp(CheckForUpdateResponseWrapper),
DoUpdateResp(SignedResponseWrapper), DoUpdateResp(SignedResponseWrapper),
} }
#[post("/v1/dnclient")]
pub async fn dnclient_req( pub async fn dnclient_req(
req: Json<RequestV1>, req: Json<RequestV1>,
state: Data<AppState>, state: Data<AppState>,
@ -53,7 +57,7 @@ pub async fn dnclient_req(
.await .await
.optional()); .optional());
let key = match maybe_key { let host_key = match maybe_key {
Some(k) => k, Some(k) => k,
None => { None => {
err!( err!(
@ -67,8 +71,9 @@ pub async fn dnclient_req(
}; };
let signature = handle_error!(Signature::from_slice(&req.signature)); let signature = handle_error!(Signature::from_slice(&req.signature));
let ed_pub = deserialize_ed25519_public(&host_key.client_ed_pub).unwrap();
let key = handle_error!(VerifyingKey::from_bytes( let key = handle_error!(VerifyingKey::from_bytes(
&key.client_ed_pub.try_into().unwrap() &ed_pub.try_into().unwrap()
)); ));
if key.verify(req.message.as_bytes(), &signature).is_err() { if key.verify(req.message.as_bytes(), &signature).is_err() {
@ -139,7 +144,7 @@ pub async fn dnclient_req(
id: randid!(id "hostkey"), id: randid!(id "hostkey"),
host_id: host.id.clone(), host_id: host.id.clone(),
counter: new_counter, counter: new_counter,
client_ed_pub: new_ed_key, client_ed_pub: do_update_req.ed_pubkey_pem,
client_dh_pub: new_dh_pub_bytes, client_dh_pub: new_dh_pub_bytes,
client_cert: new_config.pki.cert.as_bytes().to_vec(), client_cert: new_config.pki.cert.as_bytes().to_vec(),
salt: key_lockbox.nonce.clone(), salt: key_lockbox.nonce.clone(),
@ -176,10 +181,16 @@ pub async fn dnclient_req(
let msg_bytes = handle_error!(serde_json::to_vec(&msg)); let msg_bytes = handle_error!(serde_json::to_vec(&msg));
let old_key_lockbox = DnclientKeyLockbox {
nonce: host_key.salt.clone(),
info: host_key.info.clone(),
key: host_key.server_ed_priv.clone()
};
let resp = SignedResponse { let resp = SignedResponse {
version: 1, version: 1,
message: msg_bytes.clone(), message: msg_bytes.clone(),
signature: sign_dnclient_with_lockbox(&key_lockbox, &msg_bytes, &state.config) signature: sign_dnclient_with_lockbox(&old_key_lockbox, &msg_bytes, &state.config)
.unwrap().to_vec(), .unwrap().to_vec(),
}; };

View File

@ -3,4 +3,4 @@ pub mod dnclient;
pub mod networks; pub mod networks;
pub mod signup; pub mod signup;
pub mod totp_authenticators; pub mod totp_authenticators;
pub mod verify_totp_authenticator; pub mod verify_totp_authenticators;

View File

@ -7,7 +7,7 @@ use crate::schema::signing_cas::dsl::signing_cas;
use crate::schema::users; use crate::schema::users;
use crate::{auth, enforce, randid, AppState}; use crate::{auth, enforce, randid, AppState};
use actix_web::web::{Data, Json}; use actix_web::web::{Data, Json};
use actix_web::HttpRequest; use actix_web::{HttpRequest, post};
use chrono::{DateTime, SecondsFormat, Utc}; use chrono::{DateTime, SecondsFormat, Utc};
use diesel::{ExpressionMethods, QueryDsl, SelectableHelper}; use diesel::{ExpressionMethods, QueryDsl, SelectableHelper};
use diesel_async::RunQueryDsl; use diesel_async::RunQueryDsl;
@ -25,6 +25,7 @@ pub struct CreateNetworkResp {
pub data: NetworkNormalized, pub data: NetworkNormalized,
} }
#[post("/v1/networks")]
pub async fn create_network_req( pub async fn create_network_req(
req: Json<CreateNetworkReq>, req: Json<CreateNetworkReq>,
state: Data<AppState>, state: Data<AppState>,

View File

@ -33,7 +33,7 @@ pub struct TotpAuthResp {
pub metadata: TotpAuthRespMeta, pub metadata: TotpAuthRespMeta,
} }
#[post("/v1/verify-totp-authenticator")] #[post("/v1/verify-totp-authenticators")]
pub async fn verify_totp_req( pub async fn verify_totp_req(
req: Json<VerifyTotpAuthReq>, req: Json<VerifyTotpAuthReq>,
state: Data<AppState>, state: Data<AppState>,

View File

@ -12,9 +12,11 @@ use diesel::{ExpressionMethods, OptionalExtension, QueryDsl};
use diesel_async::RunQueryDsl; use diesel_async::RunQueryDsl;
use dnapi_rs::message::{EnrollRequest, EnrollResponse, EnrollResponseData, EnrollResponseDataOrg}; use dnapi_rs::message::{EnrollRequest, EnrollResponse, EnrollResponseData, EnrollResponseDataOrg};
use std::time::SystemTime; use std::time::SystemTime;
use trifid_pki::cert::serialize_ed25519_public; use actix_web::post;
use trifid_pki::cert::{deserialize_x25519_public, serialize_ed25519_public};
use trifid_pki::x25519_dalek::PublicKey; use trifid_pki::x25519_dalek::PublicKey;
#[post("/v2/enroll")]
pub async fn enroll_req( pub async fn enroll_req(
req: Json<EnrollRequest>, req: Json<EnrollRequest>,
state: Data<AppState>, state: Data<AppState>,
@ -84,7 +86,9 @@ pub async fn enroll_req(
let (key_lockbox, trusted_key) = handle_error!(create_dnclient_ed_key(&state.config)); let (key_lockbox, trusted_key) = handle_error!(create_dnclient_ed_key(&state.config));
let fixed_dh_key: [u8; 32] = req.dh_pubkey.clone().try_into().unwrap(); let dh_pubkey = deserialize_x25519_public(&req.dh_pubkey).unwrap();
let fixed_dh_key: [u8; 32] = dh_pubkey.clone().try_into().unwrap();
let user_dh_key = PublicKey::from(fixed_dh_key); let user_dh_key = PublicKey::from(fixed_dh_key);