mirror of
https://github.com/danbulant/Portfolio
synced 2026-07-05 02:50:47 +00:00
refactor: remove jwt completely
This commit is contained in:
parent
030cd53350
commit
7fdb0de11b
6 changed files with 2 additions and 189 deletions
|
|
@ -1,7 +1,6 @@
|
||||||
mod mutation;
|
mod mutation;
|
||||||
mod query;
|
mod query;
|
||||||
pub mod crypto;
|
pub mod crypto;
|
||||||
pub mod token;
|
|
||||||
pub mod services;
|
pub mod services;
|
||||||
pub mod error;
|
pub mod error;
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -2,33 +2,11 @@ use chrono::Duration;
|
||||||
use entity::candidate;
|
use entity::candidate;
|
||||||
use sea_orm::{DatabaseConnection, prelude::Uuid, ModelTrait};
|
use sea_orm::{DatabaseConnection, prelude::Uuid, ModelTrait};
|
||||||
|
|
||||||
use crate::{crypto::{self}, Query, token::{generate_candidate_token, candidate_token::CandidateToken}, error::{ServiceError, USER_NOT_FOUND_ERROR, INVALID_CREDENTIALS_ERROR, DB_ERROR, USER_NOT_FOUND_BY_JWT_ID, USER_NOT_FOUND_BY_SESSION_ID}, Mutation};
|
use crate::{crypto::{self}, Query, error::{ServiceError, USER_NOT_FOUND_ERROR, INVALID_CREDENTIALS_ERROR, DB_ERROR, USER_NOT_FOUND_BY_JWT_ID, USER_NOT_FOUND_BY_SESSION_ID}, Mutation};
|
||||||
|
|
||||||
pub struct CandidateService;
|
pub struct CandidateService;
|
||||||
|
|
||||||
impl CandidateService {
|
impl CandidateService {
|
||||||
#[deprecated(note = "Use session login instead")]
|
|
||||||
pub async fn login(db: &DatabaseConnection, id: i32, password: String) -> Result<String, ServiceError> {
|
|
||||||
let candidate = match Query::find_candidate_by_id(db, id).await {
|
|
||||||
Ok(candidate) => match candidate {
|
|
||||||
Some(candidate) => candidate,
|
|
||||||
None => return Err(USER_NOT_FOUND_ERROR)
|
|
||||||
},
|
|
||||||
Err(_) => {return Err(DB_ERROR)}
|
|
||||||
};
|
|
||||||
|
|
||||||
|
|
||||||
let valid = crypto::verify_password(&password,&candidate.code )
|
|
||||||
.expect("Invalid password");
|
|
||||||
|
|
||||||
if !valid {
|
|
||||||
return Err(INVALID_CREDENTIALS_ERROR)
|
|
||||||
}
|
|
||||||
|
|
||||||
let jwt = generate_candidate_token(candidate); // TODO better error handling
|
|
||||||
Ok(jwt)
|
|
||||||
}
|
|
||||||
|
|
||||||
pub async fn new_session(db: &DatabaseConnection, user_id: i32, password: String) -> Result<String, ServiceError> {
|
pub async fn new_session(db: &DatabaseConnection, user_id: i32, password: String) -> Result<String, ServiceError> {
|
||||||
let candidate = match Query::find_candidate_by_id(db, user_id).await {
|
let candidate = match Query::find_candidate_by_id(db, user_id).await {
|
||||||
Ok(candidate) => match candidate {
|
Ok(candidate) => match candidate {
|
||||||
|
|
@ -61,18 +39,6 @@ impl CandidateService {
|
||||||
Ok(session.id.to_string())
|
Ok(session.id.to_string())
|
||||||
}
|
}
|
||||||
|
|
||||||
pub async fn authenticate_candidate(db: &DatabaseConnection, token: CandidateToken) -> Result<candidate::Model, ServiceError> {
|
|
||||||
let candidate = match Query::find_candidate_by_id(db, token.application_id).await {
|
|
||||||
Ok(candidate) => match candidate {
|
|
||||||
Some(candidate) => candidate,
|
|
||||||
None => return Err(USER_NOT_FOUND_BY_JWT_ID)
|
|
||||||
},
|
|
||||||
Err(_) => {return Err(DB_ERROR)}
|
|
||||||
};
|
|
||||||
|
|
||||||
Ok(candidate)
|
|
||||||
}
|
|
||||||
|
|
||||||
pub async fn auth_user_session(db: &DatabaseConnection, uuid: Uuid) -> Result<candidate::Model, ServiceError> {
|
pub async fn auth_user_session(db: &DatabaseConnection, uuid: Uuid) -> Result<candidate::Model, ServiceError> {
|
||||||
let session = match Query::find_session_by_uuid(db, uuid).await {
|
let session = match Query::find_session_by_uuid(db, uuid).await {
|
||||||
Ok(session) => match session {
|
Ok(session) => match session {
|
||||||
|
|
@ -111,7 +77,7 @@ mod tests {
|
||||||
use sea_orm::{DbConn, Database, sea_query::TableCreateStatement, DbBackend, Schema, ConnectionTrait, prelude::Uuid};
|
use sea_orm::{DbConn, Database, sea_query::TableCreateStatement, DbBackend, Schema, ConnectionTrait, prelude::Uuid};
|
||||||
use serde_json::json;
|
use serde_json::json;
|
||||||
|
|
||||||
use crate::{crypto, Mutation, services::candidate_service::CandidateService, token};
|
use crate::{crypto, Mutation, services::candidate_service::CandidateService};
|
||||||
|
|
||||||
#[cfg(test)]
|
#[cfg(test)]
|
||||||
async fn get_memory_sqlite_connection() -> DbConn {
|
async fn get_memory_sqlite_connection() -> DbConn {
|
||||||
|
|
@ -143,24 +109,6 @@ mod tests {
|
||||||
assert!(crypto::verify_password("Tajny_kod", &*candidate.code).ok().unwrap());
|
assert!(crypto::verify_password("Tajny_kod", &*candidate.code).ok().unwrap());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
#[tokio::test]
|
|
||||||
async fn test_candidate_jwt() {
|
|
||||||
let db = &get_memory_sqlite_connection().await;
|
|
||||||
|
|
||||||
let form = serde_json::from_value(json!({
|
|
||||||
"application": 5555555,
|
|
||||||
})).unwrap();
|
|
||||||
|
|
||||||
let candidate = Mutation::create_candidate(&db, form, &"Tajny_kod".to_string()).await.unwrap();
|
|
||||||
|
|
||||||
let jwt = CandidateService::login(db, 5555555, "Tajny_kod".to_string()).await.ok().unwrap();
|
|
||||||
|
|
||||||
let claims = token::decode_candidate_token(jwt).ok().unwrap().claims;
|
|
||||||
|
|
||||||
assert_eq!(claims.application_id, candidate.application);
|
|
||||||
}
|
|
||||||
|
|
||||||
#[tokio::test]
|
#[tokio::test]
|
||||||
async fn test_candidate_session_correct_password() {
|
async fn test_candidate_session_correct_password() {
|
||||||
let db = &get_memory_sqlite_connection().await;
|
let db = &get_memory_sqlite_connection().await;
|
||||||
|
|
|
||||||
|
|
@ -1,9 +0,0 @@
|
||||||
use serde::{Serialize, Deserialize};
|
|
||||||
|
|
||||||
#[derive(Debug, Serialize, Deserialize)]
|
|
||||||
pub struct AdminToken {
|
|
||||||
// issued at
|
|
||||||
pub iat: i64,
|
|
||||||
// expiration
|
|
||||||
pub exp: i64,
|
|
||||||
}
|
|
||||||
|
|
@ -1,26 +0,0 @@
|
||||||
use chrono::Utc;
|
|
||||||
use serde::{Serialize, Deserialize};
|
|
||||||
|
|
||||||
#[derive(Debug, Serialize, Deserialize)]
|
|
||||||
pub struct CandidateToken {
|
|
||||||
// issued at
|
|
||||||
pub iat: i64,
|
|
||||||
// expiration
|
|
||||||
pub exp: i64,
|
|
||||||
pub application_id: i32,
|
|
||||||
pub name: String,
|
|
||||||
pub surname: String,
|
|
||||||
}
|
|
||||||
|
|
||||||
impl CandidateToken {
|
|
||||||
pub fn generate(application_id: i32, name: String, surname: String) -> Self {
|
|
||||||
let now = Utc::now().timestamp();
|
|
||||||
CandidateToken {
|
|
||||||
iat: now,
|
|
||||||
exp: now + 60 * 60, // 1 hour for now
|
|
||||||
application_id,
|
|
||||||
name,
|
|
||||||
surname,
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
@ -1,98 +0,0 @@
|
||||||
pub mod admin_token;
|
|
||||||
pub mod candidate_token;
|
|
||||||
|
|
||||||
use chrono::Utc;
|
|
||||||
|
|
||||||
use entity::{admin, candidate};
|
|
||||||
use jsonwebtoken::errors::Result;
|
|
||||||
use jsonwebtoken::TokenData;
|
|
||||||
use jsonwebtoken::{DecodingKey, EncodingKey};
|
|
||||||
use jsonwebtoken::{Header, Validation};
|
|
||||||
|
|
||||||
use admin_token::AdminToken;
|
|
||||||
use candidate_token::CandidateToken;
|
|
||||||
use serde::Deserialize;
|
|
||||||
|
|
||||||
const ONE_WEEK: i64 = 60 * 60 * 24 * 7;
|
|
||||||
|
|
||||||
pub fn generate_candidate_token(candidate: candidate::Model) -> String {
|
|
||||||
let now = Utc::now().timestamp();
|
|
||||||
let payload = CandidateToken {
|
|
||||||
iat: now,
|
|
||||||
exp: now + ONE_WEEK,
|
|
||||||
application_id: candidate.application,
|
|
||||||
name: candidate.name.unwrap_or_else(|| "".into()),
|
|
||||||
surname: candidate.surname.unwrap_or_else(|| "".into()),
|
|
||||||
};
|
|
||||||
|
|
||||||
jsonwebtoken::encode(
|
|
||||||
&Header::default(),
|
|
||||||
&payload,
|
|
||||||
&EncodingKey::from_secret(include_bytes!("secret.key")),
|
|
||||||
)
|
|
||||||
.unwrap()
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn generate_admin_token(_admin: admin::Model) -> String {
|
|
||||||
let now = Utc::now().timestamp();
|
|
||||||
let payload = AdminToken {
|
|
||||||
iat: now,
|
|
||||||
exp: now + ONE_WEEK,
|
|
||||||
};
|
|
||||||
|
|
||||||
jsonwebtoken::encode(
|
|
||||||
&Header::default(),
|
|
||||||
&payload,
|
|
||||||
&EncodingKey::from_secret(include_bytes!("secret.key")),
|
|
||||||
)
|
|
||||||
.unwrap()
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn decode_token<T: for<'a> Deserialize<'a>>(token: String) -> Result<TokenData<T>> {
|
|
||||||
jsonwebtoken::decode::<T>(
|
|
||||||
&token,
|
|
||||||
&DecodingKey::from_secret(include_bytes!("secret.key")),
|
|
||||||
&Validation::default(),
|
|
||||||
)
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn decode_candidate_token(token: String) -> Result<TokenData<CandidateToken>> {
|
|
||||||
decode_token(token)
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn decode_admin_token(token: String) -> Result<TokenData<AdminToken>> {
|
|
||||||
decode_token(token)
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
#[test]
|
|
||||||
fn test_encode_decode_token() {
|
|
||||||
let candidate_model = candidate::Model {
|
|
||||||
application: 101204,
|
|
||||||
code: "random_code".to_string(),
|
|
||||||
birth_surname: None,
|
|
||||||
birthplace: None,
|
|
||||||
birthdate: None,
|
|
||||||
address: None,
|
|
||||||
telephone: None,
|
|
||||||
citizenship: None,
|
|
||||||
sex: None,
|
|
||||||
study: None,
|
|
||||||
personal_identification_number: None,
|
|
||||||
personal_identification_number_hash: None,
|
|
||||||
public_key: "None".to_owned(),
|
|
||||||
private_key: "None".to_owned(),
|
|
||||||
created_at: Utc::now().naive_local(),
|
|
||||||
updated_at: Utc::now().naive_local(),
|
|
||||||
name: Some("Uplnej".to_string()),
|
|
||||||
surname: Some("Magor".to_string()),
|
|
||||||
email: Some("email.uchazece@centrum.cz".to_string()),
|
|
||||||
};
|
|
||||||
|
|
||||||
let jwt = generate_candidate_token(candidate_model.clone());
|
|
||||||
|
|
||||||
let decoded = decode_candidate_token(jwt).unwrap();
|
|
||||||
let token_claims = decoded.claims;
|
|
||||||
assert_eq!(candidate_model.name.unwrap(), token_claims.name);
|
|
||||||
assert_eq!(candidate_model.surname.unwrap(), token_claims.surname);
|
|
||||||
}
|
|
||||||
|
|
@ -1 +0,0 @@
|
||||||
temp
|
|
||||||
Loading…
Reference in a new issue