o
    'hZ                     @  s>  U d Z ddlmZ ddlZddlZddlZddlZddlZddlZddl	m
Z
 ddlmZmZmZmZmZmZmZmZmZmZmZmZ z"ddlmZ ddlmZ ddlmZ dd	lmZ dd
l m!Z! dZ"W n e#yr   dZ"e$Z!Y nw ddl%m&Z&m'Z'm(Z( ddl)m*Z*m+Z+m,Z, ddl-m.Z. ddl/m0Z0 ddl1m2Z2m3Z3m4Z4 ddl5m6Z6 ddl7m8Z8 ddl9m:Z: ddl;m<Z<m=Z= ddl>m?Z?m@Z@mAZAmBZBmCZCmDZD ddlEmFZF ddlGmHZH ddlImJZJ ddlKmLZLmMZMmNZN ddlOmPZP ddlQmRZRmSZS ddlTmUZUmVZV ddlWmXZX ddlYmZZZ dd l[m\Z\ dd!l]m^Z^ dd"l_m`Z`maZa dd#lbmcZcmdZd dd$lemfZf er<dd%lmgZg dd&lhmiZi dd'l_mjZj dZkd(Zle8Zmd)Zne.eeoef e*d*Zpd+eqd,< e.e3d-ZrdJd4d5ZsejtdKd7d8ZuG d9d: d:e!ZvG d;d< d<ZwG d=d> d>ZxG d?d@ d@eoejyZzG dAdB dBeoejyZ{dLdFdGZ|G dHdI dIee` Z}dS )Mz8Support for explicit client-side field level encryption.    )annotationsN)deepcopy)TYPE_CHECKINGAnyDict	GeneratorGenericIteratorMappingMutableMappingOptionalSequenceUnioncast)MongoCryptError)MongoCryptOptions)AutoEncrypter)ExplicitEncrypter)MongoCryptCallbackTF)_dict_to_bsondecodeencode)STANDARDUUID_SUBTYPEBinary)CodecOptions)	BSONError)DEFAULT_RAW_BSON_OPTIONSRawBSONDocument_inflate_bson)_csot)CONNECT_TIMEOUT)_spawn_daemon)AutoEncryptionOpts	RangeOpts)ConfigurationErrorEncryptedCollectionErrorEncryptionErrorInvalidOperationNetworkTimeoutServerSelectionTimeoutError)sendall)	UpdateOne)PoolOptions)_configured_socket_get_timeout_details_raise_connection_failure)ReadConcern)BulkWriteResultDeleteResult)BLOCKING_IO_ERRORSget_ssl_context)
Collection)Cursor)Database)MongoClient)_DocumentType_DocumentTypeArg)_parse_kms_tls_options
parse_host)WriteConcern)MongoCryptKmsContext)_sslConn)_Addressi  i'  )document_classuuid_representationzCodecOptions[dict[str, Any]]_DATA_KEY_OPTS)rB   addressrA   optsr-   returnUnion[socket.socket, _sslConn]c              
   C  sF   zt | |W S  ty" } zt| |t|d W Y d }~d S d }~ww )N)timeout_details)r.   	Exceptionr0   r/   )rE   rF   exc rL   Z/var/www/html/olx_land/venv/lib/python3.10/site-packages/pymongo/synchronous/encryption.py_connect_kmsq   s    rN   Iterator[None]c               
   c  s@    zdV  W dS  t y     ty }  zt| | d} ~ ww )z2Context manager to wrap encryption related errors.N)r   rJ   r'   )rK   rL   rL   rM   _wrap_encryption_errorsx   s   
rP   c                   @  sf   e Zd Zd*dd	Zd+ddZd,ddZd-ddZd.ddZd/ddZd0d!d"Z	d1d%d&Z
d-d'd(Zd)S )2_EncryptionIOclient'Optional[MongoClient[_DocumentTypeArg]]key_vault_collCollection[_DocumentTypeArg]mongocryptd_clientrF   r#   c                 C  sj   |  |durt || _nd| _ttt |jttddt	ddd| _
|| _|| _d| _|t| _dS )z8Internal class to perform I/O on behalf of pymongocrypt.Nmajority)level)w)codec_optionsread_concernwrite_concernF)weakrefref
client_refr   r6   r   with_options_KEY_VAULT_OPTSr1   r>   rT   rV   rF   _spawned_kms_ssl_contexts_IS_SYNC)selfrR   rT   rV   rF   rL   rL   rM   __init__   s    z_EncryptionIO.__init__kms_contextr?   rG   Nonec                 C  sB  |j }|j}|j}| j|}|du rtdddddddt}tt	t
d}t|||d}t|t}|j}	|	rBt|	d }
t|
 zt||}zz<t|| |jdkr|tt	t
d trh||j}nddlm} |||j}|sztd|| |jdksTW n7 ty     ty } z$t|trt d	}t|trd}nd}t!|||t"|d
 W Y d}~nd}~ww W |#  W dS W |#  W dS |#  w  ty     ty  } z;t$ }t|t%s|dur|dkr z|&  W n ty } zt| d| |j'}||d}~ww W Y d}~dS d}~ww )zuComplete a KMS request.

        :param kms_context: A :class:`MongoCryptKmsContext`.

        :return: None
        NFgMbP?)connect_timeoutsocket_timeoutssl_contextg    .Ar   )receive_data_socketzKMS connection closedz	timed out)
msg_prefixrI   z, last attempt failed with: )(endpointmessagekms_providerrc   getr5   rd   maxr    clamp_remaining_KMS_CONNECT_TIMEOUTr-   r=   _HTTPS_PORTusleepfloattimesleeprN   r+   bytes_needed
settimeoutrecvpymongo.network_layerrl   OSErrorfeedr   rJ   
isinstancer4   sockettimeoutr0   r/   close	remainingr)   failcode)re   rg   rn   ro   providerctxri   rF   rE   sleep_u	sleep_secconndatarl   rK   rm   r   	final_errrL   rL   rM   kms_request   s   









z_EncryptionIO.kms_requestdatabasestrfilterbytesOptional[list[bytes]]c                 C  sJ   |   | jt|d}dd |D W  d   S 1 sw   Y  dS )ap  Get the collection info for a namespace.

        The returned collection info is passed to libmongocrypt which reads
        the JSON schema.

        :param database: The database on which to run listCollections.
        :param filter: The filter to pass to listCollections.

        :return: All documents from the listCollections command response as BSON.
        )r   c                 S  s   g | ]}t |d tqS )F)r   rD   ).0docrL   rL   rM   
<listcomp>  s    z1_EncryptionIO.collection_info.<locals>.<listcomp>N)r_   list_collectionsr   )re   r   r   cursorrL   rL   rM   collection_info   s   $z_EncryptionIO.collection_infoc                 C  s.   d| _ | jjpdg}|| jj t| dS )z~Spawn mongocryptd.

        Note this method is thread safe; at most one mongocryptd will start
        successfully.
        TmongocryptdN)rb   rF   _mongocryptd_spawn_pathextend_mongocryptd_spawn_argsr"   )re   argsrL   rL   rM   spawn  s   z_EncryptionIO.spawncmdc                 C  s   | j s| jjs|   t|t}| jdusJ z| j| j|td}W |j	S  tyC   | jjr1 |   | j| j|td}Y |j	S w )zMark a command for encryption.

        :param database: The database on which to run this command.
        :param cmd: The BSON command to run.

        :return: The marked command response from mongocryptd.
        NrZ   )
rb   rF   _mongocryptd_bypass_spawnr   r   r   rV   commandr*   raw)re   r   r   inflated_cmdresrL   rL   rM   mark_command  s$   



z_EncryptionIO.mark_commandGenerator[bytes, None]c                 c  sX    | j dusJ | j t|}|D ]}|jV  qW d   dS 1 s%w   Y  dS )zYields one or more keys from the key vault.

        :param filter: The filter to pass to find.

        :return: A generator which yields the requested keys from the key vault.
        N)rT   findr   r   )re   r   r   keyrL   rL   rM   
fetch_keys*  s   
"z_EncryptionIO.fetch_keysdata_keyr   c                 C  sX   t |t}|d}t|tr|jtkrtdt| | j	dus$J | j	
| |S )zInsert a data key into the key vault.

        :param data_key: The data key document to insert.

        :return: The _id of the inserted data key document.
        _idz5data_key _id must be Binary with a UUID subtype, not N)r   ra   rq   r   r   subtyper   	TypeErrortyperT   
insert_one)re   r   raw_docdata_key_idrL   rL   rM   insert_data_key6  s   

z_EncryptionIO.insert_data_keyr   MutableMapping[str, Any]c                 C  s   t |S )zEncode a document to BSON.

        A document can be any mapping type (like :class:`dict`).

        :param doc: mapping type representing a document

        :return: The encoded BSON bytes.
        )r   )re   r   rL   rL   rM   bson_encodeH  s   	z_EncryptionIO.bson_encodec                 C  s*   d| _ d| _| jr| j  d| _dS dS )zjRelease resources.

        Note it is not safe to call this method from __del__ or any GC hooks.
        N)r_   rT   rV   r   re   rL   rL   rM   r   S  s   

z_EncryptionIO.closeN)rR   rS   rT   rU   rV   rS   rF   r#   )rg   r?   rG   rh   )r   r   r   r   rG   r   rG   rh   )r   r   r   r   rG   r   )r   r   rG   r   )r   r   rG   r   )r   r   rG   r   )__name__
__module____qualname__rf   r   r   r   r   r   r   r   r   rL   rL   rL   rM   rQ      s    


U




rQ   c                   @  s4   e Zd ZdZddddZedd	d
ZdddZdS )RewrapManyDataKeyResultzuResult object returned by a :meth:`~ClientEncryption.rewrap_many_data_key` operation.

    .. versionadded:: 4.2
    Nbulk_write_resultOptional[BulkWriteResult]rG   rh   c                 C  s
   || _ d S N_bulk_write_result)re   r   rL   rL   rM   rf   e  s   
z RewrapManyDataKeyResult.__init__c                 C  s   | j S )aD  The result of the bulk write operation used to update the key vault
        collection with one or more rewrapped data keys. If
        :meth:`~ClientEncryption.rewrap_many_data_key` does not find any matching keys to rewrap,
        no bulk write operation will be executed and this field will be
        ``None``.
        r   r   rL   rL   rM   r   h  s   z)RewrapManyDataKeyResult.bulk_write_resultr   c                 C  s   | j j d| jdS )N())	__class__r   r   r   rL   rL   rM   __repr__r  s   z RewrapManyDataKeyResult.__repr__r   )r   r   rG   rh   )rG   r   )rG   r   )r   r   r   __doc__rf   propertyr   r   rL   rL   rL   rM   r   _  s    	r   c                   @  sB   e Zd ZdZdddZdddZdddZd ddZd ddZdS )!
_EncrypterzEncrypts and decrypts MongoDB commands.

    This class is used to support automatic encryption and decryption of
    MongoDB commands.
    rR   MongoClient[_DocumentTypeArg]rF   r#   c                 C  s  |j du rd}nt|j dt}|jdu rd}nt|jdt}|j| _d| _|t ddd	}|jdur8|j}n|| |}|jrCd}n|| |}|j	
d
d\}}	|| |	 }
t|jdtd}t||
||}t|t|j||j|j|j||j|jd| _d| _dS )zCreate a _Encrypter for a client.

        :param client: The encrypted MongoClient.
        :param opts: The encrypted client's :class:`AutoEncryptionOpts`.
        NF	encrypterr   mongo_clientr   rG   c                 S  s:   |j jjd u r	|S | jd ur| jS |jdd d}|| _|S )Nr   )minPoolSizeauto_encryption_opts)optionspool_optionsmax_pool_size_internal_client
_duplicate)r   r   internal_clientrL   rL   rM   _get_internal_client  s   
z1_Encrypter.__init__.<locals>._get_internal_client.   )connectserverSelectionTimeoutMS)kms_providers
schema_mapcrypt_shared_lib_pathcrypt_shared_lib_requiredbypass_encryptionencrypted_fields_mapbypass_query_analysiskey_expiration_ms)r   r   r   r   rG   r   )_schema_mapr   rD   _encrypted_fields_map_bypass_auto_encryptionr   rc   rd   _key_vault_client_key_vault_namespacesplitr9   _mongocryptd_uri_MONGOCRYPTD_TIMEOUT_MSrQ   r   _create_mongocrypt_options_kms_providers_crypt_shared_lib_path_crypt_shared_lib_required_bypass_query_analysis_key_expiration_ms_auto_encrypter_closed)re   rR   rF   r   r   r   key_vault_clientmetadata_clientdbcollrT   rV   io_callbacksrL   rL   rM   rf   }  sR   







z_Encrypter.__init__r   r   r   Mapping[str, Any]rZ   CodecOptions[_DocumentTypeArg]rG   dict[str, Any]c                 C  sV   |    t|d|}t  | j||}t|tW  d   S 1 s$w   Y  dS )a  Encrypt a MongoDB command.

        :param database: The database for this command.
        :param cmd: A command document.
        :param codec_options: The CodecOptions to use while encoding `cmd`.

        :return: The encrypted command to execute.
        FN)_check_closedr   rP   r   encryptr   r   )re   r   r   rZ   encoded_cmdencrypted_cmdrL   rL   rM   r     s   $z_Encrypter.encryptresponser   Optional[bytes]c                 C  sD   |    t  tt| j|W  d   S 1 sw   Y  dS )zDecrypt a MongoDB command response.

        :param response: A MongoDB command response as BSON.

        :return: The decrypted command response.
        N)r   rP   r   r   r   decrypt)re   r   rL   rL   rM   r     s   $z_Encrypter.decryptrh   c                 C  s   | j rtdd S )Nz"Cannot use MongoClient after close)r   r(   r   rL   rL   rM   r     s   z_Encrypter._check_closedc                 C  s.   d| _ | j  | jr| j  d| _dS dS )zCleanup resources.TN)r   r   r   r   r   rL   rL   rM   r     s   


z_Encrypter.closeN)rR   r   rF   r#   )r   r   r   r   rZ   r   rG   r   )r   r   rG   r   r   )	r   r   r   r   rf   r   r   r   r   rL   rL   rL   rM   r   v  s    

G

r   c                   @  s2   e Zd ZdZdZ	 dZ	 dZ	 dZ	 dZ	 dZ	dS )		Algorithmz9An enum that defines the supported encryption algorithms.z+AEAD_AES_256_CBC_HMAC_SHA_512-Deterministicz$AEAD_AES_256_CBC_HMAC_SHA_512-RandomIndexed	UnindexedRangeRangePreviewN)
r   r   r   r   +AEAD_AES_256_CBC_HMAC_SHA_512_Deterministic$AEAD_AES_256_CBC_HMAC_SHA_512_RandomINDEXED	UNINDEXEDRANGERANGEPREVIEWrL   rL   rL   rM   r     s    r   c                   @  s    e Zd ZdZdZ	 dZ	 dZdS )	QueryTypezmAn enum that defines the supported values for explicit encryption query_type.

    .. versionadded:: 4.2
    equalityranger  N)r   r   r   r   EQUALITYr	  r
  rL   rL   rL   rM   r    s    r  kwargsr   r   c                  K  s0   |  dd u r| dd  tdi | ddiS )Nr   enable_multiple_collinfoTrL   )rq   popr   )r  rL   rL   rM   r   %  s   r   c                   @  s  e Zd ZdZ		d]d^ddZ		d]d_ddZ			d`dad$d%Z						&dbdcd2d3Z					ddded4d5Z					dddfd8d9Z	dgd:d;Z
dhd>d?ZdidAdBZdjdDdEZdkdFdGZdldHdIZdmdJdKZ		d]dndOdPZdodRdSZdpdWdXZdqdYdZZdqd[d\ZdS )rClientEncryptionz,Explicit client-side field level encryption.Nr   r   key_vault_namespacer   r   r   rZ   r   kms_tls_optionsOptional[Mapping[str, Any]]r   Optional[int]rG   rh   c                 C  s   t stdt|tstdt| t|ts/tdd t|jD s/tdt|j	 || _
|| _|| _|| _|dd\}}|| | }	t||||d}
t|
jt| _td	|	d	|
| _t| jt|d	|d
| _| jjd	ustJ | jj| _d	S )a  Explicit client-side field level encryption.

        The ClientEncryption class encapsulates explicit operations on a key
        vault collection that cannot be done directly on a MongoClient. Similar
        to configuring auto encryption on a MongoClient, it is constructed with
        a MongoClient (to a MongoDB cluster containing the key vault
        collection), KMS provider configuration, and keyVaultNamespace. It
        provides an API for explicitly encrypting and decrypting values, and
        creating data keys. It does not provide an API to query keys from the
        key vault collection, as this can be done directly on the MongoClient.

        See :ref:`explicit-client-side-encryption` for an example.

        :param kms_providers: Map of KMS provider options. The `kms_providers`
            map values differ by provider:

              - `aws`: Map with "accessKeyId" and "secretAccessKey" as strings.
                These are the AWS access key ID and AWS secret access key used
                to generate KMS messages. An optional "sessionToken" may be
                included to support temporary AWS credentials.
              - `azure`: Map with "tenantId", "clientId", and "clientSecret" as
                strings. Additionally, "identityPlatformEndpoint" may also be
                specified as a string (defaults to 'login.microsoftonline.com').
                These are the Azure Active Directory credentials used to
                generate Azure Key Vault messages.
              - `gcp`: Map with "email" as a string and "privateKey"
                as `bytes` or a base64 encoded string.
                Additionally, "endpoint" may also be specified as a string
                (defaults to 'oauth2.googleapis.com'). These are the
                credentials used to generate Google Cloud KMS messages.
              - `kmip`: Map with "endpoint" as a host with required port.
                For example: ``{"endpoint": "example.com:443"}``.
              - `local`: Map with "key" as `bytes` (96 bytes in length) or
                a base64 encoded string which decodes
                to 96 bytes. "key" is the master key used to encrypt/decrypt
                data keys. This key should be generated and stored as securely
                as possible.

            KMS providers may be specified with an optional name suffix
            separated by a colon, for example "kmip:name" or "aws:name".
            Named KMS providers do not support :ref:`CSFLE on-demand credentials`.
        :param key_vault_namespace: The namespace for the key vault collection.
            The key vault collection contains all data keys used for encryption
            and decryption. Data keys are stored as documents in this MongoDB
            collection. Data keys are protected with encryption by a KMS
            provider.
        :param key_vault_client: A MongoClient connected to a MongoDB cluster
            containing the `key_vault_namespace` collection.
        :param codec_options: An instance of
            :class:`~bson.codec_options.CodecOptions` to use when encoding a
            value for encryption and decoding the decrypted BSON value. This
            should be the same CodecOptions instance configured on the
            MongoClient, Database, or Collection used to access application
            data.
        :param kms_tls_options: A map of KMS provider names to TLS
            options to use when creating secure connections to KMS providers.
            Accepts the same TLS options as
            :class:`pymongo.mongo_client.MongoClient`. For example, to
            override the system default CA file::

              kms_tls_options={'kmip': {'tlsCAFile': certifi.where()}}

            Or to supply a client certificate::

              kms_tls_options={'kmip': {'tlsCertificateKeyFile': 'client.pem'}}
        :param key_expiration_ms: The cache expiration time for data encryption keys.
            Defaults to ``None`` which defers to libmongocrypt's default which is currently 60000.
            Set to 0 to disable key expiration.

        .. versionchanged:: 4.12
           Added the `key_expiration_ms` parameter.
        .. versionchanged:: 4.0
           Added the `kms_tls_options` parameter and the "kmip" KMS provider.

        .. versionadded:: 3.9
        zclient-side field level encryption requires the pymongocrypt library: install a compatible version with: python -m pip install --upgrade 'pymongo[encryption]'zJcodec_options must be an instance of bson.codec_options.CodecOptions, not c                 s      | ]}|j d kV  qdS )r9   Nr   r   clsrL   rL   rM   	<genexpr>      z,ClientEncryption.__init__.<locals>.<genexpr>zMongoClient required but given r   r   )r  r   N)r   r   r   )_HAVE_PYMONGOCRYPTr%   r   r   r   r   r9   any__mro__r   r   r   r   _codec_optionsr   r#   r<   _kms_tls_optionsrd   rc   rQ   _io_callbacksr   r   _encryptionrT   _key_vault_coll)re   r   r  r   rZ   r  r   r   r   rT   rF   rL   rL   rM   rf   /  sF   U

zClientEncryption.__init__r   Database[_DocumentTypeArg]nameencrypted_fieldsrp   Optional[str]
master_keyr  r   6tuple[Collection[_DocumentTypeArg], Mapping[str, Any]]c           
      K  s   t |tstdd t|jD stdt|j t|}t|d D ]2\}}t |t	rW|
ddu rWz| j||d|d | d< W q% tyV }	 zt|	||	d}	~	ww q%||d< d	|d
< z|jdd|i||fW S  ty }	 zt|	||	d}	~	ww )a	  Create a collection with encryptedFields.

        .. warning::
            This function does not update the encryptedFieldsMap in the client's
            AutoEncryptionOpts, thus the user must create a new client after calling this function with
            the encryptedFields returned.

        Normally collection creation is automatic. This method should
        only be used to specify options on
        creation. :class:`~pymongo.errors.EncryptionError` will be
        raised if the collection already exists.

        :param database: the database to create the collection
        :param name: the name of the collection to create
        :param encrypted_fields: Document that describes the encrypted fields for
            Queryable Encryption. The "keyId" may be set to ``None`` to auto-generate the data keys.  For example:

            .. code-block: python

              {
                "escCollection": "enxcol_.encryptedCollection.esc",
                "ecocCollection": "enxcol_.encryptedCollection.ecoc",
                "fields": [
                    {
                        "path": "firstName",
                        "keyId": Binary.from_uuid(UUID('00000000-0000-0000-0000-000000000000')),
                        "bsonType": "string",
                        "queries": {"queryType": "equality"}
                    },
                    {
                        "path": "ssn",
                        "keyId": Binary.from_uuid(UUID('04104104-1041-0410-4104-104104104104')),
                        "bsonType": "string"
                    }
                  ]
              }

          :param kms_provider: the KMS provider to be used
          :param master_key: Identifies a KMS-specific key used to encrypt the
            new data key. If the kmsProvider is "local" the `master_key` is
            not applicable and may be omitted.
          :param kwargs: additional keyword arguments are the same as "create_collection".

        All optional `create collection command`_ parameters should be passed
        as keyword arguments to this method.
        See the documentation for :meth:`~pymongo.database.Database.create_collection` for all valid options.

        :raises: - :class:`~pymongo.errors.EncryptedCollectionError`: When either data-key creation or creating the collection fails.

        .. versionadded:: 4.4

        .. _create collection command:
            https://mongodb.com/docs/manual/reference/command/create

        c                 s  r  )r8   Nr  r  rL   rL   rM   r    r  z?ClientEncryption.create_encrypted_collection.<locals>.<genexpr>zDatabase required but given fieldskeyIdN)rp   r)  encryptedFieldsFcheck_existsr&  rL   )r   r8   r  r   r  r   r   r   	enumeratedictrq   create_data_keyr'   r&   create_collectionrJ   )
re   r   r&  r'  rp   r)  r  ifieldrK   rL   rL   rM   create_encrypted_collection  s4   
@z,ClientEncryption.create_encrypted_collectionkey_alt_namesOptional[Sequence[str]]key_materialr   r   c              	   C  sL   |    t  tt| jj||||dW  d   S 1 sw   Y  dS )a  Create and insert a new data key into the key vault collection.

        :param kms_provider: The KMS provider to use. Supported values are
            "aws", "azure", "gcp", "kmip", "local", or a named provider like
            "kmip:name".
        :param master_key: Identifies a KMS-specific key used to encrypt the
            new data key. If the kmsProvider is "local" the `master_key` is
            not applicable and may be omitted.

            If the `kms_provider` type is "aws" it is required and has the
            following fields::

              - `region` (string): Required. The AWS region, e.g. "us-east-1".
              - `key` (string): Required. The Amazon Resource Name (ARN) to
                 the AWS customer.
              - `endpoint` (string): Optional. An alternate host to send KMS
                requests to. May include port number, e.g.
                "kms.us-east-1.amazonaws.com:443".

            If the `kms_provider` type is "azure" it is required and has the
            following fields::

              - `keyVaultEndpoint` (string): Required. Host with optional
                 port, e.g. "example.vault.azure.net".
              - `keyName` (string): Required. Key name in the key vault.
              - `keyVersion` (string): Optional. Version of the key to use.

            If the `kms_provider` type is "gcp" it is required and has the
            following fields::

              - `projectId` (string): Required. The Google cloud project ID.
              - `location` (string): Required. The GCP location, e.g. "us-east1".
              - `keyRing` (string): Required. Name of the key ring that contains
                the key to use.
              - `keyName` (string): Required. Name of the key to use.
              - `keyVersion` (string): Optional. Version of the key to use.
              - `endpoint` (string): Optional. Host with optional port.
                Defaults to "cloudkms.googleapis.com".

            If the `kms_provider` type is "kmip" it is optional and has the
            following fields::

              - `keyId` (string): Optional. `keyId` is the KMIP Unique
                Identifier to a 96 byte KMIP Secret Data managed object. If
                keyId is omitted, the driver creates a random 96 byte KMIP
                Secret Data managed object.
              - `endpoint` (string): Optional. Host with optional
                 port, e.g. "example.vault.azure.net:".
              - `delegated` (bool): Optional. If True (recommended), the
                KMIP server will perform encryption and decryption. If
                delegated is not provided, defaults to false.

        :param key_alt_names: An optional list of string alternate
            names used to reference a key. If a key is created with alternate
            names, then encryption may refer to the key by the unique alternate
            name instead of by ``key_id``. The following example shows creating
            and referring to a data key by alternate name::

              client_encryption.create_data_key("local", key_alt_names=["name1"])
              # reference the key with the alternate name
              client_encryption.encrypt("457-55-5462", key_alt_name="name1",
                                        algorithm=Algorithm.AEAD_AES_256_CBC_HMAC_SHA_512_Random)
        :param key_material: Sets the custom key material to be used
            by the data key for encryption and decryption.

        :return: The ``_id`` of the created data key document as a
          :class:`~bson.binary.Binary` with subtype
          :data:`~bson.binary.UUID_SUBTYPE`.

        .. versionchanged:: 4.2
           Added the `key_material` parameter.
        )r)  r6  r8  N)r   rP   r   r   r#  r1  )re   rp   r)  r6  r8  rL   rL   rM   r1  
  s   O$z ClientEncryption.create_data_keyFvalue	algorithmkey_id"Optional[Union[Binary, uuid.UUID]]key_alt_name
query_typecontention_factor
range_optsOptional[RangeOpts]is_expressionboolc	                 C  s   |    t|tjrt|}|d ur!t|tr|jtks!tdt	d|i| j
d}	d }
|r6t	|j| j
d}
t  | jj|	||||||
|d}t|d W  d    S 1 sXw   Y  d S )Nz2key_id must be a bson.binary.Binary with subtype 4vr   r9  r:  r;  r=  r>  r?  r@  rB  )r   r   uuidUUIDr   	from_uuidr   r   r   r   r   documentrP   r#  r   r   )re   r9  r:  r;  r=  r>  r?  r@  rB  r   range_opts_bytesencrypted_docrL   rL   rM   _encrypt_helpere  s>   



$z ClientEncryption._encrypt_helperc                 C      t t| j|||||||ddS )a  Encrypt a BSON value with a given key and algorithm.

        Note that exactly one of ``key_id`` or  ``key_alt_name`` must be
        provided.

        :param value: The BSON value to encrypt.
        :param algorithm` (string): The encryption algorithm to use. See
            :class:`Algorithm` for some valid options.
        :param key_id: Identifies a data key by ``_id`` which must be a
            :class:`~bson.binary.Binary` with subtype 4 (
            :attr:`~bson.binary.UUID_SUBTYPE`).
        :param key_alt_name: Identifies a key vault document by 'keyAltName'.
        :param query_type` (str): The query type to execute. See :class:`QueryType` for valid options.
        :param contention_factor` (int): The contention factor to use
            when the algorithm is :attr:`Algorithm.INDEXED`.  An integer value
            *must* be given when the :attr:`Algorithm.INDEXED` algorithm is
            used.
        :param range_opts: Index options for `range` queries. See
            :class:`RangeOpts` for some valid options.

        :return: The encrypted value, a :class:`~bson.binary.Binary` with subtype 6.

        .. versionchanged:: 4.9
           Added the `range_opts` parameter.

        .. versionchanged:: 4.7
           ``key_id`` can now be passed in as a :class:`uuid.UUID`.

        .. versionchanged:: 4.2
           Added the `query_type` and `contention_factor` parameters.
        FrE  )r   r   rL  )re   r9  r:  r;  r=  r>  r?  r@  rL   rL   rM   r        )zClientEncryption.encrypt
expressionr   c                 C  rM  )al  Encrypt a BSON expression with a given key and algorithm.

        Note that exactly one of ``key_id`` or  ``key_alt_name`` must be
        provided.

        :param expression: The BSON aggregate or match expression to encrypt.
        :param algorithm` (string): The encryption algorithm to use. See
            :class:`Algorithm` for some valid options.
        :param key_id: Identifies a data key by ``_id`` which must be a
            :class:`~bson.binary.Binary` with subtype 4 (
            :attr:`~bson.binary.UUID_SUBTYPE`).
        :param key_alt_name: Identifies a key vault document by 'keyAltName'.
        :param query_type` (str): The query type to execute. See
            :class:`QueryType` for valid options.
        :param contention_factor` (int): The contention factor to use
            when the algorithm is :attr:`Algorithm.INDEXED`.  An integer value
            *must* be given when the :attr:`Algorithm.INDEXED` algorithm is
            used.
        :param range_opts: Index options for `range` queries. See
            :class:`RangeOpts` for some valid options.

        :return: The encrypted expression, a :class:`~bson.RawBSONDocument`.

        .. versionchanged:: 4.9
           Added the `range_opts` parameter.

        .. versionchanged:: 4.7
           ``key_id`` can now be passed in as a :class:`uuid.UUID`.

        .. versionadded:: 4.4
        TrE  )r   r   rL  )re   rO  r:  r;  r=  r>  r?  r@  rL   rL   rM   encrypt_expression  rN  z#ClientEncryption.encrypt_expressionc                 C  sx   |    t|tr|jdkstdt  td|i}| j|}t	|| j
dd W  d   S 1 s5w   Y  dS )zDecrypt an encrypted value.

        :param value` (Binary): The encrypted value, a
            :class:`~bson.binary.Binary` with subtype 6.

        :return: The decrypted BSON value.
           z<value to decrypt must be a bson.binary.Binary with subtype 6rD  r   N)r   r   r   r   r   rP   r   r#  r   r   r   )re   r9  r   decrypted_docrL   rL   rM   r     s   $zClientEncryption.decryptidOptional[RawBSONDocument]c                 C  &   |    | jdusJ | jd|iS )a  Get a data key by id.

        :param id` (Binary): The UUID of a key a which must be a
            :class:`~bson.binary.Binary` with subtype 4 (
            :attr:`~bson.binary.UUID_SUBTYPE`).

        :return: The key document.

        .. versionadded:: 4.2
        Nr   r   r$  find_onere   rS  rL   rL   rM   get_key     zClientEncryption.get_keyCursor[RawBSONDocument]c                 C  s"   |    | jdusJ | ji S )zGet all of the data keys.

        :return: An instance of :class:`~pymongo.cursor.Cursor` over the data key
          documents.

        .. versionadded:: 4.2
        N)r   r$  r   r   rL   rL   rM   get_keys  s   zClientEncryption.get_keysr3   c                 C  rU  )aI  Delete a key document in the key vault collection that has the given ``key_id``.

        :param id` (Binary): The UUID of a key a which must be a
            :class:`~bson.binary.Binary` with subtype 4 (
            :attr:`~bson.binary.UUID_SUBTYPE`).

        :return: The delete result.

        .. versionadded:: 4.2
        Nr   )r   r$  
delete_onerX  rL   rL   rM   
delete_key)  rZ  zClientEncryption.delete_keyc                 C  s4   |    dd|ii}| jdusJ | jd|i|S )a  Add ``key_alt_name`` to the set of alternate names in the key document with UUID ``key_id``.

        :param id: The UUID of a key a which must be a
            :class:`~bson.binary.Binary` with subtype 4 (
            :attr:`~bson.binary.UUID_SUBTYPE`).
        :param key_alt_name: The key alternate name to add.

        :return: The previous version of the key document.

        .. versionadded:: 4.2
        z	$addToSetkeyAltNamesNr   r   r$  find_one_and_update)re   rS  r=  updaterL   rL   rM   add_key_alt_name8  s   z!ClientEncryption.add_key_alt_namec                 C  rU  )zGet a key document in the key vault collection that has the given ``key_alt_name``.

        :param key_alt_name: (str): The key alternate name of the key to get.

        :return: The key document.

        .. versionadded:: 4.2
        Nr_  rV  )re   r=  rL   rL   rM   get_key_by_alt_nameI  s   	z$ClientEncryption.get_key_by_alt_namec              
   C  s\   |    ddddd|ggiddddd	|gid
igiiig}| jdus%J | jd|i|S )a  Remove ``key_alt_name`` from the set of keyAltNames in the key document with UUID ``id``.

        Also removes the ``keyAltNames`` field from the key document if it would otherwise be empty.

        :param id: The UUID of a key a which must be a
            :class:`~bson.binary.Binary` with subtype 4 (
            :attr:`~bson.binary.UUID_SUBTYPE`).
        :param key_alt_name: The key alternate name to remove.

        :return: Returns the previous version of the key document.

        .. versionadded:: 4.2
        $setr_  z$condz$eqz$keyAltNamesz$$REMOVEz$filterz$nez$$this)inputcondNr   r`  )re   rS  r=  pipelinerL   rL   rM   remove_key_alt_nameV  s$   
z$ClientEncryption.remove_key_alt_namer   r   r   c                 C  s   |dur|du rt d|   t  | j|||}|du r*t W  d   S W d   n1 s4w   Y  t|t}g }|d D ]}|d |d dddid	}td
|d
 i|}	|	|	 qD|sht S | j
dusoJ | j
|}
t|
S )a  Decrypts and encrypts all matching data keys in the key vault with a possibly new `master_key` value.

        :param filter: A document used to filter the data keys.
        :param provider: The new KMS provider to use to encrypt the data keys,
            or ``None`` to use the current KMS provider(s).
        :param master_key: The master key fields corresponding to the new KMS
            provider when ``provider`` is not ``None``.

        :return: A :class:`RewrapManyDataKeyResult`.

        This method allows you to re-encrypt all of your data-keys with a new CMK, or master key.
        Note that this does *not* require re-encrypting any of the data in your encrypted collections,
        but rather refreshes the key that protects the keys that encrypt the data:

        .. code-block:: python

           client_encryption.rewrap_many_data_key(
               filter={"keyAltNames": "optional filter for which keys you want to update"},
               master_key={
                   "provider": "azure",  # replace with your cloud provider
                   "master_key": {
                       # put the rest of your master_key options here
                       "key": "<your new key>"
                   },
               },
           )

        .. versionadded:: 4.2
        Nz1A provider must be given if a master_key is givenrD  keyMaterial	masterKey)rj  rk  
updateDateT)re  z$currentDater   )r%   r   rP   r#  rewrap_many_data_keyr   r   r   r,   appendr$  
bulk_write)re   r   r   r)  
raw_resultr   replacementsr   update_modelopresultrL   rL   rM   rm  z  s.   #
z%ClientEncryption.rewrap_many_data_keyClientEncryption[_DocumentType]c                 C  s   | S r   rL   r   rL   rL   rM   	__enter__  s   zClientEncryption.__enter__exc_typeexc_valexc_tbc                 C  s   |    d S r   )r   )re   rw  rx  ry  rL   rL   rM   __exit__  s   zClientEncryption.__exit__c                 C  s   | j d u r	tdd S )Nz"Cannot use closed ClientEncryption)r#  r(   r   rL   rL   rM   r     s   
zClientEncryption._check_closedc                 C  s.   | j r| j   | j  d| _ d| _dS dS )aE  Release resources.

        Note that using this class in a with-statement will automatically call
        :meth:`close`::

            with ClientEncryption(...) as client_encryption:
                encrypted = client_encryption.encrypt(value, ...)
                decrypted = client_encryption.decrypt(encrypted)

        N)r"  r   r#  r   rL   rL   rM   r     s   


zClientEncryption.close)NN)r   r   r  r   r   r   rZ   r   r  r  r   r  rG   rh   )r   r%  r&  r   r'  r   rp   r(  r)  r  r  r   rG   r*  )NNN)
rp   r   r)  r  r6  r7  r8  r   rG   r   )NNNNNF)r9  r   r:  r   r;  r<  r=  r(  r>  r(  r?  r  r@  rA  rB  rC  rG   r   )NNNNN)r9  r   r:  r   r;  r<  r=  r(  r>  r(  r?  r  r@  rA  rG   r   )rO  r   r:  r   r;  r<  r=  r(  r>  r(  r?  r  r@  rA  rG   r   )r9  r   rG   r   )rS  r   rG   rT  )rG   r[  )rS  r   rG   r3   )rS  r   r=  r   rG   r   )r=  r   rG   rT  )rS  r   r=  r   rG   rT  )r   r   r   r(  r)  r  rG   r   )rG   ru  )rw  r   rx  r   ry  r   rG   rh   r   )r   r   r   r   rf   r5  r1  rL  r   rP  r   rY  r\  r^  rc  rd  ri  rm  rv  rz  r   r   rL   rL   rL   rM   r  ,  s\     \_.;
7





'
:

r  )rE   rA   rF   r-   rG   rH   )rG   rO   )r  r   rG   r   )~r   
__future__r   
contextlibenumr   rx   rF  r]   copyr   typingr   r   r   r   r   r	   r
   r   r   r   r   r   pymongocrypt.errorsr   pymongocrypt.mongocryptr   'pymongocrypt.synchronous.auto_encrypterr   +pymongocrypt.synchronous.explicit_encrypterr   &pymongocrypt.synchronous.state_machiner   r  ImportErrorobjectbsonr   r   r   bson.binaryr   r   r   bson.codec_optionsr   bson.errorsr   bson.raw_bsonr   r   r   pymongor    pymongo.commonr!   pymongo.daemonr"   pymongo.encryption_optionsr#   r$   pymongo.errorsr%   r&   r'   r(   r)   r*   r}   r+   pymongo.operationsr,   pymongo.pool_optionsr-   pymongo.pool_sharedr.   r/   r0   pymongo.read_concernr1   pymongo.resultsr2   r3   pymongo.ssl_supportr4   r5   pymongo.synchronous.collectionr6   pymongo.synchronous.cursorr7   pymongo.synchronous.databaser8    pymongo.synchronous.mongo_clientr9   pymongo.typingsr:   r;   pymongo.uri_parser_sharedr<   r=   pymongo.write_concernr>   r?   pymongo.pyopenssl_contextr@   rA   rd   ru   rt   r   r   rD   __annotations__ra   rN   contextmanagerrP   rQ   r   r   Enumr   r  r   r  rL   rL   rL   rM   <module>   s   8 

 [x
