add: postgres support

chore: restructure
This commit is contained in:
trisua 2025-03-22 22:17:47 -04:00
parent cda879f6df
commit b6fe2fba37
58 changed files with 3403 additions and 603 deletions

View file

@ -0,0 +1,71 @@
use rainbeam_shared::{
hash::{hash_salted, salt},
snow::AlmostSnowflake,
unix_epoch_timestamp,
};
use serde::{Deserialize, Serialize};
/// `(ip, token, creation timestamp)`
pub type Token = (String, String, usize);
#[derive(Debug, Serialize)]
pub struct User {
pub id: usize,
pub created: usize,
pub username: String,
pub password: String,
pub salt: String,
pub settings: UserSettings,
pub tokens: Vec<Token>,
}
#[derive(Debug, Serialize, Deserialize)]
pub struct UserSettings;
impl Default for UserSettings {
fn default() -> Self {
Self {}
}
}
impl User {
/// Create a new [`User`].
pub fn new(username: String, password: String) -> Self {
let salt = salt();
let password = hash_salted(password, salt.clone());
Self {
id: AlmostSnowflake::new(1234567890)
.to_string()
.parse::<usize>()
.unwrap(),
created: unix_epoch_timestamp() as usize,
username,
password,
salt,
settings: UserSettings::default(),
tokens: Vec::new(),
}
}
/// Create a new token
///
/// # Returns
/// `(unhashed id, token)`
pub fn create_token(ip: &str) -> (String, Token) {
let unhashed = rainbeam_shared::hash::uuid();
(
unhashed.clone(),
(
ip.to_string(),
rainbeam_shared::hash::hash(unhashed),
unix_epoch_timestamp() as usize,
),
)
}
/// Check if the given password is correct for the user.
pub fn check_password(&self, against: String) -> bool {
self.password == hash_salted(against, self.salt.clone())
}
}

View file

@ -0,0 +1,56 @@
pub mod auth;
use serde::{Deserialize, Serialize};
#[derive(Serialize, Deserialize)]
pub struct ApiReturn<T>
where
T: Serialize,
{
pub ok: bool,
pub message: String,
pub payload: T,
}
#[derive(Debug)]
pub enum Error {
DatabaseConnection(String),
UserNotFound,
RegistrationDisabled,
DatabaseError(String),
IncorrectPassword,
AlreadyAuthenticated,
DataTooLong(String),
DataTooShort(String),
Unknown,
}
impl ToString for Error {
fn to_string(&self) -> String {
match self {
Error::DatabaseConnection(msg) => msg.to_owned(),
Error::DatabaseError(msg) => format!("Database error: {msg}"),
Error::UserNotFound => "Unable to find user with given parameters".to_string(),
Error::RegistrationDisabled => "Registration is disabled".to_string(),
Error::IncorrectPassword => "The given password is invalid".to_string(),
Error::AlreadyAuthenticated => "Already authenticated".to_string(),
Error::DataTooLong(name) => format!("Given {name} is too long!"),
Error::DataTooShort(name) => format!("Given {name} is too short!"),
_ => format!("An unknown error as occurred: ({:?})", self),
}
}
}
impl<T> Into<ApiReturn<T>> for Error
where
T: Default + Serialize,
{
fn into(self) -> ApiReturn<T> {
ApiReturn {
ok: false,
message: self.to_string(),
payload: T::default(),
}
}
}
pub type Result<T> = std::result::Result<T, Error>;