mirror of
				https://github.com/MindWorkAI/AI-Studio.git
				synced 2025-11-04 04:20:20 +00:00 
			
		
		
		
	Added some documentation
This commit is contained in:
		
							parent
							
								
									e6789dcfeb
								
							
						
					
					
						commit
						c3039c2b5e
					
				@ -5,6 +5,7 @@ use rocket::http::Status;
 | 
				
			|||||||
use rocket::Request;
 | 
					use rocket::Request;
 | 
				
			||||||
use rocket::request::FromRequest;
 | 
					use rocket::request::FromRequest;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					/// The API token used to authenticate requests.
 | 
				
			||||||
pub static API_TOKEN: Lazy<APIToken> = Lazy::new(|| {
 | 
					pub static API_TOKEN: Lazy<APIToken> = Lazy::new(|| {
 | 
				
			||||||
    let mut token = [0u8; 32];
 | 
					    let mut token = [0u8; 32];
 | 
				
			||||||
    let mut rng = rand_chacha::ChaChaRng::from_entropy();
 | 
					    let mut rng = rand_chacha::ChaChaRng::from_entropy();
 | 
				
			||||||
@ -16,11 +17,13 @@ pub static API_TOKEN: Lazy<APIToken> = Lazy::new(|| {
 | 
				
			|||||||
    token
 | 
					    token
 | 
				
			||||||
});
 | 
					});
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					/// The API token data structure used to authenticate requests.
 | 
				
			||||||
pub struct APIToken {
 | 
					pub struct APIToken {
 | 
				
			||||||
    hex_text: String,
 | 
					    hex_text: String,
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
impl APIToken {
 | 
					impl APIToken {
 | 
				
			||||||
 | 
					    /// Creates a new API token from a byte vector.
 | 
				
			||||||
    fn from_bytes(bytes: Vec<u8>) -> Self {
 | 
					    fn from_bytes(bytes: Vec<u8>) -> Self {
 | 
				
			||||||
        APIToken {
 | 
					        APIToken {
 | 
				
			||||||
            hex_text: bytes.iter().fold(String::new(), |mut result, byte| {
 | 
					            hex_text: bytes.iter().fold(String::new(), |mut result, byte| {
 | 
				
			||||||
@ -30,6 +33,7 @@ impl APIToken {
 | 
				
			|||||||
        }
 | 
					        }
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    /// Creates a new API token from a hexadecimal text.
 | 
				
			||||||
    fn from_hex_text(hex_text: &str) -> Self {
 | 
					    fn from_hex_text(hex_text: &str) -> Self {
 | 
				
			||||||
        APIToken {
 | 
					        APIToken {
 | 
				
			||||||
            hex_text: hex_text.to_string(),
 | 
					            hex_text: hex_text.to_string(),
 | 
				
			||||||
@ -40,17 +44,21 @@ impl APIToken {
 | 
				
			|||||||
        self.hex_text.as_str()
 | 
					        self.hex_text.as_str()
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    /// Validates the received token against the valid token.
 | 
				
			||||||
    fn validate(&self, received_token: &Self) -> bool {
 | 
					    fn validate(&self, received_token: &Self) -> bool {
 | 
				
			||||||
        received_token.to_hex_text() == self.to_hex_text()
 | 
					        received_token.to_hex_text() == self.to_hex_text()
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					/// The request outcome type used to handle API token requests.
 | 
				
			||||||
type RequestOutcome<R, T> = rocket::request::Outcome<R, T>;
 | 
					type RequestOutcome<R, T> = rocket::request::Outcome<R, T>;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					/// The request outcome implementation for the API token.
 | 
				
			||||||
#[rocket::async_trait]
 | 
					#[rocket::async_trait]
 | 
				
			||||||
impl<'r> FromRequest<'r> for APIToken {
 | 
					impl<'r> FromRequest<'r> for APIToken {
 | 
				
			||||||
    type Error = APITokenError;
 | 
					    type Error = APITokenError;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    /// Handles the API token requests.
 | 
				
			||||||
    async fn from_request(request: &'r Request<'_>) -> RequestOutcome<Self, Self::Error> {
 | 
					    async fn from_request(request: &'r Request<'_>) -> RequestOutcome<Self, Self::Error> {
 | 
				
			||||||
        let token = request.headers().get_one("token");
 | 
					        let token = request.headers().get_one("token");
 | 
				
			||||||
        match token {
 | 
					        match token {
 | 
				
			||||||
@ -68,6 +76,7 @@ impl<'r> FromRequest<'r> for APIToken {
 | 
				
			|||||||
    }
 | 
					    }
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					/// The API token error types.
 | 
				
			||||||
#[derive(Debug)]
 | 
					#[derive(Debug)]
 | 
				
			||||||
pub enum APITokenError {
 | 
					pub enum APITokenError {
 | 
				
			||||||
    Missing,
 | 
					    Missing,
 | 
				
			||||||
 | 
				
			|||||||
@ -13,12 +13,13 @@ use crate::dotnet::stop_dotnet_server;
 | 
				
			|||||||
use crate::environment::{is_prod, CONFIG_DIRECTORY, DATA_DIRECTORY};
 | 
					use crate::environment::{is_prod, CONFIG_DIRECTORY, DATA_DIRECTORY};
 | 
				
			||||||
use crate::log::switch_to_file_logging;
 | 
					use crate::log::switch_to_file_logging;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
// The Tauri main window.
 | 
					/// The Tauri main window.
 | 
				
			||||||
static MAIN_WINDOW: Lazy<Mutex<Option<Window>>> = Lazy::new(|| Mutex::new(None));
 | 
					static MAIN_WINDOW: Lazy<Mutex<Option<Window>>> = Lazy::new(|| Mutex::new(None));
 | 
				
			||||||
 | 
					
 | 
				
			||||||
// The update response coming from the Tauri updater.
 | 
					/// The update response coming from the Tauri updater.
 | 
				
			||||||
static CHECK_UPDATE_RESPONSE: Lazy<Mutex<Option<UpdateResponse<tauri::Wry>>>> = Lazy::new(|| Mutex::new(None));
 | 
					static CHECK_UPDATE_RESPONSE: Lazy<Mutex<Option<UpdateResponse<tauri::Wry>>>> = Lazy::new(|| Mutex::new(None));
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					/// Starts the Tauri app.
 | 
				
			||||||
pub fn start_tauri() {
 | 
					pub fn start_tauri() {
 | 
				
			||||||
    info!("Starting Tauri app...");
 | 
					    info!("Starting Tauri app...");
 | 
				
			||||||
    let app = tauri::Builder::default()
 | 
					    let app = tauri::Builder::default()
 | 
				
			||||||
@ -118,6 +119,7 @@ pub fn start_tauri() {
 | 
				
			|||||||
    }
 | 
					    }
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					/// Changes the location of the main window to the given URL.
 | 
				
			||||||
pub async fn change_location_to(url: &str) {
 | 
					pub async fn change_location_to(url: &str) {
 | 
				
			||||||
    // Try to get the main window. If it is not available yet, wait for it:
 | 
					    // Try to get the main window. If it is not available yet, wait for it:
 | 
				
			||||||
    let mut main_window_ready = false;
 | 
					    let mut main_window_ready = false;
 | 
				
			||||||
@ -149,6 +151,7 @@ pub async fn change_location_to(url: &str) {
 | 
				
			|||||||
    }
 | 
					    }
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					/// Checks for updates.
 | 
				
			||||||
#[get("/updates/check")]
 | 
					#[get("/updates/check")]
 | 
				
			||||||
pub async fn check_for_update(_token: APIToken) -> Json<CheckUpdateResponse> {
 | 
					pub async fn check_for_update(_token: APIToken) -> Json<CheckUpdateResponse> {
 | 
				
			||||||
    let app_handle = MAIN_WINDOW.lock().unwrap().as_ref().unwrap().app_handle();
 | 
					    let app_handle = MAIN_WINDOW.lock().unwrap().as_ref().unwrap().app_handle();
 | 
				
			||||||
@ -194,6 +197,7 @@ pub async fn check_for_update(_token: APIToken) -> Json<CheckUpdateResponse> {
 | 
				
			|||||||
    }
 | 
					    }
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					/// The response to the check for update request.
 | 
				
			||||||
#[derive(Serialize)]
 | 
					#[derive(Serialize)]
 | 
				
			||||||
pub struct CheckUpdateResponse {
 | 
					pub struct CheckUpdateResponse {
 | 
				
			||||||
    update_is_available: bool,
 | 
					    update_is_available: bool,
 | 
				
			||||||
@ -202,6 +206,7 @@ pub struct CheckUpdateResponse {
 | 
				
			|||||||
    changelog: String,
 | 
					    changelog: String,
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					/// Installs the update.
 | 
				
			||||||
#[get("/updates/install")]
 | 
					#[get("/updates/install")]
 | 
				
			||||||
pub async fn install_update(_token: APIToken) {
 | 
					pub async fn install_update(_token: APIToken) {
 | 
				
			||||||
    let cloned_response_option = CHECK_UPDATE_RESPONSE.lock().unwrap().clone();
 | 
					    let cloned_response_option = CHECK_UPDATE_RESPONSE.lock().unwrap().clone();
 | 
				
			||||||
 | 
				
			|||||||
@ -3,10 +3,16 @@ use log::info;
 | 
				
			|||||||
use rcgen::generate_simple_self_signed;
 | 
					use rcgen::generate_simple_self_signed;
 | 
				
			||||||
use sha2::{Sha256, Digest};
 | 
					use sha2::{Sha256, Digest};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					/// The certificate used for the runtime API server.
 | 
				
			||||||
pub static CERTIFICATE: OnceLock<Vec<u8>> = OnceLock::new();
 | 
					pub static CERTIFICATE: OnceLock<Vec<u8>> = OnceLock::new();
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					/// The private key used for the certificate of the runtime API server.
 | 
				
			||||||
pub static CERTIFICATE_PRIVATE_KEY: OnceLock<Vec<u8>> = OnceLock::new();
 | 
					pub static CERTIFICATE_PRIVATE_KEY: OnceLock<Vec<u8>> = OnceLock::new();
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					/// The fingerprint of the certificate used for the runtime API server.
 | 
				
			||||||
pub static CERTIFICATE_FINGERPRINT: OnceLock<String> = OnceLock::new();
 | 
					pub static CERTIFICATE_FINGERPRINT: OnceLock<String> = OnceLock::new();
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					/// Generates a TLS certificate for the runtime API server.
 | 
				
			||||||
pub fn generate_certificate() {
 | 
					pub fn generate_certificate() {
 | 
				
			||||||
    
 | 
					    
 | 
				
			||||||
    info!("Try to generate a TLS certificate for the runtime API server...");
 | 
					    info!("Try to generate a TLS certificate for the runtime API server...");
 | 
				
			||||||
 | 
				
			|||||||
@ -6,6 +6,7 @@ use serde::Serialize;
 | 
				
			|||||||
use crate::api_token::APIToken;
 | 
					use crate::api_token::APIToken;
 | 
				
			||||||
use crate::encryption::{EncryptedText, ENCRYPTION};
 | 
					use crate::encryption::{EncryptedText, ENCRYPTION};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					/// Sets the clipboard text to the provided encrypted text.
 | 
				
			||||||
#[post("/clipboard/set", data = "<encrypted_text>")]
 | 
					#[post("/clipboard/set", data = "<encrypted_text>")]
 | 
				
			||||||
pub fn set_clipboard(_token: APIToken, encrypted_text: EncryptedText) -> Json<SetClipboardResponse> {
 | 
					pub fn set_clipboard(_token: APIToken, encrypted_text: EncryptedText) -> Json<SetClipboardResponse> {
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@ -53,6 +54,7 @@ pub fn set_clipboard(_token: APIToken, encrypted_text: EncryptedText) -> Json<Se
 | 
				
			|||||||
    }
 | 
					    }
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					/// The response for setting the clipboard text.
 | 
				
			||||||
#[derive(Serialize)]
 | 
					#[derive(Serialize)]
 | 
				
			||||||
pub struct SetClipboardResponse {
 | 
					pub struct SetClipboardResponse {
 | 
				
			||||||
    success: bool,
 | 
					    success: bool,
 | 
				
			||||||
 | 
				
			|||||||
@ -26,12 +26,15 @@ static DOTNET_SERVER_PORT: Lazy<u16> = Lazy::new(|| get_available_port().unwrap(
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
static DOTNET_INITIALIZED: Lazy<Mutex<bool>> = Lazy::new(|| Mutex::new(false));
 | 
					static DOTNET_INITIALIZED: Lazy<Mutex<bool>> = Lazy::new(|| Mutex::new(false));
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					/// Returns the desired port of the .NET server. Our .NET app calls this endpoint to get
 | 
				
			||||||
 | 
					/// the port where the .NET server should listen to.
 | 
				
			||||||
#[get("/system/dotnet/port")]
 | 
					#[get("/system/dotnet/port")]
 | 
				
			||||||
pub fn dotnet_port(_token: APIToken) -> String {
 | 
					pub fn dotnet_port(_token: APIToken) -> String {
 | 
				
			||||||
    let dotnet_server_port = *DOTNET_SERVER_PORT;
 | 
					    let dotnet_server_port = *DOTNET_SERVER_PORT;
 | 
				
			||||||
    format!("{dotnet_server_port}")
 | 
					    format!("{dotnet_server_port}")
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					/// Starts the .NET server in a separate process.
 | 
				
			||||||
pub fn start_dotnet_server() {
 | 
					pub fn start_dotnet_server() {
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    // Get the secret password & salt and convert it to a base64 string:
 | 
					    // Get the secret password & salt and convert it to a base64 string:
 | 
				
			||||||
@ -128,6 +131,7 @@ pub fn start_dotnet_server() {
 | 
				
			|||||||
    });
 | 
					    });
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					/// This endpoint is called by the .NET server to signal that the server is ready.
 | 
				
			||||||
#[get("/system/dotnet/ready")]
 | 
					#[get("/system/dotnet/ready")]
 | 
				
			||||||
pub async fn dotnet_ready(_token: APIToken) {
 | 
					pub async fn dotnet_ready(_token: APIToken) {
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@ -158,6 +162,7 @@ pub async fn dotnet_ready(_token: APIToken) {
 | 
				
			|||||||
    change_location_to(url.as_str()).await;
 | 
					    change_location_to(url.as_str()).await;
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					/// Stops the .NET server process.
 | 
				
			||||||
pub fn stop_dotnet_server() {
 | 
					pub fn stop_dotnet_server() {
 | 
				
			||||||
    if let Some(server_process) = DOTNET_SERVER.lock().unwrap().take() {
 | 
					    if let Some(server_process) = DOTNET_SERVER.lock().unwrap().take() {
 | 
				
			||||||
        let server_kill_result = server_process.kill();
 | 
					        let server_kill_result = server_process.kill();
 | 
				
			||||||
 | 
				
			|||||||
@ -21,6 +21,7 @@ type Aes256CbcDec = cbc::Decryptor<aes::Aes256>;
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
type DataOutcome<'r, T> = data::Outcome<'r, T>;
 | 
					type DataOutcome<'r, T> = data::Outcome<'r, T>;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					/// The encryption instance used for the IPC channel.
 | 
				
			||||||
pub static ENCRYPTION: Lazy<Encryption> = Lazy::new(|| {
 | 
					pub static ENCRYPTION: Lazy<Encryption> = Lazy::new(|| {
 | 
				
			||||||
    //
 | 
					    //
 | 
				
			||||||
    // Generate a secret key & salt for the AES encryption for the IPC channel:
 | 
					    // Generate a secret key & salt for the AES encryption for the IPC channel:
 | 
				
			||||||
@ -41,6 +42,7 @@ pub static ENCRYPTION: Lazy<Encryption> = Lazy::new(|| {
 | 
				
			|||||||
    Encryption::new(&secret_key, &secret_key_salt).unwrap()
 | 
					    Encryption::new(&secret_key, &secret_key_salt).unwrap()
 | 
				
			||||||
});
 | 
					});
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					/// The encryption struct used for the IPC channel.
 | 
				
			||||||
pub struct Encryption {
 | 
					pub struct Encryption {
 | 
				
			||||||
    key: [u8; 32],
 | 
					    key: [u8; 32],
 | 
				
			||||||
    iv: [u8; 16],
 | 
					    iv: [u8; 16],
 | 
				
			||||||
@ -58,6 +60,7 @@ impl Encryption {
 | 
				
			|||||||
    // algorithms we chose, requires a fixed key length, and our password is too long.
 | 
					    // algorithms we chose, requires a fixed key length, and our password is too long.
 | 
				
			||||||
    const ITERATIONS: u32 = 100;
 | 
					    const ITERATIONS: u32 = 100;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    /// Initializes the encryption with the given secret password and salt.
 | 
				
			||||||
    pub fn new(secret_password: &[u8], secret_key_salt: &[u8]) -> Result<Self, String> {
 | 
					    pub fn new(secret_password: &[u8], secret_key_salt: &[u8]) -> Result<Self, String> {
 | 
				
			||||||
        if secret_password.len() != 512 {
 | 
					        if secret_password.len() != 512 {
 | 
				
			||||||
            return Err("The secret password must be 512 bytes long.".to_string());
 | 
					            return Err("The secret password must be 512 bytes long.".to_string());
 | 
				
			||||||
@ -92,6 +95,7 @@ impl Encryption {
 | 
				
			|||||||
        Ok(encryption)
 | 
					        Ok(encryption)
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    /// Encrypts the given data.
 | 
				
			||||||
    pub fn encrypt(&self, data: &str) -> Result<EncryptedText, String> {
 | 
					    pub fn encrypt(&self, data: &str) -> Result<EncryptedText, String> {
 | 
				
			||||||
        let cipher = Aes256CbcEnc::new(&self.key.into(), &self.iv.into());
 | 
					        let cipher = Aes256CbcEnc::new(&self.key.into(), &self.iv.into());
 | 
				
			||||||
        let encrypted = cipher.encrypt_padded_vec_mut::<Pkcs7>(data.as_bytes());
 | 
					        let encrypted = cipher.encrypt_padded_vec_mut::<Pkcs7>(data.as_bytes());
 | 
				
			||||||
@ -100,6 +104,7 @@ impl Encryption {
 | 
				
			|||||||
        Ok(EncryptedText::new(result))
 | 
					        Ok(EncryptedText::new(result))
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    /// Decrypts the given data.
 | 
				
			||||||
    pub fn decrypt(&self, encrypted_data: &EncryptedText) -> Result<String, String> {
 | 
					    pub fn decrypt(&self, encrypted_data: &EncryptedText) -> Result<String, String> {
 | 
				
			||||||
        let decoded = BASE64_STANDARD.decode(encrypted_data.get_encrypted()).map_err(|e| format!("Error decoding base64: {e}"))?;
 | 
					        let decoded = BASE64_STANDARD.decode(encrypted_data.get_encrypted()).map_err(|e| format!("Error decoding base64: {e}"))?;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@ -119,14 +124,18 @@ impl Encryption {
 | 
				
			|||||||
    }
 | 
					    }
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					/// Represents encrypted text.
 | 
				
			||||||
#[derive(Clone, Serialize, Deserialize)]
 | 
					#[derive(Clone, Serialize, Deserialize)]
 | 
				
			||||||
pub struct EncryptedText(String);
 | 
					pub struct EncryptedText(String);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
impl EncryptedText {
 | 
					impl EncryptedText {
 | 
				
			||||||
 | 
					    
 | 
				
			||||||
 | 
					    /// Creates a new encrypted text instance.
 | 
				
			||||||
    pub fn new(encrypted_data: String) -> Self {
 | 
					    pub fn new(encrypted_data: String) -> Self {
 | 
				
			||||||
        EncryptedText(encrypted_data)
 | 
					        EncryptedText(encrypted_data)
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    /// Returns the encrypted data.
 | 
				
			||||||
    pub fn get_encrypted(&self) -> &str {
 | 
					    pub fn get_encrypted(&self) -> &str {
 | 
				
			||||||
        &self.0
 | 
					        &self.0
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
@ -144,11 +153,13 @@ impl fmt::Display for EncryptedText {
 | 
				
			|||||||
    }
 | 
					    }
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
// Use Case: When we receive encrypted text from the client as body (e.g., in a POST request).
 | 
					/// Use Case: When we receive encrypted text from the client as body (e.g., in a POST request).
 | 
				
			||||||
// We must interpret the body as EncryptedText.
 | 
					/// We must interpret the body as EncryptedText.
 | 
				
			||||||
#[rocket::async_trait]
 | 
					#[rocket::async_trait]
 | 
				
			||||||
impl<'r> data::FromData<'r> for EncryptedText {
 | 
					impl<'r> data::FromData<'r> for EncryptedText {
 | 
				
			||||||
    type Error = String;
 | 
					    type Error = String;
 | 
				
			||||||
 | 
					    
 | 
				
			||||||
 | 
					    /// Parses the data as EncryptedText.
 | 
				
			||||||
    async fn from_data(req: &'r Request<'_>, data: Data<'r>) -> DataOutcome<'r, Self> {
 | 
					    async fn from_data(req: &'r Request<'_>, data: Data<'r>) -> DataOutcome<'r, Self> {
 | 
				
			||||||
        let content_type = req.content_type();
 | 
					        let content_type = req.content_type();
 | 
				
			||||||
        if content_type.map_or(true, |ct| !ct.is_text()) {
 | 
					        if content_type.map_or(true, |ct| !ct.is_text()) {
 | 
				
			||||||
 | 
				
			|||||||
@ -2,10 +2,13 @@ use std::sync::OnceLock;
 | 
				
			|||||||
use rocket::get;
 | 
					use rocket::get;
 | 
				
			||||||
use crate::api_token::APIToken;
 | 
					use crate::api_token::APIToken;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					/// The data directory where the application stores its data.
 | 
				
			||||||
pub static DATA_DIRECTORY: OnceLock<String> = OnceLock::new();
 | 
					pub static DATA_DIRECTORY: OnceLock<String> = OnceLock::new();
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					/// The config directory where the application stores its configuration.
 | 
				
			||||||
pub static CONFIG_DIRECTORY: OnceLock<String> = OnceLock::new();
 | 
					pub static CONFIG_DIRECTORY: OnceLock<String> = OnceLock::new();
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					/// Returns the config directory.
 | 
				
			||||||
#[get("/system/directories/config")]
 | 
					#[get("/system/directories/config")]
 | 
				
			||||||
pub fn get_config_directory(_token: APIToken) -> String {
 | 
					pub fn get_config_directory(_token: APIToken) -> String {
 | 
				
			||||||
    match CONFIG_DIRECTORY.get() {
 | 
					    match CONFIG_DIRECTORY.get() {
 | 
				
			||||||
@ -14,6 +17,7 @@ pub fn get_config_directory(_token: APIToken) -> String {
 | 
				
			|||||||
    }
 | 
					    }
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					/// Returns the data directory.
 | 
				
			||||||
#[get("/system/directories/data")]
 | 
					#[get("/system/directories/data")]
 | 
				
			||||||
pub fn get_data_directory(_token: APIToken) -> String {
 | 
					pub fn get_data_directory(_token: APIToken) -> String {
 | 
				
			||||||
    match DATA_DIRECTORY.get() {
 | 
					    match DATA_DIRECTORY.get() {
 | 
				
			||||||
@ -22,10 +26,12 @@ pub fn get_data_directory(_token: APIToken) -> String {
 | 
				
			|||||||
    }
 | 
					    }
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					/// Returns true if the application is running in development mode.
 | 
				
			||||||
pub fn is_dev() -> bool {
 | 
					pub fn is_dev() -> bool {
 | 
				
			||||||
    cfg!(debug_assertions)
 | 
					    cfg!(debug_assertions)
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					/// Returns true if the application is running in production mode.
 | 
				
			||||||
pub fn is_prod() -> bool {
 | 
					pub fn is_prod() -> bool {
 | 
				
			||||||
    !is_dev()
 | 
					    !is_dev()
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
@ -11,6 +11,7 @@ use crate::environment::is_dev;
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
static LOGGER: OnceLock<RuntimeLoggerHandle> = OnceLock::new();
 | 
					static LOGGER: OnceLock<RuntimeLoggerHandle> = OnceLock::new();
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					/// Initialize the logging system.
 | 
				
			||||||
pub fn init_logging() {
 | 
					pub fn init_logging() {
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    //
 | 
					    //
 | 
				
			||||||
@ -60,6 +61,7 @@ pub fn init_logging() {
 | 
				
			|||||||
    LOGGER.set(runtime_logger).expect("Cannot set LOGGER");
 | 
					    LOGGER.set(runtime_logger).expect("Cannot set LOGGER");
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					/// Switch the logging system to a file-based output.
 | 
				
			||||||
pub fn switch_to_file_logging(logger_path: PathBuf) -> Result<(), Box<dyn Error>>{
 | 
					pub fn switch_to_file_logging(logger_path: PathBuf) -> Result<(), Box<dyn Error>>{
 | 
				
			||||||
    LOGGER.get().expect("No LOGGER was set").handle.reset_flw(&FileLogWriter::builder(
 | 
					    LOGGER.get().expect("No LOGGER was set").handle.reset_flw(&FileLogWriter::builder(
 | 
				
			||||||
        FileSpec::default()
 | 
					        FileSpec::default()
 | 
				
			||||||
@ -137,7 +139,7 @@ fn terminal_colored_logger_format(
 | 
				
			|||||||
    write!(w, "{}", flexi_logger::style(level).paint(record.args().to_string()))
 | 
					    write!(w, "{}", flexi_logger::style(level).paint(record.args().to_string()))
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
// Custom LOGGER format for the log files:
 | 
					/// Custom LOGGER format for the log files:
 | 
				
			||||||
fn file_logger_format(
 | 
					fn file_logger_format(
 | 
				
			||||||
    w: &mut dyn std::io::Write,
 | 
					    w: &mut dyn std::io::Write,
 | 
				
			||||||
    now: &mut DeferredNow,
 | 
					    now: &mut DeferredNow,
 | 
				
			||||||
 | 
				
			|||||||
@ -28,7 +28,6 @@ async fn main() {
 | 
				
			|||||||
    let app_commit_hash = metadata_lines.next().unwrap();
 | 
					    let app_commit_hash = metadata_lines.next().unwrap();
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    init_logging();
 | 
					    init_logging();
 | 
				
			||||||
 | 
					 | 
				
			||||||
    info!("Starting MindWork AI Studio:");
 | 
					    info!("Starting MindWork AI Studio:");
 | 
				
			||||||
    
 | 
					    
 | 
				
			||||||
    let working_directory = std::env::current_dir().unwrap();
 | 
					    let working_directory = std::env::current_dir().unwrap();
 | 
				
			||||||
 | 
				
			|||||||
@ -1,5 +1,6 @@
 | 
				
			|||||||
use std::net::TcpListener;
 | 
					use std::net::TcpListener;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					/// Returns an available port on the local machine.
 | 
				
			||||||
pub fn get_available_port() -> Option<u16> {
 | 
					pub fn get_available_port() -> Option<u16> {
 | 
				
			||||||
    TcpListener::bind(("127.0.0.1", 0))
 | 
					    TcpListener::bind(("127.0.0.1", 0))
 | 
				
			||||||
        .map(|listener| listener.local_addr().unwrap().port())
 | 
					        .map(|listener| listener.local_addr().unwrap().port())
 | 
				
			||||||
 | 
				
			|||||||
@ -8,10 +8,10 @@ use crate::certificate::{CERTIFICATE, CERTIFICATE_PRIVATE_KEY};
 | 
				
			|||||||
use crate::environment::is_dev;
 | 
					use crate::environment::is_dev;
 | 
				
			||||||
use crate::network::get_available_port;
 | 
					use crate::network::get_available_port;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
// The port used for the runtime API server. In the development environment, we use a fixed
 | 
					/// The port used for the runtime API server. In the development environment, we use a fixed
 | 
				
			||||||
// port, in the production environment we use the next available port. This differentiation
 | 
					/// port, in the production environment we use the next available port. This differentiation
 | 
				
			||||||
// is necessary because we cannot communicate the port to the .NET server in the development
 | 
					/// is necessary because we cannot communicate the port to the .NET server in the development
 | 
				
			||||||
// environment.
 | 
					/// environment.
 | 
				
			||||||
pub static API_SERVER_PORT: Lazy<u16> = Lazy::new(|| {
 | 
					pub static API_SERVER_PORT: Lazy<u16> = Lazy::new(|| {
 | 
				
			||||||
    if is_dev() {
 | 
					    if is_dev() {
 | 
				
			||||||
        5000
 | 
					        5000
 | 
				
			||||||
@ -20,6 +20,8 @@ pub static API_SERVER_PORT: Lazy<u16> = Lazy::new(|| {
 | 
				
			|||||||
    }
 | 
					    }
 | 
				
			||||||
});
 | 
					});
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					/// Starts the runtime API server. The server is used to communicate with the .NET server and
 | 
				
			||||||
 | 
					/// to provide additional functionality to the Tauri app.
 | 
				
			||||||
pub fn start_runtime_api() {
 | 
					pub fn start_runtime_api() {
 | 
				
			||||||
    let api_port = *API_SERVER_PORT;
 | 
					    let api_port = *API_SERVER_PORT;
 | 
				
			||||||
    info!("Try to start the API server on 'http://localhost:{api_port}'...");
 | 
					    info!("Try to start the API server on 'http://localhost:{api_port}'...");
 | 
				
			||||||
 | 
				
			|||||||
@ -7,6 +7,7 @@ use keyring::error::Error::NoEntry;
 | 
				
			|||||||
use crate::api_token::APIToken;
 | 
					use crate::api_token::APIToken;
 | 
				
			||||||
use crate::encryption::{EncryptedText, ENCRYPTION};
 | 
					use crate::encryption::{EncryptedText, ENCRYPTION};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					/// Stores a secret in the secret store using the operating system's keyring.
 | 
				
			||||||
#[post("/secrets/store", data = "<request>")]
 | 
					#[post("/secrets/store", data = "<request>")]
 | 
				
			||||||
pub fn store_secret(_token: APIToken, request: Json<StoreSecret>) -> Json<StoreSecretResponse> {
 | 
					pub fn store_secret(_token: APIToken, request: Json<StoreSecret>) -> Json<StoreSecretResponse> {
 | 
				
			||||||
    let user_name = request.user_name.as_str();
 | 
					    let user_name = request.user_name.as_str();
 | 
				
			||||||
@ -43,6 +44,7 @@ pub fn store_secret(_token: APIToken, request: Json<StoreSecret>) -> Json<StoreS
 | 
				
			|||||||
    }
 | 
					    }
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					/// The structure of the request to store a secret.
 | 
				
			||||||
#[derive(Deserialize)]
 | 
					#[derive(Deserialize)]
 | 
				
			||||||
pub struct StoreSecret {
 | 
					pub struct StoreSecret {
 | 
				
			||||||
    destination: String,
 | 
					    destination: String,
 | 
				
			||||||
@ -50,12 +52,14 @@ pub struct StoreSecret {
 | 
				
			|||||||
    secret: EncryptedText,
 | 
					    secret: EncryptedText,
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					/// The structure of the response to storing a secret.
 | 
				
			||||||
#[derive(Serialize)]
 | 
					#[derive(Serialize)]
 | 
				
			||||||
pub struct StoreSecretResponse {
 | 
					pub struct StoreSecretResponse {
 | 
				
			||||||
    success: bool,
 | 
					    success: bool,
 | 
				
			||||||
    issue: String,
 | 
					    issue: String,
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					/// Retrieves a secret from the secret store using the operating system's keyring.
 | 
				
			||||||
#[post("/secrets/get", data = "<request>")]
 | 
					#[post("/secrets/get", data = "<request>")]
 | 
				
			||||||
pub fn get_secret(_token: APIToken, request: Json<RequestSecret>) -> Json<RequestedSecret> {
 | 
					pub fn get_secret(_token: APIToken, request: Json<RequestSecret>) -> Json<RequestedSecret> {
 | 
				
			||||||
    let user_name = request.user_name.as_str();
 | 
					    let user_name = request.user_name.as_str();
 | 
				
			||||||
@ -100,6 +104,7 @@ pub fn get_secret(_token: APIToken, request: Json<RequestSecret>) -> Json<Reques
 | 
				
			|||||||
    }
 | 
					    }
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					/// The structure of the request to retrieve a secret.
 | 
				
			||||||
#[derive(Deserialize)]
 | 
					#[derive(Deserialize)]
 | 
				
			||||||
pub struct RequestSecret {
 | 
					pub struct RequestSecret {
 | 
				
			||||||
    destination: String,
 | 
					    destination: String,
 | 
				
			||||||
@ -107,6 +112,7 @@ pub struct RequestSecret {
 | 
				
			|||||||
    is_trying: bool,
 | 
					    is_trying: bool,
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					/// The structure of the response to retrieving a secret.
 | 
				
			||||||
#[derive(Serialize)]
 | 
					#[derive(Serialize)]
 | 
				
			||||||
pub struct RequestedSecret {
 | 
					pub struct RequestedSecret {
 | 
				
			||||||
    success: bool,
 | 
					    success: bool,
 | 
				
			||||||
@ -114,6 +120,7 @@ pub struct RequestedSecret {
 | 
				
			|||||||
    issue: String,
 | 
					    issue: String,
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					/// Deletes a secret from the secret store using the operating system's keyring.
 | 
				
			||||||
#[post("/secrets/delete", data = "<request>")]
 | 
					#[post("/secrets/delete", data = "<request>")]
 | 
				
			||||||
pub fn delete_secret(_token: APIToken, request: Json<RequestSecret>) -> Json<DeleteSecretResponse> {
 | 
					pub fn delete_secret(_token: APIToken, request: Json<RequestSecret>) -> Json<DeleteSecretResponse> {
 | 
				
			||||||
    let user_name = request.user_name.as_str();
 | 
					    let user_name = request.user_name.as_str();
 | 
				
			||||||
@ -151,6 +158,7 @@ pub fn delete_secret(_token: APIToken, request: Json<RequestSecret>) -> Json<Del
 | 
				
			|||||||
    }
 | 
					    }
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					/// The structure of the response to deleting a secret.
 | 
				
			||||||
#[derive(Serialize)]
 | 
					#[derive(Serialize)]
 | 
				
			||||||
pub struct DeleteSecretResponse {
 | 
					pub struct DeleteSecretResponse {
 | 
				
			||||||
    success: bool,
 | 
					    success: bool,
 | 
				
			||||||
 | 
				
			|||||||
		Loading…
	
		Reference in New Issue
	
	Block a user