use axum::http::HeaderMap;
use std::sync::Arc;
use uuid::Uuid;
use zeroize::Zeroize;
use rand::rngs::OsRng;
use rand::RngCore;
use crate::callback::AuthCallback;
use crate::errors::AppError;
use crate::repositories::{AuditEventType, CreateWalletMaterial, KdfParams, ShareAAuthMethod};
use crate::services::derive_pubkey_from_seed;
use crate::services::EmailService;
use crate::AppState;
pub async fn auto_enroll_wallet<C: AuthCallback, E: EmailService>(
state: &Arc<AppState<C, E>>,
user_id: Uuid,
password: &str,
headers: &HeaderMap,
) -> Result<(), AppError> {
let wallet_signing = state
.settings_service
.get_bool("feature_wallet_signing")
.await
.ok()
.flatten()
.unwrap_or(false);
let wallet_enroll = state
.settings_service
.get_bool("postlogin_wallet_enroll_enabled")
.await
.ok()
.flatten()
.unwrap_or(false);
if !wallet_signing || !wallet_enroll {
return Ok(());
}
if state.wallet_material_repo.exists_for_user(user_id).await? {
return Ok(());
}
let mut seed = [0u8; 32];
OsRng.fill_bytes(&mut seed);
let (mut share_a, share_b, _share_c) = state.wallet_signing_service.split_secret(&seed)?;
let solana_pubkey = derive_pubkey_from_seed(&seed)?;
seed.zeroize();
let kdf_params = KdfParams::default();
let mut salt = [0u8; 16];
OsRng.fill_bytes(&mut salt);
let mut key = state
.wallet_signing_service
.derive_key_argon2(
password.as_bytes().to_vec(),
salt.to_vec(),
kdf_params.clone(),
)
.await?;
let (ciphertext, nonce) = state
.wallet_signing_service
.encrypt_aes_gcm(&key, &share_a)?;
key.zeroize();
share_a.zeroize();
let material = CreateWalletMaterial {
user_id,
solana_pubkey,
share_a_auth_method: ShareAAuthMethod::Password,
share_a_ciphertext: ciphertext,
share_a_nonce: nonce.to_vec(),
share_a_kdf_salt: Some(salt.to_vec()),
share_a_kdf_params: Some(kdf_params),
prf_salt: None,
share_a_pin_hash: None,
share_b,
api_key_id: None,
};
state.wallet_material_repo.create(material).await?;
let _ = state
.audit_service
.log_user_event(AuditEventType::WalletEnrolled, user_id, Some(headers))
.await;
Ok(())
}