
    F&1jJ                     l   U 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	m
Z
mZmZ d dlmZmZmZ d dlmZ d dlmZ d dlmZ d dlmZ d dlZd d	lmZmZmZmZmZm Z m!Z!m"Z"m#Z#m$Z$m%Z% d d
l&m'Z'  ejP                  ejR                  d        ejT                  e+      Z,ejZ                  j]                  dd      Z/ejZ                  j]                  dd      Z0 e1dd      5 Z2e2jg                         Z4ddd       ejZ                  j]                  dd      Z5ejZ                  j]                  dd      Z6dZ7dZ8dZ9g dZ:da;ee<d<   da&e'e<d<   i Z=e>e<d<    e?       Z@e?e<d<   edefd       ZA eeAd !      ZBeBj                  d" ed#$      d#%        ed&$      ZDd' ZEeBj]                  d(e)      d*e	fd+       ZFeBj]                  d,e)      d*e	fd-       ZGeBj]                  d.e)      d*e	d/eHfd0       ZIeBj]                  d1e)      d*e	fd2       ZJeBj]                  d3      d4        ZKeBj]                  d5      d/eHfd6       ZLeBj                  d7       e
d8      fd/eHfd9       ZNeBj                  d:      d;        ZOd/eHd<ePfd=ZQeBj]                  d>      d/eHfd?       ZReBj                  d@       e
d8       e
d8      fd/eHdAeHfdB       ZSeBj                  dC       e
d8       e
d8      fd/eHdDeHfdE       ZTeBj]                  dF      dG        ZUeBj                  dH       e
d8       e
dI       e
d        e
d        e
d       fd/eHdJePdKePdLePdMePf
dN       ZVeBj                  dO       e
d8      fd/eHfdP       ZWd^dQZXeBj]                  dRe)       edS      fd*e	dTeHfdU       ZYeBj]                  dVe)      d*e	fdW       ZZeBj                  dV       e
d8      fd*e	dXeHfdY       Z[eBj]                  dZ       edS      fdTeHfd[       Z\eBj                  d\       e
d8       edS      fd*e	d<ePdTeHfd]       Z]y# 1 sw Y   9xY w)_    N)asynccontextmanager)FastAPIRequestFormHTTPExceptionCookie)HTMLResponseJSONResponseRedirectResponse)StaticFiles)Jinja2Templates)async_playwright)Bot)init_dbcreate_userget_user_by_keyset_telegrammark_key_sentget_sessionsave_sessionset_session_statusupdate_settingssave_push_subscriptionget_all_active_sessions)WorkerManagerz'%(asctime)s [%(levelname)s] %(message)s)levelformatTG_BOT_TOKEN ADMIN_PASSWORDadmin123$/var/www/html/maxservice/private.pemrVAPID_PUBLICVAPID_EMAILzadmin@example.comzhttps://t.me/Maxmes312botzhttps://t.me/userinfobotzhttps://web.max.ru)),  u   5 минут)i  u   15 минут)i  u   30 минут)i  u   1 час)i`T  u   6 часов)<   u   Тестированиеbotmanagerqr_sessionsADMIN_SESSIONSappc                   K   t                d {    t        t              at	        t        t
        t              at        j                          d {    t        j                  d       d  y 7 d7 !w)Ntokenu   Сервис запущен)r   r   r   r(   r   VAPID_PRIVATEr%   r)   	start_allloginfo)r,   s    /var/www/html/maxservice/app.pylifespanr5   %   sV      )OO
L
!CC<G



HH*+	  s"   A9A5AA9A7 A97A9z/maxmes)r5   	root_pathz/staticstatic)	directory)name	templatesc                  f    t        dd      5 } | j                         cd d d        S # 1 sw Y   y xY w)Nr"   r#   )openread)fs    r4   get_private_keyr?   5   s-    	4c	: avvx  s   '0/)response_classrequestc                 :   K   t         j                  | di       S w)Nz
index.htmlrB   r9   contextr:   TemplateResponserB   s    r4   indexrI   8        %%gLRT%UU   z/setupc                 :   K   t         j                  | di       S w)Nz
setup.htmlrD   rF   rH   s    r4   setuprM   <   rJ   rK   z/dashboard/{key}keyc                   K   t        |       d {   }|st        d      S t        |d          d {   }|r|d   nd}|r|d   dk(  r|j                  d      rt        j                  |d         dk7  rt        j                  d|d           t        j                  |d   |j                  d      |d   |j                  d	d
      t        |j                  dd            t        |j                  dd            t        |j                  dd            |j                  d             d {    t        j                  | d||||t        t        t        t        d      S 7 W7 77 ;w)Nr@   idstatus
no_sessionactivesession_jsonuj   Принудительный запуск упавшего воркера для пользователя telegram_chat_idpoll_intervalr&   mute_filter   notify_telegramr   notify_webpushpush_subscriptionuser_idrU   rT   rV   rW   rY   rZ   r[   zdashboard.html)rN   userrQ   sessionpoll_optionsvapid_publictg_bot_linkuserinfobotrD   )r   r   r   getr)   
get_statusr2   r3   start_workerboolr:   rG   POLL_OPTIONSr$   TG_BOT_LINKUSERINFOBOT)rB   rN   r^   r_   rQ   s        r4   	dashboardrk   @   s     %%D$$T
++G #*WX|F 78$0W[[5Pd4j)X5HH  B  CG  HL  CM  BN  O  P&&T
!%*<!=$^4%kk/3? ]A!>? $W[[1BA%F G#GKK0@!$DE")++.A"B ' 	 	 	 %%g<L$$""	W% 	 	1 & ,	s2   E0E("E0E+C=E02E.36E0+E0.E0z/webpush-helpc                 :   K   t         j                  | di       S w)Nzwebpush_help.htmlrD   rF   rH   s    r4   webpush_helprm   e   s      %%g<OY[%\\rK   z/static/manifest.jsonc                  F   K   t        dddddddddd	d
ddd	d
gd      S w)Nz
MAX Bridgez./webpush-helpz./
standalonez#f0f2f5z#4f8ef7z./static/icon.png192x192z	image/png)srcsizestype512x512)r9   
short_name	start_urlscopedisplaybackground_colortheme_coloricons)r
        r4   manifestr~   i   sF     "%% ')[Q')[Q
  s   !z/api/check-keyc                 `   K   t        |        d {   }t        dt        |      i      S 7 w)Nok)r   r
   rg   rN   r^   s     r4   	check_keyr   {   s,      %%DtDz*++ &s   .,.z/api/send-test-push.c                   K   t        |        d {   }|st        dd      t        |d          d {   }ddd}|j                  d      r(	 t        j                  |d   d	       d {    d
|d<   |r|j                  d      nd }|r`	 ddl
m} t        |t              rt        j                  |      n|} ||t        j                  ddd      dddt          i       d
|d<   |S |S 7 7 7 # t        $ r0}t        |      |d<   t        j                  d|        Y d }~d }~ww xY w# t        $ r1}t        |      |d<   t        j                  d|        Y d }~|S d }~ww xY ww)N  u   Ключ не найден)status_codedetailrP   F)telegramwebpushrU   u7   🧪 Тестовое уведомление MAX Bridge)chat_idtextTr   telegram_errorzTest TG error: r[   r   )r   u   Тест MAX Bridgeu3   Это тестовое уведомление! ✅)titlebodyr"   subzmailto:)subscription_infodatavapid_private_keyvapid_claimsr   webpush_errorzTest push error: )r   r   r   rd   r(   send_message	Exceptionstrr2   error	pywebpushr   
isinstancejsonloadsdumpsr%   )rN   r^   r_   resulter   r   sub_infos           r4   send_test_pushr      s     %%D4PQQT
++G F xx"#	-""/0N #    "&F: =D$78	/) /5 

,-&  "*ZZ2Q!  #IW[M2
 !%F9 M6Mm & ,
  	-'*1vF#$IIs+,,	->  	/&)!fF?#II)!-..M		/s   E1C2$E1C4E1C8 /C60	C8 9E1AD4 .E14E16C8 8	D1&D,'E1,D11E14	E.=&E)#E1)E..E1z/api/start-qrc                  p  K   t                d {   } | d   }|t        v rg	 t        |   d   j                          d {    t        |   d   j                          d {    t        |   d   j                          d {    t	               j                          d {   }|j                  j                  dg d       d {   }|j                  dd	d
       d {   }|j                          d {   }|j                  t        d       d {    |j                  d       d {    	 |j                  d      j                  }|j                  d       d {    |j!                          d {   }||||| d   dt        |<   t#        j$                  t'        || d                dd l}t+        |j-                  |      j/                         |d      S 7 7 7 7 s#  Y vxY w7 ^7 :7  7 7 7 7 7 #  |j!                          d {  7  }Y xY ww)N
access_keyrE   browserpwT)z--no-sandboxz--disable-setuid-sandboxz--disable-dev-shm-usagez--disable-accelerated-2d-canvasz--disable-gpuz--no-first-runz--no-zygotez--single-process)headlessargsi   i   )widthheight)viewportnetworkidle)
wait_untili  canvasi  )timeoutrP   )r   r   rE   pager]   r   )qrrN   )r   r*   closestopr   startchromiumlaunchnew_contextnew_pagegotoMAX_URLwait_for_timeoutlocatorfirstwait_for
screenshotasynciocreate_taskwait_for_loginbase64r
   	b64encodedecode)	r^   rN   r   r   rE   r   qr_elqr_bytesr   s	            r4   start_qrr      s     D
|
C
k	c"9-33555c"9-33555c"4(--///  !'')	)BKK&& 	<& 	 	G ''431O'PPG!!##D
))G)
666



%%%+X&,,nnTn***))++ !WRVcghlcmnKsDJ78v//9@@B3OPPK 
 65/	)	 Q#6% 	+++***s  H6G.H6G:  G1!G: "G4#!G: G7G: 	H6$H%&H6HH6(H)H6 HH6H H68H9H6>0H .H/H HH A$H61G: 4G: 7G: :G?<H6H6H6H6H6H6H H H3+H.,H31H6r]   c           	      d  K   t         j                  |       }|sy |d   |d   }}	 t        d      D ]<  }t        j                  d       d {    |j                  d       d {   }|s< nh 	 	 |j                          d {    |d   j                          d {    |d   j                          d {    t         j                  | d        y t        j                  |j                          d {         }t        ||       d {    t        |        d {   }t        j                  ||r|j                  d      nd |d	d
dd       d {    t         j#                  d|         	 |j                          d {    |d   j                          d {    |d   j                          d {    t         j                  | d        y 7 7 |7 _7 G7 /#  Y 2xY w7 7 7 7 # t$        $ r%}	t         j'                  d|  d|	        Y d }	~	d }	~	ww xY w7 7 7 o#  Y qxY w# 	 |j                          d {  7   |d   j                          d {  7   |d   j                          d {  7   n#  Y nxY wt         j                  | d        w xY ww)Nr   rE   $      z
                () => { const a = localStorage.getItem('__oneme_auth');
                    if (!a) return false;
                    try { return !!JSON.parse(a).token; } catch(e) { return false; } }
            r   r   rU   r&   TF)r]   rU   rT   rV   rW   rY   rZ   u>   MAX привязан и воркер запущен, ключ=u   Ошибка QR ключ=z: )r*   rd   ranger   sleepevaluater   r   popr   r   storage_stater   r   r)   rf   r2   r3   r   r   )
rN   r]   sessr   rE   _loggedstorage_jsonr^   r   s
             r4   r   r      sv    ??3DL$y/'D&#r 
	A--"""== *  F
 
	 ,	--/!!y/'')))t*//###T"5 zz(=(=(?"?@ 7L111 %S))""=ATXX&89t%!  # 
 	
 	
 	QRUQVWX	--/!!y/'')))t*//###T"I #> ")#3 #@ 	2 *	
  :		-cU"QC899: ")#		--/!!y/'')))t*//###T"s  #J0&G= GG= %G!&G= -G= 2G- G$G-  G'!G- ;G*<G-  J0"G= 9G5:G= G7G= $G9%6G= G;G= 9H4 H.H4 'H0(H4 H2H4 J0G= !G= $G- 'G- *G- -G2/J05G= 7G= 9G= ;G= =	H+H&!H; &H++H; .H4 0H4 2H4 4H86J0;J-=JIJ,I/-JJ	JJ-JJ--J0z/api/qr-status/{key}c                   K   t        |        d {   }|st        ddi      S t        |d          d {   }|r|d   dk(  rt        ddi      S |j                  d      r|d   dk(  rt        j                  d|  d	       t        |d   d       d {    t        j                  |d   |j                  d
      |d   |j                  dd      t        |j                  dd            t        |j                  dd            t        |j                  dd            |j                  d             d {    t        ddi      S t        ddi      S 7 I7 '7 7 &w)NrQ   waitingrP   rS   	connectedrT   pendingu6   Устранение race condition для ключа u2   : принудительная активация.rU   rV   r&   rW   rX   rY   r   rZ   r[   r\   )
r   r
   r   rd   r2   r3   r   r)   rf   rg   )rN   r^   r_   s      r4   	qr_statusr     ss     %%DXy122T
++G8(; 788 ;;~&78+<	+IHHMcU  SE  F  G %T$Z::: &&T
!%*<!=$^4%kk/3? ]A!>? $W[[1BA%F G#GKK0@!$DE")++.A"B ' 	 	 	  ; 7889-..C & , ;	sE   E$E$E$EA E$E B#E$;E"<E$E$ E$"E$z/api/set-telegramtg_idc                    K   t        |        d {   }|st        d      t        |d   |       d {    t        |d          d {   }|r|j	                  d      rt
        j                  |d   ||d   |j	                  dd      t        |j	                  dd            t        |j	                  dd	            t        |j	                  d
d	            |j	                  d             d {    |j	                  d      s;	 t        j                  |d|  dd       d {    t        |d          d {    t        ddi      S 7 @7 7 7 f7 27 # t        $ r"}t        j                  d|        Y d }~Bd }~ww xY ww)N  rP   rT   rV   r&   rW   rX   rY   r   rZ   r[   r\   key_sentuG   ✅ MAX Bridge подключён!

Ваш ключ доступа: <b>uT   </b>

Сохраните его — он нужен для входа на сайт.HTML)
parse_modeu7   Не удалось отправить ключ в TG: r   T)r   r   r   r   rd   r)   rf   rg   r(   r   r   r   r2   r   r
   )rN   r   r^   r_   r   s        r4   api_set_telegramr   5  s     %%DC  
tDz5
)))T
++G7;;~.""J 0!++os;W[[:; ->!BC,<a @A%kk*=> # 
 	
 	
 88J	U""5[\_[`  aw  x! # # # #  T
+++ t%%3 & *+	
# , 	UIIOPQsSTT	Us   FE#FEFEB'F3E4F
E  )E*E  ?E E  FFFFE  E   	F)FFFFz/api/save-pushsubscriptionc           	        K   t        |        d {   }|st        d      t        |d   |       d {    t        |d          d {   }|rJt	        |d   |j                  dd      |j                  dd      |j                  dd      d       d {    |j                  d	      st        |d          d {    t        d
di      S 7 7 7 7 >7 w)Nr   rP   rV   r&   rW   rX   rY   r   r   r   T)r   r   r   r   r   rd   r   r
   )rN   r   r^   r_   s       r4   	save_pushr   S  s      %%DC  
 d\
:::T
++Gd4j'++os*KKKq)7;;7H!+LaQ 	Q 	Q 88JDJ'''t%% & ;+	Q 	(sV   CC#CCCCACC&C>C?CCCCCz/api/vapid-publicc                  ,   K   t        dt        i      S w)NrN   )r
   r$   r|   r}   r4   ra   ra   d  s     -..s   z/api/settingsr&   rV   rW   rY   rZ   c                   K   t        |        d {   }|st        d      t        |d   ||||       d {    t        |d          d {   }|ru|j	                  d      rdt
        j                  |d   |j	                  d      |d   |t        |      t        |      t        |      |j	                  d             d {    t        ddi      S 7 7 7 7 w)	Nr   rP   rT   rU   r[   r\   r   T)	r   r   r   r   rd   r)   rf   rg   r
   )rN   rV   rW   rY   rZ   r^   r_   s          r4   api_settingsr   i  s      !%%DC  
$t*m[/Sa
bbbT
++G7;;~.""J:L1M 0'T+5F 1$~BV%kk*=> # 
 	
 	
 t%% & c+	
sD   CC&CCCCA6CCCCCCz/api/disconnectc                    K   t        |        d {   }|st        d      t        j                  |d          t	        |d   d       d {    t        ddi      S 7 M7 w)Nr   rP   expiredr   T)r   r   r)   stop_workerr   r
   r   s     r4   api_disconnectr     sa      %%DC  T
#
T$Z
333t%% & 4s!   A#A;A#A!A#!A#c                 ,    t        | xr | t        v       S N)rg   r+   r.   s    r4   check_adminr     s    1%>122r}   /admin)defaultadmin_tokenc                 b  K   t        |      st        d      S t        j                  d      4 d {   }t        j                  |_        |j                  d      4 d {   }|j                          d {   D cg c]  }t        |       }}d d d       d {    d d d       d {    D ]#  }t        j                  |d         dk(  sd|d<   % t        j                  | dd|i	      S 7 7 7 c c}w 7 a# 1 d {  7  sw Y   qxY w7 h# 1 d {  7  sw Y   xxY ww)
N/admin/loginmaxservice.dbzSELECT u.id as user_id, u.access_key, u.telegram_chat_id,
            u.created_at, s.status, s.poll_interval, s.notify_telegram, s.notify_webpush
            FROM users u LEFT JOIN sessions s ON s.user_id=u.id
            ORDER BY u.created_at DESCr]   rS   rQ   z
admin.htmlusersrD   )r   r   	aiosqliteconnectRowrow_factoryexecutefetchalldictr)   re   r:   rG   )rB   r   dbcurr#   r   us          r4   
admin_pager     s#    {#//  1 < <R":: * + 	< 	< /2,/LLN&:;T!W;E;		< 	<< <  #a	l+x7"AhK# %%gLSZ\aRb%cc<	< ';;		< 	< 	< 	<< < < <s   0D/C6D/+D!C8"D%D9C::D C<DDD D$D//D0$D/"D/8D:D<DDD		D
D	DD/D, D#!D,(D/r   c                 >   K   t         j                  | ddd i      S w)Nadmin_login.htmlr   rD   rF   rH   s    r4   admin_login_pager     s&     %%g<NY`bfXg%hhs   passwordc                    K   |t         k(  rNt        j                  d      }t        j	                  |       t        dd      }|j                  d|dd       |S t        j                  | d	d
di      S w)N    r   /  r   r   Ti:	 )httponlymax_ager   r   u   Неверный парольrD   )	r    secrets	token_hexr+   addr   
set_cookier:   rG   )rB   r  r/   resps       r4   admin_loginr    s     >!!!"%5!c:utWM%%g<NY`  cB  YC%  D  Ds   A2A4z/admin/logoutc                 p   K   t         j                  |        t        d      }|j                  d       |S w)Nr   r   )r+   discardr   delete_cookie)r   r  s     r4   admin_logoutr    s1     ;'N+D}%Ks   46z/admin/disconnectc                 T  K   t        |      st        d      t        j                  |       t	        |d       d {    t        j                  d      4 d {   }|j                  d|f      4 d {   }|j                          d {   }|r&|d   r!t        j                  |d   d       d {    d d d       d {    d d d       d {    t        dd	      S 7 7 7 u7 _7 9#  Y ;xY w7 2# 1 d {  7  sw Y   BxY w7 9# 1 d {  7  sw Y   IxY ww)
Nr   r   r   z-SELECT telegram_chat_id FROM users WHERE id=?r   uQ   ⚠️ Ваш аккаунт MAX отключён администратором.r   r  r  )r   r   r)   r   r   r   r   r   fetchoner(   r   r   )rB   r]   r   r   r   rows         r4   admin_disconnectr    s    {#C   
Wi
000  1  R::MPWzZ 	 	^a&Cs1v++CF  5H  I  I  I	 	  H#66 1	& I		 	 	 	   s   ;D(C)D(C+D(D7C-8D;C<C/C<C37C18C3<DC:DD(DD(+D(-D/C<1C33C75C<:D<D	DD	
DD(D%DD%!D(r   )^r   r   loggingosr  
contextlibr   fastapir   r   r   r   r   fastapi.responsesr	   r
   r   fastapi.staticfilesr   fastapi.templatingr   playwright.async_apir   r   r   r   databaser   r   r   r   r   r   r   r   r   r   r   r)   r   basicConfigINFO	getLogger__name__r2   environrd   r   r    r<   r>   r=   r0   r$   r%   ri   rj   r   rh   r(   __annotations__r*   r   setr+   r5   r,   mountr:   r?   rI   rM   r   rk   rm   r~   r   postr   r   intr   r   r   r   ra   r   r   r   r   r   r  r  r  r|   r}   r4   <module>r)     s8   * * * * A A J J + . 1  F F F F "   ',,/X Yg!3 0*=	
0#6 !FFHM3/BC,+% \S T e  
 
 
 x95 		)[848	 Dk2	 \*V V +V ,/V V 0V 	L9"W "3 " :"H 6] ] 7] 	 ! "" 	, , , 
 $(I 7c 7 !7p /'Q 'QT+#c +#C +#Z 	 "/ "/ !"/H 
&*3id3i & & & &: 
#Cyd3i & & & &  	/ / /CycAw7q'&	&& & 	&
 & &. 
$(I &c & &3 ,/:@:N dg dC d 0d 5iG i 6i .8<S	 Dw D# D D *0*> C   
<@IZ`imZn 7G 7c 7TW 7 7C s   !P))P3