feat: introduce hero_vault
This commit is contained in:
416
src/rhai/crypto.rs
Normal file
416
src/rhai/crypto.rs
Normal file
@@ -0,0 +1,416 @@
|
||||
//! Rhai bindings for SAL crypto functionality
|
||||
|
||||
use rhai::{Engine, Dynamic, FnPtr, EvalAltResult};
|
||||
use base64::{Engine as _, engine::general_purpose::STANDARD as BASE64};
|
||||
use std::fs;
|
||||
use std::path::PathBuf;
|
||||
|
||||
use crate::crypto::{keypair, symmetric, ethereum};
|
||||
use crate::crypto::error::CryptoError;
|
||||
use crate::crypto::kvs;
|
||||
|
||||
// Key space management functions
|
||||
fn load_key_space(name: &str, password: &str) -> bool {
|
||||
// Get the key spaces directory from config
|
||||
let home_dir = dirs::home_dir().unwrap_or_else(|| PathBuf::from("."));
|
||||
let key_spaces_dir = home_dir.join(".hero-vault").join("key-spaces");
|
||||
|
||||
// Check if directory exists
|
||||
if !key_spaces_dir.exists() {
|
||||
log::error!("Key spaces directory does not exist");
|
||||
return false;
|
||||
}
|
||||
|
||||
// Get the key space file path
|
||||
let space_path = key_spaces_dir.join(format!("{}.json", name));
|
||||
|
||||
// Check if file exists
|
||||
if !space_path.exists() {
|
||||
log::error!("Key space file not found: {}", space_path.display());
|
||||
return false;
|
||||
}
|
||||
|
||||
// Read the file
|
||||
let serialized = match fs::read_to_string(&space_path) {
|
||||
Ok(data) => data,
|
||||
Err(e) => {
|
||||
log::error!("Error reading key space file: {}", e);
|
||||
return false;
|
||||
}
|
||||
};
|
||||
|
||||
// Deserialize the encrypted space
|
||||
let encrypted_space = match symmetric::deserialize_encrypted_space(&serialized) {
|
||||
Ok(space) => space,
|
||||
Err(e) => {
|
||||
log::error!("Error deserializing key space: {}", e);
|
||||
return false;
|
||||
}
|
||||
};
|
||||
|
||||
// Decrypt the space
|
||||
let space = match symmetric::decrypt_key_space(&encrypted_space, password) {
|
||||
Ok(space) => space,
|
||||
Err(e) => {
|
||||
log::error!("Error decrypting key space: {}", e);
|
||||
return false;
|
||||
}
|
||||
};
|
||||
|
||||
// Set as current space
|
||||
match keypair::set_current_space(space) {
|
||||
Ok(_) => true,
|
||||
Err(e) => {
|
||||
log::error!("Error setting current space: {}", e);
|
||||
false
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
fn create_key_space(name: &str, password: &str) -> bool {
|
||||
match keypair::create_space(name) {
|
||||
Ok(_) => {
|
||||
// Get the current space
|
||||
match keypair::get_current_space() {
|
||||
Ok(space) => {
|
||||
// Encrypt the key space
|
||||
let encrypted_space = match symmetric::encrypt_key_space(&space, password) {
|
||||
Ok(encrypted) => encrypted,
|
||||
Err(e) => {
|
||||
log::error!("Error encrypting key space: {}", e);
|
||||
return false;
|
||||
}
|
||||
};
|
||||
|
||||
// Serialize the encrypted space
|
||||
let serialized = match symmetric::serialize_encrypted_space(&encrypted_space) {
|
||||
Ok(json) => json,
|
||||
Err(e) => {
|
||||
log::error!("Error serializing encrypted space: {}", e);
|
||||
return false;
|
||||
}
|
||||
};
|
||||
|
||||
// Get the key spaces directory
|
||||
let home_dir = dirs::home_dir().unwrap_or_else(|| PathBuf::from("."));
|
||||
let key_spaces_dir = home_dir.join(".hero-vault").join("key-spaces");
|
||||
|
||||
// Create directory if it doesn't exist
|
||||
if !key_spaces_dir.exists() {
|
||||
match fs::create_dir_all(&key_spaces_dir) {
|
||||
Ok(_) => {},
|
||||
Err(e) => {
|
||||
log::error!("Error creating key spaces directory: {}", e);
|
||||
return false;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Write to file
|
||||
let space_path = key_spaces_dir.join(format!("{}.json", name));
|
||||
match fs::write(&space_path, serialized) {
|
||||
Ok(_) => {
|
||||
log::info!("Key space created and saved to {}", space_path.display());
|
||||
true
|
||||
},
|
||||
Err(e) => {
|
||||
log::error!("Error writing key space file: {}", e);
|
||||
false
|
||||
}
|
||||
}
|
||||
},
|
||||
Err(e) => {
|
||||
log::error!("Error getting current space: {}", e);
|
||||
false
|
||||
}
|
||||
}
|
||||
},
|
||||
Err(e) => {
|
||||
log::error!("Error creating key space: {}", e);
|
||||
false
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Auto-save function for internal use
|
||||
fn auto_save_key_space(password: &str) -> bool {
|
||||
match keypair::get_current_space() {
|
||||
Ok(space) => {
|
||||
// Encrypt the key space
|
||||
let encrypted_space = match symmetric::encrypt_key_space(&space, password) {
|
||||
Ok(encrypted) => encrypted,
|
||||
Err(e) => {
|
||||
log::error!("Error encrypting key space: {}", e);
|
||||
return false;
|
||||
}
|
||||
};
|
||||
|
||||
// Serialize the encrypted space
|
||||
let serialized = match symmetric::serialize_encrypted_space(&encrypted_space) {
|
||||
Ok(json) => json,
|
||||
Err(e) => {
|
||||
log::error!("Error serializing encrypted space: {}", e);
|
||||
return false;
|
||||
}
|
||||
};
|
||||
|
||||
// Get the key spaces directory
|
||||
let home_dir = dirs::home_dir().unwrap_or_else(|| PathBuf::from("."));
|
||||
let key_spaces_dir = home_dir.join(".hero-vault").join("key-spaces");
|
||||
|
||||
// Create directory if it doesn't exist
|
||||
if !key_spaces_dir.exists() {
|
||||
match fs::create_dir_all(&key_spaces_dir) {
|
||||
Ok(_) => {},
|
||||
Err(e) => {
|
||||
log::error!("Error creating key spaces directory: {}", e);
|
||||
return false;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Write to file
|
||||
let space_path = key_spaces_dir.join(format!("{}.json", space.name));
|
||||
match fs::write(&space_path, serialized) {
|
||||
Ok(_) => {
|
||||
log::info!("Key space saved to {}", space_path.display());
|
||||
true
|
||||
},
|
||||
Err(e) => {
|
||||
log::error!("Error writing key space file: {}", e);
|
||||
false
|
||||
}
|
||||
}
|
||||
},
|
||||
Err(e) => {
|
||||
log::error!("Error getting current space: {}", e);
|
||||
false
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
fn encrypt_key_space(password: &str) -> String {
|
||||
match keypair::get_current_space() {
|
||||
Ok(space) => {
|
||||
match symmetric::encrypt_key_space(&space, password) {
|
||||
Ok(encrypted_space) => {
|
||||
match serde_json::to_string(&encrypted_space) {
|
||||
Ok(json) => json,
|
||||
Err(e) => {
|
||||
log::error!("Error serializing encrypted space: {}", e);
|
||||
String::new()
|
||||
}
|
||||
}
|
||||
},
|
||||
Err(e) => {
|
||||
log::error!("Error encrypting key space: {}", e);
|
||||
String::new()
|
||||
}
|
||||
}
|
||||
},
|
||||
Err(e) => {
|
||||
log::error!("Error getting current space: {}", e);
|
||||
String::new()
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
fn decrypt_key_space(encrypted: &str, password: &str) -> bool {
|
||||
match serde_json::from_str(encrypted) {
|
||||
Ok(encrypted_space) => {
|
||||
match symmetric::decrypt_key_space(&encrypted_space, password) {
|
||||
Ok(space) => {
|
||||
match keypair::set_current_space(space) {
|
||||
Ok(_) => true,
|
||||
Err(e) => {
|
||||
log::error!("Error setting current space: {}", e);
|
||||
false
|
||||
}
|
||||
}
|
||||
},
|
||||
Err(e) => {
|
||||
log::error!("Error decrypting key space: {}", e);
|
||||
false
|
||||
}
|
||||
}
|
||||
},
|
||||
Err(e) => {
|
||||
log::error!("Error parsing encrypted space: {}", e);
|
||||
false
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Keypair management functions
|
||||
fn create_keypair(name: &str, password: &str) -> bool {
|
||||
match keypair::create_keypair(name) {
|
||||
Ok(_) => {
|
||||
// Auto-save the key space after creating a keypair
|
||||
auto_save_key_space(password)
|
||||
},
|
||||
Err(e) => {
|
||||
log::error!("Error creating keypair: {}", e);
|
||||
false
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
fn select_keypair(name: &str) -> bool {
|
||||
match keypair::select_keypair(name) {
|
||||
Ok(_) => true,
|
||||
Err(e) => {
|
||||
log::error!("Error selecting keypair: {}", e);
|
||||
false
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
fn list_keypairs() -> Vec<String> {
|
||||
match keypair::list_keypairs() {
|
||||
Ok(keypairs) => keypairs,
|
||||
Err(e) => {
|
||||
log::error!("Error listing keypairs: {}", e);
|
||||
Vec::new()
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Cryptographic operations
|
||||
fn sign(message: &str) -> String {
|
||||
let message_bytes = message.as_bytes();
|
||||
match keypair::keypair_sign(message_bytes) {
|
||||
Ok(signature) => BASE64.encode(signature),
|
||||
Err(e) => {
|
||||
log::error!("Error signing message: {}", e);
|
||||
String::new()
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
fn verify(message: &str, signature: &str) -> bool {
|
||||
let message_bytes = message.as_bytes();
|
||||
match BASE64.decode(signature) {
|
||||
Ok(signature_bytes) => {
|
||||
match keypair::keypair_verify(message_bytes, &signature_bytes) {
|
||||
Ok(is_valid) => is_valid,
|
||||
Err(e) => {
|
||||
log::error!("Error verifying signature: {}", e);
|
||||
false
|
||||
}
|
||||
}
|
||||
},
|
||||
Err(e) => {
|
||||
log::error!("Error decoding signature: {}", e);
|
||||
false
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Symmetric encryption
|
||||
fn generate_key() -> String {
|
||||
let key = symmetric::generate_symmetric_key();
|
||||
BASE64.encode(key)
|
||||
}
|
||||
|
||||
fn encrypt(key: &str, message: &str) -> String {
|
||||
match BASE64.decode(key) {
|
||||
Ok(key_bytes) => {
|
||||
let message_bytes = message.as_bytes();
|
||||
match symmetric::encrypt_symmetric(&key_bytes, message_bytes) {
|
||||
Ok(ciphertext) => BASE64.encode(ciphertext),
|
||||
Err(e) => {
|
||||
log::error!("Error encrypting message: {}", e);
|
||||
String::new()
|
||||
}
|
||||
}
|
||||
},
|
||||
Err(e) => {
|
||||
log::error!("Error decoding key: {}", e);
|
||||
String::new()
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
fn decrypt(key: &str, ciphertext: &str) -> String {
|
||||
match BASE64.decode(key) {
|
||||
Ok(key_bytes) => {
|
||||
match BASE64.decode(ciphertext) {
|
||||
Ok(ciphertext_bytes) => {
|
||||
match symmetric::decrypt_symmetric(&key_bytes, &ciphertext_bytes) {
|
||||
Ok(plaintext) => {
|
||||
match String::from_utf8(plaintext) {
|
||||
Ok(text) => text,
|
||||
Err(e) => {
|
||||
log::error!("Error converting plaintext to string: {}", e);
|
||||
String::new()
|
||||
}
|
||||
}
|
||||
},
|
||||
Err(e) => {
|
||||
log::error!("Error decrypting ciphertext: {}", e);
|
||||
String::new()
|
||||
}
|
||||
}
|
||||
},
|
||||
Err(e) => {
|
||||
log::error!("Error decoding ciphertext: {}", e);
|
||||
String::new()
|
||||
}
|
||||
}
|
||||
},
|
||||
Err(e) => {
|
||||
log::error!("Error decoding key: {}", e);
|
||||
String::new()
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Ethereum operations
|
||||
fn create_ethereum_wallet() -> bool {
|
||||
match ethereum::create_ethereum_wallet() {
|
||||
Ok(_) => true,
|
||||
Err(e) => {
|
||||
log::error!("Error creating Ethereum wallet: {}", e);
|
||||
false
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
fn get_ethereum_address() -> String {
|
||||
match ethereum::get_current_ethereum_wallet() {
|
||||
Ok(wallet) => wallet.address_string(),
|
||||
Err(e) => {
|
||||
log::error!("Error getting Ethereum address: {}", e);
|
||||
String::new()
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// Register crypto functions with the Rhai engine
|
||||
pub fn register_crypto_module(engine: &mut Engine) -> Result<(), Box<EvalAltResult>> {
|
||||
// Register key space functions
|
||||
engine.register_fn("load_key_space", load_key_space);
|
||||
engine.register_fn("create_key_space", create_key_space);
|
||||
engine.register_fn("encrypt_key_space", encrypt_key_space);
|
||||
engine.register_fn("decrypt_key_space", decrypt_key_space);
|
||||
|
||||
// Register keypair functions
|
||||
engine.register_fn("create_keypair", create_keypair);
|
||||
engine.register_fn("select_keypair", select_keypair);
|
||||
engine.register_fn("list_keypairs", list_keypairs);
|
||||
|
||||
// Register signing/verification functions
|
||||
engine.register_fn("sign", sign);
|
||||
engine.register_fn("verify", verify);
|
||||
|
||||
// Register symmetric encryption functions
|
||||
engine.register_fn("generate_key", generate_key);
|
||||
engine.register_fn("encrypt", encrypt);
|
||||
engine.register_fn("decrypt", decrypt);
|
||||
|
||||
// Register Ethereum functions
|
||||
engine.register_fn("create_ethereum_wallet", create_ethereum_wallet);
|
||||
engine.register_fn("get_ethereum_address", get_ethereum_address);
|
||||
|
||||
Ok(())
|
||||
}
|
@@ -11,6 +11,7 @@ mod nerdctl;
|
||||
mod git;
|
||||
mod text;
|
||||
mod rfs;
|
||||
mod crypto;
|
||||
|
||||
#[cfg(test)]
|
||||
mod tests;
|
||||
@@ -73,6 +74,9 @@ pub use crate::text::{
|
||||
// Re-export TextReplacer functions
|
||||
pub use text::*;
|
||||
|
||||
// Re-export crypto module
|
||||
pub use crypto::register_crypto_module;
|
||||
|
||||
// Rename copy functions to avoid conflicts
|
||||
pub use os::copy as os_copy;
|
||||
|
||||
@@ -116,6 +120,9 @@ pub fn register(engine: &mut Engine) -> Result<(), Box<rhai::EvalAltResult>> {
|
||||
// Register RFS module functions
|
||||
rfs::register(engine)?;
|
||||
|
||||
// Register Crypto module functions
|
||||
crypto::register_crypto_module(engine)?;
|
||||
|
||||
// Future modules can be registered here
|
||||
|
||||
|
||||
|
Reference in New Issue
Block a user