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
Generated
+11 -4
View File
@@ -123,6 +123,12 @@ dependencies = [
"windows-targets 0.52.6",
]
[[package]]
name = "base64"
version = "0.21.7"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "9d297deb1925b89f2ccc13d7635fa0714f12c87adce1c75356b39ca9b7178567"
[[package]]
name = "base64"
version = "0.22.1"
@@ -780,6 +786,7 @@ name = "icarus"
version = "0.1.100"
dependencies = [
"axum",
"base64 0.21.7",
"common-multipart-rfc7578",
"futures",
"icarus_envy",
@@ -961,7 +968,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "a808e078330e6af222eb0044b71d4b1ff981bfef43e7bc8133a88234e0c86a0c"
dependencies = [
"anyhow",
"base64",
"base64 0.22.1",
"flate2",
"openssl",
"regex",
@@ -1792,7 +1799,7 @@ version = "0.8.6"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "ee6798b1838b6a0f69c007c133b8df5866302197e404e8b6ee8ed3e3a5e68dc6"
dependencies = [
"base64",
"base64 0.22.1",
"bytes",
"crc",
"crossbeam-queue",
@@ -1868,7 +1875,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "aa003f0038df784eb8fecbbac13affe3da23b45194bd57dba231c8f48199c526"
dependencies = [
"atoi",
"base64",
"base64 0.22.1",
"bitflags",
"byteorder",
"bytes",
@@ -1912,7 +1919,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "db58fcd5a53cf07c184b154801ff91347e4c30d17a3562a635ff028ad5deda46"
dependencies = [
"atoi",
"base64",
"base64 0.22.1",
"bitflags",
"byteorder",
"crc",
+1
View File
@@ -19,6 +19,7 @@ uuid = { version = "1.17.0", features = ["v4", "serde"] }
sqlx = { version = "0.8.6", features = ["postgres", "runtime-tokio-native-tls", "time", "uuid"] }
time = { version = "0.3.41", features = ["formatting", "macros", "parsing", "serde"] }
thiserror = "1.0"
base64 = "0.21"
josekit = { version = "0.10.1" }
icarus_meta = { git = "ssh://git@git.kundeng.us/phoenix/icarus_meta.git", tag = "v0.3.0-devel-f4b71de969-680" }
icarus_models = { git = "ssh://git@git.kundeng.us/phoenix/icarus_models.git", tag = "v0.5.1-devel-1c5de9dc26-111" }
+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 {