aboutsummaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
authorRobin Krahl <robin.krahl@ireas.org>2019-01-07 20:23:02 +0000
committerRobin Krahl <me@robin-krahl.de>2019-01-11 04:36:37 +0100
commitcd6bcd3613c2a511ddf1f19f5739493de2c5a278 (patch)
tree0c409a8d1e6d2da62b13ee169b4454b187173c36 /src
parent5b5d87966e6dfbd8cef3bcac9546664590d43d9e (diff)
downloadnitrocli-otp-qr-cd6bcd3613c2a511ddf1f19f5739493de2c5a278.tar.gz
nitrocli-otp-qr-cd6bcd3613c2a511ddf1f19f5739493de2c5a278.tar.bz2
Implement call to import to capture QR code
Diffstat (limited to 'src')
-rw-r--r--src/main.rs70
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);