use crate::constants; use crate::users::{User, UserEmail}; use crate::utils::rand_utils::rand_string; use actix_session::Session; use actix_web::dev::Payload; use actix_web::{Error, FromRequest, HttpRequest}; use futures_util::future::{Ready, ready}; use std::net::IpAddr; /// Matrix Gateway session errors #[derive(thiserror::Error, Debug)] enum MatrixGWSessionError { #[error("Missing state!")] OIDCMissingState, #[error("Missing IP address!")] OIDCMissingIP, #[error("Invalid state!")] OIDCInvalidState, #[error("Invalid IP address!")] OIDCInvalidIP, } /// Matrix Gateway session /// /// Basic wrapper around actix-session extractor pub struct MatrixGWSession(Session); impl MatrixGWSession { /// Generate OpenID state for this session pub fn gen_oidc_state(&self, ip: IpAddr) -> anyhow::Result { let random_string = rand_string(50); self.0 .insert(constants::sessions::OIDC_STATE_KEY, random_string.clone())?; self.0.insert(constants::sessions::OIDC_REMOTE_IP, ip)?; Ok(random_string) } /// Validate OpenID state pub fn validate_state(&self, state: &str, ip: IpAddr) -> anyhow::Result<()> { let session_state: String = self .0 .get(constants::sessions::OIDC_STATE_KEY)? .ok_or(MatrixGWSessionError::OIDCMissingState)?; let session_ip: IpAddr = self .0 .get(constants::sessions::OIDC_REMOTE_IP)? .ok_or(MatrixGWSessionError::OIDCMissingIP)?; if session_state != state { return Err(anyhow::anyhow!(MatrixGWSessionError::OIDCInvalidState)); } if session_ip != ip { return Err(anyhow::anyhow!(MatrixGWSessionError::OIDCInvalidIP)); } Ok(()) } /// Set current user pub fn set_user(&self, user: &User) -> anyhow::Result<()> { self.0.insert(constants::sessions::USER_ID, &user.email)?; Ok(()) } /// Get current user pub fn current_user(&self) -> anyhow::Result> { Ok(self.0.get(constants::sessions::USER_ID)?) } /// Remove defined user pub fn unset_current_user(&self) -> anyhow::Result<()> { self.0.remove(constants::sessions::USER_ID); Ok(()) } } impl FromRequest for MatrixGWSession { type Error = Error; type Future = Ready>; #[inline] fn from_request(req: &HttpRequest, _: &mut Payload) -> Self::Future { ready( Session::from_request(req, &mut Payload::None) .into_inner() .map(MatrixGWSession), ) } }