
    F/j1                         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 d dlmZ d dlmZ d dlmZmZ d dlmZ d	Z G d
 de      Z G d de      Z G d de      Zd ZeZy)    N)default_backend)ecutils)serialization)hashes)InvalidSignature)b64urldecodeb64urlencode)signzVAPID-RFC/ECE-RFCc                       e Zd ZdZy)VapidExceptionzAn exception wrapper for Vapid.N)__name__
__module____qualname____doc__     O/var/www/html/maxservice/venv/lib/python3.12/site-packages/py_vapid/__init__.pyr   r      s    )r   r   c                      e Zd ZdZdZdZdZddZed        Z	ed        Z
ed        Zed        Zedd	       Zed
        Zed        Zed        Zej$                  d        Zed        Zd Zd Zd Zd Zd Zd Zd ZddZy)Vapid01zwMinimal VAPID Draft 01 signature generation library.

    https://tools.ietf.org/html/draft-ietf-webpush-vapid-01

    NWebPushc                 l    |i }|| _         || _        |r | j                  j                         | _        yy)zInitialize VAPID with an optional private key.

        :param private_key: A private key object
        :type private_key: ec.EllipticCurvePrivateKey

        N)confprivate_key
public_key_public_key)selfr   r   s      r   __init__zVapid01.__init__+   s<     <D	&#//::<D r   c           	          t        j                  t        t        j                  t        |            d      t        j                         t                     } | |      S )a  Initialize VAPID using a private key point in "raw" or
        "uncompressed" form. Raw keys consist of a single, 32 octet
        encoded integer.

        :param private_raw: A private key point in uncompressed form.
        :type private_raw: bytes

           )curvebackend)r   derive_private_keyintbinasciihexlifyr	   	SECP256R1r   )clsprivate_rawkeys      r   from_rawzVapid01.from_raw9   sH     ##  k!:;R@,,.#%

 3xr   c                     t         j                  j                  t        j                         t	        |            } |        }||_        |S )N)r!   data)r   EllipticCurvePublicKeyfrom_encoded_pointr'   r	   r   )r(   
public_rawr*   sss       r   from_raw_publiczVapid01.from_raw_publicJ   sB    ''::,,.|J'? ; 
 U	r   c                 d    | j                  dj                  |j                         dd             S )zInitialize VAPID using a private key in PEM format.

        :param private_key: A private key in PEM format.
        :type private_key: bytes

        r      )from_derjoin
splitlines)r(   r   s     r   from_pemzVapid01.from_pemS   s,     ||CHH[%;%;%=a%CDEEr   c                 d    t        j                  t        |      dt                     } | |      S )zInitialize VAPID using a private key in DER format.

        :param private_key: A private key in DER format and Base64-encoded.
        :type private_key: bytes

        N)passwordr"   )r   load_der_private_keyr	   r   )r(   r   r*   s      r   r6   zVapid01.from_der^   s.     00%o>O
 3xr   c                 (   t         j                  j                  |      s?t        j                  d        |        }|j                          |j                  |       |S t        |d      5 }|j                         }ddd       	 dv r"| j                  |j                  d            }|S | j                  |j                  d            }|S # 1 sw Y   RxY w# t        $ r/}t        j                  dt        |             t        |      d}~ww xY w)zInitialize VAPID using a file containing a private key in PEM or
        DER format.

        :param private_key_file: Name of the file containing the private key
        :type private_key_file: str

        z(Private key not found, generating key...rNz
-----BEGINutf8z#Could not open private key file: %s)ospathisfilelogginginfogenerate_keyssave_keyopenreadr9   encoder6   	Exceptionerrorreprr   )r(   private_key_filevapidfiler   excs         r   	from_filezVapid01.from_filek   s     ww~~./LLCDEE!NN+,L"C( 	&D))+K	&	&{*[%7%7%?@ L [%7%7%?@L	& 	&  	&MM?cK %%	&s*   +C%C +!C C	D"*DDc                     |j                         j                  dd      }t        |      }t        |      dk(  r| j	                  |      S | j                  |      S )zInitialize VAPID using a string containing the private key. This
        will try to determine if the key is in RAW or DER format.

        :param private_key: String containing the key info
        :type private_key: str

           
r       )rI   replacer	   lenr+   r6   )r(   r   pkeyr*   s       r   from_stringzVapid01.from_string   sR     !!#++E374 s8r><<%%||D!!r   c                     |j                  dd      d   j                  dd      } |        j                  |j                               }|j                  |d   j                         |d         S )zVerify a VAPID authorization token.

        :param key: base64 serialized public key
        :type key: str
        :param auth: authorization token
        type key: str

         r4   .r   validation_tokenverification_token)rsplitr2   rI   verify_token)r(   r*   authtokenskps        r   verifyzVapid01.verify   sj     S!$Q'..sA6U""3::<0#AY--/F1I  
 	
r   c                 H    | j                   st        d      | j                   S )zThe VAPID private ECDSA keyz$No private key. Call generate_keys())_private_keyr   r   s    r   r   zVapid01.private_key   s%        !GHH   r   c                 V    || _         |r | j                  j                         | _        yy)zSet the VAPID private ECDSA key

        :param value: the byte array containing the private ECDSA key data
        :type value: ec.EllipticCurvePrivateKey

        N)rf   r   r   r   )r   values     r   r   zVapid01.private_key   s+     "#//::<D r   c                     | j                   S )a   The VAPID public ECDSA key

        The public key is currently read only. Set it via the `.private_key`
        method. This will autogenerate a public and private key if no value
        has been set.

        :returns ec.EllipticCurvePublicKey

        )r   rg   s    r   r   zVapid01.public_key   s     r   c                 n    t        j                  t        j                         t                     | _        y)z Generate a valid ECDSA Key Pair.N)r   generate_private_keyr'   r   r   rg   s    r   rE   zVapid01.generate_keys   s     222<<>?CTUr   c                     | j                   j                  t        j                  j                  t        j
                  j                  t        j                               S )N)encodingformatencryption_algorithm)r   private_bytesr   EncodingPEMPrivateFormatPKCS8NoEncryptionrg   s    r   private_pemzVapid01.private_pem   sJ    --"++// ..44!.!;!;!= . 
 	
r   c                     | j                   j                  t        j                  j                  t        j
                  j                        S )N)rn   ro   )r   public_bytesr   rr   rs   PublicFormatSubjectPublicKeyInforg   s    r   
public_pemzVapid01.public_pem   s<    ++"++// --BB , 
 	
r   c                     t        |d      5 }|j                  | j                                |j                          ddd       y# 1 sw Y   yxY w)zSave the private key to a PEM file.

        :param key_file: The file path to save the private key data
        :type key_file: str

        wbN)rG   writerw   closer   key_filerO   s      r   rF   zVapid01.save_key   sC     (D! 	TJJt'')*JJL	 	 	   0AAc                     t        |d      5 }|j                  | j                                |j                          ddd       y# 1 sw Y   yxY w)zSave the public key to a PEM file.
        :param key_file: The name of the file to save the public key
        :type key_file: str

        r~   N)rG   r   r|   r   r   s      r   save_public_keyzVapid01.save_public_key   sA     (D! 	TJJt()JJL	 	 	r   c                    t        |j                  d            }t        t        j                  |dd       d      }t        t        j                  |dd       d      }	 | j
                  j                  t        j                  ||      |t        j                  t        j                                      y# t        $ r Y yw xY w)aq  Internally used to verify the verification token is correct.

        :param validation_token: Provided validation token string
        :type validation_token: str
        :param verification_token: Generated verification token
        :type verification_token: str
        :returns: Boolean indicating if verifictation token is valid.
        :rtype: boolean

        r?   NrT   r    )signature_algorithmTF)r	   rI   r$   r%   r&   r   rd   ecutilsencode_dss_signaturer   ECDSAr   SHA256r   )r   r]   r^   hsigr>   ss         r   r`   zVapid01.verify_token   s     .55f=>  cr+R0  bc+R0	OO"",,Q2 $&HHV]]_$= # 
  		s    AB8 8	CCc                    t        j                  |      }|j                  d      s#t        t	        j                               dz   |d<   | j
                  j                  dd      st        |j                  dd            }n|j                  d      d u}|st        d      t        j                  d|j                  d	d      t        j                        st        d
      |S )NexpiQ z	no-strictFsub zGMissing 'sub' from claims. 'sub' is your admin email as a mailto: link.z^https?://[^/:]+(:\d+)?$audzyMissing 'aud' from claims. 'aud' is the scheme, host and optional port for this transaction e.g. https://example.com:8080)copydeepcopygetr$   timer   
_check_subr   rematch
IGNORECASE)r   claimscclaimsvalids       r   
_base_signzVapid01._base_sign  s    --'{{5! -5GENyy}}[%0w{{5"56EKK&d2E ?  xx'UB)?
 !< 
 r   c                 v   t        | j                  |      | j                        }d}|t        | j                  j                  t        j                  j                  t        j                  j                              z  }|r	|dz   |z   }n|}dj                  | j                  |j                  d            |dS )a  Sign a set of claims.
        :param claims: JSON object containing the JWT claims to use.
        :type claims: dict
        :param crypto_key: Optional existing crypto_key header content. The
            vapid public key will be appended to this data.
        :type crypto_key: str
        :returns: a hash containing the header fields to use in
            the subscription update.
        :rtype: dict

        z
p256ecdsa=;z{} {}=)Authorizationz
Crypto-Key)r   r   r   r
   r   ry   r   rr   X962rz   UncompressedPointro   _schemastripr   r   
crypto_keysigrW   s        r   r   zVapid01.sign  s     4??6*D,<,<=OO((&&++**<<
 	
 #c)D0JJ %^^DLL#))C.I$
 	
r   )NNN)r   r   r   r   rf   r   r   r   classmethodr+   r2   r9   r6   rQ   rX   rd   propertyr   setterr   rE   rw   r|   rF   r   r`   r   r   r   r   r   r   r       s    LKG=      F F 
 
 & &4 " " 
 
 ! ! 	= 	= 
  
 V

	0.
r   r   c                   ,    e Zd ZdZdZddZed        Zy)Vapid02zaMinimal Vapid RFC8292 signature generation library

    https://tools.ietf.org/html/rfc8292

    rN   Nc                 6   t        | j                  |      | j                        }| j                  j	                  t
        j                  j                  t
        j                  j                        }ddj                  | j                  |t        |            iS )a  Generate an authorization token

        :param claims: JSON object containing the JWT claims to use.
        :type claims: dict
        :param crypto_key: Optional existing crypto_key header content. The
            vapid public key will be appended to this data.
        :type crypto_key: str
        :returns: a hash containing the header fields to use in
            the subscription update.
        :rtype: dict
        r   z{schema} t={t},k={k})schematk)r   r   r   r   ry   r   rr   r   rz   r   ro   r   r
   r   s        r   r   zVapid02.signC  s     4??6*D,<,<=++""'')C)C)U)U
 3::||sl4.@ ; 
 	
r   c                    |j                  dd      }|d   j                         | j                  k(  sJ d       i }|d   j                  d      D ]  }|j                  dd      }|d   ||d   <   ! d|j	                         v sJ d       d	|j	                         v sJ d
        |        j                  |d   j                               }|d	   j                  dd      }|j                  |d   j                         |d         S )zEnsure that the token is correctly formatted and valid

        :param auth: An Authorization header
        :type auth: str
        :rtype: bool

        rZ   r4   r   zIncorrect schema specified,r   r   z!Auth missing public key 'k' valuer   z Auth missing token set 't' valuer[   r\   )r_   lowerr   splitkeysr2   rI   r`   )r(   ra   pref_tokpartstokkvrc   rb   s           r   rd   zVapid02.verifyY  s    ;;sA&{  "ckk1O3OO1A;$$S) 	!C3"Ba5E"Q%L	! ejjl"G$GG"ejjl"F$FF"U""5:#4#4#67s""3*#AY--/F1I  
 	
r   r   )r   r   r   r   r   r   r   rd   r   r   r   r   r   :  s'     G
, 
 
r   r   c                 T    d}t        j                  || t         j                        duS )a  Check to see if the `sub` is a properly formatted `mailto:`

    a `mailto:` should be a SMTP mail address. Mind you, since I run
    YouFailAtEmail.com, you have every right to yell about how terrible
    this check is. I really should be doing a proper component parse
    and valiate each component individually per RFC5341, instead I do
    the unholy regex you see below.

    :param sub: Candidate JWT `sub`
    :type sub: str
    :rtype: bool

    z^(mailto:.+@((localhost|[%\w-]+(\.[%\w-]+)+|([0-9a-f]{1,4}):+([0-9a-f]{1,4})?)))|https:\/\/(localhost|[\w-]+\.[\w\.-]+|([0-9a-f]{1,4}:+)+([0-9a-f]{1,4})?)$N)r   r   r   )r   patterns     r   r   r   q  s&     mG88GS"--0<<r   )r@   rC   r%   r   r   r   cryptography.hazmat.backendsr   )cryptography.hazmat.primitives.asymmetricr   r   r   cryptography.hazmat.primitivesr   r   cryptography.exceptionsr   py_vapid.utilsr	   r
   py_vapid.jwtr   VERSIONrJ   r   objectr   r   r   Vapidr   r   r   <module>r      si   
 
    	  8 J 8 1 4 5  	Y 	W
f W
t4
g 4
n=$ 	r   