cloud_file_signer/gcp/
mod.rs

1//! An implementation of the [`CloudFileSigner`] trait for Google Cloud Storage.
2
3use std::time::Duration;
4use std::time::SystemTime;
5
6use google_cloud_storage::client::Client;
7use google_cloud_storage::client::ClientConfig;
8use google_cloud_storage::sign::SignedURLMethod;
9use google_cloud_storage::sign::SignedURLOptions;
10
11use crate::CloudFileSigner;
12use crate::Permission;
13use crate::PresignedUrl;
14use crate::SignerError;
15
16use self::uri::GcpUri;
17
18mod uri;
19
20/// A signer for Google Cloud Storage.
21pub struct GcpFileSigner {
22    client: Client,
23}
24
25impl GcpFileSigner {
26    /// Create a new signer for Google Cloud Storage.
27    #[must_use]
28    pub fn new(client: Client) -> Self {
29        Self { client }
30    }
31
32    /// Create a new signer for Google Cloud Storage using environment variables.
33    pub async fn from_env() -> Self {
34        let client_config = ClientConfig::default().with_auth().await.unwrap();
35        let client = Client::new(client_config);
36        Self { client }
37    }
38
39    async fn sign_read_request(
40        &self,
41        uri: &GcpUri,
42        expiration: Duration,
43    ) -> Result<PresignedUrl, SignerError> {
44        let valid_from = SystemTime::now();
45
46        let opts = SignedURLOptions {
47            expires: expiration,
48            method: SignedURLMethod::GET,
49            ..Default::default()
50        };
51
52        let signed_url = self
53            .client
54            .signed_url(uri.bucket(), uri.key(), None, None, opts)
55            .await
56            .map_err(|e| SignerError::other_error(e.to_string()))?;
57        Ok(PresignedUrl::new(signed_url, valid_from, expiration))
58    }
59}
60
61#[async_trait::async_trait]
62impl CloudFileSigner for GcpFileSigner {
63    async fn sign(
64        &self,
65        path: &str,
66        _valid_from: SystemTime,
67        expiration: Duration,
68        permission: Permission,
69    ) -> Result<PresignedUrl, SignerError> {
70        let uri = path.parse::<GcpUri>()?;
71        match permission {
72            Permission::Read => self.sign_read_request(&uri, expiration).await,
73            Permission::Write => Err(SignerError::permission_not_supported(
74                "GCP does not support write permissions",
75            )),
76        }
77    }
78}