1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
|
use std::sync::Arc;
use axum::{response::{IntoResponse, Html, Redirect}, Form, Extension};
use axum_extra::extract::{PrivateCookieJar, cookie::Cookie};
use serde::Deserialize;
use sqlx::{query, query_as};
use tracing::debug;
use crate::{errors::ServiceError, State, models::DbUser};
use chrono::prelude::*;
#[derive(Deserialize, Debug)]
pub struct RegisterForm {
pub email: String,
pub prefname: String,
pub password: String,
#[serde(rename="password-confirm")]
pub password_confirm: String
}
#[derive(Deserialize)]
pub struct LoginForm {
pub email: String,
pub password: String,
}
pub async fn login() -> impl IntoResponse {
let mut buf = Vec::new();
crate::templates::login_html(&mut buf).unwrap();
Html(buf)
}
pub async fn login_post(Form(login): Form<LoginForm>, state: Extension<Arc<State>>, jar: PrivateCookieJar) -> Result<(PrivateCookieJar, Redirect), ServiceError> {
let mut conn = state.conn.acquire().await?;
let user: DbUser = query_as("SELECT * FROM users WHERE email=$1").bind(login.email)
.fetch_one(&mut conn)
.await?;
if bcrypt::verify(login.password, &user.pw_hash)? {
debug!("Logged in ID {} (email {})", user.id, user.email);
query("UPDATE users SET last_login=$1 WHERE id=$2").bind(Utc::now()).bind(user.id)
.execute(&mut conn)
.await?;
let updated_jar = jar.add(Cookie::new("user-id", user.id.clone()));
} else {
}
Ok((updated_jar, Redirect::to("/")))
}
pub async fn register() -> impl IntoResponse {
let mut buf = Vec::new();
crate::templates::register_html(&mut buf).unwrap();
Html(buf)
}
pub async fn register_post(Form(reg): Form<RegisterForm>, state: Extension<Arc<State>>) -> impl IntoResponse {
if reg.password_confirm == reg.password {
let hash = match bcrypt::hash(reg.password, bcrypt::DEFAULT_COST) {
Ok(h) => h,
Err(e) => {
return Err(ServiceError::NotAuthorized);
}
};
let mut conn = state.conn.acquire().await?;
let ulid = ulid::Ulid::new();
query("INSERT INTO users (id, email, pref_name, pw_hash, last_login) VALUES ($1, $2, $3, $4, $5)").bind(ulid.to_string()).bind(reg.email.clone()).bind(reg.prefname).bind(hash).bind(Utc::now())
.execute(&mut conn)
.await?;
}
Ok(Redirect::to("/dash/auth/login"))
}
|