quorum_core/utility/
config.rs1use crate::utility::secrets::{SECRETS_BACKUP_PATH, SECRETS_PATH};
17use crate::utility::secrets::{
18 load_encrypted_config, prompt_passphrase, prompt_passphrase_new, run_setup,
19 save_encrypted_config, secrets_exist,
20};
21use crate::utility::std::{press_enter_to_continue, typewriter_println};
22use arc_swap::ArcSwap;
23use colored::Colorize;
24use std::path::Path;
25use std::sync::Arc;
26use std::sync::OnceLock;
27use zeroize::Zeroizing;
28
29use crate::utility::config_schema::{ConfigFields, parse_config_field};
31
32static CONFIG: OnceLock<ArcSwap<ConfigFields>> = OnceLock::new();
34
35pub struct Config;
41
42impl Config {
43 pub fn load() -> Result<(), Box<dyn std::error::Error>> {
50 if !Path::new(SECRETS_PATH).exists() && Path::new(SECRETS_BACKUP_PATH).exists() {
51 let backup_data = std::fs::read(SECRETS_BACKUP_PATH)
52 .map_err(|e| format!("Failed to read backup: {}", e))?;
53 std::fs::write(SECRETS_PATH, backup_data)
54 .map_err(|e| format!("Failed to restore from backup: {}", e))?;
55 }
56
57 if secrets_exist() {
58 if !cfg!(debug_assertions) {
59 println!();
60 typewriter_println(&format!(
61 "{}",
62 "Enter passphrase to unlock the server...".cyan().bold()
63 ))
64 .map_err(|e| e.to_string())?;
65
66 let passphrase = Zeroizing::new(prompt_passphrase()?);
67 Self::load_with_passphrase(&passphrase)
68 } else {
69 Self::load_with_passphrase("correct horse battery staple")
70 }
71 } else {
72 let config_fields = run_setup()?;
73
74 if !cfg!(debug_assertions) {
75 let passphrase = Zeroizing::new(prompt_passphrase_new()?);
76
77 println!();
78 typewriter_println(&format!(
79 "{}",
80 "Passphrase setup successfully!".cyan().bold()
81 ))
82 .map_err(|e| e.to_string())?;
83
84 press_enter_to_continue(true, true);
85 save_encrypted_config(&config_fields, &passphrase)?;
86 } else {
87 save_encrypted_config(&config_fields, "correct horse battery staple")?;
88 }
89
90 Self::load()
91 }
92 }
93
94 pub fn reload() -> Result<(), Box<dyn std::error::Error>> {
96 typewriter_println(&format!(
97 "{}",
98 "Enter passphrase to reload config...".cyan().bold()
99 ))
100 .map_err(|e| e.to_string())?;
101
102 let passphrase = prompt_passphrase()?;
103 let config_fields = load_encrypted_config(&passphrase)?;
104
105 CONFIG
106 .get()
107 .expect("Config not initialized. Call Config::load() first.")
108 .store(Arc::new(config_fields));
109
110 Ok(())
111 }
112
113 pub fn load_with_passphrase(passphrase: &str) -> Result<(), Box<dyn std::error::Error>> {
115 let config_fields = load_encrypted_config(passphrase)
116 .map_err(|e| -> Box<dyn std::error::Error> { e.into() })?;
117
118 if let Some(existing) = CONFIG.get() {
119 existing.store(Arc::new(config_fields));
120 Ok(())
121 } else {
122 CONFIG
123 .set(ArcSwap::from_pointee(config_fields))
124 .map_err(|_| "Config already initialized".into())
125 }
126 }
127
128 pub fn get() -> arc_swap::Guard<Arc<ConfigFields>> {
130 CONFIG
131 .get()
132 .expect("Config not initialized. Call Config::load() first.")
133 .load()
134 }
135
136 pub fn update(config_key: &str, config_value: &str) -> Result<(), Box<dyn std::error::Error>> {
148 let existing = CONFIG
149 .get()
150 .ok_or("Config not initialized. Call Config::load() first.")?;
151
152 let current = existing.load();
153 let mut new_fields = (**current).clone();
154
155 match parse_config_field(&mut new_fields, config_key, config_value) {
157 Ok(true) => {
158 save_encrypted_config(&new_fields, "correct horse battery staple")?;
160 existing.store(Arc::new(new_fields));
161 Ok(())
162 }
163 Ok(false) => {
164 Err(format!("Unknown config key: {}", config_key).into())
166 }
167 Err(e) => {
168 Err(e.into())
170 }
171 }
172 }
173}
174
175pub use crate::utility::config_schema::{CONFIG_SCHEMA, field_names};