aegis_vault/
algorithm.rs

1use std::{str::FromStr, string::ToString};
2
3use ring::hmac;
4use serde::{de::Deserializer, ser::Serializer, Deserialize, Serialize};
5
6#[allow(clippy::upper_case_acronyms)]
7#[derive(Debug, Default, Eq, PartialEq, Clone, Copy)]
8#[repr(u32)]
9// #[enum_type(name = "OTPMethod")]
10pub enum Method {
11    // #[enum_value(name = "TOTP")]
12    #[default]
13    TOTP = 0,
14    // #[enum_value(name = "HOTP")]
15    HOTP = 1,
16    Steam = 2,
17}
18
19impl Serialize for Method {
20    fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
21    where
22        S: Serializer,
23    {
24        serializer.serialize_str(&self.to_string())
25    }
26}
27
28impl<'de> Deserialize<'de> for Method {
29    fn deserialize<D>(deserializer: D) -> std::result::Result<Self, D::Error>
30    where
31        D: Deserializer<'de>,
32    {
33        Ok(Self::from_str(&String::deserialize(deserializer)?).unwrap())
34    }
35}
36
37impl From<u32> for Method {
38    fn from(u: u32) -> Self {
39        match u {
40            1 => Self::HOTP,
41            2 => Self::Steam,
42            _ => Self::default(),
43        }
44    }
45}
46
47impl Method {
48    pub fn is_time_based(self) -> bool {
49        matches!(self, Self::TOTP | Self::Steam)
50    }
51
52    pub fn is_event_based(self) -> bool {
53        matches!(self, Self::HOTP)
54    }
55
56    pub fn to_string(self) -> String {
57        match self {
58            Self::HOTP => "Counter-based".to_string(),
59            Self::TOTP => "Time-based".to_string(),
60            Self::Steam => "Steam".to_string(),
61        }
62    }
63}
64
65impl FromStr for Method {
66    type Err = anyhow::Error;
67    fn from_str(s: &str) -> Result<Self, Self::Err> {
68        match s.to_lowercase().as_ref() {
69            "totp" | "otp" => Ok(Self::TOTP),
70            "hotp" => Ok(Self::HOTP),
71            "steam" => Ok(Self::Steam),
72            _ => anyhow::bail!("Unsupported Method"),
73        }
74    }
75}
76
77impl ToString for Method {
78    fn to_string(&self) -> String {
79        match *self {
80            Self::TOTP => "totp",
81            Self::HOTP => "hotp",
82            Self::Steam => "steam",
83        }
84        .to_string()
85    }
86}
87
88#[allow(clippy::upper_case_acronyms)]
89#[derive(Debug, Default, Eq, PartialEq, Clone, Copy)]
90#[repr(u32)]
91// #[enum_type(name = "OTPAlgorithm")]
92pub enum Algorithm {
93    // #[enum_value(name = "SHA1")]
94    #[default]
95    SHA1 = 0,
96    // #[enum_value(name = "SHA256")]
97    SHA256 = 1,
98    // #[enum_value(name = "SHA512")]
99    SHA512 = 2,
100}
101
102impl Serialize for Algorithm {
103    fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
104    where
105        S: Serializer,
106    {
107        serializer.serialize_str(&self.to_string())
108    }
109}
110
111impl<'de> Deserialize<'de> for Algorithm {
112    fn deserialize<D>(deserializer: D) -> std::result::Result<Self, D::Error>
113    where
114        D: Deserializer<'de>,
115    {
116        Ok(Self::from_str(&String::deserialize(deserializer)?).unwrap())
117    }
118}
119
120impl Algorithm {
121    pub fn to_string(self) -> String {
122        match self {
123            Self::SHA1 => "SHA-1".to_string(),
124            Self::SHA256 => "SHA-256".to_string(),
125            Self::SHA512 => "SHA-512".to_string(),
126        }
127    }
128}
129
130impl FromStr for Algorithm {
131    type Err = anyhow::Error;
132    fn from_str(s: &str) -> Result<Self, Self::Err> {
133        match s.to_lowercase().as_ref() {
134            "sha1" => Ok(Self::SHA1),
135            "sha256" => Ok(Self::SHA256),
136            "sha512" => Ok(Self::SHA512),
137            _ => anyhow::bail!("Unsupported HMAC-algorithm"),
138        }
139    }
140}
141
142impl ToString for Algorithm {
143    fn to_string(&self) -> String {
144        match *self {
145            Self::SHA1 => "sha1",
146            Self::SHA256 => "sha256",
147            Self::SHA512 => "sha512",
148        }
149        .to_string()
150    }
151}
152
153impl From<Algorithm> for hmac::Algorithm {
154    fn from(h: Algorithm) -> Self {
155        match h {
156            Algorithm::SHA1 => hmac::HMAC_SHA1_FOR_LEGACY_USE_ONLY,
157            Algorithm::SHA256 => hmac::HMAC_SHA256,
158            Algorithm::SHA512 => hmac::HMAC_SHA512,
159        }
160    }
161}
162
163impl From<u32> for Algorithm {
164    fn from(u: u32) -> Self {
165        match u {
166            1 => Self::SHA256,
167            2 => Self::SHA512,
168            _ => Self::default(),
169        }
170    }
171}