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
Original file line number Diff line number Diff line change
Expand Up @@ -93,6 +93,7 @@ async def encrypt(
contention_factor=None,
range_opts=None,
is_expression=False,
text_opts=None,
):
"""Encrypts a BSON value.

Expand All @@ -114,6 +115,8 @@ async def encrypt(
with the "range" algorithm encoded as a BSON document.
- `is_expression` (boolean): True if this is an encryptExpression()
context. Defaults to False.
- `text_opts` (bytes): Options for explicit encryption
with the "textPreview" algorithm encoded as a BSON document.

:Returns:
The encrypted BSON value.
Expand All @@ -122,6 +125,8 @@ async def encrypt(
Added the `query_type` and `contention_factor` parameters.
.. versionchanged:: 1.5
Added the `range_opts` and `is_expression` parameters.
.. versionchanged:: 1.16
Added the `text_opts` parameter.
"""
# CDRIVER-3275 key_alt_name needs to be wrapped in a bson document.
if key_alt_name is not None:
Expand All @@ -134,6 +139,7 @@ async def encrypt(
contention_factor,
range_opts,
is_expression,
text_opts,
)
with self.mongocrypt.explicit_encryption_context(value, opts) as ctx:
return await run_state_machine(ctx, self.callback)
Expand Down
5 changes: 5 additions & 0 deletions bindings/python/pymongocrypt/mongocrypt.py
Original file line number Diff line number Diff line change
Expand Up @@ -501,6 +501,11 @@ def __init__(self, ctx, kms_providers, value, opts):
):
self._raise_from_status()

if opts.text_opts is not None:
with MongoCryptBinaryIn(opts.text_opts) as text_opts:
if not lib.mongocrypt_ctx_setopt_algorithm_text(ctx, text_opts.bin):
self._raise_from_status()

with MongoCryptBinaryIn(value) as binary:
if opts.is_expression:
if not lib.mongocrypt_ctx_explicit_encrypt_expression_init(
Expand Down
10 changes: 10 additions & 0 deletions bindings/python/pymongocrypt/options.py
Original file line number Diff line number Diff line change
Expand Up @@ -170,6 +170,7 @@ def __init__(
contention_factor=None,
range_opts=None,
is_expression=False,
text_opts=None,
):
"""Options for explicit encryption.

Expand All @@ -186,11 +187,15 @@ def __init__(
with the "range" algorithm encoded as a BSON document.
- `is_expression` (boolean): True if this is an encryptExpression()
context. Defaults to False.
- `text_opts` (bytes): Options for explicit encryption
with the "textPreview" algorithm encoded as a BSON document.

.. versionchanged:: 1.3
Added the `query_type` and `contention_factor` parameters.
.. versionchanged:: 1.5
Added the `range_opts` and `is_expression` parameters.
.. versionchanged:: 1.16
Added the `text_opts` parameter.
"""
self.algorithm = algorithm
self.key_id = key_id
Expand All @@ -212,6 +217,11 @@ def __init__(
)
self.range_opts = range_opts
self.is_expression = is_expression
if text_opts is not None and not isinstance(text_opts, bytes):
raise TypeError(
f"text_opts must be an bytes or None, not: {type(text_opts)}"
)
self.text_opts = text_opts


class DataKeyOpts:
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -93,6 +93,7 @@ def encrypt(
contention_factor=None,
range_opts=None,
is_expression=False,
text_opts=None,
):
"""Encrypts a BSON value.

Expand All @@ -114,6 +115,8 @@ def encrypt(
with the "range" algorithm encoded as a BSON document.
- `is_expression` (boolean): True if this is an encryptExpression()
context. Defaults to False.
- `text_opts` (bytes): Options for explicit encryption
with the "textPreview" algorithm encoded as a BSON document.

:Returns:
The encrypted BSON value.
Expand All @@ -122,6 +125,8 @@ def encrypt(
Added the `query_type` and `contention_factor` parameters.
.. versionchanged:: 1.5
Added the `range_opts` and `is_expression` parameters.
.. versionchanged:: 1.16
Added the `text_opts` parameter.
"""
# CDRIVER-3275 key_alt_name needs to be wrapped in a bson document.
if key_alt_name is not None:
Expand All @@ -134,6 +139,7 @@ def encrypt(
contention_factor,
range_opts,
is_expression,
text_opts,
)
with self.mongocrypt.explicit_encryption_context(value, opts) as ctx:
return run_state_machine(ctx, self.callback)
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
{
"v": {
"$binary": "EqQAAAADdHMAhQAAAANlAH0AAAAFZAAgAAAAACmNEIGYF35VPFzmyWuvaCXPAVtXyzAMQ3fdWSFJ3Ji9BXMAIAAAAAA3qH8Y7MnTiDaHYF8L84k4YsWj2IP25sY5lBUo5s2aOgVsACAAAAAAVdUcnSWSe5b9XPo4L/3LELFwsT0PwiNBPYNs3UIhEWQAABJjbQAAAAAAAAAAAAhjZgABCGRmAAEA",
"$type": "06"
}
}
8 changes: 8 additions & 0 deletions bindings/python/test/data/fle2-text-search/textopts.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
{
"caseSensitive": true,
"diacriticSensitive": true,
"prefix": {
"strMaxQueryLength": 10,
"strMinQueryLength": 2
}
}
49 changes: 49 additions & 0 deletions bindings/python/test/test_mongocrypt.py
Original file line number Diff line number Diff line change
Expand Up @@ -38,6 +38,7 @@
import unittest.mock

import respx
from pymongo import MongoClient
from pymongo_auth_aws.auth import AwsCredential

from pymongocrypt.asynchronous.auto_encrypter import AsyncAutoEncrypter
Expand Down Expand Up @@ -1013,6 +1014,30 @@ async def test_range_query_int32(self):
encrypted_val, adjust_range_counter(encrypted_val, expected)
)

async def test_text_query(self):
key_path = "keys/ABCDEFAB123498761234123456789012-local-document.json"
key_id = json_data(key_path)["_id"]
encrypter = AsyncExplicitEncrypter(
MockAsyncCallback(
key_docs=[bson_data(key_path)], kms_reply=http_data("kms-reply.txt")
),
self.mongo_crypt_opts(),
)
self.addCleanup(encrypter.close)

text_opts = bson_data("fle2-text-search/textopts.json")
expected = bson_data("fle2-text-search/encrypted-payload.json")
value = bson.encode({"v": "foo"})
encrypted = await encrypter.encrypt(
value,
"textPreview",
key_id=key_id,
query_type="suffixPreview",
contention_factor=0,
text_opts=text_opts,
)
self.assertEqual(encrypted, expected)


class TestNeedKMSAzureCredentials(unittest.TestCase):
maxDiff = None
Expand Down Expand Up @@ -1459,6 +1484,30 @@ def test_rangePreview_query_int32(self):
is_expression=True,
)

def test_text_query(self):
key_path = "keys/ABCDEFAB123498761234123456789012-local-document.json"
key_id = json_data(key_path)["_id"]
encrypter = ExplicitEncrypter(
MockCallback(
key_docs=[bson_data(key_path)], kms_reply=http_data("kms-reply.txt")
),
self.mongo_crypt_opts(),
)
self.addCleanup(encrypter.close)

text_opts = bson_data("fle2-text-search/textopts.json")
expected = bson_data("fle2-text-search/encrypted-payload.json")
value = bson.encode({"v": "foo"})
encrypted = encrypter.encrypt(
value,
"textPreview",
key_id=key_id,
query_type="suffixPreview",
contention_factor=0,
text_opts=text_opts,
)
self.assertEqual(encrypted, expected)


def read(filename, **kwargs):
with open(os.path.join(DATA_DIR, filename), **kwargs) as fp:
Expand Down
Loading