Files
leonwww/dns/src/auth.rs

95 lines
2.7 KiB
Rust
Raw Normal View History

2025-08-12 21:31:09 +03:00
use actix_web::{dev::ServiceRequest, web, Error, HttpMessage};
use actix_web_httpauth::extractors::bearer::BearerAuth;
use actix_web_httpauth::extractors::AuthenticationError;
use actix_web_httpauth::headers::www_authenticate::bearer::Bearer;
use jsonwebtoken::{decode, encode, DecodingKey, EncodingKey, Header, Validation, Algorithm};
use serde::{Deserialize, Serialize};
use bcrypt::{hash, verify, DEFAULT_COST};
use std::time::{SystemTime, UNIX_EPOCH};
use chrono::{DateTime, Utc};
#[derive(Debug, Serialize, Deserialize)]
pub struct Claims {
pub user_id: i32,
pub username: String,
pub exp: usize,
}
#[derive(Debug, Serialize, Deserialize)]
pub struct RegisterRequest {
pub username: String,
pub password: String,
}
#[derive(Debug, Serialize, Deserialize)]
pub struct LoginRequest {
pub username: String,
pub password: String,
}
#[derive(Debug, Serialize, Deserialize)]
pub struct LoginResponse {
pub token: String,
pub user: UserInfo,
}
#[derive(Debug, Serialize, Deserialize)]
pub struct UserInfo {
pub id: i32,
pub username: String,
pub registrations_remaining: i32,
pub domain_invite_codes: i32,
pub created_at: DateTime<Utc>,
}
pub fn generate_jwt(user_id: i32, username: &str, secret: &str) -> Result<String, jsonwebtoken::errors::Error> {
let expiration = SystemTime::now()
.duration_since(UNIX_EPOCH)
.unwrap()
.as_secs() + 86400 * 7; // 7 days
let claims = Claims {
user_id,
username: username.to_string(),
exp: expiration as usize,
};
encode(&Header::default(), &claims, &EncodingKey::from_secret(secret.as_ref()))
}
pub fn validate_jwt(token: &str, secret: &str) -> Result<Claims, jsonwebtoken::errors::Error> {
let mut validation = Validation::new(Algorithm::HS256);
validation.validate_exp = true;
decode::<Claims>(token, &DecodingKey::from_secret(secret.as_ref()), &validation)
.map(|token_data| token_data.claims)
}
pub fn hash_password(password: &str) -> Result<String, bcrypt::BcryptError> {
hash(password, DEFAULT_COST)
}
pub fn verify_password(password: &str, hash: &str) -> Result<bool, bcrypt::BcryptError> {
verify(password, hash)
}
pub async fn jwt_middleware(
req: ServiceRequest,
credentials: BearerAuth,
) -> Result<ServiceRequest, (Error, ServiceRequest)> {
let jwt_secret = req
.app_data::<web::Data<String>>()
.unwrap()
.as_ref();
match validate_jwt(credentials.token(), jwt_secret) {
Ok(claims) => {
req.extensions_mut().insert(claims);
Ok(req)
}
Err(_) => {
let config = AuthenticationError::new(Bearer::default());
Err((Error::from(config), req))
}
}
}