uselesskey_core_jwk_builder/
lib.rs1#![forbid(unsafe_code)]
2
3use uselesskey_core_jwk_shape::{AnyJwk, Jwks, PrivateJwk, PublicJwk};
10use uselesskey_core_jwks_order::{HasKid, KidSorted};
11
12#[derive(Clone, Default)]
17pub struct JwksBuilder {
18 entries: KidSorted<OrderedJwk>,
19}
20
21#[derive(Clone)]
22struct OrderedJwk(AnyJwk);
23
24impl HasKid for OrderedJwk {
25 fn kid(&self) -> &str {
26 self.0.kid()
27 }
28}
29
30impl JwksBuilder {
31 pub fn new() -> Self {
33 Self::default()
34 }
35
36 pub fn add_public(mut self, jwk: PublicJwk) -> Self {
38 self.push_public(jwk);
39 self
40 }
41
42 pub fn add_private(mut self, jwk: PrivateJwk) -> Self {
44 self.push_private(jwk);
45 self
46 }
47
48 pub fn add_any(mut self, jwk: AnyJwk) -> Self {
50 self.push_any(jwk);
51 self
52 }
53
54 pub fn push_public(&mut self, jwk: PublicJwk) -> &mut Self {
56 self.push_any(AnyJwk::from(jwk))
57 }
58
59 pub fn push_private(&mut self, jwk: PrivateJwk) -> &mut Self {
61 self.push_any(AnyJwk::from(jwk))
62 }
63
64 pub fn push_any(&mut self, jwk: AnyJwk) -> &mut Self {
66 self.entries.push(OrderedJwk(jwk));
67 self
68 }
69
70 pub fn build(self) -> Jwks {
72 Jwks {
73 keys: self.entries.build().into_iter().map(|jwk| jwk.0).collect(),
74 }
75 }
76}
77
78#[cfg(test)]
79mod tests {
80 use super::*;
81
82 fn sample_rsa_public(kid: &str, n: &str) -> PublicJwk {
83 PublicJwk::Rsa(uselesskey_core_jwk_shape::RsaPublicJwk {
84 kty: "RSA",
85 use_: "sig",
86 alg: "RS256",
87 kid: kid.to_string(),
88 n: n.to_string(),
89 e: "AQAB".to_string(),
90 })
91 }
92
93 fn sample_oct_private(kid: &str, k: &str) -> PrivateJwk {
94 PrivateJwk::Oct(uselesskey_core_jwk_shape::OctJwk {
95 kty: "oct",
96 use_: "sig",
97 alg: "HS256",
98 kid: kid.to_string(),
99 k: k.to_string(),
100 })
101 }
102
103 #[test]
104 fn jwks_builder_orders_by_kid() {
105 let jwk1 = PublicJwk::Rsa(uselesskey_core_jwk_shape::RsaPublicJwk {
106 kty: "RSA",
107 use_: "sig",
108 alg: "RS256",
109 kid: "b".to_string(),
110 n: "n".to_string(),
111 e: "e".to_string(),
112 });
113 let jwk2 = PublicJwk::Ec(uselesskey_core_jwk_shape::EcPublicJwk {
114 kty: "EC",
115 use_: "sig",
116 alg: "ES256",
117 crv: "P-256",
118 kid: "a".to_string(),
119 x: "x".to_string(),
120 y: "y".to_string(),
121 });
122
123 let jwks = JwksBuilder::new().add_public(jwk1).add_public(jwk2).build();
124
125 assert_eq!(jwks.keys.len(), 2);
126 assert_eq!(jwks.keys[0].kid(), "a");
127 assert_eq!(jwks.keys[1].kid(), "b");
128 }
129
130 #[test]
131 fn jwks_builder_stable_for_same_kid() {
132 let jwk1 = PublicJwk::Rsa(uselesskey_core_jwk_shape::RsaPublicJwk {
133 kty: "RSA",
134 use_: "sig",
135 alg: "RS256",
136 kid: "same".to_string(),
137 n: "n1".to_string(),
138 e: "e1".to_string(),
139 });
140 let jwk2 = PublicJwk::Rsa(uselesskey_core_jwk_shape::RsaPublicJwk {
141 kty: "RSA",
142 use_: "sig",
143 alg: "RS256",
144 kid: "same".to_string(),
145 n: "n2".to_string(),
146 e: "e2".to_string(),
147 });
148
149 let jwks = JwksBuilder::new().add_public(jwk1).add_public(jwk2).build();
150
151 assert_eq!(jwks.keys[0].kid(), "same");
152 assert_eq!(jwks.keys[1].kid(), "same");
153 let first = jwks.keys[0].to_value();
154 let second = jwks.keys[1].to_value();
155 assert_eq!(first["n"], "n1");
156 assert_eq!(second["n"], "n2");
157 }
158
159 #[test]
160 fn jwks_builder_push_methods_and_display() {
161 let jwk_pub = sample_rsa_public("kid-b", "nb");
162 let jwk_priv = sample_oct_private("kid-a", "ka");
163
164 let mut builder = JwksBuilder::new();
165 builder.push_public(jwk_pub.clone());
166 builder.push_private(jwk_priv.clone());
167 builder.push_any(AnyJwk::from(jwk_pub.clone()));
168
169 let jwks = builder.build();
170 let json = jwks.to_string();
171 let v: serde_json::Value = serde_json::from_str(&json).expect("valid JSON");
172
173 let keys = v["keys"].as_array().expect("keys array");
174 assert_eq!(keys.len(), 3);
175 assert_eq!(jwks.keys.len(), 3);
176 }
177
178 #[test]
179 fn jwks_builder_add_methods_work() {
180 let jwk_priv = sample_oct_private("kid-a", "ka");
181 let jwk_any = AnyJwk::from(sample_rsa_public("kid-b", "nb"));
182
183 let jwks = JwksBuilder::new()
184 .add_private(jwk_priv)
185 .add_any(jwk_any)
186 .build();
187
188 assert_eq!(jwks.keys.len(), 2);
189 }
190}