From 446e78b95a2d2b74afb9ab7c39bf135ee5e8ab32 Mon Sep 17 00:00:00 2001 From: Robin Krahl Date: Thu, 27 Aug 2020 13:13:54 +0200 Subject: Add otp-cache extension --- extensions/otp-cache/src/ext.rs | 110 ++++++++++++++++++++++++++++++++++++++++ 1 file changed, 110 insertions(+) create mode 100644 extensions/otp-cache/src/ext.rs (limited to 'extensions/otp-cache/src/ext.rs') diff --git a/extensions/otp-cache/src/ext.rs b/extensions/otp-cache/src/ext.rs new file mode 100644 index 0000000..ccebd39 --- /dev/null +++ b/extensions/otp-cache/src/ext.rs @@ -0,0 +1,110 @@ +use std::ffi; +use std::fmt; +use std::process; +use std::str; + +#[derive(Debug, structopt::StructOpt)] +pub struct Args { + #[structopt(long, hidden(true))] + pub nitrocli: String, + + #[structopt(long, hidden(true))] + pub verbosity: Option, +} + +#[derive(Debug)] +pub struct Nitrocli { + cmd: process::Command, +} + +#[derive(Clone, Copy, Debug, Eq, Ord, PartialEq, PartialOrd)] +pub enum OtpAlgorithm { + Hotp, + Totp, +} + +impl Args { + pub fn nitrocli(&self) -> Nitrocli { + // TODO: set verbosity args + Nitrocli::new(&self.nitrocli) + } +} + +impl Nitrocli { + pub fn new(nitrocli: &str) -> Nitrocli { + Nitrocli { + cmd: process::Command::new(nitrocli), + } + } + + pub fn arg(&mut self, arg: impl AsRef) -> &mut Nitrocli { + self.cmd.arg(arg); + self + } + + pub fn args(&mut self, args: I) -> &mut Nitrocli + where + I: IntoIterator, + S: AsRef, + { + self.cmd.args(args); + self + } + + pub fn text(&mut self) -> anyhow::Result { + let output = self.cmd.output()?; + if output.status.success() { + String::from_utf8(output.stdout).map_err(From::from) + } else { + Err(anyhow::anyhow!( + "nitrocli call failed: {}", + String::from_utf8_lossy(&output.stderr) + )) + } + } +} + +impl fmt::Display for OtpAlgorithm { + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + write!( + f, + "{}", + match self { + OtpAlgorithm::Hotp => "hotp", + OtpAlgorithm::Totp => "totp", + } + ) + } +} + +impl str::FromStr for OtpAlgorithm { + type Err = anyhow::Error; + + fn from_str(s: &str) -> Result { + match s { + "hotp" => Ok(OtpAlgorithm::Hotp), + "totp" => Ok(OtpAlgorithm::Totp), + _ => Err(anyhow::anyhow!("Unexpected OTP algorithm: {}", s)), + } + } +} + +impl<'de> serde::Deserialize<'de> for OtpAlgorithm { + fn deserialize(deserializer: D) -> Result + where + D: serde::Deserializer<'de>, + { + use serde::de::Error as _; + + str::FromStr::from_str(&String::deserialize(deserializer)?).map_err(D::Error::custom) + } +} + +impl serde::Serialize for OtpAlgorithm { + fn serialize(&self, serializer: S) -> Result + where + S: serde::Serializer, + { + self.to_string().serialize(serializer) + } +} -- cgit v1.2.1