diff --git a/core/src/error.rs b/core/src/error.rs index 1923f34..d145b37 100644 --- a/core/src/error.rs +++ b/core/src/error.rs @@ -1,8 +1,10 @@ pub enum ServiceError { + InvalidApplicationId, InvalidCredentials, Forbidden, ExpiredSession, JwtError, + UserAlreadyExists, UserNotFound, DbError, UserNotFoundByJwtId, @@ -12,10 +14,12 @@ pub enum ServiceError { impl ServiceError { fn code_and_message(&self) -> (u16, String) { match self { + ServiceError::InvalidApplicationId => (400, "Invalid application id".to_string()), ServiceError::InvalidCredentials => (401, "Invalid credentials".to_string()), ServiceError::Forbidden => (403, "Forbidden".to_string()), ServiceError::ExpiredSession => (401, "Session expired, please login again".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::DbError => (500, "Database error".to_string()), ServiceError::UserNotFoundByJwtId => (500, "User not found, please contact technical support".to_string()), diff --git a/core/src/services/candidate_service.rs b/core/src/services/candidate_service.rs index f789418..7f0491d 100644 --- a/core/src/services/candidate_service.rs +++ b/core/src/services/candidate_service.rs @@ -1,19 +1,36 @@ use entity::candidate; 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; +const CODES: [&str; 3] = ["101", "102", "103"]; + pub struct CandidateService; impl CandidateService { + /// Creates a new candidate with: + /// Encrypted personal identification number + /// Hashed password + /// Encrypted private key + /// Public key pub async fn create( db: &DbConn, application_id: i32, plain_text_password: &String, personal_id_number: String ) -> Result{ + // 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.. let hashed_password = hash_password(plain_text_password.to_string()).await.unwrap(); let (pubkey, priv_key_plain_text) = crypto::create_identity(); @@ -50,6 +67,15 @@ impl CandidateService { ) -> Result { 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 code have to be exactly 6 digits? + return false; + } + let code = &s[0..3]; + CODES.contains(&code) + } } @@ -59,6 +85,17 @@ mod tests { 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)] async fn get_memory_sqlite_connection() -> DbConn { use entity::candidate;