1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
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)
}
}
|