cleaning up
This commit is contained in:
parent
1d6270c551
commit
50e85f7de9
4 changed files with 64 additions and 18 deletions
55
src/auth.rs
55
src/auth.rs
|
@ -23,7 +23,7 @@ pub struct User {
|
||||||
pub email: Option<String>,
|
pub email: Option<String>,
|
||||||
|
|
||||||
/// Hashed password
|
/// Hashed password
|
||||||
pub password: Option<Vec<u8>>,
|
pub password: Option<String>,
|
||||||
|
|
||||||
/// User's chosen displayed name
|
/// User's chosen displayed name
|
||||||
pub display_name: Option<String>,
|
pub display_name: Option<String>,
|
||||||
|
@ -43,6 +43,55 @@ pub struct User {
|
||||||
pub deleted_at: Option<DateTime<Utc>>,
|
pub deleted_at: Option<DateTime<Utc>>,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
impl Default for User {
|
||||||
|
fn default() -> Self {
|
||||||
|
Self {
|
||||||
|
id: Uuid::nil(),
|
||||||
|
name: Default::default(),
|
||||||
|
email: Default::default(),
|
||||||
|
password: Default::default(),
|
||||||
|
display_name: Default::default(),
|
||||||
|
bio: Default::default(),
|
||||||
|
roles: Default::default(),
|
||||||
|
created_at: Default::default(),
|
||||||
|
modified_at: Default::default(),
|
||||||
|
deleted_at: Default::default(),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl User {
|
||||||
|
pub async fn create(
|
||||||
|
pool: &Pool<Postgres>,
|
||||||
|
username: &str,
|
||||||
|
password: &str,
|
||||||
|
roles: &Vec<Uuid>,
|
||||||
|
) -> Result<Self> {
|
||||||
|
let result = sqlx::query!(
|
||||||
|
r#"INSERT INTO users ( name, password, roles ) VALUES ( $1,$2,$3 ) RETURNING id, created_at"#,
|
||||||
|
username,
|
||||||
|
hash(&password)?,
|
||||||
|
roles,
|
||||||
|
)
|
||||||
|
.fetch_one(pool)
|
||||||
|
.await?;
|
||||||
|
Ok(Self {
|
||||||
|
id: result.id,
|
||||||
|
name: username.to_owned(),
|
||||||
|
roles: roles.to_owned(),
|
||||||
|
created_at: result.created_at.and_utc(),
|
||||||
|
..Default::default()
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
pub async fn find(pool: &Pool<Postgres>, name: &str) -> Result<Option<Self>> {
|
||||||
|
Ok(sqlx::query_as("SELECT * FROM users WHERE name = $1")
|
||||||
|
.bind(name)
|
||||||
|
.fetch_optional(pool)
|
||||||
|
.await?)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
#[derive(Deserialize, Serialize, FromRow)]
|
#[derive(Deserialize, Serialize, FromRow)]
|
||||||
pub struct Role {
|
pub struct Role {
|
||||||
/// Role ID
|
/// Role ID
|
||||||
|
@ -137,7 +186,7 @@ pub fn random() -> String {
|
||||||
SaltString::generate(&mut OsRng).to_string()
|
SaltString::generate(&mut OsRng).to_string()
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn hash(plaintext: &String) -> Result<String> {
|
pub fn hash(plaintext: &str) -> Result<String> {
|
||||||
let salt = SaltString::generate(&mut OsRng);
|
let salt = SaltString::generate(&mut OsRng);
|
||||||
let hashed = Argon2::default()
|
let hashed = Argon2::default()
|
||||||
.hash_password(plaintext.as_bytes(), &salt)
|
.hash_password(plaintext.as_bytes(), &salt)
|
||||||
|
@ -146,7 +195,7 @@ pub fn hash(plaintext: &String) -> Result<String> {
|
||||||
Ok(hashed)
|
Ok(hashed)
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn verify(plaintext: &String, hash: &String) -> Result<bool> {
|
pub fn verify(plaintext: &str, hash: &str) -> Result<bool> {
|
||||||
let parsed_hash = PasswordHash::new(hash).map_err(|err| anyhow!(err))?;
|
let parsed_hash = PasswordHash::new(hash).map_err(|err| anyhow!(err))?;
|
||||||
Ok(Argon2::default()
|
Ok(Argon2::default()
|
||||||
.verify_password(plaintext.as_bytes(), &parsed_hash)
|
.verify_password(plaintext.as_bytes(), &parsed_hash)
|
||||||
|
|
|
@ -4,7 +4,7 @@ use axum::Json;
|
||||||
use serde_json::{json, Value};
|
use serde_json::{json, Value};
|
||||||
use std::sync::Arc;
|
use std::sync::Arc;
|
||||||
|
|
||||||
use crate::auth::{hash, random};
|
use crate::auth::{random, User};
|
||||||
use crate::error::AppError;
|
use crate::error::AppError;
|
||||||
use crate::roles::ROLE_SUPERADMIN;
|
use crate::roles::ROLE_SUPERADMIN;
|
||||||
use crate::state::AppState;
|
use crate::state::AppState;
|
||||||
|
@ -29,15 +29,13 @@ pub async fn bootstrap(State(state): State<Arc<AppState>>) -> Result<Json<Value>
|
||||||
let username = "admin";
|
let username = "admin";
|
||||||
let password = random();
|
let password = random();
|
||||||
|
|
||||||
sqlx::query!(
|
User::create(
|
||||||
r#"INSERT INTO users ( name, display_name, password, roles ) VALUES ( $1, $2, $3, $4 ) RETURNING id"#,
|
&state.database,
|
||||||
username,
|
&username,
|
||||||
"Administrator",
|
&password,
|
||||||
hash(&password)?,
|
&[ROLE_SUPERADMIN].to_vec(),
|
||||||
&[ROLE_SUPERADMIN],
|
)
|
||||||
)
|
.await?;
|
||||||
.fetch_one(&state.database)
|
|
||||||
.await?;
|
|
||||||
|
|
||||||
Ok(Json(json!({"username": username, "password": password})))
|
Ok(Json(json!({"username": username, "password": password})))
|
||||||
}
|
}
|
||||||
|
|
|
@ -5,7 +5,7 @@ use serde_json::{json, Value};
|
||||||
use std::sync::Arc;
|
use std::sync::Arc;
|
||||||
|
|
||||||
use crate::{
|
use crate::{
|
||||||
auth::{verify, Session},
|
auth::{verify, Session, User},
|
||||||
error::AppError,
|
error::AppError,
|
||||||
state::AppState,
|
state::AppState,
|
||||||
};
|
};
|
||||||
|
@ -20,9 +20,7 @@ pub async fn login(
|
||||||
State(state): State<Arc<AppState>>,
|
State(state): State<Arc<AppState>>,
|
||||||
Json(payload): Json<LoginRequest>,
|
Json(payload): Json<LoginRequest>,
|
||||||
) -> Result<Json<Value>, AppError> {
|
) -> Result<Json<Value>, AppError> {
|
||||||
let user = sqlx::query!("SELECT * FROM users WHERE name = $1", payload.username)
|
let user = User::find(&state.database, payload.username.as_str()).await?;
|
||||||
.fetch_optional(&state.database)
|
|
||||||
.await?;
|
|
||||||
|
|
||||||
let invalid = || -> AppError {
|
let invalid = || -> AppError {
|
||||||
AppError::ClientError {
|
AppError::ClientError {
|
||||||
|
|
|
@ -1,7 +1,8 @@
|
||||||
use crate::{content::Page, error::AppError, state::AppState};
|
|
||||||
use axum::extract::{Path, State};
|
use axum::extract::{Path, State};
|
||||||
use std::sync::Arc;
|
use std::sync::Arc;
|
||||||
|
|
||||||
|
use crate::{content::Page, error::AppError, state::AppState};
|
||||||
|
|
||||||
pub async fn page(
|
pub async fn page(
|
||||||
State(state): State<Arc<AppState>>,
|
State(state): State<Arc<AppState>>,
|
||||||
Path((site, slug)): Path<(String, String)>,
|
Path((site, slug)): Path<(String, String)>,
|
||||||
|
|
Loading…
Reference in a new issue