diff options
Diffstat (limited to 'extensions/otp-cache/src/ext.rs')
-rw-r--r-- | extensions/otp-cache/src/ext.rs | 110 |
1 files changed, 110 insertions, 0 deletions
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<String>, +} + +#[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<ffi::OsStr>) -> &mut Nitrocli { + self.cmd.arg(arg); + self + } + + pub fn args<I, S>(&mut self, args: I) -> &mut Nitrocli + where + I: IntoIterator<Item = S>, + S: AsRef<ffi::OsStr>, + { + self.cmd.args(args); + self + } + + pub fn text(&mut self) -> anyhow::Result<String> { + 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<OtpAlgorithm, Self::Err> { + 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<D>(deserializer: D) -> Result<Self, D::Error> + 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<S>(&self, serializer: S) -> Result<S::Ok, S::Error> + where + S: serde::Serializer, + { + self.to_string().serialize(serializer) + } +} |