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

## 1.20.0 [Unreleased]

### Added
- Restore support for the deprecated `prefixPreview` and `suffixPreview` query types.

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

## 1.19.0
Expand Down
2 changes: 1 addition & 1 deletion src/mc-efc-private.h
Original file line number Diff line number Diff line change
Expand Up @@ -32,7 +32,7 @@ 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.
// suffixPreview and prefixPreview are deprecated aliases for suffix and prefix, respectively.
SUPPORTS_SUFFIX_PREVIEW_DEPRECATED_QUERIES = 1 << 6,
SUPPORTS_PREFIX_PREVIEW_DEPRECATED_QUERIES = 1 << 7,
} supported_query_type_flags;
Expand Down
17 changes: 2 additions & 15 deletions src/mc-efc.c
Original file line number Diff line number Diff line change
Expand Up @@ -178,20 +178,6 @@ 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 Expand Up @@ -258,7 +244,8 @@ bool mc_EncryptedFieldConfig_parse(mc_EncryptedFieldConfig_t *efc,

if (!bson_iter_init_find(&iter, efc_bson, "strEncodeVersion")) {
if (all_supported_queries
& (SUPPORTS_SUBSTRING_PREVIEW_QUERIES | SUPPORTS_SUFFIX_QUERIES | SUPPORTS_PREFIX_QUERIES)) {
& (SUPPORTS_SUBSTRING_PREVIEW_QUERIES | SUPPORTS_SUFFIX_QUERIES | SUPPORTS_PREFIX_QUERIES
| SUPPORTS_SUFFIX_PREVIEW_DEPRECATED_QUERIES | SUPPORTS_PREFIX_PREVIEW_DEPRECATED_QUERIES)) {
// Has at least one text search query type, set to latest by default.
efc->str_encode_version = LATEST_STR_ENCODE_VERSION;
} else {
Expand Down
6 changes: 4 additions & 2 deletions src/mc-textopts.c
Original file line number Diff line number Diff line change
Expand Up @@ -368,11 +368,13 @@ bool mc_TextOpts_to_FLE2TextSearchInsertSpec_for_query(const mc_TextOpts_t *txo,
CLIENT_ERR("Unexpected query type: %s\n", _mongocrypt_query_type_to_string(query_type));
return false;
}
case MONGOCRYPT_QUERY_TYPE_PREFIX: {
case MONGOCRYPT_QUERY_TYPE_PREFIX:
case MONGOCRYPT_QUERY_TYPE_PREFIXPREVIEW_DEPRECATED: {
include_prefix = true;
break;
}
case MONGOCRYPT_QUERY_TYPE_SUFFIX: {
case MONGOCRYPT_QUERY_TYPE_SUFFIX:
case MONGOCRYPT_QUERY_TYPE_SUFFIXPREVIEW_DEPRECATED: {
include_suffix = true;
break;
}
Expand Down
14 changes: 10 additions & 4 deletions src/mongocrypt-ctx-encrypt.c
Original file line number Diff line number Diff line change
Expand Up @@ -891,7 +891,8 @@ static moe_result must_omit_encryptionInformation(const char *command_name,
for (const mc_EncryptedField_t *ef = efc->fields; ef != NULL; ef = ef->next) {
if (ef->supported_queries
& (SUPPORTS_RANGE_QUERIES | SUPPORTS_SUBSTRING_PREVIEW_QUERIES | SUPPORTS_SUFFIX_QUERIES
| SUPPORTS_PREFIX_QUERIES)) {
| SUPPORTS_PREFIX_QUERIES | SUPPORTS_SUFFIX_PREVIEW_DEPRECATED_QUERIES
| SUPPORTS_PREFIX_PREVIEW_DEPRECATED_QUERIES)) {
has_fields_requiring_ei = true;
break;
}
Expand Down Expand Up @@ -1012,7 +1013,8 @@ static bool _fle2_append_compactionTokens(mongocrypt_t *crypt,

if (ptr->supported_queries
& (SUPPORTS_RANGE_QUERIES | SUPPORTS_SUBSTRING_PREVIEW_QUERIES | SUPPORTS_SUFFIX_QUERIES
| SUPPORTS_PREFIX_QUERIES)) {
| SUPPORTS_PREFIX_QUERIES | SUPPORTS_SUFFIX_PREVIEW_DEPRECATED_QUERIES
| SUPPORTS_PREFIX_PREVIEW_DEPRECATED_QUERIES)) {
// Append the document {ecoc: <ECOCToken>, anchorPaddingToken: <AnchorPaddingTokenRoot>}
esct = mc_ESCToken_new(crypto, cl1t, status);
if (!esct) {
Expand Down Expand Up @@ -1522,6 +1524,8 @@ static bool _fle2_finalize_explicit(mongocrypt_ctx_t *ctx, mongocrypt_binary_t *
// fallthrough
case MONGOCRYPT_QUERY_TYPE_SUFFIX:
case MONGOCRYPT_QUERY_TYPE_PREFIX:
case MONGOCRYPT_QUERY_TYPE_SUFFIXPREVIEW_DEPRECATED:
case MONGOCRYPT_QUERY_TYPE_PREFIXPREVIEW_DEPRECATED:
case MONGOCRYPT_QUERY_TYPE_SUBSTRINGPREVIEW:
case MONGOCRYPT_QUERY_TYPE_RANGE:
case MONGOCRYPT_QUERY_TYPE_EQUALITY: marking.u.fle2.type = MONGOCRYPT_FLE2_PLACEHOLDER_TYPE_FIND; break;
Expand Down Expand Up @@ -2087,12 +2091,12 @@ 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 (qt == MONGOCRYPT_QUERY_TYPE_PREFIX || qt == MONGOCRYPT_QUERY_TYPE_PREFIXPREVIEW_DEPRECATED) {
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 (qt == MONGOCRYPT_QUERY_TYPE_SUFFIX || qt == MONGOCRYPT_QUERY_TYPE_SUFFIXPREVIEW_DEPRECATED) {
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");
}
Expand Down Expand Up @@ -2182,6 +2186,8 @@ static bool explicit_encrypt_init(mongocrypt_ctx_t *ctx, mongocrypt_binary_t *ms
// fallthrough
case MONGOCRYPT_QUERY_TYPE_PREFIX:
case MONGOCRYPT_QUERY_TYPE_SUFFIX:
case MONGOCRYPT_QUERY_TYPE_PREFIXPREVIEW_DEPRECATED:
case MONGOCRYPT_QUERY_TYPE_SUFFIXPREVIEW_DEPRECATED:
case MONGOCRYPT_QUERY_TYPE_SUBSTRINGPREVIEW:
matches = (ctx->opts.index_type.value == MONGOCRYPT_INDEX_TYPE_STRING);
break;
Expand Down
4 changes: 4 additions & 0 deletions src/mongocrypt-ctx-private.h
Original file line number Diff line number Diff line change
Expand Up @@ -47,6 +47,10 @@ typedef enum _mongocrypt_query_type_t {
MONGOCRYPT_QUERY_TYPE_PREFIX = 4,
MONGOCRYPT_QUERY_TYPE_SUFFIX = 5,
MONGOCRYPT_QUERY_TYPE_SUBSTRINGPREVIEW = 6,
// prefixPreview and suffixPreview are deprecated aliases for prefix and suffix, respectively. They behave
// identically; the distinct values exist for consistency (cf. rangePreview) and to ease eventual removal.
MONGOCRYPT_QUERY_TYPE_PREFIXPREVIEW_DEPRECATED = 7,
MONGOCRYPT_QUERY_TYPE_SUFFIXPREVIEW_DEPRECATED = 8,
} mongocrypt_query_type_t;

const char *_mongocrypt_query_type_to_string(mongocrypt_query_type_t val);
Expand Down
12 changes: 8 additions & 4 deletions src/mongocrypt-ctx.c
Original file line number Diff line number Diff line change
Expand Up @@ -1028,11 +1028,13 @@ 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))) {
_mongocrypt_ctx_fail_w_msg(ctx, "Query type 'prefixPreview' is deprecated, please use 'prefix'");
return false;
// 'prefixPreview' is a deprecated alias for 'prefix'.
ctx->opts.query_type.value = MONGOCRYPT_QUERY_TYPE_PREFIXPREVIEW_DEPRECATED;
ctx->opts.query_type.set = true;
} else if (mstr_eq_ignore_case(qt_str, mstrv_lit(MONGOCRYPT_QUERY_TYPE_SUFFIXPREVIEW_DEPRECATED_STR))) {
_mongocrypt_ctx_fail_w_msg(ctx, "Query type 'suffixPreview' is deprecated, please use 'suffix'");
return false;
// 'suffixPreview' is a deprecated alias for 'suffix'.
ctx->opts.query_type.value = MONGOCRYPT_QUERY_TYPE_SUFFIXPREVIEW_DEPRECATED;
ctx->opts.query_type.set = true;
} 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 Down Expand Up @@ -1066,6 +1068,8 @@ const char *_mongocrypt_query_type_to_string(mongocrypt_query_type_t val) {
case MONGOCRYPT_QUERY_TYPE_RANGE: return "Range";
case MONGOCRYPT_QUERY_TYPE_PREFIX: return "Prefix";
case MONGOCRYPT_QUERY_TYPE_SUFFIX: return "Suffix";
case MONGOCRYPT_QUERY_TYPE_PREFIXPREVIEW_DEPRECATED: return "PrefixPreview";
case MONGOCRYPT_QUERY_TYPE_SUFFIXPREVIEW_DEPRECATED: return "SuffixPreview";
case MONGOCRYPT_QUERY_TYPE_SUBSTRINGPREVIEW: return "SubstringPreview";
default: return "Unknown";
}
Expand Down
41 changes: 18 additions & 23 deletions test/test-mongocrypt-ctx-encrypt.c
Original file line number Diff line number Diff line change
Expand Up @@ -2511,10 +2511,11 @@ static void _test_encrypt_fle2_explicit(_mongocrypt_tester_t *tester) {
}

{
// "suffixPreview" is a deprecated alias for "suffix" and must produce identical output.
ee_testcase tc = {0};
tc.desc = "find suffix";
tc.desc = "find suffixPreview";
tc.algorithm = MONGOCRYPT_ALGORITHM_STRING_STR;
tc.query_type = MONGOCRYPT_QUERY_TYPE_SUFFIX_STR;
tc.query_type = MONGOCRYPT_QUERY_TYPE_SUFFIXPREVIEW_DEPRECATED_STR;
tc.contention_factor = OPT_I64(1);
tc.msg = TEST_BSON("{'v': 'abc'}");
tc.user_key_id = &keyABC_id;
Expand All @@ -2529,10 +2530,11 @@ static void _test_encrypt_fle2_explicit(_mongocrypt_tester_t *tester) {
}

{
// "prefixPreview" is a deprecated alias for "prefix" and must produce identical output.
ee_testcase tc = {0};
tc.desc = "find prefix";
tc.desc = "find prefixPreview";
tc.algorithm = MONGOCRYPT_ALGORITHM_STRING_STR;
tc.query_type = MONGOCRYPT_QUERY_TYPE_PREFIX_STR;
tc.query_type = MONGOCRYPT_QUERY_TYPE_PREFIXPREVIEW_DEPRECATED_STR;
tc.contention_factor = OPT_I64(1);
tc.msg = TEST_BSON("{'v': 'abc'}");
tc.user_key_id = &keyABC_id;
Expand Down Expand Up @@ -4410,8 +4412,9 @@ static void _test_rangePreview_fails(_mongocrypt_tester_t *tester) {
bson_free(local_kek);
}

// `_test_prefixPreview_suffixPreview_fails` tests that use of "prefixPreview" or "suffixPreview" errors.
static void _test_prefixPreview_suffixPreview_fails(_mongocrypt_tester_t *tester) {
// `_test_prefixPreview_suffixPreview_succeeds` tests that "prefixPreview" and "suffixPreview" are accepted as
// deprecated aliases for "prefix" and "suffix".
static void _test_prefixPreview_suffixPreview_succeeds(_mongocrypt_tester_t *tester) {
#define TF(suffix) TEST_FILE("./test/data/fle2-insert-text-search-preview/" suffix)

// local_kek is the KEK used to encrypt the keyMaterial in ./test/data/key-document-local.json
Expand All @@ -4420,35 +4423,31 @@ static void _test_prefixPreview_suffixPreview_fails(_mongocrypt_tester_t *tester
mongocrypt_binary_t *kms_providers =
TEST_BSON(BSON_STR({"local" : {"key" : {"$binary" : {"base64" : "%s", "subType" : "00"}}}}), local_kek);

// Test setting 'prefixPreview' as an explicit encryption queryType results in error.
// Test setting 'prefixPreview' as an explicit encryption queryType succeeds.
{
mongocrypt_t *crypt = mongocrypt_new();
mongocrypt_setopt_kms_providers(crypt, kms_providers);
ASSERT_OK(mongocrypt_init(crypt), crypt);
mongocrypt_ctx_t *ctx = mongocrypt_ctx_new(crypt);
ASSERT_OK(ctx, crypt);
ASSERT_FAILS(mongocrypt_ctx_setopt_query_type(ctx, MONGOCRYPT_QUERY_TYPE_PREFIXPREVIEW_DEPRECATED_STR, -1),
ctx,
"Query type 'prefixPreview' is deprecated");
ASSERT_OK(mongocrypt_ctx_setopt_query_type(ctx, MONGOCRYPT_QUERY_TYPE_PREFIXPREVIEW_DEPRECATED_STR, -1), ctx);
mongocrypt_ctx_destroy(ctx);
mongocrypt_destroy(crypt);
}

// Test setting 'suffixPreview' as an explicit encryption queryType results in error.
// Test setting 'suffixPreview' as an explicit encryption queryType succeeds.
{
mongocrypt_t *crypt = mongocrypt_new();
mongocrypt_setopt_kms_providers(crypt, kms_providers);
ASSERT_OK(mongocrypt_init(crypt), crypt);
mongocrypt_ctx_t *ctx = mongocrypt_ctx_new(crypt);
ASSERT_OK(ctx, crypt);
ASSERT_FAILS(mongocrypt_ctx_setopt_query_type(ctx, MONGOCRYPT_QUERY_TYPE_SUFFIXPREVIEW_DEPRECATED_STR, -1),
ctx,
"Query type 'suffixPreview' is deprecated");
ASSERT_OK(mongocrypt_ctx_setopt_query_type(ctx, MONGOCRYPT_QUERY_TYPE_SUFFIXPREVIEW_DEPRECATED_STR, -1), ctx);
mongocrypt_ctx_destroy(ctx);
mongocrypt_destroy(crypt);
}

// Test setting 'prefixPreview' from encryptedFields results in error.
// Test setting 'prefixPreview' from encryptedFields succeeds.
{
mongocrypt_t *crypt = mongocrypt_new();
mongocrypt_setopt_kms_providers(crypt, kms_providers);
Expand All @@ -4457,14 +4456,12 @@ static void _test_prefixPreview_suffixPreview_fails(_mongocrypt_tester_t *tester
ASSERT_OK(mongocrypt_init(crypt), crypt);
mongocrypt_ctx_t *ctx = mongocrypt_ctx_new(crypt);
ASSERT_OK(ctx, crypt);
ASSERT_FAILS(mongocrypt_ctx_encrypt_init(ctx, "db", -1, TF("cmd.json")),
ctx,
"Cannot use field 'encrypted' with 'prefixPreview' queries");
ASSERT_OK(mongocrypt_ctx_encrypt_init(ctx, "db", -1, TF("cmd.json")), ctx);
mongocrypt_ctx_destroy(ctx);
mongocrypt_destroy(crypt);
}

// Test setting 'suffixPreview' from encryptedFields results in error.
// Test setting 'suffixPreview' from encryptedFields succeeds.
{
mongocrypt_t *crypt = mongocrypt_new();
mongocrypt_setopt_kms_providers(crypt, kms_providers);
Expand All @@ -4473,9 +4470,7 @@ static void _test_prefixPreview_suffixPreview_fails(_mongocrypt_tester_t *tester
ASSERT_OK(mongocrypt_init(crypt), crypt);
mongocrypt_ctx_t *ctx = mongocrypt_ctx_new(crypt);
ASSERT_OK(ctx, crypt);
ASSERT_FAILS(mongocrypt_ctx_encrypt_init(ctx, "db", -1, TF("cmd.json")),
ctx,
"Cannot use field 'encrypted' with 'suffixPreview' queries");
ASSERT_OK(mongocrypt_ctx_encrypt_init(ctx, "db", -1, TF("cmd.json")), ctx);
mongocrypt_ctx_destroy(ctx);
mongocrypt_destroy(crypt);
}
Expand Down Expand Up @@ -6904,7 +6899,7 @@ void _mongocrypt_tester_install_ctx_encrypt(_mongocrypt_tester_t *tester) {
INSTALL_TEST(_test_encrypt_fle2_insert_text_search_payload_with_str_encode_version);
INSTALL_TEST(_test_bulkWrite);
INSTALL_TEST(_test_rangePreview_fails);
INSTALL_TEST(_test_prefixPreview_suffixPreview_fails);
INSTALL_TEST(_test_prefixPreview_suffixPreview_succeeds);
INSTALL_TEST(_test_textPreview_fails);
INSTALL_TEST(_test_no_trimFactor);
INSTALL_TEST(_test_range_sends_cryptoParams);
Expand Down
10 changes: 3 additions & 7 deletions test/test-mongocrypt-ctx-setopt.c
Original file line number Diff line number Diff line change
Expand Up @@ -1041,23 +1041,19 @@ static void _test_setopt_for_explicit_encrypt(_mongocrypt_tester_t *tester) {
ASSERT_EX_ENCRYPT_INIT_FAILS(bson, "suffix query type requires string index type");
}

// Can't use "prefixPreview" or "suffixPreview".
// "prefixPreview" and "suffixPreview" are accepted as deprecated aliases for "prefix" and "suffix".
{
mongocrypt_destroy(crypt);
crypt = _mongocrypt_tester_mongocrypt(TESTER_MONGOCRYPT_DEFAULT);
REFRESH_CTX;
ASSERT_KEY_ID_OK(uuid);
ASSERT_FAILS(mongocrypt_ctx_setopt_query_type(ctx, MONGOCRYPT_QUERY_TYPE_PREFIXPREVIEW_DEPRECATED_STR, -1),
ctx,
"'prefixPreview' is deprecated");
ASSERT_OK(mongocrypt_ctx_setopt_query_type(ctx, MONGOCRYPT_QUERY_TYPE_PREFIXPREVIEW_DEPRECATED_STR, -1), ctx);

mongocrypt_destroy(crypt);
crypt = _mongocrypt_tester_mongocrypt(TESTER_MONGOCRYPT_DEFAULT);
REFRESH_CTX;
ASSERT_KEY_ID_OK(uuid);
ASSERT_FAILS(mongocrypt_ctx_setopt_query_type(ctx, MONGOCRYPT_QUERY_TYPE_SUFFIXPREVIEW_DEPRECATED_STR, -1),
ctx,
"'suffixPreview' is deprecated");
ASSERT_OK(mongocrypt_ctx_setopt_query_type(ctx, MONGOCRYPT_QUERY_TYPE_SUFFIXPREVIEW_DEPRECATED_STR, -1), ctx);
}

/* It is an error to set a string algorithm without setting text options */
Expand Down