DNS backend
This commit is contained in:
95
dns/src/auth.rs
Normal file
95
dns/src/auth.rs
Normal file
@@ -0,0 +1,95 @@
|
||||
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))
|
||||
}
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user