diff --git a/src/main.rs b/src/main.rs index 71f4c68..0daf601 100644 --- a/src/main.rs +++ b/src/main.rs @@ -1,5 +1,12 @@ +use aes_gcm::{ + aead::{Aead, AeadCore, KeyInit, OsRng}, + Aes256Gcm, Key, Nonce, +}; use axum::{Router, routing::get}; +use base64::{engine::general_purpose::STANDARD as BASE64, Engine as _}; +use sha2::{Digest, Sha256}; use sqlx::{sqlite::SqlitePoolOptions, SqlitePool}; +use std::collections::HashMap; use std::net::SocketAddr; use tracing_subscriber::EnvFilter; @@ -9,6 +16,26 @@ struct AppState { master_key: String, } +fn get_master_key(master_key: &str) -> Key { + let mut hasher = Sha256::new(); + hasher.update(master_key.as_bytes()); + let result = hasher.finalize(); + *Key::::from_slice(&result) +} + +fn encrypt_secret(master_key: &str, plaintext: &str) -> String { + let key = get_master_key(master_key); + let cipher = Aes256Gcm::new(&key); + let nonce = Aes256Gcm::generate_nonce(&mut OsRng); + let ciphertext = cipher + .encrypt(&nonce, plaintext.as_bytes()) + .expect("encryption failure"); + + let mut payload = nonce.to_vec(); + payload.extend_from_slice(&ciphertext); + BASE64.encode(payload) +} + #[tokio::main] async fn main() { tracing_subscriber::fmt() @@ -43,6 +70,28 @@ async fn main() { tracing::info!("Migrations successful."); + if let Ok(file_content) = std::fs::read_to_string("secrets.json") { + tracing::info!("Found secrets.json, provisioning"); + let secrets: HashMap = + serde_json::from_str(&file_content).expect("Invalid secrets.json format"); + + for (key, value) in secrets { + let encrypted_val = encrypt_secret(&master_key, &value); + sqlx::query( + "INSERT INTO secrets (key_name, encrypted_value) VALUES (?, ?) ON CONFLICT(key_name) DO UPDATE SET encrypted_value = excluded.encrypted_value" + ) + .bind(key) + .bind(encrypted_val) + .execute(&pool) + .await + .expect("Failed to insert secret"); + } + + std::fs::rename("secrets.json", "secrets.json.bak") + .expect("Failed to rename secrets.json"); + tracing::info!("Provisioned secrets and renamed to secrets.json.bak"); + } + let state = AppState { pool, master_key,