ironflow_store/entities/
api_key.rs1use chrono::{DateTime, Utc};
4use serde::{Deserialize, Serialize};
5use uuid::Uuid;
6
7use crate::entities::api_key_scope::ApiKeyScope;
8
9#[derive(Debug, Clone, Serialize, Deserialize)]
11pub struct ApiKey {
12 pub id: Uuid,
14 pub user_id: Uuid,
16 pub name: String,
18 #[serde(skip_serializing)]
20 pub key_hash: String,
21 pub key_prefix: String,
23 pub scopes: Vec<ApiKeyScope>,
25 pub is_active: bool,
27 pub expires_at: Option<DateTime<Utc>>,
29 pub last_used_at: Option<DateTime<Utc>>,
31 pub created_at: DateTime<Utc>,
33 pub updated_at: DateTime<Utc>,
35 pub rate_limit_override: Option<u32>,
41}
42
43#[derive(Debug, Clone)]
45pub struct NewApiKey {
46 pub user_id: Uuid,
48 pub name: String,
50 pub key_hash: String,
52 pub key_prefix: String,
54 pub scopes: Vec<ApiKeyScope>,
56 pub expires_at: Option<DateTime<Utc>>,
58 pub rate_limit_override: Option<u32>,
61}
62
63#[derive(Debug, Clone, Default)]
65pub struct ApiKeyUpdate {
66 pub name: Option<String>,
68 pub scopes: Option<Vec<ApiKeyScope>>,
70 pub is_active: Option<bool>,
72 pub expires_at: Option<Option<DateTime<Utc>>>,
74 pub rate_limit_override: Option<Option<u32>>,
76}
77
78#[cfg(test)]
79mod tests {
80 use super::*;
81
82 #[test]
83 fn api_key_serde_excludes_hash() {
84 let key = ApiKey {
85 id: Uuid::now_v7(),
86 user_id: Uuid::now_v7(),
87 name: "test-key".to_string(),
88 key_hash: "secret_hash".to_string(),
89 key_prefix: "irfl_abc".to_string(),
90 scopes: vec![ApiKeyScope::RunsRead],
91 is_active: true,
92 expires_at: None,
93 last_used_at: None,
94 created_at: Utc::now(),
95 updated_at: Utc::now(),
96 rate_limit_override: None,
97 };
98
99 let json = serde_json::to_string(&key).expect("serialize");
100 assert!(!json.contains("secret_hash"));
101 assert!(json.contains("test-key"));
102 assert!(json.contains("irfl_abc"));
103 }
104
105 #[test]
106 fn api_key_update_default_is_empty() {
107 let update = ApiKeyUpdate::default();
108 assert!(update.name.is_none());
109 assert!(update.scopes.is_none());
110 assert!(update.is_active.is_none());
111 assert!(update.expires_at.is_none());
112 assert!(update.rate_limit_override.is_none());
113 }
114}