mockforge_http/handlers/
risk_simulation.rs1use axum::{extract::State, http::StatusCode, response::Json};
7use serde::{Deserialize, Serialize};
8use std::collections::HashMap;
9use std::sync::Arc;
10
11use crate::auth::risk_engine::{RiskEngine, RiskEngineConfig};
12
13#[derive(Clone)]
15pub struct RiskSimulationState {
16 pub risk_engine: Arc<RiskEngine>,
18}
19
20#[derive(Debug, Deserialize)]
22pub struct SetRiskScoreRequest {
23 pub user_id: String,
25 pub risk_score: f64,
27}
28
29#[derive(Debug, Deserialize)]
31pub struct SetRiskFactorsRequest {
32 pub user_id: String,
34 pub risk_factors: HashMap<String, f64>,
36}
37
38#[derive(Debug, Deserialize)]
40pub struct TriggerMfaRequest {
41 pub user_id: String,
43 pub mfa_type: String,
45}
46
47#[derive(Debug, Deserialize)]
49pub struct BlockUserRequest {
50 pub user_id: String,
52 pub reason: String,
54}
55
56pub async fn set_risk_score(
58 State(state): State<RiskSimulationState>,
59 Json(request): Json<SetRiskScoreRequest>,
60) -> Result<Json<serde_json::Value>, StatusCode> {
61 state
62 .risk_engine
63 .set_simulated_risk(request.user_id.clone(), Some(request.risk_score))
64 .await;
65
66 Ok(Json(serde_json::json!({
67 "success": true,
68 "user_id": request.user_id,
69 "risk_score": request.risk_score
70 })))
71}
72
73pub async fn set_risk_factors(
75 State(state): State<RiskSimulationState>,
76 Json(request): Json<SetRiskFactorsRequest>,
77) -> Result<Json<serde_json::Value>, StatusCode> {
78 state
79 .risk_engine
80 .set_simulated_factors(request.user_id.clone(), request.risk_factors.clone())
81 .await;
82
83 Ok(Json(serde_json::json!({
84 "success": true,
85 "user_id": request.user_id,
86 "risk_factors": request.risk_factors
87 })))
88}
89
90pub async fn clear_risk(
92 State(state): State<RiskSimulationState>,
93 axum::extract::Path(user_id): axum::extract::Path<String>,
94) -> Result<Json<serde_json::Value>, StatusCode> {
95 state.risk_engine.clear_simulated_risk(&user_id).await;
96
97 Ok(Json(serde_json::json!({
98 "success": true,
99 "user_id": user_id,
100 "message": "Simulated risk cleared"
101 })))
102}
103
104pub async fn trigger_mfa(
106 State(state): State<RiskSimulationState>,
107 Json(request): Json<TriggerMfaRequest>,
108) -> Result<Json<serde_json::Value>, StatusCode> {
109 state.risk_engine.set_simulated_risk(request.user_id.clone(), Some(0.8)).await;
111
112 Ok(Json(serde_json::json!({
113 "success": true,
114 "user_id": request.user_id,
115 "mfa_type": request.mfa_type,
116 "message": "MFA prompt triggered"
117 })))
118}
119
120pub async fn block_user(
122 State(state): State<RiskSimulationState>,
123 Json(request): Json<BlockUserRequest>,
124) -> Result<Json<serde_json::Value>, StatusCode> {
125 state.risk_engine.set_simulated_risk(request.user_id.clone(), Some(0.95)).await;
127
128 Ok(Json(serde_json::json!({
129 "success": true,
130 "user_id": request.user_id,
131 "reason": request.reason,
132 "message": "User login blocked"
133 })))
134}
135
136pub async fn get_risk_assessment(
138 State(state): State<RiskSimulationState>,
139 axum::extract::Path(user_id): axum::extract::Path<String>,
140) -> Json<serde_json::Value> {
141 let risk_factors = HashMap::new();
142 let assessment = state.risk_engine.assess_risk(&user_id, &risk_factors).await;
143
144 Json(serde_json::json!({
145 "user_id": user_id,
146 "risk_score": assessment.risk_score,
147 "risk_factors": assessment.risk_factors,
148 "recommended_action": assessment.recommended_action
149 }))
150}
151
152pub fn risk_simulation_router(state: RiskSimulationState) -> axum::Router {
154 use axum::routing::{delete, get, post};
155
156 axum::Router::new()
157 .route("/risk/simulate", post(set_risk_score))
158 .route("/risk/factors", post(set_risk_factors))
159 .route("/risk/clear/{user_id}", delete(clear_risk))
160 .route("/risk/trigger-mfa", post(trigger_mfa))
161 .route("/risk/block", post(block_user))
162 .route("/risk/assessment/{user_id}", get(get_risk_assessment))
163 .with_state(state)
164}