mirror of
https://github.com/n08i40k/schedule-parser-rusted.git
synced 2025-12-06 09:47:50 +03:00
Тесты JWT
Имплементация PartialEq для utils::jwt::VerifyError Замена устаревшего changeset_options на diesel Удалена проверка на ошибку создания токена, так как вероятность её появления близка к нулю
This commit is contained in:
@@ -1,5 +1,4 @@
|
|||||||
use diesel::prelude::*;
|
use diesel::prelude::*;
|
||||||
use diesel::{AsExpression, FromSqlRow};
|
|
||||||
use serde::Serialize;
|
use serde::Serialize;
|
||||||
|
|
||||||
#[derive(diesel_derive_enum::DbEnum, Serialize, Debug, Clone, Copy, PartialEq)]
|
#[derive(diesel_derive_enum::DbEnum, Serialize, Debug, Clone, Copy, PartialEq)]
|
||||||
@@ -14,7 +13,7 @@ pub enum UserRole {
|
|||||||
|
|
||||||
#[derive(Identifiable, AsChangeset, Queryable, Selectable, Serialize)]
|
#[derive(Identifiable, AsChangeset, Queryable, Selectable, Serialize)]
|
||||||
#[diesel(table_name = crate::database::schema::users)]
|
#[diesel(table_name = crate::database::schema::users)]
|
||||||
#[changeset_options(treat_none_as_null = "true")]
|
#[diesel(treat_none_as_null = true)]
|
||||||
pub struct User {
|
pub struct User {
|
||||||
pub id: String,
|
pub id: String,
|
||||||
pub username: String,
|
pub username: String,
|
||||||
|
|||||||
@@ -16,12 +16,11 @@ pub async fn sign_in(data: Json<SignInDto>, app_state: web::Data<AppState>) -> J
|
|||||||
let mut lock = app_state.connection();
|
let mut lock = app_state.connection();
|
||||||
let conn = lock.deref_mut();
|
let conn = lock.deref_mut();
|
||||||
|
|
||||||
user.access_token =
|
user.access_token = utility::jwt::encode(&user.id);
|
||||||
utility::jwt::encode(&user.id).expect("Failed to generate jet token");
|
|
||||||
|
|
||||||
user.save_changes::<User>(conn)
|
user.save_changes::<User>(conn)
|
||||||
.expect("Failed to update user");
|
.expect("Failed to update user");
|
||||||
|
|
||||||
SignInResult::ok(&user)
|
SignInResult::ok(&user)
|
||||||
}
|
}
|
||||||
Ok(false) | Err(_) => SignInResult::err(IncorrectCredentials),
|
Ok(false) | Err(_) => SignInResult::err(IncorrectCredentials),
|
||||||
|
|||||||
@@ -1,9 +1,13 @@
|
|||||||
use chrono::{DateTime, Duration, Utc};
|
use chrono::DateTime;
|
||||||
|
use chrono::Duration;
|
||||||
|
use chrono::TimeZone;
|
||||||
|
use chrono::Utc;
|
||||||
use hmac::{Hmac, Mac};
|
use hmac::{Hmac, Mac};
|
||||||
use jwt::{SignWithKey, Token, VerifyWithKey};
|
use jwt::{SignWithKey, Token, VerifyWithKey};
|
||||||
use sha2::Sha256;
|
use sha2::Sha256;
|
||||||
use std::collections::BTreeMap;
|
use std::collections::BTreeMap;
|
||||||
use std::env;
|
use std::env;
|
||||||
|
use std::mem::discriminant;
|
||||||
use std::sync::LazyLock;
|
use std::sync::LazyLock;
|
||||||
|
|
||||||
static JWT_SECRET: LazyLock<Hmac<Sha256>> = LazyLock::new(|| {
|
static JWT_SECRET: LazyLock<Hmac<Sha256>> = LazyLock::new(|| {
|
||||||
@@ -16,9 +20,14 @@ static JWT_SECRET: LazyLock<Hmac<Sha256>> = LazyLock::new(|| {
|
|||||||
pub enum VerifyError {
|
pub enum VerifyError {
|
||||||
JwtError(jwt::Error),
|
JwtError(jwt::Error),
|
||||||
InvalidSignature,
|
InvalidSignature,
|
||||||
NoExpirationTag,
|
InvalidToken,
|
||||||
Expired,
|
Expired,
|
||||||
NoId,
|
}
|
||||||
|
|
||||||
|
impl PartialEq for VerifyError {
|
||||||
|
fn eq(&self, other: &Self) -> bool {
|
||||||
|
discriminant(self) == discriminant(other)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn verify_and_decode(token: &String) -> Result<String, VerifyError> {
|
pub fn verify_and_decode(token: &String) -> Result<String, VerifyError> {
|
||||||
@@ -27,31 +36,29 @@ pub fn verify_and_decode(token: &String) -> Result<String, VerifyError> {
|
|||||||
let result: Result<BTreeMap<String, String>, jwt::Error> = token.verify_with_key(jwt);
|
let result: Result<BTreeMap<String, String>, jwt::Error> = token.verify_with_key(jwt);
|
||||||
|
|
||||||
match result {
|
match result {
|
||||||
Ok(claims) => match claims.get("exp") {
|
Ok(claims) => {
|
||||||
None => Err(VerifyError::NoExpirationTag),
|
let exp = claims.get("exp").unwrap();
|
||||||
Some(exp) => {
|
let exp_date = DateTime::from_timestamp(exp.parse::<i64>().unwrap(), 0)
|
||||||
let exp_date = DateTime::from_timestamp(exp.parse::<i64>().unwrap(), 0)
|
.expect("Failed to parse expiration time");
|
||||||
.expect("Failed to parse expiration time");
|
|
||||||
|
|
||||||
if Utc::now() > exp_date {
|
if Utc::now() > exp_date {
|
||||||
return Err(VerifyError::Expired);
|
return Err(VerifyError::Expired);
|
||||||
}
|
|
||||||
|
|
||||||
match claims.get("id").cloned() {
|
|
||||||
None => Err(VerifyError::NoId),
|
|
||||||
Some(id) => Ok(id),
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
},
|
|
||||||
|
Ok(claims.get("id").cloned().unwrap())
|
||||||
|
}
|
||||||
Err(err) => Err(match err {
|
Err(err) => Err(match err {
|
||||||
jwt::Error::InvalidSignature => VerifyError::InvalidSignature,
|
jwt::Error::InvalidSignature => VerifyError::InvalidSignature,
|
||||||
|
jwt::Error::Format | jwt::Error::Base64(_) | jwt::Error::NoClaimsComponent => {
|
||||||
|
VerifyError::InvalidToken
|
||||||
|
}
|
||||||
|
|
||||||
_ => VerifyError::JwtError(err),
|
_ => VerifyError::JwtError(err),
|
||||||
}),
|
}),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn encode(id: &String) -> Result<String, jwt::Error> {
|
pub fn encode(id: &String) -> String {
|
||||||
let header = jwt::Header {
|
let header = jwt::Header {
|
||||||
type_: Some(jwt::header::HeaderType::JsonWebToken),
|
type_: Some(jwt::header::HeaderType::JsonWebToken),
|
||||||
..Default::default()
|
..Default::default()
|
||||||
@@ -69,8 +76,65 @@ pub fn encode(id: &String) -> Result<String, jwt::Error> {
|
|||||||
claims.insert("iat", iat_str.as_str());
|
claims.insert("iat", iat_str.as_str());
|
||||||
claims.insert("exp", exp_str.as_str());
|
claims.insert("exp", exp_str.as_str());
|
||||||
|
|
||||||
match Token::new(header, claims).sign_with_key(&*JWT_SECRET) {
|
Token::new(header, claims)
|
||||||
Ok(token) => Ok(token.as_str().to_string()),
|
.sign_with_key(&*JWT_SECRET)
|
||||||
Err(err) => Err(err),
|
.unwrap()
|
||||||
|
.as_str()
|
||||||
|
.to_string()
|
||||||
|
}
|
||||||
|
|
||||||
|
#[cfg(test)]
|
||||||
|
mod tests {
|
||||||
|
use super::*;
|
||||||
|
use dotenvy::dotenv;
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn test_encode() {
|
||||||
|
dotenv().unwrap();
|
||||||
|
|
||||||
|
assert_eq!(encode(&"test".to_string()).is_empty(), false);
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn test_decode_invalid_token() {
|
||||||
|
dotenv().unwrap();
|
||||||
|
|
||||||
|
let token = "".to_string();
|
||||||
|
let result = verify_and_decode(&token);
|
||||||
|
|
||||||
|
assert!(result.is_err());
|
||||||
|
assert_eq!(result.err().unwrap(), VerifyError::InvalidToken);
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn test_decode_invalid_signature() {
|
||||||
|
dotenv().unwrap();
|
||||||
|
|
||||||
|
let token = "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJleHAiOiIxODY4ODEyOTI4IiwiaWF0IjoiMTc0MjY2ODkyOCIsImlkIjoiNjdkY2M5YTk1MDdiMDAwMDc3Mjc0NGEyIn0.DQYFYF-3DoJgCLOVdAWa47nUaCJAh16DXj-ChNSSmWz".to_string();
|
||||||
|
let result = verify_and_decode(&token);
|
||||||
|
|
||||||
|
assert!(result.is_err());
|
||||||
|
assert_eq!(result.err().unwrap(), VerifyError::InvalidToken);
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn test_decode_expired() {
|
||||||
|
dotenv().unwrap();
|
||||||
|
|
||||||
|
let token = "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJleHAiOiIxNjE2NTI2Mzc2IiwiaWF0IjoiMTQ5MDM4MjM3NiIsImlkIjoiNjdkY2M5YTk1MDdiMDAwMDc3Mjc0NGEyIn0.Qc2LbMJTvl2hWzDM2XyQv4m9lIqR84COAESQAieUxz8".to_string();
|
||||||
|
let result = verify_and_decode(&token);
|
||||||
|
|
||||||
|
assert!(result.is_err());
|
||||||
|
assert_eq!(result.err().unwrap(), VerifyError::Expired);
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn test_decode_ok() {
|
||||||
|
dotenv().unwrap();
|
||||||
|
|
||||||
|
let token = "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJleHAiOiIxODY4ODEyOTI4IiwiaWF0IjoiMTc0MjY2ODkyOCIsImlkIjoiNjdkY2M5YTk1MDdiMDAwMDc3Mjc0NGEyIn0.DQYFYF-3DoJgCLOVdAWa47nUaCJAh16DXj-ChNSSmWw".to_string();
|
||||||
|
let result = verify_and_decode(&token);
|
||||||
|
|
||||||
|
assert!(result.is_ok());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user