11//! Support for explicit encryption.
22
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+
311use crate :: {
4- bson:: Binary ,
12+ bson:: {
13+ doc,
14+ spec:: BinarySubtype ,
15+ Binary ,
16+ Bson ,
17+ Document ,
18+ RawBinaryRef ,
19+ RawBson ,
20+ RawDocumentBuf ,
21+ } ,
522 client:: options:: TlsOptions ,
623 coll:: options:: CollectionOptions ,
724 error:: { Error , Result } ,
@@ -12,12 +29,6 @@ use crate::{
1229 Cursor ,
1330 Namespace ,
1431} ;
15- use bson:: { doc, spec:: BinarySubtype , RawBinaryRef , RawDocumentBuf } ;
16- use mongocrypt:: {
17- ctx:: { Algorithm , Ctx , KmsProvider } ,
18- Crypt ,
19- } ;
20- use serde:: { Deserialize , Serialize } ;
2132
2233use super :: { options:: KmsProviders , state_machine:: CryptExecutor } ;
2334
@@ -245,7 +256,7 @@ impl ClientEncryption {
245256 /// # use mongodb::error::Result;
246257 /// # async fn func() -> Result<()> {
247258 /// # let client_encryption: ClientEncryption = todo!();
248- /// # let key = todo! ();
259+ /// # let key = String::new ();
249260 /// let encrypted = client_encryption
250261 /// .encrypt(
251262 /// "plaintext",
@@ -271,20 +282,91 @@ impl ClientEncryption {
271282 algorithm,
272283 contention_factor : None ,
273284 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 ,
274337 } ,
275338 }
276339 }
277340
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) ?;
280344 let result = self . exec . run_ctx ( ctx, None ) . await ?;
281345 let bin_ref = result
282346 . get_binary ( "v" )
283347 . map_err ( |e| Error :: internal ( format ! ( "invalid encryption result: {}" , e) ) ) ?;
284348 Ok ( bin_ref. to_binary ( ) )
285349 }
286350
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 > {
288370 let mut builder = self . crypt . ctx_builder ( ) ;
289371 match & opts. key {
290372 EncryptKey :: Id ( id) => {
@@ -301,7 +383,11 @@ impl ClientEncryption {
301383 if let Some ( qtype) = & opts. query_type {
302384 builder = builder. query_type ( qtype) ?;
303385 }
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)
305391 }
306392
307393 /// Decrypts an encrypted value (BSON binary of subtype 6).
@@ -444,6 +530,29 @@ pub(crate) struct EncryptOptions {
444530 pub ( crate ) algorithm : Algorithm ,
445531 pub ( crate ) contention_factor : Option < i64 > ,
446532 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 > ,
447556}
448557
449558/// A pending `ClientEncryption::encrypt` action.
@@ -466,11 +575,47 @@ impl<'a> EncryptAction<'a> {
466575 }
467576
468577 /// Set the query type.
469- #[ allow( clippy:: redundant_clone) ]
470578 pub fn query_type ( mut self , qtype : impl Into < String > ) -> Self {
471579 self . opts . query_type = Some ( qtype. into ( ) ) ;
472580 self
473581 }
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+ }
474619}
475620
476621/// An encryption key reference.
0 commit comments