linkrs_server/web/
middleware.rs1use axum::{
6 extract::{Request, State},
7 http::StatusCode,
8 middleware::Next,
9 response::{IntoResponse, Response},
10 Json,
11};
12use serde_json::json;
13
14use crate::storage::{
15 StorageClient, StorageOperationContextOps, StorageSchemaContextOps, StorageSyncContextOps,
16};
17use crate::web::WebState;
18
19fn deny(status: StatusCode, code: &str, message: String) -> Response {
20 (
21 status,
22 Json(json!({ "error": { "code": code, "message": message }, "status": status.as_u16() })),
23 )
24 .into_response()
25}
26
27pub async fn web_auth_middleware<
32 S: StorageClient
33 + StorageSchemaContextOps
34 + StorageSyncContextOps
35 + StorageOperationContextOps
36 + Clone
37 + Send
38 + Sync
39 + 'static,
40>(
41 State(web_state): State<WebState<S>>,
42 mut request: Request,
43 next: Next,
44) -> Response {
45 if web_state
49 .core_state
50 .server
51 .get_graph_service()
52 .is_auth_disabled()
53 {
54 request.extensions_mut().insert(0i64);
55 return next.run(request).await;
56 }
57
58 let session_id = match request
59 .headers()
60 .get("X-Session-ID")
61 .and_then(|h| h.to_str().ok())
62 .and_then(|s| s.parse::<i64>().ok())
63 {
64 Some(id) => id,
65 None => {
66 return deny(
67 StatusCode::UNAUTHORIZED,
68 "unauthenticated",
69 "missing or invalid session id".to_string(),
70 );
71 }
72 };
73
74 let session = match web_state
75 .core_state
76 .server
77 .get_session_manager()
78 .find_session(session_id)
79 {
80 Some(session) => session,
81 None => {
82 return deny(
83 StatusCode::UNAUTHORIZED,
84 "unauthenticated",
85 "session not found or expired".to_string(),
86 );
87 }
88 };
89
90 if web_state
91 .core_state
92 .server
93 .get_graph_service()
94 .is_user_locked(&session.user())
95 {
96 return deny(
97 StatusCode::FORBIDDEN,
98 "account_locked",
99 format!("account {} is locked", session.user()),
100 );
101 }
102
103 request.extensions_mut().insert(session_id);
105
106 next.run(request).await
107}