Skip to content

Commit

Permalink
Enable @path syntax (#9)
Browse files Browse the repository at this point in the history
* Enable -S @./path_to_key syntax

This makes it possible to use jwt-cli for SHA256 (and other SHA
algorithms) by passing references to .der files

E.g.
MY_JWT=$(jwt encode -A RS256 -S @./private_key.der '{"field":"value"}')
jwt decode -A RS256 -S @./public_key.der $MY_JWT

will now work

* add tests, and update help text

* commas
  • Loading branch information
hughsimpson authored and mike-engel committed Jan 10, 2019
1 parent 407e918 commit 2dae4b8
Show file tree
Hide file tree
Showing 4 changed files with 56 additions and 6 deletions.
Binary file added private_key.der
Binary file not shown.
Binary file added public_key.der
Binary file not shown.
29 changes: 23 additions & 6 deletions src/main.rs
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,7 @@ use jwt::errors::{ErrorKind, Result as JWTResult};
use jwt::{dangerous_unsafe_decode, decode, encode, Algorithm, Header, TokenData, Validation};
use serde_json::{from_str, to_string_pretty, Value};
use std::collections::BTreeMap;
use std::fs;
use std::process::exit;
use term_painter::Attr::*;
use term_painter::Color::*;
Expand Down Expand Up @@ -132,7 +133,7 @@ impl TokenOutput {

fn config_options<'a, 'b>() -> App<'a, 'b> {
App::new("jwt")
.about("Encode and decode JWTs from the command line")
.about("Encode and decode JWTs from the command line. RSA encryption currently only supports keys in DER format")
.version(crate_version!())
.author(crate_authors!())
.subcommand(
Expand Down Expand Up @@ -215,7 +216,7 @@ fn config_options<'a, 'b>() -> App<'a, 'b> {
.validator(is_num),
).arg(
Arg::with_name("secret")
.help("the secret to sign the JWT with")
.help("the secret to sign the JWT with. Can be prefixed with @ to read from a binary file")
.takes_value(true)
.long("secret")
.short("S")
Expand All @@ -239,7 +240,7 @@ fn config_options<'a, 'b>() -> App<'a, 'b> {
.default_value("HS256"),
).arg(
Arg::with_name("secret")
.help("the secret to sign the JWT with")
.help("the secret to validate the JWT with. Can be prefixed with @ to read from a binary file")
.takes_value(true)
.long("secret")
.short("S")
Expand Down Expand Up @@ -306,6 +307,22 @@ fn create_validations(alg: Algorithm) -> Validation {
}
}

fn slurp_file(file_name: &str) -> Vec<u8> {
return fs::read(file_name).expect(&format!("Unable to read file {}", file_name));
}

fn bytes_from_secret_string(secret_string: &str) -> Vec<u8> {
let secret: Vec<u8>;
if secret_string.is_empty() { secret = Vec::new() }
else {
match secret_string.chars().next().unwrap() {
'@' => secret = slurp_file(&secret_string.chars().skip(1).collect::<String>()),
_ => secret = secret_string.bytes().into_iter().collect::<Vec<_>>(),
}
}
return secret;
}

fn encode_token(matches: &ArgMatches) -> JWTResult<String> {
let algorithm = translate_algorithm(SupportedAlgorithms::from_string(
matches.value_of("algorithm").unwrap(),
Expand Down Expand Up @@ -353,9 +370,9 @@ fn encode_token(matches: &ArgMatches) -> JWTResult<String> {
.map(|p| p.unwrap())
.collect();
let Payload(claims) = Payload::from_payloads(payloads);
let secret = matches.value_of("secret").unwrap().as_bytes();
let secret = bytes_from_secret_string(matches.value_of("secret").unwrap());

encode(&header, &claims, secret.as_ref())
encode(&header, &claims, &secret)
}

fn decode_token(
Expand All @@ -368,7 +385,7 @@ fn decode_token(
let algorithm = translate_algorithm(SupportedAlgorithms::from_string(
matches.value_of("algorithm").unwrap(),
));
let secret = matches.value_of("secret").unwrap().as_bytes();
let secret = bytes_from_secret_string(matches.value_of("secret").unwrap());
let jwt = matches.value_of("jwt").unwrap().to_string();
let secret_validator = create_validations(algorithm);

Expand Down
33 changes: 33 additions & 0 deletions tests/jwt-cli.rs
Original file line number Diff line number Diff line change
Expand Up @@ -393,4 +393,37 @@ mod tests {

assert!(result.is_ok());
}

#[test]
fn encodes_and_decodes_a_token_using_key_from_file() {
let body: String = "{\"field\":\"value\"}".to_string();
let encode_matcher = config_options()
.get_matches_from_safe(vec![
"jwt",
"encode",
"-A",
"RS256",
"-S",
"@./private_key.der",
&body,
])
.unwrap();
let encode_matches = encode_matcher.subcommand_matches("encode").unwrap();
let encoded_token = encode_token(&encode_matches).unwrap();
let decode_matcher = config_options()
.get_matches_from_safe(vec![
"jwt",
"decode",
"-S",
"@./public_key.der",
"-A",
"RS256",
&encoded_token,
])
.unwrap();
let decode_matches = decode_matcher.subcommand_matches("decode").unwrap();
let (result, _, _) = decode_token(&decode_matches);

assert!(result.is_ok());
}
}

0 comments on commit 2dae4b8

Please sign in to comment.