diff options
Diffstat (limited to 'src')
-rw-r--r-- | src/main.rs | 70 |
1 files changed, 69 insertions, 1 deletions
diff --git a/src/main.rs b/src/main.rs index 04140ed..b3fb3f3 100644 --- a/src/main.rs +++ b/src/main.rs @@ -2,9 +2,40 @@ //! Reads OTP configuration from a QR code and writes it to an OTP slot on a Nitrokey device. +use std::fmt; +use std::fs; +use std::io; +use std::path; use std::process; #[derive(Debug)] +enum Error { + IoError(io::Error), + Error(String), +} + +impl fmt::Display for Error { + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + match *self { + Error::IoError(ref err) => write!(f, "IO error: {}", err), + Error::Error(ref string) => write!(f, "Error: {}", string), + } + } +} + +impl From<&str> for Error { + fn from(string: &str) -> Error { + Error::Error(string.to_string()) + } +} + +impl From<io::Error> for Error { + fn from(error: io::Error) -> Error { + Error::IoError(error) + } +} + +#[derive(Debug)] struct Options { slot: u8, file: Option<String>, @@ -41,9 +72,46 @@ fn parse_options() -> Result<Options, i32> { Ok(options) } +fn import_qr_code() -> Result<path::PathBuf, Error> { + let mut temp = mktemp::Temp::new_file()?; + let path = temp.to_path_buf(); + + let status = process::Command::new("import").arg(&path).status()?; + + if status.success() { + temp.release(); + Ok(path) + } else { + match status.code() { + Some(code) => Err(Error::Error(format!( + "import failed with error code {}", + code + ))), + None => Err(Error::from("import was terminated by a signal")), + } + } +} + +fn run(options: Options) -> Result<(), Error> { + let path = match options.file { + Some(ref file) => path::PathBuf::from(file), + None => import_qr_code()?, + }; + if options.file.is_none() { + fs::remove_file(&path)?; + } + Ok(()) +} + fn main() { let status = match parse_options() { - Ok(_) => 0, + Ok(options) => match run(options) { + Ok(()) => 0, + Err(err) => { + println!("{}", err); + 1 + } + }, Err(err) => err, }; process::exit(status); |