U
    mah f                     @   sX  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Zd dlZd dl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 dlmZ d dlmZ ejjZd	Zd
d Zdd Zdd ZeejejfZdd Zdd Z e!dddddgZ"dd Z#d+ddZ$dZ%d Z&e&ddddddddddddfd!d"Z'd#d$ Z(efd%d&Z)d'd( Z*d)d* Z+dS ),    N)
exceptions)requests)_helpers)_DEFAULT_UNIVERSE_DOMAIN)_NOW)_UTC)DEFAULT_RETRYz[https://googleapis.dev/python/google-api-core/latest/auth.html#setting-up-a-service-accountc                 C   s(   t | tjjjs$tdt| tdS )ai  Raise AttributeError if the credentials are unsigned.

    :type credentials: :class:`google.auth.credentials.Signing`
    :param credentials: The credentials used to create a private key
                        for signing text.

    :raises: :exc:`AttributeError` if credentials is not an instance
            of :class:`google.auth.credentials.Signing`.
    zyou need a private key to sign credentials.the credentials you are currently using {} just contains a token. see {} for more details.N)	
isinstancegoogleauthcredentialsZSigningAttributeErrorformattypeSERVICE_ACCOUNT_URL)r    r   A/tmp/pip-unpacked-wheel-asmaws5f/google/cloud/storage/_signing.pyensure_signed_credentials/   s    
 r   c                 C   s4   t |  | |d}t|}| j}|||dS )a  Gets query parameters for creating a signed URL.

    :type credentials: :class:`google.auth.credentials.Signing`
    :param credentials: The credentials used to create a private key
                        for signing text.

    :type expiration: int or long
    :param expiration: When the signed URL should expire.

    :type string_to_sign: str
    :param string_to_sign: The string to be signed by the credentials.

    :raises: :exc:`AttributeError` if credentials is not an instance
            of :class:`google.auth.credentials.Signing`.

    :rtype: dict
    :returns: Query parameters matching the signing credentials with a
              signed payload.
    asciiZGoogleAccessIdZExpires	Signature)r   
sign_bytesencodebase64	b64encodesigner_email)r   
expirationstring_to_signsignature_bytes	signatureZservice_account_namer   r   r   get_signed_query_params_v2B   s    
r    c                 C   sX   t | tjrtt}||  } t | tjr:t| }|d } t | tsTtdt	|  | S )a  Convert 'expiration' to a number of seconds in the future.

    :type expiration: Union[Integer, datetime.datetime, datetime.timedelta]
    :param expiration: Point in time when the signed URL should expire. If
                       a ``datetime`` instance is passed without an explicit
                       ``tzinfo`` set,  it will be assumed to be ``UTC``.

    :raises: :exc:`TypeError` when expiration is not a valid type.

    :rtype: int
    :returns: a timestamp as an absolute number of seconds since epoch.
    i@B =Expected an integer timestamp, datetime, or timedelta. Got %s)
r	   datetime	timedeltar   r   r   Z_microseconds_from_datetimeint	TypeErrorr   )r   nowZmicrosr   r   r   get_expiration_seconds_v2a   s    

r'   c                 C   s   t | tstdt|  tt}t | tr0| }t | tjr\| jdkrT| j	t
jd} | | } t | tjrtt|  }|tkrtdt |S )aV  Convert 'expiration' to a number of seconds offset from the current time.

    :type expiration: Union[Integer, datetime.datetime, datetime.timedelta]
    :param expiration: Point in time when the signed URL should expire. If
                       a ``datetime`` instance is passed without an explicit
                       ``tzinfo`` set,  it will be assumed to be ``UTC``.

    :raises: :exc:`TypeError` when expiration is not a valid type.
    :raises: :exc:`ValueError` when expiration is too large.
    :rtype: Integer
    :returns: seconds in the future when the signed URL will expire
    r!   Ntzinfoz.Max allowed expiration interval is seven days )r	   _EXPIRATION_TYPESr%   r   r   r   r$   r"   r)   replacer   UTCr#   total_seconds
SEVEN_DAYS
ValueError)r   r&   secondsr   r   r   get_expiration_seconds_v4   s$    


r1   c                 C   s   | dkrg } nt | tr$t|  } | s0g g fS tt}| D ]0\}}|  }d|	 }|| 
| q>tdd | D }dd |D }||fS )am  Canonicalize headers for signing.

    See:
    https://cloud.google.com/storage/docs/access-control/signed-urls#about-canonical-extension-headers

    :type headers: Union[dict|List(Tuple(str,str))]
    :param headers:
        (Optional) Additional HTTP headers to be included as part of the
        signed URLs.  See:
        https://cloud.google.com/storage/docs/xml-api/reference-headers
        Requests using the signed URL *must* pass the specified header
        (name and value) with each request for the URL.

    :rtype: str
    :returns: List of headers, normalized / sortted per the URL refernced above.
    N c                 s   s    | ]\}}|d  |fV  qdS ),N)join).0keyvalr   r   r   	<genexpr>   s     z(get_canonical_headers.<locals>.<genexpr>c                 S   s   g | ]}d j | qS )z{}:{})r   )r5   itemr   r   r   
<listcomp>   s     z)get_canonical_headers.<locals>.<listcomp>)r	   dictlistitemscollectionsdefaultdictlowerstripr4   splitappendsorted)headers
normalizedr6   r7   ordered_headerscanonical_headersr   r   r   get_canonical_headers   s    

rI   
_Canonicalmethodresourcequery_parametersrE   c                 C   sv   t |\}}| dkr"d} |d |dkr8t| |g |S tdd | D }tj|}| d| }t| |||S )ah  Canonicalize method, resource per the V2 spec.

    :type method: str
    :param method: The HTTP verb that will be used when requesting the URL.
                   Defaults to ``'GET'``. If method is ``'RESUMABLE'`` then the
                   signature will additionally contain the `x-goog-resumable`
                   header, and the method changed to POST. See the signed URL
                   docs regarding this flow:
                   https://cloud.google.com/storage/docs/access-control/signed-urls

    :type resource: str
    :param resource: A pointer to a specific resource
                     (typically, ``/bucket-name/path/to/blob.txt``).

    :type query_parameters: dict
    :param query_parameters:
        (Optional) Additional query parameters to be included as part of the
        signed URLs.  See:
        https://cloud.google.com/storage/docs/xml-api/reference-headers#query

    :type headers: Union[dict|List(Tuple(str,str))]
    :param headers:
        (Optional) Additional HTTP headers to be included as part of the
        signed URLs.  See:
        https://cloud.google.com/storage/docs/xml-api/reference-headers
        Requests using the signed URL *must* pass the specified header
        (name and value) with each request for the URL.

    :rtype: :class:_Canonical
    :returns: Canonical method, resource, query_parameters, and headers.
    	RESUMABLEPOSTzx-goog-resumable:startNc                 s   s*   | ]"\}}|  |r| pd fV  qdS ) N)r@   rA   r5   r6   valuer   r   r   r8      s   z"canonicalize_v2.<locals>.<genexpr>?)rI   rC   rJ   rD   r=   urllibparse	urlencode)rK   rL   rM   rE   _Znormalized_qpZ
encoded_qpZcanonical_resourcer   r   r   canonicalize_v2   s     
rX   rP   GETc                 C   s   t |}t||||
}|j|p d|p&dt|g}||j ||j d|}|rv|rvt	||||}|||d}nt
| ||}|dk	r||d< |dk	r||d< |	dk	r|	|d< ||j t| }dj||tj|d	S )
a  Generate a V2 signed URL to provide query-string auth'n to a resource.

    .. note::

        Assumes ``credentials`` implements the
        :class:`google.auth.credentials.Signing` interface. Also assumes
        ``credentials`` has a ``signer_email`` property which
        identifies the credentials.

    .. note::

        If you are on Google Compute Engine, you can't generate a signed URL.
        If you'd like to be able to generate a signed URL from GCE, you can use a
        standard service account from a JSON file rather than a GCE service account.

    See headers [reference](https://cloud.google.com/storage/docs/reference-headers)
    for more details on optional arguments.

    :type credentials: :class:`google.auth.credentials.Signing`
    :param credentials: Credentials object with an associated private key to
                        sign text.

    :type resource: str
    :param resource: A pointer to a specific resource
                     (typically, ``/bucket-name/path/to/blob.txt``).
                     Caller should have already URL-encoded the value.

    :type expiration: Union[Integer, datetime.datetime, datetime.timedelta]
    :param expiration: Point in time when the signed URL should expire. If
                       a ``datetime`` instance is passed without an explicit
                       ``tzinfo`` set,  it will be assumed to be ``UTC``.

    :type api_access_endpoint: str
    :param api_access_endpoint: (Optional) URI base. Defaults to empty string.

    :type method: str
    :param method: The HTTP verb that will be used when requesting the URL.
                   Defaults to ``'GET'``. If method is ``'RESUMABLE'`` then the
                   signature will additionally contain the `x-goog-resumable`
                   header, and the method changed to POST. See the signed URL
                   docs regarding this flow:
                   https://cloud.google.com/storage/docs/access-control/signed-urls


    :type content_md5: str
    :param content_md5: (Optional) The MD5 hash of the object referenced by
                        ``resource``.

    :type content_type: str
    :param content_type: (Optional) The content type of the object referenced
                         by ``resource``.

    :type response_type: str
    :param response_type: (Optional) Content type of responses to requests for
                          the signed URL. Ignored if content_type is set on
                          object/blob metadata.

    :type response_disposition: str
    :param response_disposition: (Optional) Content disposition of responses to
                                 requests for the signed URL.

    :type generation: str
    :param generation: (Optional) A value that indicates which generation of
                       the resource to fetch.

    :type headers: Union[dict|List(Tuple(str,str))]
    :param headers:
        (Optional) Additional HTTP headers to be included as part of the
        signed URLs.  See:
        https://cloud.google.com/storage/docs/xml-api/reference-headers
        Requests using the signed URL *must* pass the specified header
        (name and value) with each request for the URL.

    :type service_account_email: str
    :param service_account_email: (Optional) E-mail address of the service account.

    :type access_token: str
    :param access_token: (Optional) Access token for a service account.

    :type query_parameters: dict
    :param query_parameters:
        (Optional) Additional query parameters to be included as part of the
        signed URLs.  See:
        https://cloud.google.com/storage/docs/xml-api/reference-headers#query

    :raises: :exc:`TypeError` when expiration is not a valid type.
    :raises: :exc:`AttributeError` if credentials is not an instance
            of :class:`google.auth.credentials.Signing`.

    :rtype: str
    :returns: A signed URL you can use to access the resource
              until expiration.
    rP   
r   Nresponse-content-typeresponse-content-disposition
generationz"{endpoint}{resource}?{querystring})ZendpointrL   Zquerystring)r'   rX   rK   strextendrE   rC   rL   r4   _sign_messager    updaterM   rD   r=   r   rT   rU   rV   )r   rL   r   api_access_endpointrK   content_md5content_typeresponse_typeresponse_dispositionr]   rE   rM   service_account_emailaccess_tokenuniverse_domainZexpiration_stamp	canonicalZelements_to_signr   r   Zsigned_query_paramsZsorted_signed_query_paramsr   r   r   generate_signed_url_v2  sN    n
     
rk   i:	 zhttps://storage.googleapis.comc           %      C   sJ  t |}|dkrt \}}n|}|dd }|}|r8|sFt|  | j}| d}| d| }|
dkrji }
|dk	rz||
d< |dk	r||
d< dd |
D }d	|krtj|j|
d
< | dkrd}d|
d< t	|
\}}d
|d }d
dd |D }|dkri }ndd | D }d|d< ||d< ||d< ||d< ||d< |dk	rT||d< |dk	rf||d< |	dk	rx|	|d< t|}t|}d|kr|d }nd}||||||g}d
|}t|d } d||| g}!d
|!}"|r|rt|"|||}#t|#}$t|$d}#n | |"d}$t|$d}#d ||||#S )!a/  Generate a V4 signed URL to provide query-string auth'n to a resource.

    .. note::

        Assumes ``credentials`` implements the
        :class:`google.auth.credentials.Signing` interface. Also assumes
        ``credentials`` has a ``signer_email`` property which
        identifies the credentials.

    .. note::

        If you are on Google Compute Engine, you can't generate a signed URL.
        If you'd like to be able to generate a signed URL from GCE,you can use a
        standard service account from a JSON file rather than a GCE service account.

    See headers [reference](https://cloud.google.com/storage/docs/reference-headers)
    for more details on optional arguments.

    :type credentials: :class:`google.auth.credentials.Signing`
    :param credentials: Credentials object with an associated private key to
                        sign text. That credentials must provide signer_email
                        only if service_account_email and access_token are not
                        passed.

    :type resource: str
    :param resource: A pointer to a specific resource
                     (typically, ``/bucket-name/path/to/blob.txt``).
                     Caller should have already URL-encoded the value.

    :type expiration: Union[Integer, datetime.datetime, datetime.timedelta]
    :param expiration: Point in time when the signed URL should expire. If
                       a ``datetime`` instance is passed without an explicit
                       ``tzinfo`` set,  it will be assumed to be ``UTC``.

    :type api_access_endpoint: str
    :param api_access_endpoint: URI base. Defaults to
                                "https://storage.googleapis.com/"

    :type method: str
    :param method: The HTTP verb that will be used when requesting the URL.
                   Defaults to ``'GET'``. If method is ``'RESUMABLE'`` then the
                   signature will additionally contain the `x-goog-resumable`
                   header, and the method changed to POST. See the signed URL
                   docs regarding this flow:
                   https://cloud.google.com/storage/docs/access-control/signed-urls


    :type content_md5: str
    :param content_md5: (Optional) The MD5 hash of the object referenced by
                        ``resource``.

    :type content_type: str
    :param content_type: (Optional) The content type of the object referenced
                         by ``resource``.

    :type response_type: str
    :param response_type: (Optional) Content type of responses to requests for
                          the signed URL. Ignored if content_type is set on
                          object/blob metadata.

    :type response_disposition: str
    :param response_disposition: (Optional) Content disposition of responses to
                                 requests for the signed URL.

    :type generation: str
    :param generation: (Optional) A value that indicates which generation of
                       the resource to fetch.

    :type headers: dict
    :param headers:
        (Optional) Additional HTTP headers to be included as part of the
        signed URLs.  See:
        https://cloud.google.com/storage/docs/xml-api/reference-headers
        Requests using the signed URL *must* pass the specified header
        (name and value) with each request for the URL.

    :type query_parameters: dict
    :param query_parameters:
        (Optional) Additional query parameters to be included as part of the
        signed URLs.  See:
        https://cloud.google.com/storage/docs/xml-api/reference-headers#query

    :type service_account_email: str
    :param service_account_email: (Optional) E-mail address of the service account.

    :type access_token: str
    :param access_token: (Optional) Access token for a service account.

    :raises: :exc:`TypeError` when expiration is not a valid type.
    :raises: :exc:`AttributeError` if credentials is not an instance
            of :class:`google.auth.credentials.Signing`.

    :rtype: str
    :returns: A signed URL you can use to access the resource
              until expiration.
    N   z/auto/storage/goog4_request/zContent-TypezContent-MD5c                 S   s   g | ]}|  qS r   )r@   )r5   r6   r   r   r   r:   6  s     z*generate_signed_url_v4.<locals>.<listcomp>hostHostrN   rO   startzx-goog-resumablerZ   ;c                 S   s   g | ]\}}|qS r   r   )r5   r6   rW   r   r   r   r:   B  s     c                 S   s   i | ]\}}||pd qS )rP   r   rQ   r   r   r   
<dictcomp>G  s      z*generate_signed_url_v4.<locals>.<dictcomp>zGOOG4-RSA-SHA256zX-Goog-AlgorithmzX-Goog-CredentialzX-Goog-DatezX-Goog-ExpireszX-Goog-SignedHeadersr[   r\   r]   zx-goog-content-sha256zUNSIGNED-PAYLOADr   z{}{}?{}&X-Goog-Signature={})r1   get_v4_now_dtstampsr   r   rT   rU   urlparsenetlocupperrI   r4   r=   _url_encoder;   hashlibsha256r   	hexdigestr`   r   	b64decodebinasciihexlifydecoder   r   )%r   rL   r   rb   rK   rc   rd   re   rf   r]   rE   rM   rg   rh   ri   Z_request_timestampZexpiration_secondsZrequest_timestamp	datestampZclient_emailZcredential_scopeZ
credentialheader_namesrH   rG   Zcanonical_header_stringZsigned_headersZcanonical_query_stringZlowercased_headerspayloadZcanonical_elementsZcanonical_requestZcanonical_request_hashZstring_elementsr   r   r   r   r   r   generate_signed_url_v4  s    r








   
   r   c                  C   s0   t tjdd} | d}|  d}||fS )z~Get current timestamp and datestamp in V4 valid format.

    :rtype: str, str
    :returns: Current timestamp, datestamp.
    Nr(   z%Y%m%dT%H%M%SZz%Y%m%d)r   r   r+   strftimedate)r&   	timestampr   r   r   r   rs     s    
rs   c           	         s   t | } dd| d| dd| ddtdt| d	i t  fd
d}t	}||}| }|j
tjjkrtd|j t|jd	}|d S )a  Signs a message.

    :type message: str
    :param message: The message to be signed.

    :type access_token: str
    :param access_token: Access token for a service account.


    :type service_account_email: str
    :param service_account_email: E-mail address of the service account.

    :raises: :exc:`TransportError` if an `access_token` is unauthorized.

    :rtype: str
    :returns: The signature of the message.

    rO   zhttps://iamcredentials.z/v1/projects/-/serviceAccounts/z:signBlob?alt=jsonzBearer zapplication/json)AuthorizationzContent-typer   zutf-8c                     s    d} | S )N)urlrK   bodyrE   r   )responser   rE   rK   requestr   r   r   retriable_request  s    z(_sign_message.<locals>.retriable_requestz%Error calling the IAM signBytes API: Z
signedBlob)r   	_to_bytesjsondumpsr   r   r~   r   Requestr   statushttpclientOKr   ZTransportErrordataloads)	messagerh   rg   ri   r   retrycallr   r   r   r   r   r`     s$    

r`   c                 C   s    dd |   D }dt|S )zEncode query params into URL.

    :type query_params: dict
    :param query_params: Query params to be encoded.

    :rtype: str
    :returns: URL encoded query params.
    c                 S   s&   g | ]\}}t | d t | qS )=)_quote_param)r5   namerR   r   r   r   r:     s   z_url_encode.<locals>.<listcomp>&)r=   r4   rD   )Zquery_paramsparamsr   r   r   rw     s    	rw   c                 C   s"   t | tst| } tjj| ddS )zQuote query param.

    :type param: Any
    :param param: Query param to be encoded.

    :rtype: str
    :returns: URL encoded query param.
    ~)safe)r	   bytesr^   rT   rU   quote)paramr   r   r   r     s    	
r   )rP   rY   NNNNNNNNNN),r   r|   r>   r"   rx   r   r   rT   Zgoogle.auth.credentialsr
   Zgoogle.authr   Zgoogle.auth.transportr   Zgoogle.cloudr   Zgoogle.cloud.storage._helpersr   r   r   Zgoogle.cloud.storage.retryr   utcnowZNOWr   r   r    r'   r$   r#   r*   r1   rI   
namedtuplerJ   rX   rk   r.   ZDEFAULT_ENDPOINTr   rs   r`   rw   r   r   r   r   r   <module>   s   &% 
6            
 !
 ^
5