rust_license_key/
parser.rs1use base64::engine::general_purpose::STANDARD as BASE64_STANDARD;
12use base64::Engine;
13
14use crate::crypto::PublicKey;
15use crate::error::{LicenseError, Result};
16use crate::models::{
17 LicensePayload, SignedLicense, MAX_SUPPORTED_LICENSE_VERSION, MIN_SUPPORTED_LICENSE_VERSION,
18};
19
20#[derive(Debug, Clone)]
49pub struct LicenseParser {
50 public_key: PublicKey,
52}
53
54impl LicenseParser {
55 pub fn new(public_key: PublicKey) -> Self {
61 Self { public_key }
62 }
63
64 pub fn from_public_key_base64(public_key_base64: &str) -> Result<Self> {
74 let public_key = PublicKey::from_base64(public_key_base64)?;
75 Ok(Self::new(public_key))
76 }
77
78 pub fn parse_json(&self, json: &str) -> Result<LicensePayload> {
102 let signed_license = SignedLicense::from_json(json).map_err(|e| {
104 LicenseError::JsonDeserializationFailed {
105 reason: e.to_string(),
106 }
107 })?;
108
109 self.parse_signed_license(&signed_license)
110 }
111
112 pub fn parse_signed_license(&self, signed_license: &SignedLicense) -> Result<LicensePayload> {
125 self.public_key
128 .verify_base64(
129 signed_license.encoded_payload.as_bytes(),
130 &signed_license.encoded_signature,
131 )
132 .map_err(|_| LicenseError::InvalidSignature)?;
133
134 let payload_bytes = BASE64_STANDARD
136 .decode(&signed_license.encoded_payload)
137 .map_err(|e| LicenseError::Base64DecodingFailed {
138 reason: e.to_string(),
139 })?;
140
141 let payload: LicensePayload = serde_json::from_slice(&payload_bytes).map_err(|e| {
143 LicenseError::JsonDeserializationFailed {
144 reason: e.to_string(),
145 }
146 })?;
147
148 if payload.format_version < MIN_SUPPORTED_LICENSE_VERSION {
150 return Err(LicenseError::UnsupportedLicenseVersion {
151 found: payload.format_version,
152 supported: format!(
153 "{} to {}",
154 MIN_SUPPORTED_LICENSE_VERSION, MAX_SUPPORTED_LICENSE_VERSION
155 ),
156 });
157 }
158
159 if payload.format_version > MAX_SUPPORTED_LICENSE_VERSION {
160 return Err(LicenseError::UnsupportedLicenseVersion {
161 found: payload.format_version,
162 supported: format!(
163 "{} to {}",
164 MIN_SUPPORTED_LICENSE_VERSION, MAX_SUPPORTED_LICENSE_VERSION
165 ),
166 });
167 }
168
169 Ok(payload)
170 }
171
172 pub fn decode_unverified(&self, json: &str) -> Result<(LicensePayload, bool)> {
188 let signed_license = SignedLicense::from_json(json).map_err(|e| {
190 LicenseError::JsonDeserializationFailed {
191 reason: e.to_string(),
192 }
193 })?;
194
195 let signature_valid = self
197 .public_key
198 .verify_base64(
199 signed_license.encoded_payload.as_bytes(),
200 &signed_license.encoded_signature,
201 )
202 .is_ok();
203
204 let payload_bytes = BASE64_STANDARD
206 .decode(&signed_license.encoded_payload)
207 .map_err(|e| LicenseError::Base64DecodingFailed {
208 reason: e.to_string(),
209 })?;
210
211 let payload: LicensePayload = serde_json::from_slice(&payload_bytes).map_err(|e| {
212 LicenseError::JsonDeserializationFailed {
213 reason: e.to_string(),
214 }
215 })?;
216
217 Ok((payload, signature_valid))
218 }
219
220 pub fn public_key(&self) -> &PublicKey {
222 &self.public_key
223 }
224}
225
226pub fn parse_license(license_json: &str, public_key_base64: &str) -> Result<LicensePayload> {
244 let parser = LicenseParser::from_public_key_base64(public_key_base64)?;
245 parser.parse_json(license_json)
246}
247
248pub fn extract_payload_unverified(license_json: &str) -> Result<String> {
262 let signed_license = SignedLicense::from_json(license_json).map_err(|e| {
263 LicenseError::JsonDeserializationFailed {
264 reason: e.to_string(),
265 }
266 })?;
267
268 let payload_bytes = BASE64_STANDARD
269 .decode(&signed_license.encoded_payload)
270 .map_err(|e| LicenseError::Base64DecodingFailed {
271 reason: e.to_string(),
272 })?;
273
274 String::from_utf8(payload_bytes).map_err(|e| LicenseError::InvalidLicenseFormat {
275 reason: format!("payload is not valid UTF-8: {}", e),
276 })
277}
278
279#[cfg(test)]
280mod tests {
281 use super::*;
282 use crate::builder::LicenseBuilder;
283 use crate::crypto::KeyPair;
284 use chrono::Duration;
285
286 fn create_test_license(key_pair: &KeyPair) -> String {
287 LicenseBuilder::new()
288 .license_id("TEST-LIC-001")
289 .customer_id("TEST-CUST-001")
290 .customer_name("Test Customer")
291 .expires_in(Duration::days(30))
292 .allowed_feature("premium")
293 .build_and_sign_to_json(key_pair)
294 .expect("Should create test license")
295 }
296
297 #[test]
298 fn test_parse_valid_license() {
299 let key_pair = KeyPair::generate().expect("Key generation should succeed");
300 let license_json = create_test_license(&key_pair);
301
302 let parser = LicenseParser::new(key_pair.public_key());
303 let payload = parser
304 .parse_json(&license_json)
305 .expect("Should parse license");
306
307 assert_eq!(payload.license_id, "TEST-LIC-001");
308 assert_eq!(payload.customer_id, "TEST-CUST-001");
309 assert_eq!(payload.customer_name.as_deref(), Some("Test Customer"));
310 }
311
312 #[test]
313 fn test_parse_with_wrong_key_fails() {
314 let key_pair_1 = KeyPair::generate().expect("Key generation should succeed");
315 let key_pair_2 = KeyPair::generate().expect("Key generation should succeed");
316
317 let license_json = create_test_license(&key_pair_1);
319
320 let parser = LicenseParser::new(key_pair_2.public_key());
322 let result = parser.parse_json(&license_json);
323
324 assert!(result.is_err());
325 assert!(matches!(
326 result.unwrap_err(),
327 LicenseError::InvalidSignature
328 ));
329 }
330
331 #[test]
332 fn test_parse_tampered_license_fails() {
333 let key_pair = KeyPair::generate().expect("Key generation should succeed");
334 let license_json = create_test_license(&key_pair);
335
336 let mut signed: SignedLicense = serde_json::from_str(&license_json).expect("Should parse");
338
339 let mut chars: Vec<char> = signed.encoded_payload.chars().collect();
341 if let Some(c) = chars.get_mut(10) {
342 *c = if *c == 'A' { 'B' } else { 'A' };
343 }
344 signed.encoded_payload = chars.into_iter().collect();
345
346 let tampered_json = serde_json::to_string(&signed).expect("Should serialize");
348
349 let parser = LicenseParser::new(key_pair.public_key());
351 let result = parser.parse_json(&tampered_json);
352
353 assert!(result.is_err());
354 }
355
356 #[test]
357 fn test_parse_invalid_json() {
358 let key_pair = KeyPair::generate().expect("Key generation should succeed");
359 let parser = LicenseParser::new(key_pair.public_key());
360
361 let result = parser.parse_json("not valid json");
362 assert!(matches!(
363 result.unwrap_err(),
364 LicenseError::JsonDeserializationFailed { .. }
365 ));
366 }
367
368 #[test]
369 fn test_decode_unverified() {
370 let key_pair = KeyPair::generate().expect("Key generation should succeed");
371 let license_json = create_test_license(&key_pair);
372
373 let parser = LicenseParser::new(key_pair.public_key());
374 let (payload, signature_valid) = parser
375 .decode_unverified(&license_json)
376 .expect("Should decode");
377
378 assert!(signature_valid);
379 assert_eq!(payload.license_id, "TEST-LIC-001");
380 }
381
382 #[test]
383 fn test_decode_unverified_with_wrong_key() {
384 let key_pair_1 = KeyPair::generate().expect("Key generation should succeed");
385 let key_pair_2 = KeyPair::generate().expect("Key generation should succeed");
386
387 let license_json = create_test_license(&key_pair_1);
388
389 let parser = LicenseParser::new(key_pair_2.public_key());
390 let (payload, signature_valid) = parser
391 .decode_unverified(&license_json)
392 .expect("Should decode");
393
394 assert!(!signature_valid);
396 assert_eq!(payload.license_id, "TEST-LIC-001");
397 }
398
399 #[test]
400 fn test_extract_payload_unverified() {
401 let key_pair = KeyPair::generate().expect("Key generation should succeed");
402 let license_json = create_test_license(&key_pair);
403
404 let payload_json = extract_payload_unverified(&license_json).expect("Should extract");
405
406 let value: serde_json::Value =
408 serde_json::from_str(&payload_json).expect("Should be valid JSON");
409 assert_eq!(value["id"], "TEST-LIC-001");
410 }
411
412 #[test]
413 fn test_from_public_key_base64() {
414 let key_pair = KeyPair::generate().expect("Key generation should succeed");
415 let public_key_base64 = key_pair.public_key_base64();
416
417 let parser = LicenseParser::from_public_key_base64(&public_key_base64)
418 .expect("Should create parser");
419
420 let license_json = create_test_license(&key_pair);
421 let payload = parser.parse_json(&license_json).expect("Should parse");
422
423 assert_eq!(payload.license_id, "TEST-LIC-001");
424 }
425
426 #[test]
427 fn test_parse_license_convenience_function() {
428 let key_pair = KeyPair::generate().expect("Key generation should succeed");
429 let public_key_base64 = key_pair.public_key_base64();
430 let license_json = create_test_license(&key_pair);
431
432 let payload =
433 parse_license(&license_json, &public_key_base64).expect("Should parse license");
434
435 assert_eq!(payload.license_id, "TEST-LIC-001");
436 }
437}