
    :                        d Z ddlmZ ddlm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	m
Z
 ddlmZ ddlmZ ddlZd	Zh d
ZdZdZ G d de
j(                        Z G d de      Z G d de      Z G d de      Z G d de      Zd Z G d d ej4                  ej6                  e            Z G d de      Z G d de      Z G d de      Z  G d  d!e      Z!d.d"Z" G d# d$e      Z# G d% d&e      Z$d' Z%d( Z&d) Z'd* Z(d+ Z)d, Z*d- Z+y)/zAUtility functions for managing customer supplied encryption keys.    )absolute_import)division)unicode_literalsN)
exceptions)	resources)
console_iozHhttps://cloud.google.com/compute/docs/disks/customer-supplied-encryption>   keyurikey-type,   iX  c                       e Zd ZdZy)ErrorzFBase exception for Csek(customer supplied encryption keys) exceptions.N)__name__
__module____qualname____doc__     0lib/googlecloudsdk/api_lib/compute/csek_utils.pyr   r   &   s    Nr   r   c                   "     e Zd ZdZ fdZ xZS )InvalidKeyFileExceptionz!There's a problem in a CSEK file.c                 J    t         t        |   dj                  |             y )Nz{0}
For information on proper key file format see: https://cloud.google.com/compute/docs/disks/customer-supplied-encryption#key_file)superr   __init__format)selfbase_message	__class__s     r   r   z InvalidKeyFileException.__init__-   s#    	
!41	006|0DFr   r   r   r   r   r   __classcell__r   s   @r   r   r   *   s    )F Fr   r   c                   "     e Zd ZdZ fdZ xZS )BadPatternExceptionz$A (e.g.) url pattern is bad and why.c                     || _         || _        t        t        |   dj                  | j                   | j                               y )Nz&Invalid value for [{0}] pattern: [{1}])pattern_typepatternr   r#   r   r   )r   r%   r&   r   s      r   r   zBadPatternException.__init__7   s@    $DDL	
t-077LL	r   r   r!   s   @r   r#   r#   4   s    , r   r#   c                   "     e Zd ZdZ fdZ xZS )InvalidKeyExceptionNoContextz.Indicate that a particular key is bad and why.c                     || _         || _        t        t        |   dj                  | j                   | j                               y )NzInvalid key, [{0}] : {1})r	   issuer   r(   r   r   )r   r	   r*   r   s      r   r   z%InvalidKeyExceptionNoContext.__init__C   s=    DHDJ	
&6"))HHJJ	r   r   r!   s   @r   r(   r(   @   s    6 r   r(   c                   "     e Zd ZdZ fdZ xZS )InvalidKeyExceptionz6Indicate that a particular key is bad, why, and where.c                     || _         || _        || _        t        t        |   dj                  | j                   | j                  | j                               y )Nz"Invalid key, [{0}], for [{1}]: {2})r	   key_idr*   r   r,   r   r   )r   r	   r.   r*   r   s       r   r   zInvalidKeyException.__init__O   sK    DHDKDJ	
t-,33HHKKJJ	r   r   r!   s   @r   r,   r,   L   s    > r   r,   c           	         |dk  rt        dj                  |            t        |       |k7  r%t        | dj                  |t        |                   | d   dk7  rt        | d      	 | j	                  d      }t        j                  d	|       st        |d
      	 t        j                  |       y# t
        $ r t        | d      w xY w# t        $ r*}t        | dj                  |j                              d}~ww xY w)zFValidateKey(s, k) returns None or raises InvalidKeyExceptionNoContext.   z6ValidateKey requires expected_key_length > 1.  Got {0}zTKey should contain {0} characters (including padding), but is [{1}] characters long.=z4Bad padding.  Keys should end with an '=' character.asciiz"Key contains non-ascii characters.z^[a-zA-Z0-9+/=]*$zKey contains unexpected characters. Base64 encoded strings contain only letters (upper or lower case), numbers, plusses '+', slashes '/', or equality signs '='.zKey is not valid base64: [{0}].N)
ValueErrorr   lenr(   encodeUnicodeDecodeErrorrematchbase64	b64decode	TypeErrormessage)base64_encoded_stringexpected_key_lengthbase64_encoded_string_as_strts       r   ValidateKeyrB   Z   s2    1
Mf013 3 		#66
&	((.%&)() ) 2#%
&@B B.#8#?#?#H  
&(=	>
&$	AB B=
12 
 .
&,. .. 
 =
&)00;= ==s$   (B2 C 2C	C>%C99C>c                       e Zd ZdZd Zedd       Zej                  d        Z	ej                  d        Z
ed        Zy)	CsekKeyBasez#A class representing for CSEK keys.c                 H    t        || j                                || _        y )N)r?   )rB   GetKeyLength_key_material)r   key_materials     r   r   zCsekKeyBase.__init__   s    $2C2C2EF%Dr   c                 t    |dk(  rt        |       S |dk(  r|rt        |       S t        |d      t        |      )a  Make a CSEK key.

    Args:
      key_material: str, the key material for this key
      key_type: str, the type of this key
      allow_rsa_encrypted: bool, whether the key is allowed to be RSA-wrapped

    Returns:
      CsekRawKey or CsekRsaEncryptedKey derived from the given key material and
      type.

    Raises:
      BadKeyTypeException: if the key is not a valid key type
    rawzrsa-encryptedzLthis feature is only allowed in the alpha and beta versions of this command.)
CsekRawKeyCsekRsaEncryptedKeyBadKeyTypeExceptionrH   key_typeallow_rsa_encrypteds      r   MakeKeyzCsekKeyBase.MakeKey   sO    " 5%%?"	"<00
 
 h
''r   c                     t        d      )Nz"GetKeyLength() must be overridden.NotImplementedErrorr   s    r   rF   zCsekKeyBase.GetKeyLength   s    
B
CCr   c                     ~t        d      )NzToMessage() must be overridden.rS   r   compute_clients     r   	ToMessagezCsekKeyBase.ToMessage   s    
?
@@r   c                     | j                   S N)rG   rU   s    r   rH   zCsekKeyBase.key_material   s    r   NF)r   r   r   r   r   staticmethodrQ   abcabstractmethodrF   rY   propertyrH   r   r   r   rD   rD      sj    +& ( (: D D A A  r   rD   c                       e Zd ZdZd Zd Zy)rK   z!Class representing raw CSEK keys.c                     t         S r[   )BASE64_RAW_KEY_LENGTH_IN_CHARSrU   s    r   rF   zCsekRawKey.GetKeyLength   s    ))r   c                 `    |j                   j                  t        | j                              S )N)rawKeyMESSAGES_MODULECustomerEncryptionKeystrrH   rW   s     r   rY   zCsekRawKey.ToMessage   s/    ))??4$$% @ ' 'r   Nr   r   r   r   rF   rY   r   r   r   rK   rK      s    )*'r   rK   c                       e Zd ZdZd Zd Zy)rL   z+Class representing rsa encrypted CSEK keys.c                     t         S r[   )(BASE64_RSA_ENCRYPTED_KEY_LENGTH_IN_CHARSrU   s    r   rF   z CsekRsaEncryptedKey.GetKeyLength   s    33r   c                 `    |j                   j                  t        | j                              S )N)rsaEncryptedKeyrf   rW   s     r   rY   zCsekRsaEncryptedKey.ToMessage   s/    ))??D--. @ 0 0r   Nrj   r   r   r   rL   rL      s    340r   rL   c                   $     e Zd ZdZd fd	Z xZS )rM   zA key type is bad and why.c                     || _         dj                  | j                         }|r|d|z   z  }|dz  }t        t        |   |       y )NzInvalid key type [{0}]z: .)rO   r   r   rM   r   )r   rO   explanationmsgr   s       r   r   zBadKeyTypeException.__init__   sI    DM
"
)
)$--
8C	TKc3JC	
t-c2r   ) r   r!   s   @r   rM   rM      s    "3 3r   rM   c                        e Zd Z fdZ xZS )MissingCsekExceptionc                 J    t         t        |   dj                  |             y )Nz0Key required for resource [{0}], but none found.)r   rw   r   r   )r   resourcer   s     r   r   zMissingCsekException.__init__   s"    	
.:AA(KMr   )r   r   r   r   r    r!   s   @r   rw   rw      s    M Mr   rw   c           	          | j                  dddj                  |t                     |r+| j                  dddd	j                  |t              
       yy)z$Adds arguments related to csek keys.z--csek-key-fileFILEaA        Path to a Customer-Supplied Encryption Key (CSEK) key file that maps
      Compute Engine {resource}s to user managed keys to be used when
      creating, mounting, or taking snapshots of disks.

      If you pass `-` as value of the flag, the CSEK is read from stdin.
      See {csek_help} for more details.
      )ry   	csek_help)metavarhelpz--require-csek-key-create
store_trueTa          Refuse to create {resource}s not protected by a user managed key in
        the key file when --csek-key-file is given. This behavior is enabled
        by default to prevent incorrect gcloud invocations from accidentally
        creating {resource}s with no user managed key. Disabling the check
        allows creation of some {resource}s without a matching
        Customer-Supplied Encryption Key in the supplied --csek-key-file.
        See {csek_help} for more details.
        )actiondefaultr~   N)add_argumentr   CSEK_HELP_URL)parserflags_about_creationresource_types      r   AddCsekKeyArgsr      sm    
 &-=&
A  
C 
# FM]FC  E r   c                   "    e Zd ZdZd Zd Zd Zy)
UriPatternzCA uri-based pattern that maybe be matched against resource objects.c                     |j                  d      st        d|      t        j                  j	                  |      j                         | _        y )Nhttpr
   )
startswithr#   r   REGISTRYParseURLRelativeName_path_as_string)r   path_as_strings     r   r   zUriPattern.__init__  sC    $$V,~66$--66$ 	r   c                 <    | j                   |j                         k(  S )z*Tests if its argument matches the pattern.)r   r   )r   ry   s     r   MatcheszUriPattern.Matches  s    8#8#8#:::r   c                      d| j                   z   S )NzUri Pattern: )r   rU   s    r   __str__zUriPattern.__str__  s    T1111r   N)r   r   r   r   r   r   r   r   r   r   r   r      s    K';2r   r   c                   Z    e Zd ZdZed        Zed	d       Zed	d       Zd Z	d	dZ
d	dZy)
CsekKeyStorez0Represents a map from resource patterns to keys.c                 B    t        j                  |d      } | ||      S )a  FromFile loads a CsekKeyStore from a file.

    Args:
      fname: str, the name of a file intended to contain a well-formed key file
      allow_rsa_encrypted: bool, whether to allow keys of type 'rsa-encrypted'

    Returns:
      A CsekKeyStore, if found

    Raises:
      googlecloudsdk.core.util.files.Error: If the file cannot be read or is
                                            larger than max_bytes.
    F)binary)r   ReadFromFileOrStdin)clsfnamerP   contents       r   FromFilezCsekKeyStore.FromFile  s$      ,,U5AGw+,,r   c                 \    | j                   yt        j                  | j                   |      S )a  FromFile attempts to load a CsekKeyStore from a command's args.

    Args:
      args: CLI args with a csek_key_file field set
      allow_rsa_encrypted: bool, whether to allow keys of type 'rsa-encrypted'

    Returns:
      A CsekKeyStore, if a valid key file name is provided as csek_key_file
      None, if args.csek_key_file is None

    Raises:
      exceptions.BadFileException: there's a problem reading fname
      exceptions.InvalidKeyFileException: the key file failed to parse
        or was otherwise invalid
    N)csek_key_filer   r   )argsrP   s     r   FromArgszCsekKeyStore.FromArgs)  s-    " !  !3!35HIIr   c           	          t        | t        j                        sJ i }	 t        j                  |       }t        |t
              st        d      |D ]  }t        |t              s-t        dj                  t        j                  |                  t        |j                               t        k7  rAt        dj                  t        j                  |      dj                  t                          t        |d         }	 t        j!                  |d   |d   |      ||<    	 t        |t              sJ |S # t"        $ r'}t%        |j&                  ||j(                  	      d
}~ww xY w# t*        $ r}t        |j,                   d
}~ww xY w)a.  _ParseAndValidate(s) inteprets s as a csek key file.

    Args:
      s: str, an input to parse
      allow_rsa_encrypted: bool, whether to allow RSA-wrapped keys

    Returns:
      a valid state object

    Raises:
      InvalidKeyFileException: if the input doesn't parse or is not well-formed.
    z1Key file's top-level element must be a JSON list.z7Key file records must be JSON objects, but [{0}] found.z4Record [{0}] has incorrect json keys; [{1}] expected,r
   r	   r   rN   )r	   r.   r*   N)
isinstancesixstring_typesjsonloadslistr   dictr   dumpssetkeysEXPECTED_RECORD_KEY_KEYSjoinr   rD   rQ   r(   r,   r	   r*   r4   r   )srP   staterecords
key_recordr&   es          r   _ParseAndValidatezCsekKeyStore._ParseAndValidate?  sy    a))***E-

1g&%@B 	B  **d+'GNN**Z(*+ + z !%=='DKK**Z(((3467 7
 Z./	N&..%e,z*7M"5 / 7%.  0 eT"""L , 	N#gQWWM
M	N  -#QVV,,-s<   C!E- !D:#E- :	E*"E%%E**E- -	F6FFc                 ,    t        | j                        S r[   )r5   r   rU   s    r   __len__zCsekKeyStore.__len__s  s    tzz?r   c           
      @   t        | j                  t              sJ d}t        j                  | j                        D ]H  \  }}|j                  |      s|d   r(t        dj                  |d   |t        |                  ||f}J |r|d   t        |      |d   S )a  Search for the unique key corresponding to a given resource.

    Args:
      resource: the resource to find a key for.
      raise_if_missing: bool, raise an exception if the resource is not found.

    Returns: CsekKeyBase, corresponding to the resource, or None if not found
      and not raise_if_missing.

    Raises:
      InvalidKeyFileException: if there are two records matching the resource.
      MissingCsekException: if raise_if_missing and no key is found
        for the provided resource.
    )NNr   zEUri patterns [{0}] and [{1}] both match resource [{2}].  Bailing out.r0   )
r   r   r   r   	iteritemsr   r   r   ri   rw   )r   ry   raise_if_missingsearch_statepatr	   s         r   	LookupKeyzCsekKeyStore.LookupKeyv  s      djj$'''LMM$**-S	X	?'..4fq/3H/78 8
 Sz . \!_4 **?r   c                 :    t         j                  ||      | _        y r[   )r   r   r   )r   json_stringrP   s      r   r   zCsekKeyStore.__init__  s    //0CEDJr   Nr\   )r   r   r   r   classmethodr   r]   r   r   r   r   r   r   r   r   r   r     sU    8 - -$ J J* 1 1f DEr   r   c                 ,    | r| j                  |      S d S r[   )rY   )csek_key_or_nonecomputes     r   MaybeToMessager     s    0@		#	#G	,JdJr   c                 .    | r|r| j                  |      S y r[   )r   )csek_keys_or_nonery   s     r   MaybeLookupKeyr     s    8&&x00	r   c                 2    t        | |      }t        ||      S r[   )r   r   )r   ry   rX   	maybe_keys       r   MaybeLookupKeyMessager     s    .9)		>	22r   c                 @    |D cg c]  }t        | |       c}S c c}w r[   )r   )r   resource_collectionrs      r   MaybeLookupKeysr     s$    8K	L8K1.*A
.8K	LL	Ls   c                 T    t        | |      D cg c]  }t        ||       c}S c c}w r[   )r   r   )r   r   rX   ks       r   MaybeLookupKeyMessagesr     s=     +-@
A
C
A 12.N
+
A
C C 
Cs   %c           	      f    t        | |D cg c]  }|r|j                  |      nd  c}      S c c}w r[   )r   Parse)r   r   urisus       r   MaybeLookupKeysByUrir     s6    	156A1Q$&6
8 86s   .
c                 V    t        | ||      D cg c]  }t        ||       c}S c c}w r[   )r   r   )r   r   r   rX   r   s        r   MaybeLookupKeyMessagesByUrir     s>     0&$
?
A
? 12.N
+
?
A A 
As   &)Try   ),r   
__future__r   r   r   r^   r:   r   r8   googlecloudsdk.api_lib.computer   googlecloudsdk.corer   googlecloudsdk.core.consoler   r   r   r   rc   rm   r   r   r#   r(   r,   rB   with_metaclassABCMetaobjectrD   rK   rL   rM   rw   r   r   r   r   r   r   r   r   r   r   r   r   r   <module>r      s2   H &  ' 
   	 5 ) 2 
05 !# +. (OJ OFe F	1 		#: 	1 '=T0$#$$S[[&9 0f' '0+ 0	31 	3M5 ME<2 2"KE6 KEbK3
MC8Ar   