gimpey_db_gateway/clients/
refresh_token_client.rs

1use rustls::crypto::ring::default_provider;
2use rustls::{ClientConfig, RootCertStore};
3use rustls_native_certs::load_native_certs;
4use std::str::FromStr;
5use tonic::{metadata::MetadataValue, Request, Status};
6use tonic_rustls::channel::Channel as RustlsChannel;
7
8use crate::generated::refresh_token::{
9    refresh_token_service_client::RefreshTokenServiceClient, CreateRefreshTokenRequest,
10    CreateRefreshTokenResponse, GetRefreshTokenRequest, GetRefreshTokenResponse, Meta,
11};
12
13#[derive(Debug, Clone)]
14pub struct RefreshTokenClient {
15    inner: RefreshTokenServiceClient<RustlsChannel>,
16    api_key: String,
17}
18
19impl RefreshTokenClient {
20    pub async fn connect(
21        domain: &str,
22        api_key: String,
23        is_secure: bool,
24    ) -> Result<Self, Box<dyn std::error::Error>> {
25        let channel = if is_secure {
26            let provider = default_provider();
27            let _ = provider.install_default();
28
29            let mut roots = RootCertStore::empty();
30            for cert in load_native_certs().expect("Could not load platform certs") {
31                roots.add(cert).unwrap();
32            }
33
34            let config = ClientConfig::builder()
35                .with_root_certificates(roots)
36                .with_no_client_auth();
37
38            let channel = RustlsChannel::from_shared(format!("https://{domain}"))?
39                .tls_config(config)?
40                .connect()
41                .await?;
42
43            channel
44        } else {
45            RustlsChannel::from_shared(format!("http://{domain}"))?
46                .connect()
47                .await?
48        };
49
50        Ok(Self {
51            inner: RefreshTokenServiceClient::new(channel),
52            api_key,
53        })
54    }
55
56    fn with_auth<T>(&self, message: T) -> Request<T> {
57        let mut req = Request::new(message);
58        let meta = MetadataValue::from_str(&self.api_key).unwrap();
59        req.metadata_mut().insert("x-api-key", meta);
60        req
61    }
62
63    pub async fn create_refresh_token(
64        &mut self,
65        session_id: String,
66        account_id: String,
67        token_hash: String,
68        fingerprint_hash: String,
69        user_agent: String,
70        issued_at: u64,
71        expires_at: u64,
72        meta: Option<Meta>,
73    ) -> Result<CreateRefreshTokenResponse, Status> {
74        let request = CreateRefreshTokenRequest {
75            session_id,
76            account_id,
77            token_hash,
78            fingerprint_hash,
79            user_agent,
80            issued_at,
81            expires_at,
82            meta,
83        };
84
85        let response = self
86            .inner
87            .create_refresh_token(self.with_auth(request))
88            .await?;
89        Ok(response.into_inner())
90    }
91
92    pub async fn get_refresh_token(
93        &mut self,
94        token_hash: String,
95    ) -> Result<GetRefreshTokenResponse, Status> {
96        let request = GetRefreshTokenRequest { token_hash };
97        let response = self
98            .inner
99            .get_refresh_token(self.with_auth(request))
100            .await?;
101        Ok(response.into_inner())
102    }
103}