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::FromRequest;
 | 
			
		||||
 | 
			
		||||
/// The API token used to authenticate requests.
 | 
			
		||||
pub static API_TOKEN: Lazy<APIToken> = Lazy::new(|| {
 | 
			
		||||
    let mut token = [0u8; 32];
 | 
			
		||||
    let mut rng = rand_chacha::ChaChaRng::from_entropy();
 | 
			
		||||
@ -16,11 +17,13 @@ pub static API_TOKEN: Lazy<APIToken> = Lazy::new(|| {
 | 
			
		||||
    token
 | 
			
		||||
});
 | 
			
		||||
 | 
			
		||||
/// The API token data structure used to authenticate requests.
 | 
			
		||||
pub struct APIToken {
 | 
			
		||||
    hex_text: String,
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
impl APIToken {
 | 
			
		||||
    /// Creates a new API token from a byte vector.
 | 
			
		||||
    fn from_bytes(bytes: Vec<u8>) -> Self {
 | 
			
		||||
        APIToken {
 | 
			
		||||
            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 {
 | 
			
		||||
        APIToken {
 | 
			
		||||
            hex_text: hex_text.to_string(),
 | 
			
		||||
@ -40,17 +44,21 @@ impl APIToken {
 | 
			
		||||
        self.hex_text.as_str()
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    /// Validates the received token against the valid token.
 | 
			
		||||
    fn validate(&self, received_token: &Self) -> bool {
 | 
			
		||||
        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>;
 | 
			
		||||
 | 
			
		||||
/// The request outcome implementation for the API token.
 | 
			
		||||
#[rocket::async_trait]
 | 
			
		||||
impl<'r> FromRequest<'r> for APIToken {
 | 
			
		||||
    type Error = APITokenError;
 | 
			
		||||
 | 
			
		||||
    /// Handles the API token requests.
 | 
			
		||||
    async fn from_request(request: &'r Request<'_>) -> RequestOutcome<Self, Self::Error> {
 | 
			
		||||
        let token = request.headers().get_one("token");
 | 
			
		||||
        match token {
 | 
			
		||||
@ -68,6 +76,7 @@ impl<'r> FromRequest<'r> for APIToken {
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
/// The API token error types.
 | 
			
		||||
#[derive(Debug)]
 | 
			
		||||
pub enum APITokenError {
 | 
			
		||||
    Missing,
 | 
			
		||||
 | 
			
		||||
@ -13,12 +13,13 @@ use crate::dotnet::stop_dotnet_server;
 | 
			
		||||
use crate::environment::{is_prod, CONFIG_DIRECTORY, DATA_DIRECTORY};
 | 
			
		||||
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));
 | 
			
		||||
 | 
			
		||||
// 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));
 | 
			
		||||
 | 
			
		||||
/// Starts the Tauri app.
 | 
			
		||||
pub fn start_tauri() {
 | 
			
		||||
    info!("Starting Tauri app...");
 | 
			
		||||
    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) {
 | 
			
		||||
    // Try to get the main window. If it is not available yet, wait for it:
 | 
			
		||||
    let mut main_window_ready = false;
 | 
			
		||||
@ -149,6 +151,7 @@ pub async fn change_location_to(url: &str) {
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
/// Checks for updates.
 | 
			
		||||
#[get("/updates/check")]
 | 
			
		||||
pub async fn check_for_update(_token: APIToken) -> Json<CheckUpdateResponse> {
 | 
			
		||||
    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)]
 | 
			
		||||
pub struct CheckUpdateResponse {
 | 
			
		||||
    update_is_available: bool,
 | 
			
		||||
@ -202,6 +206,7 @@ pub struct CheckUpdateResponse {
 | 
			
		||||
    changelog: String,
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
/// Installs the update.
 | 
			
		||||
#[get("/updates/install")]
 | 
			
		||||
pub async fn install_update(_token: APIToken) {
 | 
			
		||||
    let cloned_response_option = CHECK_UPDATE_RESPONSE.lock().unwrap().clone();
 | 
			
		||||
 | 
			
		||||
@ -3,10 +3,16 @@ use log::info;
 | 
			
		||||
use rcgen::generate_simple_self_signed;
 | 
			
		||||
use sha2::{Sha256, Digest};
 | 
			
		||||
 | 
			
		||||
/// The certificate used for the runtime API server.
 | 
			
		||||
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();
 | 
			
		||||
 | 
			
		||||
/// The fingerprint of the certificate used for the runtime API server.
 | 
			
		||||
pub static CERTIFICATE_FINGERPRINT: OnceLock<String> = OnceLock::new();
 | 
			
		||||
 | 
			
		||||
/// Generates a TLS certificate for the runtime API server.
 | 
			
		||||
pub fn generate_certificate() {
 | 
			
		||||
    
 | 
			
		||||
    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::encryption::{EncryptedText, ENCRYPTION};
 | 
			
		||||
 | 
			
		||||
/// Sets the clipboard text to the provided encrypted text.
 | 
			
		||||
#[post("/clipboard/set", data = "<encrypted_text>")]
 | 
			
		||||
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)]
 | 
			
		||||
pub struct SetClipboardResponse {
 | 
			
		||||
    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));
 | 
			
		||||
 | 
			
		||||
/// 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")]
 | 
			
		||||
pub fn dotnet_port(_token: APIToken) -> String {
 | 
			
		||||
    let dotnet_server_port = *DOTNET_SERVER_PORT;
 | 
			
		||||
    format!("{dotnet_server_port}")
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
/// Starts the .NET server in a separate process.
 | 
			
		||||
pub fn start_dotnet_server() {
 | 
			
		||||
 | 
			
		||||
    // 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")]
 | 
			
		||||
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;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
/// Stops the .NET server process.
 | 
			
		||||
pub fn stop_dotnet_server() {
 | 
			
		||||
    if let Some(server_process) = DOTNET_SERVER.lock().unwrap().take() {
 | 
			
		||||
        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>;
 | 
			
		||||
 | 
			
		||||
/// The encryption instance used for the IPC channel.
 | 
			
		||||
pub static ENCRYPTION: Lazy<Encryption> = Lazy::new(|| {
 | 
			
		||||
    //
 | 
			
		||||
    // 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()
 | 
			
		||||
});
 | 
			
		||||
 | 
			
		||||
/// The encryption struct used for the IPC channel.
 | 
			
		||||
pub struct Encryption {
 | 
			
		||||
    key: [u8; 32],
 | 
			
		||||
    iv: [u8; 16],
 | 
			
		||||
@ -58,6 +60,7 @@ impl Encryption {
 | 
			
		||||
    // algorithms we chose, requires a fixed key length, and our password is too long.
 | 
			
		||||
    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> {
 | 
			
		||||
        if secret_password.len() != 512 {
 | 
			
		||||
            return Err("The secret password must be 512 bytes long.".to_string());
 | 
			
		||||
@ -92,6 +95,7 @@ impl Encryption {
 | 
			
		||||
        Ok(encryption)
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    /// Encrypts the given data.
 | 
			
		||||
    pub fn encrypt(&self, data: &str) -> Result<EncryptedText, String> {
 | 
			
		||||
        let cipher = Aes256CbcEnc::new(&self.key.into(), &self.iv.into());
 | 
			
		||||
        let encrypted = cipher.encrypt_padded_vec_mut::<Pkcs7>(data.as_bytes());
 | 
			
		||||
@ -100,6 +104,7 @@ impl Encryption {
 | 
			
		||||
        Ok(EncryptedText::new(result))
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    /// Decrypts the given data.
 | 
			
		||||
    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}"))?;
 | 
			
		||||
 | 
			
		||||
@ -119,14 +124,18 @@ impl Encryption {
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
/// Represents encrypted text.
 | 
			
		||||
#[derive(Clone, Serialize, Deserialize)]
 | 
			
		||||
pub struct EncryptedText(String);
 | 
			
		||||
 | 
			
		||||
impl EncryptedText {
 | 
			
		||||
    
 | 
			
		||||
    /// Creates a new encrypted text instance.
 | 
			
		||||
    pub fn new(encrypted_data: String) -> Self {
 | 
			
		||||
        EncryptedText(encrypted_data)
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    /// Returns the encrypted data.
 | 
			
		||||
    pub fn get_encrypted(&self) -> &str {
 | 
			
		||||
        &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).
 | 
			
		||||
// We must interpret the body as EncryptedText.
 | 
			
		||||
/// 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.
 | 
			
		||||
#[rocket::async_trait]
 | 
			
		||||
impl<'r> data::FromData<'r> for EncryptedText {
 | 
			
		||||
    type Error = String;
 | 
			
		||||
    
 | 
			
		||||
    /// Parses the data as EncryptedText.
 | 
			
		||||
    async fn from_data(req: &'r Request<'_>, data: Data<'r>) -> DataOutcome<'r, Self> {
 | 
			
		||||
        let content_type = req.content_type();
 | 
			
		||||
        if content_type.map_or(true, |ct| !ct.is_text()) {
 | 
			
		||||
 | 
			
		||||
@ -2,10 +2,13 @@ use std::sync::OnceLock;
 | 
			
		||||
use rocket::get;
 | 
			
		||||
use crate::api_token::APIToken;
 | 
			
		||||
 | 
			
		||||
/// The data directory where the application stores its data.
 | 
			
		||||
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();
 | 
			
		||||
 | 
			
		||||
/// Returns the config directory.
 | 
			
		||||
#[get("/system/directories/config")]
 | 
			
		||||
pub fn get_config_directory(_token: APIToken) -> String {
 | 
			
		||||
    match CONFIG_DIRECTORY.get() {
 | 
			
		||||
@ -14,6 +17,7 @@ pub fn get_config_directory(_token: APIToken) -> String {
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
/// Returns the data directory.
 | 
			
		||||
#[get("/system/directories/data")]
 | 
			
		||||
pub fn get_data_directory(_token: APIToken) -> String {
 | 
			
		||||
    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 {
 | 
			
		||||
    cfg!(debug_assertions)
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
/// Returns true if the application is running in production mode.
 | 
			
		||||
pub fn is_prod() -> bool {
 | 
			
		||||
    !is_dev()
 | 
			
		||||
}
 | 
			
		||||
@ -11,6 +11,7 @@ use crate::environment::is_dev;
 | 
			
		||||
 | 
			
		||||
static LOGGER: OnceLock<RuntimeLoggerHandle> = OnceLock::new();
 | 
			
		||||
 | 
			
		||||
/// Initialize the logging system.
 | 
			
		||||
pub fn init_logging() {
 | 
			
		||||
 | 
			
		||||
    //
 | 
			
		||||
@ -60,6 +61,7 @@ pub fn init_logging() {
 | 
			
		||||
    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>>{
 | 
			
		||||
    LOGGER.get().expect("No LOGGER was set").handle.reset_flw(&FileLogWriter::builder(
 | 
			
		||||
        FileSpec::default()
 | 
			
		||||
@ -137,7 +139,7 @@ fn terminal_colored_logger_format(
 | 
			
		||||
    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(
 | 
			
		||||
    w: &mut dyn std::io::Write,
 | 
			
		||||
    now: &mut DeferredNow,
 | 
			
		||||
 | 
			
		||||
@ -28,7 +28,6 @@ async fn main() {
 | 
			
		||||
    let app_commit_hash = metadata_lines.next().unwrap();
 | 
			
		||||
 | 
			
		||||
    init_logging();
 | 
			
		||||
 | 
			
		||||
    info!("Starting MindWork AI Studio:");
 | 
			
		||||
    
 | 
			
		||||
    let working_directory = std::env::current_dir().unwrap();
 | 
			
		||||
 | 
			
		||||
@ -1,5 +1,6 @@
 | 
			
		||||
use std::net::TcpListener;
 | 
			
		||||
 | 
			
		||||
/// Returns an available port on the local machine.
 | 
			
		||||
pub fn get_available_port() -> Option<u16> {
 | 
			
		||||
    TcpListener::bind(("127.0.0.1", 0))
 | 
			
		||||
        .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::network::get_available_port;
 | 
			
		||||
 | 
			
		||||
// 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
 | 
			
		||||
// is necessary because we cannot communicate the port to the .NET server in the development
 | 
			
		||||
// environment.
 | 
			
		||||
/// 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
 | 
			
		||||
/// is necessary because we cannot communicate the port to the .NET server in the development
 | 
			
		||||
/// environment.
 | 
			
		||||
pub static API_SERVER_PORT: Lazy<u16> = Lazy::new(|| {
 | 
			
		||||
    if is_dev() {
 | 
			
		||||
        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() {
 | 
			
		||||
    let api_port = *API_SERVER_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::encryption::{EncryptedText, ENCRYPTION};
 | 
			
		||||
 | 
			
		||||
/// Stores a secret in the secret store using the operating system's keyring.
 | 
			
		||||
#[post("/secrets/store", data = "<request>")]
 | 
			
		||||
pub fn store_secret(_token: APIToken, request: Json<StoreSecret>) -> Json<StoreSecretResponse> {
 | 
			
		||||
    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)]
 | 
			
		||||
pub struct StoreSecret {
 | 
			
		||||
    destination: String,
 | 
			
		||||
@ -50,12 +52,14 @@ pub struct StoreSecret {
 | 
			
		||||
    secret: EncryptedText,
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
/// The structure of the response to storing a secret.
 | 
			
		||||
#[derive(Serialize)]
 | 
			
		||||
pub struct StoreSecretResponse {
 | 
			
		||||
    success: bool,
 | 
			
		||||
    issue: String,
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
/// Retrieves a secret from the secret store using the operating system's keyring.
 | 
			
		||||
#[post("/secrets/get", data = "<request>")]
 | 
			
		||||
pub fn get_secret(_token: APIToken, request: Json<RequestSecret>) -> Json<RequestedSecret> {
 | 
			
		||||
    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)]
 | 
			
		||||
pub struct RequestSecret {
 | 
			
		||||
    destination: String,
 | 
			
		||||
@ -107,6 +112,7 @@ pub struct RequestSecret {
 | 
			
		||||
    is_trying: bool,
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
/// The structure of the response to retrieving a secret.
 | 
			
		||||
#[derive(Serialize)]
 | 
			
		||||
pub struct RequestedSecret {
 | 
			
		||||
    success: bool,
 | 
			
		||||
@ -114,6 +120,7 @@ pub struct RequestedSecret {
 | 
			
		||||
    issue: String,
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
/// Deletes a secret from the secret store using the operating system's keyring.
 | 
			
		||||
#[post("/secrets/delete", data = "<request>")]
 | 
			
		||||
pub fn delete_secret(_token: APIToken, request: Json<RequestSecret>) -> Json<DeleteSecretResponse> {
 | 
			
		||||
    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)]
 | 
			
		||||
pub struct DeleteSecretResponse {
 | 
			
		||||
    success: bool,
 | 
			
		||||
 | 
			
		||||
		Loading…
	
		Reference in New Issue
	
	Block a user