|
3 | 3 | mod create_data_key;
|
4 | 4 | mod encrypt;
|
5 | 5 |
|
| 6 | +use std::time::Duration; |
| 7 | + |
6 | 8 | use mongocrypt::{ctx::KmsProvider, Crypt};
|
7 | 9 | use serde::{Deserialize, Serialize};
|
8 | 10 | use typed_builder::TypedBuilder;
|
@@ -61,32 +63,44 @@ impl ClientEncryption {
|
61 | 63 | key_vault_namespace: Namespace,
|
62 | 64 | kms_providers: impl IntoIterator<Item = (KmsProvider, bson::Document, Option<TlsOptions>)>,
|
63 | 65 | ) -> Result<Self> {
|
64 |
| - let kms_providers = KmsProviders::new(kms_providers)?; |
65 |
| - let crypt = Crypt::builder() |
66 |
| - .kms_providers(&kms_providers.credentials_doc()?)? |
67 |
| - .use_need_kms_credentials_state() |
68 |
| - .retry_kms(true)? |
69 |
| - .use_range_v2()? |
70 |
| - .build()?; |
71 |
| - let exec = CryptExecutor::new_explicit( |
72 |
| - key_vault_client.weak(), |
73 |
| - key_vault_namespace.clone(), |
74 |
| - kms_providers, |
75 |
| - )?; |
76 |
| - let key_vault = key_vault_client |
77 |
| - .database(&key_vault_namespace.db) |
78 |
| - .collection_with_options( |
79 |
| - &key_vault_namespace.coll, |
80 |
| - CollectionOptions::builder() |
81 |
| - .write_concern(WriteConcern::majority()) |
82 |
| - .read_concern(ReadConcern::majority()) |
83 |
| - .build(), |
84 |
| - ); |
85 |
| - Ok(ClientEncryption { |
86 |
| - crypt, |
87 |
| - exec, |
88 |
| - key_vault, |
89 |
| - }) |
| 66 | + Self::builder(key_vault_client, key_vault_namespace, kms_providers).build() |
| 67 | + } |
| 68 | + |
| 69 | + /// Initialize a builder to construct a [`ClientEncryption`]. Methods on |
| 70 | + /// [`ClientEncryptionBuilder`] can be chained to set options. |
| 71 | + /// |
| 72 | + /// ```no_run |
| 73 | + /// # use bson::doc; |
| 74 | + /// # use mongocrypt::ctx::KmsProvider; |
| 75 | + /// # use mongodb::client_encryption::ClientEncryption; |
| 76 | + /// # use mongodb::error::Result; |
| 77 | + /// # fn func() -> Result<()> { |
| 78 | + /// # let kv_client = todo!(); |
| 79 | + /// # let kv_namespace = todo!(); |
| 80 | + /// # let local_key = doc! { }; |
| 81 | + /// let enc = ClientEncryption::builder( |
| 82 | + /// kv_client, |
| 83 | + /// kv_namespace, |
| 84 | + /// [ |
| 85 | + /// (KmsProvider::Local, doc! { "key": local_key }, None), |
| 86 | + /// (KmsProvider::Kmip, doc! { "endpoint": "localhost:5698" }, None), |
| 87 | + /// ] |
| 88 | + /// ) |
| 89 | + /// .build()?; |
| 90 | + /// # Ok(()) |
| 91 | + /// # } |
| 92 | + /// ``` |
| 93 | + pub fn builder( |
| 94 | + key_vault_client: Client, |
| 95 | + key_vault_namespace: Namespace, |
| 96 | + kms_providers: impl IntoIterator<Item = (KmsProvider, bson::Document, Option<TlsOptions>)>, |
| 97 | + ) -> ClientEncryptionBuilder { |
| 98 | + ClientEncryptionBuilder { |
| 99 | + key_vault_client, |
| 100 | + key_vault_namespace, |
| 101 | + kms_providers: kms_providers.into_iter().collect(), |
| 102 | + key_cache_expiration: None, |
| 103 | + } |
90 | 104 | }
|
91 | 105 |
|
92 | 106 | // pub async fn rewrap_many_data_key(&self, _filter: Document, _opts: impl
|
@@ -189,6 +203,68 @@ impl ClientEncryption {
|
189 | 203 | }
|
190 | 204 | }
|
191 | 205 |
|
| 206 | +/// Builder for constructing a [`ClientEncryption`]. Construct by calling |
| 207 | +/// [`ClientEncryption::builder`]. |
| 208 | +pub struct ClientEncryptionBuilder { |
| 209 | + key_vault_client: Client, |
| 210 | + key_vault_namespace: Namespace, |
| 211 | + kms_providers: Vec<(KmsProvider, bson::Document, Option<TlsOptions>)>, |
| 212 | + key_cache_expiration: Option<Duration>, |
| 213 | +} |
| 214 | + |
| 215 | +impl ClientEncryptionBuilder { |
| 216 | + /// Set the duration of time after which the data encryption key cache should expire. Defaults |
| 217 | + /// to 60 seconds if unset. |
| 218 | + pub fn key_cache_expiration(mut self, expiration: impl Into<Option<Duration>>) -> Self { |
| 219 | + self.key_cache_expiration = expiration.into(); |
| 220 | + self |
| 221 | + } |
| 222 | + |
| 223 | + /// Build the [`ClientEncryption`]. |
| 224 | + pub fn build(self) -> Result<ClientEncryption> { |
| 225 | + let kms_providers = KmsProviders::new(self.kms_providers)?; |
| 226 | + |
| 227 | + let mut crypt_builder = Crypt::builder() |
| 228 | + .kms_providers(&kms_providers.credentials_doc()?)? |
| 229 | + .use_need_kms_credentials_state() |
| 230 | + .use_range_v2()? |
| 231 | + .retry_kms(true)?; |
| 232 | + if let Some(key_cache_expiration) = self.key_cache_expiration { |
| 233 | + let expiration_ms: u64 = key_cache_expiration.as_millis().try_into().map_err(|_| { |
| 234 | + Error::invalid_argument(format!( |
| 235 | + "key_cache_expiration must not exceed {} milliseconds, got {:?}", |
| 236 | + u64::MAX, |
| 237 | + key_cache_expiration |
| 238 | + )) |
| 239 | + })?; |
| 240 | + crypt_builder = crypt_builder.key_cache_expiration(expiration_ms)?; |
| 241 | + } |
| 242 | + let crypt = crypt_builder.build()?; |
| 243 | + |
| 244 | + let exec = CryptExecutor::new_explicit( |
| 245 | + self.key_vault_client.weak(), |
| 246 | + self.key_vault_namespace.clone(), |
| 247 | + kms_providers, |
| 248 | + )?; |
| 249 | + let key_vault = self |
| 250 | + .key_vault_client |
| 251 | + .database(&self.key_vault_namespace.db) |
| 252 | + .collection_with_options( |
| 253 | + &self.key_vault_namespace.coll, |
| 254 | + CollectionOptions::builder() |
| 255 | + .write_concern(WriteConcern::majority()) |
| 256 | + .read_concern(ReadConcern::majority()) |
| 257 | + .build(), |
| 258 | + ); |
| 259 | + |
| 260 | + Ok(ClientEncryption { |
| 261 | + crypt, |
| 262 | + exec, |
| 263 | + key_vault, |
| 264 | + }) |
| 265 | + } |
| 266 | +} |
| 267 | + |
192 | 268 | /// A KMS-specific key used to encrypt data keys.
|
193 | 269 | #[derive(Debug, Clone, Serialize, Deserialize)]
|
194 | 270 | #[serde(untagged)]
|
|
0 commit comments