seismic_enclave/client/
http_client.rs

1use crate::get_sample_schnorrkel_keypair;
2
3use super::*;
4use reqwest::Client;
5use serde::Deserialize;
6use std::net::{IpAddr, Ipv4Addr, SocketAddr};
7
8// Unspecified (0.0.0.0) exposes to public internet
9// Localhost (127.0.0.1) will only allow other processes on machine to ping
10pub const TEE_DEFAULT_ENDPOINT_ADDR: IpAddr = IpAddr::V4(Ipv4Addr::UNSPECIFIED);
11pub const TEE_DEFAULT_ENDPOINT_PORT: u16 = 7878;
12
13/// An implementation of the TEE client API that
14/// makes HTTP requests to the TEE server
15#[derive(Debug, Clone)]
16pub struct TeeHttpClient {
17    /// url of the TEE server
18    pub base_url: String,
19    /// HTTP client for making requests
20    pub client: Client,
21}
22
23impl Default for TeeHttpClient {
24    fn default() -> Self {
25        Self {
26            base_url: format!(
27                "http://{}:{}",
28                TEE_DEFAULT_ENDPOINT_ADDR, TEE_DEFAULT_ENDPOINT_PORT
29            ),
30            client: Client::new(),
31        }
32    }
33}
34
35impl TeeHttpClient {
36    /// Creates a new instance of the TEE client
37    pub fn new(base_url: String) -> Self {
38        println!("Base URL: {}", base_url);
39        Self {
40            base_url,
41            client: Client::new(),
42        }
43    }
44
45    /// Creates a new instance of the TEE client
46    pub fn new_from_addr_port(addr: IpAddr, port: u16) -> Self {
47        Self {
48            base_url: format!("http://{}:{}", addr, port),
49            client: Client::new(),
50        }
51    }
52
53    pub fn new_from_addr(addr: &SocketAddr) -> Self {
54        let base_url = format!("http://{}", addr);
55        println!("Base URL: {}", base_url);
56        Self {
57            base_url,
58            client: Client::new(),
59        }
60    }
61}
62
63#[derive(Deserialize)]
64pub struct TeeErrorResponse {
65    error: String,
66}
67
68impl TeeAPI for TeeHttpClient {
69    async fn genesis_data(
70        &self,
71        payload: GenesisData,
72    ) -> Result<GenesisDataResponse, anyhow::Error> {
73        let payload_json = serde_json::to_string(&payload)?;
74        let response = self
75            .client
76            .post(format!("{}/genesis/data", self.base_url))
77            .header("Content-Type", "application/json")
78            .body(payload_json)
79            .send()
80            .await?;
81
82        let body = response.bytes().await?.to_vec();
83        let genesis_response: GenesisDataResponse = serde_json::from_slice(&body)?;
84        Ok(genesis_response)
85    }
86
87    async fn attestation_get_evidence(
88        &self,
89        payload: AttestationGetEvidenceRequest,
90    ) -> Result<AttestationGetEvidenceResponse, anyhow::Error> {
91        let payload_json = serde_json::to_string(&payload)?;
92        let response = self
93            .client
94            .post(format!("{}/attestation/evidence/get", self.base_url))
95            .header("Content-Type", "application/json")
96            .body(payload_json)
97            .send()
98            .await?;
99
100        let body = response.bytes().await?.to_vec();
101        let attestation_response: AttestationGetEvidenceResponse = serde_json::from_slice(&body)?;
102        Ok(attestation_response)
103    }
104
105    async fn attestation_eval_evidence(
106        &self,
107        payload: AttestationEvalEvidenceRequest,
108    ) -> Result<AttestationEvalEvidenceResponse, anyhow::Error> {
109        let payload_json = serde_json::to_string(&payload)?;
110        let response = self
111            .client
112            .post(format!("{}/attestation/evidence/evaluate", self.base_url))
113            .header("Content-Type", "application/json")
114            .body(payload_json)
115            .send()
116            .await?;
117
118        let body = response.bytes().await?.to_vec();
119        let evaluation_response: AttestationEvalEvidenceResponse = serde_json::from_slice(&body)?;
120        Ok(evaluation_response)
121    }
122
123    async fn signing_sign(
124        &self,
125        payload: Secp256k1SignRequest,
126    ) -> Result<Secp256k1SignResponse, anyhow::Error> {
127        let payload_json = serde_json::to_string(&payload)?;
128        let response = self
129            .client
130            .post(format!("{}/signing/sign", self.base_url))
131            .header("Content-Type", "application/json")
132            .body(payload_json)
133            .send()
134            .await?;
135
136        let body = response.bytes().await?.to_vec();
137        let sign_response: Secp256k1SignResponse = serde_json::from_slice(&body)?;
138        Ok(sign_response)
139    }
140
141    async fn signing_verify(
142        &self,
143        payload: Secp256k1VerifyRequest,
144    ) -> Result<Secp256k1VerifyResponse, anyhow::Error> {
145        let payload_json = serde_json::to_string(&payload)?;
146        let response = self
147            .client
148            .post(format!("{}/signing/verify", self.base_url))
149            .header("Content-Type", "application/json")
150            .body(payload_json)
151            .send()
152            .await?;
153
154        let body = response.bytes().await?.to_vec();
155        let verify_response: Secp256k1VerifyResponse = serde_json::from_slice(&body)?;
156        Ok(verify_response)
157    }
158
159    async fn tx_io_encrypt(
160        &self,
161        payload: IoEncryptionRequest,
162    ) -> Result<IoEncryptionResponse, anyhow::Error> {
163        let payload_json = serde_json::to_string(&payload)?;
164
165        // Using reqwest's Client to send a POST request
166        let response = self
167            .client
168            .post(format!("{}/tx_io/encrypt", self.base_url))
169            .header("Content-Type", "application/json")
170            .body(payload_json)
171            .send()
172            .await?;
173
174        if !response.status().is_success() {
175            let error: TeeErrorResponse = serde_json::from_str(&response.text().await?)?;
176            return Err(anyhow::anyhow!(error.error));
177        }
178
179        // Extract the response body as bytes
180        let body: Vec<u8> = response.bytes().await?.to_vec();
181
182        // Parse the response body into the IoEncryptionResponse struct
183        let enc_response: IoEncryptionResponse = serde_json::from_slice(&body)?;
184
185        Ok(enc_response)
186    }
187
188    async fn tx_io_decrypt(
189        &self,
190        payload: IoDecryptionRequest,
191    ) -> Result<IoDecryptionResponse, anyhow::Error> {
192        let payload_json = serde_json::to_string(&payload)?;
193
194        // Using reqwest's Client to send a POST request
195        let response = self
196            .client
197            .post(format!("{}/tx_io/decrypt", self.base_url))
198            .header("Content-Type", "application/json")
199            .body(payload_json)
200            .send()
201            .await?;
202
203        if !response.status().is_success() {
204            let error: TeeErrorResponse = serde_json::from_str(&response.text().await?)?;
205            return Err(anyhow::anyhow!(error.error));
206        }
207        // Extract the response body as bytes
208        let body: Vec<u8> = response.bytes().await?.to_vec();
209
210        // Parse the response body into the IoDecryptionResponse struct
211        let dec_response: IoDecryptionResponse = serde_json::from_slice(&body)?;
212
213        Ok(dec_response)
214    }
215
216    async fn get_eph_rng_keypair(&self) -> Result<SchnorrkelKeypair, anyhow::Error> {
217        Ok(get_sample_schnorrkel_keypair())
218    }
219}