diff --git a/api/.env b/api/.env
index cc9cbc9..b0548e2 100644
--- a/api/.env
+++ b/api/.env
@@ -1,7 +1,8 @@
-HOSTNAME=localhost
-PORT=42069
-TOKEN_KEY=k4.local.hWoS2ZulK9xPEATtXH1Dvj_iynzqfUv5ER5_IFTg5-Q
-DATABASE_URL=postgres://debt_pirate:HRURqlUmtjIy@192.168.122.251/debt_pirate
ASSETS_DIR=/home/zcdziura/Documents/Projects/debt-pirate/api/assets
+DATABASE_URL=postgres://debt_pirate:HRURqlUmtjIy@192.168.122.251/debt_pirate
+HOSTNAME=localhost
MAINTENANCE_USER_ACCOUNT=debt_pirate:HRURqlUmtjIy
+PORT=42069
RUST_LOG=debt_pirate=trace
+SEND_VERIFICATION_EMAIL=false
+TOKEN_KEY=k4.local.hWoS2ZulK9xPEATtXH1Dvj_iynzqfUv5ER5_IFTg5-Q
diff --git a/api/.vscode/launch.json b/api/.vscode/launch.json
index 3f4b3f6..8207875 100644
--- a/api/.vscode/launch.json
+++ b/api/.vscode/launch.json
@@ -7,15 +7,15 @@
{
"type": "lldb",
"request": "launch",
- "name": "Debug executable 'auth-test'",
+ "name": "Debug executable 'debt-pirate'",
"cargo": {
"args": [
"build",
- "--bin=auth-test",
- "--package=auth-test"
+ "--bin=debt-pirate",
+ "--package=debt-pirate"
],
"filter": {
- "name": "auth-test",
+ "name": "debt-pirate",
"kind": "bin"
}
},
@@ -25,16 +25,16 @@
{
"type": "lldb",
"request": "launch",
- "name": "Debug unit tests in executable 'auth-test'",
+ "name": "Debug unit tests in executable 'debt-pirate'",
"cargo": {
"args": [
"test",
"--no-run",
- "--bin=auth-test",
- "--package=auth-test"
+ "--bin=debt-pirate",
+ "--package=debt-pirate"
],
"filter": {
- "name": "auth-test",
+ "name": "debt-pirate",
"kind": "bin"
}
},
diff --git a/api/Cargo.toml b/api/Cargo.toml
index 064021b..3f2cdc2 100644
--- a/api/Cargo.toml
+++ b/api/Cargo.toml
@@ -25,9 +25,7 @@ lettre = { version = "0.11", default-features = false, features = [
"tokio1",
"tokio1-rustls-tls",
] }
-log = "0.4"
num_cpus = "1.16"
-once_cell = "1.19"
pasetors = "0.7"
serde = { version = "1.0", features = ["derive", "rc", "std"] }
serde_json = "1.0"
diff --git a/api/assets/new-user-confirmation.html b/api/assets/new-user-confirmation.html
index 6941c18..1d45cfd 100644
--- a/api/assets/new-user-confirmation.html
+++ b/api/assets/new-user-confirmation.html
@@ -123,7 +123,7 @@
- Click or tap the button below to confirm your email address. If you didn't create an account with Auth-Test, you can safely delete this email.
+ Click or tap the button below to confirm your email address. If you didn't create an account with Debt Pirate, you can safely delete this email.
|
@@ -160,7 +160,7 @@
- Thank you, The Auth-Test Team
+ Thank you, The Debt Pirate Team
|
diff --git a/api/src/models/environment.rs b/api/src/models/environment.rs
index 8a60ba8..b33cd1d 100644
--- a/api/src/models/environment.rs
+++ b/api/src/models/environment.rs
@@ -1,38 +1,24 @@
use std::{
- collections::HashSet,
path::{Path, PathBuf},
sync::mpsc::Sender,
};
-use once_cell::sync::Lazy;
use pasetors::{keys::SymmetricKey, version4::V4};
use crate::services::UserConfirmationMessage;
use super::AppError;
-static REQUIRED_ENV_VARS: Lazy> = Lazy::new(|| {
- [
- "HOSTNAME",
- "PORT",
- "TOKEN_KEY",
- "DATABASE_URL",
- "ASSETS_DIR",
- "RUST_LOG",
- ]
- .into_iter()
- .collect()
-});
-
#[derive(Clone)]
pub struct Environment {
- hostname: String,
- port: u32,
- token_key: SymmetricKey,
+ assets_dir: PathBuf,
database_url: String,
email_sender: Sender,
- assets_dir: PathBuf,
+ hostname: String,
+ port: u32,
rust_log: String,
+ send_verification_email: bool,
+ token_key: SymmetricKey,
}
impl Environment {
@@ -41,14 +27,14 @@ impl Environment {
dotenvy::dotenv_iter()
.expect("Missing .env file")
.filter_map(|item| item.ok())
- .filter(|(key, _)| REQUIRED_ENV_VARS.contains(key.as_str()))
.for_each(|(key, value)| match key.as_str() {
+ "ASSETS_DIR" => builder.with_assets_dir(value),
+ "DATABASE_URL" => builder.with_database_url(value),
"HOSTNAME" => builder.with_hostname(value),
"PORT" => builder.with_port(value),
- "TOKEN_KEY" => builder.with_token_key(value),
- "DATABASE_URL" => builder.with_database_url(value),
- "ASSETS_DIR" => builder.with_assets_dir(value),
"RUST_LOG" => builder.with_rust_log(value),
+ "SEND_VERIFICATION_EMAIL" => builder.with_send_verification_email(value),
+ "TOKEN_KEY" => builder.with_token_key(value),
_ => {}
});
@@ -87,41 +73,48 @@ impl Environment {
pub fn rust_log(&self) -> &str {
self.rust_log.as_str()
}
+
+ pub fn send_verification_email(&self) -> bool {
+ self.send_verification_email
+ }
}
impl From for Environment {
fn from(builder: EnvironmentObjectBuilder) -> Self {
let EnvironmentObjectBuilder {
- hostname,
- port,
- token_key,
+ assets_dir,
database_url,
email_sender,
- assets_dir,
+ hostname,
+ port,
rust_log,
+ send_verification,
+ token_key,
} = builder;
Self {
- hostname: hostname.unwrap(),
- port: port.unwrap(),
- token_key: token_key.unwrap(),
+ assets_dir: assets_dir.unwrap(),
database_url: database_url.unwrap(),
email_sender: email_sender.unwrap(),
- assets_dir: assets_dir.unwrap(),
+ hostname: hostname.unwrap(),
+ port: port.unwrap(),
rust_log: rust_log.unwrap(),
+ send_verification_email: send_verification.unwrap_or(true),
+ token_key: token_key.unwrap(),
}
}
}
#[derive(Debug, Default)]
pub struct EnvironmentObjectBuilder {
- pub hostname: Option,
- pub port: Option,
- pub token_key: Option>,
+ pub assets_dir: Option,
pub database_url: Option,
pub email_sender: Option>,
- pub assets_dir: Option,
+ pub hostname: Option,
+ pub port: Option,
pub rust_log: Option,
+ pub send_verification: Option,
+ pub token_key: Option>,
}
impl EnvironmentObjectBuilder {
@@ -199,4 +192,9 @@ impl EnvironmentObjectBuilder {
pub fn with_rust_log(&mut self, rust_log: String) {
self.rust_log = Some(rust_log);
}
+
+ pub fn with_send_verification_email(&mut self, send_verification_email: String) {
+ let send_verification_email = send_verification_email.to_lowercase() == "true";
+ self.send_verification = Some(send_verification_email);
+ }
}
diff --git a/api/src/models/error.rs b/api/src/models/error.rs
index 4bf2487..ff85385 100644
--- a/api/src/models/error.rs
+++ b/api/src/models/error.rs
@@ -116,10 +116,7 @@ enum ErrorKind {
impl IntoResponse for AppError {
fn into_response(self) -> axum::response::Response {
- match &self.kind {
- ErrorKind::DuplicateRecord => (),
- _ => (),
- }
+ 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 49df903..7c9fdb2 100644
--- a/api/src/requests/mod.rs
+++ b/api/src/requests/mod.rs
@@ -1,8 +1,15 @@
mod user;
-use axum::Router;
+use std::time::Duration;
+
+use axum::{
+ extract::{MatchedPath, Request},
+ response::Response,
+ Router,
+};
use tokio::net::TcpListener;
-use tracing::info;
+use tower_http::trace::TraceLayer;
+use tracing::{error, info, info_span, warn, Span};
use crate::{
db::DbPool,
@@ -38,8 +45,31 @@ pub async fn start_app(pool: DbPool, env: Environment) -> Result<(), AppError> {
.await
.unwrap();
+ let logging_layer = TraceLayer::new_for_http()
+ .make_span_with(|request: &Request| {
+ let request_path = request
+ .extensions()
+ .get::()
+ .map(MatchedPath::as_str).unwrap();
+
+ info_span!("http_request", method = %request.method(), path = %request_path, status = tracing::field::Empty)
+ })
+ .on_response(|response: &Response, _duration: Duration, _span: &Span| {
+ let status = response.status();
+
+ _span.record("status", status.to_string());
+
+ match status.as_u16() {
+ w if (300..400).contains(&w) => warn!(""),
+ e if e >= 400 => error!(""),
+ _ => info!("")
+ }
+ });
+
let app_state = AppState::new(pool, env);
- let app = Router::new().merge(user::requests(app_state.clone()));
+ let app = Router::new()
+ .merge(user::requests(app_state.clone()))
+ .layer(logging_layer);
info!("API started successfully.");
axum::serve(listener, app)
diff --git a/api/src/requests/user/create/handler.rs b/api/src/requests/user/create/handler.rs
index 22c051f..0bbc723 100644
--- a/api/src/requests/user/create/handler.rs
+++ b/api/src/requests/user/create/handler.rs
@@ -51,13 +51,15 @@ pub async fn user_registration_post_handler(
auth_token: auth_token.clone(),
};
- let _ = app_state
- .env()
- .email_sender()
- .send(new_user_confirmation_message)
- .inspect_err(|err| {
- eprintln!("Got the rollowing error while sending across the channel: {err}");
- });
+ if app_state.env().send_verification_email() {
+ let _ = app_state
+ .env()
+ .email_sender()
+ .send(new_user_confirmation_message)
+ .inspect_err(|err| {
+ eprintln!("Got the rollowing error while sending across the channel: {err}");
+ });
+ }
let response = (
StatusCode::CREATED,
diff --git a/api/src/services/auth_token.rs b/api/src/services/auth_token.rs
index 376479d..8fa496c 100644
--- a/api/src/services/auth_token.rs
+++ b/api/src/services/auth_token.rs
@@ -104,7 +104,7 @@ fn generate_token(
};
local::encrypt(
- &key,
+ key,
&claims,
Some(&footer),
Some("TODO_ENV_NAME_HERE".as_bytes()),
diff --git a/api/src/services/logger.rs b/api/src/services/logger.rs
index 6a6cb7e..ead58de 100644
--- a/api/src/services/logger.rs
+++ b/api/src/services/logger.rs
@@ -1,18 +1,75 @@
-use tracing::level_filters::LevelFilter;
-use tracing_subscriber::{fmt::time::UtcTime, EnvFilter};
+#![allow(unused)]
+use std::time::SystemTime;
+
+use humantime::format_rfc3339_millis;
+use tracing::{level_filters::LevelFilter, Event, Subscriber};
+use tracing_subscriber::{
+ fmt::{
+ format::{DefaultFields, Writer},
+ FmtContext, FormatEvent, FormatFields, FormattedFields,
+ },
+ registry::{LookupSpan, Scope},
+ EnvFilter,
+};
use crate::models::Environment;
pub fn initialize_logger(env: &Environment) {
let log_level = env.rust_log();
+ #[cfg(debug_assertions)]
+ tracing_subscriber::fmt()
+ .with_env_filter(
+ EnvFilter::builder()
+ .with_default_directive(LevelFilter::TRACE.into())
+ .parse_lossy(log_level),
+ )
+ .event_format(tracing_subscriber::fmt::format().compact())
+ .with_target(false)
+ .with_file(true)
+ .with_line_number(true)
+ .init();
+
+ #[cfg(not(debug_assertions))]
tracing_subscriber::fmt()
.with_env_filter(
EnvFilter::builder()
.with_default_directive(LevelFilter::INFO.into())
.parse_lossy(log_level),
)
- .with_timer(UtcTime::rfc_3339())
- .with_target(false)
+ .event_format(EventFormatter)
+ .fmt_fields(DefaultFields::new())
.init();
}
+
+struct EventFormatter;
+impl FormatEvent for EventFormatter
+where
+ S: Subscriber + for<'a> LookupSpan<'a>,
+ N: for<'a> FormatFields<'a> + 'static,
+{
+ fn format_event(
+ &self,
+ ctx: &FmtContext<'_, S, N>,
+ mut writer: Writer<'_>,
+ event: &Event<'_>,
+ ) -> std::fmt::Result {
+ let timestamp = format_rfc3339_millis(SystemTime::now());
+ let level = event.metadata().level();
+
+ write!(writer, "{timestamp} {level:<5} ")?;
+
+ ctx.field_format().format_fields(writer.by_ref(), event)?;
+
+ for span in ctx.event_scope().into_iter().flat_map(Scope::from_root) {
+ let exts = span.extensions();
+ if let Some(fields) = exts.get::>() {
+ if !fields.is_empty() {
+ write!(writer, "{}", fields.fields)?;
+ }
+ }
+ }
+
+ writeln!(writer)
+ }
+}
diff --git a/api/src/services/mailer/service.rs b/api/src/services/mailer/service.rs
index 703c270..c836207 100644
--- a/api/src/services/mailer/service.rs
+++ b/api/src/services/mailer/service.rs
@@ -1,4 +1,10 @@
-use std::{fs::File, io::Read, path::Path, sync::mpsc::Receiver, thread};
+use std::{
+ fs::File,
+ io::Read,
+ path::Path,
+ sync::{mpsc::Receiver, LazyLock},
+ thread,
+};
use lettre::{
message::{header::ContentType, Mailbox},
@@ -8,21 +14,20 @@ use lettre::{
},
AsyncSmtpTransport, AsyncTransport, Message, Tokio1Executor,
};
-use once_cell::sync::Lazy;
use tokio::runtime::Handle;
use super::UserConfirmationMessage;
-static CREDENTIALS: Lazy = Lazy::new(|| {
+static CREDENTIALS: LazyLock = LazyLock::new(|| {
Credentials::new(
"donotreply@mail.dziura.cloud".to_owned(),
"hunter2".to_owned(),
)
});
-static NUM_CPUS: Lazy = Lazy::new(|| num_cpus::get() as u32);
+static NUM_CPUS: LazyLock = LazyLock::new(|| num_cpus::get() as u32);
-static FROM_MAILBOX: Lazy = Lazy::new(|| {
+static FROM_MAILBOX: LazyLock = LazyLock::new(|| {
"No Not Reply Auth-Test "
.parse()
.unwrap()