shared/domain/signing_keys/
model.rs1use crate::domain::query::IntoBsonDocument;
2use chrono::{DateTime, Utc};
3use mongodb::bson;
4use serde::{Deserialize, Serialize};
5use sqlx::FromRow;
6use utoipa::ToSchema;
7
8use super::super::serde::{
9 deserialize_datetime, deserialize_object_id_as_string, deserialize_option_datetime,
10};
11
12pub struct SigningKeys {
13 pub private_key: String,
14 pub key: SigningKey,
15}
16
17#[derive(Clone, Debug, PartialEq, Eq, Deserialize, Serialize, FromRow, ToSchema)]
18pub struct SigningKey {
19 #[serde(
20 rename = "_id",
21 default,
22 skip_serializing_if = "Option::is_none",
23 deserialize_with = "deserialize_object_id_as_string"
24 )]
25 pub id: Option<String>,
26
27 #[sqlx(rename = "createdAt")]
28 #[serde(rename = "createdAt", deserialize_with = "deserialize_datetime")]
29 pub created_at: DateTime<Utc>,
30
31 #[sqlx(rename = "rotatedAt")]
32 #[serde(rename = "rotatedAt", deserialize_with = "deserialize_option_datetime")]
33 pub rotated_at: Option<DateTime<Utc>>,
34
35 #[sqlx(rename = "expiresAt")]
36 #[serde(rename = "expiresAt", deserialize_with = "deserialize_option_datetime")]
37 pub expires_at: Option<DateTime<Utc>>,
38
39 pub status: String, pub encrypted_private_key: String,
42 pub public_key: String,
43 pub algorithm: String,
44 pub kid: String,
45 pub kty: String,
46}
47
48impl SigningKey {
49 pub fn id(&self) -> Result<&str, crate::error::CoreError> {
50 self.id.as_deref().ok_or_else(|| {
51 tracing::error!(
52 error_code = "ValidationError::Malformed",
53 "Unexpected null/missing data"
54 );
55 crate::error::CoreError::Validation(crate::error::ValidationError::Malformed {
56 field: crate::error::CredentialField::ObjectId,
57 })
58 })
59 }
60}
61
62impl SigningKey {
63 pub fn new(prv: &str, public: &str) -> Self {
64 Self {
65 id: None,
66 created_at: Utc::now(),
67 rotated_at: None,
68 expires_at: None,
69 status: "active".into(),
70 encrypted_private_key: prv.into(),
71 public_key: public.into(),
72 algorithm: String::from("RS256"),
73 kid: String::from("k1"),
74 kty: String::from("RSA"),
75 }
76 }
77}
78impl SigningKey {
79 pub fn with_algorithm(mut self, algorithm: &str) -> Self {
80 self.algorithm = algorithm.into();
81 self
82 }
83 pub fn with_kid(mut self, kid: &str) -> Self {
84 self.kid = kid.into();
85 self
86 }
87 pub fn with_kty(mut self, kty: &str) -> Self {
88 self.kty = kty.into();
89 self
90 }
91}
92
93impl IntoBsonDocument for SigningKey {
94 fn into_bson_document(self) -> Result<bson::Document, bson::ser::Error> {
95 let mut doc = bson::to_document(&self)?;
96
97 for key in &["createdAt", "rotatedAt", "expiresAt"] {
98 if let Some(bson::Bson::String(s)) = doc.get(*key).cloned()
99 && let Ok(dt) = DateTime::parse_from_rfc3339(&s)
100 {
101 doc.insert(
102 *key,
103 bson::Bson::DateTime(bson::DateTime::from_millis(dt.timestamp_millis())),
104 );
105 }
106 }
107
108 Ok(doc)
109 }
110}