Skip to content

Commit 509d27e

Browse files
Disallow setting query_type for encrypt_expression (#1275)
1 parent 2815edc commit 509d27e

File tree

4 files changed

+76
-10
lines changed

4 files changed

+76
-10
lines changed

src/action/csfle/encrypt.rs

Lines changed: 11 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -40,13 +40,15 @@ impl ClientEncryption {
4040
/// Encrypts a Match Expression or Aggregate Expression to query a range index.
4141
/// `expression` is expected to be a BSON document of one of the following forms:
4242
/// 1. A Match Expression of this form:
43-
/// {$and: [{<field>: {$gt: <value1>}}, {<field>: {$lt: <value2> }}]}
43+
/// `{$and: [{<field>: {$gt: <value1>}}, {<field>: {$lt: <value2> }}]}`
4444
/// 2. An Aggregate Expression of this form:
45-
/// {$and: [{$gt: [<fieldpath>, <value1>]}, {$lt: [<fieldpath>, <value2>]}]
46-
/// $gt may also be $gte. $lt may also be $lte.
45+
/// `{$and: [{$gt: [<fieldpath>, <value1>]}, {$lt: [<fieldpath>, <value2>]}]`
46+
///
47+
/// For either expression, `$gt` may also be `$gte`, and `$lt` may also be `$lte`.
4748
///
4849
/// The expression will be encrypted using the [`Algorithm::Range`] algorithm and the
49-
/// "range" query type.
50+
/// "range" query type. It is not valid to set a query type in [`EncryptOptions`] when calling
51+
/// this method.
5052
///
5153
/// `await` will return a d[`Result<Document>`] containing the encrypted expression.
5254
#[deeplink]
@@ -61,10 +63,7 @@ impl ClientEncryption {
6163
mode: Expression { value: expression },
6264
key: key.into(),
6365
algorithm: Algorithm::Range,
64-
options: Some(EncryptOptions {
65-
query_type: Some("range".into()),
66-
..Default::default()
67-
}),
66+
options: None,
6867
}
6968
}
7069
}
@@ -110,14 +109,17 @@ pub struct Expression {
110109
}
111110

112111
/// Options for encrypting a value.
113-
#[derive(Debug, Clone, Default)]
112+
#[derive(Debug, Clone, Default, TypedBuilder)]
113+
#[builder(field_defaults(default, setter(into)))]
114114
#[non_exhaustive]
115115
#[export_tokens]
116116
pub struct EncryptOptions {
117117
/// The contention factor.
118118
pub contention_factor: Option<i64>,
119+
119120
/// The query type.
120121
pub query_type: Option<String>,
122+
121123
/// Set the range options. This should only be set when the algorithm is
122124
/// [`Algorithm::Range`].
123125
pub range_options: Option<RangeOptions>,

src/client/csfle/client_encryption/encrypt.rs

Lines changed: 14 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -32,7 +32,20 @@ impl<'a> Action for Encrypt<'a, Value> {
3232
impl<'a> Action for Encrypt<'a, Expression> {
3333
type Future = EncryptExpressionFuture;
3434

35-
async fn execute(self) -> Result<Document> {
35+
async fn execute(mut self) -> Result<Document> {
36+
let options = self.options.get_or_insert_with(Default::default);
37+
match options.query_type {
38+
Some(ref query_type) => {
39+
if query_type != "range" {
40+
return Err(Error::invalid_argument(format!(
41+
"query_type cannot be set for encrypt_expression, got {}",
42+
query_type
43+
)));
44+
}
45+
}
46+
None => options.query_type = Some("range".to_string()),
47+
}
48+
3649
let ctx = self
3750
.client_enc
3851
.get_ctx_builder(self.key, self.algorithm, self.options.unwrap_or_default())?

src/options.rs

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -15,6 +15,8 @@
1515
//! .build();
1616
//! ```
1717
18+
#[cfg(feature = "in-use-encryption")]
19+
pub use crate::action::csfle::{DataKeyOptions, EncryptOptions};
1820
#[cfg(any(
1921
feature = "zstd-compression",
2022
feature = "zlib-compression",

src/test/csfle.rs

Lines changed: 49 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -48,6 +48,7 @@ use crate::{
4848
options::{
4949
CollectionOptions,
5050
Credential,
51+
EncryptOptions,
5152
FindOptions,
5253
IndexOptions,
5354
ReadConcern,
@@ -3602,3 +3603,51 @@ async fn fle2_example() -> Result<()> {
36023603

36033604
Ok(())
36043605
}
3606+
3607+
#[tokio::test]
3608+
async fn encrypt_expression_with_options() {
3609+
let key_vault_client = Client::for_test().await.into_client();
3610+
let client_encryption = ClientEncryption::new(
3611+
key_vault_client,
3612+
KV_NAMESPACE.clone(),
3613+
vec![LOCAL_KMS.clone()],
3614+
)
3615+
.unwrap();
3616+
let data_key = client_encryption
3617+
.create_data_key(LocalMasterKey::builder().build())
3618+
.await
3619+
.unwrap();
3620+
3621+
let expression = rawdoc! {
3622+
"$and": [
3623+
{ "a": { "$gt": 0 } },
3624+
{ "a": { "$lt": 10 } },
3625+
]
3626+
};
3627+
let range_options = RangeOptions::builder()
3628+
.min(Bson::from(0))
3629+
.max(Bson::from(10))
3630+
.build();
3631+
3632+
let invalid_encrypt_options = EncryptOptions::builder()
3633+
.contention_factor(0)
3634+
.range_options(range_options.clone())
3635+
.query_type("bad".to_string())
3636+
.build();
3637+
let error = client_encryption
3638+
.encrypt_expression(expression.clone(), data_key.clone())
3639+
.with_options(invalid_encrypt_options)
3640+
.await
3641+
.unwrap_err();
3642+
assert!(matches!(*error.kind, ErrorKind::InvalidArgument { .. }));
3643+
3644+
let valid_encrypt_options = EncryptOptions::builder()
3645+
.contention_factor(0)
3646+
.range_options(range_options)
3647+
.build();
3648+
client_encryption
3649+
.encrypt_expression(expression, data_key)
3650+
.with_options(valid_encrypt_options)
3651+
.await
3652+
.unwrap();
3653+
}

0 commit comments

Comments
 (0)