mirror of
https://github.com/danbulant/Portfolio
synced 2026-07-06 03:20:53 +00:00
Merge pull request #29 from EETagent/application_id_validation
Application id validation
This commit is contained in:
commit
fc3e2cde6f
3 changed files with 48 additions and 7 deletions
|
|
@ -1,8 +1,10 @@
|
||||||
pub enum ServiceError {
|
pub enum ServiceError {
|
||||||
|
InvalidApplicationId,
|
||||||
InvalidCredentials,
|
InvalidCredentials,
|
||||||
Forbidden,
|
Forbidden,
|
||||||
ExpiredSession,
|
ExpiredSession,
|
||||||
JwtError,
|
JwtError,
|
||||||
|
UserAlreadyExists,
|
||||||
UserNotFound,
|
UserNotFound,
|
||||||
DbError,
|
DbError,
|
||||||
UserNotFoundByJwtId,
|
UserNotFoundByJwtId,
|
||||||
|
|
@ -12,10 +14,12 @@ pub enum ServiceError {
|
||||||
impl ServiceError {
|
impl ServiceError {
|
||||||
fn code_and_message(&self) -> (u16, String) {
|
fn code_and_message(&self) -> (u16, String) {
|
||||||
match self {
|
match self {
|
||||||
|
ServiceError::InvalidApplicationId => (400, "Invalid application id".to_string()),
|
||||||
ServiceError::InvalidCredentials => (401, "Invalid credentials".to_string()),
|
ServiceError::InvalidCredentials => (401, "Invalid credentials".to_string()),
|
||||||
ServiceError::Forbidden => (403, "Forbidden".to_string()),
|
ServiceError::Forbidden => (403, "Forbidden".to_string()),
|
||||||
ServiceError::ExpiredSession => (401, "Session expired, please login again".to_string()),
|
ServiceError::ExpiredSession => (401, "Session expired, please login again".to_string()),
|
||||||
ServiceError::JwtError => (500, "Error while encoding JWT".to_string()),
|
ServiceError::JwtError => (500, "Error while encoding JWT".to_string()),
|
||||||
|
ServiceError::UserAlreadyExists => (409, "User already exists".to_string()),
|
||||||
ServiceError::UserNotFound => (404, "User not found".to_string()),
|
ServiceError::UserNotFound => (404, "User not found".to_string()),
|
||||||
ServiceError::DbError => (500, "Database error".to_string()),
|
ServiceError::DbError => (500, "Database error".to_string()),
|
||||||
ServiceError::UserNotFoundByJwtId => (500, "User not found, please contact technical support".to_string()),
|
ServiceError::UserNotFoundByJwtId => (500, "User not found, please contact technical support".to_string()),
|
||||||
|
|
|
||||||
|
|
@ -1,19 +1,36 @@
|
||||||
use entity::candidate;
|
use entity::candidate;
|
||||||
use sea_orm::{DbConn, prelude::Uuid};
|
use sea_orm::{DbConn, prelude::Uuid};
|
||||||
|
|
||||||
use crate::{Mutation, crypto::{hash_password, self}, error::{ServiceError}};
|
use crate::{Mutation, crypto::{hash_password, self}, error::{ServiceError}, Query};
|
||||||
|
|
||||||
use super::session_service::SessionService;
|
use super::session_service::SessionService;
|
||||||
|
|
||||||
|
const FIELD_OF_STUDY_PREFIXES: [&str; 3] = ["101", "102", "103"];
|
||||||
|
|
||||||
pub struct CandidateService;
|
pub struct CandidateService;
|
||||||
|
|
||||||
impl CandidateService {
|
impl CandidateService {
|
||||||
|
/// Creates a new candidate with:
|
||||||
|
/// Encrypted personal identification number
|
||||||
|
/// Hashed password
|
||||||
|
/// Encrypted private key
|
||||||
|
/// Public key
|
||||||
pub async fn create(
|
pub async fn create(
|
||||||
db: &DbConn,
|
db: &DbConn,
|
||||||
application_id: i32,
|
application_id: i32,
|
||||||
plain_text_password: &String,
|
plain_text_password: &String,
|
||||||
personal_id_number: String
|
personal_id_number: String
|
||||||
) -> Result<candidate::Model, ServiceError>{
|
) -> Result<candidate::Model, ServiceError>{
|
||||||
|
// Check if application id starts with 101, 102 or 103
|
||||||
|
if !CandidateService::is_application_id_valid(application_id) {
|
||||||
|
return Err(ServiceError::InvalidApplicationId)
|
||||||
|
}
|
||||||
|
|
||||||
|
// Check if user with that application id already exists
|
||||||
|
if Query::find_candidate_by_id(db, application_id).await.unwrap().is_some() {
|
||||||
|
return Err(ServiceError::UserAlreadyExists)
|
||||||
|
}
|
||||||
|
|
||||||
// TODO: unwrap pro testing..
|
// TODO: unwrap pro testing..
|
||||||
let hashed_password = hash_password(plain_text_password.to_string()).await.unwrap();
|
let hashed_password = hash_password(plain_text_password.to_string()).await.unwrap();
|
||||||
let (pubkey, priv_key_plain_text) = crypto::create_identity();
|
let (pubkey, priv_key_plain_text) = crypto::create_identity();
|
||||||
|
|
@ -50,6 +67,15 @@ impl CandidateService {
|
||||||
) -> Result<candidate::Model, ServiceError> {
|
) -> Result<candidate::Model, ServiceError> {
|
||||||
SessionService::auth_user_session(db, session_uuid).await
|
SessionService::auth_user_session(db, session_uuid).await
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fn is_application_id_valid(application_id: i32) -> bool {
|
||||||
|
let s = &application_id.to_string();
|
||||||
|
if s.len() <= 3 { // TODO: does the field of study prefix have to be exactly 6 digits?
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
let field_of_study_prefix = &s[0..3];
|
||||||
|
FIELD_OF_STUDY_PREFIXES.contains(&field_of_study_prefix)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
@ -59,6 +85,17 @@ mod tests {
|
||||||
|
|
||||||
use crate::{crypto, services::candidate_service::CandidateService};
|
use crate::{crypto, services::candidate_service::CandidateService};
|
||||||
|
|
||||||
|
#[tokio::test]
|
||||||
|
async fn test_application_id_validation() {
|
||||||
|
assert!(CandidateService::is_application_id_valid(101_101));
|
||||||
|
assert!(CandidateService::is_application_id_valid(102_107));
|
||||||
|
assert!(CandidateService::is_application_id_valid(103_109));
|
||||||
|
assert!(!CandidateService::is_application_id_valid(104_109));
|
||||||
|
assert!(!CandidateService::is_application_id_valid(100_109));
|
||||||
|
assert!(!CandidateService::is_application_id_valid(201_109));
|
||||||
|
assert!(!CandidateService::is_application_id_valid(101));
|
||||||
|
}
|
||||||
|
|
||||||
#[cfg(test)]
|
#[cfg(test)]
|
||||||
async fn get_memory_sqlite_connection() -> DbConn {
|
async fn get_memory_sqlite_connection() -> DbConn {
|
||||||
use entity::candidate;
|
use entity::candidate;
|
||||||
|
|
@ -84,7 +121,7 @@ mod tests {
|
||||||
let secret_message = "trnka".to_string();
|
let secret_message = "trnka".to_string();
|
||||||
|
|
||||||
|
|
||||||
let candidate = CandidateService::create(&db, 5555555, &plain_text_password, "".to_string()).await.ok().unwrap();
|
let candidate = CandidateService::create(&db, 103151, &plain_text_password, "".to_string()).await.ok().unwrap();
|
||||||
|
|
||||||
let encrypted_message = crypto::encrypt_password_with_recipients(&secret_message, vec![&candidate.public_key]).await.unwrap();
|
let encrypted_message = crypto::encrypt_password_with_recipients(&secret_message, vec![&candidate.public_key]).await.unwrap();
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -119,9 +119,9 @@ mod tests {
|
||||||
|
|
||||||
let db = get_memory_sqlite_connection().await;
|
let db = get_memory_sqlite_connection().await;
|
||||||
|
|
||||||
let candidate = CandidateService::create(&db, 5555555, &SECRET.to_string(), "".to_string()).await.ok().unwrap();
|
let candidate = CandidateService::create(&db, 103151, &SECRET.to_string(), "".to_string()).await.ok().unwrap();
|
||||||
|
|
||||||
assert_eq!(candidate.application, 5555555);
|
assert_eq!(candidate.application, 103151);
|
||||||
assert_ne!(candidate.code, SECRET.to_string());
|
assert_ne!(candidate.code, SECRET.to_string());
|
||||||
assert!(crypto::verify_password(SECRET.to_string(), candidate.code).await.ok().unwrap());
|
assert!(crypto::verify_password(SECRET.to_string(), candidate.code).await.ok().unwrap());
|
||||||
}
|
}
|
||||||
|
|
@ -130,12 +130,12 @@ mod tests {
|
||||||
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;
|
||||||
|
|
||||||
CandidateService::create(&db, 5555555, &"Tajny_kod".to_string(), "".to_string()).await.ok().unwrap();
|
CandidateService::create(&db, 103151, &"Tajny_kod".to_string(), "".to_string()).await.ok().unwrap();
|
||||||
|
|
||||||
// correct password
|
// correct password
|
||||||
let session = SessionService::new_session(
|
let session = SessionService::new_session(
|
||||||
db,
|
db,
|
||||||
5555555,
|
103151,
|
||||||
"Tajny_kod".to_string(),
|
"Tajny_kod".to_string(),
|
||||||
"127.0.0.1".to_string(),
|
"127.0.0.1".to_string(),
|
||||||
)
|
)
|
||||||
|
|
@ -153,7 +153,7 @@ mod tests {
|
||||||
async fn test_candidate_session_incorrect_password() {
|
async fn test_candidate_session_incorrect_password() {
|
||||||
let db = &get_memory_sqlite_connection().await;
|
let db = &get_memory_sqlite_connection().await;
|
||||||
|
|
||||||
let candidate_form = CandidateService::create(&db, 5555555, &"Tajny_kod".to_string(), "".to_string()).await.ok().unwrap();
|
let candidate_form = CandidateService::create(&db, 103151, &"Tajny_kod".to_string(), "".to_string()).await.ok().unwrap();
|
||||||
|
|
||||||
// incorrect password
|
// incorrect password
|
||||||
assert!(
|
assert!(
|
||||||
|
|
|
||||||
Loading…
Reference in a new issue