ironshield_api/handler/
response.rs1use axum::extract::Json;
4
5use ironshield_types::{
6 load_private_key_from_env,
7 load_public_key_from_env,
8 IronShieldChallengeResponse,
9 IronShieldToken
10};
11use crate::constant;
12use crate::handler::{
13 error::{
14 ErrorHandler,
15 PUB_KEY_FAIL,
16 SIG_KEY_FAIL,
17 INVALID_SOLUTION,
18 SIGNATURE_FAIL
19 },
20 result::ResultHandler
21};
22
23use serde_json::{
24 json,
25 Value
26};
27
28pub async fn handle_challenge_response(
29 Json(payload): Json<IronShieldChallengeResponse>,
30) -> ResultHandler<Json<Value>> {
31 validate_challenge_response(&payload)?;
33
34 let token = verify_and_generate_token(payload).await?;
36
37 Ok(Json(json!({
39 "status": constant::STATUS_OK,
40 "message": constant::STATUS_OK_MSG,
41 "token": token
42 })))
43}
44
45fn validate_challenge_response(
46 response: &IronShieldChallengeResponse
47) -> ResultHandler<()> {
48 if response.solution < 0 {
49 return Err(ErrorHandler::InvalidRequest(format!("{}: {}", INVALID_SOLUTION, response.solution)));
50 }
51
52 Ok(())
53}
54
55async fn verify_and_generate_token(
56 response: IronShieldChallengeResponse
57) -> ResultHandler<IronShieldToken> {
58 let valid_for = chrono::Utc::now().timestamp_millis() + (60 * 60 * 1000);
63
64 let signing_key = load_private_key_from_env()
67 .map_err(|e| ErrorHandler::ProcessingError(format!("{}: {}", SIG_KEY_FAIL, e)))?;
68 let public_key = load_public_key_from_env()
69 .map_err(|e| ErrorHandler::ProcessingError(format!("{}: {}", PUB_KEY_FAIL, e)))?
70 .to_bytes();
71
72 let auth_msg = format!(
73 "{}|{}",
74 hex::encode(response.solved_challenge.challenge_signature),
75 valid_for
76 );
77
78 let auth_signature = ironshield_types::generate_signature(&signing_key, &auth_msg)
80 .map_err(|e| ErrorHandler::ProcessingError(format!("{}: {}", SIGNATURE_FAIL, e)))?;
81
82 let token = IronShieldToken::new(
83 response.solved_challenge.challenge_signature,
84 valid_for,
85 public_key,
86 auth_signature,
87 );
88
89 Ok(token)
90}