Saving changes

This commit is contained in:
kdeng00
2025-07-30 17:25:22 -04:00
parent 5fd4f120f3
commit 7947bed574
4 changed files with 126 additions and 28 deletions
+113
View File
@@ -0,0 +1,113 @@
use std::collections::BTreeMap;
use axum::{
http::{Request, StatusCode},
middleware::Next,
response::{IntoResponse, Response},
Json,
};
use josekit::{
jwt::{self, JwtPayload},
jws::{self, JwsHeader, JwsSigner, JwsVerifier},
jwk::Jwk,
};
use serde::{Deserialize, Serialize};
use serde_json::{json, Value};
use thiserror::Error;
use time::OffsetDateTime;
#[derive(Debug, Serialize, Deserialize)]
pub struct UserClaims {
pub sub: String, // Subject (user ID)
pub exp: i64, // Expiration time (UTC timestamp)
pub iat: i64, // Issued at (UTC timestamp)
#[serde(skip_serializing_if = "Option::is_none")]
pub roles: Option<Vec<String>>, // Optional roles
}
// use time::OffsetDateTime;
#[derive(Error, Debug)]
pub enum JwtError {
#[error("Token creation failed")]
TokenCreation,
#[error("Token verification failed")]
TokenVerification,
#[error("Invalid token")]
InvalidToken,
#[error("Token expired")]
ExpiredToken,
#[error("Invalid key")]
InvalidKey,
}
pub struct JwtAuth {
key: Jwk, // Now properly parameterized
}
impl JwtAuth {
pub fn new(secret: &str) -> Result<Self, JwtError> {
let mut key = Jwk::new("oct");
key.set_parameter("k", Some(json!(base64::encode(secret))))
.map_err(|_| JwtError::InvalidKey)?;
Ok(Self { key })
}
pub fn create_token(&self, claims: &UserClaims) -> Result<String, JwtError> {
let mut header = JwsHeader::new();
header.set_token_type("JWT");
let claims_value = serde_json::to_value(claims)
.map_err(|_| JwtError::SerializationError)?;
let claims_map = claims_value.as_object()
.ok_or(JwtError::SerializationError)?
.to_owned();
let mut payload = JwtPayload::new();
for (k, v) in claims_map {
payload.set_claim(&k, Some(v))
.map_err(|_| JwtError::TokenCreation)?;
}
let signer = jws::HS256.signer_from_jwk(&self.key)
.map_err(|_| JwtError::TokenCreation)?;
jwt::encode_with_signer(&payload, &header, &signer)
.map_err(|_| JwtError::TokenCreation)
}
pub fn verify_token(&self, token: &str) -> Result<UserClaims, JwtError> {
let verifier = jws::HS256.verifier_from_jwk(&self.key)
.map_err(|_| JwtError::TokenVerification)?;
let (payload, _) = jwt::decode_with_verifier(token, &verifier)
.map_err(|_| JwtError::InvalidToken)?;
// Convert payload to JSON value
let mut claims_value = json!({});
if let Some(Value::Object(map)) = claims_value.as_object_mut() {
for key in payload.claim_names() {
if let Some(value) = payload.claim(key) {
map.insert(key.to_string(), value.clone());
}
}
}
let claims = serde_json::from_value(claims_value)
.map_err(|_| JwtError::InvalidToken)?;
// Check expiration
if let Some(Value::Number(exp)) = payload.claim("exp") {
if let Some(exp) = exp.as_i64() {
let now = OffsetDateTime::now_utc().unix_timestamp();
if exp < now {
return Err(JwtError::ExpiredToken);
}
}
}
Ok(claims)
}
}
+1 -24
View File
@@ -1,3 +1,4 @@
pub mod auth;
pub mod callers;
pub mod db {
@@ -156,30 +157,6 @@ pub mod init {
}
}
mod auth {
use std::collections::BTreeMap;
use serde::{Deserialize, Serialize};
use axum::{
http::{Request, StatusCode},
middleware::Next,
response::{IntoResponse, Response},
Json,
};
use time::OffsetDateTime;
#[derive(Debug, Serialize, Deserialize)]
pub struct UserClaims {
pub sub: String, // Subject (user ID)
pub exp: i64, // Expiration time (UTC timestamp)
pub iat: i64, // Issued at (UTC timestamp)
#[serde(skip_serializing_if = "Option::is_none")]
pub roles: Option<Vec<String>>, // Optional roles
}
}
// TODO: Move elsewhere
fn get_full() -> String {