Skip to content
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
2 changes: 1 addition & 1 deletion .evergreen/run-csfle-tests.sh
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,7 @@ set -o xtrace

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

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

if [[ "$OPENSSL" = true ]]; then
Expand Down
4 changes: 2 additions & 2 deletions Cargo.lock

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

6 changes: 6 additions & 0 deletions Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -72,6 +72,12 @@ in-use-encryption-unstable = ["in-use-encryption"]
# TODO: pending https://github.com/tokio-rs/tracing/issues/2036 stop depending directly on log.
tracing-unstable = ["dep:tracing", "dep:log", "bson3?/serde_json-1"]

# 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.
text-indexes-unstable = []

[dependencies]
base64 = "0.13.0"
bitflags = "1.1.0"
Expand Down
1 change: 1 addition & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -57,6 +57,7 @@ features = ["sync"]
| `compat-3-0-0` | Required for future compatibility if default features are disabled. |
| `azure-oidc` | Enable support for Azure OIDC environment authentication. |
| `gcp-oidc` | Enable support for GCP OIDC environment authentication. |
| `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. |

## Web Framework Examples

Expand Down
96 changes: 96 additions & 0 deletions src/action/csfle/encrypt.rs
Original file line number Diff line number Diff line change
Expand Up @@ -123,6 +123,14 @@ pub struct EncryptOptions {
/// Set the range options. This should only be set when the algorithm is
/// [`Algorithm::Range`].
pub range_options: Option<RangeOptions>,

/// Set the text options. This should only be set when the algorithm is
/// [`Algorithm::TextPreview`].
///
/// NOTE: This option is unstable and subject to backwards-breaking changes. It should only be
/// used in experimental workloads.
#[cfg(feature = "text-indexes-unstable")]
pub text_options: Option<TextOptions>,
}

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

/// Options for a queryable encryption field supporting text queries.
///
/// NOTE: These options are unstable and subject to backwards-breaking changes. They should only be
/// used in experimental workloads.
#[skip_serializing_none]
#[derive(Clone, Default, Debug, Serialize, TypedBuilder)]
#[serde(rename_all = "camelCase")]
#[builder(field_defaults(default, setter(into)))]
#[non_exhaustive]
#[cfg(feature = "text-indexes-unstable")]
pub struct TextOptions {
/// Options for substring queries.
pub substring: Option<SubstringOptions>,

/// Options for prefix queries.
pub prefix: Option<PrefixOptions>,

/// Options for suffix queries.
pub suffix: Option<SuffixOptions>,

/// Whether text indexes for this field are case-sensitive.
pub case_sensitive: bool,

/// Whether text indexes for this field are diacritic-sensitive.
pub diacritic_sensitive: bool,
}

/// Options for substring queries.
///
/// NOTE: These options are unstable and subject to backwards-breaking changes. They should only be
/// used in experimental workloads.
#[derive(Clone, Default, Debug, Serialize, TypedBuilder)]
#[serde(rename_all = "camelCase")]
#[builder(field_defaults(default, setter(into)))]
#[non_exhaustive]
#[cfg(feature = "text-indexes-unstable")]
pub struct SubstringOptions {
/// The maximum allowed string length. Inserting a longer string will result in an error.
#[serde(rename = "strMaxLength")]
pub max_string_length: i32,

/// The minimum allowed query length. Querying with a shorter string will result in an error.
#[serde(rename = "strMinQueryLength")]
pub min_query_length: i32,

/// The maximum allowed query length. Querying with a longer string will result in an error.
#[serde(rename = "strMaxQueryLength")]
pub max_query_length: i32,
}

/// Options for prefix queries.
///
/// NOTE: These options are unstable and subject to backwards-breaking changes. They should only be
/// used in experimental workloads.
#[derive(Clone, Default, Debug, Serialize, TypedBuilder)]
#[serde(rename_all = "camelCase")]
#[builder(field_defaults(default, setter(into)))]
#[non_exhaustive]
#[cfg(feature = "text-indexes-unstable")]
pub struct PrefixOptions {
/// The minimum allowed query length. Querying with a shorter string will result in an error.
#[serde(rename = "strMinQueryLength")]
pub min_query_length: i32,

/// The maximum allowed query length. Querying with a longer string will result in an error.
#[serde(rename = "strMaxQueryLength")]
pub max_query_length: i32,
}

/// Options for suffix queries.
///
/// NOTE: These options are unstable and subject to backwards-breaking changes. They should only be
/// used in experimental workloads.
#[derive(Clone, Default, Debug, Serialize, TypedBuilder)]
#[serde(rename_all = "camelCase")]
#[builder(field_defaults(default, setter(into)))]
#[non_exhaustive]
#[cfg(feature = "text-indexes-unstable")]
pub struct SuffixOptions {
/// The minimum allowed query length. Querying with a shorter string will result in an error.
#[serde(rename = "strMinQueryLength")]
pub min_query_length: i32,

/// The maximum allowed query length. Querying with a longer string will result in an error.
#[serde(rename = "strMaxQueryLength")]
pub max_query_length: i32,
}

#[option_setters(EncryptOptions, skip = [query_type])]
#[export_doc(encrypt, extra = [query_type])]
#[export_doc(encrypt_expr)]
Expand Down
7 changes: 7 additions & 0 deletions src/client/csfle/client_encryption.rs
Original file line number Diff line number Diff line change
Expand Up @@ -28,6 +28,13 @@ use super::{options::KmsProviders, state_machine::CryptExecutor};

pub use super::client_builder::EncryptedClientBuilder;
pub use crate::action::csfle::encrypt::{EncryptKey, RangeOptions};
#[cfg(feature = "text-indexes-unstable")]
pub use crate::action::csfle::encrypt::{
PrefixOptions,
SubstringOptions,
SuffixOptions,
TextOptions,
};

/// A handle to the key vault. Used to create data encryption keys, and to explicitly encrypt and
/// decrypt values when auto-encryption is not an option.
Expand Down
5 changes: 5 additions & 0 deletions src/client/csfle/client_encryption/encrypt.rs
Original file line number Diff line number Diff line change
Expand Up @@ -86,6 +86,11 @@ impl ClientEncryption {
let options_doc = crate::bson_compat::serialize_to_document(range_options)?;
builder = builder.algorithm_range(options_doc)?;
}
#[cfg(feature = "text-indexes-unstable")]
if let Some(text_options) = &opts.text_options {
let options_doc = crate::bson_compat::serialize_to_document(text_options)?;
builder = builder.algorithm_text(options_doc)?;
}
Ok(builder)
}
}
8 changes: 8 additions & 0 deletions src/test.rs
Original file line number Diff line number Diff line change
Expand Up @@ -259,6 +259,14 @@ pub(crate) async fn streaming_monitor_protocol_supported() -> bool {
.is_some()
}

#[cfg(feature = "in-use-encryption")]
pub(crate) fn mongocrypt_version_lt(version: &str) -> bool {
let mut actual_version = semver::Version::parse(mongocrypt::version()).unwrap();
actual_version.pre = semver::Prerelease::EMPTY;
let requirement = semver::VersionReq::parse(&format!("<{version}")).unwrap();
requirement.matches(&actual_version)
}

pub(crate) static DEFAULT_URI: LazyLock<String> = LazyLock::new(get_default_uri);
pub(crate) static SERVER_API: LazyLock<Option<ServerApi>> =
LazyLock::new(|| match std::env::var("MONGODB_API_VERSION") {
Expand Down
Loading