diff --git a/src/config_file.rs b/src/config_file.rs index 1110fd9..97d52a6 100644 --- a/src/config_file.rs +++ b/src/config_file.rs @@ -1,6 +1,8 @@ +use std::cell::{RefCell, Ref}; + use crate::{clean_file::CleanFile, stringify_ser}; -#[derive(Debug, Clone)] +#[derive(Debug)] #[derive(serde::Serialize, serde::Deserialize)] pub struct AccountDetails { // account key @@ -8,7 +10,7 @@ pub struct AccountDetails { pub kid: String, } -#[derive(Debug, Clone)] +#[derive(Debug)] #[derive(serde::Serialize, serde::Deserialize)] pub struct OrderDetails { pub url: String, @@ -17,71 +19,71 @@ pub struct OrderDetails { pub dns_names: Vec, } -#[derive(Debug, Clone)] +#[derive(Debug)] #[derive(serde::Serialize, serde::Deserialize)] struct AcmecConfig { // account - account_details: Option, + account_details: RefCell>, // current pending order - order_details: Option, - pkey_pem: Option>, + order_details: RefCell>, + pkey_pem: RefCell>>, } impl Default for AcmecConfig { fn default() -> Self { return Self { - account_details: None, + account_details: RefCell::new(None), - order_details: None, - pkey_pem: None, + order_details: RefCell::new(None), + pkey_pem: RefCell::new(None), }; } } pub struct ConfigFile { - clean_file: CleanFile, + clean_file: RefCell, config: AcmecConfig, } impl ConfigFile { - fn write(&mut self) -> Result<(), &'static str> { - return self.clean_file.write(stringify_ser(&(self.config))?.as_bytes()); + fn write(&self) -> Result<(), &'static str> { + return self.clean_file.borrow_mut().write(stringify_ser(&(self.config))?.as_bytes()); } pub fn open(path: String, create: bool) -> Result { - let clean_file = CleanFile::open(path, create)?; - let config: AcmecConfig = serde_json::from_reader(clean_file.file()).unwrap_or_default(); + let clean_file = RefCell::new(CleanFile::open(path, create)?); + let config: AcmecConfig = serde_json::from_reader(clean_file.borrow().file()).unwrap_or_default(); return Ok(Self { clean_file, config }); } pub fn delete(self) -> Result<(), &'static str> { - return self.clean_file.delete(); + return self.clean_file.into_inner().delete(); } - pub fn account_details(&self) -> Option { - return self.config.account_details.clone(); + pub fn account_details(&self) -> Ref<'_, Option> { + return self.config.account_details.borrow(); } - pub fn set_account_details(&mut self, account_details: AccountDetails) -> Result<(), &'static str> { - self.config.account_details.replace(account_details); + pub fn set_account_details(&self, account_details: AccountDetails) -> Result<(), &'static str> { + self.config.account_details.borrow_mut().replace(account_details); return self.write(); } - pub fn order_details(&self) -> Option { - return self.config.order_details.clone(); + pub fn order_details(&self) -> Ref<'_, Option> { + return self.config.order_details.borrow(); } - pub fn set_order_details(&mut self, order_details: OrderDetails) -> Result<(), &'static str> { - self.config.order_details.replace(order_details); + pub fn set_order_details(&self, order_details: OrderDetails) -> Result<(), &'static str> { + self.config.order_details.borrow_mut().replace(order_details); return self.write(); } - pub fn pkey_pem(&self) -> Option> { - return self.config.pkey_pem.clone(); + pub fn pkey_pem(&self) -> Ref<'_, Option>> { + return self.config.pkey_pem.borrow(); } - pub fn set_pkey_pem(&mut self, pkey_pem: Vec) -> Result<(), &'static str> { - self.config.pkey_pem.replace(pkey_pem); + pub fn set_pkey_pem(&self, pkey_pem: Vec) -> Result<(), &'static str> { + self.config.pkey_pem.borrow_mut().replace(pkey_pem); return self.write(); } pub fn discard_order(&mut self) -> Result<(), &'static str> { - self.config.order_details.take(); - self.config.pkey_pem.take(); + self.config.order_details.borrow_mut().take(); + self.config.pkey_pem.borrow_mut().take(); return self.write(); } } \ No newline at end of file diff --git a/src/main.rs b/src/main.rs index 2012625..f17adba 100644 --- a/src/main.rs +++ b/src/main.rs @@ -277,7 +277,8 @@ fn main() -> Result<(), &'static str> { return Ok(()); } - let account_details = config_file.account_details().ok_or("invalid config file")?; + let borrow = config_file.account_details(); + let account_details = borrow.as_ref().ok_or("invalid config file")?; let kp = if let Some(passphrase) = pem_passphrase { PKey::private_key_from_pem_passphrase(&(account_details.pem_kp), passphrase.as_os_str().as_bytes()) } else { @@ -285,6 +286,7 @@ fn main() -> Result<(), &'static str> { }.map_err(|_| "failed to decode account keypair pem")?; let mut context = AcmecContext::new(&(kp)); context.set_key_id(account_details.kid.clone()); + drop(borrow); match action.as_str() { "delete" => { @@ -293,7 +295,8 @@ fn main() -> Result<(), &'static str> { } "order" => match args_iter.next().as_deref() { Some("place") => { - config_file.order_details().map_or(Ok(()), |_| Err("there is already an order pending"))?; + config_file.order_details().as_ref().map_or(Ok(()), |_| Err("there is already an order pending"))?; + let mut payload = String::from(r#"{"identifiers":["#); let dns_names: Vec = args_iter.collect(); let mut iter = dns_names.iter(); @@ -343,7 +346,8 @@ fn main() -> Result<(), &'static str> { return Ok(()); }, Some("finalize") => { - let Some(order) = config_file.order_details() else { + let borrow = config_file.order_details(); + let Some(order) = borrow.as_ref() else { return Err("no order pending"); }; @@ -365,6 +369,7 @@ fn main() -> Result<(), &'static str> { "pending" => (), status => { eprintln!("order status: {status}"); + drop(borrow); config_file.discard_order()?; return Err("bad order status"); } @@ -372,7 +377,8 @@ fn main() -> Result<(), &'static str> { std::thread::sleep(std::time::Duration::from_secs(3)); } - let (cert_kp, pkey_pem) = if let Some(pkey_pem) = config_file.pkey_pem() { + let mut pem_borrow = config_file.pkey_pem(); + let (cert_kp, pkey_pem) = if let Some(pkey_pem) = pem_borrow.as_ref() { let cert_kp = if let Some(passphrase) = &(pkey_passphrase) { PKey::private_key_from_pem_passphrase(&(pkey_pem), passphrase.as_os_str().as_bytes()) } else { @@ -383,6 +389,7 @@ fn main() -> Result<(), &'static str> { } else { let cert_kp = Rsa::generate(2048).and_then(|keypair| PKey::from_rsa(keypair)).map_err(|_| "failed to generate rsa keypair")?; + drop(pem_borrow); config_file.set_pkey_pem( if let Some(passphrase) = &(pkey_passphrase) { cert_kp.private_key_to_pem_pkcs8_passphrase(Cipher::aes_256_cbc(), passphrase.as_os_str().as_bytes()) @@ -391,7 +398,8 @@ fn main() -> Result<(), &'static str> { }.map_err(|_| "failed to serialize private key")? )?; - (cert_kp, config_file.pkey_pem().unwrap()) + pem_borrow = config_file.pkey_pem(); + (cert_kp, pem_borrow.as_ref().unwrap()) }; let pkey_pem_view = from_utf8(&(pkey_pem)).map_err(|_| "invalid utf-8 bytes in pem-encoded private key")?; @@ -414,6 +422,8 @@ fn main() -> Result<(), &'static str> { status => { eprintln!("order status: {status}"); // safe to discard order i think + drop(borrow); + drop(pem_borrow); config_file.discard_order()?; return Err("bad order status"); } @@ -434,6 +444,8 @@ fn main() -> Result<(), &'static str> { println!("{}", pkey_pem_view); } + drop(borrow); + drop(pem_borrow); config_file.discard_order()?; return Ok(()); },