From d96b168ee6d61bd46a8ed9af0cd9d6cf56f802a8 Mon Sep 17 00:00:00 2001 From: Thorsten Sommer Date: Tue, 5 Nov 2024 20:57:03 +0100 Subject: [PATCH] Refactored certificate generation --- runtime/src/certificate.rs | 32 ++++++++++++++++++++++++++++++++ runtime/src/dotnet.rs | 5 +++-- runtime/src/lib.rs | 3 ++- runtime/src/main.rs | 21 +++++---------------- 4 files changed, 42 insertions(+), 19 deletions(-) create mode 100644 runtime/src/certificate.rs diff --git a/runtime/src/certificate.rs b/runtime/src/certificate.rs new file mode 100644 index 00000000..2f212195 --- /dev/null +++ b/runtime/src/certificate.rs @@ -0,0 +1,32 @@ +use std::sync::OnceLock; +use log::info; +use rcgen::generate_simple_self_signed; +use sha2::{Sha256, Digest}; + +pub static CERTIFICATE: OnceLock> = OnceLock::new(); +pub static CERTIFICATE_PRIVATE_KEY: OnceLock> = OnceLock::new(); +pub static CERTIFICATE_FINGERPRINT: OnceLock = OnceLock::new(); + +pub fn generate_certificate() { + + info!("Try to generate a TLS certificate for the runtime API server..."); + + let subject_alt_names = vec!["localhost".to_string()]; + let certificate_data = generate_simple_self_signed(subject_alt_names).unwrap(); + let certificate_binary_data = certificate_data.cert.der().to_vec(); + + let certificate_fingerprint = Sha256::digest(certificate_binary_data).to_vec(); + let certificate_fingerprint = certificate_fingerprint.iter().fold(String::new(), |mut result, byte| { + result.push_str(&format!("{:02x}", byte)); + result + }); + + let certificate_fingerprint = certificate_fingerprint.to_uppercase(); + + CERTIFICATE_FINGERPRINT.set(certificate_fingerprint.clone()).expect("Could not set the certificate fingerprint."); + CERTIFICATE.set(certificate_data.cert.pem().as_bytes().to_vec()).expect("Could not set the certificate."); + CERTIFICATE_PRIVATE_KEY.set(certificate_data.key_pair.serialize_pem().as_bytes().to_vec()).expect("Could not set the private key."); + + info!("Certificate fingerprint: '{certificate_fingerprint}'."); + info!("Done generating certificate for the runtime API server."); +} \ No newline at end of file diff --git a/runtime/src/dotnet.rs b/runtime/src/dotnet.rs index 0b1b9a07..fe528896 100644 --- a/runtime/src/dotnet.rs +++ b/runtime/src/dotnet.rs @@ -9,6 +9,7 @@ use tauri::api::process::{Command, CommandChild, CommandEvent}; use tauri::Url; use crate::api_token::{APIToken, API_TOKEN}; use crate::app_window::change_location_to; +use crate::certificate::CERTIFICATE_FINGERPRINT; use crate::encryption::ENCRYPTION; use crate::environment::is_dev; use crate::network::get_available_port; @@ -30,7 +31,7 @@ pub fn dotnet_port(_token: APIToken) -> String { format!("{dotnet_server_port}") } -pub fn start_dotnet_server(api_server_port: u16, certificate_fingerprint: String) { +pub fn start_dotnet_server(api_server_port: u16) { // Get the secret password & salt and convert it to a base64 string: let secret_password = BASE64_STANDARD.encode(ENCRYPTION.secret_password); @@ -39,7 +40,7 @@ pub fn start_dotnet_server(api_server_port: u16, certificate_fingerprint: String let dotnet_server_environment = HashMap::from_iter([ (String::from("AI_STUDIO_SECRET_PASSWORD"), secret_password), (String::from("AI_STUDIO_SECRET_KEY_SALT"), secret_key_salt), - (String::from("AI_STUDIO_CERTIFICATE_FINGERPRINT"), certificate_fingerprint), + (String::from("AI_STUDIO_CERTIFICATE_FINGERPRINT"), CERTIFICATE_FINGERPRINT.get().unwrap().to_string()), (String::from("AI_STUDIO_API_TOKEN"), API_TOKEN.to_hex_text().to_string()), ]); diff --git a/runtime/src/lib.rs b/runtime/src/lib.rs index c5b9560a..22e7092d 100644 --- a/runtime/src/lib.rs +++ b/runtime/src/lib.rs @@ -6,4 +6,5 @@ pub mod network; pub mod api_token; pub mod app_window; pub mod secret; -pub mod clipboard; \ No newline at end of file +pub mod clipboard; +pub mod certificate; \ No newline at end of file diff --git a/runtime/src/main.rs b/runtime/src/main.rs index d2168917..41ef20db 100644 --- a/runtime/src/main.rs +++ b/runtime/src/main.rs @@ -14,6 +14,7 @@ use rocket::routes; use rocket::config::{Shutdown}; use sha2::{Sha256, Digest}; use mindwork_ai_studio::app_window::start_tauri; +use mindwork_ai_studio::certificate::{generate_certificate, CERTIFICATE, CERTIFICATE_PRIVATE_KEY}; use mindwork_ai_studio::dotnet::start_dotnet_server; use mindwork_ai_studio::environment::is_dev; use mindwork_ai_studio::log::init_logging; @@ -66,19 +67,7 @@ async fn main() { info!("Running in production mode."); } - info!("Try to generate a TLS certificate for the runtime API server..."); - - let subject_alt_names = vec!["localhost".to_string()]; - let certificate_data = generate_simple_self_signed(subject_alt_names).unwrap(); - let certificate_binary_data = certificate_data.cert.der().to_vec(); - let certificate_fingerprint = Sha256::digest(certificate_binary_data).to_vec(); - let certificate_fingerprint = certificate_fingerprint.iter().fold(String::new(), |mut result, byte| { - result.push_str(&format!("{:02x}", byte)); - result - }); - let certificate_fingerprint = certificate_fingerprint.to_uppercase(); - info!("Certificate fingerprint: '{certificate_fingerprint}'."); - info!("Done generating certificate for the runtime API server."); + generate_certificate(); let api_port = *API_SERVER_PORT; info!("Try to start the API server on 'http://localhost:{api_port}'..."); @@ -122,8 +111,8 @@ async fn main() { .merge(("cli_colors", false)) // Read the TLS certificate and key from the generated certificate data in-memory: - .merge(("tls.certs", certificate_data.cert.pem().as_bytes())) - .merge(("tls.key", certificate_data.key_pair.serialize_pem().as_bytes())) + .merge(("tls.certs", CERTIFICATE.get().unwrap())) + .merge(("tls.key", CERTIFICATE_PRIVATE_KEY.get().unwrap())) // Set the shutdown configuration: .merge(("shutdown", shutdown)); @@ -152,6 +141,6 @@ async fn main() { }); info!("Secret password for the IPC channel was generated successfully."); - start_dotnet_server(*API_SERVER_PORT, certificate_fingerprint); + start_dotnet_server(*API_SERVER_PORT); start_tauri(); } \ No newline at end of file