Add proper logging
This commit is contained in:
parent
9ab0cb2a6e
commit
1c77822b49
75
Cargo.lock
generated
75
Cargo.lock
generated
|
@ -31,6 +31,15 @@ dependencies = [
|
||||||
"libc",
|
"libc",
|
||||||
]
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "ansi_term"
|
||||||
|
version = "0.12.1"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "d52a9bb7ec0cf484c551830a7ce27bd20d67eac647e1befb56b0be4ee39a55d2"
|
||||||
|
dependencies = [
|
||||||
|
"winapi",
|
||||||
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "anyhow"
|
name = "anyhow"
|
||||||
version = "1.0.61"
|
version = "1.0.61"
|
||||||
|
@ -937,6 +946,15 @@ dependencies = [
|
||||||
"cfg-if 1.0.0",
|
"cfg-if 1.0.0",
|
||||||
]
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "matchers"
|
||||||
|
version = "0.1.0"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "8263075bb86c5a1b1427b5ae862e8889656f126e9f77c484496e8b47cf5c5558"
|
||||||
|
dependencies = [
|
||||||
|
"regex-automata",
|
||||||
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "matches"
|
name = "matches"
|
||||||
version = "0.1.9"
|
version = "0.1.9"
|
||||||
|
@ -1382,6 +1400,15 @@ dependencies = [
|
||||||
"regex-syntax",
|
"regex-syntax",
|
||||||
]
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "regex-automata"
|
||||||
|
version = "0.1.10"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "6c230d73fb8d8c1b9c0b3135c5142a8acee3a0558fb8db5cf1cb65f8d7862132"
|
||||||
|
dependencies = [
|
||||||
|
"regex-syntax",
|
||||||
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "regex-syntax"
|
name = "regex-syntax"
|
||||||
version = "0.6.27"
|
version = "0.6.27"
|
||||||
|
@ -1533,6 +1560,15 @@ dependencies = [
|
||||||
"digest 0.10.3",
|
"digest 0.10.3",
|
||||||
]
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "sharded-slab"
|
||||||
|
version = "0.1.4"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "900fba806f70c630b0a382d0d825e17a0f19fcd059a2ade1ff237bcddf446b31"
|
||||||
|
dependencies = [
|
||||||
|
"lazy_static",
|
||||||
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "signal-hook-registry"
|
name = "signal-hook-registry"
|
||||||
version = "1.4.0"
|
version = "1.4.0"
|
||||||
|
@ -1826,6 +1862,8 @@ dependencies = [
|
||||||
"toml",
|
"toml",
|
||||||
"tower",
|
"tower",
|
||||||
"tower-http",
|
"tower-http",
|
||||||
|
"tracing",
|
||||||
|
"tracing-subscriber",
|
||||||
]
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
|
@ -1943,6 +1981,7 @@ dependencies = [
|
||||||
"tower",
|
"tower",
|
||||||
"tower-layer",
|
"tower-layer",
|
||||||
"tower-service",
|
"tower-service",
|
||||||
|
"tracing",
|
||||||
]
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
|
@ -1988,6 +2027,36 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "5aeea4303076558a00714b823f9ad67d58a3bbda1df83d8827d21193156e22f7"
|
checksum = "5aeea4303076558a00714b823f9ad67d58a3bbda1df83d8827d21193156e22f7"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"once_cell",
|
"once_cell",
|
||||||
|
"valuable",
|
||||||
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "tracing-log"
|
||||||
|
version = "0.1.3"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "78ddad33d2d10b1ed7eb9d1f518a5674713876e97e5bb9b7345a7984fbb4f922"
|
||||||
|
dependencies = [
|
||||||
|
"lazy_static",
|
||||||
|
"log",
|
||||||
|
"tracing-core",
|
||||||
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "tracing-subscriber"
|
||||||
|
version = "0.3.15"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "60db860322da191b40952ad9affe65ea23e7dd6a5c442c2c42865810c6ab8e6b"
|
||||||
|
dependencies = [
|
||||||
|
"ansi_term",
|
||||||
|
"matchers",
|
||||||
|
"once_cell",
|
||||||
|
"regex",
|
||||||
|
"sharded-slab",
|
||||||
|
"smallvec",
|
||||||
|
"thread_local",
|
||||||
|
"tracing",
|
||||||
|
"tracing-core",
|
||||||
|
"tracing-log",
|
||||||
]
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
|
@ -2127,6 +2196,12 @@ dependencies = [
|
||||||
"percent-encoding",
|
"percent-encoding",
|
||||||
]
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "valuable"
|
||||||
|
version = "0.1.0"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "830b7e5d4d90034032940e4ace0d9a9a057e7a45cd94e6c007832e39edb82f6d"
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "version_check"
|
name = "version_check"
|
||||||
version = "0.9.4"
|
version = "0.9.4"
|
||||||
|
|
|
@ -18,6 +18,8 @@ thiserror = "1.0.32"
|
||||||
tokio = { version = "1.20.1", features = ["full"] }
|
tokio = { version = "1.20.1", features = ["full"] }
|
||||||
toml = "0.5.9"
|
toml = "0.5.9"
|
||||||
tower = "0.4.13"
|
tower = "0.4.13"
|
||||||
tower-http = { version = "0.3.4", features = ["fs"] }
|
tower-http = { version = "0.3.4", features = ["fs", "trace"] }
|
||||||
|
tracing = "0.1.36"
|
||||||
|
tracing-subscriber = { version = "0.3.15", features = ["env-filter"] }
|
||||||
|
|
||||||
[features]
|
[features]
|
||||||
|
|
40
src/main.rs
40
src/main.rs
|
@ -20,6 +20,7 @@ use axum_sessions::{async_session::MemoryStore, SessionLayer};
|
||||||
use serde::Deserialize;
|
use serde::Deserialize;
|
||||||
use sqlx::postgres::PgPoolOptions;
|
use sqlx::postgres::PgPoolOptions;
|
||||||
use sqlx::{Pool, Postgres};
|
use sqlx::{Pool, Postgres};
|
||||||
|
use std::net::SocketAddr;
|
||||||
use std::sync::Arc;
|
use std::sync::Arc;
|
||||||
use tasks::RawTask;
|
use tasks::RawTask;
|
||||||
use tasks::Task;
|
use tasks::Task;
|
||||||
|
@ -27,6 +28,10 @@ use tera::Tera;
|
||||||
use thiserror::Error as ThisError;
|
use thiserror::Error as ThisError;
|
||||||
use tower::ServiceBuilder;
|
use tower::ServiceBuilder;
|
||||||
use tower_http::services::ServeDir;
|
use tower_http::services::ServeDir;
|
||||||
|
use tower_http::trace::TraceLayer;
|
||||||
|
use tracing::info;
|
||||||
|
use tracing_subscriber::EnvFilter;
|
||||||
|
use tracing_subscriber::FmtSubscriber;
|
||||||
|
|
||||||
#[derive(ThisError, Debug)]
|
#[derive(ThisError, Debug)]
|
||||||
pub enum Error {
|
pub enum Error {
|
||||||
|
@ -97,27 +102,42 @@ pub struct Config {
|
||||||
connection_string: String,
|
connection_string: String,
|
||||||
template_dir: Option<String>,
|
template_dir: Option<String>,
|
||||||
static_dir: Option<std::path::PathBuf>,
|
static_dir: Option<std::path::PathBuf>,
|
||||||
|
address: Option<SocketAddr>,
|
||||||
}
|
}
|
||||||
|
|
||||||
#[tokio::main]
|
#[tokio::main]
|
||||||
async fn main() -> Result<(), Error> {
|
async fn main() -> Result<(), Error> {
|
||||||
|
let subscriber = FmtSubscriber::builder()
|
||||||
|
.with_env_filter(EnvFilter::from_env("TMTD_LOG"))
|
||||||
|
.with_ansi(true)
|
||||||
|
.with_file(true)
|
||||||
|
.with_line_number(true)
|
||||||
|
.finish();
|
||||||
|
|
||||||
|
tracing::subscriber::set_global_default(subscriber).unwrap();
|
||||||
|
|
||||||
let filename = std::env::var("TMTD_CONFIG").unwrap_or_else(|_| "config.toml".into());
|
let filename = std::env::var("TMTD_CONFIG").unwrap_or_else(|_| "config.toml".into());
|
||||||
|
info!("Loading file {}", filename);
|
||||||
let contents = std::fs::read_to_string(filename)?;
|
let contents = std::fs::read_to_string(filename)?;
|
||||||
let config: Config = toml::from_str(&contents)?;
|
let config: Config = toml::from_str(&contents)?;
|
||||||
|
info!("Config loaded, connecting to database...");
|
||||||
let pool = Arc::new(
|
let pool = Arc::new(
|
||||||
PgPoolOptions::new()
|
PgPoolOptions::new()
|
||||||
.connect(&config.connection_string)
|
.connect(&config.connection_string)
|
||||||
.await?,
|
.await?,
|
||||||
);
|
);
|
||||||
|
|
||||||
|
info!("Creating default tables (if needed)");
|
||||||
sqlx::query("create table if not exists users(id serial primary key, username text not null unique, password_hash text not null)").execute(&*pool).await?;
|
sqlx::query("create table if not exists users(id serial primary key, username text not null unique, password_hash text not null)").execute(&*pool).await?;
|
||||||
sqlx::query("create table if not exists tasks(id serial primary key, owner int not null, title text not null, description text not null, status int not null)").execute(&*pool).await?;
|
sqlx::query("create table if not exists tasks(id serial primary key, owner int not null, title text not null, description text not null, status int not null)").execute(&*pool).await?;
|
||||||
|
|
||||||
|
info!("Loading templates...");
|
||||||
let tera = Arc::new(Tera::new(&format!(
|
let tera = Arc::new(Tera::new(&format!(
|
||||||
"{}/**/*.html",
|
"{}/**/*.html",
|
||||||
config.template_dir.as_deref().unwrap_or("templates")
|
config.template_dir.as_deref().unwrap_or("templates")
|
||||||
))?);
|
))?);
|
||||||
|
|
||||||
|
info!("Creating session layer");
|
||||||
let store = MemoryStore::new();
|
let store = MemoryStore::new();
|
||||||
if config.secret.len() < 64 {
|
if config.secret.len() < 64 {
|
||||||
return Err("Secret must be at least 64 bytes!".to_string().into());
|
return Err("Secret must be at least 64 bytes!".to_string().into());
|
||||||
|
@ -154,10 +174,16 @@ async fn main() -> Result<(), Error> {
|
||||||
ServiceBuilder::new()
|
ServiceBuilder::new()
|
||||||
.layer(Extension(pool))
|
.layer(Extension(pool))
|
||||||
.layer(Extension(tera))
|
.layer(Extension(tera))
|
||||||
.layer(session_layer),
|
.layer(session_layer)
|
||||||
|
.layer(TraceLayer::new_for_http()),
|
||||||
);
|
);
|
||||||
|
|
||||||
axum::Server::bind(&"0.0.0.0:3000".parse().unwrap())
|
info!("Starting server...");
|
||||||
|
let address = config
|
||||||
|
.address
|
||||||
|
.unwrap_or_else(|| "0.0.0.0:3000".parse().unwrap());
|
||||||
|
info!("Server started on {}", address);
|
||||||
|
axum::Server::bind(&address)
|
||||||
.serve(app.into_make_service())
|
.serve(app.into_make_service())
|
||||||
.await
|
.await
|
||||||
.unwrap();
|
.unwrap();
|
||||||
|
@ -170,7 +196,10 @@ macro_rules! login_or_redirect {
|
||||||
($session:expr, $to:literal) => {
|
($session:expr, $to:literal) => {
|
||||||
match $session.get::<String>("logged_in_as") {
|
match $session.get::<String>("logged_in_as") {
|
||||||
Some(username) => username,
|
Some(username) => username,
|
||||||
None => return Err(::axum::response::Redirect::to($to).into()),
|
None => {
|
||||||
|
::tracing::warn!("User not logged in, redirecting to {}", $to);
|
||||||
|
return Err(::axum::response::Redirect::to($to).into());
|
||||||
|
}
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
@ -195,21 +224,25 @@ async fn homepage(
|
||||||
) -> Result<Html<String>, Error> {
|
) -> Result<Html<String>, Error> {
|
||||||
let username = login_or_redirect!(session, "/login");
|
let username = login_or_redirect!(session, "/login");
|
||||||
|
|
||||||
|
info!("Getting user ID...");
|
||||||
let (id,): (i32,) = sqlx::query_as("select id from users where username=$1")
|
let (id,): (i32,) = sqlx::query_as("select id from users where username=$1")
|
||||||
.bind(&username)
|
.bind(&username)
|
||||||
.fetch_one(&*pool)
|
.fetch_one(&*pool)
|
||||||
.await?;
|
.await?;
|
||||||
|
|
||||||
|
info!("Getting tasks");
|
||||||
let tasks: Vec<RawTask> =
|
let tasks: Vec<RawTask> =
|
||||||
sqlx::query_as("select id,title,description,status from tasks where owner=$1")
|
sqlx::query_as("select id,title,description,status from tasks where owner=$1")
|
||||||
.bind(id)
|
.bind(id)
|
||||||
.fetch_all(&*pool)
|
.fetch_all(&*pool)
|
||||||
.await?;
|
.await?;
|
||||||
|
|
||||||
|
info!("Sorting tasks");
|
||||||
let mut tasks: Vec<Task> = tasks.into_iter().map(Task::from).collect();
|
let mut tasks: Vec<Task> = tasks.into_iter().map(Task::from).collect();
|
||||||
tasks.sort_unstable();
|
tasks.sort_unstable();
|
||||||
tasks.reverse();
|
tasks.reverse();
|
||||||
|
|
||||||
|
info!("rendering pagee");
|
||||||
let rendered = tera.render(
|
let rendered = tera.render(
|
||||||
"home.html",
|
"home.html",
|
||||||
&ctx! {
|
&ctx! {
|
||||||
|
@ -217,5 +250,6 @@ async fn homepage(
|
||||||
},
|
},
|
||||||
)?;
|
)?;
|
||||||
|
|
||||||
|
info!("Rendering finished");
|
||||||
Ok(Html(rendered))
|
Ok(Html(rendered))
|
||||||
}
|
}
|
||||||
|
|
12
src/tasks.rs
12
src/tasks.rs
|
@ -16,6 +16,7 @@ use sqlx::FromRow;
|
||||||
use sqlx::{Pool, Postgres};
|
use sqlx::{Pool, Postgres};
|
||||||
use std::sync::Arc;
|
use std::sync::Arc;
|
||||||
use tera::Tera;
|
use tera::Tera;
|
||||||
|
use tracing::info;
|
||||||
|
|
||||||
#[derive(Deserialize)]
|
#[derive(Deserialize)]
|
||||||
pub struct BareTask {
|
pub struct BareTask {
|
||||||
|
@ -101,11 +102,13 @@ pub async fn update_form(
|
||||||
) -> Result<Html<String>, Error> {
|
) -> Result<Html<String>, Error> {
|
||||||
let username = login_or_redirect!(session, "/login");
|
let username = login_or_redirect!(session, "/login");
|
||||||
|
|
||||||
|
info!("Getting user id");
|
||||||
let (user_id,): (i32,) = sqlx::query_as("select id from users where username=$1")
|
let (user_id,): (i32,) = sqlx::query_as("select id from users where username=$1")
|
||||||
.bind(&username)
|
.bind(&username)
|
||||||
.fetch_one(&*pool)
|
.fetch_one(&*pool)
|
||||||
.await?;
|
.await?;
|
||||||
|
|
||||||
|
info!("Getting task");
|
||||||
let task: Option<RawTask> =
|
let task: Option<RawTask> =
|
||||||
sqlx::query_as("select id,title,description,status from tasks where id=$1 and owner=$2")
|
sqlx::query_as("select id,title,description,status from tasks where id=$1 and owner=$2")
|
||||||
.bind(id)
|
.bind(id)
|
||||||
|
@ -114,6 +117,7 @@ pub async fn update_form(
|
||||||
.await?;
|
.await?;
|
||||||
|
|
||||||
if let Some(task) = task {
|
if let Some(task) = task {
|
||||||
|
info!("Rendering template");
|
||||||
let c = ctx! {
|
let c = ctx! {
|
||||||
"task" => task,
|
"task" => task,
|
||||||
"url" => uri.to_string()
|
"url" => uri.to_string()
|
||||||
|
@ -121,6 +125,7 @@ pub async fn update_form(
|
||||||
|
|
||||||
let rendered = tera.render("tasks/update.html", &c)?;
|
let rendered = tera.render("tasks/update.html", &c)?;
|
||||||
|
|
||||||
|
info!("Rendering finished, returning");
|
||||||
#[allow(clippy::needless_return)] // it's a compile error, clippy
|
#[allow(clippy::needless_return)] // it's a compile error, clippy
|
||||||
return Ok(Html(rendered));
|
return Ok(Html(rendered));
|
||||||
}
|
}
|
||||||
|
@ -167,11 +172,13 @@ pub async fn create_backend(
|
||||||
) -> Result<Redirect, Error> {
|
) -> Result<Redirect, Error> {
|
||||||
let username = login_or_redirect!(session, "/login");
|
let username = login_or_redirect!(session, "/login");
|
||||||
|
|
||||||
|
info!("Getting user id");
|
||||||
let (user_id,): (i32,) = sqlx::query_as("select id from users where username=$1")
|
let (user_id,): (i32,) = sqlx::query_as("select id from users where username=$1")
|
||||||
.bind(&username)
|
.bind(&username)
|
||||||
.fetch_one(&*pool)
|
.fetch_one(&*pool)
|
||||||
.await?;
|
.await?;
|
||||||
|
|
||||||
|
info!("Inserting task...");
|
||||||
let (id,): (i32,) = sqlx::query_as(
|
let (id,): (i32,) = sqlx::query_as(
|
||||||
"insert into tasks (owner,title, description, status) values ($1, $2, $3, $4) returning id",
|
"insert into tasks (owner,title, description, status) values ($1, $2, $3, $4) returning id",
|
||||||
)
|
)
|
||||||
|
@ -182,6 +189,7 @@ pub async fn create_backend(
|
||||||
.fetch_one(&*pool)
|
.fetch_one(&*pool)
|
||||||
.await?;
|
.await?;
|
||||||
|
|
||||||
|
info!("Done, redirecting");
|
||||||
Ok(Redirect::to(&format!("/tasks/{}", id)))
|
Ok(Redirect::to(&format!("/tasks/{}", id)))
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -193,11 +201,13 @@ pub async fn task_detail(
|
||||||
) -> Result<Html<String>, Error> {
|
) -> Result<Html<String>, Error> {
|
||||||
let username = login_or_redirect!(session, "/login");
|
let username = login_or_redirect!(session, "/login");
|
||||||
|
|
||||||
|
info!("Getting user id");
|
||||||
let (user_id,): (i32,) = sqlx::query_as("select id from users where username=$1")
|
let (user_id,): (i32,) = sqlx::query_as("select id from users where username=$1")
|
||||||
.bind(&username)
|
.bind(&username)
|
||||||
.fetch_one(&*pool)
|
.fetch_one(&*pool)
|
||||||
.await?;
|
.await?;
|
||||||
|
|
||||||
|
info!("Getting task");
|
||||||
let task: Option<RawTask> =
|
let task: Option<RawTask> =
|
||||||
sqlx::query_as("select id,title,description,status from tasks where id=$1 and owner=$2")
|
sqlx::query_as("select id,title,description,status from tasks where id=$1 and owner=$2")
|
||||||
.bind(id)
|
.bind(id)
|
||||||
|
@ -206,12 +216,14 @@ pub async fn task_detail(
|
||||||
.await?;
|
.await?;
|
||||||
|
|
||||||
if let Some(task) = task.map(Task::from) {
|
if let Some(task) = task.map(Task::from) {
|
||||||
|
info!("Rendering");
|
||||||
let c = ctx! {
|
let c = ctx! {
|
||||||
"task" => task
|
"task" => task
|
||||||
};
|
};
|
||||||
|
|
||||||
let rendered = tera.render("tasks/detail.html", &c)?;
|
let rendered = tera.render("tasks/detail.html", &c)?;
|
||||||
|
|
||||||
|
info!("Rendering complete, returning");
|
||||||
return Ok(Html(rendered));
|
return Ok(Html(rendered));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
14
src/users.rs
14
src/users.rs
|
@ -14,6 +14,8 @@ use sqlx::{Pool, Postgres};
|
||||||
use std::sync::Arc;
|
use std::sync::Arc;
|
||||||
use tera::Context;
|
use tera::Context;
|
||||||
use tera::Tera;
|
use tera::Tera;
|
||||||
|
use tracing::info;
|
||||||
|
use tracing::warn;
|
||||||
|
|
||||||
#[derive(Clone, Debug, Deserialize)]
|
#[derive(Clone, Debug, Deserialize)]
|
||||||
pub struct RawUser {
|
pub struct RawUser {
|
||||||
|
@ -26,6 +28,7 @@ pub async fn create_user(
|
||||||
Extension(pool): Extension<Arc<Pool<Postgres>>>,
|
Extension(pool): Extension<Arc<Pool<Postgres>>>,
|
||||||
) -> Result<Redirect, Error> {
|
) -> Result<Redirect, Error> {
|
||||||
let handle = tokio::task::spawn_blocking(move || {
|
let handle = tokio::task::spawn_blocking(move || {
|
||||||
|
info!("Encrypting password");
|
||||||
let salt = SaltString::generate(&mut OsRng);
|
let salt = SaltString::generate(&mut OsRng);
|
||||||
let password_hash = Pbkdf2.hash_password(data.password.as_bytes(), &salt);
|
let password_hash = Pbkdf2.hash_password(data.password.as_bytes(), &salt);
|
||||||
|
|
||||||
|
@ -34,6 +37,7 @@ pub async fn create_user(
|
||||||
|
|
||||||
let hash = handle.await??;
|
let hash = handle.await??;
|
||||||
|
|
||||||
|
info!("Inserting into database");
|
||||||
sqlx::query("INSERT INTO users (username, password_hash) VALUES ($1, $2)")
|
sqlx::query("INSERT INTO users (username, password_hash) VALUES ($1, $2)")
|
||||||
.bind(data.username)
|
.bind(data.username)
|
||||||
.bind(hash)
|
.bind(hash)
|
||||||
|
@ -48,17 +52,20 @@ pub async fn login_backend(
|
||||||
Extension(pool): Extension<Arc<Pool<Postgres>>>,
|
Extension(pool): Extension<Arc<Pool<Postgres>>>,
|
||||||
mut session: WritableSession,
|
mut session: WritableSession,
|
||||||
) -> Result<Redirect, Error> {
|
) -> Result<Redirect, Error> {
|
||||||
|
info!("Fetching user hash");
|
||||||
let hash: Option<(String,)> =
|
let hash: Option<(String,)> =
|
||||||
sqlx::query_as("SELECT password_hash FROM users WHERE username=$1")
|
sqlx::query_as("SELECT password_hash FROM users WHERE username=$1")
|
||||||
.bind(&data.username)
|
.bind(&data.username)
|
||||||
.fetch_optional(&*pool)
|
.fetch_optional(&*pool)
|
||||||
.await?;
|
.await?;
|
||||||
|
|
||||||
let hash = hash
|
let hash = hash.map(|(h,)| h).ok_or_else(|| {
|
||||||
.map(|(h,)| h)
|
warn!("User was not found in the database");
|
||||||
.ok_or_else(|| "Error: user not found. Have you registered?".to_string())?;
|
"Error: user not found. Have you registered?".to_string()
|
||||||
|
})?;
|
||||||
|
|
||||||
let handle = tokio::task::spawn_blocking(move || {
|
let handle = tokio::task::spawn_blocking(move || {
|
||||||
|
info!("Verifying password");
|
||||||
let parsed_hash = PasswordHash::new(&hash)?;
|
let parsed_hash = PasswordHash::new(&hash)?;
|
||||||
Pbkdf2
|
Pbkdf2
|
||||||
.verify_password(data.password.as_bytes(), &parsed_hash)
|
.verify_password(data.password.as_bytes(), &parsed_hash)
|
||||||
|
@ -77,6 +84,7 @@ pub async fn login_backend(
|
||||||
macro_rules! login_and_redirect {
|
macro_rules! login_and_redirect {
|
||||||
($session:expr, $to:literal) => {
|
($session:expr, $to:literal) => {
|
||||||
if $session.get::<String>("logged_in_as").is_some() {
|
if $session.get::<String>("logged_in_as").is_some() {
|
||||||
|
::tracing::warn!("User already logged in, redirecting to {}", $to);
|
||||||
return Err(::axum::response::Redirect::to($to).into());
|
return Err(::axum::response::Redirect::to($to).into());
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
Loading…
Reference in a new issue