Files
ImageApi/src/data/mod.rs
Cameron Cordes f9983240df
All checks were successful
Core Repos/ImageApi/pipeline/head This commit looks good
Core Repos/ImageApi/pipeline/pr-master This commit looks good
Use log crate for logging instead of println
2021-02-24 21:26:11 -05:00

130 lines
3.2 KiB
Rust

use std::str::FromStr;
use log::error;
use actix_web::error::ErrorUnauthorized;
use actix_web::{dev, http::header, Error, FromRequest, HttpRequest};
use futures::future::{err, ok, Ready};
use jsonwebtoken::{decode, Algorithm, DecodingKey, Validation};
use serde::{Deserialize, Serialize};
#[derive(Serialize)]
pub struct Token<'a> {
pub token: &'a str,
}
#[derive(Debug, Deserialize, Serialize)]
pub struct Claims {
pub sub: String,
pub exp: i64,
}
pub fn secret_key() -> String {
if cfg!(test) {
String::from("test_key")
} else {
dotenv::var("SECRET_KEY").expect("SECRET_KEY env not set!")
}
}
impl FromStr for Claims {
type Err = jsonwebtoken::errors::Error;
fn from_str(s: &str) -> Result<Self, Self::Err> {
let token = *(s.split("Bearer ").collect::<Vec<_>>().last().unwrap_or(&""));
match decode::<Claims>(
&token,
&DecodingKey::from_secret(secret_key().as_bytes()),
&Validation::new(Algorithm::HS256),
) {
Ok(data) => Ok(data.claims),
Err(other) => {
error!("DecodeError: {}", other);
Err(other)
}
}
}
}
impl FromRequest for Claims {
type Error = Error;
type Future = Ready<Result<Self, Self::Error>>;
type Config = ();
fn from_request(req: &HttpRequest, _payload: &mut dev::Payload) -> Self::Future {
let claims = match req.headers().get(header::AUTHORIZATION) {
Some(header) => Claims::from_str(header.to_str().unwrap_or("")),
None => Err(jsonwebtoken::errors::Error::from(
jsonwebtoken::errors::ErrorKind::InvalidToken,
)),
};
if let Ok(claims) = claims {
ok(claims)
} else {
err(ErrorUnauthorized("Bad token"))
}
}
}
#[derive(Deserialize)]
pub struct ThumbnailRequest {
pub path: String,
pub size: Option<String>,
}
#[derive(Deserialize)]
pub struct LoginRequest {
pub username: String,
pub password: String,
}
#[derive(Deserialize)]
pub struct CreateAccountRequest {
pub username: String,
pub password: String,
pub confirmation: String,
}
#[derive(Deserialize)]
pub struct AddFavoriteRequest {
pub path: String,
}
#[cfg(test)]
mod tests {
use super::Claims;
use jsonwebtoken::errors::ErrorKind;
use std::str::FromStr;
#[test]
fn test_token_from_claims() {
let claims = Claims {
exp: 16136164790, // 2481-ish
sub: String::from("9"),
};
let c = Claims::from_str(
"eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJzdWIiOiI5IiwiZXhwIjoxNjEzNjE2NDc5MH0.9wwK4l8vhvq55YoueEljMbN_5uVTaAsGLLRPr0AuymE")
.unwrap();
assert_eq!(claims.sub, c.sub);
assert_eq!(claims.exp, c.exp);
}
#[test]
fn test_expired_token() {
let err = Claims::from_str(
"eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJzdWIiOiI5IiwiZXhwIjoxNn0.eZnfaNfiD54VMbphIqeBICeG9SzAtwNXntLwtTBihjY");
match err.unwrap_err().into_kind() {
ErrorKind::ExpiredSignature => assert!(true),
kind => {
println!("Unexpected error: {:?}", kind);
assert!(false)
}
}
}
}