use std::str::FromStr; use axum::{ debug_handler, extract::{Path, Query, State}, response::{IntoResponse, Response}, Json, }; use http::StatusCode; use pasetors::{claims::ClaimsValidationRules, keys::SymmetricKey, version4::V4}; use tracing::{debug, error}; use uuid::Uuid; use crate::{ db::{verify_user, DbPool}, models::{ApiResponse, AppError}, requests::{ auth::generate_login_auth_and_session_tokens, user::verify::UserVerifyGetResponseTokenAndExpiration, AppState, }, services::{auth_token::verify_token, user_session, CachePool}, }; use super::{UserVerifyGetParams, UserVerifyGetResponse}; #[debug_handler] pub async fn user_verification_get_handler( State(state): State, Path(user_id): Path, Query(query): Query, ) -> Result { let db_pool = state.db_pool(); let cache_pool = state.cache_pool(); let env = state.env(); let UserVerifyGetParams { verification_token } = query; let token_key = env.token_key(); verify_new_user_request(db_pool, cache_pool, user_id, verification_token, token_key).await } async fn verify_new_user_request( db_pool: &DbPool, cache_pool: &CachePool, user_id: i32, verification_token: String, token_key: &SymmetricKey, ) -> Result { debug!(user_id); let validation_rules = { let mut rules = ClaimsValidationRules::new(); rules.validate_audience_with(format!("/user/{user_id}/verify").as_str()); rules }; let verified_token = verify_token( token_key, verification_token.as_str(), Some(validation_rules.clone()), ) .inspect_err(|err| error!(?err))?; let verification_token_id = verified_token .payload_claims() .map(|claims| claims.get_claim("jti")) .flatten() .map(|jti| Uuid::from_str(jti.as_str().unwrap()).unwrap()) .unwrap(); user_session::exists(cache_pool, verification_token_id) .await .and_then(|exists| { if exists { Ok(user_session::get_user_session( cache_pool, verification_token_id, )) } else { Err(AppError::no_session_found()) } })? .await?; verify_user(db_pool, user_id) .await .inspect_err(|err| error!(?err))?; let ((session_token, session_token_expiration), (auth_token, auth_token_expiration)) = generate_login_auth_and_session_tokens(cache_pool, token_key, user_id).await?; let response = UserVerifyGetResponse { user_id, session: UserVerifyGetResponseTokenAndExpiration { token: session_token, expires_at: session_token_expiration, }, auth: UserVerifyGetResponseTokenAndExpiration { token: auth_token, expires_at: auth_token_expiration, }, }; Ok(( StatusCode::OK, Json(ApiResponse::::new(response)), ) .into_response()) }