Skip to content

Commit 38ecd69

Browse files
RUST-2237 Support for text indexes in explicit encryption (#1479)
1 parent 3bf5ff6 commit 38ecd69

File tree

12 files changed

+533
-10
lines changed

12 files changed

+533
-10
lines changed

.evergreen/run-csfle-tests.sh

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -10,7 +10,7 @@ set -o xtrace
1010

1111
export CSFLE_TLS_CERT_DIR="${DRIVERS_TOOLS}/.evergreen/x509gen"
1212

13-
FEATURE_FLAGS+=("in-use-encryption" "azure-kms")
13+
FEATURE_FLAGS+=("in-use-encryption" "azure-kms" "text-indexes-unstable")
1414
CARGO_OPTIONS+=("--ignore-default-filter")
1515

1616
if [[ "$OPENSSL" = true ]]; then

Cargo.lock

Lines changed: 2 additions & 2 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

Cargo.toml

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -72,6 +72,12 @@ in-use-encryption-unstable = ["in-use-encryption"]
7272
# TODO: pending https://github.com/tokio-rs/tracing/issues/2036 stop depending directly on log.
7373
tracing-unstable = ["dep:tracing", "dep:log", "bson3?/serde_json-1"]
7474

75+
# Enables support for text indexes in explicit encryption. This feature is in preview and should be
76+
# used for experimental workloads only. This feature is unstable and its security is not guaranteed
77+
# until released as Generally Available (GA). The GA version of this feature may not be backwards
78+
# compatible with the preview version.
79+
text-indexes-unstable = []
80+
7581
[dependencies]
7682
base64 = "0.13.0"
7783
bitflags = "1.1.0"

README.md

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -57,6 +57,7 @@ features = ["sync"]
5757
| `compat-3-0-0` | Required for future compatibility if default features are disabled. |
5858
| `azure-oidc` | Enable support for Azure OIDC environment authentication. |
5959
| `gcp-oidc` | Enable support for GCP OIDC environment authentication. |
60+
| `text-indexes-unstable` | Enables support for text indexes in explicit encryption. This feature is in preview and should be used for experimental workloads only. This feature is unstable and its security is not guaranteed until released as Generally Available (GA). The GA version of this feature may not be backwards compatible with the preview version. |
6061

6162
## Web Framework Examples
6263

src/action/csfle/encrypt.rs

Lines changed: 96 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -123,6 +123,14 @@ pub struct EncryptOptions {
123123
/// Set the range options. This should only be set when the algorithm is
124124
/// [`Algorithm::Range`].
125125
pub range_options: Option<RangeOptions>,
126+
127+
/// Set the text options. This should only be set when the algorithm is
128+
/// [`Algorithm::TextPreview`].
129+
///
130+
/// NOTE: This option is unstable and subject to backwards-breaking changes. It should only be
131+
/// used in experimental workloads.
132+
#[cfg(feature = "text-indexes-unstable")]
133+
pub text_options: Option<TextOptions>,
126134
}
127135

128136
/// The index options for a Queryable Encryption field supporting "range" queries.
@@ -150,6 +158,94 @@ pub struct RangeOptions {
150158
pub precision: Option<i32>,
151159
}
152160

161+
/// Options for a queryable encryption field supporting text queries.
162+
///
163+
/// NOTE: These options are unstable and subject to backwards-breaking changes. They should only be
164+
/// used in experimental workloads.
165+
#[skip_serializing_none]
166+
#[derive(Clone, Default, Debug, Serialize, TypedBuilder)]
167+
#[serde(rename_all = "camelCase")]
168+
#[builder(field_defaults(default, setter(into)))]
169+
#[non_exhaustive]
170+
#[cfg(feature = "text-indexes-unstable")]
171+
pub struct TextOptions {
172+
/// Options for substring queries.
173+
pub substring: Option<SubstringOptions>,
174+
175+
/// Options for prefix queries.
176+
pub prefix: Option<PrefixOptions>,
177+
178+
/// Options for suffix queries.
179+
pub suffix: Option<SuffixOptions>,
180+
181+
/// Whether text indexes for this field are case-sensitive.
182+
pub case_sensitive: bool,
183+
184+
/// Whether text indexes for this field are diacritic-sensitive.
185+
pub diacritic_sensitive: bool,
186+
}
187+
188+
/// Options for substring queries.
189+
///
190+
/// NOTE: These options are unstable and subject to backwards-breaking changes. They should only be
191+
/// used in experimental workloads.
192+
#[derive(Clone, Default, Debug, Serialize, TypedBuilder)]
193+
#[serde(rename_all = "camelCase")]
194+
#[builder(field_defaults(default, setter(into)))]
195+
#[non_exhaustive]
196+
#[cfg(feature = "text-indexes-unstable")]
197+
pub struct SubstringOptions {
198+
/// The maximum allowed string length. Inserting a longer string will result in an error.
199+
#[serde(rename = "strMaxLength")]
200+
pub max_string_length: i32,
201+
202+
/// The minimum allowed query length. Querying with a shorter string will result in an error.
203+
#[serde(rename = "strMinQueryLength")]
204+
pub min_query_length: i32,
205+
206+
/// The maximum allowed query length. Querying with a longer string will result in an error.
207+
#[serde(rename = "strMaxQueryLength")]
208+
pub max_query_length: i32,
209+
}
210+
211+
/// Options for prefix queries.
212+
///
213+
/// NOTE: These options are unstable and subject to backwards-breaking changes. They should only be
214+
/// used in experimental workloads.
215+
#[derive(Clone, Default, Debug, Serialize, TypedBuilder)]
216+
#[serde(rename_all = "camelCase")]
217+
#[builder(field_defaults(default, setter(into)))]
218+
#[non_exhaustive]
219+
#[cfg(feature = "text-indexes-unstable")]
220+
pub struct PrefixOptions {
221+
/// The minimum allowed query length. Querying with a shorter string will result in an error.
222+
#[serde(rename = "strMinQueryLength")]
223+
pub min_query_length: i32,
224+
225+
/// The maximum allowed query length. Querying with a longer string will result in an error.
226+
#[serde(rename = "strMaxQueryLength")]
227+
pub max_query_length: i32,
228+
}
229+
230+
/// Options for suffix queries.
231+
///
232+
/// NOTE: These options are unstable and subject to backwards-breaking changes. They should only be
233+
/// used in experimental workloads.
234+
#[derive(Clone, Default, Debug, Serialize, TypedBuilder)]
235+
#[serde(rename_all = "camelCase")]
236+
#[builder(field_defaults(default, setter(into)))]
237+
#[non_exhaustive]
238+
#[cfg(feature = "text-indexes-unstable")]
239+
pub struct SuffixOptions {
240+
/// The minimum allowed query length. Querying with a shorter string will result in an error.
241+
#[serde(rename = "strMinQueryLength")]
242+
pub min_query_length: i32,
243+
244+
/// The maximum allowed query length. Querying with a longer string will result in an error.
245+
#[serde(rename = "strMaxQueryLength")]
246+
pub max_query_length: i32,
247+
}
248+
153249
#[option_setters(EncryptOptions, skip = [query_type])]
154250
#[export_doc(encrypt, extra = [query_type])]
155251
#[export_doc(encrypt_expr)]

src/client/csfle/client_encryption.rs

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -28,6 +28,13 @@ use super::{options::KmsProviders, state_machine::CryptExecutor};
2828

2929
pub use super::client_builder::EncryptedClientBuilder;
3030
pub use crate::action::csfle::encrypt::{EncryptKey, RangeOptions};
31+
#[cfg(feature = "text-indexes-unstable")]
32+
pub use crate::action::csfle::encrypt::{
33+
PrefixOptions,
34+
SubstringOptions,
35+
SuffixOptions,
36+
TextOptions,
37+
};
3138

3239
/// A handle to the key vault. Used to create data encryption keys, and to explicitly encrypt and
3340
/// decrypt values when auto-encryption is not an option.

src/client/csfle/client_encryption/encrypt.rs

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -86,6 +86,11 @@ impl ClientEncryption {
8686
let options_doc = crate::bson_compat::serialize_to_document(range_options)?;
8787
builder = builder.algorithm_range(options_doc)?;
8888
}
89+
#[cfg(feature = "text-indexes-unstable")]
90+
if let Some(text_options) = &opts.text_options {
91+
let options_doc = crate::bson_compat::serialize_to_document(text_options)?;
92+
builder = builder.algorithm_text(options_doc)?;
93+
}
8994
Ok(builder)
9095
}
9196
}

src/test.rs

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -259,6 +259,14 @@ pub(crate) async fn streaming_monitor_protocol_supported() -> bool {
259259
.is_some()
260260
}
261261

262+
#[cfg(feature = "in-use-encryption")]
263+
pub(crate) fn mongocrypt_version_lt(version: &str) -> bool {
264+
let mut actual_version = semver::Version::parse(mongocrypt::version()).unwrap();
265+
actual_version.pre = semver::Prerelease::EMPTY;
266+
let requirement = semver::VersionReq::parse(&format!("<{version}")).unwrap();
267+
requirement.matches(&actual_version)
268+
}
269+
262270
pub(crate) static DEFAULT_URI: LazyLock<String> = LazyLock::new(get_default_uri);
263271
pub(crate) static SERVER_API: LazyLock<Option<ServerApi>> =
264272
LazyLock::new(|| match std::env::var("MONGODB_API_VERSION") {

0 commit comments

Comments
 (0)