Remove user_id from user creation and verification responses

This commit is contained in:
Z. Charles Dziura 2025-03-06 16:31:10 -05:00
parent 2bdb3ff67a
commit fd04e6445b
7 changed files with 46 additions and 44 deletions

View file

@ -79,6 +79,9 @@ CREATE TABLE IF NOT EXISTS
updated_at TIMESTAMP WITH TIME ZONE NULL
);
CREATE INDEX IF NOT EXISTS user_account_permission_user_id_idx ON public.user_account_permission(user_id);
CREATE INDEX IF NOT EXISTS user_account_permission_account_id_idx ON public.user_account_permission(account_id);
CREATE TABLE IF NOT EXISTS
public.budget (
id INT GENERATED ALWAYS AS IDENTITY PRIMARY KEY,

View file

@ -1,19 +1,18 @@
use std::{sync::mpsc::Sender, time::SystemTime};
use crate::{
db::{insert_new_user, DbPool, NewUserEntity, UserEntity},
db::{DbPool, NewUserEntity, UserEntity, insert_new_user},
models::{ApiResponse, AppError, Session},
requests::AppState,
services::{
self, auth_token::generate_new_user_token, hash_password, CachePool,
UserConfirmationMessage,
self, CachePool, UserConfirmationMessage, auth_token::generate_new_user_token,
hash_password,
},
};
use axum::{
debug_handler,
Json, debug_handler,
extract::State,
response::{IntoResponse, Response},
Json,
};
use http::StatusCode;
use pasetors::{keys::SymmetricKey, version4::V4};
@ -38,6 +37,9 @@ pub async fn user_registration_post_handler(
mail_sender,
)
.await
.map(|(status_code, response)| {
(status_code, ApiResponse::new(response).into_json_response()).into_response()
})
}
async fn register_new_user_request(
@ -47,7 +49,7 @@ async fn register_new_user_request(
signing_key: &SymmetricKey<V4>,
send_verification_email: bool,
email_sender: &Sender<UserConfirmationMessage>,
) -> Result<Response, AppError> {
) -> Result<(StatusCode, UserRegistrationResponse), AppError> {
debug!(?body, send_verification_email);
let UserRegistrationRequest {
@ -111,22 +113,15 @@ async fn register_new_user_request(
});
UserRegistrationResponse {
user_id,
expires_at: None,
session_token: None,
}
} else {
UserRegistrationResponse {
user_id,
expires_at: Some(expires_at),
session_token: Some(verification_token),
}
};
let response = (
StatusCode::CREATED,
ApiResponse::new(response_body).into_json_response(),
);
Ok(response.into_response())
Ok((StatusCode::CREATED, response_body))
}

View file

@ -8,8 +8,6 @@ use serde_with::{serde_as, skip_serializing_none};
#[derive(Debug, Serialize)]
#[serde(rename_all = "camelCase")]
pub struct UserRegistrationResponse {
pub user_id: i32,
#[serde(serialize_with = "humantime_serde::serialize")]
pub expires_at: Option<SystemTime>,

View file

@ -2,8 +2,8 @@ mod create;
mod verify;
use axum::{
routing::{get, post},
Router,
routing::{get, post},
};
use create::user_registration_post_handler;
@ -17,7 +17,7 @@ pub fn requests(state: AppState) -> Router {
"/user",
Router::new()
.route("/", post(user_registration_post_handler))
.route("/{user_id}/verify", get(user_verification_get_handler)),
.route("/verify", get(user_verification_get_handler)),
)
.with_state(state.clone())
}

View file

@ -2,23 +2,22 @@ use std::str::FromStr;
use axum::{
debug_handler,
extract::{Path, Query, State},
extract::{Query, State},
response::{IntoResponse, Response},
Json,
};
use http::StatusCode;
use pasetors::{claims::ClaimsValidationRules, keys::SymmetricKey, version4::V4};
use tracing::{debug, error};
use tracing::error;
use uuid::Uuid;
use crate::{
db::{verify_user, DbPool},
db::{DbPool, verify_user},
models::{ApiResponse, AppError},
requests::{
auth::generate_login_auth_and_session_tokens,
user::verify::UserVerifyGetResponseTokenAndExpiration, AppState,
AppState, auth::generate_login_auth_and_session_tokens,
user::verify::UserVerifyGetResponseTokenAndExpiration,
},
services::{auth_token::verify_token, user_session, CachePool},
services::{CachePool, auth_token::verify_token, user_session},
};
use super::{UserVerifyGetParams, UserVerifyGetResponse};
@ -26,7 +25,6 @@ use super::{UserVerifyGetParams, UserVerifyGetResponse};
#[debug_handler]
pub async fn user_verification_get_handler(
State(state): State<AppState>,
Path(user_id): Path<i32>,
Query(query): Query<UserVerifyGetParams>,
) -> Result<Response, AppError> {
let db_pool = state.db_pool();
@ -34,21 +32,22 @@ pub async fn user_verification_get_handler(
let token_key = state.config().secrets().token_key();
let UserVerifyGetParams { verification_token } = query;
verify_new_user_request(db_pool, cache_pool, user_id, verification_token, token_key).await
verify_new_user_request(db_pool, cache_pool, verification_token, token_key)
.await
.map(|(status_code, response)| {
(status_code, ApiResponse::new(response).into_json_response()).into_response()
})
}
async fn verify_new_user_request(
db_pool: &DbPool,
cache_pool: &CachePool,
user_id: i32,
verification_token: String,
token_key: &SymmetricKey<V4>,
) -> Result<Response, AppError> {
debug!(user_id);
) -> Result<(StatusCode, UserVerifyGetResponse), AppError> {
let validation_rules = {
let mut rules = ClaimsValidationRules::new();
rules.validate_audience_with(format!("/user/{user_id}/verify").as_str());
rules.validate_audience_with(format!("/user/verify").as_str());
rules
};
@ -59,11 +58,24 @@ async fn verify_new_user_request(
)
.inspect_err(|err| error!(?err))?;
let verification_token_id = verified_token
let (user_id, verification_token_id) = verified_token
.payload_claims()
.map(|claims| claims.get_claim("jti"))
.flatten()
.map(|jti| Uuid::from_str(jti.as_str().unwrap()).unwrap())
.map(|claims| {
(
claims
.get_claim("sub")
.map(|sub| sub.as_str())
.flatten()
.map(|sub| sub.parse::<i32>().unwrap())
.unwrap(),
claims
.get_claim("jti")
.map(|jti| jti.as_str())
.flatten()
.unwrap(),
)
})
.map(|(user_id, jti)| (user_id, Uuid::from_str(jti).unwrap()))
.unwrap();
user_session::exists(cache_pool, verification_token_id)
@ -88,7 +100,6 @@ async fn verify_new_user_request(
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,
@ -99,9 +110,5 @@ async fn verify_new_user_request(
},
};
Ok((
StatusCode::OK,
Json(ApiResponse::<UserVerifyGetResponse>::new(response)),
)
.into_response())
Ok((StatusCode::OK, response))
}

View file

@ -5,7 +5,6 @@ use serde::Serialize;
#[derive(Debug, Serialize)]
#[serde(rename_all = "camelCase")]
pub struct UserVerifyGetResponse {
pub user_id: i32,
pub session: UserVerifyGetResponseTokenAndExpiration,
pub auth: UserVerifyGetResponseTokenAndExpiration,
}

View file

@ -96,7 +96,7 @@ pub fn generate_new_user_token(key: &SymmetricKey<V4>, user_id: i32) -> (String,
key,
user_id,
FIFTEEN_MINUTES,
Some(format!("/user/{user_id}/verify").as_str()),
Some(format!("/user/verify").as_str()),
)
}