o
    hC_                  
   @   s  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mZ d dl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 d dlmZ d d	lmZ d d
lmZ d dlmZmZ d dlmZ d dlmZm Z m!Z!m"Z"m#Z#m$Z$m%Z% zd dl&Z'd dl(m)Z) d dl*m+Z+ d dl,m-Z- W n e.y Z/ zede/ dZ/[/ww dd Z0dd Z1e0e1fD ]Z2ze2 Z3W  n e.y   Y qw dd Z3eG dd deZ4eG dd deZ5G dd de5Z6G dd dee6Z7dS )     N)datetime	timedelta)GzipFile)SpooledTemporaryFile)	parse_qsl	urlencodeurlsplit)ManifestFilesMixin)ImproperlyConfiguredSuspiciousOperation)File)deconstructible)filepath_to_uri)is_naive
make_naive)BaseStorage)GzipCompressionWrappercheck_locationget_available_overwrite_name
lookup_env	safe_joinsettingto_bytes)Config)ClientError)CloudFrontSignerz&Could not load Boto3's S3 bindings. %sc                     sF   ddl m  ddlm ddlm ddlm  fdd} | S )Nr   )default_backend)hashes)padding)load_pem_private_keyc                    s:   t |tr
|d}|d  d t|  fddS )Nascii)passwordbackendc                    s    |    S N)signZPKCS1v15SHA1x)r   keyr    a/var/www/html/magazine_api/magazine_env/lib/python3.10/site-packages/storages/backends/s3boto3.py<lambda>2   s    zP_use_cryptography_signer.<locals>._cloud_front_signer_from_pem.<locals>.<lambda>)
isinstancestrencoder   key_idpemr   r   r   r   r(   r*   _cloud_front_signer_from_pem+   s   

z>_use_cryptography_signer.<locals>._cloud_front_signer_from_pem)Zcryptography.hazmat.backendsr   Zcryptography.hazmat.primitivesr   Z)cryptography.hazmat.primitives.asymmetricr   Z,cryptography.hazmat.primitives.serializationr   r4   r)   r2   r*   _use_cryptography_signer"   s   	r6   c                     s   dd l   fdd} | S )Nr   c                    s4   t |tr
|d}j| t|  fddS )Nr    c                    s    |  dS )NzSHA-1)r$   r&   )r(   rsar)   r*   r+   ?   s    zG_use_rsa_signer.<locals>._cloud_front_signer_from_pem.<locals>.<lambda>)r,   r-   r.   Z
PrivateKeyZ
load_pkcs1r   r/   r7   r3   r*   r4   ;   s   

z5_use_rsa_signer.<locals>._cloud_front_signer_from_pemr8   r5   r)   r8   r*   _use_rsa_signer7   s   r9   c                 C   s   t d)NznAn RSA backend is required for signing cloudfront URLs.
Supported backends are packages: cryptography and rsa.)r
   r/   r)   r)   r*   r4   K   s   r4   c                       s   e Zd ZdZdddZedd Zdd Zd	d
 ZeeeZ	 fddZ
 fddZ fddZedd Zdd Zdd Zdd Z  ZS )S3Boto3StorageFileag  
    The default file object used by the S3Boto3Storage backend.

    This file implements file streaming using boto's multipart
    uploading functionality. The file can be opened in read or
    write mode.

    This class extends Django's File class. However, the contained
    data is only the data contained in the current buffer. So you
    should not access the contained file object directly. You should
    access the data via this class.

    Warning: This file *must* be closed using the close() method in
    order to properly write the file to S3. Be sure to close the file
    in your application.
    Nc                 C   s   d|v rd|v rt d|| _|t| jjd  d| _|| _d|v r(dd ndd | _|j	|| _
d|vr=| j
  d	| _d
| _d | _d | _d | _|pRtdd| _d
| _d S )Nrwz"Can't combine 'r' and 'w' in mode./bc                 S   s   | S r#   r)   r>   r)   r)   r*   r+   j   s    z-S3Boto3StorageFile.__init__.<locals>.<lambda>c                 S   s   |   S r#   )decoder?   r)   r)   r*   r+   j   s    Fr   ZAWS_S3_FILE_BUFFER_SIZEi  P )
ValueError_storagelenlocationlstripname_mode_force_modebucketObjectobjload	_is_dirty_raw_bytes_written_file
_multipart_partsr   buffer_size_write_counter)selfrF   modeZstoragerR   r)   r)   r*   __init__d   s    

zS3Boto3StorageFile.__init__c                 C   s   | j jS r#   )rK   content_lengthrT   r)   r)   r*   size{      zS3Boto3StorageFile.sizec                 C   sz   | j d u r:t| jjdtdd| _ d| jv r&d| _| j| j  | j 	d | jj
r:| jjdkr:t| j| j dd	| _ | j S )
Nz.S3Boto3StorageFileZFILE_UPLOAD_TEMP_DIR)max_sizesuffixdirr;   Fr   gzipg        )rU   fileobjmtime)rO   r   rB   max_memory_sizer   rG   rM   rK   Zdownload_fileobjseekr^   content_encodingr   rX   r)   r)   r*   	_get_file   s   

zS3Boto3StorageFile._get_filec                 C   s
   || _ d S r#   )rO   )rT   valuer)   r)   r*   	_set_file      
zS3Boto3StorageFile._set_filec                    *   d| j vr	td| t j|i |S Nr;   z!File was not opened in read mode.)rG   AttributeErrorrH   superreadrT   argskwargs	__class__r)   r*   rl         
zS3Boto3StorageFile.readc                    rh   ri   )rG   rj   rH   rk   readlinerm   rp   r)   r*   rs      rr   zS3Boto3StorageFile.readlinec                    s   d| j vr	tdd| _| jd u r$| jjdi | j| jj| _g | _	| j
| jkr.|   t|}|  jt|7  _t |S )Nr<   z"File was not opened in write mode.Tr)   )rG   rj   rM   rP   rK   Zinitiate_multipart_uploadrB   _get_write_parametersr(   rQ   rR   _buffer_file_size_flush_write_bufferr   rN   rC   rk   write)rT   contentZbstrrp   r)   r*   rw      s   


zS3Boto3StorageFile.writec                 C   s4   | j  }| j dtj | j  }| j | |S Nr   )filetellrb   osSEEK_END)rT   poslengthr)   r)   r*   ru      s
   

z$S3Boto3StorageFile._buffer_file_sizec                 C   sv   | j r9|  jd7  _| jd | j| j}|j| j d}| j	|d | jd | jd | j
  d S d S )N   r   )BodyETag)r   Z
PartNumber)ru   rS   rz   rb   rP   ZPartZuploadrl   rQ   appendtruncate)rT   partresponser)   r)   r*   rv      s   z&S3Boto3StorageFile._flush_write_bufferc              
   C   s   d| j v sJ | jdksJ z| j  W dS  tyE } z#|jd d dkr9| jjd	ddi| j| jj	 n W Y d}~dS d}~ww )
a  
        Attempt to create an empty file for this key when this File is closed if no bytes
        have been written and no object already exists on S3 for this key.

        This behavior is meant to mimic the behavior of Django's builtin FileSystemStorage,
        where files are always created after they are opened in write mode:

            f = storage.open('file.txt', mode='w')
            f.close()
        r<   r   ResponseMetadataHTTPStatusCode  r       Nr)   )
rG   rN   rK   rL   r   r   putrB   rt   r(   )rT   errr)   r)   r*   _create_empty_on_close   s   
z)S3Boto3StorageFile._create_empty_on_closec                 C   sv   | j r|   | jjd| jid n| jd ur| j  d| jv r*| jdkr*|   | j	d ur9| j	
  d | _	d S d S )NZParts)ZMultipartUploadr<   r   )rM   rv   rP   ZcompleterQ   abortrG   rN   r   rO   closerX   r)   r)   r*   r      s   




zS3Boto3StorageFile.closer#   )__name__
__module____qualname____doc__rV   propertyrY   rd   rf   rz   rl   rs   rw   ru   rv   r   r   __classcell__r)   r)   rp   r*   r:   Q   s     



r:   c                       s   e Zd ZdZdZdZddgZddgZdd	gZdZ	 fd
dZ
dd Zdd Zdd Zdd Zedd Zdd Zedd Zdd Zdd Zdd Zd d! Zd"d# Zd?d%d&Zd'd( Zd)d* Zd+d, Zd-d. Zd/d0 Zd@d1d2Zd3d4 Zd5d6 Z d7d8 Z!d9d: Z"dAd;d<Z#d@ fd=d>	Z$  Z%S )BS3Boto3Storagez
    Amazon Simple Storage Service using Boto3

    This storage backend supports opening files in read or write
    mode and supports streaming(buffering) data in chunks to S3
    when writing.
    zapplication/octet-streamNAWS_S3_ACCESS_KEY_IDAWS_ACCESS_KEY_IDAWS_S3_SECRET_ACCESS_KEYAWS_SECRET_ACCESS_KEYZAWS_SESSION_TOKENZAWS_SECURITY_TOKENc                    sx   t  jdi | t|  | jrd| _d | _t | _| 	 \| _
| _|  | _| js:td| ji| j| jd| _d S d S )Nzhttps:addressing_style)s3signature_versionproxiesr)   )rk   rV   r   secure_urlsurl_protocol_bucket	threadinglocal_connections_get_access_keys
access_key
secret_key_get_security_tokensecurity_tokenconfigr   r   r   r   )rT   settingsrp   r)   r*   rV      s   

zS3Boto3Storage.__init__c                 C   s
   t ||S r#   r5   )rT   r0   r(   r)   r)   r*   get_cloudfront_signer  rg   z$S3Boto3Storage.get_cloudfront_signerc                 C   sr  t d}t d}t|t|A rtd|r| ||}nd }t d}t d}t d}|s/|r5|r5tdi dt dt d	d
t dt ddt ddt dddt di dt ddt dddt dddt ddt dddt dd |d!t d"d#t d$dd%t d&d'd(t d)d*d+t d,d-t d.d/t d0t d1t d2t d3dt d4d t d5d6t d7d d8S )9NZAWS_CLOUDFRONT_KEY_IDZAWS_CLOUDFRONT_KEYzLBoth AWS_CLOUDFRONT_KEY_ID and AWS_CLOUDFRONT_KEY must be provided together.r   r   ZAWS_S3_SESSION_PROFILEzdAWS_S3_SESSION_PROFILE should not be provided with AWS_S3_ACCESS_KEY_ID and AWS_S3_SECRET_ACCESS_KEYr   r   r   r   session_profilefile_overwriteZAWS_S3_FILE_OVERWRITETobject_parametersZAWS_S3_OBJECT_PARAMETERSbucket_nameZAWS_STORAGE_BUCKET_NAMEquerystring_authZAWS_QUERYSTRING_AUTHquerystring_expireZAWS_QUERYSTRING_EXPIREi  r   ZAWS_S3_SIGNATURE_VERSIONrD   ZAWS_LOCATION custom_domainZAWS_S3_CUSTOM_DOMAINcloudfront_signerr   ZAWS_S3_ADDRESSING_STYLEr   ZAWS_S3_SECURE_URLSZfile_name_charsetZAWS_S3_FILE_NAME_CHARSETzutf-8r^   ZAWS_IS_GZIPPEDFgzip_content_typesZGZIP_CONTENT_TYPES)ztext/cssztext/javascriptzapplication/javascriptzapplication/x-javascriptzimage/svg+xmlZAWS_S3_URL_PROTOCOLzhttp:ZAWS_S3_ENDPOINT_URLZAWS_S3_PROXIESZAWS_S3_REGION_NAMEZAWS_S3_USE_SSLZAWS_S3_VERIFYZAWS_S3_MAX_MEMORY_SIZEr   ZAWS_DEFAULT_ACL)r   endpoint_urlr   region_nameuse_sslverifyra   default_acl)r   boolr
   r   )rT   Zcloudfront_key_idZcloudfront_keyr   Zs3_access_key_idZs3_secret_access_keyZs3_session_profiler)   r)   r*   get_default_settings  sx   



	





z#S3Boto3Storage.get_default_settingsc                 C   s&   | j  }|dd  |dd  |S Nr   r   )__dict__copypoprT   stater)   r)   r*   __getstate__P  s   
zS3Boto3Storage.__getstate__c                 C   s   t  |d< d |d< || _d S r   )r   r   r   r   r)   r)   r*   __setstate__V  s   
zS3Boto3Storage.__setstate__c                 C   sJ   t | jdd }|d u r!|  }|jd| j| j| j| j| jd| j_	| jj	S )N
connectionr   )r   r   r   r   r   )
getattrr   _create_sessionresourcer   r   r   r   r   r   )rT   r   sessionr)   r)   r*   r   [  s   
zS3Boto3Storage.connectionc                 C   s2   | j rtj| j d}|S tj| j| j| jd}|S )z
        If a user specifies a profile name and this class obtains access keys
        from another source such as environment variables,we want the profile
        name to take precedence.
        )Zprofile_name)Zaws_access_key_idZaws_secret_access_keyZaws_session_token)r   boto3Sessionr   r   r   )rT   r   r)   r)   r*   r   j  s   zS3Boto3Storage._create_sessionc                 C   s    | j du r| j| j| _ | j S )za
        Get the current bucket. If there is no current bucket object
        create it.
        N)r   r   Bucketr   rX   r)   r)   r*   rI   z  s   
zS3Boto3Storage.bucketc                 C   s(   | j pt| j}| jpt| j}||fS )z
        Gets the access keys to use when accessing S3. If none is
        provided in the settings then get them from the environment
        variables.
        )r   r   access_key_namesr   secret_key_names)rT   r   r   r)   r)   r*   r     s   zS3Boto3Storage._get_access_keysc                 C   s   | j pt| j}|S )zr
        Gets the security token to use when accessing S3. Get it from
        the environment variables.
        )r   r   security_token_names)rT   r   r)   r)   r*   r     s   z"S3Boto3Storage._get_security_tokenc                 C   s2   t |dd}|dr|ds|d7 }|S )zB
        Cleans the name so that Windows style paths work
        \r=   )	posixpathnormpathreplaceendswith)rT   rF   Z
clean_namer)   r)   r*   _clean_name  s   zS3Boto3Storage._clean_namec                 C   s*   zt | j|W S  ty   td| w )z
        Normalizes the name so that paths like /path/to/ignored/../something.txt
        work. We check to make sure that the path pointed to is not outside
        the directory specified by the LOCATION setting.
        z Attempted access to '%s' denied.)r   rD   rA   r   rT   rF   r)   r)   r*   _normalize_name  s
   zS3Boto3Storage._normalize_namec                 C   s   t |S )zGzip a given string content.)r   )rT   rx   r)   r)   r*   _compress_content  rZ   z S3Boto3Storage._compress_contentrbc              
   C   s\   |  | |}z	t||| }W |S  ty- } z|jd d dkr(td|  d }~ww )Nr   r   r   zFile does not exist: %s)r   r   r:   r   r   FileNotFoundError)rT   rF   rU   fr   r)   r)   r*   _open  s   zS3Boto3Storage._openc                 C   s   |  |}| |}| ||}t|dr| r |dtj | jr7|d | j	v r7d|vr7| 
|}d|d< | j|}|j||d |S )Nseekabler   ContentTypeContentEncodingr^   )Z	ExtraArgs)r   r   rt   hasattrr   rb   r|   SEEK_SETr^   r   r   rI   rJ   Zupload_fileobj)rT   rF   rx   Zcleaned_nameparamsrK   r)   r)   r*   _save  s   


zS3Boto3Storage._savec                 C   s$   |  | |}| j|  d S r#   )r   r   rI   rJ   deleter   r)   r)   r*   r     s   zS3Boto3Storage.deletec              
   C   sh   |  | |}z| jjjj| j|d W dS  ty3 } z|jd d dkr.W Y d }~dS  d }~ww )N)r   KeyTr   r   r   F)	r   r   r   metaclientZhead_objectr   r   r   )rT   rF   errorr)   r)   r*   exists  s   zS3Boto3Storage.existsc           
      C   s   |  | |}|r|ds|d7 }g }g }| jjjd}|j| jd|d}|D ]0}|	ddD ]}|
t|d | q2|	ddD ]}|d }	|	|krY|
t|	| qFq*||fS )	Nr=   Zlist_objects)r   	DelimiterPrefixZCommonPrefixesr)   r   ZContentsr   )r   r   r   r   r   r   Zget_paginatorZpaginater   getr   r   relpath)
rT   rF   pathdirectoriesfilesZ	paginatorZpagespageentryr(   r)   r)   r*   listdir  s"   zS3Boto3Storage.listdirc                 C   s   |  | |}| j|jS r#   )r   r   rI   rJ   rW   r   r)   r)   r*   rY     s   zS3Boto3Storage.sizec                 C   sl   i }t |\}}t|dd }|p|p| j}||d< |r ||d< || | d|vr4| jr4| j|d< |S )Ncontent_typer   r   ZACL)	mimetypes
guess_typer   default_content_typeupdateget_object_parametersr   )rT   rF   rx   r   _typeencodingr   r)   r)   r*   rt     s   
z$S3Boto3Storage._get_write_parametersc                 C   s
   | j  S )aB  
        Returns a dictionary that is passed to file upload. Override this
        method to adjust this on a per-object basis to set e.g ContentDisposition.

        By default, returns the value of AWS_S3_OBJECT_PARAMETERS.

        Setting ContentEncoding will prevent objects from being automatically gzipped.
        )r   r   r   r)   r)   r*   r     s   
	z$S3Boto3Storage.get_object_parametersc                 C   s4   |  | |}| j|}tdr|jS t|jS )z
        Returns an (aware) datetime object containing the last modified time if
        USE_TZ is True, otherwise returns a naive datetime in the local timezone.
        ZUSE_TZ)r   r   rI   rJ   r   Zlast_modifiedr   )rT   rF   r   r)   r)   r*   get_modified_time  s
   
z S3Boto3Storage.get_modified_timec                 C   s   |  |}t|r|S t|S )zBReturns a naive datetime object containing the last modified time.)r   r   r   )rT   rF   r`   r)   r)   r*   modified_time  s   
zS3Boto3Storage.modified_timec                    sX   t |}t|jdd}h d  fdd|D }dd |D }|jd|d}| S )	NT)keep_blank_values>
   	signaturez
x-amz-dateZawsaccesskeyidzx-amz-algorithmzx-amz-security-tokenzx-amz-credentialexpireszx-amz-signaturezx-amz-signedheaderszx-amz-expiresc                 3   s(    | ]\}}|   vr||fV  qd S r#   )lower).0r(   valZ	blacklistr)   r*   	<genexpr>4  s   & z;S3Boto3Storage._strip_signing_parameters.<locals>.<genexpr>c                 s   s    | ]}d  |V  qdS )=N)join)r  keyvalr)   r)   r*   r  7  s    &)query)r   r   r  _replacer  geturl)rT   urlZ	split_urlqsZfiltered_qsZ	joined_qsr)   r  r*   _strip_signing_parameters&  s   z(S3Boto3Storage._strip_signing_parametersc              	   C   s   |  | |}|r| ni }|d u r| j}| jrHd| j| jt||r,dt|nd}| j	rF| j
rFt t|d }| j
j||dS |S | jj|d< ||d< | jjjjd|||d	}| j	rc|S | |S )
Nz{}//{}/{}{}z?{}r   )seconds)Zdate_less_thanr   r   Z
get_object)ZParamsZ	ExpiresInZ
HttpMethod)r   r   r   r   r   formatr   r   r   r   r   r   utcnowr   Zgenerate_presigned_urlrI   rF   r   r   r  )rT   rF   
parametersZexpireZhttp_methodr   r  Z
expirationr)   r)   r*   r  ;  s.   
zS3Boto3Storage.urlc                    s(   |  |}| jrt||S t ||S )z+Overwrite existing file with the same name.)r   r   r   rk   get_available_name)rT   rF   
max_lengthrp   r)   r*   r  X  s   

z!S3Boto3Storage.get_available_name)r   r#   )NNN)&r   r   r   r   r   r   r   r   r   r   rV   r   r   r   r   r   r   r   rI   r   r   r   r   r   r   r   r   r   r   rY   rt   r   r   r   r  r  r  r   r)   r)   rp   r*   r      sH    9

	




r   c                   @   s   e Zd ZdZdZdS )S3StaticStoragezLQuerystring auth must be disabled so that url() returns a consistent output.FN)r   r   r   r   r   r)   r)   r)   r*   r  `  s    r  c                       s    e Zd ZdZ fddZ  ZS )S3ManifestStaticStoragezCopy the file before saving for compatibility with ManifestFilesMixin
    which does not play nicely with boto3 automatically closing the file.

    See: https://github.com/boto/s3transfer/issues/80#issuecomment-562356142
    c                    sR   | d t }||  t ||W  d    S 1 s"w   Y  d S ry   )rb   tempfiler   rw   rl   rk   r   )rT   rF   rx   tmprp   r)   r*   r   l  s
   

$zS3ManifestStaticStorage._save)r   r   r   r   r   r   r)   r)   rp   r*   r  e  s    r  )8r   r|   r   r  r   r   r   r^   r   r   urllib.parser   r   r   Z"django.contrib.staticfiles.storager	   Zdjango.core.exceptionsr
   r   Zdjango.core.files.baser   Zdjango.utils.deconstructr   Zdjango.utils.encodingr   Zdjango.utils.timezoner   r   Zstorages.baser   Zstorages.utilsr   r   r   r   r   r   r   Zboto3.sessionr   Zbotocore.clientr   Zbotocore.exceptionsr   Zbotocore.signersr   ImportErrorer6   r9   Z_signer_factoryr4   r:   r   r  r  r)   r)   r)   r*   <module>   sZ    $   x