aboutsummaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
authorRobin Krahl <robin.krahl@ireas.org>2019-01-07 20:55:37 +0000
committerRobin Krahl <me@robin-krahl.de>2019-01-11 04:36:43 +0100
commitdd55b04186c295319602d95d2486225570ed3591 (patch)
treed4ad85ed6c417993870864d4fd9253f871b65b10 /src
parentcd6bcd3613c2a511ddf1f19f5739493de2c5a278 (diff)
downloadnitrocli-otp-qr-dd55b04186c295319602d95d2486225570ed3591.tar.gz
nitrocli-otp-qr-dd55b04186c295319602d95d2486225570ed3591.tar.bz2
Implement QR code decoding using zbarimg
Diffstat (limited to 'src')
-rw-r--r--src/main.rs52
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)?;
}