moq_token/
algorithm.rs

1use std::{fmt, str::FromStr};
2
3/// A subset of jsonwebtoken algorithms.
4///
5/// We could support all of them, but there's currently no point using public key crypto.
6/// The relay can fetch any resource it wants; it doesn't need to forge tokens.
7///
8/// TODO support public key crypto at some point.
9#[derive(Clone, Copy, Debug, serde::Serialize, serde::Deserialize, PartialEq, Eq, Hash)]
10pub enum Algorithm {
11	HS256,
12	HS384,
13	HS512,
14}
15
16impl From<Algorithm> for jsonwebtoken::Algorithm {
17	fn from(val: Algorithm) -> Self {
18		match val {
19			Algorithm::HS256 => jsonwebtoken::Algorithm::HS256,
20			Algorithm::HS384 => jsonwebtoken::Algorithm::HS384,
21			Algorithm::HS512 => jsonwebtoken::Algorithm::HS512,
22		}
23	}
24}
25
26impl FromStr for Algorithm {
27	type Err = anyhow::Error;
28
29	fn from_str(s: &str) -> Result<Self, Self::Err> {
30		match s {
31			"HS256" => Ok(Algorithm::HS256),
32			"HS384" => Ok(Algorithm::HS384),
33			"HS512" => Ok(Algorithm::HS512),
34			_ => anyhow::bail!("invalid algorithm: {}", s),
35		}
36	}
37}
38
39impl fmt::Display for Algorithm {
40	fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
41		match self {
42			Algorithm::HS256 => write!(f, "HS256"),
43			Algorithm::HS384 => write!(f, "HS384"),
44			Algorithm::HS512 => write!(f, "HS512"),
45		}
46	}
47}
48
49#[cfg(test)]
50mod tests {
51	use super::*;
52
53	#[test]
54	fn test_algorithm_from_str_valid() {
55		assert_eq!(Algorithm::from_str("HS256").unwrap(), Algorithm::HS256);
56		assert_eq!(Algorithm::from_str("HS384").unwrap(), Algorithm::HS384);
57		assert_eq!(Algorithm::from_str("HS512").unwrap(), Algorithm::HS512);
58	}
59
60	#[test]
61	fn test_algorithm_from_str_invalid() {
62		assert!(Algorithm::from_str("HS128").is_err());
63		assert!(Algorithm::from_str("RS256").is_err());
64		assert!(Algorithm::from_str("invalid").is_err());
65		assert!(Algorithm::from_str("").is_err());
66	}
67
68	#[test]
69	fn test_algorithm_display() {
70		assert_eq!(Algorithm::HS256.to_string(), "HS256");
71		assert_eq!(Algorithm::HS384.to_string(), "HS384");
72		assert_eq!(Algorithm::HS512.to_string(), "HS512");
73	}
74
75	#[test]
76	fn test_algorithm_to_jsonwebtoken_algorithm() {
77		assert_eq!(
78			jsonwebtoken::Algorithm::from(Algorithm::HS256),
79			jsonwebtoken::Algorithm::HS256
80		);
81		assert_eq!(
82			jsonwebtoken::Algorithm::from(Algorithm::HS384),
83			jsonwebtoken::Algorithm::HS384
84		);
85		assert_eq!(
86			jsonwebtoken::Algorithm::from(Algorithm::HS512),
87			jsonwebtoken::Algorithm::HS512
88		);
89	}
90
91	#[test]
92	fn test_algorithm_serde() {
93		let alg = Algorithm::HS256;
94		let json = serde_json::to_string(&alg).unwrap();
95		assert_eq!(json, "\"HS256\"");
96
97		let deserialized: Algorithm = serde_json::from_str(&json).unwrap();
98		assert_eq!(deserialized, alg);
99	}
100
101	#[test]
102	fn test_algorithm_equality() {
103		assert_eq!(Algorithm::HS256, Algorithm::HS256);
104		assert_ne!(Algorithm::HS256, Algorithm::HS384);
105		assert_ne!(Algorithm::HS384, Algorithm::HS512);
106	}
107
108	#[test]
109	fn test_algorithm_clone() {
110		let alg = Algorithm::HS256;
111		let cloned = alg;
112		assert_eq!(alg, cloned);
113	}
114}