From 2a6f6a0413c3d4871db50bc65f80a3ed342daeab Mon Sep 17 00:00:00 2001 From: aiden Date: Thu, 25 May 2023 04:58:55 +0100 Subject: [PATCH] dropfile --- Cargo.toml | 5 +--- src/clean_file.rs | 55 ------------------------------------------ src/config_file/mod.rs | 25 ++++++++++--------- src/main.rs | 22 ++++++++--------- 4 files changed, 24 insertions(+), 83 deletions(-) delete mode 100644 src/clean_file.rs diff --git a/Cargo.toml b/Cargo.toml index ca9bea6..b99925b 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -3,12 +3,9 @@ name = "acmec" version = "0.1.0" edition = "2021" -# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html - [dependencies] serde = { version = "1.0.136", features = ["derive"] } reqwest = { version = "*", features = ["blocking", "json"] } openssl = "0.10.38" serde_json = "1.0.79" - -[features] +dropfile = { git = "https://github.com/bridgeloop/dropfile.git" } \ No newline at end of file diff --git a/src/clean_file.rs b/src/clean_file.rs deleted file mode 100644 index 78294d1..0000000 --- a/src/clean_file.rs +++ /dev/null @@ -1,55 +0,0 @@ -use std::{fs::File, io::{Seek, Write}}; - -pub struct CleanFile { - path: String, - file: Option, - created: bool, - written_to: bool, -} -impl CleanFile { - pub fn open(path: String, create: bool) -> Result { - let mut file_options = File::options(); - file_options.read(true).write(true).create_new(create); - - let file = file_options.open(&(path)).map_err(|err| match err.kind() { - std::io::ErrorKind::AlreadyExists => "file already exists", - _ => "failed to open file" - })?; - - return Ok(Self { path, file: Some(file), created: create, written_to: false, }); - } - - fn delete_file(&mut self) -> Result<(), &'static str> { - return if let Some(_) = self.file.take() { - std::fs::remove_file(&(self.path)).map_err(|_| "failed to delete file") - } else { Ok(()) }; - } - pub fn delete(mut self) -> Result<(), &'static str> { - return self.delete_file(); - } - - pub fn write>(&mut self, bytes: T) -> Result<(), &'static str> { - let file: &mut File = self.file.as_mut().ok_or("file deleted")?; - file.set_len(0).map_err(|_| "failed to truncate file")?; - file.seek(std::io::SeekFrom::Start(0)).map_err(|_| "failed to seek file")?; - file.write_all(bytes.as_ref()).map_err(|_| "failed to write to file")?; - - self.written_to = true; - return Ok(()); - } - - pub fn file(&self) -> Result<&File, &'static str> { - return self.file.as_ref().ok_or("file deleted"); - } - - pub fn path(&self) -> &str { - return &(self.path); - } -} -impl Drop for CleanFile { - fn drop(&mut self) { - if self.created && !self.written_to { - self.delete_file().unwrap(); - } - } -} \ No newline at end of file diff --git a/src/config_file/mod.rs b/src/config_file/mod.rs index a8adc24..c98765c 100644 --- a/src/config_file/mod.rs +++ b/src/config_file/mod.rs @@ -1,5 +1,6 @@ -use std::ops::{Deref, DerefMut}; -use crate::{clean_file::CleanFile, stringify_ser}; +use std::{ops::{Deref, DerefMut}, path::Path}; +use crate::stringify_ser; +use dropfile::DropFile; mod acmec_config; use acmec_config::AcmecConfig; @@ -22,20 +23,20 @@ pub struct OrderDetails { } pub struct ConfigFile { - clean_file: Option, + file: Option, config: AcmecConfig, } impl ConfigFile { 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()).unwrap_or_default(); - return Ok(Self { clean_file: Some(clean_file), config, }); + let mut file = DropFile::open(path, create)?; + let config: AcmecConfig = serde_json::from_reader(&mut(file)).unwrap_or_default(); + return Ok(Self { file: Some(file), config, }); } pub fn delete(mut self) -> Result<(), &'static str> { - return self.clean_file.take().unwrap().delete(); + return self.file.take().unwrap().delete(); } - pub fn path(&self) -> &str { - return self.clean_file.as_ref().unwrap().path(); + pub fn path(&self) -> &Path { + return self.file.as_ref().unwrap().path(); } } impl Deref for ConfigFile { @@ -51,12 +52,12 @@ impl DerefMut for ConfigFile { } impl Drop for ConfigFile { fn drop(&mut self) { - let Some(mut clean_file) = self.clean_file.take() else { + let Some(mut file) = self.file.take() else { return; }; if self.changed() { let json_config = stringify_ser(&(self.config)).unwrap(); - clean_file.write(json_config).unwrap(); + file.write_trunc(json_config.as_bytes()).unwrap(); } } -} \ No newline at end of file +} diff --git a/src/main.rs b/src/main.rs index 2d165e1..dc1b1e6 100644 --- a/src/main.rs +++ b/src/main.rs @@ -38,13 +38,11 @@ use openssl::{ }; use reqwest::{self, header::HeaderValue, blocking::{Client as HttpClient, Response as HttpResponse}}; use {serde, serde_json}; +use dropfile::DropFile; mod acme; use acme::*; -mod clean_file; -use clean_file::*; - mod config_file; use config_file::*; @@ -303,7 +301,7 @@ fn main() -> Result<(), &'static str> { let config_file = ConfigFile::open(config_path, false)?; let mut context = AcmecContext::with_config_file(&(config_file), pem_passphrase)?; - println!("REALLY delete \"{}\"? this cannot be undone! [yes / any other line]", config_file.path()); + println!("REALLY delete \"{}\"? this cannot be undone! [yes / any other line]", config_file.path().display()); let mut buf = String::new(); std::io::stdin().read_line(&mut(buf)).expect("failed to read line from stdin"); if buf != "yes\n" { @@ -381,8 +379,8 @@ fn main() -> Result<(), &'static str> { let cert_path = args_iter.next().ok_or("expected path to cert file")?; let pkey_path = args_iter.next().ok_or("expected path to pkey file")?; - let mut cert_file = CleanFile::open(cert_path, true)?; - let mut pkey_file = CleanFile::open(pkey_path, true)?; + let mut cert_file = DropFile::open(cert_path, true)?; + let mut pkey_file = DropFile::open(pkey_path, true)?; for url in &(order.challenges) { acme_post(&mut(context), &(url), "{}")?; @@ -449,11 +447,11 @@ fn main() -> Result<(), &'static str> { .text() .map_err(|_| "failed to read response")?; - if let Err(_) = cert_file.write(&(cert)) { + if let Err(_) = cert_file.write_trunc(cert.as_bytes()) { eprintln!("failed to write certificate to file, printing to stdout instead"); println!("{}", cert); } - if let Err(_) = pkey_file.write(&*(pkey_pem)) { + if let Err(_) = pkey_file.write_trunc(pkey_pem) { eprintln!("failed to write private key to file, printing to stdout instead"); println!("{}", pkey_pem_view); } @@ -488,14 +486,14 @@ fn main() -> Result<(), &'static str> { builder.sign(&(kp), MessageDigest::sha256()).unwrap(); let cert_pem = builder.build().to_pem().map_err(|_| "failed to encode certificate as pem")?; - let mut cert_file = CleanFile::open(cert_path, true)?; - let mut priv_file = CleanFile::open(key_path, true)?; + let mut cert_file = DropFile::open(cert_path, true)?; + let mut priv_file = DropFile::open(key_path, true)?; - if let Err(_) = cert_file.write(&(cert_pem)) { + if let Err(_) = cert_file.write_trunc(&(cert_pem)) { eprintln!("failed to write certificate! printing to stdout instead..."); println!("{}", from_utf8(&(cert_pem)).unwrap()); } - if let Err(_) = priv_file.write(&(priv_pem)) { + if let Err(_) = priv_file.write_trunc(&(priv_pem)) { eprintln!("failed to write private key! printing to stdout instead..."); println!("{}", from_utf8(&(priv_pem)).unwrap()); }