auth: newtype jti claims, sessions, & store

Lewis: May this revision serve well! <lu5a@proton.me>
This commit is contained in:
Lewis
2026-07-12 08:03:14 +02:00
parent a405d523ca
commit 8559764d31
17 changed files with 113 additions and 114 deletions
@@ -14,7 +14,7 @@ use tranquil_pds::auth::NormalizedLoginIdentifier;
use tranquil_pds::auth::{ServiceTokenVerifier, generate_app_password, is_service_token};
use tranquil_pds::rate_limit::{AccountCreationLimit, PasswordResetLimit, RateLimited};
use tranquil_pds::state::AppState;
use tranquil_pds::types::{Did, Handle, PlainPassword};
use tranquil_pds::types::{Did, Handle, Jti, Nsid, PlainPassword};
use tranquil_pds::validation::validate_password;
fn generate_setup_token() -> String {
@@ -368,7 +368,7 @@ pub async fn create_passkey_account(
let access_jwt = if byod_auth.is_some() {
match tranquil_pds::auth::create_access_token_with_metadata(&did, &secret_key_bytes) {
Ok(token_meta) => {
let refresh_jti = uuid::Uuid::new_v4().to_string();
let refresh_jti = Jti::from(uuid::Uuid::new_v4().to_string());
let refresh_expires = chrono::Utc::now() + chrono::Duration::hours(24);
let session_data = tranquil_db_traits::SessionTokenCreate {
did: did_typed.clone(),
+12 -11
View File
@@ -8,6 +8,7 @@ use chrono::{DateTime, Duration, Utc};
use hmac::{Hmac, Mac};
use k256::ecdsa::{Signature, SigningKey, signature::Signer};
use sha2::Sha256;
use tranquil_types::{Did, Jti, Nsid};
type HmacSha256 = Hmac<Sha256>;
@@ -83,7 +84,7 @@ pub fn create_access_token_with_jti(
scopes: Option<&str>,
controller_did: Option<&str>,
hostname: Option<&str>,
jti: &str,
jti: &Jti,
expires_at: DateTime<Utc>,
) -> Result<String> {
let scope = scopes.unwrap_or(TokenScope::Access.as_str());
@@ -94,7 +95,7 @@ pub fn create_access_token_with_jti(
TokenType::Access,
key_bytes,
expires_at,
jti.to_string(),
jti.clone(),
act,
hostname,
)?
@@ -106,7 +107,7 @@ pub fn create_access_token_with_jti(
pub fn create_refresh_token_with_jti(
did: &str,
key_bytes: &[u8],
jti: &str,
jti: &Jti,
expires_at: DateTime<Utc>,
) -> Result<String> {
Ok(create_signed_token_pinned(
@@ -115,7 +116,7 @@ pub fn create_refresh_token_with_jti(
TokenType::Refresh,
key_bytes,
expires_at,
jti.to_string(),
jti.clone(),
None,
None,
)?
@@ -142,8 +143,8 @@ pub fn create_service_token(
exp: expiration,
iat: Utc::now().timestamp(),
scope: None,
lxm: lxm.map(ToOwned::to_owned),
jti: uuid::Uuid::new_v4().to_string(),
lxm: lxm.cloned(),
jti: Jti::new(uuid::Uuid::new_v4().to_string()),
act: None,
};
@@ -173,7 +174,7 @@ fn create_signed_token_with_act(
let expires_at = Utc::now()
.checked_add_signed(duration)
.expect("valid timestamp");
let jti = uuid::Uuid::new_v4().to_string();
let jti = Jti::new(uuid::Uuid::new_v4().to_string());
create_signed_token_pinned(did, scope, typ, key_bytes, expires_at, jti, act, hostname)
}
@@ -184,7 +185,7 @@ fn create_signed_token_pinned(
typ: TokenType,
key_bytes: &[u8],
expires_at: DateTime<Utc>,
jti: String,
jti: Jti,
act: Option<ActClaim>,
hostname: Option<&str>,
) -> Result<TokenWithMetadata> {
@@ -294,8 +295,8 @@ pub fn create_service_token_hs256(
exp: expiration,
iat: Utc::now().timestamp(),
scope: None,
lxm: Some(lxm.to_string()),
jti: uuid::Uuid::new_v4().to_string(),
lxm: Some(lxm.clone()),
jti: Jti::new(uuid::Uuid::new_v4().to_string()),
act: None,
};
@@ -314,7 +315,7 @@ fn create_hs256_token_with_metadata(
.expect("valid timestamp");
let expiration = expires_at.timestamp();
let jti = uuid::Uuid::new_v4().to_string();
let jti = Jti::new(uuid::Uuid::new_v4().to_string());
let claims = Claims {
iss: did.to_owned(),
+3 -2
View File
@@ -2,6 +2,7 @@ use chrono::{DateTime, Utc};
use serde::{Deserialize, Serialize, de, ser};
use std::fmt;
use std::str::FromStr;
use tranquil_types::{Did, Jti, Nsid};
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
pub enum TokenType {
@@ -217,7 +218,7 @@ pub struct Claims {
pub scope: Option<String>,
#[serde(skip_serializing_if = "Option::is_none")]
pub lxm: Option<Nsid>,
pub jti: String,
pub jti: Jti,
#[serde(skip_serializing_if = "Option::is_none")]
pub act: Option<ActClaim>,
}
@@ -240,7 +241,7 @@ pub struct TokenData<T> {
pub struct TokenWithMetadata {
pub token: String,
pub jti: String,
pub jti: Jti,
pub expires_at: DateTime<Utc>,
}
+3 -2
View File
@@ -10,6 +10,7 @@ use hmac::{Hmac, Mac};
use k256::ecdsa::{Signature, SigningKey, VerifyingKey, signature::Verifier};
use sha2::Sha256;
use subtle::ConstantTimeEq;
use tranquil_types::{Did, Jti};
type HmacSha256 = Hmac<Sha256>;
@@ -29,7 +30,7 @@ pub fn get_did_from_token(token: &str) -> Result<String, TokenDecodeError> {
Ok(claims.sub.unwrap_or(claims.iss))
}
pub fn get_jti_from_token(token: &str) -> Result<String, TokenDecodeError> {
pub fn get_jti_from_token(token: &str) -> Result<Jti, TokenDecodeError> {
let parts: Vec<&str> = token.split('.').collect();
if parts.len() != 3 {
return Err(TokenDecodeError::InvalidFormat);
@@ -45,7 +46,7 @@ pub fn get_jti_from_token(token: &str) -> Result<String, TokenDecodeError> {
claims
.get("jti")
.and_then(|j| j.as_str())
.map(|s| s.to_string())
.map(Jti::new)
.ok_or(TokenDecodeError::MissingClaim)
}
+17 -17
View File
@@ -84,8 +84,8 @@ impl std::fmt::Display for SessionId {
pub struct SessionToken {
pub id: SessionId,
pub did: Did,
pub access_jti: String,
pub refresh_jti: String,
pub access_jti: Jti,
pub refresh_jti: Jti,
pub access_expires_at: DateTime<Utc>,
pub refresh_expires_at: DateTime<Utc>,
pub login_type: LoginType,
@@ -100,8 +100,8 @@ pub struct SessionToken {
#[derive(Debug, Clone)]
pub struct SessionTokenCreate {
pub did: Did,
pub access_jti: String,
pub refresh_jti: String,
pub access_jti: Jti,
pub refresh_jti: Jti,
pub access_expires_at: DateTime<Utc>,
pub refresh_expires_at: DateTime<Utc>,
pub login_type: LoginType,
@@ -124,7 +124,7 @@ pub struct SessionForRefresh {
#[derive(Debug, Clone)]
pub struct SessionListItem {
pub id: SessionId,
pub access_jti: String,
pub access_jti: Jti,
pub created_at: DateTime<Utc>,
pub refresh_expires_at: DateTime<Utc>,
}
@@ -175,8 +175,8 @@ pub struct RefreshGraceReplay {
pub did: Did,
pub scope: Option<String>,
pub controller_did: Option<Did>,
pub access_jti: String,
pub refresh_jti: String,
pub access_jti: Jti,
pub refresh_jti: Jti,
pub access_expires_at: DateTime<Utc>,
pub refresh_expires_at: DateTime<Utc>,
pub key_bytes: Vec<u8>,
@@ -205,10 +205,10 @@ pub enum RefreshGraceLookup {
#[derive(Debug, Clone)]
pub struct SessionRefreshData {
pub did: Did,
pub old_refresh_jti: String,
pub old_refresh_jti: Jti,
pub session_id: SessionId,
pub new_access_jti: String,
pub new_refresh_jti: String,
pub new_access_jti: Jti,
pub new_refresh_jti: Jti,
pub new_access_expires_at: DateTime<Utc>,
pub new_refresh_expires_at: DateTime<Utc>,
}
@@ -219,17 +219,17 @@ pub trait SessionRepository: Send + Sync {
async fn get_session_by_access_jti(
&self,
access_jti: &str,
access_jti: &Jti,
) -> Result<Option<SessionToken>, DbError>;
async fn get_session_for_refresh(
&self,
refresh_jti: &str,
refresh_jti: &Jti,
) -> Result<Option<SessionForRefresh>, DbError>;
async fn delete_session_by_access_jti(
&self,
access_jti: &str,
access_jti: &Jti,
did: &Did,
) -> Result<u64, DbError>;
@@ -244,7 +244,7 @@ pub trait SessionRepository: Send + Sync {
async fn delete_sessions_by_did_except_jti(
&self,
did: &Did,
except_jti: &str,
except_jti: &Jti,
) -> Result<u64, DbError>;
async fn list_sessions_by_did(&self, did: &Did) -> Result<Vec<SessionListItem>, DbError>;
@@ -253,7 +253,7 @@ pub trait SessionRepository: Send + Sync {
&self,
session_id: SessionId,
did: &Did,
) -> Result<Option<String>, DbError>;
) -> Result<Option<Jti>, DbError>;
async fn delete_sessions_by_app_password(
&self,
@@ -265,9 +265,9 @@ pub trait SessionRepository: Send + Sync {
&self,
did: &Did,
app_password_name: &str,
) -> Result<Vec<String>, DbError>;
) -> Result<Vec<Jti>, DbError>;
async fn lookup_refresh_grace(&self, refresh_jti: &str) -> Result<RefreshGraceLookup, DbError>;
async fn lookup_refresh_grace(&self, refresh_jti: &Jti) -> Result<RefreshGraceLookup, DbError>;
async fn list_app_passwords(&self, user_id: Uuid) -> Result<Vec<AppPasswordRecord>, DbError>;
+2 -2
View File
@@ -119,7 +119,7 @@ pub trait UserRepository: Send + Sync {
async fn get_session_access_expiry(
&self,
did: &Did,
access_jti: &str,
access_jti: &Jti,
) -> Result<Option<DateTime<Utc>>, DbError>;
async fn get_oauth_token_with_user(
@@ -926,7 +926,7 @@ pub struct UserIdAndPasswordHash {
#[derive(Debug, Clone)]
pub struct PasswordResetResult {
pub did: Did,
pub session_jtis: Vec<String>,
pub session_jtis: Vec<Jti>,
}
#[derive(Debug, Clone)]
+23 -23
View File
@@ -34,8 +34,8 @@ impl SessionRepository for PostgresSessionRepository {
RETURNING id
"#,
data.did.as_str(),
data.access_jti,
data.refresh_jti,
data.access_jti.as_str(),
data.refresh_jti.as_str(),
data.access_expires_at,
data.refresh_expires_at,
data.login_type.is_legacy(),
@@ -53,7 +53,7 @@ impl SessionRepository for PostgresSessionRepository {
async fn get_session_by_access_jti(
&self,
access_jti: &str,
access_jti: &Jti,
) -> Result<Option<SessionToken>, DbError> {
let row = sqlx::query!(
r#"
@@ -63,7 +63,7 @@ impl SessionRepository for PostgresSessionRepository {
FROM session_tokens
WHERE access_jti = $1
"#,
access_jti
access_jti.as_str()
)
.fetch_optional(&self.pool)
.await
@@ -72,8 +72,8 @@ impl SessionRepository for PostgresSessionRepository {
Ok(row.map(|r| SessionToken {
id: SessionId::new(r.id),
did: Did::from(r.did),
access_jti: r.access_jti,
refresh_jti: r.refresh_jti,
access_jti: Jti::from(r.access_jti),
refresh_jti: Jti::from(r.refresh_jti),
access_expires_at: r.access_expires_at,
refresh_expires_at: r.refresh_expires_at,
login_type: LoginType::from_legacy_flag(r.legacy_login),
@@ -88,7 +88,7 @@ impl SessionRepository for PostgresSessionRepository {
async fn get_session_for_refresh(
&self,
refresh_jti: &str,
refresh_jti: &Jti,
) -> Result<Option<SessionForRefresh>, DbError> {
let row = sqlx::query!(
r#"
@@ -98,7 +98,7 @@ impl SessionRepository for PostgresSessionRepository {
JOIN user_keys k ON u.id = k.user_id
WHERE st.refresh_jti = $1 AND st.refresh_expires_at > NOW()
"#,
refresh_jti
refresh_jti.as_str()
)
.fetch_optional(&self.pool)
.await
@@ -116,12 +116,12 @@ impl SessionRepository for PostgresSessionRepository {
async fn delete_session_by_access_jti(
&self,
access_jti: &str,
access_jti: &Jti,
did: &Did,
) -> Result<u64, DbError> {
let result = sqlx::query!(
"DELETE FROM session_tokens WHERE access_jti = $1 AND did = $2",
access_jti,
access_jti.as_str(),
did.as_str()
)
.execute(&self.pool)
@@ -160,7 +160,7 @@ impl SessionRepository for PostgresSessionRepository {
async fn delete_sessions_by_did_except_jti(
&self,
did: &Did,
except_jti: &str,
except_jti: &Jti,
) -> Result<u64, DbError> {
let result = sqlx::query!(
"DELETE FROM session_tokens WHERE did = $1 AND access_jti != $2",
@@ -192,7 +192,7 @@ impl SessionRepository for PostgresSessionRepository {
.into_iter()
.map(|r| SessionListItem {
id: SessionId::new(r.id),
access_jti: r.access_jti,
access_jti: Jti::from(r.access_jti),
created_at: r.created_at,
refresh_expires_at: r.refresh_expires_at,
})
@@ -203,7 +203,7 @@ impl SessionRepository for PostgresSessionRepository {
&self,
session_id: SessionId,
did: &Did,
) -> Result<Option<String>, DbError> {
) -> Result<Option<Jti>, DbError> {
let row = sqlx::query_scalar!(
"SELECT access_jti FROM session_tokens WHERE id = $1 AND did = $2",
session_id.as_i32(),
@@ -213,7 +213,7 @@ impl SessionRepository for PostgresSessionRepository {
.await
.map_err(map_sqlx_error)?;
Ok(row)
Ok(row.map(Jti::from))
}
async fn delete_sessions_by_app_password(
@@ -237,7 +237,7 @@ impl SessionRepository for PostgresSessionRepository {
&self,
did: &Did,
app_password_name: &str,
) -> Result<Vec<String>, DbError> {
) -> Result<Vec<Jti>, DbError> {
let rows = sqlx::query_scalar!(
"SELECT access_jti FROM session_tokens WHERE did = $1 AND app_password_name = $2",
did.as_str(),
@@ -247,10 +247,10 @@ impl SessionRepository for PostgresSessionRepository {
.await
.map_err(map_sqlx_error)?;
Ok(rows)
Ok(rows.into_iter().map(Jti::from).collect())
}
async fn lookup_refresh_grace(&self, refresh_jti: &str) -> Result<RefreshGraceLookup, DbError> {
async fn lookup_refresh_grace(&self, refresh_jti: &Jti) -> Result<RefreshGraceLookup, DbError> {
let row = sqlx::query!(
r#"
SELECT u.used_at, st.id AS session_id, st.did, st.scope, st.controller_did,
@@ -262,7 +262,7 @@ impl SessionRepository for PostgresSessionRepository {
JOIN user_keys k ON us.id = k.user_id
WHERE u.refresh_jti = $1
"#,
refresh_jti
refresh_jti.as_str()
)
.fetch_optional(&self.pool)
.await
@@ -281,8 +281,8 @@ impl SessionRepository for PostgresSessionRepository {
did: Did::from(r.did),
scope: r.scope,
controller_did: r.controller_did.map(Did::from),
access_jti: r.access_jti,
refresh_jti: r.refresh_jti,
access_jti: Jti::from(r.access_jti),
refresh_jti: Jti::from(r.refresh_jti),
access_expires_at: r.access_expires_at,
refresh_expires_at: r.refresh_expires_at,
key_bytes: r.key_bytes,
@@ -524,7 +524,7 @@ impl SessionRepository for PostgresSessionRepository {
// rest see `rows_affected == 0`.
let claimed = sqlx::query!(
"INSERT INTO used_refresh_tokens (refresh_jti, session_id) VALUES ($1, $2) ON CONFLICT (refresh_jti) DO NOTHING",
data.old_refresh_jti,
data.old_refresh_jti.as_str(),
data.session_id.as_i32()
)
.execute(&mut *tx)
@@ -567,8 +567,8 @@ impl SessionRepository for PostgresSessionRepository {
refresh_expires_at = $4, updated_at = NOW()
WHERE id = $5
"#,
data.new_access_jti,
data.new_refresh_jti,
data.new_access_jti.as_str(),
data.new_refresh_jti.as_str(),
data.new_access_expires_at,
data.new_refresh_expires_at,
data.session_id.as_i32()
+7 -4
View File
@@ -176,12 +176,12 @@ impl UserRepository for PostgresUserRepository {
async fn get_session_access_expiry(
&self,
did: &Did,
access_jti: &str,
access_jti: &Jti,
) -> Result<Option<DateTime<Utc>>, DbError> {
let row = sqlx::query!(
"SELECT access_expires_at FROM session_tokens WHERE did = $1 AND access_jti = $2",
did.as_str(),
access_jti
access_jti.as_str()
)
.fetch_optional(&self.pool)
.await
@@ -1874,13 +1874,16 @@ impl UserRepository for PostgresUserRepository {
.await
.map_err(map_sqlx_error)?;
let session_jtis: Vec<String> = sqlx::query_scalar!(
let session_jtis: Vec<Jti> = sqlx::query_scalar!(
"SELECT access_jti FROM session_tokens WHERE did = $1",
user_did
)
.fetch_all(&mut *tx)
.await
.map_err(map_sqlx_error)?;
.map_err(map_sqlx_error)?
.into_iter()
.map(Jti::from)
.collect();
sqlx::query!("DELETE FROM session_tokens WHERE did = $1", user_did)
.execute(&mut *tx)
+2 -2
View File
@@ -36,7 +36,7 @@ pub struct DPoPJwk {
#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct DPoPProofPayload {
pub jti: String,
pub jti: DPoPProofId,
pub htm: String,
pub htu: String,
pub iat: i64,
@@ -181,7 +181,7 @@ impl DPoPVerifier {
let jkt = compute_jwk_thumbprint(&header.jwk)?;
Ok(DPoPVerifyResult {
jkt: jkt.into(),
jti: payload.jti.clone().into(),
jti: payload.jti.clone(),
})
}
}
-12
View File
@@ -271,18 +271,6 @@ pub struct TokenRequest {
pub client_secret: Option<String>,
}
#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct DPoPClaims {
pub jti: String,
pub htm: String,
pub htu: String,
pub iat: i64,
#[serde(skip_serializing_if = "Option::is_none")]
pub ath: Option<String>,
#[serde(skip_serializing_if = "Option::is_none")]
pub nonce: Option<String>,
}
#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct JwkPublicKey {
pub kty: String,
+1 -1
View File
@@ -105,7 +105,7 @@ pub fn extract_auth_token_from_header(auth_header: Option<&str>) -> Option<Extra
None
}
pub fn extract_jti_from_headers(headers: &axum::http::HeaderMap) -> Option<String> {
pub fn extract_jti_from_headers(headers: &axum::http::HeaderMap) -> Option<crate::types::Jti> {
let auth_header = headers.get(AUTHORIZATION)?.to_str().ok()?;
let token = extract_bearer_token_from_header(Some(auth_header))?;
tranquil_auth::get_jti_from_token(&token).ok()
+2 -2
View File
@@ -6,7 +6,7 @@ use reqwest::Client;
use serde::{Deserialize, Serialize};
use std::time::Duration;
use tracing::debug;
use tranquil_types::Did;
use tranquil_types::{Did, Jti, Nsid};
#[derive(Debug, thiserror::Error)]
pub enum ServiceTokenError {
@@ -122,7 +122,7 @@ pub struct ServiceTokenClaims {
#[serde(skip_serializing_if = "Option::is_none")]
pub lxm: Option<String>,
#[serde(default)]
pub jti: Option<String>,
pub jti: Option<Jti>,
}
impl ServiceTokenClaims {
+17 -15
View File
@@ -1437,12 +1437,12 @@ impl<S: StorageIO + 'static> tranquil_db_traits::SessionRepository for Metastore
async fn get_session_by_access_jti(
&self,
access_jti: &str,
access_jti: &Jti,
) -> Result<Option<tranquil_db_traits::SessionToken>, DbError> {
let (tx, rx) = oneshot::channel();
self.pool.send(MetastoreRequest::Session(
SessionRequest::GetSessionByAccessJti {
access_jti: access_jti.to_owned(),
access_jti: access_jti.to_string(),
tx,
},
))?;
@@ -1451,12 +1451,12 @@ impl<S: StorageIO + 'static> tranquil_db_traits::SessionRepository for Metastore
async fn get_session_for_refresh(
&self,
refresh_jti: &str,
refresh_jti: &Jti,
) -> Result<Option<tranquil_db_traits::SessionForRefresh>, DbError> {
let (tx, rx) = oneshot::channel();
self.pool.send(MetastoreRequest::Session(
SessionRequest::GetSessionForRefresh {
refresh_jti: refresh_jti.to_owned(),
refresh_jti: refresh_jti.to_string(),
tx,
},
))?;
@@ -1465,13 +1465,13 @@ impl<S: StorageIO + 'static> tranquil_db_traits::SessionRepository for Metastore
async fn delete_session_by_access_jti(
&self,
access_jti: &str,
access_jti: &Jti,
did: &Did,
) -> Result<u64, DbError> {
let (tx, rx) = oneshot::channel();
self.pool.send(MetastoreRequest::Session(
SessionRequest::DeleteSessionByAccessJti {
access_jti: access_jti.to_owned(),
access_jti: access_jti.to_string(),
did: did.clone(),
tx,
},
@@ -1509,7 +1509,7 @@ impl<S: StorageIO + 'static> tranquil_db_traits::SessionRepository for Metastore
async fn delete_sessions_by_did_except_jti(
&self,
did: &Did,
except_jti: &str,
except_jti: &Jti,
) -> Result<u64, DbError> {
let (tx, rx) = oneshot::channel();
self.pool.send(MetastoreRequest::Session(
@@ -1540,7 +1540,7 @@ impl<S: StorageIO + 'static> tranquil_db_traits::SessionRepository for Metastore
&self,
session_id: tranquil_db_traits::SessionId,
did: &Did,
) -> Result<Option<String>, DbError> {
) -> Result<Option<Jti>, DbError> {
let (tx, rx) = oneshot::channel();
self.pool.send(MetastoreRequest::Session(
SessionRequest::GetSessionAccessJtiById {
@@ -1549,7 +1549,7 @@ impl<S: StorageIO + 'static> tranquil_db_traits::SessionRepository for Metastore
tx,
},
))?;
recv(rx).await
recv(rx).await.map(|jti: Option<String>| jti.map(Jti::from))
}
async fn delete_sessions_by_app_password(
@@ -1572,7 +1572,7 @@ impl<S: StorageIO + 'static> tranquil_db_traits::SessionRepository for Metastore
&self,
did: &Did,
app_password_name: &str,
) -> Result<Vec<String>, DbError> {
) -> Result<Vec<Jti>, DbError> {
let (tx, rx) = oneshot::channel();
self.pool.send(MetastoreRequest::Session(
SessionRequest::GetSessionJtisByAppPassword {
@@ -1581,17 +1581,19 @@ impl<S: StorageIO + 'static> tranquil_db_traits::SessionRepository for Metastore
tx,
},
))?;
recv(rx).await
recv(rx)
.await
.map(|jtis: Vec<String>| jtis.into_iter().map(Jti::from).collect())
}
async fn lookup_refresh_grace(
&self,
refresh_jti: &str,
refresh_jti: &Jti,
) -> Result<tranquil_db_traits::RefreshGraceLookup, DbError> {
let (tx, rx) = oneshot::channel();
self.pool.send(MetastoreRequest::Session(
SessionRequest::LookupRefreshGrace {
refresh_jti: refresh_jti.to_owned(),
refresh_jti: refresh_jti.to_string(),
tx,
},
))?;
@@ -3328,13 +3330,13 @@ impl<S: StorageIO + 'static> tranquil_db_traits::UserRepository for MetastoreCli
async fn get_session_access_expiry(
&self,
did: &Did,
access_jti: &str,
access_jti: &Jti,
) -> Result<Option<DateTime<Utc>>, DbError> {
let (tx, rx) = oneshot::channel();
self.pool.send(MetastoreRequest::User(
UserRequest::GetSessionAccessExpiry {
did: did.clone(),
access_jti: access_jti.to_owned(),
access_jti: access_jti.to_string(),
tx,
},
))?;
@@ -6094,7 +6094,7 @@ mod tests {
use super::*;
use crate::eventlog::{EventLog, EventLogConfig};
use crate::metastore::MetastoreConfig;
use tranquil_types::{Did, Handle};
use tranquil_types::{Did, Handle, InviteCode, Jti};
struct TestHarness {
_metastore_dir: tempfile::TempDir,
@@ -6308,10 +6308,10 @@ mod tests {
let refresh = SessionRequest::RefreshSessionAtomic {
data: tranquil_db_traits::SessionRefreshData {
did: did.clone(),
old_refresh_jti: "r0".to_string(),
old_refresh_jti: Jti::new("r0"),
session_id: sid,
new_access_jti: "a1".to_string(),
new_refresh_jti: "r1".to_string(),
new_access_jti: Jti::new("a1"),
new_refresh_jti: Jti::new("r1"),
new_access_expires_at: Utc::now(),
new_refresh_expires_at: Utc::now(),
},
+5 -5
View File
@@ -438,8 +438,8 @@ mod tests {
let now = chrono::Utc::now();
tranquil_db_traits::SessionTokenCreate {
did: tranquil_types::Did::new(did.to_string()).unwrap(),
access_jti: access_jti.to_string(),
refresh_jti: refresh_jti.to_string(),
access_jti: tranquil_types::Jti::new(access_jti),
refresh_jti: tranquil_types::Jti::new(refresh_jti),
access_expires_at: now + chrono::Duration::minutes(120),
refresh_expires_at: now + chrono::Duration::days(90),
login_type: tranquil_db_traits::LoginType::Legacy,
@@ -484,10 +484,10 @@ mod tests {
let now = chrono::Utc::now();
tranquil_db_traits::SessionRefreshData {
did: did.clone(),
old_refresh_jti: old_refresh_jti.to_string(),
old_refresh_jti: tranquil_types::Jti::new(old_refresh_jti),
session_id,
new_access_jti: new_access_jti.to_string(),
new_refresh_jti: new_refresh_jti.to_string(),
new_access_jti: tranquil_types::Jti::new(new_access_jti),
new_refresh_jti: tranquil_types::Jti::new(new_refresh_jti),
new_access_expires_at: now + chrono::Duration::minutes(120),
new_refresh_expires_at: now + chrono::Duration::days(90),
}
@@ -85,8 +85,8 @@ impl SessionOps {
id: SessionId::new(v.id),
did: Did::new(v.did.clone())
.map_err(|_| MetastoreError::CorruptData("invalid session did"))?,
access_jti: v.access_jti.clone(),
refresh_jti: v.refresh_jti.clone(),
access_jti: Jti::from(v.access_jti.clone()),
refresh_jti: Jti::from(v.refresh_jti.clone()),
access_expires_at: DateTime::from_timestamp_millis(v.access_expires_at_ms)
.unwrap_or_default(),
refresh_expires_at: DateTime::from_timestamp_millis(v.refresh_expires_at_ms)
@@ -241,8 +241,8 @@ impl SessionOps {
.controller_did
.clone()
.and_then(|d| Did::new(d).ok()),
access_jti: session.access_jti.clone(),
refresh_jti: session.refresh_jti.clone(),
access_jti: Jti::from(session.access_jti.clone()),
refresh_jti: Jti::from(session.refresh_jti.clone()),
access_expires_at,
refresh_expires_at,
key_bytes,
@@ -285,8 +285,8 @@ impl SessionOps {
let value = SessionTokenValue {
id: session_id,
did: data.did.to_string(),
access_jti: data.access_jti.clone(),
refresh_jti: data.refresh_jti.clone(),
access_jti: data.access_jti.to_string(),
refresh_jti: data.refresh_jti.to_string(),
access_expires_at_ms: data.access_expires_at.timestamp_millis(),
refresh_expires_at_ms: data.refresh_expires_at.timestamp_millis(),
login_type: login_type_to_u8(data.login_type),
@@ -501,7 +501,7 @@ impl SessionOps {
.iter()
.map(|s| SessionListItem {
id: SessionId::new(s.id),
access_jti: s.access_jti.clone(),
access_jti: Jti::from(s.access_jti.clone()),
created_at: DateTime::from_timestamp_millis(s.created_at_ms).unwrap_or_default(),
refresh_expires_at: DateTime::from_timestamp_millis(s.refresh_expires_at_ms)
.unwrap_or_default(),
@@ -848,8 +848,8 @@ impl SessionOps {
let old_refresh_jti = session.refresh_jti.clone();
let rotated_at_ms = Utc::now().timestamp_millis();
session.access_jti = data.new_access_jti.clone();
session.refresh_jti = data.new_refresh_jti.clone();
session.access_jti = data.new_access_jti.to_string();
session.refresh_jti = data.new_refresh_jti.to_string();
session.access_expires_at_ms = data.new_access_expires_at.timestamp_millis();
session.refresh_expires_at_ms = data.new_refresh_expires_at.timestamp_millis();
session.updated_at_ms = rotated_at_ms;
@@ -2210,7 +2210,10 @@ impl UserOps {
})
.collect();
let session_jtis: Vec<String> = sessions.iter().map(|(_, _, jti)| jti.clone()).collect();
let session_jtis: Vec<Jti> = sessions
.iter()
.map(|(_, _, jti)| Jti::from(jti.clone()))
.collect();
let mut batch = self.db.batch();