Add logging
This commit is contained in:
parent
864ce0c13d
commit
8c6ffbfb5c
11 changed files with 78 additions and 69 deletions
3
api/.env
3
api/.env
|
@ -1,8 +1,7 @@
|
|||
HOSTNAME=localhost
|
||||
PORT=42069
|
||||
DOMAIN=http://api.debtpirate.app
|
||||
RP_ID=debtpirate.app
|
||||
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
|
||||
MAINTENANCE_USER_ACCOUNT=debt_pirate:HRURqlUmtjIy
|
||||
RUST_LOG=debt_pirate=trace
|
||||
|
|
|
@ -1,16 +1,15 @@
|
|||
[package]
|
||||
name = "auth-test"
|
||||
name = "debt-pirate"
|
||||
version = "0.1.0"
|
||||
edition = "2021"
|
||||
|
||||
[dependencies]
|
||||
argon2 = "0.5"
|
||||
axum = { version = "0.7", features = [
|
||||
"default",
|
||||
"macros",
|
||||
"multipart",
|
||||
"ws",
|
||||
], default-features = false }
|
||||
] }
|
||||
base64 = "0.22"
|
||||
dotenvy = "0.15"
|
||||
futures = "0.3"
|
||||
|
@ -39,7 +38,10 @@ sqlx = { version = "0.8", features = [
|
|||
"postgres",
|
||||
"runtime-tokio",
|
||||
] }
|
||||
syslog-tracing = "0.3.1"
|
||||
tokio = { version = "1.35", features = ["full"] }
|
||||
tower = "0.5"
|
||||
tower-http = { version = "0.6", features = ["full"] }
|
||||
tracing = "0.1.40"
|
||||
tracing-subscriber = { version = "0.3.18", features = ["env-filter", "time"] }
|
||||
uuid = { version = "1.10", features = ["serde", "v7"] }
|
||||
|
|
|
@ -9,8 +9,9 @@ mod services;
|
|||
|
||||
use db::{create_connection_pool, run_migrations};
|
||||
use requests::start_app;
|
||||
use services::{start_emailer_service, UserConfirmationMessage};
|
||||
use services::{initialize_logger, start_emailer_service, UserConfirmationMessage};
|
||||
use tokio::runtime::Handle;
|
||||
use tracing::info;
|
||||
|
||||
#[tokio::main]
|
||||
async fn main() {
|
||||
|
@ -24,13 +25,22 @@ async fn main() {
|
|||
}
|
||||
};
|
||||
|
||||
initialize_logger(&env);
|
||||
|
||||
info!("Initializing database connection pool...");
|
||||
let pool = create_connection_pool(env.db_connection_uri()).await;
|
||||
info!("Database connection pool created successfully.");
|
||||
|
||||
info!("Running database schema migrations...");
|
||||
if let Err(err) = run_migrations(&pool).await {
|
||||
eprintln!("{err:?}");
|
||||
process::exit(2);
|
||||
}
|
||||
info!("Database schema migrations completed successfully.");
|
||||
|
||||
info!("Starting email sender service...");
|
||||
start_emailer_service(Handle::current(), env.assets_dir(), rx);
|
||||
info!("Email service started successfully.");
|
||||
|
||||
if let Err(err) = start_app(pool, env).await {
|
||||
eprintln!("{err:?}");
|
||||
|
|
|
@ -15,11 +15,10 @@ static REQUIRED_ENV_VARS: Lazy<HashSet<&'static str>> = Lazy::new(|| {
|
|||
[
|
||||
"HOSTNAME",
|
||||
"PORT",
|
||||
"DOMAIN",
|
||||
"RP_ID",
|
||||
"TOKEN_KEY",
|
||||
"DATABASE_URL",
|
||||
"ASSETS_DIR",
|
||||
"RUST_LOG",
|
||||
]
|
||||
.into_iter()
|
||||
.collect()
|
||||
|
@ -29,12 +28,11 @@ static REQUIRED_ENV_VARS: Lazy<HashSet<&'static str>> = Lazy::new(|| {
|
|||
pub struct Environment {
|
||||
hostname: String,
|
||||
port: u32,
|
||||
domain: String,
|
||||
rp_id: String,
|
||||
token_key: SymmetricKey<V4>,
|
||||
database_url: String,
|
||||
email_sender: Sender<UserConfirmationMessage>,
|
||||
assets_dir: PathBuf,
|
||||
rust_log: String,
|
||||
}
|
||||
|
||||
impl Environment {
|
||||
|
@ -47,11 +45,10 @@ impl Environment {
|
|||
.for_each(|(key, value)| match key.as_str() {
|
||||
"HOSTNAME" => builder.with_hostname(value),
|
||||
"PORT" => builder.with_port(value),
|
||||
"DOMAIN" => builder.with_domain(value),
|
||||
"RP_ID" => builder.with_rp_id(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),
|
||||
_ => {}
|
||||
});
|
||||
|
||||
|
@ -71,14 +68,6 @@ impl Environment {
|
|||
self.port
|
||||
}
|
||||
|
||||
pub fn domain(&self) -> &str {
|
||||
self.domain.as_str()
|
||||
}
|
||||
|
||||
pub fn rp_id(&self) -> &str {
|
||||
self.rp_id.as_str()
|
||||
}
|
||||
|
||||
pub fn token_key(&self) -> &SymmetricKey<V4> {
|
||||
&self.token_key
|
||||
}
|
||||
|
@ -94,6 +83,10 @@ impl Environment {
|
|||
pub fn email_sender(&self) -> &Sender<UserConfirmationMessage> {
|
||||
&self.email_sender
|
||||
}
|
||||
|
||||
pub fn rust_log(&self) -> &str {
|
||||
self.rust_log.as_str()
|
||||
}
|
||||
}
|
||||
|
||||
impl From<EnvironmentObjectBuilder> for Environment {
|
||||
|
@ -101,23 +94,21 @@ impl From<EnvironmentObjectBuilder> for Environment {
|
|||
let EnvironmentObjectBuilder {
|
||||
hostname,
|
||||
port,
|
||||
domain,
|
||||
rp_id,
|
||||
token_key,
|
||||
database_url,
|
||||
email_sender,
|
||||
assets_dir,
|
||||
rust_log,
|
||||
} = builder;
|
||||
|
||||
Self {
|
||||
hostname: hostname.unwrap(),
|
||||
port: port.unwrap(),
|
||||
domain: domain.unwrap(),
|
||||
rp_id: rp_id.unwrap(),
|
||||
token_key: token_key.unwrap(),
|
||||
database_url: database_url.unwrap(),
|
||||
email_sender: email_sender.unwrap(),
|
||||
assets_dir: assets_dir.unwrap(),
|
||||
rust_log: rust_log.unwrap(),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -126,12 +117,11 @@ impl From<EnvironmentObjectBuilder> for Environment {
|
|||
pub struct EnvironmentObjectBuilder {
|
||||
pub hostname: Option<String>,
|
||||
pub port: Option<u32>,
|
||||
pub domain: Option<String>,
|
||||
pub rp_id: Option<String>,
|
||||
pub token_key: Option<SymmetricKey<V4>>,
|
||||
pub database_url: Option<String>,
|
||||
pub email_sender: Option<Sender<UserConfirmationMessage>>,
|
||||
pub assets_dir: Option<PathBuf>,
|
||||
pub rust_log: Option<String>,
|
||||
}
|
||||
|
||||
impl EnvironmentObjectBuilder {
|
||||
|
@ -145,9 +135,8 @@ impl EnvironmentObjectBuilder {
|
|||
pub fn uninitialized_variables(&self) -> Option<Vec<&'static str>> {
|
||||
let mut missing_vars = [
|
||||
("HOSTNAME", self.hostname.as_deref()),
|
||||
("DOMAIN", self.domain.as_deref()),
|
||||
("RP_ID", self.rp_id.as_deref()),
|
||||
("DATABASE_URL", self.database_url.as_deref()),
|
||||
("RUST_LOG", self.rust_log.as_deref()),
|
||||
]
|
||||
.into_iter()
|
||||
.filter_map(|(key, value)| value.map(|_| key).xor(Some(key)))
|
||||
|
@ -181,14 +170,6 @@ impl EnvironmentObjectBuilder {
|
|||
self.port = port;
|
||||
}
|
||||
|
||||
pub fn with_domain(&mut self, domain: String) {
|
||||
self.domain = Some(domain);
|
||||
}
|
||||
|
||||
pub fn with_rp_id(&mut self, rp_id: String) {
|
||||
self.rp_id = Some(rp_id);
|
||||
}
|
||||
|
||||
pub fn with_token_key(&mut self, key: String) {
|
||||
match SymmetricKey::<V4>::try_from(key.as_str()).map_err(|_| AppError::token_key()) {
|
||||
Ok(key) => self.token_key = Some(key),
|
||||
|
@ -214,4 +195,8 @@ impl EnvironmentObjectBuilder {
|
|||
|
||||
self.assets_dir = Some(assets_dir);
|
||||
}
|
||||
|
||||
pub fn with_rust_log(&mut self, rust_log: String) {
|
||||
self.rust_log = Some(rust_log);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -2,6 +2,7 @@ mod user;
|
|||
|
||||
use axum::Router;
|
||||
use tokio::net::TcpListener;
|
||||
use tracing::info;
|
||||
|
||||
use crate::{
|
||||
db::DbPool,
|
||||
|
@ -31,6 +32,8 @@ impl AppState {
|
|||
pub async fn start_app(pool: DbPool, env: Environment) -> Result<(), AppError> {
|
||||
let address = env.hostname();
|
||||
let port = env.port();
|
||||
|
||||
info!("Listening on {address}:{port}...");
|
||||
let listener = TcpListener::bind(format!("{address}:{port}"))
|
||||
.await
|
||||
.unwrap();
|
||||
|
@ -38,6 +41,7 @@ pub async fn start_app(pool: DbPool, env: Environment) -> Result<(), AppError> {
|
|||
let app_state = AppState::new(pool, env);
|
||||
let app = Router::new().merge(user::requests(app_state.clone()));
|
||||
|
||||
info!("API started successfully.");
|
||||
axum::serve(listener, app)
|
||||
.await
|
||||
.map_err(AppError::app_startup)?;
|
||||
|
|
|
@ -1,10 +1,8 @@
|
|||
use std::time::Duration;
|
||||
|
||||
use crate::{
|
||||
db::{insert_new_user, NewUserEntity, UserEntity},
|
||||
models::ApiResponse,
|
||||
requests::AppState,
|
||||
services::{auth_token::generate_token, hash_string, UserConfirmationMessage},
|
||||
services::{auth_token::generate_new_user_token, hash_string, UserConfirmationMessage},
|
||||
};
|
||||
use axum::{
|
||||
extract::State,
|
||||
|
@ -15,8 +13,6 @@ use http::StatusCode;
|
|||
|
||||
use super::models::{UserRegistrationRequest, UserRegistrationResponse};
|
||||
|
||||
static FIFTEEN_MINUTES: u64 = 60 * 15;
|
||||
|
||||
pub async fn user_registration_post_handler(
|
||||
State(app_state): State<AppState>,
|
||||
Json(request): Json<UserRegistrationRequest>,
|
||||
|
@ -47,15 +43,13 @@ pub async fn user_registration_post_handler(
|
|||
})?;
|
||||
|
||||
let signing_key = app_state.env().token_key();
|
||||
let (auth_token, expiration) = generate_token(
|
||||
signing_key,
|
||||
user_id,
|
||||
Some(Duration::from_secs(FIFTEEN_MINUTES)),
|
||||
Some("user-verify.debtpirate.bikeshedengineering.internal"),
|
||||
);
|
||||
let (auth_token, expiration) = generate_new_user_token(signing_key, user_id);
|
||||
|
||||
let new_user_confirmation_message =
|
||||
UserConfirmationMessage::new(email.as_str(), name.as_str(), auth_token.as_str());
|
||||
let new_user_confirmation_message = UserConfirmationMessage {
|
||||
email: email.clone(),
|
||||
name: name.clone(),
|
||||
auth_token: auth_token.clone(),
|
||||
};
|
||||
|
||||
let _ = app_state
|
||||
.env()
|
||||
|
|
|
@ -12,8 +12,9 @@ use uuid::Uuid;
|
|||
|
||||
use crate::models::AppError;
|
||||
|
||||
static FOURTY_FIVE_DAYS: u64 = 3_888_000; // 60 * 60 * 24 * 45
|
||||
static ONE_HOUR: u64 = 3_600;
|
||||
static FOURTY_FIVE_DAYS: Duration = Duration::from_secs(3_888_000);
|
||||
static ONE_HOUR: Duration = Duration::from_secs(3_600);
|
||||
static FIFTEEN_MINUTES: Duration = Duration::from_secs(900);
|
||||
|
||||
pub fn verify_token(
|
||||
key: &SymmetricKey<V4>,
|
||||
|
@ -47,19 +48,23 @@ pub fn verify_token(
|
|||
}
|
||||
|
||||
pub fn generate_access_token(key: &SymmetricKey<V4>, user_id: i32) -> (String, SystemTime) {
|
||||
generate_token(
|
||||
key,
|
||||
user_id,
|
||||
Some(Duration::from_secs(FOURTY_FIVE_DAYS)),
|
||||
None,
|
||||
)
|
||||
generate_token(key, user_id, Some(FOURTY_FIVE_DAYS), None)
|
||||
}
|
||||
|
||||
pub fn generate_auth_token(key: &SymmetricKey<V4>, user_id: i32) -> (String, SystemTime) {
|
||||
generate_token(key, user_id, None, None)
|
||||
}
|
||||
|
||||
pub fn generate_token(
|
||||
pub fn generate_new_user_token(key: &SymmetricKey<V4>, user_id: i32) -> (String, SystemTime) {
|
||||
generate_token(
|
||||
key,
|
||||
user_id,
|
||||
Some(FIFTEEN_MINUTES),
|
||||
Some(format!("api.debtpirate.bikeshedengineering.internal/user/{user_id}/verify").as_str()),
|
||||
)
|
||||
}
|
||||
|
||||
fn generate_token(
|
||||
key: &SymmetricKey<V4>,
|
||||
user_id: i32,
|
||||
duration: Option<Duration>,
|
||||
|
@ -69,7 +74,7 @@ pub fn generate_token(
|
|||
let expiration = if let Some(duration) = duration {
|
||||
duration
|
||||
} else {
|
||||
Duration::from_secs(ONE_HOUR)
|
||||
ONE_HOUR
|
||||
};
|
||||
|
||||
let token = Claims::new_expires_in(&expiration)
|
||||
|
|
18
api/src/services/logger.rs
Normal file
18
api/src/services/logger.rs
Normal file
|
@ -0,0 +1,18 @@
|
|||
use tracing::level_filters::LevelFilter;
|
||||
use tracing_subscriber::{fmt::time::UtcTime, EnvFilter};
|
||||
|
||||
use crate::models::Environment;
|
||||
|
||||
pub fn initialize_logger(env: &Environment) {
|
||||
let log_level = env.rust_log();
|
||||
|
||||
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)
|
||||
.init();
|
||||
}
|
|
@ -3,13 +3,3 @@ pub struct UserConfirmationMessage {
|
|||
pub name: String,
|
||||
pub auth_token: String,
|
||||
}
|
||||
|
||||
impl UserConfirmationMessage {
|
||||
pub fn new(email: &str, name: &str, auth_token: &str) -> Self {
|
||||
Self {
|
||||
email: email.to_owned(),
|
||||
name: name.to_owned(),
|
||||
auth_token: auth_token.to_owned(),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1,6 +1,8 @@
|
|||
pub mod auth_token;
|
||||
mod hasher;
|
||||
mod logger;
|
||||
mod mailer;
|
||||
|
||||
pub use hasher::*;
|
||||
pub use logger::*;
|
||||
pub use mailer::*;
|
||||
|
|
Loading…
Add table
Reference in a new issue