use chrono::{DateTime, Utc};
use ironflow_store::entities::{Secret, SecretMetadata};
use serde::{Deserialize, Serialize};
use uuid::Uuid;
use validator::Validate;
#[cfg_attr(feature = "openapi", derive(utoipa::ToSchema))]
#[derive(Debug, Serialize)]
pub struct SecretResponse {
pub id: Uuid,
pub key: String,
pub created_at: DateTime<Utc>,
pub updated_at: DateTime<Utc>,
}
impl From<SecretMetadata> for SecretResponse {
fn from(meta: SecretMetadata) -> Self {
Self {
id: meta.id,
key: meta.key,
created_at: meta.created_at,
updated_at: meta.updated_at,
}
}
}
impl From<Secret> for SecretResponse {
fn from(secret: Secret) -> Self {
Self {
id: secret.id,
key: secret.key,
created_at: secret.created_at,
updated_at: secret.updated_at,
}
}
}
#[cfg_attr(feature = "openapi", derive(utoipa::ToSchema))]
#[derive(Debug, Deserialize, Validate)]
pub struct SetSecretRequest {
#[validate(length(min = 1, max = 512), custom(function = "validate_secret_key"))]
pub key: String,
#[validate(length(min = 1, max = 65536))]
pub value: String,
}
fn validate_secret_key(key: &str) -> Result<(), validator::ValidationError> {
if !key
.chars()
.all(|c| c.is_ascii_alphanumeric() || matches!(c, '/' | '-' | '_' | '.'))
{
let mut err = validator::ValidationError::new("invalid_characters");
err.message =
Some("key must only contain alphanumeric characters, '/', '-', '_', '.'".into());
return Err(err);
}
if key.starts_with('/') || key.ends_with('/') || key.contains("//") {
let mut err = validator::ValidationError::new("invalid_format");
err.message = Some("key must not start/end with '/' or contain '//'".into());
return Err(err);
}
Ok(())
}