Skip to content

Commit

Permalink
The 1.0 release!
Browse files Browse the repository at this point in the history
This is the initial non-beta, non-alpha release of jwt-cli!

New features
- Everything is parsed by serde now. You can pass strings, numbers,
arrays, objects, whatever. If serde can parse it, it's valid!

Things left to do
- Add jwt-cli to package managers!
  • Loading branch information
mike-engel committed Jul 4, 2017
1 parent 4bce03c commit 8beede5
Show file tree
Hide file tree
Showing 5 changed files with 63 additions and 37 deletions.
19 changes: 16 additions & 3 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
@@ -1,3 +1,16 @@
# 1.0.0
> 2017-07-03
The 1.0 release!

This is the initial non-beta, non-alpha release of jwt-cli!

#### New features
- Everything is parsed by serde now. You can pass strings, numbers, arrays, objects, whatever. If serde can parse it, it's valid!

#### Things left to do
- Add jwt-cli to package managers!

# 0.9.1
> 2017-07-03
Expand All @@ -7,7 +20,7 @@ The forkless release!
- Swaps out my fork of `jsonwebtoken` for the master branch of keats' `jsonwebtoken`

#### Roadmap to 1.0
- Allow for json payload items via `-P this=json(['arbitrary', 'data'])
- Allow for json payload items via `-P this=json(['arbitrary', 'data'])`

# 0.9.0
> 2017-07-03
Expand All @@ -26,7 +39,7 @@ The `iat` and `exp` release!
- Moves to my instance of `jsonwebtoken` until some PRs are merged

#### Roadmap to 1.0
- Allow for json payload items via `-P this=json(['arbitrary', 'data'])
- Allow for json payload items via `-P this=json(['arbitrary', 'data'])`

# 0.8.1
> 2017-07-02
Expand All @@ -46,7 +59,7 @@ Dependency updates
#### Roadmap to 1.0
- Automatically set `iat` and `exp`
- Default `exp` to 30 minutes from now
- Allow for json payload items via `-P this=json(['arbitrary', 'data'])
- Allow for json payload items via `-P this=json(['arbitrary', 'data'])`

# 0.7.0
> 2017-03-13
Expand Down
2 changes: 1 addition & 1 deletion Cargo.lock

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

8 changes: 2 additions & 6 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -52,14 +52,10 @@ cargo build
cargo build --release
```

If it built successfully, you should be able to run the command from the `target` folder.
If it built successfully, you should be able to run the command via `cargo`.

```sh
# on macOS/linux
./target/debug/jwt help

# on windows
target\debug\jwt.exe help
cargo run -- help
```

# [Code of conduct](code_of_conduct.md)
Expand Down
31 changes: 10 additions & 21 deletions src/main.rs
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,7 @@ use chrono::{Duration, Utc};
use clap::{App, Arg, ArgMatches, SubCommand};
use jwt::{Algorithm, decode, encode, Header, TokenData, Validation};
use jwt::errors::{Error, ErrorKind, Result as JWTResult};
use serde_json::{to_string_pretty, to_value, Value};
use serde_json::{from_str, to_string_pretty, Value};
use std::collections::BTreeMap;
use term_painter::ToStyle;
use term_painter::Color::*;
Expand Down Expand Up @@ -55,26 +55,14 @@ impl PayloadItem {
fn from_string_with_name(val: Option<&str>, name: &str) -> Option<PayloadItem> {
match val {
Some(value) => {
match to_value(value) {
match from_str(value) {
Ok(json_value) => Some(PayloadItem(name.to_string(), json_value)),
_ => None,
}
}
_ => None,
}
}

fn from_int_with_name(val: Option<&str>, name: &str) -> Option<PayloadItem> {
match val {
Some(value) => {
match i64::from_str_radix(&value, 10) {
Ok(int_value) => {
match to_value(int_value) {
Err(_) => {
match from_str(format!("\"{}\"", value).as_str()) {
Ok(json_value) => Some(PayloadItem(name.to_string(), json_value)),
_ => None,
Err(_) => None,
}
}
_ => None,
}
}
_ => None,
Expand All @@ -84,8 +72,9 @@ impl PayloadItem {
fn split_payload_item(p: &str) -> PayloadItem {
let split: Vec<&str> = p.split('=').collect();
let (name, value) = (split[0], split[1]);
let payload_item = PayloadItem::from_string_with_name(Some(value), name);

PayloadItem(name.to_string(), to_value(value).unwrap_or(Value::Null))
payload_item.unwrap()
}
}

Expand Down Expand Up @@ -253,7 +242,7 @@ fn is_num(val: String) -> Result<(), String> {

match parse_result {
Ok(_) => Ok(()),
Err(_) => Err(String::from("expires must be an integer")),
Err(_) => Err(String::from("exp and nbf must be integers")),
}
}

Expand Down Expand Up @@ -312,12 +301,12 @@ fn encode_token(matches: &ArgMatches) -> JWTResult<String> {
.map(|p| PayloadItem::from_string(Some(p)))
.collect()
});
let expires = PayloadItem::from_int_with_name(matches.value_of("expires"), "exp");
let expires = PayloadItem::from_string_with_name(matches.value_of("expires"), "exp");
let issuer = PayloadItem::from_string_with_name(matches.value_of("issuer"), "iss");
let subject = PayloadItem::from_string_with_name(matches.value_of("subject"), "sub");
let audience = PayloadItem::from_string_with_name(matches.value_of("audience"), "aud");
let principal = PayloadItem::from_string_with_name(matches.value_of("principal"), "prn");
let not_before = PayloadItem::from_int_with_name(matches.value_of("not_before"), "nbf");
let not_before = PayloadItem::from_string_with_name(matches.value_of("not_before"), "nbf");
let mut maybe_payloads: Vec<Option<PayloadItem>> = vec![expires, issuer, subject, audience, principal, not_before];

maybe_payloads.append(&mut custom_payloads.unwrap_or(Vec::new()));
Expand Down
40 changes: 34 additions & 6 deletions tests/jwt-cli.rs
Original file line number Diff line number Diff line change
Expand Up @@ -172,7 +172,9 @@ mod tests {

#[test]
fn encodes_a_token() {
let matches = config_options()
let exp = (Utc::now() + Duration::minutes(60)).timestamp();
let nbf = Utc::now().timestamp();
let encode_matcher = config_options()
.get_matches_from_safe(vec![
"jwt",
"encode",
Expand All @@ -183,25 +185,51 @@ mod tests {
"-a",
"yolo",
"-e",
"0987654321",
&exp.to_string(),
"-i",
"yolo-service",
"-k",
"1234",
"-n",
"001293",
&nbf.to_string(),
"-P",
"this=that",
"-P",
"number=10",
"-P",
"array=[1, 2, 3]",
"-P",
"object={\"foo\": \"bar\"}",
"-p",
"yolo-principal",
"-s",
"yolo-subject",
])
.unwrap();
let encode_matches = matches.subcommand_matches("encode").unwrap();
let result = encode_token(&encode_matches);
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", "1234567890", &encoded_token])
.unwrap();
let decode_matches = decode_matcher.subcommand_matches("decode").unwrap();
let decoded_token = decode_token(&decode_matches);

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

let TokenData { claims, header } = decoded_token.unwrap();

assert_eq!(header.alg, Algorithm::HS256);
assert_eq!(header.kid, Some("1234".to_string()));
assert_eq!(claims.0["aud"], "yolo");
assert_eq!(claims.0["iss"], "yolo-service");
assert_eq!(claims.0["prn"], "yolo-principal");
assert_eq!(claims.0["sub"], "yolo-subject");
assert_eq!(claims.0["nbf"], nbf);
assert_eq!(claims.0["exp"], exp);
assert_eq!(claims.0["this"], "that");
assert_eq!(claims.0["number"], 10);
assert_eq!(claims.0["array"].to_string(), "[1,2,3]");
assert_eq!(claims.0["object"]["foo"], "bar");
}

#[test]
Expand Down

0 comments on commit 8beede5

Please sign in to comment.