trifid-api 0.3.0-alpha1 and some work on a tfweb rewrite #6

Merged
core merged 12 commits from api-and-web-rewrite into master 2023-12-28 05:44:29 +00:00
14 changed files with 80 additions and 20 deletions
Showing only changes of commit 057e9e3ce3 - Show all commits

View File

@ -1,7 +1,7 @@
<?xml version="1.0" encoding="UTF-8"?>
<project version="4">
<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>
<synchronize>true</synchronize>
<jdbc-driver>org.postgresql.Driver</jdbc-driver>

2
Cargo.lock generated
View File

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

View File

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

View File

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

View File

@ -13,6 +13,7 @@ use log::{debug, error, trace};
use reqwest::StatusCode;
use serde::{Deserialize, Serialize};
use std::error::Error;
use reqwest::header::HeaderValue;
use trifid_pki::cert::serialize_ed25519_public;
use trifid_pki::ed25519_dalek::{Signature, Signer, SigningKey, Verifier};
use url::Url;
@ -90,10 +91,15 @@ impl Client {
.body(req_json)
.send()?;
let empty_hval;
#[allow(clippy::unwrap_used)] {
empty_hval = HeaderValue::from_str("").unwrap();
};
let req_id = resp
.headers()
.get("X-Request-ID")
.ok_or("Response missing X-Request-ID")?
.unwrap_or(&empty_hval)
.to_str()?;
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)?);
debug!("inserted private key into config: {:?}", config);
debug!("inserted private key into config");
let config_str = serde_yaml::to_string(&config)?;
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 session_token: Option<SessionToken>,
pub auth_token: Option<()>,
pub auth_token: Option<AuthToken>,
}
#[macro_export]
@ -52,7 +52,24 @@ macro_rules! auth {
auth_info.session_token = Some(real_token.clone());
} else if token.starts_with("auth-") {
// 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

View File

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

View File

@ -2,6 +2,7 @@ use crate::config::Config;
use crate::error::APIErrorResponse;
use actix_web::middleware::Logger;
use actix_web::web::{Data, JsonConfig};
use actix_web::dev::Service;
use actix_web::{App, Error, HttpResponse, HttpServer};
use diesel::Connection;
use diesel_async::async_connection_wrapper::AsyncConnectionWrapper;
@ -12,6 +13,8 @@ use diesel_migrations::{embed_migrations, EmbeddedMigrations, MigrationHarness};
use log::{error, info};
use std::fs;
use std::path::PathBuf;
use actix_web::http::header::{HeaderName, HeaderValue};
use std::str::FromStr;
pub mod error;
#[macro_use]
@ -138,10 +141,22 @@ async fn main() {
.service(routes::v1::auth::verify_magic_link::verify_link_req)
.service(routes::v1::auth::magic_link::login_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::dnclient::dnclient_req)
.service(routes::v1::networks::create_network_req)
.service(routes::v2::enroll::enroll_req)
.wrap(Logger::default())
.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())
})
.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 serde::Serialize;
use std::time::SystemTime;
use actix_web::post;
use trifid_pki::cert::{
deserialize_ed25519_public, deserialize_x25519_public, serialize_ed25519_public,
};
use trifid_pki::ed25519_dalek::{Signature, Verifier, VerifyingKey};
use trifid_pki::x25519_dalek::PublicKey;
use crate::crypt::DnclientKeyLockbox;
#[derive(Serialize, Debug)]
#[serde(untagged)]
pub enum DnclientResponse {
CheckForUpdateResp(CheckForUpdateResponseWrapper),
DoUpdateResp(SignedResponseWrapper),
}
#[post("/v1/dnclient")]
pub async fn dnclient_req(
req: Json<RequestV1>,
state: Data<AppState>,
@ -53,7 +57,7 @@ pub async fn dnclient_req(
.await
.optional());
let key = match maybe_key {
let host_key = match maybe_key {
Some(k) => k,
None => {
err!(
@ -67,8 +71,9 @@ pub async fn dnclient_req(
};
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(
&key.client_ed_pub.try_into().unwrap()
&ed_pub.try_into().unwrap()
));
if key.verify(req.message.as_bytes(), &signature).is_err() {
@ -139,7 +144,7 @@ pub async fn dnclient_req(
id: randid!(id "hostkey"),
host_id: host.id.clone(),
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_cert: new_config.pki.cert.as_bytes().to_vec(),
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 old_key_lockbox = DnclientKeyLockbox {
nonce: host_key.salt.clone(),
info: host_key.info.clone(),
key: host_key.server_ed_priv.clone()
};
let resp = SignedResponse {
version: 1,
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(),
};

View File

@ -3,4 +3,4 @@ pub mod dnclient;
pub mod networks;
pub mod signup;
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::{auth, enforce, randid, AppState};
use actix_web::web::{Data, Json};
use actix_web::HttpRequest;
use actix_web::{HttpRequest, post};
use chrono::{DateTime, SecondsFormat, Utc};
use diesel::{ExpressionMethods, QueryDsl, SelectableHelper};
use diesel_async::RunQueryDsl;
@ -25,6 +25,7 @@ pub struct CreateNetworkResp {
pub data: NetworkNormalized,
}
#[post("/v1/networks")]
pub async fn create_network_req(
req: Json<CreateNetworkReq>,
state: Data<AppState>,

View File

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

View File

@ -12,9 +12,11 @@ use diesel::{ExpressionMethods, OptionalExtension, QueryDsl};
use diesel_async::RunQueryDsl;
use dnapi_rs::message::{EnrollRequest, EnrollResponse, EnrollResponseData, EnrollResponseDataOrg};
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;
#[post("/v2/enroll")]
pub async fn enroll_req(
req: Json<EnrollRequest>,
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 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);