From 05525618514409101c1d6474dafb201386d14a30 Mon Sep 17 00:00:00 2001 From: phoenix Date: Thu, 30 Oct 2025 19:24:37 +0000 Subject: [PATCH] tsk-90: Add UserClaims (#91) Closes #90 Reviewed-on: https://git.kundeng.us/phoenix/icarus_models/pulls/91 Co-authored-by: phoenix Co-committed-by: phoenix --- .gitea/workflows/tag_release.yaml | 3 +++ Cargo.lock | 2 +- Cargo.toml | 2 +- src/token.rs | 40 ++++++++++++++++++++++++++++--- 4 files changed, 42 insertions(+), 5 deletions(-) diff --git a/.gitea/workflows/tag_release.yaml b/.gitea/workflows/tag_release.yaml index 0a829b4..1e59728 100644 --- a/.gitea/workflows/tag_release.yaml +++ b/.gitea/workflows/tag_release.yaml @@ -4,6 +4,9 @@ on: push: branches: - main + pull_request: + branches: + - main jobs: release: diff --git a/Cargo.lock b/Cargo.lock index 23e9d50..beb8475 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -149,7 +149,7 @@ checksum = "5419bdc4f6a9207fbeba6d11b604d481addf78ecd10c11ad51e76c2f6482748d" [[package]] name = "icarus_models" -version = "0.9.1" +version = "0.9.2" dependencies = [ "josekit", "rand", diff --git a/Cargo.toml b/Cargo.toml index 6566422..bd4eaa3 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "icarus_models" -version = "0.9.1" +version = "0.9.2" edition = "2024" rust-version = "1.90" description = "models used for the icarus project" diff --git a/src/token.rs b/src/token.rs index 5831a75..d359e1d 100644 --- a/src/token.rs +++ b/src/token.rs @@ -1,8 +1,8 @@ use std::default::Default; -use serde::{Deserialize, Serialize}; +use serde::Deserialize; -#[derive(Clone, Debug, Default, Deserialize, Serialize)] +#[derive(Clone, Debug, Default, Deserialize, serde::Serialize)] pub struct Token { pub scope: String, pub expiration: i64, @@ -11,7 +11,7 @@ pub struct Token { pub issued: i64, } -#[derive(Clone, Debug, Deserialize, Serialize)] +#[derive(Clone, Debug, Deserialize, serde::Serialize)] pub struct AccessToken { #[serde(alias = "init::is_uuid_nil")] pub user_id: uuid::Uuid, @@ -27,6 +27,21 @@ pub struct AccessToken { pub message: String, } +#[derive(Clone, Debug, serde::Serialize, Deserialize)] +pub struct UserClaims { + pub iss: String, + pub aud: String, // Audience + pub sub: String, // Subject (user ID) + #[serde(deserialize_with = "deserialize_i64_from_f64")] + pub exp: i64, // Expiration time (UTC timestamp) + #[serde(deserialize_with = "deserialize_i64_from_f64")] + pub iat: i64, // Issued at (UTC timestamp) + // pub azp: String, + // pub gty: String, + #[serde(skip_serializing_if = "Option::is_none")] + pub roles: Option>, // Optional roles +} + impl AccessToken { /// Get the token fit for Bearer authentication pub fn bearer_token(&self) -> String { @@ -56,6 +71,25 @@ impl Token { } } +fn deserialize_i64_from_f64<'de, D>(deserializer: D) -> Result +where + D: serde::Deserializer<'de>, +{ + let val = f64::deserialize(deserializer)?; + // Handle NaN and infinity cases + if val.is_nan() || val.is_infinite() { + return Err(serde::de::Error::custom("invalid float value")); + } + // Round to nearest integer and convert + let rounded = val.round(); + // Check if the rounded value can fit in i64 + if rounded < (i64::MIN as f64) || rounded > (i64::MAX as f64) { + Err(serde::de::Error::custom("float out of i64 range")) + } else { + Ok(rounded as i64) + } +} + pub fn get_issued() -> time::Result { Ok(time::OffsetDateTime::now_utc()) }