From 704046922042664717cd60b615052d11acc0db77 Mon Sep 17 00:00:00 2001 From: Pawel Terlecki Date: Tue, 12 Mar 2019 16:22:02 -0400 Subject: SERVER-39171 Implement encrypt.bsonType validation A new MatchExpression was added in JSONSchemaParser. FleBlob is currently used only here. We may decide to share it in the future as necessary. --- src/mongo/db/matcher/SConscript | 1 - src/mongo/db/matcher/expression.h | 1 + src/mongo/db/matcher/expression_parser.cpp | 33 ++++++ src/mongo/db/matcher/expression_parser.h | 1 + src/mongo/db/matcher/expression_parser_test.cpp | 132 ++++++++++++++++++++- src/mongo/db/matcher/expression_type.cpp | 40 ------- src/mongo/db/matcher/expression_type.h | 112 ++++++++++++++++- src/mongo/db/matcher/schema/json_schema_parser.cpp | 43 ++----- .../db/matcher/schema/json_schema_parser_test.cpp | 19 ++- src/mongo/db/pipeline/document_source_match.cpp | 1 + src/mongo/db/query/canonical_query_encoder.cpp | 3 + 11 files changed, 310 insertions(+), 76 deletions(-) delete mode 100644 src/mongo/db/matcher/expression_type.cpp diff --git a/src/mongo/db/matcher/SConscript b/src/mongo/db/matcher/SConscript index 06d5c7b0549..0b081311c62 100644 --- a/src/mongo/db/matcher/SConscript +++ b/src/mongo/db/matcher/SConscript @@ -40,7 +40,6 @@ env.Library( 'expression_text_base.cpp', 'expression_text_noop.cpp', 'expression_tree.cpp', - 'expression_type.cpp', 'expression_where_base.cpp', 'expression_where_noop.cpp', 'expression_with_placeholder.cpp', diff --git a/src/mongo/db/matcher/expression.h b/src/mongo/db/matcher/expression.h index 02db8946ef4..0fb0a2060b4 100644 --- a/src/mongo/db/matcher/expression.h +++ b/src/mongo/db/matcher/expression.h @@ -112,6 +112,7 @@ public: // JSON Schema expressions. INTERNAL_SCHEMA_ALLOWED_PROPERTIES, INTERNAL_SCHEMA_ALL_ELEM_MATCH_FROM_INDEX, + INTERNAL_SCHEMA_BIN_DATA_ENCRYPTED_TYPE, INTERNAL_SCHEMA_BIN_DATA_SUBTYPE, INTERNAL_SCHEMA_COND, INTERNAL_SCHEMA_EQ, diff --git a/src/mongo/db/matcher/expression_parser.cpp b/src/mongo/db/matcher/expression_parser.cpp index b86387bc2f6..c3cbe66f628 100644 --- a/src/mongo/db/matcher/expression_parser.cpp +++ b/src/mongo/db/matcher/expression_parser.cpp @@ -1412,6 +1412,33 @@ StatusWithMatchExpression parseInternalSchemaBinDataSubType(StringData name, BSO name, static_cast(valueAsInt.getValue()))}; } +StatusWithMatchExpression parseInternalSchemaBinDataEncryptedType(StringData name, BSONElement e) { + if (!e.isNumber()) { + return Status(ErrorCodes::FailedToParse, + str::stream() << InternalSchemaBinDataEncryptedTypeExpression::kName + << " must be represented as a number"); + } + + auto valueAsInt = MatchExpressionParser::parseIntegerElementToInt(e); + if (!valueAsInt.isOK()) { + return Status(ErrorCodes::FailedToParse, + str::stream() << "Invalid numerical type code for " + << InternalSchemaBinDataEncryptedTypeExpression::kName + << ": " + << e.number()); + } + + if (!isValidBSONType(valueAsInt.getValue())) { + return Status(ErrorCodes::FailedToParse, + str::stream() << InternalSchemaBinDataEncryptedTypeExpression::kName + << " value must represent a valid BSON type: " + << valueAsInt.getValue()); + } + + return {stdx::make_unique( + name, static_cast(valueAsInt.getValue()))}; +} + /** * Parses a single field in a sub expression. * If the query is { x : { $gt : 5, $lt : 8 } }, @@ -1740,6 +1767,10 @@ StatusWithMatchExpression parseSubField(const BSONObj& context, return {stdx::make_unique(name, e)}; } + case PathAcceptingKeyword::INTERNAL_SCHEMA_BIN_DATA_ENCRYPTED_TYPE: { + return parseInternalSchemaBinDataEncryptedType(name, e); + } + case PathAcceptingKeyword::INTERNAL_SCHEMA_BIN_DATA_SUBTYPE: { return parseInternalSchemaBinDataSubType(name, e); } @@ -1880,6 +1911,8 @@ MONGO_INITIALIZER(MatchExpressionParser)(InitializerContext* context) { {"_internalExprEq", PathAcceptingKeyword::INTERNAL_EXPR_EQ}, {"_internalSchemaAllElemMatchFromIndex", PathAcceptingKeyword::INTERNAL_SCHEMA_ALL_ELEM_MATCH_FROM_INDEX}, + {"_internalSchemaBinDataEncryptedType", + PathAcceptingKeyword::INTERNAL_SCHEMA_BIN_DATA_ENCRYPTED_TYPE}, {"_internalSchemaBinDataSubType", PathAcceptingKeyword::INTERNAL_SCHEMA_BIN_DATA_SUBTYPE}, {"_internalSchemaEq", PathAcceptingKeyword::INTERNAL_SCHEMA_EQ}, diff --git a/src/mongo/db/matcher/expression_parser.h b/src/mongo/db/matcher/expression_parser.h index 7ee6cf4bac5..a5adb44cb61 100644 --- a/src/mongo/db/matcher/expression_parser.h +++ b/src/mongo/db/matcher/expression_parser.h @@ -62,6 +62,7 @@ enum class PathAcceptingKeyword { GREATER_THAN_OR_EQUAL, INTERNAL_EXPR_EQ, INTERNAL_SCHEMA_ALL_ELEM_MATCH_FROM_INDEX, + INTERNAL_SCHEMA_BIN_DATA_ENCRYPTED_TYPE, INTERNAL_SCHEMA_BIN_DATA_SUBTYPE, INTERNAL_SCHEMA_EQ, INTERNAL_SCHEMA_FMOD, diff --git a/src/mongo/db/matcher/expression_parser_test.cpp b/src/mongo/db/matcher/expression_parser_test.cpp index 35be4683fe3..0b9de433bc6 100644 --- a/src/mongo/db/matcher/expression_parser_test.cpp +++ b/src/mongo/db/matcher/expression_parser_test.cpp @@ -36,6 +36,7 @@ #include "mongo/db/matcher/expression.h" #include "mongo/db/matcher/expression_always_boolean.h" #include "mongo/db/matcher/expression_leaf.h" +#include "mongo/db/matcher/expression_type.h" #include "mongo/db/matcher/extensions_callback_noop.h" #include "mongo/db/pipeline/expression_context_for_test.h" @@ -575,10 +576,139 @@ TEST(InternalBinDataSubTypeMatchExpressionTest, InvalidSubTypeDoesNotParse) { TEST(InternalBinDataSubTypeMatchExpressionTest, InvalidNumericalSubTypeDoesNotParse) { boost::intrusive_ptr expCtx(new ExpressionContextForTest()); auto query1 = BSON("a" << BSON("$_internalSchemaBinDataSubType" << 99)); - auto query2 = BSON("a" << BSON("$_ internalSchemaBinDataSubType" << 2.1)); + auto query2 = BSON("a" << BSON("$_internalSchemaBinDataSubType" << 2.1)); auto statusWith1 = MatchExpressionParser::parse(query1, expCtx); auto statusWith2 = MatchExpressionParser::parse(query2, expCtx); ASSERT_NOT_OK(statusWith1.getStatus()); ASSERT_NOT_OK(statusWith2.getStatus()); } + +TEST(InternalSchemaBinDataEncryptedTypeExpressionTest, BsonTypeMatches) { + boost::intrusive_ptr expCtx(new ExpressionContextForTest()); + auto query = BSON("a" << BSON("$_internalSchemaBinDataEncryptedType" << BSONType::String)); + auto expr = uassertStatusOK(MatchExpressionParser::parse(query, expCtx)); + + FleBlobHeader blob; + blob.fleBlobSubtype = FleBlobSubtype::Deterministic; + memset(blob.keyUUID, 0, sizeof(blob.keyUUID)); + blob.originalBsonType = BSONType::String; + + BSONObj matchingDoc = BSON("a" << BSONBinData(reinterpret_cast(&blob), + sizeof(FleBlobHeader), + BinDataType::Encrypt)); + ASSERT_TRUE(expr->matchesBSON(matchingDoc)); +} + +TEST(InternalSchemaBinDataEncryptedTypeExpressionTest, BsonTypeDoesNotMatch) { + boost::intrusive_ptr expCtx(new ExpressionContextForTest()); + auto query = BSON("a" << BSON("$_internalSchemaBinDataEncryptedType" << BSONType::String)); + auto expr = uassertStatusOK(MatchExpressionParser::parse(query, expCtx)); + + FleBlobHeader blob; + blob.fleBlobSubtype = FleBlobSubtype::Deterministic; + memset(blob.keyUUID, 0, sizeof(blob.keyUUID)); + blob.originalBsonType = BSONType::NumberInt; + + BSONObj notMatchingDoc = BSON("a" << BSONBinData(reinterpret_cast(&blob), + sizeof(FleBlobHeader), + BinDataType::Encrypt)); + ASSERT_FALSE(expr->matchesBSON(notMatchingDoc)); +} + +TEST(InternalSchemaBinDataEncryptedTypeExpressionTest, NonNumericalArgumentDoesNotParse) { + boost::intrusive_ptr expCtx(new ExpressionContextForTest()); + ASSERT_EQ(MatchExpressionParser::parse(BSON("a" << BSON("$_internalSchemaBinDataEncryptedType" + << "bar")), + expCtx) + .getStatus(), + ErrorCodes::FailedToParse); + ASSERT_EQ(MatchExpressionParser::parse(BSON("a" << BSON("$_internalSchemaBinDataEncryptedType" + << "0")), + expCtx) + .getStatus(), + ErrorCodes::FailedToParse); +} + +TEST(InternalSchemaBinDataEncryptedTypeExpressionTest, InvalidNumericalArgumentDoesNotParse) { + boost::intrusive_ptr expCtx(new ExpressionContextForTest()); + ASSERT_EQ(MatchExpressionParser::parse( + BSON("a" << BSON("$_internalSchemaBinDataEncryptedType" << 0.21)), expCtx) + .getStatus(), + ErrorCodes::FailedToParse); + ASSERT_EQ(MatchExpressionParser::parse( + BSON("a" << BSON("$_internalSchemaBinDataEncryptedType" << 13.3)), expCtx) + .getStatus(), + ErrorCodes::FailedToParse); +} + +TEST(InternalSchemaBinDataEncryptedTypeExpressionTest, NonBsonTypeArgumentDoesNotParse) { + boost::intrusive_ptr expCtx(new ExpressionContextForTest()); + ASSERT_EQ(MatchExpressionParser::parse(BSON("a" << BSON("$_internalSchemaBinDataEncryptedType" + << (BSONType::JSTypeMax + 1))), + expCtx) + .getStatus(), + ErrorCodes::FailedToParse); +} + +TEST(InternalSchemaBinDataEncryptedTypeExpressionTest, IntentToEncryptFleBlobDoesNotMatch) { + boost::intrusive_ptr expCtx(new ExpressionContextForTest()); + auto query = BSON("a" << BSON("$_internalSchemaBinDataEncryptedType" << BSONType::String)); + auto expr = uassertStatusOK(MatchExpressionParser::parse(query, expCtx)); + + FleBlobHeader blob; + blob.fleBlobSubtype = FleBlobSubtype::IntentToEncrypt; + memset(blob.keyUUID, 0, sizeof(blob.keyUUID)); + blob.originalBsonType = BSONType::String; + BSONObj notMatch = BSON("a" << BSONBinData(reinterpret_cast(&blob), + sizeof(FleBlobHeader), + BinDataType::Encrypt)); + + ASSERT_FALSE(expr->matchesBSON(notMatch)); +} + +TEST(InternalSchemaBinDataEncryptedTypeExpressionTest, UnknownFleBlobTypeDoesNotMatch) { + boost::intrusive_ptr expCtx(new ExpressionContextForTest()); + auto query = BSON("a" << BSON("$_internalSchemaBinDataEncryptedType" << BSONType::String)); + auto expr = uassertStatusOK(MatchExpressionParser::parse(query, expCtx)); + + FleBlobHeader blob; + blob.fleBlobSubtype = 6; + memset(blob.keyUUID, 0, sizeof(blob.keyUUID)); + blob.originalBsonType = BSONType::String; + BSONObj notMatch = BSON("a" << BSONBinData(reinterpret_cast(&blob), + sizeof(FleBlobHeader), + BinDataType::Encrypt)); + try { + expr->matchesBSON(notMatch); + } catch (...) { + ASSERT_EQ(exceptionToStatus().code(), 33118); + } +} + +TEST(InternalSchemaBinDataEncryptedTypeExpressionTest, EmptyFleBlobDoesNotMatch) { + boost::intrusive_ptr expCtx(new ExpressionContextForTest()); + auto query = BSON("a" << BSON("$_internalSchemaBinDataEncryptedType" << BSONType::String)); + auto expr = uassertStatusOK(MatchExpressionParser::parse(query, expCtx)); + + BSONObj notMatch = BSON("a" << BSONBinData(nullptr, 0, BinDataType::Encrypt)); + ASSERT_FALSE(expr->matchesBSON(notMatch)); +} + +TEST(InternalSchemaBinDataEncryptedTypeExpressionTest, NonEncryptBinDataSubTypeDoesNotMatch) { + boost::intrusive_ptr expCtx(new ExpressionContextForTest()); + auto query = BSON("a" << BSON("$_internalSchemaBinDataEncryptedType" << BSONType::String)); + auto expr = uassertStatusOK(MatchExpressionParser::parse(query, expCtx)); + + BSONObj notMatch = BSON("a" << BSONBinData("\x69\xb7", 2, BinDataGeneral)); + ASSERT_FALSE(expr->matchesBSON(notMatch)); +} + +TEST(InternalSchemaBinDataEncryptedTypeExpressionTest, NonBinDataValueDoesNotMatch) { + boost::intrusive_ptr expCtx(new ExpressionContextForTest()); + auto query = BSON("a" << BSON("$_internalSchemaBinDataEncryptedType" << BSONType::String)); + auto expr = uassertStatusOK(MatchExpressionParser::parse(query, expCtx)); + + BSONObj notMatch = BSON("a" << BSONArray()); + ASSERT_FALSE(expr->matchesBSON(notMatch)); +} } // namespace mongo diff --git a/src/mongo/db/matcher/expression_type.cpp b/src/mongo/db/matcher/expression_type.cpp deleted file mode 100644 index e620328996f..00000000000 --- a/src/mongo/db/matcher/expression_type.cpp +++ /dev/null @@ -1,40 +0,0 @@ -/** - * Copyright (C) 2018-present MongoDB, Inc. - * - * This program is free software: you can redistribute it and/or modify - * it under the terms of the Server Side Public License, version 1, - * as published by MongoDB, Inc. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * Server Side Public License for more details. - * - * You should have received a copy of the Server Side Public License - * along with this program. If not, see - * . - * - * As a special exception, the copyright holders give permission to link the - * code of portions of this program with the OpenSSL library under certain - * conditions as described in each individual source file and distribute - * linked combinations including the program with the OpenSSL library. You - * must comply with the Server Side Public License in all respects for - * all of the code used other than as permitted herein. If you modify file(s) - * with this exception, you may extend this exception to your version of the - * file(s), but you are not obligated to do so. If you do not wish to do so, - * delete this exception statement from your version. If you delete this - * exception statement from all source files in the program, then also delete - * it in the license file. - */ - -#include "mongo/platform/basic.h" - -#include "mongo/db/matcher/expression_type.h" - -namespace mongo { - -constexpr StringData InternalSchemaBinDataSubTypeExpression::kName; -constexpr StringData InternalSchemaTypeExpression::kName; -constexpr StringData TypeMatchExpression::kName; - -} // namespace mongo diff --git a/src/mongo/db/matcher/expression_type.h b/src/mongo/db/matcher/expression_type.h index d3e66580092..c206103693c 100644 --- a/src/mongo/db/matcher/expression_type.h +++ b/src/mongo/db/matcher/expression_type.h @@ -34,6 +34,20 @@ namespace mongo { +/** + * Types of the encryption payload. + */ +enum FleBlobSubtype { IntentToEncrypt = 0, Deterministic = 1, Random = 2 }; + +/** + * The structure represents how data is laid out in an encrypted payload. + */ +struct FleBlobHeader { + int8_t fleBlobSubtype; + int8_t keyUUID[16]; + int8_t originalBsonType; +}; + template class TypeMatchExpressionBase : public LeafMatchExpression { public: @@ -165,8 +179,6 @@ public: ElementPath::NonLeafArrayBehavior::kTraverse), _binDataSubType(binDataSubType) {} - virtual ~InternalSchemaBinDataSubTypeExpression() = default; - StringData name() const { return kName; } @@ -223,4 +235,100 @@ private: BinDataType _binDataSubType; }; + +/** + * Implements matching semantics for the JSON Schema keyword encrypt.bsonType. A document + * matches successfully if a field is encrypted and the encrypted payload indicates the + * original BSON element matches the specified type. + */ +class InternalSchemaBinDataEncryptedTypeExpression final : public LeafMatchExpression { +public: + static constexpr StringData kName = "$_internalSchemaBinDataEncryptedType"_sd; + + InternalSchemaBinDataEncryptedTypeExpression(StringData path, BSONType encryptedType) + : LeafMatchExpression(MatchExpression::INTERNAL_SCHEMA_BIN_DATA_ENCRYPTED_TYPE, + path, + ElementPath::LeafArrayBehavior::kNoTraversal, + ElementPath::NonLeafArrayBehavior::kTraverse), + _encryptedType(encryptedType) {} + + StringData name() const { + return kName; + } + + bool matchesSingleElement(const BSONElement& elem, + MatchDetails* details = nullptr) const final { + if (elem.type() != BSONType::BinData) + return false; + if (elem.binDataType() != BinDataType::Encrypt) + return false; + + int binDataLen; + auto binData = elem.binData(binDataLen); + if (!binDataLen) + return false; + + auto fleBlobSubType = binData[0]; + switch (fleBlobSubType) { + case FleBlobSubtype::IntentToEncrypt: + return false; + case FleBlobSubtype::Deterministic: + case FleBlobSubtype::Random: { + // Verify the type of the encrypted data. + auto fleBlob = reinterpret_cast(binData); + return fleBlob->originalBsonType == _encryptedType; + } + default: + uasserted(33118, + str::stream() << "unexpected subtype " << static_cast(fleBlobSubType) + << " of encrypted binary data (0, 1 and 2 are allowed)"); + } + } + + std::unique_ptr shallowClone() const final { + auto expr = + stdx::make_unique(path(), _encryptedType); + if (getTag()) { + expr->setTag(getTag()->clone()); + } + return std::move(expr); + } + + void debugString(StringBuilder& debug, int level) const final { + _debugAddSpace(debug, level); + debug << path() << " " << name() << ": " << typeName(_encryptedType); + + if (auto td = getTag()) { + debug << " "; + td->debugString(&debug); + } + debug << "\n"; + } + + BSONObj getSerializedRightHandSide() const final { + BSONObjBuilder bob; + bob.append(name(), _encryptedType); + return bob.obj(); + } + + bool equivalent(const MatchExpression* other) const final { + if (matchType() != other->matchType()) + return false; + + auto realOther = static_cast(other); + + if (path() != realOther->path()) { + return false; + } + + return _encryptedType == realOther->_encryptedType; + } + +private: + ExpressionOptimizerFunc getOptimizer() const final { + return [](std::unique_ptr expression) { return expression; }; + } + + BSONType _encryptedType; +}; } // namespace mongo diff --git a/src/mongo/db/matcher/schema/json_schema_parser.cpp b/src/mongo/db/matcher/schema/json_schema_parser.cpp index 14e861be176..2b35d8e34b5 100644 --- a/src/mongo/db/matcher/schema/json_schema_parser.cpp +++ b/src/mongo/db/matcher/schema/json_schema_parser.cpp @@ -1275,32 +1275,6 @@ Status translateScalarKeywords(StringMap& keywordMap, return Status::OK(); } -/** - * Parses the parameters to the 'encrypt' keyword. Returns an OK status if these parameters - * are valid, and a non-OK status otherwise." - */ -Status verifyEncryptOptions(BSONObj encryptObj) { - const IDLParserErrorContext encryptCtxt("encrypt"); - - // This checks the types of all the fields. Will throw on any parsing error. - EncryptionInfo encryptInfo; - try { - encryptInfo = EncryptionInfo::parse(encryptCtxt, encryptObj); - } catch (...) { - return exceptionToStatus(); - } - auto typePointer = encryptInfo.getBsonType(); - if (typePointer) { - auto it = kTypeAliasMap.find(typePointer.get()); - if (it == kTypeAliasMap.end()) { - return {ErrorCodes::FailedToParse, - "Invalid BSON type found in encrypt object: " + typePointer.get()}; - } - } - - return Status::OK(); -} - /** * Parses JSON Schema encrypt keyword in 'keywordMap' and adds it to 'andExpr'. Returns a * non-OK status if an error occurs during parsing. @@ -1350,12 +1324,19 @@ Status translateEncryptionKeywords(StringMap& keywordMap, << "' must be an object "}; } - auto encryptStatus = verifyEncryptOptions(encryptElt.embeddedObject()); - if (!encryptStatus.isOK()) { - return encryptStatus; - } + try { + // This checks the types of all the fields. Will throw on any parsing error. + const IDLParserErrorContext encryptCtxt("encrypt"); + auto encryptInfo = EncryptionInfo::parse(encryptCtxt, encryptElt.embeddedObject()); - andExpr->add(new InternalSchemaBinDataSubTypeExpression(path, BinDataType::Encrypt)); + andExpr->add(new InternalSchemaBinDataSubTypeExpression(path, BinDataType::Encrypt)); + + if (auto typeOptional = encryptInfo.getBsonType()) + andExpr->add(new InternalSchemaBinDataEncryptedTypeExpression( + path, typeFromName(typeOptional.get()))); + } catch (const AssertionException&) { + return exceptionToStatus(); + } } return Status::OK(); diff --git a/src/mongo/db/matcher/schema/json_schema_parser_test.cpp b/src/mongo/db/matcher/schema/json_schema_parser_test.cpp index 0040d28db38..6483b6f195e 100644 --- a/src/mongo/db/matcher/schema/json_schema_parser_test.cpp +++ b/src/mongo/db/matcher/schema/json_schema_parser_test.cpp @@ -1871,6 +1871,23 @@ TEST(JSONSchemaParserTest, EncryptTranslatesCorrectly) { })")); } +TEST(JSONSchemaParserTest, EncryptWithBsonTypeTranslatesCorrectly) { + BSONObj schema = fromjson("{properties: {foo: {encrypt: {bsonType: \"string\"}}}}"); + auto result = JSONSchemaParser::parse(schema); + ASSERT_OK(result.getStatus()); + auto optimizedResult = MatchExpression::optimize(std::move(result.getValue())); + ASSERT_SERIALIZES_TO(optimizedResult, fromjson(R"( + { + $or: + [{foo: {$not: {$exists: true}}}, { + $and: + [ {foo: {$_internalSchemaBinDataSubType: 6}}, + {foo: {$_internalSchemaBinDataEncryptedType: 2}}, + {foo: {$_internalSchemaType: [5]}}] + }] + })")); +} + TEST(JSONSchemaParserTest, TopLevelEncryptTranslatesCorrectly) { BSONObj schema = fromjson("{encrypt: {}}"); auto result = JSONSchemaParser::parse(schema); @@ -2004,7 +2021,7 @@ TEST(JSONSchemaParserTest, FailsToParseWithBadBSONType) { auto schema = BSON("properties" << BSON("foo" << BSON("encrypt" << BSON("bsonType" << "Stringx")))); auto result = JSONSchemaParser::parse(schema); - ASSERT_EQ(result.getStatus().code(), ErrorCodes::FailedToParse); + ASSERT_EQ(result.getStatus().code(), ErrorCodes::BadValue); schema = BSON("properties" << BSON("foo" << BSON("encrypt" << BSON("bsonType" << 1)))); result = JSONSchemaParser::parse(schema); diff --git a/src/mongo/db/pipeline/document_source_match.cpp b/src/mongo/db/pipeline/document_source_match.cpp index 11aa84c71a4..7cb3bcec620 100644 --- a/src/mongo/db/pipeline/document_source_match.cpp +++ b/src/mongo/db/pipeline/document_source_match.cpp @@ -271,6 +271,7 @@ Document redactSafePortionDollarOps(BSONObj expr) { case PathAcceptingKeyword::GEO_NEAR: case PathAcceptingKeyword::INTERNAL_EXPR_EQ: case PathAcceptingKeyword::INTERNAL_SCHEMA_ALL_ELEM_MATCH_FROM_INDEX: + case PathAcceptingKeyword::INTERNAL_SCHEMA_BIN_DATA_ENCRYPTED_TYPE: case PathAcceptingKeyword::INTERNAL_SCHEMA_BIN_DATA_SUBTYPE: case PathAcceptingKeyword::INTERNAL_SCHEMA_EQ: case PathAcceptingKeyword::INTERNAL_SCHEMA_FMOD: diff --git a/src/mongo/db/query/canonical_query_encoder.cpp b/src/mongo/db/query/canonical_query_encoder.cpp index 27f8bc24590..91982bff80a 100644 --- a/src/mongo/db/query/canonical_query_encoder.cpp +++ b/src/mongo/db/query/canonical_query_encoder.cpp @@ -174,6 +174,9 @@ const char* encodeMatchType(MatchExpression::MatchType mt) { case MatchExpression::INTERNAL_SCHEMA_ALLOWED_PROPERTIES: return "internalSchemaAllowedProperties"; + case MatchExpression::INTERNAL_SCHEMA_BIN_DATA_ENCRYPTED_TYPE: + return "internalSchemaBinDataEncryptedType"; + case MatchExpression::INTERNAL_SCHEMA_BIN_DATA_SUBTYPE: return "internalSchemaBinDataSubType"; -- cgit v1.2.1