Skip to content

Commit

Permalink
remove base64 dependency
Browse files Browse the repository at this point in the history
  • Loading branch information
deepu105 committed Jan 12, 2024
1 parent bd5fbc4 commit 98b2d38
Show file tree
Hide file tree
Showing 7 changed files with 69 additions and 66 deletions.
1 change: 0 additions & 1 deletion Cargo.lock

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

1 change: 0 additions & 1 deletion Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -45,7 +45,6 @@ tui-textarea = { version = "0.4.0", default-features = false, features = [
] }
backtrace = "0.3"
human-panic = "1.1"
base64 = "0.21"
jsonwebtoken = "9.2.0"
chrono = "0.4"

Expand Down
31 changes: 21 additions & 10 deletions src/app/jwt_decoder.rs
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@ use serde_derive::{Deserialize, Serialize};
use serde_json::{to_string_pretty, Value};

use super::{
jwt_utils::{decoding_key_from_jwks_secret, get_secret, JWTError, JWTResult, SecretFileType},
jwt_utils::{decoding_key_from_jwks_secret, get_secret, JWTError, JWTResult, SecretType},
models::{ScrollableTxt, TabRoute, TabsState},
ActiveBlock, App, Route, RouteId, TextInput,
};
Expand Down Expand Up @@ -227,6 +227,7 @@ fn decode_token(
let mut secret_validator = Validation::new(algorithm);

secret_validator.leeway = 1000;
secret_validator.validate_aud = false;

if arguments.ignore_exp {
secret_validator
Expand Down Expand Up @@ -255,31 +256,41 @@ fn decoding_key_from_secret(
let (secret, file_type) = get_secret(alg, secret_string);
let secret = secret?;
match alg {
Algorithm::HS256 | Algorithm::HS384 | Algorithm::HS512 => Ok(DecodingKey::from_secret(&secret)),
Algorithm::HS256 | Algorithm::HS384 | Algorithm::HS512 => match file_type {
SecretType::Plain => Ok(DecodingKey::from_secret(&secret)),
SecretType::Jwks => decoding_key_from_jwks_secret(&secret, header),
SecretType::B64 => {
DecodingKey::from_base64_secret(std::str::from_utf8(&secret)?).map_err(Error::into)
}
_ => Err(JWTError::Internal(format!(
"Invalid secret file type for {alg:?}"
))),
},
Algorithm::RS256
| Algorithm::RS384
| Algorithm::RS512
| Algorithm::PS256
| Algorithm::PS384
| Algorithm::PS512 => match file_type {
SecretFileType::Pem => DecodingKey::from_rsa_pem(&secret).map_err(Error::into),
SecretFileType::Der => Ok(DecodingKey::from_rsa_der(&secret)),
SecretFileType::Jwks => decoding_key_from_jwks_secret(&secret, header),
SecretType::Pem => DecodingKey::from_rsa_pem(&secret).map_err(Error::into),
SecretType::Der => Ok(DecodingKey::from_rsa_der(&secret)),
SecretType::Jwks => decoding_key_from_jwks_secret(&secret, header),
_ => Err(JWTError::Internal(format!(
"Invalid secret file type for {alg:?}"
))),
},
Algorithm::ES256 | Algorithm::ES384 => match file_type {
SecretFileType::Pem => DecodingKey::from_ec_pem(&secret).map_err(Error::into),
SecretFileType::Der => Ok(DecodingKey::from_ec_der(&secret)),
SecretFileType::Jwks => decoding_key_from_jwks_secret(&secret, header),
SecretType::Pem => DecodingKey::from_ec_pem(&secret).map_err(Error::into),
SecretType::Der => Ok(DecodingKey::from_ec_der(&secret)),
SecretType::Jwks => decoding_key_from_jwks_secret(&secret, header),
_ => Err(JWTError::Internal(format!(
"Invalid secret file type for {alg:?}"
))),
},
Algorithm::EdDSA => match file_type {
SecretFileType::Pem => DecodingKey::from_ed_pem(&secret).map_err(Error::into),
SecretFileType::Der => Ok(DecodingKey::from_ed_der(&secret)),
SecretType::Pem => DecodingKey::from_ed_pem(&secret).map_err(Error::into),
SecretType::Der => Ok(DecodingKey::from_ed_der(&secret)),
SecretType::Jwks => decoding_key_from_jwks_secret(&secret, header),
_ => Err(JWTError::Internal(format!(
"Invalid secret file type for {alg:?}"
))),
Expand Down
24 changes: 16 additions & 8 deletions src/app/jwt_encoder.rs
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@ use jsonwebtoken::{errors::Error, Algorithm, EncodingKey, Header};

use super::{
jwt_decoder::Payload,
jwt_utils::{get_secret, JWTError, JWTResult, SecretFileType},
jwt_utils::{get_secret, JWTError, JWTResult, SecretType},
models::{ScrollableTxt, TabRoute, TabsState},
ActiveBlock, App, Route, RouteId, TextAreaInput, TextInput,
};
Expand Down Expand Up @@ -112,29 +112,37 @@ pub fn encoding_key_from_secret(alg: &Algorithm, secret_string: &str) -> JWTResu
let secret = secret?;

match alg {
Algorithm::HS256 | Algorithm::HS384 | Algorithm::HS512 => Ok(EncodingKey::from_secret(&secret)),
Algorithm::HS256 | Algorithm::HS384 | Algorithm::HS512 => match file_type {
SecretType::Plain => Ok(EncodingKey::from_secret(&secret)),
SecretType::B64 => {
EncodingKey::from_base64_secret(std::str::from_utf8(&secret)?).map_err(Error::into)
}
_ => Err(JWTError::Internal(format!(
"Invalid secret file type for {alg:?}"
))),
},
Algorithm::RS256
| Algorithm::RS384
| Algorithm::RS512
| Algorithm::PS256
| Algorithm::PS384
| Algorithm::PS512 => match file_type {
SecretFileType::Pem => EncodingKey::from_rsa_pem(&secret).map_err(Error::into),
SecretFileType::Der => Ok(EncodingKey::from_rsa_der(&secret)),
SecretType::Pem => EncodingKey::from_rsa_pem(&secret).map_err(Error::into),
SecretType::Der => Ok(EncodingKey::from_rsa_der(&secret)),
_ => Err(JWTError::Internal(format!(
"Invalid secret file type for {alg:?}"
))),
},
Algorithm::ES256 | Algorithm::ES384 => match file_type {
SecretFileType::Pem => EncodingKey::from_ec_pem(&secret).map_err(Error::into),
SecretFileType::Der => Ok(EncodingKey::from_ec_der(&secret)),
SecretType::Pem => EncodingKey::from_ec_pem(&secret).map_err(Error::into),
SecretType::Der => Ok(EncodingKey::from_ec_der(&secret)),
_ => Err(JWTError::Internal(format!(
"Invalid secret file type for {alg:?}"
))),
},
Algorithm::EdDSA => match file_type {
SecretFileType::Pem => EncodingKey::from_ed_pem(&secret).map_err(Error::into),
SecretFileType::Der => Ok(EncodingKey::from_ed_der(&secret)),
SecretType::Pem => EncodingKey::from_ed_pem(&secret).map_err(Error::into),
SecretType::Der => Ok(EncodingKey::from_ed_der(&secret)),
_ => Err(JWTError::Internal(format!(
"Invalid secret file type for {alg:?}"
))),
Expand Down
74 changes: 30 additions & 44 deletions src/app/jwt_utils.rs
Original file line number Diff line number Diff line change
@@ -1,6 +1,5 @@
use std::fmt;
use std::{fmt, str::Utf8Error};

use base64::{engine::general_purpose::STANDARD as base64_engine, Engine as _};
use jsonwebtoken::{
errors::{Error, ErrorKind},
jwk, Algorithm, DecodingKey, Header,
Expand All @@ -23,14 +22,14 @@ impl From<jsonwebtoken::errors::Error> for JWTError {
}
}

impl From<serde_json::Error> for JWTError {
fn from(value: serde_json::Error) -> Self {
impl From<Utf8Error> for JWTError {
fn from(value: Utf8Error) -> Self {
JWTError::Internal(value.to_string())
}
}

impl From<base64::DecodeError> for JWTError {
fn from(value: base64::DecodeError) -> Self {
impl From<serde_json::Error> for JWTError {
fn from(value: serde_json::Error) -> Self {
JWTError::Internal(value.to_string())
}
}
Expand All @@ -56,46 +55,41 @@ impl fmt::Display for JWTError {
}
}

pub enum SecretFileType {
pub enum SecretType {
Pem,
Der,
Jwks,
Na,
B64,
Plain,
}

pub fn get_secret(alg: &Algorithm, secret_string: &str) -> (JWTResult<Vec<u8>>, SecretFileType) {
pub fn get_secret(alg: &Algorithm, secret_string: &str) -> (JWTResult<Vec<u8>>, SecretType) {
return match alg {
Algorithm::HS256 | Algorithm::HS384 | Algorithm::HS512 => {
if secret_string.starts_with('@') {
(
slurp_file(&secret_string.chars().skip(1).collect::<String>()).map_err(JWTError::from),
SecretFileType::Na,
if secret_string.ends_with(".json") {
SecretType::Jwks
} else {
SecretType::Plain
},
)
} else if secret_string.starts_with("b64:") {
(
base64_engine
.decode(secret_string.chars().skip(4).collect::<String>())
.map_err(JWTError::from),
SecretFileType::Na,
Ok(
secret_string
.chars()
.skip(4)
.collect::<String>()
.as_bytes()
.to_owned(),
),
SecretType::B64,
)
} else {
(Ok(secret_string.as_bytes().to_owned()), SecretFileType::Na)
}
}
Algorithm::EdDSA => {
if !&secret_string.starts_with('@') {
return (
Err(JWTError::Internal(format!(
"Secret for {alg:?} must be a file path starting with @",
))),
SecretFileType::Na,
);
(Ok(secret_string.as_bytes().to_owned()), SecretType::Plain)
}

(
slurp_file(&secret_string.chars().skip(1).collect::<String>()).map_err(JWTError::from),
get_secret_file_type(secret_string),
)
}
_ => {
if secret_string.starts_with('@') {
Expand All @@ -105,7 +99,7 @@ pub fn get_secret(alg: &Algorithm, secret_string: &str) -> (JWTResult<Vec<u8>>,
)
} else {
// allows to read JWKS from argument (e.g. output of 'curl https://auth.domain.com/jwks.json')
(Ok(secret_string.as_bytes().to_vec()), SecretFileType::Jwks)
(Ok(secret_string.as_bytes().to_vec()), SecretType::Jwks)
}
}
};
Expand Down Expand Up @@ -145,15 +139,7 @@ fn decoding_key_from_jwks(jwks: jwk::JwkSet, header: &Header) -> JWTResult<Decod
}
};

match &jwk.algorithm {
jwk::AlgorithmParameters::RSA(rsa) => {
DecodingKey::from_rsa_components(&rsa.n, &rsa.e).map_err(Error::into)
}
jwk::AlgorithmParameters::EllipticCurve(ec) => {
DecodingKey::from_ec_components(&ec.x, &ec.y).map_err(Error::into)
}
_ => Err(JWTError::Internal("Unsupported alg".to_string())),
}
DecodingKey::from_jwk(jwk).map_err(Error::into)
}

fn parse_jwks(secret: &[u8]) -> Option<jwk::JwkSet> {
Expand All @@ -163,13 +149,13 @@ fn parse_jwks(secret: &[u8]) -> Option<jwk::JwkSet> {
}
}

fn get_secret_file_type(secret_string: &str) -> SecretFileType {
fn get_secret_file_type(secret_string: &str) -> SecretType {
if secret_string.ends_with(".pem") {
SecretFileType::Pem
SecretType::Pem
} else if secret_string.ends_with(".json") {
SecretFileType::Jwks
SecretType::Jwks
} else {
SecretFileType::Der
SecretType::Der
}
}

Expand Down
2 changes: 1 addition & 1 deletion src/ui/decoder.rs
Original file line number Diff line number Diff line change
Expand Up @@ -70,7 +70,7 @@ fn draw_secret_block(f: &mut Frame<'_>, app: &App, area: Rect) {
vertical_chunks_with_margin(vec![Constraint::Length(1), Constraint::Min(2)], area, 1);

let mut text = Text::from(
"Prepend 'b64:' for base64 encoded secret. Prepend '@' for file path (.pem, .pk8, .der)",
"Prepend 'b64:' for base64 encoded secret. Prepend '@' for file path (.pem, .pk8, .der, .json)",
);
text.patch_style(style_default(app.light_theme));
let paragraph = Paragraph::new(text).block(Block::default());
Expand Down
2 changes: 1 addition & 1 deletion src/ui/encoder.rs
Original file line number Diff line number Diff line change
Expand Up @@ -82,7 +82,7 @@ fn draw_secret_block(f: &mut Frame<'_>, app: &App, area: Rect) {
vertical_chunks_with_margin(vec![Constraint::Length(1), Constraint::Min(2)], area, 1);

let mut text = Text::from(
"Prepend 'b64:' for base64 encoded secret. Prepend '@' for file path (.pem, .pk8, .der)",
"Prepend 'b64:' for base64 encoded secret. Prepend '@' for file path (.pem, .pk8, .der, .json)",
);
text.patch_style(style_default(app.light_theme));
let paragraph = Paragraph::new(text).block(Block::default());
Expand Down

0 comments on commit 98b2d38

Please sign in to comment.