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
9 changes: 9 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,15 @@

## Unreleased

### Added
- Stable support for prefix and suffix queries:
- The `prefixPreview` query type is replaced with `prefix`.
- The `suffixPreview` query type is replaced with `suffix`.
- Use the `string` algorithm (formerly `textPreview`) for `prefix`, `suffix`, and `substringPreview` query types.

### Removed
- Support for the experimental `prefixPreview` and `suffixPreview` query types.

<!-- TODO: add entries for next release -->

## 1.18.1
Expand Down
8 changes: 4 additions & 4 deletions bindings/python/test/test_mongocrypt.py
Original file line number Diff line number Diff line change
Expand Up @@ -1030,9 +1030,9 @@ async def test_text_query(self):
value = bson.encode({"v": "foo"})
encrypted = await encrypter.encrypt(
value,
"textPreview",
"string",
key_id=key_id,
query_type="suffixPreview",
query_type="suffix",
contention_factor=0,
text_opts=text_opts,
)
Expand Down Expand Up @@ -1500,9 +1500,9 @@ def test_text_query(self):
value = bson.encode({"v": "foo"})
encrypted = encrypter.encrypt(
value,
"textPreview",
"string",
key_id=key_id,
query_type="suffixPreview",
query_type="suffix",
contention_factor=0,
text_opts=text_opts,
)
Expand Down
3 changes: 3 additions & 0 deletions src/mc-efc-private.h
Original file line number Diff line number Diff line change
Expand Up @@ -32,6 +32,9 @@ typedef enum _supported_query_type_flags {
SUPPORTS_SUBSTRING_PREVIEW_QUERIES = 1 << 3,
SUPPORTS_SUFFIX_QUERIES = 1 << 4,
SUPPORTS_PREFIX_QUERIES = 1 << 5,
// prefixPreview and suffixPreview are dropped. Setting this results in an error.
SUPPORTS_SUFFIX_PREVIEW_DEPRECATED_QUERIES = 1 << 6,
SUPPORTS_PREFIX_PREVIEW_DEPRECATED_QUERIES = 1 << 7,
} supported_query_type_flags;

typedef struct _mc_EncryptedField_t {
Expand Down
24 changes: 20 additions & 4 deletions src/mc-efc.c
Original file line number Diff line number Diff line change
Expand Up @@ -35,12 +35,14 @@ static bool _parse_query_type_string(const char *queryType, supported_query_type
*out = SUPPORTS_RANGE_PREVIEW_DEPRECATED_QUERIES;
} else if (mstr_eq_ignore_case(mstrv_lit(MONGOCRYPT_QUERY_TYPE_SUBSTRINGPREVIEW_STR), qtv)) {
*out = SUPPORTS_SUBSTRING_PREVIEW_QUERIES;
} else if (mstr_eq_ignore_case(mstrv_lit(MONGOCRYPT_QUERY_TYPE_SUFFIXPREVIEW_DEPRECATED_STR), qtv)
|| mstr_eq_ignore_case(mstrv_lit(MONGOCRYPT_QUERY_TYPE_SUFFIX_STR), qtv)) {
} else if (mstr_eq_ignore_case(mstrv_lit(MONGOCRYPT_QUERY_TYPE_SUFFIX_STR), qtv)) {
*out = SUPPORTS_SUFFIX_QUERIES;
} else if (mstr_eq_ignore_case(mstrv_lit(MONGOCRYPT_QUERY_TYPE_PREFIXPREVIEW_DEPRECATED_STR), qtv)
|| mstr_eq_ignore_case(mstrv_lit(MONGOCRYPT_QUERY_TYPE_PREFIX_STR), qtv)) {
} else if (mstr_eq_ignore_case(mstrv_lit(MONGOCRYPT_QUERY_TYPE_PREFIX_STR), qtv)) {
*out = SUPPORTS_PREFIX_QUERIES;
} else if (mstr_eq_ignore_case(mstrv_lit(MONGOCRYPT_QUERY_TYPE_SUFFIXPREVIEW_DEPRECATED_STR), qtv)) {
*out = SUPPORTS_SUFFIX_PREVIEW_DEPRECATED_QUERIES;
} else if (mstr_eq_ignore_case(mstrv_lit(MONGOCRYPT_QUERY_TYPE_PREFIXPREVIEW_DEPRECATED_STR), qtv)) {
*out = SUPPORTS_PREFIX_PREVIEW_DEPRECATED_QUERIES;
} else {
return false;
}
Expand Down Expand Up @@ -176,6 +178,20 @@ static bool _parse_field(mc_EncryptedFieldConfig_t *efc, bson_t *field, mongocry
return false;
}

if (query_types & SUPPORTS_PREFIX_PREVIEW_DEPRECATED_QUERIES) {
CLIENT_ERR("Cannot use field '%s' with 'prefixPreview' queries. 'prefixPreview' is unsupported. Use 'prefix' "
"instead.",
field_path);
return false;
}

if (query_types & SUPPORTS_SUFFIX_PREVIEW_DEPRECATED_QUERIES) {
CLIENT_ERR("Cannot use field '%s' with 'suffixPreview' queries. 'suffixPreview' is unsupported. Use 'suffix' "
"instead.",
field_path);
return false;
}

/* Prepend a new mc_EncryptedField_t */
mc_EncryptedField_t *ef = bson_malloc0(sizeof(mc_EncryptedField_t));
if (has_keyid) {
Expand Down
32 changes: 16 additions & 16 deletions src/mongocrypt-ctx-encrypt.c
Original file line number Diff line number Diff line change
Expand Up @@ -1539,7 +1539,7 @@ static bool _fle2_finalize_explicit(mongocrypt_ctx_t *ctx, mongocrypt_binary_t *
goto fail;
// fallthrough
case MONGOCRYPT_INDEX_TYPE_RANGE: marking.u.fle2.algorithm = MONGOCRYPT_FLE2_ALGORITHM_RANGE; break;
case MONGOCRYPT_INDEX_TYPE_TEXTPREVIEW: marking.u.fle2.algorithm = MONGOCRYPT_FLE2_ALGORITHM_TEXT_SEARCH; break;
case MONGOCRYPT_INDEX_TYPE_STRING: marking.u.fle2.algorithm = MONGOCRYPT_FLE2_ALGORITHM_TEXT_SEARCH; break;
default:
// This might be unreachable because of other validation. Better safe than
// sorry.
Expand Down Expand Up @@ -1631,7 +1631,7 @@ static bool _fle2_finalize_explicit(mongocrypt_ctx_t *ctx, mongocrypt_binary_t *
case MONGOCRYPT_INDEX_TYPE_EQUALITY:
case MONGOCRYPT_INDEX_TYPE_RANGEPREVIEW_DEPRECATED:
case MONGOCRYPT_INDEX_TYPE_RANGE:
case MONGOCRYPT_INDEX_TYPE_TEXTPREVIEW:
case MONGOCRYPT_INDEX_TYPE_STRING:
// All QE indexed algorithms require contention factor.
BSON_ASSERT(ctx->opts.contention_factor.set); // Checked earlier in explicit_encrypt_init.
marking.u.fle2.maxContentionFactor = ctx->opts.contention_factor.value;
Expand Down Expand Up @@ -2088,18 +2088,18 @@ static bool explicit_encrypt_init(mongocrypt_ctx_t *ctx, mongocrypt_binary_t *ms
if (ctx->opts.query_type.set) {
const mongocrypt_query_type_t qt = ctx->opts.query_type.value;
if (qt == MONGOCRYPT_QUERY_TYPE_PREFIX) {
if (!(ctx->opts.index_type.set && ctx->opts.index_type.value == MONGOCRYPT_INDEX_TYPE_TEXTPREVIEW)) {
return _mongocrypt_ctx_fail_w_msg(ctx, "prefix query type requires textPreview index type");
if (!(ctx->opts.index_type.set && ctx->opts.index_type.value == MONGOCRYPT_INDEX_TYPE_STRING)) {
return _mongocrypt_ctx_fail_w_msg(ctx, "prefix query type requires string index type");
}
}
if (qt == MONGOCRYPT_QUERY_TYPE_SUFFIX) {
if (!(ctx->opts.index_type.set && ctx->opts.index_type.value == MONGOCRYPT_INDEX_TYPE_TEXTPREVIEW)) {
return _mongocrypt_ctx_fail_w_msg(ctx, "suffix query type requires textPreview index type");
if (!(ctx->opts.index_type.set && ctx->opts.index_type.value == MONGOCRYPT_INDEX_TYPE_STRING)) {
return _mongocrypt_ctx_fail_w_msg(ctx, "suffix query type requires string index type");
}
}
if (qt == MONGOCRYPT_QUERY_TYPE_SUBSTRINGPREVIEW) {
if (!(ctx->opts.index_type.set && ctx->opts.index_type.value == MONGOCRYPT_INDEX_TYPE_TEXTPREVIEW)) {
return _mongocrypt_ctx_fail_w_msg(ctx, "substringPreview query type requires textPreview index type");
if (!(ctx->opts.index_type.set && ctx->opts.index_type.value == MONGOCRYPT_INDEX_TYPE_STRING)) {
return _mongocrypt_ctx_fail_w_msg(ctx, "substringPreview query type requires string index type");
}
}
}
Expand All @@ -2113,14 +2113,14 @@ static bool explicit_encrypt_init(mongocrypt_ctx_t *ctx, mongocrypt_binary_t *ms
return _mongocrypt_ctx_fail_w_msg(ctx, "cannot set range opts with equality index type");
}

if (ctx->opts.index_type.value == MONGOCRYPT_INDEX_TYPE_TEXTPREVIEW) {
return _mongocrypt_ctx_fail_w_msg(ctx, "cannot set range opts with textPreview index type");
if (ctx->opts.index_type.value == MONGOCRYPT_INDEX_TYPE_STRING) {
return _mongocrypt_ctx_fail_w_msg(ctx, "cannot set range opts with 'string' algorithm");
}
}

if (ctx->opts.textopts.set && ctx->opts.index_type.set) {
if (ctx->opts.index_type.value != MONGOCRYPT_INDEX_TYPE_TEXTPREVIEW) {
return _mongocrypt_ctx_fail_w_msg(ctx, "cannot set text opts without textPreview index type");
if (ctx->opts.index_type.value != MONGOCRYPT_INDEX_TYPE_STRING) {
return _mongocrypt_ctx_fail_w_msg(ctx, "cannot set string opts without string index type");
}
}

Expand All @@ -2147,13 +2147,13 @@ static bool explicit_encrypt_init(mongocrypt_ctx_t *ctx, mongocrypt_binary_t *ms
}

// Check required options for text algorithm are set:
if (ctx->opts.index_type.set && (ctx->opts.index_type.value == MONGOCRYPT_INDEX_TYPE_TEXTPREVIEW)) {
if (ctx->opts.index_type.set && (ctx->opts.index_type.value == MONGOCRYPT_INDEX_TYPE_STRING)) {
if (!ctx->opts.contention_factor.set) {
return _mongocrypt_ctx_fail_w_msg(ctx, "contention factor is required for textPreview algorithm");
return _mongocrypt_ctx_fail_w_msg(ctx, "contention factor is required for string algorithm");
}

if (!ctx->opts.textopts.set) {
return _mongocrypt_ctx_fail_w_msg(ctx, "text opts are required for textPreview algorithm");
return _mongocrypt_ctx_fail_w_msg(ctx, "string opts are required for string algorithm");
}
}

Expand Down Expand Up @@ -2183,7 +2183,7 @@ static bool explicit_encrypt_init(mongocrypt_ctx_t *ctx, mongocrypt_binary_t *ms
case MONGOCRYPT_QUERY_TYPE_PREFIX:
case MONGOCRYPT_QUERY_TYPE_SUFFIX:
case MONGOCRYPT_QUERY_TYPE_SUBSTRINGPREVIEW:
matches = (ctx->opts.index_type.value == MONGOCRYPT_INDEX_TYPE_TEXTPREVIEW);
matches = (ctx->opts.index_type.value == MONGOCRYPT_INDEX_TYPE_STRING);
break;
default:
CLIENT_ERR("unsupported value for query_type: %d", (int)ctx->opts.query_type.value);
Expand Down
18 changes: 7 additions & 11 deletions src/mongocrypt-ctx.c
Original file line number Diff line number Diff line change
Expand Up @@ -245,8 +245,8 @@ bool mongocrypt_ctx_setopt_algorithm(mongocrypt_ctx_t *ctx, const char *algorith
} else if (mstr_eq_ignore_case(algo_str, mstrv_lit(MONGOCRYPT_ALGORITHM_RANGEPREVIEW_DEPRECATED_STR))) {
_mongocrypt_ctx_fail_w_msg(ctx, "Algorithm 'rangePreview' is deprecated, please use 'range'");
return false;
} else if (mstr_eq_ignore_case(algo_str, mstrv_lit(MONGOCRYPT_ALGORITHM_TEXTPREVIEW_STR))) {
ctx->opts.index_type.value = MONGOCRYPT_INDEX_TYPE_TEXTPREVIEW;
} else if (mstr_eq_ignore_case(algo_str, mstrv_lit(MONGOCRYPT_ALGORITHM_STRING_STR))) {
ctx->opts.index_type.value = MONGOCRYPT_INDEX_TYPE_STRING;
ctx->opts.index_type.set = true;
} else {
char *error = bson_strdup_printf("unsupported algorithm string \"%.*s\"",
Expand Down Expand Up @@ -1028,15 +1028,11 @@ bool mongocrypt_ctx_setopt_query_type(mongocrypt_ctx_t *ctx, const char *query_t
ctx->opts.query_type.value = MONGOCRYPT_QUERY_TYPE_SUFFIX;
ctx->opts.query_type.set = true;
} else if (mstr_eq_ignore_case(qt_str, mstrv_lit(MONGOCRYPT_QUERY_TYPE_PREFIXPREVIEW_DEPRECATED_STR))) {
// TODO: MONGOCRYPT-870 disallow prefixPreview
// _mongocrypt_ctx_fail_w_msg(ctx, "Query type 'prefixPreview' is deprecated, please use 'prefix'");
ctx->opts.query_type.value = MONGOCRYPT_QUERY_TYPE_PREFIX;
ctx->opts.query_type.set = true;
_mongocrypt_ctx_fail_w_msg(ctx, "Query type 'prefixPreview' is deprecated, please use 'prefix'");
return false;
} else if (mstr_eq_ignore_case(qt_str, mstrv_lit(MONGOCRYPT_QUERY_TYPE_SUFFIXPREVIEW_DEPRECATED_STR))) {
// TODO: MONGOCRYPT-870 disallow suffixPreview
// _mongocrypt_ctx_fail_w_msg(ctx, "Query type 'suffixPreview' is deprecated, please use 'suffix'");
ctx->opts.query_type.value = MONGOCRYPT_QUERY_TYPE_SUFFIX;
ctx->opts.query_type.set = true;
_mongocrypt_ctx_fail_w_msg(ctx, "Query type 'suffixPreview' is deprecated, please use 'suffix'");
return false;
} else if (mstr_eq_ignore_case(qt_str, mstrv_lit(MONGOCRYPT_QUERY_TYPE_SUBSTRINGPREVIEW_STR))) {
ctx->opts.query_type.value = MONGOCRYPT_QUERY_TYPE_SUBSTRINGPREVIEW;
ctx->opts.query_type.set = true;
Expand All @@ -1058,7 +1054,7 @@ const char *_mongocrypt_index_type_to_string(mongocrypt_index_type_t val) {
case MONGOCRYPT_INDEX_TYPE_EQUALITY: return "Equality";
case MONGOCRYPT_INDEX_TYPE_RANGE: return "Range";
case MONGOCRYPT_INDEX_TYPE_RANGEPREVIEW_DEPRECATED: return "RangePreview";
case MONGOCRYPT_INDEX_TYPE_TEXTPREVIEW: return "TextPreview";
case MONGOCRYPT_INDEX_TYPE_STRING: return "String";
default: return "Unknown";
}
}
Expand Down
2 changes: 1 addition & 1 deletion src/mongocrypt-private.h
Original file line number Diff line number Diff line change
Expand Up @@ -156,7 +156,7 @@ typedef enum {
MONGOCRYPT_INDEX_TYPE_EQUALITY = 2,
MONGOCRYPT_INDEX_TYPE_RANGE = 3,
MONGOCRYPT_INDEX_TYPE_RANGEPREVIEW_DEPRECATED = 4,
MONGOCRYPT_INDEX_TYPE_TEXTPREVIEW = 5,
MONGOCRYPT_INDEX_TYPE_STRING = 5,
} mongocrypt_index_type_t;

bool _mongocrypt_validate_and_copy_string(const char *in, int32_t in_len, char **out) MONGOCRYPT_WARN_UNUSED_RESULT;
Expand Down
12 changes: 8 additions & 4 deletions src/mongocrypt.h
Original file line number Diff line number Diff line change
Expand Up @@ -716,8 +716,10 @@ bool mongocrypt_ctx_setopt_algorithm(mongocrypt_ctx_t *ctx, const char *algorith
// DEPRECATED: support "RangePreview" has been removed in favor of "range".
#define MONGOCRYPT_ALGORITHM_RANGEPREVIEW_DEPRECATED_STR "RangePreview"
#define MONGOCRYPT_ALGORITHM_RANGE_STR "Range"
/// NOTE: "textPreview" is experimental only and may be removed in a future non-major release.
#define MONGOCRYPT_ALGORITHM_TEXTPREVIEW_STR "textPreview"
/// DEPRECATED: "textPreview" has been removed. Use "string".
#define MONGOCRYPT_ALGORITHM_TEXTPREVIEW_DEPRECATED_STR "textPreview"
// String constant for setopt_algorithm "string" explicit encryption.
#define MONGOCRYPT_ALGORITHM_STRING_STR "string"

/**
* Identify the AWS KMS master key to use for creating a data key.
Expand Down Expand Up @@ -1555,9 +1557,9 @@ MONGOCRYPT_EXPORT
bool mongocrypt_ctx_setopt_algorithm_range(mongocrypt_ctx_t *ctx, mongocrypt_binary_t *opts);

/**
* Set options for explicit encryption with the "textPreview" algorithm.
* Set options for explicit encryption with the "string" algorithm.
*
* NOTE: "textPreview" is experimental only and may be removed in a future non-major release.
* NOTE: Use of the "substringPreview" query type is experimental only and may be removed in a future non-major release.
* @p opts is a BSON document of the form:
* {
* "caseSensitive": bool,
Expand All @@ -1578,6 +1580,8 @@ bool mongocrypt_ctx_setopt_algorithm_range(mongocrypt_ctx_t *ctx, mongocrypt_bin
* }
*
* "prefix" and "suffix" can both be set.
*
* NOTE: Driver public APIs should use the name "string" rather than "text" to refer to options.
*/
MONGOCRYPT_EXPORT
bool mongocrypt_ctx_setopt_algorithm_text(mongocrypt_ctx_t *ctx, mongocrypt_binary_t *opts);
Expand Down
4 changes: 2 additions & 2 deletions test/data/cleanup/text-search/collinfo.json
Original file line number Diff line number Diff line change
Expand Up @@ -74,7 +74,7 @@
"path": "textField2",
"bsonType": "string",
"queries": [{
"queryType": "suffixPreview",
"queryType": "suffix",
"contention": {
"$numberLong": "0"
},
Expand All @@ -84,7 +84,7 @@
"diacriticSensitive": false
},
{
"queryType": "prefixPreview",
"queryType": "prefix",
"contention": {
"$numberLong": "0"
},
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -72,7 +72,7 @@
"path": "textField2",
"bsonType": "string",
"queries": [{
"queryType": "suffixPreview",
"queryType": "suffix",
"contention": {
"$numberLong": "0"
},
Expand All @@ -82,7 +82,7 @@
"diacriticSensitive": false
},
{
"queryType": "prefixPreview",
"queryType": "prefix",
"contention": {
"$numberLong": "0"
},
Expand Down
4 changes: 2 additions & 2 deletions test/data/compact/text-search/collinfo.json
Original file line number Diff line number Diff line change
Expand Up @@ -74,7 +74,7 @@
"path": "textField2",
"bsonType": "string",
"queries": [{
"queryType": "suffixPreview",
"queryType": "suffix",
"contention": {
"$numberLong": "0"
},
Expand All @@ -84,7 +84,7 @@
"diacriticSensitive": false
},
{
"queryType": "prefixPreview",
"queryType": "prefix",
"contention": {
"$numberLong": "0"
},
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -72,7 +72,7 @@
"path": "textField2",
"bsonType": "string",
"queries": [{
"queryType": "suffixPreview",
"queryType": "suffix",
"contention": {
"$numberLong": "0"
},
Expand All @@ -82,7 +82,7 @@
"diacriticSensitive": false
},
{
"queryType": "prefixPreview",
"queryType": "prefix",
"contention": {
"$numberLong": "0"
},
Expand Down
4 changes: 2 additions & 2 deletions test/data/compact/text-search/encrypted-payload.json
Original file line number Diff line number Diff line change
Expand Up @@ -78,7 +78,7 @@
"path": "textField2",
"bsonType": "string",
"queries": [{
"queryType": "suffixPreview",
"queryType": "suffix",
"contention": {
"$numberLong": "0"
},
Expand All @@ -88,7 +88,7 @@
"diacriticSensitive": false
},
{
"queryType": "prefixPreview",
"queryType": "prefix",
"contention": {
"$numberLong": "0"
},
Expand Down
4 changes: 2 additions & 2 deletions test/data/efc/efc-textSearchFields-badVersionSet.json
Original file line number Diff line number Diff line change
Expand Up @@ -30,13 +30,13 @@
"bsonType": "string",
"queries": [
{
"queryType": "suffixPreview",
"queryType": "suffix",
"contention": {
"$numberLong": "0"
}
},
{
"queryType": "prefixPreview",
"queryType": "prefix",
"contention": {
"$numberLong": "0"
}
Expand Down
4 changes: 2 additions & 2 deletions test/data/efc/efc-textSearchFields-goodVersionSet.json
Original file line number Diff line number Diff line change
Expand Up @@ -30,13 +30,13 @@
"bsonType": "string",
"queries": [
{
"queryType": "suffixPreview",
"queryType": "suffix",
"contention": {
"$numberLong": "0"
}
},
{
"queryType": "prefixPreview",
"queryType": "prefix",
"contention": {
"$numberLong": "0"
}
Expand Down
4 changes: 2 additions & 2 deletions test/data/efc/efc-textSearchFields.json
Original file line number Diff line number Diff line change
Expand Up @@ -30,13 +30,13 @@
"bsonType": "string",
"queries": [
{
"queryType": "suffixPreview",
"queryType": "suffix",
"contention": {
"$numberLong": "0"
}
},
{
"queryType": "prefixPreview",
"queryType": "prefix",
"contention": {
"$numberLong": "0"
}
Expand Down
Loading
Loading