o
    Åîï]	N  ã                   @   sÒ  d Z ddlZddlZddlZddlZddl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yE   d	ZeZY nw dd
lmZmZmZ ddlmZ ddlmZmZmZ ddlmZ ddlm Z m!Z!m"Z" ddl#m$Z$ ddl%m&Z&m'Z'm(Z(m)Z) ddl*m+Z+ ddl,m-Z-m.Z. ddl/m0Z0 ddl1m2Z2 ddl3m4Z4 ddl5m6Z6 ddl7m8Z8 dZ9dZ:dZ;ee$ed�Z<ee!ed�Z=ej>dd„ ƒZ?G dd„ deƒZ@G d d!„ d!eƒZAG d"d#„ d#eƒZBG d$d%„ d%eƒZCdS )&z8Support for explicit client-side field level encryption.é    N)ÚAutoEncrypter)ÚMongoCryptError)ÚExplicitEncrypter)ÚMongoCryptOptions)ÚMongoCryptCallbackTF)Ú_dict_to_bsonÚdecodeÚencode)ÚCodecOptions)ÚBinaryÚSTANDARDÚUUID_SUBTYPE)Ú	BSONError)ÚDEFAULT_RAW_BSON_OPTIONSÚRawBSONDocumentÚ_inflate_bson)ÚSON)ÚConfigurationErrorÚEncryptionErrorÚInvalidOperationÚServerSelectionTimeoutError)ÚMongoClient)Ú_configured_socketÚPoolOptions)ÚReadConcern)Úget_ssl_context)Ú
parse_host)ÚWriteConcern)Ú_spawn_daemoni»  é
   iè  )Údocument_classÚuuid_representationc               
   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   Ú	Exceptionr   )Úexc© r$   úD/var/www/html/env/lib/python3.10/site-packages/pymongo/encryption.pyÚ_wrap_encryption_errorsE   s   €€ÿr&   c                   @   sT   e Zd Zdd„ Zdd„ Zdd„ Zdd„ Zd	d
„ Zdd„ Zdd„ Z	dd„ Z
dd„ ZdS )Ú_EncryptionIOc                 C   sP   |durt  |¡| _nd| _|jttdd�tdd�d�| _|| _|| _	d| _
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_refÚwith_optionsÚ_KEY_VAULT_OPTSr   r   Úkey_vault_collÚmongocryptd_clientÚoptsÚ_spawned)ÚselfÚclientr3   r4   r5   r$   r$   r%   Ú__init__S   s   ý
z_EncryptionIO.__init__c           
      C   s¦   |j }|j}t|tƒ\}}tdddddddƒ}ttt|d�}t||f|ƒ}z(| |¡ |j	dkrG| 
|j	¡}	| |	¡ |j	dks0W | ¡  dS W | ¡  dS | ¡  w )z”Complete a KMS request.

        :Parameters:
          - `kms_context`: A :class:`MongoCryptKmsContext`.

        :Returns:
          None
        NT)Úconnect_timeoutÚsocket_timeoutÚssl_contextr   )ÚendpointÚmessager   Ú_HTTPS_PORTr   r   Ú_KMS_CONNECT_TIMEOUTr   ÚsendallÚbytes_neededÚrecvÚfeedÚclose)
r7   Úkms_contextr=   r>   ÚhostÚportÚctxr5   ÚconnÚdatar$   r$   r%   Úkms_requestb   s$   	þ


þüz_EncryptionIO.kms_requestc                 C   sd   |   ¡ | jt|ƒd��}|D ]}t|dtƒ  W  d  ƒ S W d  ƒ dS 1 s+w   Y  dS )a“  Get the collection info for a namespace.

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

        :Parameters:
          - `database`: The database on which to run listCollections.
          - `filter`: The filter to pass to listCollections.

        :Returns:
          The first document from the listCollections command response as BSON.
        )ÚfilterFN)r0   Úlist_collectionsr   r   Ú_DATA_KEY_OPTS)r7   ÚdatabaserM   ÚcursorÚdocr$   r$   r%   Ú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)r6   r5   Ú_mongocryptd_spawn_pathÚextendÚ_mongocryptd_spawn_argsr   )r7   Úargsr$   r$   r%   Úspawn�   s   z_EncryptionIO.spawnc                 C   sz   | j s| jjs|  ¡  t|tƒ}z| j| j|td�}W |j	S  ty<   | jjr*‚ |  ¡  | j| j|td�}Y |j	S w )z÷Mark a command for encryption.

        :Parameters:
          - `database`: The database on which to run this command.
          - `cmd`: The BSON command to run.

        :Returns:
          The marked command response from mongocryptd.
        ©r+   )
r6   r5   Ú_mongocryptd_bypass_spawnrY   r   r   r4   Úcommandr   Úraw)r7   rP   ÚcmdÚinflated_cmdÚresr$   r$   r%   Úmark_command˜   s&   


þ
ù
þùz_EncryptionIO.mark_commandc                 c   sJ   � | j  t|ƒ¡�}|D ]}|jV  qW d  ƒ dS 1 sw   Y  dS )zÙYields one or more keys from the key vault.

        :Parameters:
          - `filter`: The filter to pass to find.

        :Returns:
          A generator which yields the requested keys from the key vault.
        N)r3   Úfindr   r]   )r7   rM   rQ   Úkeyr$   r$   r%   Ú
fetch_keys´   s   €	
ÿ"ÿz_EncryptionIO.fetch_keysc                 C   s@   t |ƒ}| d¡}t|tjƒstdƒ‚| j |¡ t|j	t
d�S )zÅInsert a data key into the key vault.

        :Parameters:
          - `data_key`: The data key document to insert.

        :Returns:
          The _id of the inserted data key document.
        Ú_idzdata_key _id must be a UUID)Úsubtype)r   ÚgetÚ
isinstanceÚuuidÚUUIDÚ	TypeErrorr3   Ú
insert_oner   Úbytesr   )r7   Údata_keyÚraw_docÚdata_key_idr$   r$   r%   Úinsert_data_keyÁ   s   	
z_EncryptionIO.insert_data_keyc                 C   s   t |ƒS )zèEncode a document to BSON.

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

        :Parameters:
          - `doc`: mapping type representing a document

        :Returns:
          The encoded BSON bytes.
        )r	   )r7   rR   r$   r$   r%   Úbson_encodeÒ   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)r0   r3   r4   rE   ©r7   r$   r$   r%   rE   ß   s   

þz_EncryptionIO.closeN)Ú__name__Ú
__module__Ú__qualname__r9   rL   rS   rY   ra   rd   rq   rr   rE   r$   r$   r$   r%   r'   R   s    r'   c                   @   s@   e Zd Zdd„ Zdd„ Zdd„ Zdd„ Zd	d
„ Zedd„ ƒZ	dS )Ú
_Encrypterc                 C   sD   |j du rd}nt|j dtƒ}t|t|j|ƒƒ| _|j| _d| _dS )a1  Encrypts and decrypts MongoDB commands.

        This class is used to support automatic encryption and decryption of
        MongoDB commands.

        :Parameters:
          - `io_callbacks`: A :class:`MongoCryptCallback`.
          - `opts`: The encrypted client's :class:`AutoEncryptionOpts`.
        NF)	Ú_schema_mapr   rO   r   r   Ú_kms_providersÚ_auto_encrypterÚ_bypass_auto_encryptionÚ_closed)r7   Úio_callbacksr5   Ú
schema_mapr$   r$   r%   r9   ì   s   

ÿ
z_Encrypter.__init__c           	      C   sv   |   ¡  |o| dd¡}t|||ƒ}tƒ � | j ||¡}t|tƒ}|r(||d< |W  d  ƒ S 1 s4w   Y  dS )ab  Encrypt a MongoDB command.

        :Parameters:
          - `database`: The database for this command.
          - `cmd`: A command document.
          - `check_keys`: If True, check `cmd` for invalid keys.
          - `codec_options`: The CodecOptions to use while encoding `cmd`.

        :Returns:
          The encrypted command to execute.
        z$clusterTimeN)Ú_check_closedÚpopr   r&   rz   Úencryptr   r   )	r7   rP   r^   Ú
check_keysr+   Úcluster_timeÚencoded_cmdÚencrypted_cmdÚencrypt_cmdr$   r$   r%   r�   ÿ   s   ÿ$ùz_Encrypter.encryptc                 C   s>   |   ¡  tƒ � | j |¡W  d  ƒ S 1 sw   Y  dS )z»Decrypt a MongoDB command response.

        :Parameters:
          - `response`: A MongoDB command response as BSON.

        :Returns:
          The decrypted command response.
        N)r   r&   rz   Údecrypt)r7   Úresponser$   r$   r%   r‡     s   	
$ÿz_Encrypter.decryptc                 C   s   | j rtdƒ‚d S )Nz"Cannot use MongoClient after close)r|   r   rs   r$   r$   r%   r   &  s   ÿz_Encrypter._check_closedc                 C   s   d| _ | j ¡  dS )zCleanup resources.TN)r|   rz   rE   rs   r$   r$   r%   rE   *  s   z_Encrypter.closec                 C   sP   |j p| }|j dd¡\}}|| | }t|jdtd�}t| |||ƒ}t||ƒS )a
  Create a _CommandEncyptor for a client.

        :Parameters:
          - `client`: The encrypted MongoClient.
          - `opts`: The encrypted client's :class:`AutoEncryptionOpts`.

        :Returns:
          A :class:`_CommandEncrypter` for this client.
        Ú.é   F)ÚconnectÚserverSelectionTimeoutMS)Ú_key_vault_clientÚ_key_vault_namespaceÚsplitr   Ú_mongocryptd_uriÚ_MONGOCRYPTD_TIMEOUT_MSr'   rw   )r8   r5   Úkey_vault_clientÚdbÚcollr3   r4   r}   r$   r$   r%   Úcreate/  s   
þÿ
z_Encrypter.createN)
rt   ru   rv   r9   r�   r‡   r   rE   Ústaticmethodr•   r$   r$   r$   r%   rw   ë   s    rw   c                   @   s   e 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-RandomN)rt   ru   rv   Ú__doc__Ú+AEAD_AES_256_CBC_HMAC_SHA_512_DeterministicÚ$AEAD_AES_256_CBC_HMAC_SHA_512_Randomr$   r$   r$   r%   r—   G  s    ÿÿr—   c                   @   sX   e Zd ZdZdd„ Z		ddd„Zddd„Zd	d
„ Zdd„ Zdd„ Z	dd„ Z
dd„ ZdS )ÚClientEncryptionz,Explicit client-side field level encryption.c                 C   sz   t stdƒ‚t|tƒstdƒ‚|| _|| _|| _|| _| 	dd¡\}}|| | }t
d|ddƒ| _t| jt|dƒƒ| _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.

        :Parameters:
          - `kms_providers`: Map of KMS provider options. Two KMS providers
            are supported: "aws" and "local". The kmsProviders 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.
              - `local`: Map with "key" as a 96-byte array or string. "key"
                is the master key used to encrypt/decrypt data keys. This key
                should be generated and stored as securely as possible.

          - `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.
          - `key_vault_client`: A MongoClient connected to a MongoDB cluster
            containing the `key_vault_namespace` collection.
          - `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.

        .. versionadded:: 3.9
        z”client-side field level encryption requires the pymongocrypt library: install a compatible version with: python -m pip install 'pymongo[encryption]'zDcodec_options must be an instance of bson.codec_options.CodecOptionsr‰   rŠ   N)Ú_HAVE_PYMONGOCRYPTr   rh   r
   rk   ry   rŽ   r�   Ú_codec_optionsr�   r'   Ú_io_callbacksr   r   Ú_encryption)r7   Úkms_providersÚkey_vault_namespacer’   r+   r“   r”   r3   r$   r$   r%   r9   R  s    +ÿ

ÿzClientEncryption.__init__Nc                 C   sD   |   ¡  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.

        :Parameters:
          - `kms_provider`: The KMS provider to use. Supported values are
            "aws" and "local".
          - `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` 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".

          - `key_alt_names` (optional): 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", keyAltNames=["name1"])
              # reference the key with the alternate name
              client_encryption.encrypt("457-55-5462", keyAltName="name1",
                                        algorithm=Algorithm.Random)

        :Returns:
          The ``_id`` of the created data key document as a
          :class:`~bson.binary.Binary` with subtype
          :data:`~bson.binary.UUID_SUBTYPE`.
        )Ú
master_keyÚkey_alt_namesN)r   r&   rŸ   Úcreate_data_key)r7   Úkms_providerr¢   r£   r$   r$   r%   r¤   “  s   #þ$ÿz ClientEncryption.create_data_keyc                 C   sˆ   |   ¡  |durt|tƒr|jtkstdƒ‚td|i| jd�}tƒ � | j	j
||||d�}t|ƒd W  d  ƒ S 1 s=w   Y  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.

        :Parameters:
          - `value`: The BSON value to encrypt.
          - `algorithm` (string): The encryption algorithm to use. See
            :class:`Algorithm` for some valid options.
          - `key_id`: Identifies a data key by ``_id`` which must be a
            :class:`~bson.binary.Binary` with subtype 4 (
            :attr:`~bson.binary.UUID_SUBTYPE`).
          - `key_alt_name`: Identifies a key vault document by 'keyAltName'.

        :Returns:
          The encrypted value, a :class:`~bson.binary.Binary` with subtype 6.
        Nz2key_id must be a bson.binary.Binary with subtype 4ÚvrZ   )Úkey_idÚkey_alt_name)r   rh   r   rf   r   rk   r	   r�   r&   rŸ   r�   r   )r7   ÚvalueÚ	algorithmr§   r¨   rR   Úencrypted_docr$   r$   r%   r�   ¼  s   ÿ
ÿÿ
$ýzClientEncryption.encryptc                 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 )zßDecrypt an encrypted value.

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

        :Returns:
          The decrypted BSON value.
        é   z<value to decrypt must be a bson.binary.Binary with subtype 6r¦   rZ   N)r   rh   r   rf   rk   r&   r	   rŸ   r‡   r   r�   )r7   r©   rR   Údecrypted_docr$   r$   r%   r‡   Û  s   
ÿÿÿ$ýzClientEncryption.decryptc                 C   s   | S ©Nr$   rs   r$   r$   r%   Ú	__enter__ð  s   zClientEncryption.__enter__c                 C   s   |   ¡  d S r®   )rE   )r7   Úexc_typeÚexc_valÚexc_tbr$   r$   r%   Ú__exit__ó  s   zClientEncryption.__exit__c                 C   s   | j d u r	tdƒ‚d S )Nz"Cannot use closed ClientEncryption)rŸ   r   rs   r$   r$   r%   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ž   rE   rŸ   rs   r$   r$   r%   rE   ú  s   


üzClientEncryption.close)NN)rt   ru   rv   r˜   r9   r¤   r�   r‡   r¯   r³   r   rE   r$   r$   r$   r%   r›   O  s    A
ÿ
)r›   )Dr˜   Ú
contextlibÚosÚ
subprocessri   r.   Úpymongocrypt.auto_encrypterr   Úpymongocrypt.errorsr   Úpymongocrypt.explicit_encrypterr   Úpymongocrypt.mongocryptr   Úpymongocrypt.state_machiner   rœ   ÚImportErrorÚobjectÚbsonr   r   r	   Úbson.codec_optionsr
   Úbson.binaryr   r   r   Úbson.errorsr   Úbson.raw_bsonr   r   r   Úbson.sonr   Úpymongo.errorsr   r   r   r   Úpymongo.mongo_clientr   Úpymongo.poolr   r   Úpymongo.read_concernr   Úpymongo.ssl_supportr   Úpymongo.uri_parserr   Úpymongo.write_concernr   Úpymongo.daemonr   r?   r@   r‘   rO   r2   Úcontextmanagerr&   r'   rw   r—   r›   r$   r$   r$   r%   Ú<module>   sZ   þÿ
 \