diff --git a/CHANGELOG.md b/CHANGELOG.md index 775be4b6a..989d9206d 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -2,6 +2,9 @@ ## 1.20.0 [Unreleased] +### Added +- Restore support for the deprecated `prefixPreview` and `suffixPreview` query types. + ## 1.19.0 diff --git a/src/mc-efc-private.h b/src/mc-efc-private.h index f78379602..d759f574f 100644 --- a/src/mc-efc-private.h +++ b/src/mc-efc-private.h @@ -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; diff --git a/src/mc-efc.c b/src/mc-efc.c index ad43a531a..87fb6abc3 100644 --- a/src/mc-efc.c +++ b/src/mc-efc.c @@ -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) { @@ -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 { diff --git a/src/mc-textopts.c b/src/mc-textopts.c index 0a9a356ef..76f03e205 100644 --- a/src/mc-textopts.c +++ b/src/mc-textopts.c @@ -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; } diff --git a/src/mongocrypt-ctx-encrypt.c b/src/mongocrypt-ctx-encrypt.c index 5d967db36..dc690fe7b 100644 --- a/src/mongocrypt-ctx-encrypt.c +++ b/src/mongocrypt-ctx-encrypt.c @@ -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; } @@ -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: , anchorPaddingToken: } esct = mc_ESCToken_new(crypto, cl1t, status); if (!esct) { @@ -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; @@ -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"); } @@ -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; diff --git a/src/mongocrypt-ctx-private.h b/src/mongocrypt-ctx-private.h index 8d62765e3..e27911826 100644 --- a/src/mongocrypt-ctx-private.h +++ b/src/mongocrypt-ctx-private.h @@ -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); diff --git a/src/mongocrypt-ctx.c b/src/mongocrypt-ctx.c index ab8009214..cdfcdfb2f 100644 --- a/src/mongocrypt-ctx.c +++ b/src/mongocrypt-ctx.c @@ -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; @@ -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"; } diff --git a/test/test-mongocrypt-ctx-encrypt.c b/test/test-mongocrypt-ctx-encrypt.c index eb7dd2a01..05e3b21da 100644 --- a/test/test-mongocrypt-ctx-encrypt.c +++ b/test/test-mongocrypt-ctx-encrypt.c @@ -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; @@ -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; @@ -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 @@ -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); @@ -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); @@ -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); } @@ -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); diff --git a/test/test-mongocrypt-ctx-setopt.c b/test/test-mongocrypt-ctx-setopt.c index ecd955c57..393ba0691 100644 --- a/test/test-mongocrypt-ctx-setopt.c +++ b/test/test-mongocrypt-ctx-setopt.c @@ -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 */