use std::sync::Arc; use rocket::serde::json::Json; use rocket::State; use serde::{Deserialize, Serialize}; use crate::api::auth::WithFxaLogin; use crate::api::{auth, Empty, EMPTY}; use crate::auth::Authenticated; use crate::db::Db; use crate::db::DbConn; use crate::mailer::Mailer; use crate::push::PushClient; use crate::types::{SessionID, UserID}; use crate::utils::DeferAction; // MISSING post /session/duplicate // MISSING post /session/reauth // MISSING post /session/verify/send_push #[derive(Debug, Serialize)] pub(crate) struct StatusResp { state: &'static str, // what does this *do*? uid: UserID, } #[get("/session/status")] pub(crate) async fn status(req: Authenticated<(), WithFxaLogin>) -> auth::Result { Ok(Json(StatusResp { state: "", uid: req.context.uid })) } #[post("/session/resend_code", data = "")] pub(crate) async fn resend_code( db: &DbConn, mailer: &State>, req: Authenticated, ) -> auth::Result { let code = match req.context.verify_code { Some(code) => code, _ => return Err(auth::Error::InvalidVerificationCode), }; let user = db.get_user_by_id(&req.context.uid).await?; mailer.send_session_verify(&user.email, &code).await.map_err(|e| { error!("failed to send email: {e}"); auth::Error::EmailFailed })?; Ok(EMPTY) } #[derive(Debug, Deserialize)] #[serde(deny_unknown_fields)] pub(crate) struct VerifyReq { code: String, // MISSING service // MISSING scopes // MISSING marketingOptIn // MISSING newsletters } #[post("/session/verify_code", data = "")] pub(crate) async fn verify_code( db: &DbConn, req: Authenticated, ) -> auth::Result { if req.context.verify_code.as_ref() != Some(&req.body.code) { return Err(auth::Error::InvalidVerificationCode); } db.set_session_verified(&req.session).await?; Ok(EMPTY) } #[derive(Debug, Deserialize)] #[serde(deny_unknown_fields)] pub(crate) struct DestroyReq { custom_session_id: Option, } #[post("/session/destroy", data = "")] pub(crate) async fn destroy( db: &DbConn, db_pool: &Db, defer: &DeferAction, client: &State>, data: Authenticated, ) -> auth::Result { if data.body.custom_session_id.is_some() && !data.context.verified { return Err(auth::Error::UnverifiedSession); } let id = data.body.custom_session_id.as_ref().unwrap_or(&data.session); db.delete_session(&data.context.uid, id).await.map_err(|_| auth::Error::UnknownDevice)?; if let Some(id) = data.context.device_id { match db.get_devices(&data.context.uid).await { Err(e) => warn!("device_disconnected push failed: {e}"), Ok(devs) => defer.spawn_after_success("api::auth/session/destroy(post)", { let (client, db) = (Arc::clone(client), db_pool.clone()); async move { let db = db.begin().await?; client.device_disconnected(&db, &devs, &id).await; db.commit().await?; Ok(()) } }), }; } Ok(EMPTY) }