Added lots of debugging + token auth

Now you dont have to send your password over the wire every time and can
make do with a token instead. There's lots of debugging info now to make
it easier for me to fix bugs with the server
This commit is contained in:
2026-05-30 18:22:54 -07:00
parent d71b10f89c
commit 8ba58234e0
14 changed files with 260 additions and 77 deletions
+82 -23
View File
@@ -7,9 +7,15 @@ use bcrypt::{DEFAULT_COST, hash, verify};
use diesel_async::AsyncPgConnection;
use diesel_async::RunQueryDsl;//, AsyncConnection};
use diesel_async::pooled_connection::deadpool::Object;
use fedichat::client::{ServerMessage,ServerError};
use fedichat::client::{ServerMessage,ServerError,AuthMethod};
use rand::distr::{Alphanumeric, SampleString};
use rand::rngs::{SysRng,StdRng};
use rand::prelude::*;
use time::{OffsetDateTime,Duration};
use tracing::{instrument,warn};
#[instrument(skip_all)]
pub async fn maybe_create_user(mut connection: Object<AsyncPgConnection>, username: &str, password: &str) -> Result<ServerMessage,ServerError> {
let password = match hash(password,DEFAULT_COST) {
@@ -37,32 +43,85 @@ pub async fn maybe_create_user(mut connection: Object<AsyncPgConnection>, userna
/// Try to authenticate a user against information in the database
#[instrument(skip_all)]
pub async fn verify_user(mut connection: Object<AsyncPgConnection>, user: &str, pass: &str) -> Result<bool,ServerError> {
use schema::users::dsl::*;
pub async fn verify_user(mut connection: Object<AsyncPgConnection>, user: &str, pass: &AuthMethod) -> Result<bool,ServerError> {
let result = users
.filter(username.eq(user))
.select(models::User::as_select())
.first(&mut *connection)
match pass {
AuthMethod::Password(pass) => {
use schema::users::dsl::*;
let result = users
.filter(username.eq(user))
.select(models::User::as_select())
.first(&mut *connection)
.await;
match result {
// If we have more than 0 rows then authentication is successful
Ok(user) => match verify(pass,&user.password) {
Ok(val) => Ok(val),
Err(e) => {
warn!("Error encountered while generating password hash");
warn!("{e}");
return Err(ServerError::Generic)
}
},
// TODO: Probably actually check the error
_ => Err(ServerError::AuthenticationFailed)
}
},
AuthMethod::Token(tk) => {
use schema::tokens::dsl::*;
let result = tokens
.filter(username.eq(user))
.filter(token.eq(tk))
// Check that expiry is in the future
.filter(expiry.gt(OffsetDateTime::now_utc().unix_timestamp()))
.select(models::Token::as_select())
.first(&mut *connection)
.await;
match result {
// If we have more than 0 rows then authentication is successful
// Only need one token, no need to hash or do anything else
Ok(_) => Ok(true),
// TODO: Probably actually check the error
_ => Err(ServerError::AuthenticationFailed)
}
}
}
}
/// Create a new token for the current user with an expiry set 3 months into the future
pub async fn gen_token(mut connection: Object<AsyncPgConnection>, user: String)
-> Result<String,ServerError>
{
let mut rng = StdRng::try_from_rng(&mut SysRng).unwrap();
let new_token = Alphanumeric.sample_string(&mut rng, 32);
let expiry = OffsetDateTime::now_utc() + Duration::days(90);
let insertable = models::NewToken {
username: user,
token: new_token.clone(),
expiry: expiry.unix_timestamp()
};
let result = diesel::insert_into(schema::tokens::table)
.values(&insertable)
.execute(&mut *connection)
.await;
match result {
// If we have more than 0 rows then authentication is successful
Ok(user) => match verify(pass,&user.password) {
Ok(val) => Ok(val),
Err(e) => {
warn!("Error encountered while generating password hash");
warn!("{e}");
return Err(ServerError::Generic)
}
},
// TODO: might need to check this? I don't know what it means
Ok(_) => Ok(new_token),
// TODO: Probably actually check the error
_ => Err(ServerError::AuthenticationFailed)
Err(_e) => Err(ServerError::UserAlreadyExists)
}
}
+16
View File
@@ -73,3 +73,19 @@ pub struct Messages {
pub server_timestamp: i64,
pub username: UserT
}
#[derive(Queryable, Selectable)]
#[diesel(table_name = crate::db::schema::tokens)]
pub struct Token {
pub id: i32,
pub username: String,
pub token: String,
pub expiry: i64,
}
#[derive(Insertable)]
#[diesel(table_name = crate::db::schema::tokens)]
pub struct NewToken {
pub username: String,
pub token: String,
pub expiry: i64,
}
+10 -1
View File
@@ -48,6 +48,15 @@ diesel::table! {
}
}
diesel::table! {
tokens (id) {
id -> Int4,
username -> Text,
token -> Text,
expiry -> Int8,
}
}
diesel::table! {
users (id) {
id -> Int4,
@@ -56,4 +65,4 @@ diesel::table! {
}
}
diesel::allow_tables_to_appear_in_same_query!(groups, messages, roles, users,);
diesel::allow_tables_to_appear_in_same_query!(groups, messages, roles, tokens, users,);