1
1
//! Support for explicit encryption.
2
2
3
+ use mongocrypt:: {
4
+ ctx:: { Algorithm , Ctx , CtxBuilder , KmsProvider } ,
5
+ Crypt ,
6
+ } ;
7
+ use serde:: { Deserialize , Serialize } ;
8
+ use serde_with:: skip_serializing_none;
9
+ use typed_builder:: TypedBuilder ;
10
+
3
11
use crate :: {
4
- bson:: Binary ,
12
+ bson:: {
13
+ doc,
14
+ spec:: BinarySubtype ,
15
+ Binary ,
16
+ Bson ,
17
+ Document ,
18
+ RawBinaryRef ,
19
+ RawBson ,
20
+ RawDocumentBuf ,
21
+ } ,
5
22
client:: options:: TlsOptions ,
6
23
coll:: options:: CollectionOptions ,
7
24
error:: { Error , Result } ,
@@ -12,12 +29,6 @@ use crate::{
12
29
Cursor ,
13
30
Namespace ,
14
31
} ;
15
- use bson:: { doc, spec:: BinarySubtype , RawBinaryRef , RawDocumentBuf } ;
16
- use mongocrypt:: {
17
- ctx:: { Algorithm , Ctx , KmsProvider } ,
18
- Crypt ,
19
- } ;
20
- use serde:: { Deserialize , Serialize } ;
21
32
22
33
use super :: { options:: KmsProviders , state_machine:: CryptExecutor } ;
23
34
@@ -245,7 +256,7 @@ impl ClientEncryption {
245
256
/// # use mongodb::error::Result;
246
257
/// # async fn func() -> Result<()> {
247
258
/// # let client_encryption: ClientEncryption = todo!();
248
- /// # let key = todo! ();
259
+ /// # let key = String::new ();
249
260
/// let encrypted = client_encryption
250
261
/// .encrypt(
251
262
/// "plaintext",
@@ -271,20 +282,91 @@ impl ClientEncryption {
271
282
algorithm,
272
283
contention_factor : None ,
273
284
query_type : None ,
285
+ range_options : None ,
286
+ } ,
287
+ }
288
+ }
289
+
290
+ /// NOTE: This method is experimental only. It is not intended for public use.
291
+ ///
292
+ /// Encrypts a match or aggregate expression with the given key.
293
+ /// `EncryptExpressionAction::run` returns a [`Document`] containing the encrypted expression.
294
+ ///
295
+ /// The expression will be encrypted using the [`Algorithm::RangePreview`] algorithm and the
296
+ /// "rangePreview" query type.
297
+ ///
298
+ /// The returned `EncryptExpressionAction` must be executed via `run`, e.g.
299
+ /// ```no_run
300
+ /// # use mongocrypt::ctx::Algorithm;
301
+ /// # use mongodb::client_encryption::ClientEncryption;
302
+ /// # use mongodb::error::Result;
303
+ /// # use bson::rawdoc;
304
+ /// # async fn func() -> Result<()> {
305
+ /// # let client_encryption: ClientEncryption = todo!();
306
+ /// # let key = String::new();
307
+ /// let expression = rawdoc! {
308
+ /// "$and": [
309
+ /// { "field": { "$gte": 5 } },
310
+ /// { "field": { "$lte": 10 } },
311
+ /// ]
312
+ /// };
313
+ /// let encrypted_expression = client_encryption
314
+ /// .encrypt_expression(
315
+ /// expression,
316
+ /// key,
317
+ /// )
318
+ /// .contention_factor(10)
319
+ /// .run().await?;
320
+ /// # }
321
+ /// ```
322
+ #[ must_use]
323
+ pub fn encrypt_expression (
324
+ & self ,
325
+ expression : RawDocumentBuf ,
326
+ key : impl Into < EncryptKey > ,
327
+ ) -> EncryptExpressionAction {
328
+ EncryptExpressionAction {
329
+ client_enc : self ,
330
+ value : expression,
331
+ opts : EncryptOptions {
332
+ key : key. into ( ) ,
333
+ algorithm : Algorithm :: RangePreview ,
334
+ contention_factor : None ,
335
+ query_type : Some ( "rangePreview" . into ( ) ) ,
336
+ range_options : None ,
274
337
} ,
275
338
}
276
339
}
277
340
278
- async fn encrypt_final ( & self , value : bson:: RawBson , opts : EncryptOptions ) -> Result < Binary > {
279
- let ctx = self . encrypt_ctx ( value, & opts) ?;
341
+ async fn encrypt_final ( & self , value : RawBson , opts : EncryptOptions ) -> Result < Binary > {
342
+ let builder = self . get_ctx_builder ( & opts) ?;
343
+ let ctx = builder. build_explicit_encrypt ( value) ?;
280
344
let result = self . exec . run_ctx ( ctx, None ) . await ?;
281
345
let bin_ref = result
282
346
. get_binary ( "v" )
283
347
. map_err ( |e| Error :: internal ( format ! ( "invalid encryption result: {}" , e) ) ) ?;
284
348
Ok ( bin_ref. to_binary ( ) )
285
349
}
286
350
287
- fn encrypt_ctx ( & self , value : bson:: RawBson , opts : & EncryptOptions ) -> Result < Ctx > {
351
+ async fn encrypt_expression_final (
352
+ & self ,
353
+ value : RawDocumentBuf ,
354
+ opts : EncryptOptions ,
355
+ ) -> Result < Document > {
356
+ let builder = self . get_ctx_builder ( & opts) ?;
357
+ let ctx = builder. build_explicit_encrypt_expression ( value) ?;
358
+ let result = self . exec . run_ctx ( ctx, None ) . await ?;
359
+ let doc_ref = result
360
+ . get_document ( "v" )
361
+ . map_err ( |e| Error :: internal ( format ! ( "invalid encryption result: {}" , e) ) ) ?;
362
+ let doc = doc_ref
363
+ . to_owned ( )
364
+ . to_document ( )
365
+ . map_err ( |e| Error :: internal ( format ! ( "invalid encryption result: {}" , e) ) ) ?;
366
+ Ok ( doc)
367
+ }
368
+
369
+ fn get_ctx_builder ( & self , opts : & EncryptOptions ) -> Result < CtxBuilder > {
288
370
let mut builder = self . crypt . ctx_builder ( ) ;
289
371
match & opts. key {
290
372
EncryptKey :: Id ( id) => {
@@ -301,7 +383,11 @@ impl ClientEncryption {
301
383
if let Some ( qtype) = & opts. query_type {
302
384
builder = builder. query_type ( qtype) ?;
303
385
}
304
- Ok ( builder. build_explicit_encrypt ( value) ?)
386
+ if let Some ( range_options) = & opts. range_options {
387
+ let options_doc = bson:: to_document ( range_options) ?;
388
+ builder = builder. range_options ( options_doc) ?;
389
+ }
390
+ Ok ( builder)
305
391
}
306
392
307
393
/// Decrypts an encrypted value (BSON binary of subtype 6).
@@ -444,6 +530,29 @@ pub(crate) struct EncryptOptions {
444
530
pub ( crate ) algorithm : Algorithm ,
445
531
pub ( crate ) contention_factor : Option < i64 > ,
446
532
pub ( crate ) query_type : Option < String > ,
533
+ pub ( crate ) range_options : Option < RangeOptions > ,
534
+ }
535
+
536
+ /// NOTE: These options are experimental and not intended for public use.
537
+ ///
538
+ /// The index options for a Queryable Encryption field supporting "rangePreview" queries.
539
+ /// The options set must match the values set in the encryptedFields of the destination collection.
540
+ #[ skip_serializing_none]
541
+ #[ derive( Clone , Default , Debug , Serialize , TypedBuilder ) ]
542
+ #[ builder( field_defaults( default , setter( into) ) ) ]
543
+ #[ non_exhaustive]
544
+ pub struct RangeOptions {
545
+ /// The minimum value. This option must be set if `precision` is set.
546
+ pub min : Option < Bson > ,
547
+
548
+ /// The maximum value. This option must be set if `precision` is set.
549
+ pub max : Option < Bson > ,
550
+
551
+ /// The sparsity.
552
+ pub sparsity : i64 ,
553
+
554
+ /// The precision. This value must only be set for Double and Decimal128 fields.
555
+ pub precision : Option < i32 > ,
447
556
}
448
557
449
558
/// A pending `ClientEncryption::encrypt` action.
@@ -466,11 +575,47 @@ impl<'a> EncryptAction<'a> {
466
575
}
467
576
468
577
/// Set the query type.
469
- #[ allow( clippy:: redundant_clone) ]
470
578
pub fn query_type ( mut self , qtype : impl Into < String > ) -> Self {
471
579
self . opts . query_type = Some ( qtype. into ( ) ) ;
472
580
self
473
581
}
582
+
583
+ /// NOTE: This method is experimental and not intended for public use.
584
+ ///
585
+ /// Set the range options. This method should only be called when the algorithm is
586
+ /// [`Algorithm::RangePreview`].
587
+ pub fn range_options ( mut self , range_options : impl Into < Option < RangeOptions > > ) -> Self {
588
+ self . opts . range_options = range_options. into ( ) ;
589
+ self
590
+ }
591
+ }
592
+
593
+ /// A pending `ClientEncryption::encrypt_expression` action.
594
+ pub struct EncryptExpressionAction < ' a > {
595
+ client_enc : & ' a ClientEncryption ,
596
+ value : RawDocumentBuf ,
597
+ opts : EncryptOptions ,
598
+ }
599
+
600
+ impl < ' a > EncryptExpressionAction < ' a > {
601
+ /// Execute the encryption of the expression.
602
+ pub async fn run ( self ) -> Result < Document > {
603
+ self . client_enc
604
+ . encrypt_expression_final ( self . value , self . opts )
605
+ . await
606
+ }
607
+
608
+ /// Set the contention factor.
609
+ pub fn contention_factor ( mut self , factor : impl Into < Option < i64 > > ) -> Self {
610
+ self . opts . contention_factor = factor. into ( ) ;
611
+ self
612
+ }
613
+
614
+ /// Set the range options.
615
+ pub fn range_options ( mut self , range_options : impl Into < Option < RangeOptions > > ) -> Self {
616
+ self . opts . range_options = range_options. into ( ) ;
617
+ self
618
+ }
474
619
}
475
620
476
621
/// An encryption key reference.
0 commit comments