backend login code done, need registration, pages, and guards
This commit is contained in:
parent
8215975757
commit
9a63f1fe2c
10 changed files with 236 additions and 14 deletions
120
Cargo.lock
generated
120
Cargo.lock
generated
|
@ -17,6 +17,41 @@ version = "2.0.0"
|
|||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "512761e0bb2578dd7380c6baaa0f4ce03e84f95e960231d1dec8bf4d7d6e2627"
|
||||
|
||||
[[package]]
|
||||
name = "aead"
|
||||
version = "0.5.2"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "d122413f284cf2d62fb1b7db97e02edb8cda96d769b16e443a4f6195e35662b0"
|
||||
dependencies = [
|
||||
"crypto-common",
|
||||
"generic-array",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "aes"
|
||||
version = "0.8.4"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "b169f7a6d4742236a0a00c541b845991d0ac43e546831af1249753ab4c3aa3a0"
|
||||
dependencies = [
|
||||
"cfg-if",
|
||||
"cipher",
|
||||
"cpufeatures",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "aes-gcm"
|
||||
version = "0.10.3"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "831010a0f742e1209b3bcea8fab6a8e149051ba6099432c8cb2cc117dec3ead1"
|
||||
dependencies = [
|
||||
"aead",
|
||||
"aes",
|
||||
"cipher",
|
||||
"ctr",
|
||||
"ghash",
|
||||
"subtle",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "ahash"
|
||||
version = "0.8.11"
|
||||
|
@ -150,6 +185,12 @@ version = "0.21.7"
|
|||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "9d297deb1925b89f2ccc13d7635fa0714f12c87adce1c75356b39ca9b7178567"
|
||||
|
||||
[[package]]
|
||||
name = "base64"
|
||||
version = "0.22.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "72b3254f16251a8381aa12e40e3c4d2f0199f8c6508fbecb9d91f575e0fbb8c6"
|
||||
|
||||
[[package]]
|
||||
name = "base64ct"
|
||||
version = "1.6.0"
|
||||
|
@ -272,6 +313,16 @@ dependencies = [
|
|||
"phf_codegen",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "cipher"
|
||||
version = "0.4.4"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "773f3b9af64447d2ce9850330c473515014aa235e6a783b02db81ff39e4a3dad"
|
||||
dependencies = [
|
||||
"crypto-common",
|
||||
"inout",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "const-oid"
|
||||
version = "0.9.6"
|
||||
|
@ -284,7 +335,13 @@ version = "0.18.1"
|
|||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "4ddef33a339a91ea89fb53151bd0a4689cfce27055c291dfa69945475d22c747"
|
||||
dependencies = [
|
||||
"aes-gcm",
|
||||
"base64 0.22.1",
|
||||
"hkdf",
|
||||
"percent-encoding",
|
||||
"rand",
|
||||
"sha2",
|
||||
"subtle",
|
||||
"time",
|
||||
"version_check",
|
||||
]
|
||||
|
@ -369,6 +426,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
|
|||
checksum = "1bfb12502f3fc46cca1bb51ac28df9d618d813cdc3d2f25b9fe775a34af26bb3"
|
||||
dependencies = [
|
||||
"generic-array",
|
||||
"rand_core",
|
||||
"typenum",
|
||||
]
|
||||
|
||||
|
@ -378,6 +436,15 @@ version = "1.1.3"
|
|||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "b916ba8ce9e4182696896f015e8a5ae6081b305f74690baa8465e35f5a142ea4"
|
||||
|
||||
[[package]]
|
||||
name = "ctr"
|
||||
version = "0.9.2"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "0369ee1ad671834580515889b80f2ea915f23b8be8d0daa4bbaf2ac5c7590835"
|
||||
dependencies = [
|
||||
"cipher",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "der"
|
||||
version = "0.7.9"
|
||||
|
@ -728,6 +795,16 @@ dependencies = [
|
|||
"wasi",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "ghash"
|
||||
version = "0.5.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "f0d8a4362ccb29cb0b265253fb0a2728f592895ee6854fd9bc13f2ffda266ff1"
|
||||
dependencies = [
|
||||
"opaque-debug",
|
||||
"polyval",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "gimli"
|
||||
version = "0.31.1"
|
||||
|
@ -1155,6 +1232,15 @@ dependencies = [
|
|||
"libc",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "inout"
|
||||
version = "0.1.3"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "a0c10553d664a4d0bcff9f4215d0aac67a639cc68ef660840afe309b807bc9f5"
|
||||
dependencies = [
|
||||
"generic-array",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "is-terminal"
|
||||
version = "0.4.13"
|
||||
|
@ -1502,6 +1588,12 @@ version = "1.20.2"
|
|||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "1261fe7e33c73b354eab43b1273a57c8f967d0391e80353e51f764ac02cf6775"
|
||||
|
||||
[[package]]
|
||||
name = "opaque-debug"
|
||||
version = "0.3.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "c08d65885ee38876c4f86fa503fb49d7b507c2b62552df7c70b2fce627e06381"
|
||||
|
||||
[[package]]
|
||||
name = "orion"
|
||||
version = "0.17.7"
|
||||
|
@ -1719,6 +1811,18 @@ version = "0.3.31"
|
|||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "953ec861398dccce10c670dfeaf3ec4911ca479e9c02154b3a215178c5f566f2"
|
||||
|
||||
[[package]]
|
||||
name = "polyval"
|
||||
version = "0.6.2"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "9d1fe60d06143b2430aa532c94cfe9e29783047f06c0d7fd359a9a51b729fa25"
|
||||
dependencies = [
|
||||
"cfg-if",
|
||||
"cpufeatures",
|
||||
"opaque-debug",
|
||||
"universal-hash",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "powerfmt"
|
||||
version = "0.2.0"
|
||||
|
@ -2055,7 +2159,7 @@ version = "1.0.4"
|
|||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "1c74cae0a4cf6ccbbf5f359f08efdf8ee7e1dc532573bf0db71968cb56b1448c"
|
||||
dependencies = [
|
||||
"base64",
|
||||
"base64 0.21.7",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
|
@ -2381,7 +2485,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
|
|||
checksum = "1ed31390216d20e538e447a7a9b959e06ed9fc51c37b514b46eb758016ecd418"
|
||||
dependencies = [
|
||||
"atoi",
|
||||
"base64",
|
||||
"base64 0.21.7",
|
||||
"bitflags 2.6.0",
|
||||
"byteorder",
|
||||
"bytes",
|
||||
|
@ -2425,7 +2529,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
|
|||
checksum = "7c824eb80b894f926f89a0b9da0c7f435d27cdd35b8c655b114e58223918577e"
|
||||
dependencies = [
|
||||
"atoi",
|
||||
"base64",
|
||||
"base64 0.21.7",
|
||||
"bitflags 2.6.0",
|
||||
"byteorder",
|
||||
"chrono",
|
||||
|
@ -2985,6 +3089,16 @@ version = "0.1.1"
|
|||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "39ec24b3121d976906ece63c9daad25b85969647682eee313cb5779fdd69e14e"
|
||||
|
||||
[[package]]
|
||||
name = "universal-hash"
|
||||
version = "0.5.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "fc1de2c688dc15305988b563c3854064043356019f97a4b46276fe734c4f07ea"
|
||||
dependencies = [
|
||||
"crypto-common",
|
||||
"subtle",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "untrusted"
|
||||
version = "0.9.0"
|
||||
|
|
|
@ -4,7 +4,7 @@ version = "0.1.0"
|
|||
edition = "2021"
|
||||
|
||||
[dependencies]
|
||||
rocket = "0.5.1"
|
||||
rocket = { version = "0.5.1", features = ["secrets"] }
|
||||
rocket_dyn_templates = { version = "0.2.0", features = ["tera"] }
|
||||
rocket_db_pools = { version = "0.2.0", features = ["sqlx_postgres"] }
|
||||
sqlx = { version = "0.7", default-features = false, features = [
|
||||
|
|
|
@ -7,7 +7,7 @@ const ITERATIONS: u32 = 3;
|
|||
const MEMORY: u32 = 1 << 16;
|
||||
// TODO: make those configurable through the .toml file
|
||||
|
||||
pub fn hash(input: &str) -> Result<String, UnknownCryptoError> {
|
||||
pub fn hash<'a>(input: &'a str) -> Result<String, UnknownCryptoError> {
|
||||
let password = pwhash::Password::from_slice(input.as_bytes())?;
|
||||
|
||||
Ok(pwhash::hash_password(&password, ITERATIONS, MEMORY)?
|
||||
|
|
|
@ -1,3 +1,4 @@
|
|||
pub mod doll;
|
||||
pub mod migrate;
|
||||
pub mod schema;
|
||||
pub mod user;
|
||||
|
|
|
@ -67,3 +67,15 @@ pub struct CreateDollProfile<'a> {
|
|||
pub chassis_id: Option<&'a str>,
|
||||
pub chassis_color: Option<&'a str>,
|
||||
}
|
||||
|
||||
#[derive(Debug)]
|
||||
pub struct User {
|
||||
pub id: Uuid,
|
||||
pub created_at: chrono::DateTime<Utc>,
|
||||
pub updated_at: Option<chrono::DateTime<Utc>>,
|
||||
|
||||
pub username: String,
|
||||
pub password: String,
|
||||
|
||||
pub enabled: bool,
|
||||
}
|
||||
|
|
25
src/db/user.rs
Normal file
25
src/db/user.rs
Normal file
|
@ -0,0 +1,25 @@
|
|||
use uuid::Uuid;
|
||||
|
||||
use crate::db::schema::User;
|
||||
|
||||
use super::schema::DollTagsDb;
|
||||
|
||||
pub async fn get(mut db: DollTagsDb, username: &str) -> sqlx::Result<Option<User>> {
|
||||
sqlx::query_as!(User, "select * from users where username = $1", username)
|
||||
.fetch_optional(&mut **db)
|
||||
.await
|
||||
}
|
||||
|
||||
pub async fn create(
|
||||
mut db: DollTagsDb,
|
||||
username: &str,
|
||||
hashed_password: &str,
|
||||
) -> sqlx::Result<Uuid> {
|
||||
sqlx::query_scalar!(
|
||||
"insert into users (username, password) values ($1, $2) returning id",
|
||||
username,
|
||||
hashed_password
|
||||
)
|
||||
.fetch_one(&mut **db)
|
||||
.await
|
||||
}
|
|
@ -9,6 +9,7 @@ use rocket::fs::{relative, FileServer};
|
|||
use rocket_db_pools::Database;
|
||||
use rocket_dyn_templates::tera::try_get_value;
|
||||
use rocket_dyn_templates::Template;
|
||||
use routes::form::accounts;
|
||||
use routes::{error_handlers, form, public};
|
||||
use serde_json::{to_value, Value};
|
||||
|
||||
|
@ -39,6 +40,10 @@ fn rocket() -> _ {
|
|||
public::show_profile,
|
||||
form::register_tag::show_register,
|
||||
form::register_tag::handle_register,
|
||||
accounts::show_register,
|
||||
accounts::handle_register,
|
||||
accounts::show_login,
|
||||
accounts::handle_login,
|
||||
],
|
||||
)
|
||||
}
|
||||
|
|
|
@ -28,19 +28,12 @@ impl From<Redirect> for PageResponse {
|
|||
#[response(status = 500)]
|
||||
pub struct Fail(Template);
|
||||
|
||||
impl From<anyhow::Error> for Fail {
|
||||
fn from(value: anyhow::Error) -> Self {
|
||||
impl<T: std::fmt::Debug> From<T> for Fail {
|
||||
fn from(value: T) -> Self {
|
||||
error!("Internal error: {:?}", value);
|
||||
Fail(Template::render("error/internal", context! {}))
|
||||
}
|
||||
}
|
||||
|
||||
impl From<sqlx::Error> for Fail {
|
||||
fn from(value: sqlx::Error) -> Self {
|
||||
error!("DB error: {:?}", value);
|
||||
Fail(Template::render("error/internal", context! {}))
|
||||
}
|
||||
}
|
||||
|
||||
pub type RawResult<T> = Result<T, Fail>;
|
||||
pub type PageResult = RawResult<PageResponse>;
|
||||
|
|
71
src/routes/form/accounts.rs
Normal file
71
src/routes/form/accounts.rs
Normal file
|
@ -0,0 +1,71 @@
|
|||
use rocket::{
|
||||
form::{Contextual, Form},
|
||||
http::CookieJar,
|
||||
response::Redirect,
|
||||
tokio::task,
|
||||
};
|
||||
use rocket_dyn_templates::{context, Template};
|
||||
|
||||
use crate::{
|
||||
auth::pw,
|
||||
db::{schema::DollTagsDb, user},
|
||||
routes::error_handlers::{PageResponse, PageResult},
|
||||
};
|
||||
|
||||
#[derive(Debug, FromForm)]
|
||||
pub struct AuthForm<'a> {
|
||||
#[field(validate=len(2..=256))]
|
||||
pub username: &'a str,
|
||||
#[field(validate=len(8..))]
|
||||
pub password: &'a str,
|
||||
}
|
||||
|
||||
#[get("/login")]
|
||||
pub fn show_login() -> Template {
|
||||
todo!("meow")
|
||||
}
|
||||
|
||||
#[post("/login", data = "<form>")]
|
||||
pub async fn handle_login(
|
||||
db: DollTagsDb,
|
||||
form: Form<Contextual<'_, AuthForm<'_>>>,
|
||||
cookies: &CookieJar<'_>,
|
||||
) -> PageResult {
|
||||
let miss = || PageResponse::Page(Template::render("login", context! {failure: true}));
|
||||
|
||||
let values = match &form.value {
|
||||
None => return Ok(miss()),
|
||||
Some(v) => v,
|
||||
};
|
||||
|
||||
let user_in_db = user::get(db, &values.username).await?;
|
||||
let user = match user_in_db {
|
||||
None => return Ok(miss()),
|
||||
Some(v) => v,
|
||||
};
|
||||
|
||||
let password = String::from(values.password);
|
||||
let right_password =
|
||||
task::spawn_blocking(move || pw::verify(&password, &user.password)).await??;
|
||||
|
||||
if right_password && user.enabled {
|
||||
cookies.add_private(("user_id", user.id.to_string()));
|
||||
Ok(Redirect::to("/").into())
|
||||
} else {
|
||||
Ok(miss())
|
||||
}
|
||||
}
|
||||
|
||||
#[get("/register")]
|
||||
pub fn show_register() -> Template {
|
||||
todo!("meow")
|
||||
}
|
||||
|
||||
#[post("/register", data = "<_form>")]
|
||||
pub async fn handle_register(
|
||||
_db: DollTagsDb,
|
||||
_form: Form<AuthForm<'_>>,
|
||||
_cookies: &CookieJar<'_>,
|
||||
) -> PageResult {
|
||||
todo!("meow")
|
||||
}
|
|
@ -1 +1,2 @@
|
|||
pub mod accounts;
|
||||
pub mod register_tag;
|
||||
|
|
Loading…
Add table
Reference in a new issue