diff --git a/api/assets/new-user-confirmation.html b/api/assets/new-user-confirmation.html
index 1d45cfd..058b0be 100644
--- a/api/assets/new-user-confirmation.html
+++ b/api/assets/new-user-confirmation.html
@@ -137,7 +137,7 @@
@@ -152,7 +152,7 @@
If that doesn't work, copy and paste the following link in your browser:
- $AUTH_TOKEN
+ $VERIFICATION_TOKEN
|
diff --git a/api/src/db/user.rs b/api/src/db/user.rs
index e600a5d..fc4f13d 100644
--- a/api/src/db/user.rs
+++ b/api/src/db/user.rs
@@ -1,10 +1,13 @@
+use std::fmt::Debug;
+
use sqlx::prelude::FromRow;
+use tracing::error;
use crate::models::AppError;
use super::DbPool;
-#[derive(Debug)]
+#[derive(Clone)]
pub struct NewUserEntity {
pub username: String,
pub password: String,
@@ -12,6 +15,17 @@ pub struct NewUserEntity {
pub name: String,
}
+impl Debug for NewUserEntity {
+ fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
+ f.debug_struct("NewUserEntity")
+ .field("username", &self.username)
+ .field("password", &"********")
+ .field("email", &self.email)
+ .field("name", &self.name)
+ .finish()
+ }
+}
+
#[allow(dead_code)]
#[derive(Debug, FromRow)]
pub struct UserEntity {
@@ -30,7 +44,7 @@ pub async fn insert_new_user(
password,
email,
name,
- } = new_user;
+ } = new_user.clone();
sqlx::query_as::<_, UserEntity>("INSERT INTO public.user (username, email, password, name) VALUES ($1, $2, $3, $4) RETURNING id, username, email, name, status_id;")
.bind(username)
@@ -39,7 +53,8 @@ pub async fn insert_new_user(
.bind(name)
.fetch_one(pool).await
.map_err(|err| {
- eprintln!("Error inserting NewUserEntity {err:?}");
+ error!(%err, record = ?new_user, "Cannot insert new user record");
+
AppError::from(err)
})
}
diff --git a/api/src/models/error.rs b/api/src/models/error.rs
index ff85385..4131187 100644
--- a/api/src/models/error.rs
+++ b/api/src/models/error.rs
@@ -26,6 +26,7 @@ impl AppError {
Self::new(ErrorKind::InvalidToken)
}
+ #[allow(dead_code)]
pub fn invalid_token_audience(audience: &str) -> Self {
Self::new(ErrorKind::InvalidTokenAudience(audience.to_owned()))
}
@@ -116,7 +117,7 @@ enum ErrorKind {
impl IntoResponse for AppError {
fn into_response(self) -> axum::response::Response {
- if let ErrorKind::DuplicateRecord = &self.kind { }
+ if let ErrorKind::DuplicateRecord = &self.kind {}
StatusCode::INTERNAL_SERVER_ERROR.into_response()
}
diff --git a/api/src/requests/mod.rs b/api/src/requests/mod.rs
index deb4e5a..baa7aa9 100644
--- a/api/src/requests/mod.rs
+++ b/api/src/requests/mod.rs
@@ -52,7 +52,7 @@ pub async fn start_app(pool: DbPool, env: Environment) -> Result<(), AppError> {
let path = request
.extensions()
.get::()
- .map(MatchedPath::as_str).unwrap();
+ .map(MatchedPath::as_str).unwrap_or(request.uri().path());
info_span!("api_request", request_id = %Ulid::new(), method = %request.method(), %path, status = tracing::field::Empty)
})
diff --git a/api/src/requests/user/create/handler.rs b/api/src/requests/user/create/handler.rs
index 6f4ac41..ec949ba 100644
--- a/api/src/requests/user/create/handler.rs
+++ b/api/src/requests/user/create/handler.rs
@@ -69,13 +69,13 @@ async fn register_new_user_request(
}
})?;
- let (auth_token, expiration) = generate_new_user_token(signing_key, user_id);
+ let (verification_token, expiration) = generate_new_user_token(signing_key, user_id);
let response_body = if send_verification_email {
let new_user_confirmation_message = UserConfirmationMessage {
email,
name,
- auth_token: auth_token.clone(),
+ verification_token: verification_token.clone(),
};
let _ = email_sender
@@ -87,13 +87,13 @@ async fn register_new_user_request(
UserRegistrationResponse {
id: user_id,
expiration,
- auth_token: None,
+ verification_token: None,
}
} else {
UserRegistrationResponse {
id: user_id,
expiration,
- auth_token: Some(auth_token),
+ verification_token: Some(verification_token),
}
};
diff --git a/api/src/requests/user/create/models/registration_response.rs b/api/src/requests/user/create/models/registration_response.rs
index d25a20f..dca7bc4 100644
--- a/api/src/requests/user/create/models/registration_response.rs
+++ b/api/src/requests/user/create/models/registration_response.rs
@@ -13,5 +13,5 @@ pub struct UserRegistrationResponse {
#[serde(serialize_with = "humantime_serde::serialize")]
pub expiration: SystemTime,
- pub auth_token: Option,
+ pub verification_token: Option,
}
diff --git a/api/src/requests/user/mod.rs b/api/src/requests/user/mod.rs
index 999db39..175d394 100644
--- a/api/src/requests/user/mod.rs
+++ b/api/src/requests/user/mod.rs
@@ -1,14 +1,19 @@
-use axum::{routing::post, Router};
+mod create;
+mod verify;
+
+use axum::{
+ routing::{get, post},
+ Router,
+};
+
use create::user_registration_post_handler;
+use verify::user_verification_get_handler;
use super::AppState;
-pub mod create;
-// pub mod verify;
-
pub fn requests(app_state: AppState) -> Router {
- Router::new().route(
- "/user",
- post(user_registration_post_handler).with_state(app_state.clone()),
- )
+ Router::new()
+ .route("/user", post(user_registration_post_handler))
+ .route("/user/:user_id/verify", get(user_verification_get_handler))
+ .with_state(app_state.clone())
}
diff --git a/api/src/requests/user/verify/handler.rs b/api/src/requests/user/verify/handler.rs
index 542ab1a..a6e183e 100644
--- a/api/src/requests/user/verify/handler.rs
+++ b/api/src/requests/user/verify/handler.rs
@@ -1,28 +1,43 @@
use axum::{
+ debug_handler,
extract::{Path, Query, State},
response::{IntoResponse, Response},
- routing::get,
- Json, Router,
+ Json,
};
use http::StatusCode;
-use pasetors::claims::ClaimsValidationRules;
+use pasetors::{claims::ClaimsValidationRules, keys::SymmetricKey, version4::V4};
+use tracing::{debug, error};
use crate::{
- db::verify_user, models::ApiResponse, requests::AppState, services::auth_token::verify_token,
+ db::{verify_user, DbPool},
+ models::ApiResponse,
+ requests::AppState,
+ services::auth_token::verify_token,
};
-use super::{UserVerifyGetRequest, UserVerifyGetResponse};
+use super::{UserVerifyGetParams, UserVerifyGetResponse};
-pub fn request(app_state: AppState) -> Router {
- Router::new().route("/:user_id/verify", get(get_handler).with_state(app_state))
+#[debug_handler]
+pub async fn user_verification_get_handler(
+ State(state): State,
+ Path(user_id): Path,
+ Query(query): Query,
+) -> Result {
+ let pool = state.pool();
+ let env = state.env();
+
+ let UserVerifyGetParams { verification_token } = query;
+ let token_key = env.token_key();
+ verify_new_user_request(pool, user_id, verification_token, token_key).await
}
-async fn get_handler(
- State(app_state): State,
- Path(user_id): Path,
- Query(request): Query,
+async fn verify_new_user_request(
+ pool: &DbPool,
+ user_id: i32,
+ verification_token: String,
+ token_key: &SymmetricKey,
) -> Result {
- let UserVerifyGetRequest { auth_token } = request;
+ debug!(user_id);
let validation_rules = {
let mut rules = ClaimsValidationRules::new();
@@ -31,13 +46,18 @@ async fn get_handler(
rules
};
- let key = app_state.env().token_key();
- let response = verify_token(key, auth_token.as_str(), Some(validation_rules))
- .map(|_| UserVerifyGetResponse::new(key, user_id))
- .map_err(|err| err.into_response())?;
+ let response = verify_token(
+ token_key,
+ verification_token.as_str(),
+ Some(validation_rules),
+ )
+ .map(|_| UserVerifyGetResponse::new(token_key, user_id))
+ .inspect_err(|err| error!(?err))
+ .map_err(|err| err.into_response())?;
- verify_user(app_state.pool(), user_id)
+ verify_user(pool, user_id)
.await
+ .inspect_err(|err| error!(?err))
.map_err(|err| err.into_response())?;
Ok((
diff --git a/api/src/requests/user/verify/mod.rs b/api/src/requests/user/verify/mod.rs
index 8f2640d..72001c4 100644
--- a/api/src/requests/user/verify/mod.rs
+++ b/api/src/requests/user/verify/mod.rs
@@ -1,5 +1,5 @@
+mod handler;
mod models;
-mod request;
+pub use handler::*;
pub use models::*;
-pub use request::*;
diff --git a/api/src/requests/user/verify/models/mod.rs b/api/src/requests/user/verify/models/mod.rs
index b8be632..e063d1b 100644
--- a/api/src/requests/user/verify/models/mod.rs
+++ b/api/src/requests/user/verify/models/mod.rs
@@ -1,5 +1,5 @@
-mod request;
+mod params;
mod response;
-pub use request::*;
+pub use params::*;
pub use response::*;
diff --git a/api/src/requests/user/verify/models/request.rs b/api/src/requests/user/verify/models/params.rs
similarity index 54%
rename from api/src/requests/user/verify/models/request.rs
rename to api/src/requests/user/verify/models/params.rs
index b7a1ad2..90931d4 100644
--- a/api/src/requests/user/verify/models/request.rs
+++ b/api/src/requests/user/verify/models/params.rs
@@ -1,7 +1,7 @@
use serde::Deserialize;
#[derive(Debug, Deserialize)]
-pub struct UserVerifyGetRequest {
+pub struct UserVerifyGetParams {
#[serde(alias = "t")]
- pub auth_token: String,
+ pub verification_token: String,
}
diff --git a/api/src/services/auth_token.rs b/api/src/services/auth_token.rs
index 8fa496c..939cbc3 100644
--- a/api/src/services/auth_token.rs
+++ b/api/src/services/auth_token.rs
@@ -8,6 +8,7 @@ use pasetors::{
token::UntrustedToken,
version4::V4,
};
+use tracing::error;
use uuid::Uuid;
use crate::models::AppError;
@@ -21,7 +22,9 @@ pub fn verify_token(
token: &str,
validation_rules: Option,
) -> Result<(), AppError> {
- let token = UntrustedToken::try_from(token).map_err(|_| AppError::invalid_token())?;
+ let token = UntrustedToken::try_from(token)
+ .inspect_err(|err| error!(?err))
+ .map_err(|_| AppError::invalid_token())?;
let validation_rules = if let Some(validation_rules) = validation_rules {
validation_rules
@@ -42,6 +45,7 @@ pub fn verify_token(
Some(&footer),
Some("TODO_ENV_NAME_HERE".as_bytes()),
)
+ .inspect_err(|err| error!(?err))
.map_err(|_| AppError::invalid_token())?;
Ok(())
@@ -60,7 +64,7 @@ pub fn generate_new_user_token(key: &SymmetricKey, user_id: i32) -> (String,
key,
user_id,
Some(FIFTEEN_MINUTES),
- Some(format!("api.debtpirate.bikeshedengineering.internal/user/{user_id}/verify").as_str()),
+ Some(format!("/user/{user_id}/verify").as_str()),
)
}
diff --git a/api/src/services/mailer/service.rs b/api/src/services/mailer/service.rs
index c836207..f3be611 100644
--- a/api/src/services/mailer/service.rs
+++ b/api/src/services/mailer/service.rs
@@ -52,7 +52,7 @@ pub fn start_emailer_service(
let UserConfirmationMessage {
email: recipient_email,
name,
- auth_token,
+ verification_token,
} = message;
runtime.spawn(async move {
@@ -60,7 +60,7 @@ pub fn start_emailer_service(
recipient_email.as_str(),
new_user_confirmation_template_text.as_str(),
name.as_str(),
- auth_token.as_str(),
+ verification_token.as_str(),
)
.await;
});
@@ -72,11 +72,11 @@ async fn send_new_user_confirmation_email(
recipient_email: &str,
new_user_confirmation_template_text: &str,
name: &str,
- auth_token: &str,
+ verification_token: &str,
) {
let body = new_user_confirmation_template_text
.replace("$NAME", name)
- .replace("$AUTH_TOKEN", auth_token);
+ .replace("$VERIFICATION_TOKEN", verification_token);
let message = Message::builder()
.from(FROM_MAILBOX.clone())
diff --git a/api/src/services/mailer/user_confirmation_message.rs b/api/src/services/mailer/user_confirmation_message.rs
index d99a567..d49613e 100644
--- a/api/src/services/mailer/user_confirmation_message.rs
+++ b/api/src/services/mailer/user_confirmation_message.rs
@@ -1,5 +1,6 @@
+#[derive(Debug)]
pub struct UserConfirmationMessage {
pub email: String,
pub name: String,
- pub auth_token: String,
+ pub verification_token: String,
}