Ë
    «<ié  ã                  ó.  — d 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Zddl	Zddl
m
Z
mZmZ ddlmZmZ  ej                   e«      Z G d„ de«      Zdd„Zdd	„Zdd
„Zdddddœ	 	 	 	 	 	 	 	 	 	 	 	 	 dd„Zdd„Z	 d	 	 	 	 	 	 	 dd„Z	 	 d	 	 	 	 	 	 	 	 	 	 	 dd„Zy)zFHelpers for validating Telegram Web App initData and sending messages.é    )ÚannotationsN)ÚdatetimeÚ	timedeltaÚtimezone)ÚAnyÚMappingc                  ó   — e Zd ZdZy)ÚTelegramDataValidationErrorz/Raised when Telegram initData fails validation.N)Ú__name__Ú
__module__Ú__qualname__Ú__doc__© ó    ú?/home/cursorai/projects/telegram-earn/backend/utils/telegram.pyr
   r
      s   „ Ú9r   r
   c                óž   — t         j                  j                  | d¬«      }|j                  «       D ��ci c]  \  }}||d   “Œ c}}S c c}}w )z?Parse the initData query string into a flat dict of str -> str.F)Ústrict_parsingr   )ÚurllibÚparseÚparse_qsÚitems)Ú	init_dataÚ	parsed_qsÚkeyÚvaluess       r   Úparse_init_datar      sH   € ä—‘×%Ñ% iÀÐ%ÓF€IØ.7¯o©oÔ.?Ô@Ñ.?™{˜s FˆC�˜‘‰NÐ.?Ò@Ð@ùÓ@s   µA	c                óf   ‡ — dj                  ˆ fd„t        ‰ j                  «       «      D «       «      S )z¬
    Construct the data_check_string from parsed initData dict.

    This follows Telegram's requirement of alphabetical key sorting and
    excludes the `hash` field.
    Ú
c              3  ó<   •K  — | ]  }|d k7  r|› d‰|   › �–— Œ y­w)ÚhashÚ=Nr   )Ú.0r   Úparsed_datas     €r   Ú	<genexpr>z*build_data_check_string.<locals>.<genexpr>#   s1   øè ø€ ð á-ˆCØ�&Š=ð ˆ%ˆq�˜SÑ!Ð"Ô#Ù-ùs   ƒ)ÚjoinÚsortedÚkeys)r#   s   `r   Úbuild_data_check_stringr(      s1   ø€ ð �9‰9ó ä˜+×*Ñ*Ó,Ô-óó ð r   c                ó   — |st        d«      ‚t        j                  |j                  «       «      j	                  «       }t        j                  || j                  «       t        j                  «      j                  «       S )z8Calculate the HMAC-SHA-256 hash for a data_check_string.úBot token not configured)r
   ÚhashlibÚsha256ÚencodeÚdigestÚhmacÚnewÚ	hexdigest)Údata_check_stringÚ	bot_tokenÚ
secret_keys      r   Úcalculate_init_data_hashr5   *   s[   € áÜ)Ð*DÓEÐEä—‘ 	× 0Ñ 0Ó 2Ó3×:Ñ:Ó<€JÜ�8‰8�JÐ 1× 8Ñ 8Ó :¼G¿N¹NÓK×UÑUÓWÐWr   )Ú	auth_dateÚquery_idÚstart_paramÚextra_paramsc           
     ó<  — |st        d«      ‚i }|r<|j                  |j                  «       D ��ci c]  \  }}|t        |«      “Œ c}}«       |j	                  dt        j                  | «      «       |j	                  dt        |xs: t        t        j                  t        j                  «      j                  «       «      «      «       |r||d<   |r||d<   t        |«      }	t        |	|«      |d<   t        j                   j#                  |«      |	|d   dœS c c}}w )zó
    Build a signed initData string that mirrors Telegram's format.

    Returns a dict containing:
    - init_data: URL-encoded string ready to use
    - data_check_string: the string that was signed
    - hash: the calculated hash value
    r*   Úuserr6   r7   r8   r    )r   r2   r    )r
   Úupdater   ÚstrÚ
setdefaultÚjsonÚdumpsÚintr   Únowr   ÚutcÚ	timestampr(   r5   r   r   Ú	urlencode)
r;   r3   r6   r7   r8   r9   Úparamsr   Úvaluer2   s
             r   Úgenerate_signed_init_datarH   3   s  € ñ" Ü)Ð*DÓEÐEà€FÙØ�‰¸×9KÑ9KÔ9MÔNÑ9M©:¨3°�sœC ›J‘Ð9MÒNÔOà
×Ñ�fœdŸj™j¨Ó.Ô/Ø
×ÑØÜˆIÒDœœXŸ\™\¬(¯,©,Ó7×AÑAÓCÓDÓEôñ
 Ø%ˆˆzÑÙØ +ˆˆ}Ñä/°Ó7ÐÜ-Ð.?ÀÓK€Fˆ6�Nô —\‘\×+Ñ+¨FÓ3Ø.Ø�v‘ñð ùó! Os   °D
c                ó”   — t        | «      }t        |«      }	 t        ||«      }|j	                  d«      ||dœS # t        $ r d}Y Œ"w xY w)z¢
    Provide a debug-friendly view of the initData signature inputs/outputs.

    Useful for development harnesses to compare provided and calculated hashes.
    Nr    )Úprovided_hashÚcalculated_hashr2   )r   r(   r5   r
   Úget)r   r3   Úparsedr2   rK   s        r   Úinit_data_debug_snapshotrN   `   s_   € ô ˜YÓ'€FÜ/°Ó7ÐðÜ2Ð3DÀiÓPˆð
  Ÿ™ FÓ+Ø*Ø.ñð øô 'ò ØŠðús   ˜9 ¹AÁAc                ó@  — |st        d«      ‚t        | «      }d|vrt        d«      ‚|d   }t        |«      }t        ||«      }||k7  rt        d«      ‚|€	 ddlm} t        |dd«      }|dk  rnyd	|v rut        j                  t        |d	   «      t        j                  ¬
«      }t        j                  t        j                  «      |z
  }	|	t        |¬«      kD  rt        d|› d�«      ‚i }
d|v rt!        j"                  |d   «      }
|
S # t        t        f$ r d}Y Œ²w xY w)aP  
    Validate Telegram Web App initData payload.

    Args:
        init_data: Raw initData string from Telegram Web App.
        bot_token: Telegram bot token used to derive the secret key.
        expiration_hours: Optional expiration window in hours. Defaults to 24 hours
                         (Telegram's standard). In dev mode, can be extended via
                         TELEGRAM_INIT_DATA_EXPIRATION_HOURS setting.

    Returns:
        Parsed user data dictionary when validation succeeds.

    Raises:
        TelegramDataValidationError: if validation fails for any reason.
    r*   r    zMissing hash in init_dataz#Invalid hash - data may be tamperedr   )ÚsettingsÚ#TELEGRAM_INIT_DATA_EXPIRATION_HOURSé   r6   )Útz)ÚhourszinitData expired (older than z hours)r;   )r
   r   r(   r5   Údjango.confrP   ÚgetattrÚImportErrorÚRuntimeErrorr   ÚfromtimestamprA   r   rC   rB   r   r?   Úloads)r   r3   Úexpiration_hoursr#   Úreceived_hashr2   rK   rP   r6   ÚageÚ	user_datas              r   Úvalidate_telegram_init_datar_   t   sG  € ñ* Ü)Ð*DÓEÐEä! )Ó,€Kà�[Ñ Ü)Ð*EÓFÐFà Ñ'€MÜ/°Ó<ÐÜ.Ð/@À)ÓL€Oà˜-Ò'Ü)Ð*OÓPÐPð Ðð	"Ý,ä& xÐ1VÐXZÓ[Ðð
 ˜1ÒàØ	˜Ñ	#Ü×*Ñ*Ü�˜KÑ(Ó)Ü�|‰|ô
ˆ	ô �l‰lœ8Ÿ<™<Ó(¨9Ñ4ˆØ”Ð!1Ô2Ò2Ü-Ø/Ð0@Ð/AÀÐIóð ð €IØ�ÑÜ—J‘J˜{¨6Ñ2Ó3ˆ	àÐøô- œ\Ð*ò 	"à!Òð	"ús   ÁD	 Ä	DÄDc                ó4  — | st         j                  d«       y||ddœ}|r||d<   |r||d<   d| › d�}t        j                  |«      j	                  d	«      }	 t
        j                  j                  ||d
ddi¬«      }t
        j                  j                  |d¬«      5 }	|	j                  dk7  r*t         j                  d|	j                  «       	 ddd«       y	 ddd«       y# 1 sw Y   yxY w# t        $ r }
t         j                  d|
«       Y d}
~
yd}
~
ww xY w)zÉ
    Send a Telegram message using the Bot API via HTTP.

    This avoids introducing extra async dependencies in the webhook handler
    while still using the official Telegram Bot HTTP endpoint.
    z/Cannot send Telegram message: bot token missingFT)Úchat_idÚtextÚdisable_web_page_previewÚ
parse_modeÚreply_markupzhttps://api.telegram.org/botz/sendMessagezutf-8ÚPOSTzContent-Typezapplication/json)ÚurlÚdataÚmethodÚheadersé
   )ÚtimeoutéÈ   z0Telegram sendMessage returned non-200 status: %sNz#Failed to send Telegram message: %s)ÚloggerÚwarningr?   r@   r-   r   ÚrequestÚRequestÚurlopenÚstatusÚ	Exception)r3   ra   rb   re   rd   Úpayloadrg   rh   rp   ÚresponseÚexcs              r   Úsend_telegram_messagerx   ¹   s  € ñ Ü�‰ÐHÔIØð ØØ$(ñ€Gñ Ø *ˆ�ÑÙØ".ˆ�Ñà(¨¨°<Ð
@€CÜ�:‰:�gÓ×%Ñ% gÓ.€DðÜ—.‘.×(Ñ(ØØØØ#Ð%7Ð8ð	 )ó 
ˆô �^‰^×#Ñ# G°RÐ#Ô8¸HØ�‰ #Ò%Ü—‘ØFÈÏÉôð ÷ 9Ð8Ø%÷ 9ð ÷ 9ð ûÜò Ü�‰Ð<¸cÔBÜûðús=   ÁAC. Â1C"ÃC. ÃC. Ã"C+Ã'C. Ã+C. Ã.	DÃ7DÄD)r   r=   Úreturnúdict[str, str])r#   zMapping[str, str]ry   r=   )r2   r=   r3   r=   ry   r=   )r;   Údictr3   r=   r6   ú
int | Noner7   ú
str | Noner8   r}   r9   zdict[str, str] | Nonery   rz   )r   r=   r3   r=   ry   zdict[str, str | None])N)r   r=   r3   r=   r[   r|   ry   r{   )NÚHTML)r3   r=   ra   rA   rb   r=   re   zdict[str, Any] | Nonerd   r}   ry   Úbool)r   Ú
__future__r   r+   r/   r?   ÚloggingÚurllib.parser   Úurllib.requestr   r   r   Útypingr   r   Ú	getLoggerr   rn   Ú
ValueErrorr
   r   r(   r5   rH   rN   r_   rx   r   r   r   Ú<module>r‡      s-  ðÙ Lå "ã Û Û Û Û Û ß 2Ñ 2ß ð 
ˆ×	Ñ	˜8Ó	$€ô: *ô :óAóóXð !ØØ"Ø*.ñ*à
ð*ð ð*ð ð	*ð
 ð*ð ð*ð (ð*ð ó*óZð. $(ðBØðBàðBð !ðBð 
ó	BðR +/Ø#ð/Øð/àð/ð ð/ð (ð	/ð
 ð/ð 
ô/r   