use anyhow::{Context, Result};
use runar_common::compact_ids::compact_id;
use runar_common::logging::Logger;
use runar_keys::mobile::{NetworkKeyMessage, NodeCertificateMessage, SetupToken};
use runar_keys::node::NodeKeyManager;
use runar_macros_common::{log_debug, log_info};
use std::path::PathBuf;
use std::sync::Arc;
use uuid::Uuid;
use crate::config::{NodeConfig, SetupServerConfig};
use crate::key_store::OsKeyStore;
use crate::setup_server::SetupServer;
pub struct InitCommand {
config_dir: PathBuf,
logger: Arc<Logger>,
}
#[derive(Debug, Clone)]
pub struct SetupConfig {
keys_name: String,
setup_server: SetupServerConfig,
node_public_key: String,
}
impl SetupConfig {
pub fn new(node_public_key: String) -> Self {
Self {
keys_name: format!("runar_{}", Uuid::new_v4()),
setup_server: SetupServerConfig::default(),
node_public_key,
}
}
pub fn get_setup_server_address(&self) -> String {
format!("{}:{}", self.setup_server.ip, self.setup_server.port)
}
pub fn get_setup_server(&self) -> &SetupServerConfig {
&self.setup_server
}
pub fn get_keys_name(&self) -> &str {
&self.keys_name
}
}
impl InitCommand {
pub fn new(config_dir: PathBuf, logger: Arc<Logger>) -> Self {
Self { config_dir, logger }
}
pub async fn run(&self, force: bool) -> Result<()> {
log_info!(self.logger, "Starting Runar node initialization...");
if NodeConfig::exists(&self.config_dir) && !force {
println!("Configuration already exists in {:?}", self.config_dir);
println!("Use --force to re-initialize and discard existing configuration.");
return Ok(());
}
if force {
log_info!(
self.logger,
"Force flag specified - will re-initialize existing configuration"
);
}
log_info!(
self.logger,
"Step 1: Generating node keys and certificate signing request..."
);
let (mut node_key_manager, _setup_token) = self.generate_node_keys()?;
log_info!(
self.logger,
"Step 2: Creating temporary setup configuration..."
);
let setup_config = self.create_setup_config(&node_key_manager)?;
log_info!(
self.logger,
"Step 3: Generating QR code for mobile setup..."
);
self.generate_qr_code(&_setup_token, &setup_config)?;
log_info!(
self.logger,
"Step 4: Starting setup server and waiting for mobile device..."
);
let setup_data = self
.wait_for_mobile_setup(&_setup_token, &setup_config)
.await?;
log_info!(self.logger, "Step 5: Installing certificate...");
self.install_certificate(&mut node_key_manager, setup_data.certificate_message)?;
log_info!(self.logger, "Step 6: Installing network key...");
let network_id = setup_data.network_key_message.network_id.clone();
self.install_network_key(&mut node_key_manager, setup_data.network_key_message)?;
log_info!(self.logger, "Step 7: Saving configuration and keys...");
self.save_configuration(&setup_config, &node_key_manager, &network_id)?;
log_info!(self.logger, "Step 8: Initialization complete!");
self.print_success_message(&setup_config);
Ok(())
}
fn generate_node_keys(&self) -> Result<(NodeKeyManager, SetupToken)> {
let mut node_key_manager = NodeKeyManager::new(self.logger.clone())
.context("Failed to create node key manager")?;
let _setup_token = node_key_manager
.generate_csr()
.context("Failed to generate certificate signing request")?;
let node_public_key = node_key_manager.get_node_public_key();
let node_id = compact_id(&node_public_key);
log_info!(self.logger, "Node identity created: {node_id}");
log_debug!(
self.logger,
"Node public key: {}",
compact_id(&node_public_key)
);
Ok((node_key_manager, _setup_token))
}
fn create_setup_config(&self, node_key_manager: &NodeKeyManager) -> Result<SetupConfig> {
let node_public_key = node_key_manager.get_node_public_key();
let setup_config = SetupConfig::new(compact_id(&node_public_key));
log_info!(
self.logger,
"Setup configuration created with keys name: {}",
setup_config.get_keys_name()
);
log_debug!(
self.logger,
"Setup server will be available at: {}",
setup_config.get_setup_server_address()
);
Ok(setup_config)
}
fn generate_qr_code(
&self,
_setup_token: &SetupToken,
setup_config: &SetupConfig,
) -> Result<()> {
let full_setup_token = FullSetupToken {
setup_token: _setup_token.clone(),
server_address: setup_config.get_setup_server_address(),
};
let setup_token_bytes =
serde_cbor::to_vec(&full_setup_token).context("Failed to serialize setup token")?;
let qr_code =
qrcode::QrCode::new(&setup_token_bytes).context("Failed to generate QR code")?;
self.display_qr_code_in_terminal(&qr_code)?;
println!("📱 Scan this QR code with your mobile Runar app to complete setup");
println!(
"🌐 Setup server will be available at: {}",
setup_config.get_setup_server_address()
);
Ok(())
}
fn display_qr_code_in_terminal(&self, qr_code: &qrcode::QrCode) -> Result<()> {
let qr_string = qr_code
.render::<qrcode::render::unicode::Dense1x2>()
.build();
println!("\n📱 QR Code (ASCII):");
println!("{qr_string}");
println!();
Ok(())
}
async fn wait_for_mobile_setup(
&self,
_setup_token: &SetupToken,
setup_config: &SetupConfig,
) -> Result<crate::setup_server::SetupData> {
let server = SetupServer::new(
setup_config.get_setup_server().ip.clone(),
setup_config.get_setup_server().port,
self.logger.clone(),
);
println!("🔐 Waiting for mobile device to complete setup...");
println!("📱 Please scan the QR code with your mobile Runar app");
let setup_data = server
.wait_for_setup_data()
.await
.context("Failed to receive setup data from mobile device")?;
log_info!(self.logger, "Setup data received from mobile device");
Ok(setup_data)
}
fn install_certificate(
&self,
node_key_manager: &mut NodeKeyManager,
certificate_message: NodeCertificateMessage,
) -> Result<()> {
node_key_manager
.install_certificate(certificate_message)
.context("Failed to install certificate")?;
let status = node_key_manager.get_certificate_status();
log_info!(self.logger, "Certificate status: {status:?}");
if status != runar_keys::node::CertificateStatus::Valid {
return Err(anyhow::anyhow!(
"Certificate installation failed - status: {:?}",
status
));
}
log_info!(self.logger, "Certificate installed successfully");
Ok(())
}
fn install_network_key(
&self,
node_key_manager: &mut NodeKeyManager,
network_key_message: NetworkKeyMessage,
) -> Result<()> {
node_key_manager
.install_network_key(network_key_message)
.context("Failed to install network key")?;
log_info!(self.logger, "Network key installed successfully");
Ok(())
}
fn save_configuration(
&self,
setup_config: &SetupConfig,
node_key_manager: &NodeKeyManager,
network_id: &str,
) -> Result<()> {
let node_public_key_bytes = node_key_manager.get_node_public_key();
let node_id = setup_config.node_public_key.clone(); let node_public_key_hex = hex::encode(&node_public_key_bytes);
let final_config = NodeConfig::new(
node_id,
network_id.to_string(), node_public_key_hex, setup_config.setup_server.clone(),
);
final_config
.save(&self.config_dir)
.context("Failed to save configuration file")?;
let node_state = node_key_manager.export_state();
let serialized_state =
serde_cbor::to_vec(&node_state).context("Failed to serialize node state")?;
let key_store = OsKeyStore::new(self.logger.clone());
key_store
.store_node_keys(setup_config.get_keys_name(), &serialized_state)
.context("Failed to store node keys in OS key store")?;
log_info!(self.logger, "Configuration saved to {:?}", self.config_dir);
log_info!(
self.logger,
"Node keys stored securely in OS key store: {}",
setup_config.get_keys_name()
);
log_info!(self.logger, "Default network ID: {network_id}");
Ok(())
}
fn print_success_message(&self, setup_config: &SetupConfig) {
println!("\n🎉 Runar node initialization completed successfully!");
println!("📋 Setup Information:");
println!(" • Keys Name: {}", setup_config.keys_name);
println!(" • Node Public Key: {}", setup_config.node_public_key);
println!(" • Configuration: {:?}", self.config_dir);
println!();
println!("🚀 You can now start the node with: runar start");
println!("📱 The node is ready to accept connections from mobile devices");
}
}
#[derive(serde::Serialize, serde::Deserialize)]
struct FullSetupToken {
setup_token: SetupToken,
server_address: String,
}