diff options
author | Robin Krahl <robin.krahl@ireas.org> | 2019-01-07 20:55:37 +0000 |
---|---|---|
committer | Robin Krahl <me@robin-krahl.de> | 2019-01-11 04:36:43 +0100 |
commit | dd55b04186c295319602d95d2486225570ed3591 (patch) | |
tree | d4ad85ed6c417993870864d4fd9253f871b65b10 | |
parent | cd6bcd3613c2a511ddf1f19f5739493de2c5a278 (diff) | |
download | nitrocli-otp-qr-dd55b04186c295319602d95d2486225570ed3591.tar.gz nitrocli-otp-qr-dd55b04186c295319602d95d2486225570ed3591.tar.bz2 |
Implement QR code decoding using zbarimg
-rw-r--r-- | src/main.rs | 52 |
1 files changed, 46 insertions, 6 deletions
diff --git a/src/main.rs b/src/main.rs index b3fb3f3..9c2a8c1 100644 --- a/src/main.rs +++ b/src/main.rs @@ -7,11 +7,13 @@ use std::fs; use std::io; use std::path; use std::process; +use std::string; #[derive(Debug)] enum Error { IoError(io::Error), Error(String), + Utf8Error(string::FromUtf8Error), } impl fmt::Display for Error { @@ -19,6 +21,7 @@ impl fmt::Display for Error { match *self { Error::IoError(ref err) => write!(f, "IO error: {}", err), Error::Error(ref string) => write!(f, "Error: {}", string), + Error::Utf8Error(ref err) => write!(f, "UTF-8 error: {}", err), } } } @@ -35,6 +38,23 @@ impl From<io::Error> for Error { } } +impl From<(&str, process::ExitStatus)> for Error { + fn from(data: (&str, process::ExitStatus)) -> Error { + let (command, status) = data; + let msg = match status.code() { + Some(code) => format!("{} failed with error code {}", command, code), + None => format!("{} was terminated by a signal", command), + }; + Error::Error(msg) + } +} + +impl From<string::FromUtf8Error> for Error { + fn from(error: string::FromUtf8Error) -> Error { + Error::Utf8Error(error) + } +} + #[derive(Debug)] struct Options { slot: u8, @@ -82,13 +102,32 @@ fn import_qr_code() -> Result<path::PathBuf, Error> { 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")), + Err(Error::from(("import", status))) + } +} + +fn decode_qr_code(path: &path::Path) -> Result<String, Error> { + let output = process::Command::new("zbarimg") + .arg("--quiet") + .arg("--raw") + .arg(path) + .output()?; + if output.status.success() { + let output = String::from_utf8(output.stdout)?; + let urls = output + .split("\n") + .filter(|url| url.starts_with("otpauth://")) + .collect::<Vec<&str>>(); + if urls.is_empty() { + Err(Error::from("Could not find an otpauth QR code")) + } else { + if urls.len() > 1 { + println!("Found more than otpauth QR code, using the first one."); + } + Ok(urls[0].to_string()) } + } else { + Err(Error::from(("zbarimg", output.status))) } } @@ -97,6 +136,7 @@ fn run(options: Options) -> Result<(), Error> { Some(ref file) => path::PathBuf::from(file), None => import_qr_code()?, }; + println!("{}", decode_qr_code(&path)?); if options.file.is_none() { fs::remove_file(&path)?; } |