flabk/src/svc/auth.rs

93 lines
2.2 KiB
Rust

use std::time::SystemTime;
use jsonwebtoken::{EncodingKey, Header};
use serde::{Deserialize, Serialize};
use crate::{
database::{
db::DBError,
keys::Keys,
users::{self, UserSelect, Users},
},
sec,
};
#[derive(Clone)]
pub struct Auth {
secret: String,
users: Users,
}
const KEY_JWT_SECRET: &str = "JWT_SECRET";
const SECS_JWT_EXPIRE: u64 = 60 * 60; // 1hr
impl Auth {
pub async fn new(db: Keys, users: Users) -> Self {
Self {
secret: match db.get_key(KEY_JWT_SECRET).await {
Ok(secret) => secret,
Err(_) => {
// Create new secret and store to db
// If that fails, crash the application
let secret = sec::new_id();
db.set_key(KEY_JWT_SECRET, &secret).await.unwrap();
secret
}
},
users,
}
}
pub async fn login(&self, username: String, password: String) -> Result<String, AuthError> {
let user = self.users.user(UserSelect::Username(username)).await?;
if !sec::compare(&password, &user.password_hash) {
return Err(AuthError::InvalidCredentials);
}
Ok(jsonwebtoken::encode(
&Header::default(),
&Claims::from(user),
&EncodingKey::from_secret("secret".as_ref()),
)?)
}
}
#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct Claims {
pub sub: String,
pub exp: u64,
pub iat: u64,
}
impl From<users::User> for Claims {
fn from(u: users::User) -> Self {
let now = SystemTime::now()
.duration_since(SystemTime::UNIX_EPOCH)
.unwrap()
.as_secs();
Claims {
sub: u.id,
exp: now + SECS_JWT_EXPIRE,
iat: now,
}
}
}
#[derive(Debug)]
pub enum AuthError {
InvalidCredentials,
ServerError(String),
}
impl From<DBError> for AuthError {
fn from(_: DBError) -> Self {
Self::InvalidCredentials
}
}
impl From<jsonwebtoken::errors::Error> for AuthError {
fn from(e: jsonwebtoken::errors::Error) -> Self {
Self::ServerError(e.to_string())
}
}