Compute user digest on deserialization.
This commit is contained in:
parent
91a0ba05c4
commit
e9e5436e02
3 changed files with 26 additions and 30 deletions
25
src/auth.rs
25
src/auth.rs
|
@ -21,20 +21,6 @@ impl AuthStore {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl std::ops::DerefMut for AuthStore {
|
|
||||||
fn deref_mut(&mut self) -> &mut Self::Target {
|
|
||||||
&mut self.0
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl std::ops::Deref for AuthStore {
|
|
||||||
type Target = SqlitePool;
|
|
||||||
|
|
||||||
fn deref(&self) -> &Self::Target {
|
|
||||||
&self.0
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
#[derive(Default, Debug, Clone, PartialEq, Eq)]
|
#[derive(Default, Debug, Clone, PartialEq, Eq)]
|
||||||
pub struct Credentials {
|
pub struct Credentials {
|
||||||
pub username: String,
|
pub username: String,
|
||||||
|
@ -57,7 +43,9 @@ impl AuthnBackend for AuthStore {
|
||||||
let username = creds.username.trim();
|
let username = creds.username.trim();
|
||||||
let password = creds.password.trim();
|
let password = creds.password.trim();
|
||||||
|
|
||||||
let user = User::try_get(username, self).await.map_err(|_| AuthError)?;
|
let user = User::try_get(username, &self.0)
|
||||||
|
.await
|
||||||
|
.map_err(|_| AuthError)?;
|
||||||
let verifier = Argon2::default();
|
let verifier = Argon2::default();
|
||||||
let hash = PasswordHash::new(&user.pwhash).map_err(|_| AuthError)?;
|
let hash = PasswordHash::new(&user.pwhash).map_err(|_| AuthError)?;
|
||||||
Ok(
|
Ok(
|
||||||
|
@ -70,12 +58,11 @@ impl AuthnBackend for AuthStore {
|
||||||
}
|
}
|
||||||
|
|
||||||
async fn get_user(&self, user_id: &UserId<Self>) -> Result<Option<Self::User>, Self::Error> {
|
async fn get_user(&self, user_id: &UserId<Self>) -> Result<Option<Self::User>, Self::Error> {
|
||||||
let user = sqlx::query_as("select * from users where id = ?")
|
sqlx::query_as("select * from users where id = ?")
|
||||||
.bind(user_id)
|
.bind(user_id)
|
||||||
.fetch_optional(&self.0)
|
.fetch_optional(&self.0)
|
||||||
.await
|
.await
|
||||||
.map_err(|_| AuthError)?;
|
.map_err(|_| AuthError)
|
||||||
Ok(user)
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -87,7 +74,7 @@ impl AuthUser for User {
|
||||||
}
|
}
|
||||||
|
|
||||||
fn session_auth_hash(&self) -> &[u8] {
|
fn session_auth_hash(&self) -> &[u8] {
|
||||||
self.pwhash.as_bytes()
|
self.digest.as_bytes()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -7,10 +7,6 @@ use serde::{Deserialize, Serialize};
|
||||||
|
|
||||||
use crate::{auth::Credentials, AuthSession, LoginPage, LogoutPage, LogoutSuccessPage};
|
use crate::{auth::Credentials, AuthSession, LoginPage, LogoutPage, LogoutSuccessPage};
|
||||||
|
|
||||||
//-************************************************************************
|
|
||||||
// Constants
|
|
||||||
//-************************************************************************
|
|
||||||
|
|
||||||
//-************************************************************************
|
//-************************************************************************
|
||||||
// Login error and success types
|
// Login error and success types
|
||||||
//-************************************************************************
|
//-************************************************************************
|
||||||
|
|
27
src/users.rs
27
src/users.rs
|
@ -7,14 +7,14 @@ use axum::{
|
||||||
};
|
};
|
||||||
use julid::Julid;
|
use julid::Julid;
|
||||||
use serde::{Deserialize, Serialize};
|
use serde::{Deserialize, Serialize};
|
||||||
use sqlx::SqlitePool;
|
use sqlx::{sqlite::SqliteRow, Row, SqlitePool};
|
||||||
|
|
||||||
use crate::AuthSession;
|
use crate::AuthSession;
|
||||||
|
|
||||||
const USERNAME_QUERY: &str = "select * from users where username = $1";
|
const USERNAME_QUERY: &str = "select * from users where username = $1";
|
||||||
const LAST_SEEN_QUERY: &str = "update users set last_seen = (select unixepoch()) where id = $1";
|
const LAST_SEEN_QUERY: &str = "update users set last_seen = (select unixepoch()) where id = $1";
|
||||||
|
|
||||||
#[derive(Default, Clone, PartialEq, Eq, Serialize, Deserialize, sqlx::FromRow)]
|
#[derive(Default, Clone, PartialEq, Eq, Serialize, Deserialize)]
|
||||||
pub struct User {
|
pub struct User {
|
||||||
pub id: Julid,
|
pub id: Julid,
|
||||||
pub username: String,
|
pub username: String,
|
||||||
|
@ -22,10 +22,25 @@ pub struct User {
|
||||||
pub email: Option<String>,
|
pub email: Option<String>,
|
||||||
pub last_seen: Option<i64>,
|
pub last_seen: Option<i64>,
|
||||||
pub pwhash: String,
|
pub pwhash: String,
|
||||||
#[sqlx(default)]
|
|
||||||
pub digest: String,
|
pub digest: String,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
impl sqlx::FromRow<'_, SqliteRow> for User {
|
||||||
|
fn from_row(row: &SqliteRow) -> Result<Self, sqlx::Error> {
|
||||||
|
let pwhash = row.try_get("pwhash")?;
|
||||||
|
let digest = sha256::digest(&pwhash);
|
||||||
|
Ok(Self {
|
||||||
|
id: row.try_get("id")?,
|
||||||
|
username: row.try_get("username")?,
|
||||||
|
displayname: row.try_get("displayname")?,
|
||||||
|
email: row.try_get("email")?,
|
||||||
|
last_seen: row.try_get("last_seen")?,
|
||||||
|
pwhash,
|
||||||
|
digest,
|
||||||
|
})
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
impl Debug for User {
|
impl Debug for User {
|
||||||
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
|
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
|
||||||
f.debug_struct("User")
|
f.debug_struct("User")
|
||||||
|
@ -54,12 +69,10 @@ impl Display for User {
|
||||||
|
|
||||||
impl User {
|
impl User {
|
||||||
pub async fn try_get(username: &str, db: &SqlitePool) -> Result<Self, sqlx::Error> {
|
pub async fn try_get(username: &str, db: &SqlitePool) -> Result<Self, sqlx::Error> {
|
||||||
let mut user: Self = sqlx::query_as(USERNAME_QUERY)
|
sqlx::query_as(USERNAME_QUERY)
|
||||||
.bind(username)
|
.bind(username)
|
||||||
.fetch_one(db)
|
.fetch_one(db)
|
||||||
.await?;
|
.await
|
||||||
user.digest = sha256::digest(&user.pwhash);
|
|
||||||
Ok(user)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
pub async fn update_last_seen(&self, pool: &SqlitePool) {
|
pub async fn update_last_seen(&self, pool: &SqlitePool) {
|
||||||
|
|
Loading…
Reference in a new issue