systemprompt_api/services/middleware/session/
attestation.rs1use std::sync::Arc;
14use systemprompt_identifiers::{SessionId, UserId};
15use systemprompt_traits::AnalyticsProvider;
16
17#[derive(Debug, thiserror::Error)]
18pub enum SessionAttestationError {
19 #[error("Session missing or revoked")]
20 Missing,
21 #[error("Session user mismatch")]
22 UserMismatch,
23 #[error("Failed to check session: {0}")]
24 Lookup(String),
25}
26
27pub async fn attest_session(
28 analytics_provider: &Arc<dyn AnalyticsProvider>,
29 session_id: &SessionId,
30 user_id: &UserId,
31 route_context: &str,
32) -> Result<(), SessionAttestationError> {
33 let session = analytics_provider
34 .find_active_session_by_id(session_id)
35 .await
36 .map_err(|e| SessionAttestationError::Lookup(e.to_string()))?;
37
38 let Some(session) = session else {
39 tracing::info!(
40 session_id = %session_id.as_str(),
41 user_id = %user_id.as_str(),
42 route = %route_context,
43 "session attestation failed: session missing or revoked"
44 );
45 return Err(SessionAttestationError::Missing);
46 };
47
48 if let Some(session_user_id) = session.user_id.as_ref()
49 && session_user_id.as_str() != user_id.as_str()
50 {
51 tracing::warn!(
52 session_id = %session_id.as_str(),
53 claimed_user_id = %user_id.as_str(),
54 session_user_id = %session_user_id.as_str(),
55 route = %route_context,
56 "session attestation failed: session user mismatch"
57 );
58 return Err(SessionAttestationError::UserMismatch);
59 }
60
61 Ok(())
62}