Skip to main content

auths_infra_http/
oidc_tsa_client.rs

1use async_trait::async_trait;
2
3use crate::default_http_client;
4use auths_oidc_port::{OidcError, TimestampClient, TimestampConfig};
5
6/// HTTP-based implementation of TimestampClient for RFC 3161 timestamp authority operations.
7///
8/// Submits data to a configured TSA endpoint and returns the RFC 3161 timestamp token.
9/// Supports graceful degradation if TSA is unavailable and fallback_on_error is enabled.
10pub struct HttpTimestampClient;
11
12impl HttpTimestampClient {
13    /// Create a new HttpTimestampClient.
14    pub fn new() -> Self {
15        Self
16    }
17}
18
19impl Default for HttpTimestampClient {
20    fn default() -> Self {
21        Self::new()
22    }
23}
24
25#[async_trait]
26impl TimestampClient for HttpTimestampClient {
27    async fn timestamp(
28        &self,
29        data: &[u8],
30        config: &TimestampConfig,
31    ) -> Result<Option<Vec<u8>>, OidcError> {
32        let tsa_uri = match &config.tsa_uri {
33            Some(uri) => uri,
34            None => {
35                return if config.fallback_on_error {
36                    Ok(None)
37                } else {
38                    Err(OidcError::JwksResolutionFailed(
39                        "timestamp authority URI not configured".to_string(),
40                    ))
41                };
42            }
43        };
44
45        let client = default_http_client();
46
47        let response = client
48            .post(tsa_uri)
49            .header("Content-Type", "application/octet-stream")
50            .timeout(std::time::Duration::from_secs(config.timeout_secs))
51            .body(data.to_vec())
52            .send()
53            .await;
54
55        match response {
56            Ok(resp) => {
57                let timestamp_token = resp.bytes().await.map_err(|e| {
58                    OidcError::JwksResolutionFailed(format!(
59                        "failed to read timestamp response: {}",
60                        e
61                    ))
62                })?;
63
64                Ok(Some(timestamp_token.to_vec()))
65            }
66            Err(e) => {
67                if config.fallback_on_error {
68                    Ok(None)
69                } else {
70                    Err(OidcError::JwksResolutionFailed(format!(
71                        "failed to acquire timestamp from {}: {}",
72                        tsa_uri, e
73                    )))
74                }
75            }
76        }
77    }
78}
79
80#[cfg(test)]
81mod tests {
82    use super::*;
83
84    #[test]
85    fn test_http_timestamp_client_creation() {
86        let _client = HttpTimestampClient::new();
87        let _default_client = HttpTimestampClient::new();
88        // Both should construct without error
89    }
90}