use crate::key_management::KeyInfo;
use crate::shim::crypto::SignatureType;
use chrono::{Duration, Utc};
use jsonwebtoken::{decode, encode, errors::Result as JWTResult, DecodingKey, EncodingKey, Header};
use rand::Rng;
use serde::{Deserialize, Serialize};
use thiserror::Error;
pub const JWT_IDENTIFIER: &str = "auth-jwt-private";
pub const ADMIN: &[&str] = &["read", "write", "sign", "admin"];
pub const SIGN: &[&str] = &["read", "write", "sign"];
pub const WRITE: &[&str] = &["read", "write"];
pub const READ: &[&str] = &["read"];
#[derive(Debug, Error, Serialize, Deserialize)]
pub enum Error {
#[error("Filecoin method does not exist")]
MethodParam,
#[error("Incorrect permissions to access method")]
InvalidPermissions,
#[error("Missing authentication header")]
NoAuthHeader,
#[error("{0}")]
Other(String),
}
#[derive(Debug, Serialize, Deserialize)]
struct Claims {
#[serde(rename = "Allow")]
allow: Vec<String>,
exp: usize,
}
pub fn create_token(perms: Vec<String>, key: &[u8], token_exp: Duration) -> JWTResult<String> {
let exp_time = Utc::now() + token_exp;
let payload = Claims {
allow: perms,
exp: exp_time.timestamp() as usize,
};
encode(&Header::default(), &payload, &EncodingKey::from_secret(key))
}
pub fn verify_token(token: &str, key: &[u8]) -> JWTResult<Vec<String>> {
let validation = jsonwebtoken::Validation::new(jsonwebtoken::Algorithm::default());
let token = decode::<Claims>(token, &DecodingKey::from_secret(key), &validation)?;
Ok(token.claims.allow)
}
pub fn generate_priv_key() -> KeyInfo {
let priv_key = rand::thread_rng().gen::<[u8; 32]>();
KeyInfo::new(SignatureType::Bls, priv_key.to_vec())
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn create_and_verify_token() {
let perms_expected = vec![
"Ph'nglui mglw'nafh Cthulhu".to_owned(),
"R'lyeh wgah'nagl fhtagn".to_owned(),
];
let key = generate_priv_key();
let token = create_token(
perms_expected.clone(),
key.private_key(),
Duration::try_hours(1).expect("Infallible"),
)
.unwrap();
let perms = verify_token(&token, key.private_key()).unwrap();
assert_eq!(perms_expected, perms);
let token = create_token(
perms_expected.clone(),
key.private_key(),
-Duration::try_hours(1).expect("Infallible"),
)
.unwrap();
assert!(verify_token(&token, key.private_key()).is_err());
let token = create_token(
perms_expected.clone(),
key.private_key(),
-Duration::try_seconds(10).expect("Infallible"),
)
.unwrap();
let perms = verify_token(&token, key.private_key()).unwrap();
assert_eq!(perms_expected, perms);
}
}