
    g7                        d dl Z d dlZd dlZd dlZd dlmZ g dZ ej                  dej                        Z
 ej                  dej                        Z ej                  d      Zej                  j                  d      Zej                  j                  d      Z G d d	ej                  j"                        Z G d
 de      Z G d d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y)    N)GNTPRegister
GNTPNoticeGNTPSubscribeGNTPOK	GNTPError
parse_gntpzGNTP/(?P<version>\d+\.\d+) (?P<messagetype>REGISTER|NOTIFY|SUBSCRIBE|\-OK|\-ERROR) (?P<encryptionAlgorithmID>[A-Z0-9]+(:(?P<ivValue>[A-F0-9]+))?) ?((?P<keyHashAlgorithmID>[A-Z0-9]+):(?P<keyHash>[A-F0-9]+).(?P<salt>[A-F0-9]+))?
zRGNTP/(?P<version>\d+\.\d+) (?P<messagetype>REGISTER|NOTIFY|SUBSCRIBE|\-OK|\-ERROR)z([\w-]+):(.+)
z: c                       e Zd ZdZddZd Zy)_GNTPBufferzGNTP Buffer classNc                     |r.| j                  t        j                  j                  |             | j                  t               y N)writegntpshimbGNTP_EOL)selfvalues     /opt/Tautulli/lib/gntp/core.pywritelnz_GNTPBuffer.writeln)   s*    
::diikk% !**X    c                 F   t        |t              st        |      }| j                  t        j                  j                  |             | j                  t               | j                  t        j                  j                  |             | j                  t               y r   )
isinstancestrr   r   r   r   GNTP_SEPr   r   keyr   s      r   writeheaderz_GNTPBuffer.writeheader.   s_    	E3	u:5**TYY[[**X**TYY[[ **Xr   r   )__name__
__module____qualname____doc__r   r    r   r   r   r   '   s    
r   r   c                       e Zd ZdZddZej                  j                  rd Znd Zd Z	ddZ
d Zd	 Zd
 Zd Zd Zd Zd Zd ZddZd Zy)	_GNTPBasezBase initilization

	:param string messagetype: GNTP Message type
	:param string version: GNTP Protocol version
	:param string encription: Encryption protocol
	Nc                     |||d| _         t        j                  t        j                  t        j                  t        j
                  d| _        i | _        i | _        y )N)versionmessagetypeencryptionAlgorithmID)MD5SHA1SHA256SHA512)	infohashlibmd5sha1sha256sha512	hash_algoheaders	resources)r   r(   r'   
encryptions       r   __init__z_GNTPBase.__init__>   sK    &$) ++<<^^^^	$. $,$.r   c                 "    | j                         S r   )encoder   s    r   __str__z_GNTPBase.__str__Q   s    
++-r   c                 \    t         j                  j                  | j                               S r   )r   r   ur:   r;   s    r   r<   z_GNTPBase.__str__T   s    
))++dkkm
$$r   c                     t         j                  |      }|st        j                  d      |j	                         }|d   dk(  rd|d<   |S )zParse the first line of a GNTP message to get security and other info values

		:param string data: GNTP Message
		:return dict: Parsed GNTP Info line
		ERROR_PARSING_INFO_LINEr)   NONEN)GNTP_INFO_LINEmatcherrors
ParseError	groupdict)r   datarC   r.   s       r   _parse_infoz_GNTPBase._parse_infoW   sS     

t
$%				4	55		$	
!"f,#'4 	+r   c                 >   |sd| j                   d<   d| j                   d<   yt        j                  j                  |      | _        |j                         | _        | j                  | j                  vr"t        j                  d| j                  z        | j                  j                  | j                        }|j                  d      }t        j                         j                  d      } ||      j                         } ||      j                         }||z   } ||      j                         } ||      j                         }	| j                  | j                   d<   |	j                         | j                   d<   |j                         | j                   d<   y)	zSet a password for a GNTP Message

		:param string password: Null to clear password
		:param string encryptAlgo: Supports MD5, SHA1, SHA256, SHA512
		Nr)   keyHashAlgorithmzINVALID HASH "%s"utf8keyHashAlgorithmIDkeyHashsalt)r.   r   r   r   passwordupperencryptAlgor4   rD   UnsupportedErrorgetr:   timectime	hexdigestdigest)
r   rO   rQ   hashfunctionseedrN   saltHashkeyBasisr   rM   s
             r   set_passwordz_GNTPBase.set_passwordi   sM    
(,499$%#'499 	))++h'$- &&($			T^^	+		 	 !4t7G7G!G	HH##D$4$45,__V$(			V	$$	d		%	%	'$$&&(( (X%%'#'')'$($4$4$)) ! $))Ijjl$))Fr   c                     d}t        dt        |      d      D ]"  }t        |||dz    d      }|t        |      z  }$ |S )zHelper function to decode hex string to `proper` hex string

		:param string value: Human readable hex string
		:return string: Hex string
		 r         )rangelenintchr)r   r   resultitmps        r   _decode_hexz_GNTPBase._decode_hex   sP     &CJ" a	U1QU^R	 3	SX6 
-r   c                    |dz  }t        |d         }| j                  j                  |      t        |      z   }||z   }| j                  || }t        |      |k(  s$t	        j
                  d|dt        |            |S )N

LengthzINVALID_DATA_LENGTH Expected: z
 Recieved )rc   rawfindrb   rD   rE   )r   rawIdentifier
identifier
dataLengthpointerStart
pointerEndrG   s          r   _decode_binaryz_GNTPBase._decode_binary   s    :-:h'(*}-M0BB,j(*	,z	*$	Tj	 			ZY\]aYbc	dd	+r   c                    || _         |t        j                  d      | j                  j	                  dd      }|| j                   y|t        j                  d      | j                   t        j                  d      | j                  j	                  dd      }| j                   j                  d      }| j                  | j                  d	         }||z   } | j                  |   |      j                         | _	         | j                  |   | j                        j                         }|j                         | j                  d   j                         k(  st        j                  d
      y)z-Validate GNTP Message against stored passwordNzMissing passwordrM   TzInvalid keyHashrL   r*   rK   rN   zInvalid Hash)rO   rD   	AuthErrorr.   rS   r:   rh   r4   rW   r   rV   rP   )r   rO   rM   rL   rZ   r[   s         r   _validate_passwordz_GNTPBase._validate_password   s>   $-			,	--IIMM)T*'_.
_			+	,,	]]			,	--yy}}%9%@]]!!&)(dii/0( (/T^^./9@@B$(.DNN-.txx8BBD'	DIIi0668	8			.	))	r   c                     | j                   D ]6  }| j                  j                  |d      r t        j                  d|z          y)zVerify required headersFMissing Notification Header: N)_requiredHeadersr5   rS   rD   rE   )r   headers     r   validatez_GNTPBase.validate   sD    %% Ff
,,

65
)


;fD
EEFr   c           	      "   d| j                   j                  d      d| j                   j                  d      }| j                   j                  dd      r>|d| j                   j                  d      d| j                   j                  d      z  }n|d	z  }| j                   j                  d
d      rY|d| j                   j                  d
      d| j                   j                  d      d| j                   j                  d      z  }|S )z9Generate info line for GNTP Message

		:return string:
		zGNTP/r'    r(   r)   N:ivValuez NONErL   rM   .rN   )r.   rS   )r   r.   s     r   _format_infoz_GNTPBase._format_info   s     99==99==
$ 
YY]]*D1IIMM)*IIMM) 4
 7?4	YY]]'.IIMM&'IIMM)IIMM& 4 
+r   c                     i }|j                  d      D ]]  }t        j                  |      }|s|j                  d      j	                         }|j                  d      j	                         }|||<   _ |S )zHelper function to parse blocks of GNTP headers into a dictionary

		:param string data:
		:return dict: Dictionary of parsed GNTP Headers
		r	      r_   )splitGNTP_HEADERrC   groupstrip)r   rG   dlinerC   r   vals          r   _parse_dictz_GNTPBase._parse_dict   ss     	!jj  dT"5
	Q			3	Q			31S6 
(r   c                 "    || j                   |<   y r   )r5   r   s      r   
add_headerz_GNTPBase.add_header   s    $,,sr   c                     t         j                  j                  |      }t        j                  |      j                         }|| j                  |<   d|z  S )z9Add binary resource

		:param string data: Binary Data
		zx-growl-resource://%s)r   r   r   r/   r0   rV   r6   )r   rG   ro   s      r   add_resourcez_GNTPBase.add_resource   sF    
 
T	${{4 **,*#$..	 :	--r   c                    || _         t        j                  j                  |      | _        | j                  j                  d      }| j                  | j                        | _        | j                  |d         | _	        y)z-Decode GNTP Message

		:param string data:
		rj   r   N)
rO   r   r   r>   rl   r   rH   r.   r   r5   )r   rG   rO   partss       r   decodez_GNTPBase.decode   s]    
 $-YY[[$(
((..
$%txx($)!!%(+$,r   c                    t               }|j                  | j                                | j                  j	                         D ]  \  }}|j                  ||        |j                          | j                  j	                         D ]s  \  }}|j                  d|       |j                  dt        |             |j                          |j                  |       |j                          |j                          u |j                         S )zlEncode a generic GNTP Message

		:return string: GNTP Message ready to be sent. Returned as a byte string
		
Identifierrk   )
r   r   r   r5   itemsr   r6   rb   r   getvalue)r   buffkvresourcerG   s         r   r:   z_GNTPBase.encode  s     
$,,t  "# ll  " daAq,,. ,,. nhL(+Hc$i(<<>::d<<><<> 
r   )Nz1.0N)r*   r   )r   r    r!   r"   r8   r   r   PY2r<   rH   r\   rh   rs   rv   r{   r   r   r   r   r   r:   r#   r   r   r%   r%   7   s`    $ 	IIMM%$#>
4F4".	,r   r%   c                   @    e Zd ZdZddgZdgZddZd Zd Zdd	Z	d
 Z
y)r   zRepresents a GNTP Registration Command

	:param string data: (Optional) See decode()
	:param string password: (Optional) Password to use while encoding/decoding messages
	Application-NameNotifications-CountNotification-NameNc                     t         j                  | d       g | _        |r| j                  ||       y | j	                  |       | j                  dd       | j                  dd       y )NREGISTERr   pygntpr   r   )r%   r8   notificationsr   r\   r   r   rG   rO   s      r   r8   zGNTPRegister.__init__(  sW    T:&$	;;tXX??%x0??(!,r   c                 &   | j                   D ]6  }| j                  j                  |d      r t        j                  d|z          | j
                  D ]=  }| j                  D ],  }|j                  |d      rt        j                  d|z          ? y)z;Validate required headers and validate notification headersFzMissing Registration Header: rx   N)ry   r5   rS   rD   rE   r   _requiredNotificationHeaders)r   rz   notices      r   r{   zGNTPRegister.validate3  s    %% Ff
,,

65
)


;fD
EEF "" Gf22 Gv::fe$<vEFFGGr   c                 z   t         j                  j                  |      | _        | j                  j	                  d      }| j                  | j                        | _        | j                  |       | j                  |d         | _	        t        |      D ]  \  }}|dk(  r|j                         dk(  r | j                  |      }|j                  dd      r| j                  j                  |       _|j                  dd      sr| j                  ||      |d<   || j                   |j                  d      <    y)	zUDecode existing GNTP Registration message

		:param string data: Message to decode
		rj   r   r^   r   Fr   DataN)r   r   r>   rl   r   rH   r.   rv   r   r5   	enumerater   rS   r   appendrs   r6   r   rG   rO   r   rf   partr   s          r   r   zGNTPRegister.decode=  s   
 YY[[$(
((..
$%txx($)(#!!%(+$,5! 6ga1f
jjlbT"6jj$e,f%

<'((v6F6N/5DNN6::l+,6r   c                     i }||d<   ||d<   | j                   j                  |       | j                  dt        | j                                y)zAdd new Notification to Registration message

		:param string name: Notification Name
		:param boolean enabled: Enable this notification by default
		r   zNotification-Enabledr   N)r   r   r   rb   )r   nameenabledr   s       r   add_notificationzGNTPRegister.add_notificationU  sM     & $&	#*&	 F#//'T-?-?)@Ar   c                    t               }|j                  | j                                | j                  j	                         D ]  \  }}|j                  ||        |j                          t        | j                        dkD  rK| j                  D ]<  }|j	                         D ]  \  }}|j                  ||        |j                          > | j                  j	                         D ]s  \  }}|j                  d|       |j                  dt        |             |j                          |j                  |       |j                          |j                          u |j                         S )zuEncode a GNTP Registration Message

		:return string: Encoded GNTP Registration message. Returned as a byte string
		r   r   rk   )r   r   r   r5   r   r   rb   r   r6   r   r   )r   r   r   r   r   r   rG   s          r   r:   zGNTPRegister.encodeb  s2    
$,,t  "# ll  " daAq,,. 			q ## v 1	aLLN ,,. nhL(+Hc$i(<<>::d<<><<> 
r   NN)T)r   r    r!   r"   ry   r   r8   r{   r   r   r:   r#   r   r   r   r     s=      "5 5	-G60Br   r   c                   &    e Zd ZdZg dZddZd Zy)r   aM  Represents a GNTP Notification Command

	:param string data: (Optional) See decode()
	:param string app: (Optional) Set Application-Name
	:param string name: (Optional) Set Notification-Name
	:param string title: (Optional) Set Notification Title
	:param string password: (Optional) Password to use while encoding/decoding messages
	)r   r   Notification-TitleNc                     t         j                  | d       |r| j                  ||       y | j                  |       |r| j	                  d|       |r| j	                  d|       |r| j	                  d|       y y )NNOTIFYr   r   r   )r%   r8   r   r\   r   )r   rG   appr   titlerO   s         r   r8   zGNTPNotice.__init__  sl    T8$	;;tXX	OO&,
OO'.OO(%0 r   c                    t         j                  j                  |      | _        | j                  j	                  d      }| j                  | j                        | _        | j                  |       | j                  |d         | _	        t        |      D ]v  \  }}|dk(  r|j                         dk(  r | j                  |      }|j                  dd      sD| j                  ||      |d<   || j                  |j                  d      <   x y)zVDecode existing GNTP Notification message

		:param string data: Message to decode.
		rj   r   r^   r   Fr   N)r   r   r>   rl   r   rH   r.   rv   r   r5   r   r   rS   rs   r6   r   s          r   r   zGNTPNotice.decode  s    
 YY[[$(
((..
$%txx($)(#!!%(+$,5! 	6ga1f
jjlbT"6jju%((v6F6N/5DNN6::l+,	6r   )NNNNN)r   r    r!   r"   ry   r8   r   r#   r   r   r   r     s    16r   r   c                        e Zd ZdZddgZddZy)r   zRepresents a GNTP Subscribe Command

	:param string data: (Optional) See decode()
	:param string password: (Optional) Password to use while encoding/decoding messages
	zSubscriber-IDzSubscriber-NameNc                 |    t         j                  | d       |r| j                  ||       y | j                  |       y )N	SUBSCRIBE)r%   r8   r   r\   r   s      r   r8   zGNTPSubscribe.__init__  s1    T;'	;;tXXr   r   r   r    r!   r"   ry   r8   r#   r   r   r   r     s     
r   r   c                       e Zd ZdZdgZddZy)r   zRepresents a GNTP OK Response

	:param string data: (Optional) See _GNTPResponse.decode()
	:param string action: (Optional) Set type of action the OK Response is for
	Response-ActionNc                     t         j                  | d       |r| j                  |       |r| j                  d|       y y )N-OKr   r%   r8   r   r   )r   rG   actions      r   r8   zGNTPOK.__init__  s8    T5!	;;t??$f- r   r   r   r#   r   r   r   r     s    
 ''.r   r   c                   &    e Zd ZdZddgZddZd Zy)r   zRepresents a GNTP Error response

	:param string data: (Optional) See _GNTPResponse.decode()
	:param string errorcode: (Optional) Error code
	:param string errordesc: (Optional) Error Description
	
Error-CodeError-DescriptionNc                     t         j                  | d       |r| j                  |       |r%| j                  d|       | j                  d|       y y )N-ERRORr   r   r   )r   rG   	errorcode	errordescs       r   r8   zGNTPError.__init__  sF    T8$	;;t??<+??&	2 r   c                 r    | j                   j                  dd       | j                   j                  dd       fS )Nr   r   )r5   rS   r;   s    r   errorzGNTPError.error  s5    
,,

<
.<<'.
0 0r   )NNN)r   r    r!   r"   ry   r8   r   r#   r   r   r   r     s     "#6730r   r   c                    t         j                  j                  |       } t        j	                  |       }|st        j                  d      |j                         }|d   dk(  rt        | |      S |d   dk(  rt        | |      S |d   dk(  rt        | |      S |d   dk(  rt        |       S |d   dk(  rt        |       S t        j                  d	      )
zAttempt to parse a message as a GNTP message

	:param string data: Message to be parsed
	:param string password: Optional password to be used to verify the message
	INVALID_GNTP_INFOr(   r   )rO   r   r   r   r   INVALID_GNTP_MESSAGE)r   r   r>   GNTP_INFO_LINE_SHORTrC   rD   rE   rF   r   r   r   r   r   )rG   rO   rC   r.   s       r   r   r     s     			D		#	#D	)-..:%	dX	..
=X%	D8	,,
=[(	th	//
=U"	
=X%	4/00r   r   )r/   rerT   	gntp.shimr   gntp.errorsrD   __all__compile
IGNORECASErB   r   r   r   r   r   r   StringIOr   objectr%   r   r   r   r   r   r   r#   r   r   <module>r      s     	    W 	 "rzzU 
 bjj)99;;v99;;t$))$$  b bJe9 eP16 16hI &.Y . 0	 0,1r   