1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95
use crate::dto::{ ValidationCodeDataDto, ValidationCodeRequestDto, VerifyValidationCodeRequestDto, VerifyValidationCodeResponseDto, }; use crate::service::hash_service::HashService; use lightspeed_core::error::LightSpeedError; use lightspeed_core::service::jwt::{JwtService, JWT}; use lightspeed_core::utils::current_epoch_seconds; use log::*; use serde::Serialize; use std::sync::Arc; #[derive(Clone)] pub struct ValidationCodeService { jwt_service: Arc<JwtService>, hash_service: Arc<HashService>, } #[derive(Clone, Serialize)] struct ValidationCodeData<'a, Data: Serialize> { to_be_validated: &'a Data, code: &'a str, created_ts_seconds: i64, expiration_ts_seconds: i64, } impl ValidationCodeService { pub fn new(hash_service: Arc<HashService>, jwt_service: Arc<JwtService>) -> Self { Self { jwt_service, hash_service, } } pub fn random_numeric_code() -> String { use rand::Rng; let number: u32 = rand::thread_rng().gen_range(0, 1_000_000); format!("{:06}", number) } pub fn generate_validation_code<Data: Serialize>( &self, request: ValidationCodeRequestDto<Data>, ) -> Result<ValidationCodeDataDto<Data>, LightSpeedError> { info!("Generate validation code"); let created_ts_seconds = current_epoch_seconds(); let expiration_ts_seconds = created_ts_seconds + request.validation_code_validity_seconds; let token_hash = self.hash(ValidationCodeData { expiration_ts_seconds, created_ts_seconds, code: &request.code, to_be_validated: &request.to_be_validated, })?; Ok(ValidationCodeDataDto { to_be_validated: request.to_be_validated, expiration_ts_seconds, created_ts_seconds, token_hash, }) } pub fn verify_validation_code<Data: Serialize>( &self, request: VerifyValidationCodeRequestDto<Data>, ) -> Result<VerifyValidationCodeResponseDto<Data>, LightSpeedError> { debug!("Verify code {}", request.code); let calculated_token_hash = self.hash(ValidationCodeData { expiration_ts_seconds: request.data.expiration_ts_seconds, created_ts_seconds: request.data.created_ts_seconds, code: &request.code, to_be_validated: &request.data.to_be_validated, })?; Ok(VerifyValidationCodeResponseDto { to_be_validated: request.data.to_be_validated, code_valid: calculated_token_hash.eq(&request.data.token_hash), }) } fn hash<Data: Serialize>( &self, data: ValidationCodeData<Data>, ) -> Result<String, LightSpeedError> { let jwt = JWT { iat: data.created_ts_seconds, exp: data.expiration_ts_seconds, sub: "".to_owned(), payload: data, }; let token = self.jwt_service.generate_from_token(&jwt)?; Ok(self.hash_service.hash(&token)) } }