1use crate::error::KeyError;
2use crate::generate::generate;
3use crate::{Algorithm, Claims};
4use base64::Engine;
5use elliptic_curve::SecretKey;
6use elliptic_curve::pkcs8::EncodePrivateKey;
7use jsonwebtoken::{DecodingKey, EncodingKey, Header};
8use rsa::BigUint;
9use rsa::pkcs1::EncodeRsaPrivateKey;
10use serde::{Deserialize, Deserializer, Serialize, Serializer};
11use std::sync::OnceLock;
12use std::{collections::HashSet, fmt, path::Path as StdPath};
13
14#[derive(Debug, Clone, Serialize, Deserialize, PartialEq, Eq, Hash, PartialOrd, Ord)]
16#[serde(rename_all = "camelCase")]
17pub enum KeyOperation {
18 Sign,
19 Verify,
20 Decrypt,
21 Encrypt,
22}
23
24#[derive(Clone, Serialize, Deserialize)]
26#[serde(tag = "kty")]
27pub enum KeyType {
28 EC {
30 #[serde(rename = "crv")]
31 curve: EllipticCurve,
32 #[serde(serialize_with = "serialize_base64url", deserialize_with = "deserialize_base64url")]
34 x: Vec<u8>,
35 #[serde(serialize_with = "serialize_base64url", deserialize_with = "deserialize_base64url")]
37 y: Vec<u8>,
38 #[serde(
40 default,
41 skip_serializing_if = "Option::is_none",
42 serialize_with = "serialize_base64url_optional",
43 deserialize_with = "deserialize_base64url_optional"
44 )]
45 d: Option<Vec<u8>>,
46 },
47 RSA {
49 #[serde(flatten)]
50 public: RsaPublicKey,
51 #[serde(flatten, skip_serializing_if = "Option::is_none")]
52 private: Option<RsaPrivateKey>,
53 },
54 #[serde(rename = "oct")]
56 OCT {
57 #[serde(
59 rename = "k",
60 default,
61 serialize_with = "serialize_base64url",
62 deserialize_with = "deserialize_base64url"
63 )]
64 secret: Vec<u8>,
65 },
66 OKP {
68 #[serde(rename = "crv")]
69 curve: EllipticCurve,
70 #[serde(serialize_with = "serialize_base64url", deserialize_with = "deserialize_base64url")]
71 x: Vec<u8>,
72 #[serde(
73 rename = "d",
74 default,
75 skip_serializing_if = "Option::is_none",
76 serialize_with = "serialize_base64url_optional",
77 deserialize_with = "deserialize_base64url_optional"
78 )]
79 d: Option<Vec<u8>>,
80 },
81}
82
83#[derive(Clone, Serialize, Deserialize, PartialEq, Eq, Debug)]
87pub enum EllipticCurve {
88 #[serde(rename = "P-256")]
89 P256,
90 #[serde(rename = "P-384")]
91 P384,
92 #[serde(rename = "Ed25519")]
96 Ed25519,
97}
98
99#[derive(Clone, Serialize, Deserialize)]
103pub struct RsaPublicKey {
104 #[serde(serialize_with = "serialize_base64url", deserialize_with = "deserialize_base64url")]
105 pub n: Vec<u8>,
106 #[serde(serialize_with = "serialize_base64url", deserialize_with = "deserialize_base64url")]
107 pub e: Vec<u8>,
108}
109
110#[derive(Clone, Serialize, Deserialize)]
114pub struct RsaPrivateKey {
115 #[serde(serialize_with = "serialize_base64url", deserialize_with = "deserialize_base64url")]
116 pub d: Vec<u8>,
117 #[serde(serialize_with = "serialize_base64url", deserialize_with = "deserialize_base64url")]
118 pub p: Vec<u8>,
119 #[serde(serialize_with = "serialize_base64url", deserialize_with = "deserialize_base64url")]
120 pub q: Vec<u8>,
121 #[serde(serialize_with = "serialize_base64url", deserialize_with = "deserialize_base64url")]
122 pub dp: Vec<u8>,
123 #[serde(serialize_with = "serialize_base64url", deserialize_with = "deserialize_base64url")]
124 pub dq: Vec<u8>,
125 #[serde(serialize_with = "serialize_base64url", deserialize_with = "deserialize_base64url")]
126 pub qi: Vec<u8>,
127 #[serde(skip_serializing_if = "Option::is_none")]
128 pub oth: Option<Vec<RsaAdditionalPrime>>,
129}
130
131#[derive(Clone, Serialize, Deserialize)]
133pub struct RsaAdditionalPrime {
134 #[serde(serialize_with = "serialize_base64url", deserialize_with = "deserialize_base64url")]
135 pub r: Vec<u8>,
136 #[serde(serialize_with = "serialize_base64url", deserialize_with = "deserialize_base64url")]
137 pub d: Vec<u8>,
138 #[serde(serialize_with = "serialize_base64url", deserialize_with = "deserialize_base64url")]
139 pub t: Vec<u8>,
140}
141
142#[derive(Clone, Serialize, Deserialize)]
145#[serde(remote = "Self")]
146pub struct Key {
147 #[serde(rename = "alg")]
149 pub algorithm: Algorithm,
150
151 #[serde(rename = "key_ops")]
153 pub operations: HashSet<KeyOperation>,
154
155 #[serde(flatten)]
157 pub key: KeyType,
158
159 #[serde(skip_serializing_if = "Option::is_none")]
161 pub kid: Option<crate::KeyId>,
162
163 #[serde(skip)]
165 pub(crate) decode: OnceLock<DecodingKey>,
166
167 #[serde(skip)]
168 pub(crate) encode: OnceLock<EncodingKey>,
169}
170
171impl<'de> Deserialize<'de> for Key {
172 fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>
173 where
174 D: Deserializer<'de>,
175 {
176 let mut value = serde_json::Value::deserialize(deserializer)?;
177
178 if let Some(obj) = value.as_object_mut()
182 && !obj.contains_key("kty")
183 {
184 obj.insert("kty".to_string(), serde_json::Value::String("oct".to_string()));
185 }
186
187 Self::deserialize(value).map_err(serde::de::Error::custom)
188 }
189}
190
191impl Serialize for Key {
192 fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
193 where
194 S: Serializer,
195 {
196 Self::serialize(self, serializer)
197 }
198}
199
200impl fmt::Debug for Key {
201 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
202 f.debug_struct("Key")
203 .field("algorithm", &self.algorithm)
204 .field("operations", &self.operations)
205 .field("kid", &self.kid)
206 .finish()
207 }
208}
209
210impl Key {
211 #[allow(clippy::should_implement_trait)]
212 pub fn from_str(s: &str) -> crate::Result<Self> {
213 Ok(serde_json::from_str(s)?)
214 }
215
216 pub fn from_file<P: AsRef<StdPath>>(path: P) -> crate::Result<Self> {
218 let contents = std::fs::read_to_string(&path)?;
219 Self::from_encoded(&contents)
220 }
221
222 #[cfg(feature = "tokio")]
224 pub async fn from_file_async<P: AsRef<StdPath>>(path: P) -> crate::Result<Self> {
225 let contents = tokio::fs::read_to_string(path).await?;
226 Self::from_encoded(&contents)
227 }
228
229 fn from_encoded(contents: &str) -> crate::Result<Self> {
231 let contents = contents.trim();
232 if contents.starts_with('{') {
233 Ok(serde_json::from_str(contents)?)
234 } else {
235 let decoded = base64::engine::general_purpose::URL_SAFE_NO_PAD.decode(contents)?;
236 let json = String::from_utf8(decoded)?;
237 Ok(serde_json::from_str(&json)?)
238 }
239 }
240
241 pub fn to_str(&self) -> crate::Result<String> {
242 Ok(serde_json::to_string(self)?)
243 }
244
245 pub fn to_file<P: AsRef<StdPath>>(&self, path: P) -> crate::Result<()> {
247 let json = serde_json::to_string_pretty(self)?;
248 std::fs::write(path, json)?;
249 Ok(())
250 }
251
252 pub fn to_file_base64url<P: AsRef<StdPath>>(&self, path: P) -> crate::Result<()> {
254 let json = serde_json::to_string(self)?;
255 let encoded = base64::engine::general_purpose::URL_SAFE_NO_PAD.encode(json.as_bytes());
256 std::fs::write(path, encoded)?;
257 Ok(())
258 }
259
260 pub fn to_public(&self) -> crate::Result<Self> {
261 if !self.operations.contains(&KeyOperation::Verify) {
262 return Err(KeyError::VerifyUnsupported.into());
263 }
264
265 let key = match self.key {
266 KeyType::RSA { ref public, .. } => KeyType::RSA {
267 public: public.clone(),
268 private: None,
269 },
270 KeyType::EC {
271 ref x,
272 ref y,
273 ref curve,
274 ..
275 } => KeyType::EC {
276 x: x.clone(),
277 y: y.clone(),
278 curve: curve.clone(),
279 d: None,
280 },
281 KeyType::OCT { .. } => return Err(KeyError::NoPublicKey.into()),
282 KeyType::OKP { ref x, ref curve, .. } => KeyType::OKP {
283 x: x.clone(),
284 curve: curve.clone(),
285 d: None,
286 },
287 };
288
289 Ok(Self {
290 algorithm: self.algorithm,
291 operations: [KeyOperation::Verify].into(),
292 key,
293 kid: self.kid.clone(),
294 decode: Default::default(),
295 encode: Default::default(),
296 })
297 }
298
299 fn to_decoding_key(&self) -> crate::Result<&DecodingKey> {
300 if let Some(key) = self.decode.get() {
301 return Ok(key);
302 }
303
304 let decoding_key = match self.key {
305 KeyType::OCT { ref secret } => match self.algorithm {
306 Algorithm::HS256 | Algorithm::HS384 | Algorithm::HS512 => DecodingKey::from_secret(secret),
307 _ => return Err(KeyError::InvalidAlgorithm.into()),
308 },
309 KeyType::EC {
310 ref curve,
311 ref x,
312 ref y,
313 ..
314 } => match curve {
315 EllipticCurve::P256 => {
316 if self.algorithm != Algorithm::ES256 {
317 return Err(KeyError::InvalidAlgorithmForCurve("P-256").into());
318 }
319 if x.len() != 32 || y.len() != 32 {
320 return Err(KeyError::InvalidCoordinateLength("P-256").into());
321 }
322
323 DecodingKey::from_ec_components(
324 base64::engine::general_purpose::URL_SAFE_NO_PAD.encode(x).as_ref(),
325 base64::engine::general_purpose::URL_SAFE_NO_PAD.encode(y).as_ref(),
326 )?
327 }
328 EllipticCurve::P384 => {
329 if self.algorithm != Algorithm::ES384 {
330 return Err(KeyError::InvalidAlgorithmForCurve("P-384").into());
331 }
332 if x.len() != 48 || y.len() != 48 {
333 return Err(KeyError::InvalidCoordinateLength("P-384").into());
334 }
335
336 DecodingKey::from_ec_components(
337 base64::engine::general_purpose::URL_SAFE_NO_PAD.encode(x).as_ref(),
338 base64::engine::general_purpose::URL_SAFE_NO_PAD.encode(y).as_ref(),
339 )?
340 }
341 _ => return Err(KeyError::InvalidCurve("EC").into()),
342 },
343 KeyType::OKP { ref curve, ref x, .. } => match curve {
344 EllipticCurve::Ed25519 => {
345 if self.algorithm != Algorithm::EdDSA {
346 return Err(KeyError::InvalidAlgorithmForCurve("Ed25519").into());
347 }
348
349 DecodingKey::from_ed_components(
350 base64::engine::general_purpose::URL_SAFE_NO_PAD.encode(x).as_ref(),
351 )?
352 }
353 _ => return Err(KeyError::InvalidCurve("OKP").into()),
354 },
355 KeyType::RSA { ref public, .. } => {
356 DecodingKey::from_rsa_raw_components(public.n.as_ref(), public.e.as_ref())
357 }
358 };
359
360 Ok(self.decode.get_or_init(|| decoding_key))
361 }
362
363 fn to_encoding_key(&self) -> crate::Result<&EncodingKey> {
364 if let Some(key) = self.encode.get() {
365 return Ok(key);
366 }
367
368 let encoding_key = match self.key {
369 KeyType::OCT { ref secret } => match self.algorithm {
370 Algorithm::HS256 | Algorithm::HS384 | Algorithm::HS512 => EncodingKey::from_secret(secret),
371 _ => return Err(KeyError::InvalidAlgorithm.into()),
372 },
373 KeyType::EC { ref curve, ref d, .. } => {
374 let d = d.as_ref().ok_or(KeyError::MissingPrivateKey)?;
375
376 match curve {
377 EllipticCurve::P256 => {
378 let secret_key = SecretKey::<p256::NistP256>::from_slice(d)?;
379 let doc = secret_key.to_pkcs8_der()?;
380 EncodingKey::from_ec_der(doc.as_bytes())
381 }
382 EllipticCurve::P384 => {
383 let secret_key = SecretKey::<p384::NistP384>::from_slice(d)?;
384 let doc = secret_key.to_pkcs8_der()?;
385 EncodingKey::from_ec_der(doc.as_bytes())
386 }
387 _ => return Err(KeyError::InvalidCurve("EC").into()),
388 }
389 }
390 KeyType::OKP {
391 ref curve,
392 ref d,
393 ref x,
394 } => {
395 let d = d.as_ref().ok_or(KeyError::MissingPrivateKey)?;
396
397 let key_pair =
398 aws_lc_rs::signature::Ed25519KeyPair::from_seed_and_public_key(d.as_slice(), x.as_slice())?;
399
400 match curve {
401 EllipticCurve::Ed25519 => EncodingKey::from_ed_der(key_pair.to_pkcs8()?.as_ref()),
402 _ => return Err(KeyError::InvalidCurve("OKP").into()),
403 }
404 }
405 KeyType::RSA {
406 ref public,
407 ref private,
408 } => {
409 let n = BigUint::from_bytes_be(&public.n);
410 let e = BigUint::from_bytes_be(&public.e);
411 let private = private.as_ref().ok_or(KeyError::MissingPrivateKey)?;
412 let d = BigUint::from_bytes_be(&private.d);
413 let p = BigUint::from_bytes_be(&private.p);
414 let q = BigUint::from_bytes_be(&private.q);
415
416 let rsa = rsa::RsaPrivateKey::from_components(n, e, d, vec![p, q]);
417 let pem = rsa?.to_pkcs1_pem(rsa::pkcs1::LineEnding::LF);
418
419 EncodingKey::from_rsa_pem(pem?.as_bytes())?
420 }
421 };
422
423 Ok(self.encode.get_or_init(|| encoding_key))
424 }
425
426 pub fn decode(&self, token: &str) -> crate::Result<Claims> {
427 if !self.operations.contains(&KeyOperation::Verify) {
428 return Err(KeyError::VerifyUnsupported.into());
429 }
430
431 let decode = self.to_decoding_key()?;
432
433 let mut validation = jsonwebtoken::Validation::new(self.algorithm.into());
434 validation.required_spec_claims = Default::default(); validation.validate_exp = false; let token = jsonwebtoken::decode::<Claims>(token, decode, &validation)?;
438
439 if let Some(exp) = token.claims.expires
440 && exp < std::time::SystemTime::now()
441 {
442 return Err(crate::Error::TokenExpired);
443 }
444
445 token.claims.validate()?;
446
447 Ok(token.claims)
448 }
449
450 pub fn encode(&self, payload: &Claims) -> crate::Result<String> {
451 if !self.operations.contains(&KeyOperation::Sign) {
452 return Err(KeyError::SignUnsupported.into());
453 }
454
455 payload.validate()?;
456
457 let encode = self.to_encoding_key()?;
458
459 let mut header = Header::new(self.algorithm.into());
460 header.kid = self.kid.as_ref().map(|k| k.to_string());
461 let token = jsonwebtoken::encode(&header, &payload, encode)?;
462 Ok(token)
463 }
464
465 pub fn generate(algorithm: Algorithm, id: Option<crate::KeyId>) -> crate::Result<Self> {
467 generate(algorithm, id)
468 }
469}
470
471fn serialize_base64url<S>(bytes: &[u8], serializer: S) -> Result<S::Ok, S::Error>
473where
474 S: Serializer,
475{
476 let encoded = base64::engine::general_purpose::URL_SAFE_NO_PAD.encode(bytes);
477 serializer.serialize_str(&encoded)
478}
479
480fn serialize_base64url_optional<S>(bytes: &Option<Vec<u8>>, serializer: S) -> Result<S::Ok, S::Error>
481where
482 S: Serializer,
483{
484 match bytes {
485 Some(b) => serialize_base64url(b, serializer),
486 None => serializer.serialize_none(),
487 }
488}
489
490fn deserialize_base64url<'de, D>(deserializer: D) -> Result<Vec<u8>, D::Error>
492where
493 D: Deserializer<'de>,
494{
495 let s = String::deserialize(deserializer)?;
496
497 base64::engine::general_purpose::URL_SAFE_NO_PAD
499 .decode(&s)
500 .or_else(|_| {
501 base64::engine::general_purpose::URL_SAFE.decode(&s)
503 })
504 .map_err(serde::de::Error::custom)
505}
506
507fn deserialize_base64url_optional<'de, D>(deserializer: D) -> Result<Option<Vec<u8>>, D::Error>
508where
509 D: Deserializer<'de>,
510{
511 let s: Option<String> = Option::deserialize(deserializer)?;
512 match s {
513 Some(s) => {
514 let decoded = base64::engine::general_purpose::URL_SAFE_NO_PAD
515 .decode(&s)
516 .or_else(|_| base64::engine::general_purpose::URL_SAFE.decode(&s))
517 .map_err(serde::de::Error::custom)?;
518 Ok(Some(decoded))
519 }
520 None => Ok(None),
521 }
522}
523
524#[cfg(test)]
525mod tests {
526 use super::*;
527 use std::time::{Duration, SystemTime};
528
529 fn create_test_key() -> Key {
530 Key {
531 algorithm: Algorithm::HS256,
532 operations: [KeyOperation::Sign, KeyOperation::Verify].into(),
533 key: KeyType::OCT {
534 secret: b"test-secret-that-is-long-enough-for-hmac-sha256".to_vec(),
535 },
536 kid: Some(crate::KeyId::decode("test-key-1").unwrap()),
537 decode: Default::default(),
538 encode: Default::default(),
539 }
540 }
541
542 fn create_test_claims() -> Claims {
543 Claims {
544 root: "test-path".to_string(),
545 publish: vec!["test-pub".into()],
546 cluster: false,
547 subscribe: vec!["test-sub".into()],
548 expires: Some(SystemTime::now() + Duration::from_secs(3600)),
549 issued: Some(SystemTime::now()),
550 }
551 }
552
553 #[test]
554 fn test_key_from_str_valid() {
555 let key = create_test_key();
556 let json = key.to_str().unwrap();
557 let loaded_key = Key::from_str(&json).unwrap();
558
559 assert_eq!(loaded_key.algorithm, key.algorithm);
560 assert_eq!(loaded_key.operations, key.operations);
561 match (loaded_key.key, key.key) {
562 (KeyType::OCT { secret: loaded_secret }, KeyType::OCT { secret }) => {
563 assert_eq!(loaded_secret, secret);
564 }
565 _ => panic!("Expected OCT key"),
566 }
567 assert_eq!(loaded_key.kid, key.kid);
568 }
569
570 #[test]
572 fn test_key_oct_backwards_compatibility() {
573 let json = r#"{"alg":"HS256","key_ops":["sign","verify"],"k":"Fp8kipWUJeUFqeSqWym_tRC_tyI8z-QpqopIGrbrD68"}"#;
574 let key = Key::from_str(json);
575
576 assert!(key.is_ok());
577 let key = key.unwrap();
578
579 if let KeyType::OCT { ref secret, .. } = key.key {
580 let base64_key = base64::engine::general_purpose::URL_SAFE_NO_PAD.encode(secret);
581 assert_eq!(base64_key, "Fp8kipWUJeUFqeSqWym_tRC_tyI8z-QpqopIGrbrD68");
582 } else {
583 panic!("Expected OCT key");
584 }
585
586 let key_str = key.to_str();
587 assert!(key_str.is_ok());
588 let key_str = key_str.unwrap();
589
590 assert!(key_str.contains("\"alg\":\"HS256\""));
592 assert!(key_str.contains("\"key_ops\""));
593 assert!(key_str.contains("\"sign\""));
594 assert!(key_str.contains("\"verify\""));
595 assert!(key_str.contains("\"kty\":\"oct\""));
596 }
597
598 #[test]
599 fn test_key_from_str_invalid_json() {
600 let result = Key::from_str("invalid json");
601 assert!(result.is_err());
602 }
603
604 #[test]
605 fn test_key_to_str() {
606 let key = create_test_key();
607 let json = key.to_str().unwrap();
608 assert!(json.contains("\"alg\":\"HS256\""));
609 assert!(json.contains("\"key_ops\""));
610 assert!(json.contains("\"sign\""));
611 assert!(json.contains("\"verify\""));
612 assert!(json.contains("\"kid\":\"test-key-1\""));
613 assert!(json.contains("\"kty\":\"oct\""));
614 }
615
616 #[test]
617 fn test_key_sign_success() {
618 let key = create_test_key();
619 let claims = create_test_claims();
620 let token = key.encode(&claims).unwrap();
621
622 assert!(!token.is_empty());
623 assert_eq!(token.matches('.').count(), 2); }
625
626 #[test]
627 fn test_key_sign_no_permission() {
628 let mut key = create_test_key();
629 key.operations = [KeyOperation::Verify].into();
630 let claims = create_test_claims();
631
632 let result = key.encode(&claims);
633 assert!(result.is_err());
634 assert!(result.unwrap_err().to_string().contains("key does not support signing"));
635 }
636
637 #[test]
638 fn test_key_sign_invalid_claims() {
639 let key = create_test_key();
640 let invalid_claims = Claims {
641 root: "test-path".to_string(),
642 publish: vec![],
643 subscribe: vec![],
644 cluster: false,
645 expires: None,
646 issued: None,
647 };
648
649 let result = key.encode(&invalid_claims);
650 assert!(result.is_err());
651 assert!(
652 result
653 .unwrap_err()
654 .to_string()
655 .contains("no publish or subscribe allowed; token is useless")
656 );
657 }
658
659 #[test]
660 fn test_key_verify_success() {
661 let key = create_test_key();
662 let claims = create_test_claims();
663 let token = key.encode(&claims).unwrap();
664
665 let verified_claims = key.decode(&token).unwrap();
666 assert_eq!(verified_claims.root, claims.root);
667 assert_eq!(verified_claims.publish, claims.publish);
668 assert_eq!(verified_claims.subscribe, claims.subscribe);
669 assert_eq!(verified_claims.cluster, claims.cluster);
670 }
671
672 #[test]
673 fn test_key_verify_no_permission() {
674 let mut key = create_test_key();
675 key.operations = [KeyOperation::Sign].into();
676
677 let result = key.decode("some.jwt.token");
678 assert!(result.is_err());
679 assert!(
680 result
681 .unwrap_err()
682 .to_string()
683 .contains("key does not support verification")
684 );
685 }
686
687 #[test]
688 fn test_key_verify_invalid_token() {
689 let key = create_test_key();
690 let result = key.decode("invalid-token");
691 assert!(result.is_err());
692 }
693
694 #[test]
695 fn test_key_verify_path_mismatch() {
696 let key = create_test_key();
697 let claims = create_test_claims();
698 let token = key.encode(&claims).unwrap();
699
700 let result = key.decode(&token);
702 assert!(result.is_ok());
703 }
704
705 #[test]
706 fn test_key_verify_expired_token() {
707 let key = create_test_key();
708 let mut claims = create_test_claims();
709 claims.expires = Some(SystemTime::now() - Duration::from_secs(3600)); let token = key.encode(&claims).unwrap();
711
712 let result = key.decode(&token);
713 assert!(result.is_err());
714 }
715
716 #[test]
717 fn test_key_verify_token_without_exp() {
718 let key = create_test_key();
719 let claims = Claims {
720 root: "test-path".to_string(),
721 publish: vec!["".to_string()],
722 subscribe: vec!["".to_string()],
723 cluster: false,
724 expires: None,
725 issued: None,
726 };
727 let token = key.encode(&claims).unwrap();
728
729 let verified_claims = key.decode(&token).unwrap();
730 assert_eq!(verified_claims.root, claims.root);
731 assert_eq!(verified_claims.publish, claims.publish);
732 assert_eq!(verified_claims.subscribe, claims.subscribe);
733 assert_eq!(verified_claims.expires, None);
734 }
735
736 #[test]
737 fn test_key_round_trip() {
738 let key = create_test_key();
739 let original_claims = Claims {
740 root: "test-path".to_string(),
741 publish: vec!["test-pub".into()],
742 subscribe: vec!["test-sub".into()],
743 cluster: true,
744 expires: Some(SystemTime::now() + Duration::from_secs(3600)),
745 issued: Some(SystemTime::now()),
746 };
747
748 let token = key.encode(&original_claims).unwrap();
749 let verified_claims = key.decode(&token).unwrap();
750
751 assert_eq!(verified_claims.root, original_claims.root);
752 assert_eq!(verified_claims.publish, original_claims.publish);
753 assert_eq!(verified_claims.subscribe, original_claims.subscribe);
754 assert_eq!(verified_claims.cluster, original_claims.cluster);
755 }
756
757 #[test]
758 fn test_key_generate_hs256() {
759 let key = Key::generate(Algorithm::HS256, Some(crate::KeyId::decode("test-id").unwrap()));
760 assert!(key.is_ok());
761 let key = key.unwrap();
762
763 assert_eq!(key.algorithm, Algorithm::HS256);
764 assert_eq!(key.kid, Some(crate::KeyId::decode("test-id").unwrap()));
765 assert_eq!(key.operations, [KeyOperation::Sign, KeyOperation::Verify].into());
766
767 match key.key {
768 KeyType::OCT { ref secret } => assert_eq!(secret.len(), 32),
769 _ => panic!("Expected OCT key"),
770 }
771 }
772
773 #[test]
774 fn test_key_generate_hs384() {
775 let key = Key::generate(Algorithm::HS384, Some(crate::KeyId::decode("test-id").unwrap()));
776 assert!(key.is_ok());
777 let key = key.unwrap();
778
779 assert_eq!(key.algorithm, Algorithm::HS384);
780
781 match key.key {
782 KeyType::OCT { ref secret } => assert_eq!(secret.len(), 48),
783 _ => panic!("Expected OCT key"),
784 }
785 }
786
787 #[test]
788 fn test_key_generate_hs512() {
789 let key = Key::generate(Algorithm::HS512, Some(crate::KeyId::decode("test-id").unwrap()));
790 assert!(key.is_ok());
791 let key = key.unwrap();
792
793 assert_eq!(key.algorithm, Algorithm::HS512);
794
795 match key.key {
796 KeyType::OCT { ref secret } => assert_eq!(secret.len(), 64),
797 _ => panic!("Expected OCT key"),
798 }
799 }
800
801 #[test]
802 fn test_key_generate_rs512() {
803 let key = Key::generate(Algorithm::RS512, Some(crate::KeyId::decode("test-id").unwrap()));
804 assert!(key.is_ok());
805 let key = key.unwrap();
806
807 assert_eq!(key.algorithm, Algorithm::RS512);
808 assert!(matches!(key.key, KeyType::RSA { .. }));
809 match key.key {
810 KeyType::RSA {
811 ref public,
812 ref private,
813 } => {
814 assert!(private.is_some());
815 assert_eq!(public.n.len(), 256);
816 assert_eq!(public.e.len(), 3);
817 }
818 _ => panic!("Expected RSA key"),
819 }
820 }
821
822 #[test]
823 fn test_key_generate_es256() {
824 let key = Key::generate(Algorithm::ES256, Some(crate::KeyId::decode("test-id").unwrap()));
825 assert!(key.is_ok());
826 let key = key.unwrap();
827
828 assert_eq!(key.algorithm, Algorithm::ES256);
829 assert!(matches!(key.key, KeyType::EC { .. }))
830 }
831
832 #[test]
833 fn test_key_generate_ps512() {
834 let key = Key::generate(Algorithm::PS512, Some(crate::KeyId::decode("test-id").unwrap()));
835 assert!(key.is_ok());
836 let key = key.unwrap();
837
838 assert_eq!(key.algorithm, Algorithm::PS512);
839 assert!(matches!(key.key, KeyType::RSA { .. }));
840 }
841
842 #[test]
843 fn test_key_generate_eddsa() {
844 let key = Key::generate(Algorithm::EdDSA, Some(crate::KeyId::decode("test-id").unwrap()));
845 assert!(key.is_ok());
846 let key = key.unwrap();
847
848 assert_eq!(key.algorithm, Algorithm::EdDSA);
849 assert!(matches!(key.key, KeyType::OKP { .. }));
850 }
851
852 #[test]
853 fn test_key_generate_without_id() {
854 let key = Key::generate(Algorithm::HS256, None);
855 assert!(key.is_ok());
856 let key = key.unwrap();
857
858 assert_eq!(key.algorithm, Algorithm::HS256);
859 assert_eq!(key.kid, None);
860 assert_eq!(key.operations, [KeyOperation::Sign, KeyOperation::Verify].into());
861 }
862
863 #[test]
864 fn test_public_key_conversion_hmac() {
865 let key = Key::generate(Algorithm::HS256, Some(crate::KeyId::decode("test-id").unwrap()))
866 .expect("HMAC key generation failed");
867
868 assert!(key.to_public().is_err());
869 }
870
871 #[test]
872 fn test_public_key_conversion_rsa() {
873 let key = Key::generate(Algorithm::RS256, Some(crate::KeyId::decode("test-id").unwrap()));
874 assert!(key.is_ok());
875 let key = key.unwrap();
876
877 let public_key = key.to_public().unwrap();
878 assert_eq!(key.kid, public_key.kid);
879 assert_eq!(public_key.operations, [KeyOperation::Verify].into());
880 assert!(public_key.encode.get().is_none());
881 assert!(public_key.decode.get().is_none());
882 assert!(matches!(public_key.key, KeyType::RSA { .. }));
883
884 if let KeyType::RSA { public, private } = &public_key.key {
885 assert!(private.is_none());
886
887 if let KeyType::RSA { public: src_public, .. } = &key.key {
888 assert_eq!(public.e, src_public.e);
889 assert_eq!(public.n, src_public.n);
890 } else {
891 unreachable!("Expected RSA key")
892 }
893 } else {
894 unreachable!("Expected RSA key");
895 }
896 }
897
898 #[test]
899 fn test_public_key_conversion_es() {
900 let key = Key::generate(Algorithm::ES256, Some(crate::KeyId::decode("test-id").unwrap()));
901 assert!(key.is_ok());
902 let key = key.unwrap();
903
904 let public_key = key.to_public().unwrap();
905 assert_eq!(key.kid, public_key.kid);
906 assert_eq!(public_key.operations, [KeyOperation::Verify].into());
907 assert!(public_key.encode.get().is_none());
908 assert!(public_key.decode.get().is_none());
909 assert!(matches!(public_key.key, KeyType::EC { .. }));
910
911 if let KeyType::EC { x, y, d, curve } = &public_key.key {
912 assert!(d.is_none());
913
914 if let KeyType::EC {
915 x: src_x,
916 y: src_y,
917 curve: src_curve,
918 ..
919 } = &key.key
920 {
921 assert_eq!(x, src_x);
922 assert_eq!(y, src_y);
923 assert_eq!(curve, src_curve);
924 } else {
925 unreachable!("Expected EC key")
926 }
927 } else {
928 unreachable!("Expected EC key");
929 }
930 }
931
932 #[test]
933 fn test_public_key_conversion_ed() {
934 let key = Key::generate(Algorithm::EdDSA, Some(crate::KeyId::decode("test-id").unwrap()));
935 assert!(key.is_ok());
936 let key = key.unwrap();
937
938 let public_key = key.to_public().unwrap();
939 assert_eq!(key.kid, public_key.kid);
940 assert_eq!(public_key.operations, [KeyOperation::Verify].into());
941 assert!(public_key.encode.get().is_none());
942 assert!(public_key.decode.get().is_none());
943 assert!(matches!(public_key.key, KeyType::OKP { .. }));
944
945 if let KeyType::OKP { x, d, curve } = &public_key.key {
946 assert!(d.is_none());
947
948 if let KeyType::OKP {
949 x: src_x,
950 curve: src_curve,
951 ..
952 } = &key.key
953 {
954 assert_eq!(x, src_x);
955 assert_eq!(curve, src_curve);
956 } else {
957 unreachable!("Expected OKP key")
958 }
959 } else {
960 unreachable!("Expected OKP key");
961 }
962 }
963
964 #[test]
965 fn test_key_generate_sign_verify_cycle() {
966 let key = Key::generate(Algorithm::HS256, Some(crate::KeyId::decode("test-id").unwrap()));
967 assert!(key.is_ok());
968 let key = key.unwrap();
969
970 let claims = create_test_claims();
971
972 let token = key.encode(&claims).unwrap();
973 let verified_claims = key.decode(&token).unwrap();
974
975 assert_eq!(verified_claims.root, claims.root);
976 assert_eq!(verified_claims.publish, claims.publish);
977 assert_eq!(verified_claims.subscribe, claims.subscribe);
978 assert_eq!(verified_claims.cluster, claims.cluster);
979 }
980
981 #[test]
982 fn test_key_debug_no_secret() {
983 let key = create_test_key();
984 let debug_str = format!("{key:?}");
985
986 assert!(debug_str.contains("algorithm: HS256"));
987 assert!(debug_str.contains("operations"));
988 assert!(debug_str.contains("kid: Some(KeyId(\"test-key-1\"))"));
989 assert!(!debug_str.contains("secret")); }
991
992 #[test]
993 fn test_key_operations_enum() {
994 let sign_op = KeyOperation::Sign;
995 let verify_op = KeyOperation::Verify;
996 let decrypt_op = KeyOperation::Decrypt;
997 let encrypt_op = KeyOperation::Encrypt;
998
999 assert_eq!(sign_op, KeyOperation::Sign);
1000 assert_eq!(verify_op, KeyOperation::Verify);
1001 assert_eq!(decrypt_op, KeyOperation::Decrypt);
1002 assert_eq!(encrypt_op, KeyOperation::Encrypt);
1003
1004 assert_ne!(sign_op, verify_op);
1005 assert_ne!(decrypt_op, encrypt_op);
1006 }
1007
1008 #[test]
1009 fn test_key_operations_serde() {
1010 let operations = [KeyOperation::Sign, KeyOperation::Verify];
1011 let json = serde_json::to_string(&operations).unwrap();
1012 assert!(json.contains("\"sign\""));
1013 assert!(json.contains("\"verify\""));
1014
1015 let deserialized: Vec<KeyOperation> = serde_json::from_str(&json).unwrap();
1016 assert_eq!(deserialized, operations);
1017 }
1018
1019 #[test]
1020 fn test_key_serde() {
1021 let key = create_test_key();
1022 let json = serde_json::to_string(&key).unwrap();
1023 let deserialized: Key = serde_json::from_str(&json).unwrap();
1024
1025 assert_eq!(deserialized.algorithm, key.algorithm);
1026 assert_eq!(deserialized.operations, key.operations);
1027 assert_eq!(deserialized.kid, key.kid);
1028
1029 if let (
1030 KeyType::OCT {
1031 secret: original_secret,
1032 },
1033 KeyType::OCT {
1034 secret: deserialized_secret,
1035 },
1036 ) = (&key.key, &deserialized.key)
1037 {
1038 assert_eq!(deserialized_secret, original_secret);
1039 } else {
1040 panic!("Expected both keys to be OCT variant");
1041 }
1042 }
1043
1044 #[test]
1045 fn test_key_clone() {
1046 let key = create_test_key();
1047 let cloned = key.clone();
1048
1049 assert_eq!(cloned.algorithm, key.algorithm);
1050 assert_eq!(cloned.operations, key.operations);
1051 assert_eq!(cloned.kid, key.kid);
1052
1053 if let (
1054 KeyType::OCT {
1055 secret: original_secret,
1056 },
1057 KeyType::OCT { secret: cloned_secret },
1058 ) = (&key.key, &cloned.key)
1059 {
1060 assert_eq!(cloned_secret, original_secret);
1061 } else {
1062 panic!("Expected both keys to be OCT variant");
1063 }
1064 }
1065
1066 #[test]
1067 fn test_hmac_algorithms() {
1068 let key_256 = Key::generate(Algorithm::HS256, Some(crate::KeyId::decode("test-id").unwrap()));
1069 let key_384 = Key::generate(Algorithm::HS384, Some(crate::KeyId::decode("test-id").unwrap()));
1070 let key_512 = Key::generate(Algorithm::HS512, Some(crate::KeyId::decode("test-id").unwrap()));
1071
1072 let claims = create_test_claims();
1073
1074 for key in [key_256, key_384, key_512] {
1076 assert!(key.is_ok());
1077 let key = key.unwrap();
1078
1079 let token = key.encode(&claims).unwrap();
1080 let verified_claims = key.decode(&token).unwrap();
1081 assert_eq!(verified_claims.root, claims.root);
1082 }
1083 }
1084
1085 #[test]
1086 fn test_rsa_pkcs1_asymmetric_algorithms() {
1087 let key_rs256 = Key::generate(Algorithm::RS256, Some(crate::KeyId::decode("test-id").unwrap()));
1088 let key_rs384 = Key::generate(Algorithm::RS384, Some(crate::KeyId::decode("test-id").unwrap()));
1089 let key_rs512 = Key::generate(Algorithm::RS512, Some(crate::KeyId::decode("test-id").unwrap()));
1090
1091 for key in [key_rs256, key_rs384, key_rs512] {
1092 test_asymmetric_key(key);
1093 }
1094 }
1095
1096 #[test]
1097 fn test_rsa_pss_asymmetric_algorithms() {
1098 let key_ps256 = Key::generate(Algorithm::PS256, Some(crate::KeyId::decode("test-id").unwrap()));
1099 let key_ps384 = Key::generate(Algorithm::PS384, Some(crate::KeyId::decode("test-id").unwrap()));
1100 let key_ps512 = Key::generate(Algorithm::PS512, Some(crate::KeyId::decode("test-id").unwrap()));
1101
1102 for key in [key_ps256, key_ps384, key_ps512] {
1103 test_asymmetric_key(key);
1104 }
1105 }
1106
1107 #[test]
1108 fn test_ec_asymmetric_algorithms() {
1109 let key_es256 = Key::generate(Algorithm::ES256, Some(crate::KeyId::decode("test-id").unwrap()));
1110 let key_es384 = Key::generate(Algorithm::ES384, Some(crate::KeyId::decode("test-id").unwrap()));
1111
1112 for key in [key_es256, key_es384] {
1113 test_asymmetric_key(key);
1114 }
1115 }
1116
1117 #[test]
1118 fn test_ed_asymmetric_algorithms() {
1119 let key_eddsa = Key::generate(Algorithm::EdDSA, Some(crate::KeyId::decode("test-id").unwrap()));
1120
1121 test_asymmetric_key(key_eddsa);
1122 }
1123
1124 fn test_asymmetric_key(key: crate::Result<Key>) {
1125 assert!(key.is_ok());
1126 let key = key.unwrap();
1127
1128 let claims = create_test_claims();
1129 let token = key.encode(&claims).unwrap();
1130
1131 let private_verified_claims = key.decode(&token).unwrap();
1132 assert_eq!(
1133 private_verified_claims.root, claims.root,
1134 "validation using private key"
1135 );
1136
1137 let public_verified_claims = key.to_public().unwrap().decode(&token).unwrap();
1138 assert_eq!(public_verified_claims.root, claims.root, "validation using public key");
1139 }
1140
1141 #[test]
1142 fn test_cross_algorithm_verification_fails() {
1143 let key_256 = Key::generate(Algorithm::HS256, Some(crate::KeyId::decode("test-id").unwrap()));
1144 assert!(key_256.is_ok());
1145 let key_256 = key_256.unwrap();
1146
1147 let key_384 = Key::generate(Algorithm::HS384, Some(crate::KeyId::decode("test-id").unwrap()));
1148 assert!(key_384.is_ok());
1149 let key_384 = key_384.unwrap();
1150
1151 let claims = create_test_claims();
1152 let token = key_256.encode(&claims).unwrap();
1153
1154 let result = key_384.decode(&token);
1156 assert!(result.is_err());
1157 }
1158
1159 #[test]
1160 fn test_asymmetric_cross_algorithm_verification_fails() {
1161 let key_rs256 = Key::generate(Algorithm::RS256, Some(crate::KeyId::decode("test-id").unwrap()));
1162 assert!(key_rs256.is_ok());
1163 let key_rs256 = key_rs256.unwrap();
1164
1165 let key_ps256 = Key::generate(Algorithm::PS256, Some(crate::KeyId::decode("test-id").unwrap()));
1166 assert!(key_ps256.is_ok());
1167 let key_ps256 = key_ps256.unwrap();
1168
1169 let claims = create_test_claims();
1170 let token = key_rs256.encode(&claims).unwrap();
1171
1172 let private_result = key_ps256.decode(&token);
1174 let public_result = key_ps256.to_public().unwrap().decode(&token);
1175 assert!(private_result.is_err());
1176 assert!(public_result.is_err());
1177 }
1178
1179 #[test]
1180 fn test_rsa_pkcs1_public_key_conversion() {
1181 let key = Key::generate(Algorithm::RS256, Some(crate::KeyId::decode("test-id").unwrap()));
1182 assert!(key.is_ok());
1183 let key = key.unwrap();
1184
1185 assert!(key.operations.contains(&KeyOperation::Sign));
1186 assert!(key.operations.contains(&KeyOperation::Verify));
1187
1188 let public_key = key.to_public().unwrap();
1189 assert!(!public_key.operations.contains(&KeyOperation::Sign));
1190 assert!(public_key.operations.contains(&KeyOperation::Verify));
1191
1192 match key.key {
1193 KeyType::RSA {
1194 ref public,
1195 ref private,
1196 } => {
1197 assert!(private.is_some());
1198 assert_eq!(public.n.len(), 256);
1199 assert_eq!(public.e.len(), 3);
1200
1201 match public_key.key {
1202 KeyType::RSA {
1203 public: ref guest_public,
1204 private: ref public_private,
1205 } => {
1206 assert!(public_private.is_none());
1207 assert_eq!(public.n, guest_public.n);
1208 assert_eq!(public.e, guest_public.e);
1209 }
1210 _ => panic!("Expected public key to be an RSA key"),
1211 }
1212 }
1213 _ => panic!("Expected private key to be an RSA key"),
1214 }
1215 }
1216
1217 #[test]
1218 fn test_rsa_pss_public_key_conversion() {
1219 let key = Key::generate(Algorithm::PS384, Some(crate::KeyId::decode("test-id").unwrap()));
1220 assert!(key.is_ok());
1221 let key = key.unwrap();
1222
1223 assert!(key.operations.contains(&KeyOperation::Sign));
1224 assert!(key.operations.contains(&KeyOperation::Verify));
1225
1226 let public_key = key.to_public().unwrap();
1227 assert!(!public_key.operations.contains(&KeyOperation::Sign));
1228 assert!(public_key.operations.contains(&KeyOperation::Verify));
1229
1230 match key.key {
1231 KeyType::RSA {
1232 ref public,
1233 ref private,
1234 } => {
1235 assert!(private.is_some());
1236 assert_eq!(public.n.len(), 256);
1237 assert_eq!(public.e.len(), 3);
1238
1239 match public_key.key {
1240 KeyType::RSA {
1241 public: ref guest_public,
1242 private: ref public_private,
1243 } => {
1244 assert!(public_private.is_none());
1245 assert_eq!(public.n, guest_public.n);
1246 assert_eq!(public.e, guest_public.e);
1247 }
1248 _ => panic!("Expected public key to be an RSA key"),
1249 }
1250 }
1251 _ => panic!("Expected private key to be an RSA key"),
1252 }
1253 }
1254
1255 #[test]
1256 fn test_base64url_serialization() {
1257 let key = create_test_key();
1258 let json = serde_json::to_string(&key).unwrap();
1259
1260 let parsed: serde_json::Value = serde_json::from_str(&json).unwrap();
1262 let k_value = parsed["k"].as_str().unwrap();
1263
1264 assert!(!k_value.contains('='));
1266 assert!(!k_value.contains('+'));
1267 assert!(!k_value.contains('/'));
1268
1269 let decoded = base64::engine::general_purpose::URL_SAFE_NO_PAD
1271 .decode(k_value)
1272 .unwrap();
1273
1274 if let KeyType::OCT {
1275 secret: original_secret,
1276 } = &key.key
1277 {
1278 assert_eq!(decoded, *original_secret);
1279 } else {
1280 panic!("Expected both keys to be OCT variant");
1281 }
1282 }
1283
1284 #[test]
1285 fn test_backwards_compatibility_unpadded_base64url() {
1286 let unpadded_json = r#"{"kty":"oct","alg":"HS256","key_ops":["sign","verify"],"k":"dGVzdC1zZWNyZXQtdGhhdC1pcy1sb25nLWVub3VnaC1mb3ItaG1hYy1zaGEyNTY","kid":"test-key-1"}"#;
1288
1289 let key: Key = serde_json::from_str(unpadded_json).unwrap();
1291 assert_eq!(key.algorithm, Algorithm::HS256);
1292 assert_eq!(key.kid, Some(crate::KeyId::decode("test-key-1").unwrap()));
1293
1294 if let KeyType::OCT { secret } = &key.key {
1295 assert_eq!(secret, b"test-secret-that-is-long-enough-for-hmac-sha256");
1296 } else {
1297 panic!("Expected key to be OCT variant");
1298 }
1299 }
1300
1301 #[test]
1302 fn test_backwards_compatibility_padded_base64url() {
1303 let padded_json = r#"{"kty":"oct","alg":"HS256","key_ops":["sign","verify"],"k":"dGVzdC1zZWNyZXQtdGhhdC1pcy1sb25nLWVub3VnaC1mb3ItaG1hYy1zaGEyNTY=","kid":"test-key-1"}"#;
1305
1306 let key: Key = serde_json::from_str(padded_json).unwrap();
1308 assert_eq!(key.algorithm, Algorithm::HS256);
1309 assert_eq!(key.kid, Some(crate::KeyId::decode("test-key-1").unwrap()));
1310
1311 if let KeyType::OCT { secret } = &key.key {
1312 assert_eq!(secret, b"test-secret-that-is-long-enough-for-hmac-sha256");
1313 } else {
1314 panic!("Expected key to be OCT variant");
1315 }
1316 }
1317
1318 const JS_HS256_KEY: &str = r#"{"kty":"oct","alg":"HS256","k":"xm6xsSkfFqzPU3KfcbAcF2_h0OkStxQ_nNqVPYl0ync","kid":"js-test-key","key_ops":["sign","verify"],"guest":[],"guest_sub":[],"guest_pub":[]}"#;
1326
1327 const JS_HS256_TOKEN: &str = "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCIsImtpZCI6ImpzLXRlc3Qta2V5In0.eyJyb290IjoibGl2ZSIsInB1dCI6WyJjYW1lcmExIl0sImdldCI6WyJjYW1lcmExIiwiY2FtZXJhMiJdLCJpYXQiOjE3NzUxNzY3NTR9.tHNQtHh_HCIKxXOexDCM7AkjqWzbULLZzjEckfOGRfY";
1329
1330 const JS_EDDSA_PRIVATE_KEY: &str = r#"{"kty":"OKP","alg":"EdDSA","crv":"Ed25519","x":"UiU9fT_SdBBpkFtJPRCY0gX1jK_Dr9syYLFuEz4QUM4","d":"lm-L_PV3ksuQ-KrFBgFMDJqAZC3_Z6Z5UC4ZQY5OoDQ","kid":"js-eddsa-key","key_ops":["sign","verify"],"guest":[],"guest_sub":[],"guest_pub":[]}"#;
1332
1333 const JS_EDDSA_PUBLIC_KEY: &str = r#"{"kty":"OKP","alg":"EdDSA","crv":"Ed25519","x":"UiU9fT_SdBBpkFtJPRCY0gX1jK_Dr9syYLFuEz4QUM4","kid":"js-eddsa-key","guest":[],"guest_sub":[],"guest_pub":[],"key_ops":["verify"]}"#;
1335
1336 const JS_EDDSA_TOKEN: &str = "eyJhbGciOiJFZERTQSIsInR5cCI6IkpXVCIsImtpZCI6ImpzLWVkZHNhLWtleSJ9.eyJyb290Ijoic3RyZWFtIiwicHV0IjpbInZpZGVvIl0sImlhdCI6MTc3NTE3Njc1Nn0.l9rUMHjPSXWKSXRP3mmeMgTAywtqpdqQehhViWaPrKxax1Y2D9KRIYTixYz-b6PI-AoHQYusHWeeLu_HRw2cAg";
1338
1339 #[test]
1340 fn test_js_hs256_key_load() {
1341 let key = Key::from_str(JS_HS256_KEY).unwrap();
1342 assert_eq!(key.algorithm, Algorithm::HS256);
1343 assert_eq!(key.kid, Some(crate::KeyId::decode("js-test-key").unwrap()));
1344 }
1345
1346 #[test]
1347 fn test_js_hs256_token_verify() {
1348 let key = Key::from_str(JS_HS256_KEY).unwrap();
1349 let claims = key.decode(JS_HS256_TOKEN).unwrap();
1350 assert_eq!(claims.root, "live");
1351 assert_eq!(claims.publish, vec!["camera1"]);
1352 assert_eq!(claims.subscribe, vec!["camera1", "camera2"]);
1353 }
1354
1355 #[test]
1356 fn test_js_hs256_sign_and_roundtrip() {
1357 let key = Key::from_str(JS_HS256_KEY).unwrap();
1358 let claims = Claims {
1359 root: "rust-test".to_string(),
1360 publish: vec!["pub1".into()],
1361 subscribe: vec!["sub1".into()],
1362 ..Default::default()
1363 };
1364 let token = key.encode(&claims).unwrap();
1365 let verified = key.decode(&token).unwrap();
1366 assert_eq!(verified.root, "rust-test");
1367 assert_eq!(verified.publish, vec!["pub1"]);
1368 }
1369
1370 #[test]
1371 fn test_js_eddsa_key_load() {
1372 let private_key = Key::from_str(JS_EDDSA_PRIVATE_KEY).unwrap();
1373 assert_eq!(private_key.algorithm, Algorithm::EdDSA);
1374 assert!(matches!(private_key.key, KeyType::OKP { .. }));
1375
1376 let public_key = Key::from_str(JS_EDDSA_PUBLIC_KEY).unwrap();
1377 assert_eq!(public_key.algorithm, Algorithm::EdDSA);
1378 }
1379
1380 #[test]
1381 fn test_js_eddsa_token_verify_with_private_key() {
1382 let key = Key::from_str(JS_EDDSA_PRIVATE_KEY).unwrap();
1383 let claims = key.decode(JS_EDDSA_TOKEN).unwrap();
1384 assert_eq!(claims.root, "stream");
1385 assert_eq!(claims.publish, vec!["video"]);
1386 }
1387
1388 #[test]
1389 fn test_js_eddsa_token_verify_with_public_key() {
1390 let key = Key::from_str(JS_EDDSA_PUBLIC_KEY).unwrap();
1391 let claims = key.decode(JS_EDDSA_TOKEN).unwrap();
1392 assert_eq!(claims.root, "stream");
1393 assert_eq!(claims.publish, vec!["video"]);
1394 }
1395
1396 #[test]
1397 fn test_js_token_wrong_key_fails() {
1398 let wrong_key = Key::generate(Algorithm::HS256, None).unwrap();
1400 let result = wrong_key.decode(JS_HS256_TOKEN);
1401 assert!(result.is_err());
1402 }
1403
1404 #[test]
1405 fn test_js_eddsa_token_wrong_key_fails() {
1406 let wrong_key = Key::from_str(JS_HS256_KEY).unwrap();
1408 let result = wrong_key.decode(JS_EDDSA_TOKEN);
1409 assert!(result.is_err());
1410 }
1411
1412 #[test]
1413 fn test_file_io_base64url() {
1414 let key = create_test_key();
1415 let temp_dir = std::env::temp_dir();
1416 let temp_path = temp_dir.join("test_jwk.key");
1417
1418 key.to_file_base64url(&temp_path).unwrap();
1420
1421 let contents = std::fs::read_to_string(&temp_path).unwrap();
1423
1424 assert!(!contents.contains('{'));
1426 assert!(!contents.contains('}'));
1427 assert!(!contents.contains('"'));
1428
1429 let decoded = base64::engine::general_purpose::URL_SAFE_NO_PAD
1431 .decode(&contents)
1432 .unwrap();
1433 let json_str = String::from_utf8(decoded).unwrap();
1434 let _: serde_json::Value = serde_json::from_str(&json_str).unwrap();
1435
1436 let loaded_key = Key::from_file(&temp_path).unwrap();
1438 assert_eq!(loaded_key.algorithm, key.algorithm);
1439 assert_eq!(loaded_key.operations, key.operations);
1440 assert_eq!(loaded_key.kid, key.kid);
1441
1442 if let (
1443 KeyType::OCT {
1444 secret: original_secret,
1445 },
1446 KeyType::OCT { secret: loaded_secret },
1447 ) = (&key.key, &loaded_key.key)
1448 {
1449 assert_eq!(loaded_secret, original_secret);
1450 } else {
1451 panic!("Expected both keys to be OCT variant");
1452 }
1453
1454 std::fs::remove_file(temp_path).ok();
1456 }
1457}