Refactored secret-related api

This commit is contained in:
Thorsten Sommer 2024-11-05 20:32:57 +01:00
parent 0a6032f0ff
commit 6044550d92
Signed by: tsommer
GPG Key ID: 371BBA77A02C0108
3 changed files with 165 additions and 158 deletions

View File

@ -5,3 +5,4 @@ pub mod dotnet;
pub mod network;
pub mod api_token;
pub mod app_window;
pub mod secret;

View File

@ -8,9 +8,7 @@ use std::collections::HashSet;
use once_cell::sync::Lazy;
use arboard::Clipboard;
use keyring::Entry;
use serde::{Deserialize, Serialize};
use keyring::error::Error::NoEntry;
use serde::Serialize;
use log::{debug, error, info, warn};
use rcgen::generate_simple_self_signed;
use rocket::figment::Figment;
@ -148,9 +146,9 @@ async fn main() {
set_clipboard,
mindwork_ai_studio::app_window::check_for_update,
mindwork_ai_studio::app_window::install_update,
get_secret,
store_secret,
delete_secret,
mindwork_ai_studio::secret::get_secret,
mindwork_ai_studio::secret::store_secret,
mindwork_ai_studio::secret::delete_secret,
mindwork_ai_studio::environment::get_data_directory,
mindwork_ai_studio::environment::get_config_directory,
])
@ -163,157 +161,6 @@ async fn main() {
start_tauri();
}
#[post("/secrets/store", data = "<request>")]
fn store_secret(_token: APIToken, request: Json<StoreSecret>) -> Json<StoreSecretResponse> {
let user_name = request.user_name.as_str();
let decrypted_text = match ENCRYPTION.decrypt(&request.secret) {
Ok(text) => text,
Err(e) => {
error!(Source = "Secret Store"; "Failed to decrypt the text: {e}.");
return Json(StoreSecretResponse {
success: false,
issue: format!("Failed to decrypt the text: {e}"),
})
},
};
let service = format!("mindwork-ai-studio::{}", request.destination);
let entry = Entry::new(service.as_str(), user_name).unwrap();
let result = entry.set_password(decrypted_text.as_str());
match result {
Ok(_) => {
info!(Source = "Secret Store"; "Secret for {service} and user {user_name} was stored successfully.");
Json(StoreSecretResponse {
success: true,
issue: String::from(""),
})
},
Err(e) => {
error!(Source = "Secret Store"; "Failed to store secret for {service} and user {user_name}: {e}.");
Json(StoreSecretResponse {
success: false,
issue: e.to_string(),
})
},
}
}
#[derive(Deserialize)]
struct StoreSecret {
destination: String,
user_name: String,
secret: EncryptedText,
}
#[derive(Serialize)]
struct StoreSecretResponse {
success: bool,
issue: String,
}
#[post("/secrets/get", data = "<request>")]
fn get_secret(_token: APIToken, request: Json<RequestSecret>) -> Json<RequestedSecret> {
let user_name = request.user_name.as_str();
let service = format!("mindwork-ai-studio::{}", request.destination);
let entry = Entry::new(service.as_str(), user_name).unwrap();
let secret = entry.get_password();
match secret {
Ok(s) => {
info!(Source = "Secret Store"; "Secret for '{service}' and user '{user_name}' was retrieved successfully.");
// Encrypt the secret:
let encrypted_secret = match ENCRYPTION.encrypt(s.as_str()) {
Ok(e) => e,
Err(e) => {
error!(Source = "Secret Store"; "Failed to encrypt the secret: {e}.");
return Json(RequestedSecret {
success: false,
secret: EncryptedText::new(String::from("")),
issue: format!("Failed to encrypt the secret: {e}"),
});
},
};
Json(RequestedSecret {
success: true,
secret: encrypted_secret,
issue: String::from(""),
})
},
Err(e) => {
if !request.is_trying {
error!(Source = "Secret Store"; "Failed to retrieve secret for '{service}' and user '{user_name}': {e}.");
}
Json(RequestedSecret {
success: false,
secret: EncryptedText::new(String::from("")),
issue: format!("Failed to retrieve secret for '{service}' and user '{user_name}': {e}"),
})
},
}
}
#[derive(Deserialize)]
struct RequestSecret {
destination: String,
user_name: String,
is_trying: bool,
}
#[derive(Serialize)]
struct RequestedSecret {
success: bool,
secret: EncryptedText,
issue: String,
}
#[post("/secrets/delete", data = "<request>")]
fn delete_secret(_token: APIToken, request: Json<RequestSecret>) -> Json<DeleteSecretResponse> {
let user_name = request.user_name.as_str();
let service = format!("mindwork-ai-studio::{}", request.destination);
let entry = Entry::new(service.as_str(), user_name).unwrap();
let result = entry.delete_credential();
match result {
Ok(_) => {
warn!(Source = "Secret Store"; "Secret for {service} and user {user_name} was deleted successfully.");
Json(DeleteSecretResponse {
success: true,
was_entry_found: true,
issue: String::from(""),
})
},
Err(NoEntry) => {
warn!(Source = "Secret Store"; "No secret for {service} and user {user_name} was found.");
Json(DeleteSecretResponse {
success: true,
was_entry_found: false,
issue: String::from(""),
})
}
Err(e) => {
error!(Source = "Secret Store"; "Failed to delete secret for {service} and user {user_name}: {e}.");
Json(DeleteSecretResponse {
success: false,
was_entry_found: false,
issue: e.to_string(),
})
},
}
}
#[derive(Serialize)]
struct DeleteSecretResponse {
success: bool,
was_entry_found: bool,
issue: String,
}
#[post("/clipboard/set", data = "<encrypted_text>")]
fn set_clipboard(_token: APIToken, encrypted_text: EncryptedText) -> Json<SetClipboardResponse> {

159
runtime/src/secret.rs Normal file
View File

@ -0,0 +1,159 @@
use keyring::Entry;
use log::{error, info, warn};
use rocket::post;
use rocket::serde::json::Json;
use serde::{Deserialize, Serialize};
use keyring::error::Error::NoEntry;
use crate::api_token::APIToken;
use crate::encryption::{EncryptedText, ENCRYPTION};
#[post("/secrets/store", data = "<request>")]
pub fn store_secret(_token: APIToken, request: Json<StoreSecret>) -> Json<StoreSecretResponse> {
let user_name = request.user_name.as_str();
let decrypted_text = match ENCRYPTION.decrypt(&request.secret) {
Ok(text) => text,
Err(e) => {
error!(Source = "Secret Store"; "Failed to decrypt the text: {e}.");
return Json(StoreSecretResponse {
success: false,
issue: format!("Failed to decrypt the text: {e}"),
})
},
};
let service = format!("mindwork-ai-studio::{}", request.destination);
let entry = Entry::new(service.as_str(), user_name).unwrap();
let result = entry.set_password(decrypted_text.as_str());
match result {
Ok(_) => {
info!(Source = "Secret Store"; "Secret for {service} and user {user_name} was stored successfully.");
Json(StoreSecretResponse {
success: true,
issue: String::from(""),
})
},
Err(e) => {
error!(Source = "Secret Store"; "Failed to store secret for {service} and user {user_name}: {e}.");
Json(StoreSecretResponse {
success: false,
issue: e.to_string(),
})
},
}
}
#[derive(Deserialize)]
pub struct StoreSecret {
destination: String,
user_name: String,
secret: EncryptedText,
}
#[derive(Serialize)]
pub struct StoreSecretResponse {
success: bool,
issue: String,
}
#[post("/secrets/get", data = "<request>")]
pub fn get_secret(_token: APIToken, request: Json<RequestSecret>) -> Json<RequestedSecret> {
let user_name = request.user_name.as_str();
let service = format!("mindwork-ai-studio::{}", request.destination);
let entry = Entry::new(service.as_str(), user_name).unwrap();
let secret = entry.get_password();
match secret {
Ok(s) => {
info!(Source = "Secret Store"; "Secret for '{service}' and user '{user_name}' was retrieved successfully.");
// Encrypt the secret:
let encrypted_secret = match ENCRYPTION.encrypt(s.as_str()) {
Ok(e) => e,
Err(e) => {
error!(Source = "Secret Store"; "Failed to encrypt the secret: {e}.");
return Json(RequestedSecret {
success: false,
secret: EncryptedText::new(String::from("")),
issue: format!("Failed to encrypt the secret: {e}"),
});
},
};
Json(RequestedSecret {
success: true,
secret: encrypted_secret,
issue: String::from(""),
})
},
Err(e) => {
if !request.is_trying {
error!(Source = "Secret Store"; "Failed to retrieve secret for '{service}' and user '{user_name}': {e}.");
}
Json(RequestedSecret {
success: false,
secret: EncryptedText::new(String::from("")),
issue: format!("Failed to retrieve secret for '{service}' and user '{user_name}': {e}"),
})
},
}
}
#[derive(Deserialize)]
pub struct RequestSecret {
destination: String,
user_name: String,
is_trying: bool,
}
#[derive(Serialize)]
pub struct RequestedSecret {
success: bool,
secret: EncryptedText,
issue: String,
}
#[post("/secrets/delete", data = "<request>")]
pub fn delete_secret(_token: APIToken, request: Json<RequestSecret>) -> Json<DeleteSecretResponse> {
let user_name = request.user_name.as_str();
let service = format!("mindwork-ai-studio::{}", request.destination);
let entry = Entry::new(service.as_str(), user_name).unwrap();
let result = entry.delete_credential();
match result {
Ok(_) => {
warn!(Source = "Secret Store"; "Secret for {service} and user {user_name} was deleted successfully.");
Json(DeleteSecretResponse {
success: true,
was_entry_found: true,
issue: String::from(""),
})
},
Err(NoEntry) => {
warn!(Source = "Secret Store"; "No secret for {service} and user {user_name} was found.");
Json(DeleteSecretResponse {
success: true,
was_entry_found: false,
issue: String::from(""),
})
}
Err(e) => {
error!(Source = "Secret Store"; "Failed to delete secret for {service} and user {user_name}: {e}.");
Json(DeleteSecretResponse {
success: false,
was_entry_found: false,
issue: e.to_string(),
})
},
}
}
#[derive(Serialize)]
pub struct DeleteSecretResponse {
success: bool,
was_entry_found: bool,
issue: String,
}