Skip to content

RUST-1843 Support for QE range protocol V2 #1132

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 2 commits into from
Jun 11, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
33 changes: 18 additions & 15 deletions src/action/csfle/encrypt.rs
Original file line number Diff line number Diff line change
Expand Up @@ -33,12 +33,16 @@ impl ClientEncryption {
}
}

/// NOTE: This method is experimental only. It is not intended for public use.
/// Encrypts a Match Expression or Aggregate Expression to query a range index.
/// `expression` is expected to be a BSON document of one of the following forms:
/// 1. A Match Expression of this form:
/// {$and: [{<field>: {$gt: <value1>}}, {<field>: {$lt: <value2> }}]}
/// 2. An Aggregate Expression of this form:
/// {$and: [{$gt: [<fieldpath>, <value1>]}, {$lt: [<fieldpath>, <value2>]}]
/// $gt may also be $gte. $lt may also be $lte.
///
/// Encrypts a match or aggregate expression with the given key.
///
/// The expression will be encrypted using the [`Algorithm::RangePreview`] algorithm and the
/// "rangePreview" query type.
/// The expression will be encrypted using the [`Algorithm::Range`] algorithm and the
/// "range" query type.
///
/// `await` will return a d[`Result<Document>`] containing the encrypted expression.
#[deeplink]
Expand All @@ -51,10 +55,9 @@ impl ClientEncryption {
client_enc: self,
mode: Expression { value: expression },
key: key.into(),
#[allow(deprecated)]
algorithm: Algorithm::RangePreview,
algorithm: Algorithm::Range,
options: Some(EncryptOptions {
query_type: Some("rangePreview".into()),
query_type: Some("range".into()),
..Default::default()
}),
}
Expand Down Expand Up @@ -109,19 +112,16 @@ pub struct EncryptOptions {
pub contention_factor: Option<i64>,
/// The query type.
pub query_type: Option<String>,
/// NOTE: This method is experimental and not intended for public use.
///
/// Set the range options. This method should only be called when the algorithm is
/// [`Algorithm::RangePreview`].
/// Set the range options. This should only be set when the algorithm is
/// [`Algorithm::Range`].
pub range_options: Option<RangeOptions>,
}

/// NOTE: These options are experimental and not intended for public use.
///
/// The index options for a Queryable Encryption field supporting "rangePreview" queries.
/// The index options for a Queryable Encryption field supporting "range" queries.
/// The options set must match the values set in the encryptedFields of the destination collection.
#[skip_serializing_none]
#[derive(Clone, Default, Debug, Serialize, TypedBuilder)]
#[serde(rename_all = "camelCase")]
#[builder(field_defaults(default, setter(into)))]
#[non_exhaustive]
pub struct RangeOptions {
Expand All @@ -131,6 +131,9 @@ pub struct RangeOptions {
/// The maximum value. This option must be set if `precision` is set.
pub max: Option<Bson>,

/// The trim factor.
pub trim_factor: i32,

/// The sparsity.
pub sparsity: i64,

Expand Down
3 changes: 2 additions & 1 deletion src/client/csfle.rs
Original file line number Diff line number Diff line change
Expand Up @@ -99,7 +99,8 @@ impl ClientState {
fn make_crypt(opts: &AutoEncryptionOptions) -> Result<Crypt> {
let mut builder = Crypt::builder()
.kms_providers(&opts.kms_providers.credentials_doc()?)?
.use_need_kms_credentials_state();
.use_need_kms_credentials_state()
.use_range_v2()?;
if let Some(m) = &opts.schema_map {
builder = builder.schema_map(&bson::to_document(m)?)?;
}
Expand Down
1 change: 1 addition & 0 deletions src/client/csfle/client_encryption.rs
Original file line number Diff line number Diff line change
Expand Up @@ -63,6 +63,7 @@ impl ClientEncryption {
let crypt = Crypt::builder()
.kms_providers(&kms_providers.credentials_doc()?)?
.use_need_kms_credentials_state()
.use_range_v2()?
.build()?;
let exec = CryptExecutor::new_explicit(
key_vault_client.weak(),
Expand Down
38 changes: 13 additions & 25 deletions src/test/csfle.rs
Original file line number Diff line number Diff line change
Expand Up @@ -2977,19 +2977,20 @@ async fn range_explicit_encryption() -> Result<()> {
return Ok(());
}
let client = TestClient::new().await;
if client.server_version_lt(6, 2) || client.server_version_gte(8, 0) || client.is_standalone() {
if client.server_version_lt(8, 0) || client.is_standalone() {
log_uncaptured("Skipping range_explicit_encryption due to unsupported topology");
return Ok(());
}

range_explicit_encryption_test(
"DecimalNoPrecision",
RangeOptions::builder().sparsity(1).build(),
RangeOptions::builder().sparsity(1).trim_factor(1).build(),
)
.await?;
range_explicit_encryption_test(
"DecimalPrecision",
RangeOptions::builder()
.trim_factor(1)
.sparsity(1)
.min(Bson::Decimal128("0".parse()?))
.max(Bson::Decimal128("200".parse()?))
Expand All @@ -2999,12 +3000,13 @@ async fn range_explicit_encryption() -> Result<()> {
.await?;
range_explicit_encryption_test(
"DoubleNoPrecision",
RangeOptions::builder().sparsity(1).build(),
RangeOptions::builder().trim_factor(1).sparsity(1).build(),
)
.await?;
range_explicit_encryption_test(
"DoublePrecision",
RangeOptions::builder()
.trim_factor(1)
.sparsity(1)
.min(Bson::Double(0.0))
.max(Bson::Double(200.0))
Expand All @@ -3015,6 +3017,7 @@ async fn range_explicit_encryption() -> Result<()> {
range_explicit_encryption_test(
"Date",
RangeOptions::builder()
.trim_factor(1)
.sparsity(1)
.min(Bson::DateTime(DateTime::from_millis(0)))
.max(Bson::DateTime(DateTime::from_millis(200)))
Expand All @@ -3024,6 +3027,7 @@ async fn range_explicit_encryption() -> Result<()> {
range_explicit_encryption_test(
"Int",
RangeOptions::builder()
.trim_factor(1)
.sparsity(1)
.min(Bson::Int32(0))
.max(Bson::Int32(200))
Expand All @@ -3033,6 +3037,7 @@ async fn range_explicit_encryption() -> Result<()> {
range_explicit_encryption_test(
"Long",
RangeOptions::builder()
.trim_factor(1)
.sparsity(1)
.min(Bson::Int64(0))
.max(Bson::Int64(200))
Expand Down Expand Up @@ -3114,12 +3119,7 @@ async fn range_explicit_encryption_test(

for (id, num) in bson_numbers.keys().enumerate() {
let encrypted_value = client_encryption
.encrypt(
bson_numbers[num].clone(),
key1_id.clone(),
#[allow(deprecated)]
Algorithm::RangePreview,
)
.encrypt(bson_numbers[num].clone(), key1_id.clone(), Algorithm::Range)
.contention_factor(0)
.range_options(range_options.clone())
.await?;
Expand All @@ -3134,12 +3134,7 @@ async fn range_explicit_encryption_test(

// Case 1: Decrypt a payload
let insert_payload = client_encryption
.encrypt(
bson_numbers[&6].clone(),
key1_id.clone(),
#[allow(deprecated)]
Algorithm::RangePreview,
)
.encrypt(bson_numbers[&6].clone(), key1_id.clone(), Algorithm::Range)
.contention_factor(0)
.range_options(range_options.clone())
.await?;
Expand Down Expand Up @@ -3250,9 +3245,8 @@ async fn range_explicit_encryption_test(
// Case 6: Encrypting a document greater than the maximum errors
if bson_type != "DoubleNoPrecision" && bson_type != "DecimalNoPrecision" {
let num = get_raw_bson_from_num(bson_type, 201);
#[allow(deprecated)]
let error = client_encryption
.encrypt(num, key1_id.clone(), Algorithm::RangePreview)
.encrypt(num, key1_id.clone(), Algorithm::Range)
.contention_factor(0)
.range_options(range_options.clone())
.await
Expand All @@ -3267,9 +3261,8 @@ async fn range_explicit_encryption_test(
} else {
rawdoc! { &key: { "$numberInt": "6" } }
};
#[allow(deprecated)]
let error = client_encryption
.encrypt(value, key1_id.clone(), Algorithm::RangePreview)
.encrypt(value, key1_id.clone(), Algorithm::Range)
.contention_factor(0)
.range_options(range_options.clone())
.await
Expand All @@ -3286,12 +3279,7 @@ async fn range_explicit_encryption_test(
.precision(2)
.build();
let error = client_encryption
.encrypt(
bson_numbers[&6].clone(),
key1_id.clone(),
#[allow(deprecated)]
Algorithm::RangePreview,
)
.encrypt(bson_numbers[&6].clone(), key1_id.clone(), Algorithm::Range)
.contention_factor(0)
.range_options(range_options)
.await
Expand Down
Loading