25
25
TYPE_CHECKING ,
26
26
Any ,
27
27
Dict ,
28
+ Generator ,
28
29
Generic ,
29
30
Iterator ,
30
31
Mapping ,
36
37
)
37
38
38
39
try :
39
- from pymongocrypt .auto_encrypter import AutoEncrypter # type:ignore[import]
40
40
from pymongocrypt .errors import MongoCryptError # type:ignore[import]
41
- from pymongocrypt .explicit_encrypter import ExplicitEncrypter # type:ignore[import]
42
41
from pymongocrypt .mongocrypt import MongoCryptOptions # type:ignore[import]
43
- from pymongocrypt .state_machine import MongoCryptCallback # type:ignore[import]
42
+ from pymongocrypt .synchronous .auto_encrypter import AutoEncrypter # type:ignore[import]
43
+ from pymongocrypt .synchronous .explicit_encrypter import ( # type:ignore[import]
44
+ ExplicitEncrypter ,
45
+ )
46
+ from pymongocrypt .synchronous .state_machine import ( # type:ignore[import]
47
+ MongoCryptCallback ,
48
+ )
44
49
45
50
_HAVE_PYMONGOCRYPT = True
46
51
except ImportError :
53
58
from bson .errors import BSONError
54
59
from bson .raw_bson import DEFAULT_RAW_BSON_OPTIONS , RawBSONDocument , _inflate_bson
55
60
from pymongo import _csot
56
- from pymongo .collection import Collection
57
61
from pymongo .common import CONNECT_TIMEOUT
58
- from pymongo .cursor import Cursor
59
62
from pymongo .daemon import _spawn_daemon
60
- from pymongo .database import Database
61
63
from pymongo .encryption_options import AutoEncryptionOpts , RangeOpts
62
64
from pymongo .errors import (
63
65
ConfigurationError ,
67
69
PyMongoError ,
68
70
ServerSelectionTimeoutError ,
69
71
)
70
- from pymongo .mongo_client import MongoClient
71
- from pymongo .network import BLOCKING_IO_ERRORS
72
+ from pymongo .network_layer import BLOCKING_IO_ERRORS , sendall
72
73
from pymongo .operations import UpdateOne
73
- from pymongo .pool import PoolOptions , _configured_socket , _raise_connection_failure
74
+ from pymongo .pool_options import PoolOptions
74
75
from pymongo .read_concern import ReadConcern
75
76
from pymongo .results import BulkWriteResult , DeleteResult
76
77
from pymongo .ssl_support import get_ssl_context
78
+ from pymongo .synchronous .collection import Collection
79
+ from pymongo .synchronous .cursor import Cursor
80
+ from pymongo .synchronous .database import Database
81
+ from pymongo .synchronous .mongo_client import MongoClient
82
+ from pymongo .synchronous .pool import _configured_socket , _raise_connection_failure
77
83
from pymongo .typings import _DocumentType , _DocumentTypeArg
78
84
from pymongo .uri_parser import parse_host
79
85
from pymongo .write_concern import WriteConcern
80
86
81
87
if TYPE_CHECKING :
82
88
from pymongocrypt .mongocrypt import MongoCryptKmsContext
83
89
90
+
91
+ _IS_SYNC = True
92
+
84
93
_HTTPS_PORT = 443
85
94
_KMS_CONNECT_TIMEOUT = CONNECT_TIMEOUT # CDRIVER-3262 redefined this value to CONNECT_TIMEOUT
86
95
_MONGOCRYPTD_TIMEOUT_MS = 10000
@@ -167,7 +176,7 @@ def kms_request(self, kms_context: MongoCryptKmsContext) -> None:
167
176
try :
168
177
conn = _configured_socket ((host , port ), opts )
169
178
try :
170
- conn . sendall (message )
179
+ sendall (conn , message )
171
180
while kms_context .bytes_needed > 0 :
172
181
# CSOT: update timeout.
173
182
conn .settimeout (max (_csot .clamp_remaining (_KMS_CONNECT_TIMEOUT ), 0 ))
@@ -185,9 +194,7 @@ def kms_request(self, kms_context: MongoCryptKmsContext) -> None:
185
194
# Wrap I/O errors in PyMongo exceptions.
186
195
_raise_connection_failure ((host , port ), error )
187
196
188
- def collection_info (
189
- self , database : Database [Mapping [str , Any ]], filter : bytes
190
- ) -> Optional [bytes ]:
197
+ def collection_info (self , database : str , filter : bytes ) -> Optional [bytes ]:
191
198
"""Get the collection info for a namespace.
192
199
193
200
The returned collection info is passed to libmongocrypt which reads
@@ -241,7 +248,7 @@ def mark_command(self, database: str, cmd: bytes) -> bytes:
241
248
)
242
249
return res .raw
243
250
244
- def fetch_keys (self , filter : bytes ) -> Iterator [bytes ]:
251
+ def fetch_keys (self , filter : bytes ) -> Generator [bytes , None ]:
245
252
"""Yields one or more keys from the key vault.
246
253
247
254
:param filter: The filter to pass to find.
@@ -371,13 +378,16 @@ def _get_internal_client(
371
378
)
372
379
373
380
io_callbacks = _EncryptionIO ( # type:ignore[misc]
374
- metadata_client , key_vault_coll , mongocryptd_client , opts
381
+ metadata_client ,
382
+ key_vault_coll , # type:ignore[arg-type]
383
+ mongocryptd_client ,
384
+ opts ,
375
385
)
376
386
self ._auto_encrypter = AutoEncrypter (
377
387
io_callbacks ,
378
- MongoCryptOptions (
379
- opts ._kms_providers ,
380
- schema_map ,
388
+ _create_mongocrypt_options (
389
+ kms_providers = opts ._kms_providers ,
390
+ schema_map = schema_map ,
381
391
crypt_shared_lib_path = opts ._crypt_shared_lib_path ,
382
392
crypt_shared_lib_required = opts ._crypt_shared_lib_required ,
383
393
bypass_encryption = opts ._bypass_auto_encryption ,
@@ -446,11 +456,15 @@ class Algorithm(str, enum.Enum):
446
456
447
457
.. versionadded:: 4.2
448
458
"""
459
+ RANGE = "Range"
460
+ """Range.
461
+
462
+ .. versionadded:: 4.9
463
+ """
449
464
RANGEPREVIEW = "RangePreview"
450
- """RangePreview.
465
+ """**DEPRECATED** - RangePreview.
451
466
452
- .. note:: Support for Range queries is in beta.
453
- Backwards-breaking changes may be made before the final release.
467
+ .. note:: Support for RangePreview is deprecated. Use :attr:`Algorithm.RANGE` instead.
454
468
455
469
.. versionadded:: 4.4
456
470
"""
@@ -465,12 +479,27 @@ class QueryType(str, enum.Enum):
465
479
EQUALITY = "equality"
466
480
"""Used to encrypt a value for an equality query."""
467
481
468
- RANGEPREVIEW = "rangePreview "
482
+ RANGE = "range "
469
483
"""Used to encrypt a value for a range query.
470
484
471
- .. note:: Support for Range queries is in beta.
472
- Backwards-breaking changes may be made before the final release.
473
- """
485
+ .. versionadded:: 4.9
486
+ """
487
+
488
+ RANGEPREVIEW = "RangePreview"
489
+ """**DEPRECATED** - Used to encrypt a value for a rangePreview query.
490
+
491
+ .. note:: Support for RangePreview is deprecated. Use :attr:`QueryType.RANGE` instead.
492
+
493
+ .. versionadded:: 4.4
494
+ """
495
+
496
+
497
+ def _create_mongocrypt_options (** kwargs : Any ) -> MongoCryptOptions :
498
+ opts = MongoCryptOptions (** kwargs )
499
+ # Opt into range V2 encryption.
500
+ if hasattr (opts , "enable_range_v2" ):
501
+ opts .enable_range_v2 = True
502
+ return opts
474
503
475
504
476
505
class ClientEncryption (Generic [_DocumentType ]):
@@ -559,12 +588,15 @@ def __init__(
559
588
raise ConfigurationError (
560
589
"client-side field level encryption requires the pymongocrypt "
561
590
"library: install a compatible version with: "
562
- "python -m pip install 'pymongo[encryption]'"
591
+ "python -m pip install --upgrade 'pymongo[encryption]'"
563
592
)
564
593
565
594
if not isinstance (codec_options , CodecOptions ):
566
595
raise TypeError ("codec_options must be an instance of bson.codec_options.CodecOptions" )
567
596
597
+ if not isinstance (key_vault_client , MongoClient ):
598
+ raise TypeError (f"MongoClient required but given { type (key_vault_client )} " )
599
+
568
600
self ._kms_providers = kms_providers
569
601
self ._key_vault_namespace = key_vault_namespace
570
602
self ._key_vault_client = key_vault_client
@@ -580,7 +612,8 @@ def __init__(
580
612
None , key_vault_coll , None , opts
581
613
)
582
614
self ._encryption = ExplicitEncrypter (
583
- self ._io_callbacks , MongoCryptOptions (kms_providers , None )
615
+ self ._io_callbacks ,
616
+ _create_mongocrypt_options (kms_providers = kms_providers , schema_map = None ),
584
617
)
585
618
# Use the same key vault collection as the callback.
586
619
assert self ._io_callbacks .key_vault_coll is not None
@@ -649,6 +682,11 @@ def create_encrypted_collection(
649
682
https://mongodb.com/docs/manual/reference/command/create
650
683
651
684
"""
685
+ if not isinstance (database , Database ):
686
+ raise TypeError (
687
+ f"create_encrypted_collection() requires a Database but { type (database )} given"
688
+ )
689
+
652
690
encrypted_fields = deepcopy (encrypted_fields )
653
691
for i , field in enumerate (encrypted_fields ["fields" ]):
654
692
if isinstance (field , dict ) and field .get ("keyId" ) is None :
@@ -724,6 +762,9 @@ def create_data_key(
724
762
Secret Data managed object.
725
763
- `endpoint` (string): Optional. Host with optional
726
764
port, e.g. "example.vault.azure.net:".
765
+ - `delegated` (bool): Optional. If True (recommended), the
766
+ KMIP server will perform encryption and decryption. If
767
+ delegated is not provided, defaults to false.
727
768
728
769
:param key_alt_names: An optional list of string alternate
729
770
names used to reference a key. If a key is created with alternate
@@ -826,10 +867,14 @@ def encrypt(
826
867
when the algorithm is :attr:`Algorithm.INDEXED`. An integer value
827
868
*must* be given when the :attr:`Algorithm.INDEXED` algorithm is
828
869
used.
829
- :param range_opts: Experimental only, not intended for public use.
870
+ :param range_opts: Index options for `range` queries. See
871
+ :class:`RangeOpts` for some valid options.
830
872
831
873
:return: The encrypted value, a :class:`~bson.binary.Binary` with subtype 6.
832
874
875
+ .. versionchanged:: 4.9
876
+ Added the `range_opts` parameter.
877
+
833
878
.. versionchanged:: 4.7
834
879
``key_id`` can now be passed in as a :class:`uuid.UUID`.
835
880
@@ -878,10 +923,14 @@ def encrypt_expression(
878
923
when the algorithm is :attr:`Algorithm.INDEXED`. An integer value
879
924
*must* be given when the :attr:`Algorithm.INDEXED` algorithm is
880
925
used.
881
- :param range_opts: Experimental only, not intended for public use.
926
+ :param range_opts: Index options for `range` queries. See
927
+ :class:`RangeOpts` for some valid options.
882
928
883
929
:return: The encrypted expression, a :class:`~bson.RawBSONDocument`.
884
930
931
+ .. versionchanged:: 4.9
932
+ Added the `range_opts` parameter.
933
+
885
934
.. versionchanged:: 4.7
886
935
``key_id`` can now be passed in as a :class:`uuid.UUID`.
887
936
@@ -963,10 +1012,10 @@ def delete_key(self, id: Binary) -> DeleteResult:
963
1012
def add_key_alt_name (self , id : Binary , key_alt_name : str ) -> Any :
964
1013
"""Add ``key_alt_name`` to the set of alternate names in the key document with UUID ``key_id``.
965
1014
966
- :param `id` : The UUID of a key a which must be a
1015
+ :param id : The UUID of a key a which must be a
967
1016
:class:`~bson.binary.Binary` with subtype 4 (
968
1017
:attr:`~bson.binary.UUID_SUBTYPE`).
969
- :param ` key_alt_name` : The key alternate name to add.
1018
+ :param key_alt_name: The key alternate name to add.
970
1019
971
1020
:return: The previous version of the key document.
972
1021
@@ -995,10 +1044,10 @@ def remove_key_alt_name(self, id: Binary, key_alt_name: str) -> Optional[RawBSON
995
1044
996
1045
Also removes the ``keyAltNames`` field from the key document if it would otherwise be empty.
997
1046
998
- :param `id` : The UUID of a key a which must be a
1047
+ :param id : The UUID of a key a which must be a
999
1048
:class:`~bson.binary.Binary` with subtype 4 (
1000
1049
:attr:`~bson.binary.UUID_SUBTYPE`).
1001
- :param ` key_alt_name` : The key alternate name to remove.
1050
+ :param key_alt_name: The key alternate name to remove.
1002
1051
1003
1052
:return: Returns the previous version of the key document.
1004
1053
@@ -1037,7 +1086,7 @@ def rewrap_many_data_key(
1037
1086
:param filter: A document used to filter the data keys.
1038
1087
:param provider: The new KMS provider to use to encrypt the data keys,
1039
1088
or ``None`` to use the current KMS provider(s).
1040
- :param ` master_key` : The master key fields corresponding to the new KMS
1089
+ :param master_key: The master key fields corresponding to the new KMS
1041
1090
provider when ``provider`` is not ``None``.
1042
1091
1043
1092
:return: A :class:`RewrapManyDataKeyResult`.
0 commit comments