Skip to content

Commit 674d389

Browse files
committed
feat: Improved error messages/warnings
New: If no secret/publicKey is provided by the user, no signature check is performed. Rather then silently skipping the signature check, this commit introduces a warning in this case. New: If the `exp` claim is not set and the token validation check is skipped, a warning is shown. New: After a successful signature validation a success message is shown. Changed: The `InvalidAlgorithm` error message now shows the selected algorithm and the algorithm specified in the JWT header. New: If no signature validation is performed, the return code is now `2`. All tests have been updated accordingly.
1 parent be2faca commit 674d389

File tree

2 files changed

+67
-49
lines changed

2 files changed

+67
-49
lines changed

src/main.rs

Lines changed: 30 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -476,7 +476,7 @@ fn encode_token(matches: &ArgMatches) -> JWTResult<String> {
476476
fn decode_token(
477477
matches: &ArgMatches,
478478
) -> (
479-
JWTResult<TokenData<Payload>>,
479+
Option<JWTResult<TokenData<Payload>>>,
480480
JWTResult<TokenData<Payload>>,
481481
OutputFormat,
482482
) {
@@ -523,8 +523,12 @@ fn decode_token(
523523

524524
(
525525
match secret {
526-
Some(secret_key) => decode::<Payload>(&jwt, &secret_key.unwrap(), &secret_validator),
527-
None => dangerous_insecure_decode::<Payload>(&jwt),
526+
Some(secret_key) => Some(decode::<Payload>(
527+
&jwt,
528+
&secret_key.unwrap(),
529+
&secret_validator,
530+
)),
531+
None => None, // unable to safely decode token => validated_token is set to None
528532
},
529533
token_data,
530534
if matches.is_present("json") {
@@ -554,12 +558,13 @@ fn print_encoded_token(token: JWTResult<String>) {
554558
}
555559

556560
fn print_decoded_token(
557-
validated_token: JWTResult<TokenData<Payload>>,
561+
validated_token: Option<JWTResult<TokenData<Payload>>>,
558562
token_data: JWTResult<TokenData<Payload>>,
563+
options_algorithm: Algorithm,
559564
format: OutputFormat,
560565
) {
561-
if let Err(err) = &validated_token {
562-
match err.kind() {
566+
match validated_token {
567+
Some(Err(ref err)) => match err.kind() {
563568
ErrorKind::InvalidToken => {
564569
bunt::println!("{$red+bold}The JWT provided is invalid{/$}")
565570
}
@@ -587,15 +592,20 @@ fn print_decoded_token(
587592
ErrorKind::ImmatureSignature => bunt::eprintln!(
588593
"{$red+bold}The `nbf` claim is in the future which isn't allowed{/$}"
589594
),
590-
ErrorKind::InvalidAlgorithm => bunt::eprintln!(
591-
"{$red+bold}The JWT provided has a different signing algorithm than the one you \
592-
provided{/$}",
593-
),
595+
ErrorKind::InvalidAlgorithm => {
596+
let jwt_algorithm = match token_data {
597+
Ok(ref token) => token.header.alg,
598+
Err(_) => panic!("Error: Invalid token data."),
599+
};
600+
bunt::eprintln!("{$red+bold}Error: Invalid Signature! The JWT provided has a different signing algorithm ({:?}) than the one selected for validation ({:?}){/$}",jwt_algorithm, options_algorithm)
601+
}
594602
_ => bunt::eprintln!(
595-
"{$red+bold}The JWT provided is invalid because{/$} {:?}",
603+
"{$red+bold}The JWT provided is invalid because {:?}{/$}",
596604
err
597605
),
598-
};
606+
},
607+
Some(Ok(_)) => bunt::eprintln!("{$green+bold}Success! JWT signature is valid!{/$}"),
608+
None => bunt::eprintln!("{$red+bold}Warning! JWT signature has not been validated!{/$}"),
599609
}
600610

601611
match (format, token_data) {
@@ -612,8 +622,9 @@ fn print_decoded_token(
612622
}
613623

614624
exit(match validated_token {
615-
Err(_) => 1,
616-
Ok(_) => 0,
625+
Some(Ok(_)) => 0, // successful signature check
626+
Some(Err(_)) => 1, // token validation error
627+
None => 2, // no signature check performed
617628
})
618629
}
619630

@@ -631,7 +642,11 @@ fn main() {
631642
("decode", Some(decode_matches)) => {
632643
let (validated_token, token_data, format) = decode_token(decode_matches);
633644

634-
print_decoded_token(validated_token, token_data, format);
645+
let options_algorithm = translate_algorithm(SupportedAlgorithms::from_string(
646+
decode_matches.value_of("algorithm").unwrap(),
647+
));
648+
649+
print_decoded_token(validated_token, token_data, options_algorithm, format);
635650
}
636651
_ => (),
637652
}

tests/jwt-cli.rs

Lines changed: 37 additions & 34 deletions
Original file line numberDiff line numberDiff line change
@@ -252,9 +252,9 @@ mod tests {
252252
let decode_matches = decode_matcher.subcommand_matches("decode").unwrap();
253253
let (decoded_token, _, _) = decode_token(&decode_matches);
254254

255-
assert!(decoded_token.is_ok());
255+
assert!(decoded_token.as_ref().unwrap().is_ok());
256256

257-
let TokenData { claims, header } = decoded_token.unwrap();
257+
let TokenData { claims, header } = decoded_token.unwrap().unwrap();
258258

259259
assert_eq!(header.alg, Algorithm::HS256);
260260
assert_eq!(header.kid, Some("1234".to_string()));
@@ -286,9 +286,9 @@ mod tests {
286286
let decode_matches = decode_matcher.subcommand_matches("decode").unwrap();
287287
let (decoded_token, _, _) = decode_token(&decode_matches);
288288

289-
assert!(decoded_token.is_ok());
289+
assert!(decoded_token.as_ref().unwrap().is_ok());
290290

291-
let TokenData { claims, header: _ } = decoded_token.unwrap();
291+
let TokenData { claims, header: _ } = decoded_token.unwrap().unwrap();
292292
let iat = from_value::<i64>(claims.0["iat"].clone());
293293

294294
assert!(iat.is_ok());
@@ -308,7 +308,7 @@ mod tests {
308308
let decode_matches = decode_matcher.subcommand_matches("decode").unwrap();
309309
let (decoded_token, token_data, _) = decode_token(&decode_matches);
310310

311-
assert!(decoded_token.is_err());
311+
assert!(decoded_token.as_ref().unwrap().is_err());
312312

313313
let TokenData { claims, header: _ } = token_data.unwrap();
314314

@@ -328,9 +328,9 @@ mod tests {
328328
let decode_matches = decode_matcher.subcommand_matches("decode").unwrap();
329329
let (decoded_token, _, _) = decode_token(&decode_matches);
330330

331-
assert!(decoded_token.is_ok());
331+
assert!(decoded_token.as_ref().unwrap().is_ok());
332332

333-
let TokenData { claims, header: _ } = decoded_token.unwrap();
333+
let TokenData { claims, header: _ } = decoded_token.unwrap().unwrap();
334334
let exp = from_value::<i64>(claims.0["exp"].clone());
335335

336336
assert!(exp.is_ok());
@@ -357,9 +357,9 @@ mod tests {
357357
let decode_matches = decode_matcher.subcommand_matches("decode").unwrap();
358358
let (decoded_token, _, _) = decode_token(&decode_matches);
359359

360-
assert!(decoded_token.is_ok());
360+
assert!(decoded_token.as_ref().unwrap().is_ok());
361361

362-
let TokenData { claims, header: _ } = decoded_token.unwrap();
362+
let TokenData { claims, header: _ } = decoded_token.unwrap().unwrap();
363363

364364
assert!(claims.0.get("iat").is_none());
365365
}
@@ -385,9 +385,9 @@ mod tests {
385385
let decode_matches = decode_matcher.subcommand_matches("decode").unwrap();
386386
let (decoded_token, _, _) = decode_token(&decode_matches);
387387

388-
assert!(decoded_token.is_ok());
388+
assert!(decoded_token.as_ref().unwrap().is_ok());
389389

390-
let TokenData { claims, header: _ } = decoded_token.unwrap();
390+
let TokenData { claims, header: _ } = decoded_token.unwrap().unwrap();
391391
let exp_claim = from_value::<i64>(claims.0["exp"].clone());
392392

393393
assert!(exp_claim.is_ok());
@@ -407,7 +407,7 @@ mod tests {
407407
let decode_matches = decode_matcher.subcommand_matches("decode").unwrap();
408408
let (decoded_token, _, _) = decode_token(&decode_matches);
409409

410-
assert!(decoded_token.is_err());
410+
assert!(decoded_token.as_ref().unwrap().is_err());
411411
}
412412

413413
#[test]
@@ -430,7 +430,7 @@ mod tests {
430430
let decode_matches = decode_matcher.subcommand_matches("decode").unwrap();
431431
let (decoded_token, _, _) = decode_token(&decode_matches);
432432

433-
assert!(decoded_token.is_ok());
433+
assert!(decoded_token.as_ref().unwrap().is_ok());
434434
}
435435

436436
#[test]
@@ -453,9 +453,9 @@ mod tests {
453453
let decode_matches = decode_matcher.subcommand_matches("decode").unwrap();
454454
let (decoded_token, _, _) = decode_token(&decode_matches);
455455

456-
assert!(decoded_token.is_ok());
456+
assert!(decoded_token.as_ref().unwrap().is_ok());
457457

458-
let TokenData { claims, header: _ } = decoded_token.unwrap();
458+
let TokenData { claims, header: _ } = decoded_token.unwrap().unwrap();
459459
let exp_claim = from_value::<i64>(claims.0["exp"].clone());
460460
let iat_claim = from_value::<i64>(claims.0["iat"].clone());
461461

@@ -489,9 +489,9 @@ mod tests {
489489
let decode_matches = decode_matcher.subcommand_matches("decode").unwrap();
490490
let (decoded_token, _, _) = decode_token(&decode_matches);
491491

492-
assert!(decoded_token.is_ok());
492+
assert!(decoded_token.as_ref().unwrap().is_ok());
493493

494-
let TokenData { claims, header: _ } = decoded_token.unwrap();
494+
let TokenData { claims, header: _ } = decoded_token.unwrap().unwrap();
495495
let nbf_claim = from_value::<i64>(claims.0["nbf"].clone());
496496
let iat_claim = from_value::<i64>(claims.0["iat"].clone());
497497

@@ -520,7 +520,7 @@ mod tests {
520520
let decode_matches = matches.subcommand_matches("decode").unwrap();
521521
let (result, _, _) = decode_token(&decode_matches);
522522

523-
assert!(result.is_ok());
523+
assert!(result.unwrap().is_ok());
524524
}
525525

526526
#[test]
@@ -534,9 +534,10 @@ mod tests {
534534
])
535535
.unwrap();
536536
let decode_matches = matches.subcommand_matches("decode").unwrap();
537-
let (result, _, format) = decode_token(&decode_matches);
537+
let (validated_token, token_data, format) = decode_token(&decode_matches);
538538

539-
assert!(result.is_ok());
539+
assert!(validated_token.is_none()); // no signature validation
540+
assert!(token_data.is_ok());
540541
assert!(format == OutputFormat::Json);
541542
}
542543

@@ -556,7 +557,7 @@ mod tests {
556557
let decode_matches = matches.subcommand_matches("decode").unwrap();
557558
let (result, _, _) = decode_token(&decode_matches);
558559

559-
assert!(result.is_err());
560+
assert!(result.unwrap().is_err());
560561
}
561562

562563
#[test]
@@ -571,9 +572,10 @@ mod tests {
571572
])
572573
.unwrap();
573574
let decode_matches = matches.subcommand_matches("decode").unwrap();
574-
let (result, _, _) = decode_token(&decode_matches);
575+
let (validated_token, token_data, _) = decode_token(&decode_matches);
575576

576-
assert!(result.is_ok());
577+
assert!(validated_token.is_none()); // no signature validation
578+
assert!(token_data.is_ok());
577579
}
578580

579581
#[test]
@@ -586,9 +588,10 @@ mod tests {
586588
])
587589
.unwrap();
588590
let decode_matches = matches.subcommand_matches("decode").unwrap();
589-
let (result, _, _) = decode_token(&decode_matches);
591+
let (validated_token, token_data, _) = decode_token(&decode_matches);
590592

591-
assert!(result.is_ok());
593+
assert!(validated_token.is_none()); // no signature validation
594+
assert!(token_data.is_ok());
592595
}
593596

594597
#[test]
@@ -601,9 +604,10 @@ mod tests {
601604
])
602605
.unwrap();
603606
let decode_matches = matches.subcommand_matches("decode").unwrap();
604-
let (result, _, _) = decode_token(&decode_matches);
607+
let (validated_token, token_data, _) = decode_token(&decode_matches);
605608

606-
assert!(result.is_ok());
609+
assert!(validated_token.is_none()); // no signature validation
610+
assert!(token_data.is_ok());
607611
}
608612

609613
#[test]
@@ -616,9 +620,10 @@ mod tests {
616620
])
617621
.unwrap();
618622
let decode_matches = matches.subcommand_matches("decode").unwrap();
619-
let (result, _, _) = decode_token(&decode_matches);
623+
let (validated_token, token_data, _) = decode_token(&decode_matches);
620624

621-
assert!(result.is_ok());
625+
assert!(validated_token.is_none()); // no signature validation
626+
assert!(token_data.is_ok());
622627
}
623628

624629
#[test]
@@ -652,7 +657,7 @@ mod tests {
652657
let decode_matches = decode_matcher.subcommand_matches("decode").unwrap();
653658
let (result, _, _) = decode_token(&decode_matches);
654659

655-
assert!(result.is_ok());
660+
assert!(result.unwrap().is_ok());
656661
}
657662

658663
#[test]
@@ -755,9 +760,7 @@ mod tests {
755760
let decode_matches = decode_matcher.subcommand_matches("decode").unwrap();
756761
let (result, _, _) = decode_token(&decode_matches);
757762

758-
dbg!(&result);
759-
760-
assert!(result.is_ok());
763+
assert!(result.unwrap().is_ok());
761764
}
762765

763766
#[test]
@@ -791,7 +794,7 @@ mod tests {
791794
let decode_matches = decode_matcher.subcommand_matches("decode").unwrap();
792795
let (decoded_token, token_data, _) = decode_token(&decode_matches);
793796

794-
assert!(decoded_token.is_ok());
797+
assert!(decoded_token.as_ref().unwrap().is_ok());
795798

796799
let TokenData { claims, header: _ } = token_data.unwrap();
797800

0 commit comments

Comments
 (0)