o
    !dԜ                     @   s  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
mZ d dlmZmZ d dlm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 eeZd
ZdZdd Z dd Z!dd Z"dd Z#dd Z$dd Z%			d,ddZ&G dd de'Z(G dd de)Z*G dd de*Z+G d d! d!e*Z,G d"d# d#e'Z-G d$d% d%e'Z.G d&d' d'e'Z/G d(d) d)e'Z0G d*d+ d+eZ1dS )-    N)error)datetime	timedelta)tzparser)PyAsn1Error)get_trail_by_arnget_account_id_from_arn)BasicCommand)ClientError)ParameterRequiredErrorz%Y%m%dT%H%M%SZz%Y-%m-%dT%H:%M:%SZc                 C   
   |  tS )z;Returns a formatted date string in a CloudTrail date format)strftimeDATE_FORMATdate r   Ousr/lib/python3.10/site-packages/awscli/customizations/cloudtrail/validation.pyformat_date(      
r   c                 C   r   )z4Returns a formatted date string meant for CLI output)r   DISPLAY_DATE_FORMATr   r   r   r   format_display_date-   r   r   c                 C   s   | j t dS )z.Returns a normalized date using a UTC timezone)tzinfo)replacer   Ztzutcr   r   r   r   normalize_date2   s   r   c                 C   s   | dd S )zExtract the timestamp portion of a manifest file.

    Manifest file names take the following form:
    AWSLogs/{account}/CloudTrail-Digest/{region}/{ymd}/{account}_CloudTrail     -Digest_{region}_{name}_region_{date}.json.gz
    iir   )Zdigest_s3_keyr   r   r   extract_digest_key_date7   s   r   c                 C   s(   zt | W S  ty   td|  w )NzUnable to parse date value: %s)r   parse
ValueError)Zdate_stringr   r   r   
parse_dateA   s
   r   c                 C   s$   t d}|| std|  dS )zlEnsures that the arn looks correct.

    ARNs look like: arn:aws:cloudtrail:us-east-1:123456789012:trail/fooz$arn:.+:cloudtrail:.+:\d{12}:trail/.+zInvalid trail ARN provided: %sN)recompilematchr   )	trail_arnpatternr   r   r   assert_cloudtrail_arn_is_validH   s   

r$   c              	   C   s   t | d}|du r4t| |}td| |d }|dd}	|d}|r4|
s,td| d d }|d	d
 }|dd }|
sHt|}
t	|
|||||d}t
|||	|||t| dS )a  Creates a CloudTrail DigestTraverser and its object graph.

    :type cloudtrail_client: botocore.client.CloudTrail
    :param cloudtrail_client: Client used to connect to CloudTrail
    :type organization_client: botocore.client.organizations
    :param organization_client: Client used to connect to Organizations
    :type s3_client_provider: S3ClientProvider
    :param s3_client_provider: Used to create Amazon S3 client per/region.
    :param trail_arn: CloudTrail trail ARN
    :param trail_source_region: The scanned region of a trail.
    :param on_invalid: Callback that is invoked when validating a digest fails.
    :param on_gap: Callback that is invoked when a digest has no link to the
        previous digest, but there are more digests to validate. This can
        happen when a trail is disabled for a period of time.
    :param on_missing: Callback that is invoked when a digest file has been
        deleted from Amazon S3 but is supposed to be present.
    :param bucket: Amazon S3 bucket of the trail if it is different than the
        bucket that is currently associated with the trail.
    :param prefix: bucket: Key prefix prepended to each digest and log placed
        in the Amazon S3 bucket if it is different than the prefix that is
        currently associated with the trail.
    :param account_id: The account id for which the digest files are
        validated. For normal trails this is the caller account, for
        organization trails it is the member accout.

    ``on_gap``, ``on_invalid``, and ``on_missing`` callbacks are invoked with
    the following named arguments:

    - ``bucket`: The next S3 bucket.
    - ``next_key``: (optional) Next digest key that was found in the bucket.
    - ``next_end_date``: (optional) End date of the next found digest.
    - ``last_key``: The last digest key that was found.
    - ``last_start_date``: (optional) Start date of last found digest.
    - ``message``: (optional) Message string about the notification.
    NzLoaded trail info: %sZS3BucketNameZS3KeyPrefixZIsOrganizationTrailzAMissing required parameter for organization trail: '--account-id'ZOrganizationZId:   /)
account_id
trail_names3_client_providertrail_source_regiontrail_home_regionorganization_id)digest_providerstarting_bucketstarting_prefix
on_invalidon_gap
on_missingpublic_key_provider)r$   r   LOGdebuggetr   Zdescribe_organizationsplitr	   DigestProviderDigestTraverserPublicKeyProvider)cloudtrail_clientorganization_clientr+   r"   r,   r2   r3   r4   bucketprefixr)   r.   Z
trail_infoZis_org_trailZtrail_regionr*   r/   r   r   r   create_digest_traverserQ   sF   (

rA   c                   @   s2   e Zd ZdZdddZdd Zdd Zd	d
 ZdS )S3ClientProviderzCreates Amazon S3 clients and determines the region name of a client.

    This class will cache the location constraints of previously requested
    buckets and cache previously created clients for the same region.
    	us-east-1c                 C   s   || _ || _i | _i | _d S N)_session_get_bucket_location_region_client_cache_region_cache)selfsessionZget_bucket_location_regionr   r   r   __init__   s   
zS3ClientProvider.__init__c                 C   s   |  |}| |S )z=Creates an S3 client that can work with the given bucket name)_get_bucket_region_create_client)rI   bucket_nameregion_namer   r   r   
get_client   s   

zS3ClientProvider.get_clientc                 C   sB   || j vr| | j}|j|d}|d pd}|| j |< | j | S )zReturns the region of a bucket)BucketZLocationConstraintrC   )rH   rM   rF   Zget_bucket_location)rI   rN   clientresultregionr   r   r   rL      s   


z#S3ClientProvider._get_bucket_regionc                 C   s,   || j vr| jd|}|| j |< | j | S )z5Creates an Amazon S3 client for the given region nameZs3)rG   rE   create_client)rI   rO   rR   r   r   r   rM      s   


zS3ClientProvider._create_clientN)rC   )__name__
__module____qualname____doc__rK   rP   rL   rM   r   r   r   r   rB      s    
	rB   c                   @   s   e Zd ZdZdS )DigestErrorz0Exception raised when a digest fails to validateN)rV   rW   rX   rY   r   r   r   r   rZ      s    rZ   c                           e Zd ZdZ fddZ  ZS )DigestSignatureErrorz3Exception raised when a digest signature is invalidc                        d||f }t t| | d S )Nz=Digest file	s3://%s/%s	INVALID: signature verification failed)superr\   rK   rI   r?   keymessage	__class__r   r   rK      s   zDigestSignatureError.__init__rV   rW   rX   rY   rK   __classcell__r   r   rb   r   r\          r\   c                       r[   )InvalidDigestFormatz4Exception raised when a digest has an invalid formatc                    r]   )Nz.Digest file	s3://%s/%s	INVALID: invalid format)r^   rg   rK   r_   rb   r   r   rK      s   zInvalidDigestFormat.__init__rd   r   r   rb   r   rg      rf   rg   c                   @       e Zd ZdZdd Zdd ZdS )r<   z:Retrieves public keys from CloudTrail within a date range.c                 C   s
   || _ d S rD   )_cloudtrail_client)rI   r=   r   r   r   rK      s   
zPublicKeyProvider.__init__c                 C   s6   | j j||d}|d }td| tdd |D S )a  Loads public keys in a date range into a returned dict.

        :type start_date: datetime
        :param start_date: Start date of a date range.
        :type end_date: datetime
        :param end_date: End date of a date range.
        :rtype: dict
        :return: Returns a dict where each key is the fingerprint of the
            public key, and each value is a dict of public key data.
        )Z	StartTimeZEndTimeZPublicKeyListzLoaded public keys in range: %sc                 s   s    | ]	}|d  |fV  qdS )ZFingerprintNr   ).0r`   r   r   r   	<genexpr>   s    z4PublicKeyProvider.get_public_keys.<locals>.<genexpr>)ri   Zlist_public_keysr6   r7   dict)rI   
start_dateend_datepublic_keysZpublic_keys_in_ranger   r   r   get_public_keys   s   z!PublicKeyProvider.get_public_keysN)rV   rW   rX   rY   rK   rp   r   r   r   r   r<      s    r<   c                   @   s>   e Zd ZdZ		dddZdd Zdd Zd	d
 Zdd ZdS )r:   a5  
    Retrieves digest keys and digests from Amazon S3.

    This class is responsible for determining the full list of digest files
    in a bucket and loading digests from the bucket into a JSON decoded
    dict. This class is not responsible for validation or iterating from
    one digest to the next.
    Nc                 C   s,   || _ || _|| _|| _|p|| _|| _d S rD   )_client_providerr*   r)   r-   r,   r.   )rI   r+   r)   r*   r-   r,   r.   r   r   r   rK      s   

zDigestProvider.__init__c                 C   s   g }|  ||}| j|}|d}|j||d}	|	d}
tt|}tt|tdd }t	
| |}|
D ]}||rUt|}||krL |S ||krU|| q:|S )a  Returns a list of digest keys in the date range.

        This method uses a list_objects API call and provides a Marker
        parameter that is calculated based on the start_date provided.
        Amazon S3 then returns all keys in the bucket that start after
        the given key (non-inclusive). We then iterate over the keys
        until the date extracted from the yielded keys is greater than
        the given end_date.
        Zlist_objects)rQ   MarkerzContents[*].Key   )hours)_create_digest_keyrq   rP   Zget_paginatorZpaginatesearchr   r   r   r   r    _create_digest_key_regexr!   r   append)rI   r?   r@   rm   rn   digestsmarkerrR   Z	paginatorZpage_iteratorZ
key_filterZtarget_start_dateZtarget_end_dateZdigest_key_regexr`   Zextracted_dater   r   r   load_digest_keys_in_range  s*   




z(DigestProvider.load_digest_keys_in_rangec              	   C   s   | j |}|j||d}zt|d  tjdB }t|	 }W n t
tfy1   t||w d|d vs>d|d vrCt|||d d |d< |d d |d< ||fS )	zlLoads a digest by key from S3.

        Returns the JSON decode data and GZIP inflated raw content.
        rQ   KeyBody   	signatureZMetadatazsignature-algorithm
_signatureZ_signature_algorithm)rq   rP   
get_objectzlib
decompressread	MAX_WBITSjsonloadsdecoder   	ZLibErrorrg   r\   )rI   r?   r`   rR   rS   digestdigest_datar   r   r   fetch_digest#  s"   


zDigestProvider.fetch_digestc                 C   sz   |t dd }d}| jt||d| j| j| jd}| jr'|d7 }| j|d< |d7 }|jdi |}|r;|d	 | }|S )a~  Computes an Amazon S3 key based on the provided data.

        The computed is what would have been placed in the S3 bucket if
        a log digest were created at a specific time. This computed key
        does not have to actually exist as it will only be used to as
        a Marker parameter in a list_objects call.

        :return: Returns a computed key as a string.
        rs   )minutesAWSLogs/z%Y/%m/%d)r)   r   Zymdsource_regionhome_regionname{organization_id}/r.   z{account_id}/CloudTrail-Digest/{source_region}/{ymd}/{account_id}_CloudTrail-Digest_{source_region}_{name}_{home_region}_{date}.json.gzr'   Nr   )	r   r)   r   r   r,   r-   r*   r.   format)rI   rm   
key_prefixr   templatetemplate_paramsr`   r   r   r   ru   :  s&   
z!DigestProvider._create_digest_keyc                 C   s   d}t | jt | jt | jt | jd}| jr%|d7 }| j|d< |d7 }|jd
i |}|r<t |d | }d| d S )z:Creates a regular expression used to match against S3 keysr   )r)   r   r   r   r   r.   z{account_id}/CloudTrail\-Digest/{source_region}/\d+/\d+/\d+/{account_id}_CloudTrail\-Digest_{source_region}_{name}_{home_region}_.+\.json\.gzr'   ^$Nr   )r   escaper)   r,   r-   r*   r.   r   )rI   r   r   r   r`   r   r   r   rw   \  s    




z'DigestProvider._create_digest_key_regexNN)	rV   rW   rX   rY   rK   r{   r   ru   rw   r   r   r   r   r:      s    	

""r:   c                   @   s^   e Zd ZdZg dZ		dddZdddZdd	 Z	dddZdddZ	dd Z
dd ZdS )r;   z4Retrieves and validates digests within a date range.)digestPublicKeyFingerprintdigestS3BucketdigestS3ObjectpreviousDigestSignaturedigestEndTimedigestStartTimeNc	           	      C   sB   || _ || _|| _|| _|| _|| _|| _|du rt }|| _dS )a  
        :type digest_provider: DigestProvider
        :param digest_provider: DigestProvider object
        :param starting_bucket: S3 bucket where the digests are stored.
        :param starting_prefix: An optional prefix applied to each S3 key.
        :param public_key_provider: Provides public keys for a range.
        :param digest_validator: Validates digest using a validate method.
        :param on_invalid: Callback invoked when a digest is invalid.
        :param on_gap: Callback invoked when a digest has no parent, but
            there are still more digests to validate.
        :param on_missing: Callback invoked when a digest file is missing.
        N)	r0   r1   r/   _public_key_provider_on_gap_on_invalid_on_missingSha256RSADigestValidator_digest_validator)	rI   r/   r0   r1   r5   Zdigest_validatorr2   r3   r4   r   r   r   rK   {  s   
zDigestTraverser.__init__c                 c   s   |du r	t  }t|}t|}| j}| j}| ||||}| ||}| |\}}|}|r||krzA| |||\}	}tt	|	d }|	
dd}
|	V  |
du rb| j||||| jdd\}}n|	d }|
|krt|
}| ||||}W nt ty } z!|jd d d	kr|| j||||| jt|d
\}}W Y d}~nLd}~w ty } z| j||||| jt|d
\}}W Y d}~n+d}~w ty } z| j||||| jd||t|f d
\}}W Y d}~nd}~ww |r||ks4dS dS dS dS )aa  Creates and returns a generator that yields validated digest data.

        Each yielded digest dictionary contains information about the digest
        and the log file associated with the digest. Digest files are validated
        before they are yielded. Whether or not the digest is successfully
        validated is stated in the "isValid" key value pair of the yielded
        dictionary.

        :type start_date: datetime
        :param start_date: Date to start validating from (inclusive).
        :type start_date: datetime
        :param end_date: Date to stop validating at (inclusive).
        Nr   ZpreviousDigestS3BucketT)ry   r?   last_keylast_start_datecbis_cb_conditionalZpreviousDigestS3ObjectErrorCode	NoSuchKey)ry   r?   r   r   r   ra   z"Digest file	s3://%s/%s	INVALID: %s)r   utcnowr   r0   r1   _load_digests_load_public_keys_get_last_digest_load_and_validate_digestr   r8   _find_next_digestr   r   responser   strrZ   r   	Exception)rI   rm   rn   r?   r@   ry   ro   r`   r   r   Zprevious_bucketer   r   r   traverse  sz   
zDigestTraverser.traversec                 C   s   | j j||||dS )N)r?   r@   rm   rn   )r/   r{   )rI   r?   r@   rm   rn   r   r   r   r     s   zDigestTraverser._load_digestsFc           
      C   s8   |  ||\}}	|r|r|r|||||	||d ||	fS )z=Finds the next digest in the bucket and invokes any callback.)r?   next_keyr   next_end_dater   ra   )r   )
rI   ry   r?   r   r   r   r   ra   r   r   r   r   r   r     s   z!DigestTraverser._find_next_digestc                 C   s|   |sdS |du r|  }ttt|}||fS tt|}|r<|  }ttt|}||k r:td| ||fS |s dS )zFinds the previous digest key (either the last or before before_key)

        If no key is provided, the last digest is used. If a digest is found,
        the end date of the provider is adjusted to match the found key's end
        date.
        r   NzNext found key: %s)popr   r   r   r6   r7   )rI   ry   Z
before_keyr   Znext_key_dateZbefore_key_dater   r   r   r     s&   

z DigestTraverser._get_last_digestc           
      C   s   | j ||\}}| jD ]}||vrt||q|d |ks$|d |kr,td||f |d }||vr@td||| j j|f || d }| j||||| tt	|d }	||	fS )zLoads and validates a digest from S3.

        :param public_keys: Public key dictionary of fingerprint to dict.
        :return: Returns a tuple of the digest data as a dict and end_date
        :rtype: tuple
        r   r   zIDigest file	s3://%s/%s	INVALID: has been moved from its original locationr   zTDigest file	s3://%s/%s	INVALID: public key not found in region %s for fingerprint %sValuer   )
r/   r   required_digest_keysrg   rZ   r-   r   validater   r   )
rI   ro   r?   r`   r   r   Zrequired_keyZfingerprintZpublic_key_hexrn   r   r   r   r     s6   



z)DigestTraverser._load_and_validate_digestc                 C   s.   | j ||}|stdt|t|f |S )Nz&No public keys found between %s and %s)r   rp   RuntimeErrorr   )rI   rm   rn   ro   r   r   r   r     s   z!DigestTraverser._load_public_keys)NNNNrD   )NFN)rV   rW   rX   rY   r   rK   r   r   r   r   r   r   r   r   r   r   r;   s  s    

A


r;   c                   @   rh   )r   z
    Validates SHA256withRSA signed digests.

    The result of validating the digest is inserted into the digest_data
    dictionary using the isValid key value pair.
    c           	   	   C   s   z$t |}tjj|dd}| ||}t|d }t||| W dS  t	y6   t
d|||d f  tjjyC   t||w )a  Validates a digest file.

        Throws a DigestError when the digest is invalid.

        :param bucket: Bucket of the digest file
        :param key: Key of the digest file
        :param public_key: Public key bytes.
        :param digest_data: Dict of digest data returned when JSON
            decoding a manifest.
        :param inflated_digest: Inflated digest file contents as bytes.
        ZDER)r   r   zNDigest file	s3://%s/%s	INVALID: Unable to load PKCS #1 key with fingerprint %sr   N)base64	b64decodersaZ	PublicKeyZ
load_pkcs1_create_string_to_signbinascii	unhexlifyverifyr   rZ   Zpkcs1ZVerificationErrorr\   )	rI   r?   r`   Z
public_keyr   inflated_digestZdecoded_keyZto_signZsignature_bytesr   r   r   r   0  s   

z!Sha256RSADigestValidator.validatec                 C   sP   |d }|d u r
d}d|d |d |d t | |f }td| | S )Nr   nullz%s
%s/%s
%s
%sr   r   r   zDigest string to sign: %s)hashlibsha256	hexdigestr6   r7   encode)rI   r   r   Zprevious_signatureZstring_to_signr   r   r   r   N  s   z/Sha256RSADigestValidator._create_string_to_signN)rV   rW   rX   rY   r   r   r   r   r   r   r   (  s    r   c                       s   e Zd ZdZdZdZdddddd	ddd
ddddddddddddddddddddddgZ fddZ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d0d1 Zd2d3 Zd4d5 Zd6d7 Zd8d9 Zd:d; Z  ZS )=CloudTrailValidateLogszN
    Validates log digests and log files, optionally saving them to disk.
    zvalidate-logsa  
    Validates CloudTrail logs for a given period of time.

    This command uses the digest files delivered to your S3 bucket to perform
    the validation.

    The AWS CLI allows you to detect the following types of changes:

    - Modification or deletion of CloudTrail log files.
    - Modification or deletion of CloudTrail digest files.

    To validate log files with the AWS CLI, the following preconditions must
    be met:

    - You must have online connectivity to AWS.
    - You must have read access to the S3 bucket that contains the digest and
      log files.
    - The digest and log files must not have been moved from the original S3
      location where CloudTrail delivered them.
    - For organization trails you must have access to describe-organization to
      validate digest files

    When you disable Log File Validation, the chain of digest files is broken
    after one hour. CloudTrail will not digest log files that were delivered
    during a period in which the Log File Validation feature was disabled.
    For example, if you enable Log File Validation on January 1, disable it
    on January 2, and re-enable it on January 10, digest files will not be
    created for the log files delivered from January 3 to January 9. The same
    applies whenever you stop CloudTrail logging or delete a trail.

    .. note::

        Log files that have been downloaded to local disk cannot be validated
        with the AWS CLI. The CLI will download all log files each time this
        command is executed.

    .. note::

        This command requires that the role executing the command has
        permission to call ListObjects, GetObject, and GetBucketLocation for
        each bucket referenced by the trail.

    z	trail-arnTstringz.Specifies the ARN of the trail to be validated)r   requiredcli_type_name	help_textz
start-timezSpecifies that log files delivered on or after the specified UTC timestamp value will be validated. Example: "2015-01-08T05:21:42Z".zend-timezOptionally specifies that log files delivered on or before the specified UTC timestamp value will be validated. The default value is the current time. Example: "2015-01-08T12:31:41Z".)r   r   r   z	s3-bucketzOptionally specifies the S3 bucket where the digest files are stored. If a bucket name is not specified, the CLI will retrieve it by calling describe_trailsz	s3-prefixzOptionally specifies the optional S3 prefix where the digest files are stored. If not specified, the CLI will determine the prefix automatically by calling describe_trails.z
account-idzOptionally specifies the account for validating logs. This parameter is needed for organization trails for validating logs for specific account inside an organizationverboseZboolean
store_truez*Display verbose log validation information)r   r   actionr   c                    sz   t t| | d | _d| _d | _d | _d | _d | _d | _	d | _
d | _d | _d| _d| _d| _d| _d| _d | _d | _d S )NFr   T)r^   r   rK   r"   
is_verbose
start_timeend_time	s3_bucket	s3_prefixr+   r=   r)   _source_region_valid_digests_invalid_digests_valid_logs_invalid_logs_is_last_status_double_space_found_start_time_found_end_time)rI   rJ   rb   r   r   rK     s$   
zCloudTrailValidateLogs.__init__c                 C   s8   |  | | | |   | jdks| jdkrdS dS )Nr   rs   )handle_argssetup_services_callr   r   )rI   argsparsed_globalsr   r   r   	_run_main  s   

z CloudTrailValidateLogs._run_mainc                 C   s~   |j | _ |j| _|j| _|j| _|j| _tt|j| _|j	r(tt|j	| _	ntt
 | _	| j| j	kr9td| j| _d S )NzCInvalid time range specified: start-time must occur before end-time)r"   r   r   r   r   r)   r   r   r   r   r   r   r   r   )rI   r   r   r   r   r     s   z"CloudTrailValidateLogs.handle_argsc                 C   sj   |j | _t| j| j| _|j |jd}| jj	di || _|jd ur(|j|d< | jj	di || _	d S )N)rO   r   organizationsendpoint_url
cloudtrail)r   )r   )
rT   r   rB   rE   r+   Z
verify_sslrU   r>   r   r=   )rI   r   Zclient_argsr   r   r   r     s&   

z%CloudTrailValidateLogs.setup_servicesc                 C   s   t | j| j| j| j| j| j| j| j| j	| j
| jd}|   || j| j}|D ],}| | |  jd7  _| d|d |d f  |d sHq(|d D ]}| | qLq(|   d S )N)r"   r=   r>   r,   r+   r?   r@   r4   r2   r3   r)   rs   zDigest file	s3://%s/%s	validr   r   ZlogFiles)rA   r"   r=   r>   r   r+   r   r   _on_missing_digest_on_invalid_digest_on_digest_gapr)   _write_startup_textr   r   r   _track_found_timesr   _write_status_download_log_write_summary_text)rI   	traverserry   r   logr   r   r   r     s2   
zCloudTrailValidateLogs._callc                 C   sD   t |d }|| jkr|| _| js t |d }t|| j| _d S d S )Nr   r   )r   r   r   r   minr   )rI   r   Zdigest_start_timeZdigest_end_timer   r   r   r     s   
z)CloudTrailValidateLogs._track_found_timesc           
   
      s4  zi| j |d }|j|d |d d ttjdB }t }t fdddD ]}|	|}|
| q)| }|rA|
| | }||d krS| | W dS |  jd	7  _| d
|d |d f  W dS  ty }	 z|	jd d dkr{ | | W Y d}	~	dS d}	~	w ty   | | Y dS w )z9 Download a log, decompress, and compare SHA256 checksumss3Buckets3Objectr|   r   c                      s    d  dS )Nr~   i   )r   r   r   r   r   <lambda>  s    z6CloudTrailValidateLogs._download_log.<locals>.<lambda>    Z	hashValuers   zLog file	s3://%s/%s	validr   r   r   N)r+   rP   r   r   decompressobjr   r   r   iterr   updateflushr   _on_log_invalidr   r   r   r   _on_missing_logr   _on_invalid_log_format)
rI   r   rR   Zgzip_inflaterZrolling_hashchunkdataZremaining_dataZcomputed_hashr   r   r   r   r     s8   

z$CloudTrailValidateLogs._download_logFc                 C   sZ   |r| j rtjd|  ntjd|  d| _ d S | jr+d| _ tjd|  d S d S )Nz%s

z
%s

TFz%s
)r   sysstderrwriter   stdout)rI   ra   Zis_errorr   r   r   r   /  s   
z$CloudTrailValidateLogs._write_statusc                 C   s(   t jd| jt| jt| jf  d S )Nz5Validating log files for trail %s between %s and %s

)r  r  r  r"   r   r   r   rI   r   r   r   r   :  s   z*CloudTrailValidateLogs._write_startup_textc                 C   s   | j s	tjd tjdt| jt| jf  | js'| js'tjd d S | j	r-| j
s4tjd ntjdt| j	t| j
f  | | j| jd | | j| jd tjd d S )N
zResults requested for %s to %s
zNo digests found
z No valid digests found in range
zResults found for %s to %s:
r   r   )r   r  r  r  r   r   r   r   r   r   r   _write_ratior   r   r	  r   r   r   r   @  s(   z*CloudTrailValidateLogs._write_summary_textc                 C   sP   || }|dkr$t jd|||f  |dkr&t jd|||f  d S d S d S )Nr   z
%d/%d %s files validz, %d/%d %s files INVALID)r  r  r  )rI   validinvalidr   totalr   r   r   r  S  s   z#CloudTrailValidateLogs._write_ratioc                 K   s&   |  j d7  _ | d||f d d S )Nrs   z)Digest file	s3://%s/%s	INVALID: not foundTr   r   )rI   r?   r   kwargsr   r   r   r   [  s   z)CloudTrailValidateLogs._on_missing_digestc                 K   s(   |  dt|d t|d f d d S )Nz;No log files were delivered by CloudTrail between %s and %sr   r   T)r   r   )rI   r  r   r   r   r   `  s   

z%CloudTrailValidateLogs._on_digest_gapc                 K   s   |  j d7  _ | |d d S )Nrs   Tr  )rI   ra   r  r   r   r   r   f  s   z)CloudTrailValidateLogs._on_invalid_digestc                 C   .   |  j d7  _ | d|d |d f d d S )Nrs   z+Log file	s3://%s/%s	INVALID: invalid formatr   r   Tr   r   rI   Zlog_datar   r   r   r  j     z-CloudTrailValidateLogs._on_invalid_log_formatc                 C   r  )Nrs   z5Log file	s3://%s/%s	INVALID: hash value doesn't matchr   r   Tr  r  r   r   r   r   p  r  z&CloudTrailValidateLogs._on_log_invalidc                 C   r  )Nrs   z&Log file	s3://%s/%s	INVALID: not foundr   r   Tr  r  r   r   r   r  v  r  z&CloudTrailValidateLogs._on_missing_log)F)rV   rW   rX   rY   NAMEZDESCRIPTIONZ	ARG_TABLErK   r   r   r   r   r   r   r   r   r   r  r   r   r   r  r   r  re   r   r   rb   r   r   ]  sX    -
r   )NNNNNNN)2r   r   r   r   loggingr   r  r   r   r   r   r   Zdateutilr   r   Zpyasn1.errorr   r   Z&awscli.customizations.cloudtrail.utilsr   r	   Zawscli.customizations.commandsr
   Zbotocore.exceptionsr   Zawscli.schemar   	getLoggerrV   r6   r   r   r   r   r   r   r   r$   rA   objectrB   r   rZ   r\   rg   r<   r:   r;   r   r   r   r   r   r   <module>   sR   


N#  65