44from typing import TYPE_CHECKING , Any , Self
55from secrets import token_urlsafe
66
7- from PySide6 .QtCore import QObject , QTimer , Slot
7+ from PySide6 .QtCore import QObject , QTimer , Slot , Qt
88from PySide6 .QtNetwork import QHostAddress
99from PySide6 .QtWebSockets import QWebSocketServer
1010from loguru import logger
1111from orjson import dumps , loads
12+ from qfluentwidgets import MessageBox
1213
1314from app .bases .models import Task , TaskStatus
1415from app .services .core_service import coreService
1516from app .services .feature_service import featureService
1617from app .supports .config import VERSION , cfg
1718from app .supports .recorder import taskRecorder
18- from app .supports .utils import getProxies , openFile , openFolder
19+ from app .supports .utils import bringWindowToTop , getProxies , openFile , openFolder
1920
2021if TYPE_CHECKING :
2122 from PySide6 .QtWebSockets import QWebSocket
@@ -35,6 +36,8 @@ class BrowserMessageType(StrEnum):
3536 ERROR = "error"
3637 HELLO = "hello"
3738 HELLO_ACK = "hello_ack"
39+ PAIR_REQUEST = "pair_request"
40+ PAIR_RESULT = "pair_result"
3841 SUBSCRIBE_TASKS = "subscribe_tasks"
3942 TASK_SNAPSHOT = "task_snapshot"
4043 CREATE_TASK = "create_task"
@@ -204,6 +207,41 @@ def _sendError(
204207 payload ["requestId" ] = requestId
205208 self ._send (session , payload )
206209
210+ def _showPairRequestDialog (self , session : _BrowserClientSession , data : dict [str , Any ]) -> bool :
211+ extensionVersion = self ._stringField (data , "extensionVersion" , self .tr ("未知" ))
212+ clientKind = self ._stringField (data , "clientKind" , self .tr ("浏览器扩展" ))
213+ peerAddress = f"{ session .socket .peerAddress ().toString ()} :{ session .socket .peerPort ()} "
214+ content = self .tr (
215+ "浏览器扩展正在请求连接到 Ghost Downloader。\n \n "
216+ "来源: {0}\n "
217+ "客户端: {1}\n "
218+ "扩展版本: {2}\n \n "
219+ "仅在你刚刚点击扩展里的“自动配对”时允许。"
220+ ).format (peerAddress , clientKind , extensionVersion )
221+
222+ bringWindowToTop (self .mainWindow )
223+ dialog = MessageBox (self .tr ("浏览器扩展配对请求" ), content , self .mainWindow )
224+ dialog .yesButton .setText (self .tr ("允许配对" ))
225+ dialog .cancelButton .setText (self .tr ("拒绝" ))
226+ dialog .contentLabel .setTextInteractionFlags (Qt .TextInteractionFlag .TextSelectableByMouse )
227+ return bool (dialog .exec ())
228+
229+ def _handlePairRequest (self , session : _BrowserClientSession , data : dict [str , Any ]) -> None :
230+ requestId = self ._stringField (data , "requestId" )
231+
232+ if int (data .get ("protocolVersion" ) or 0 ) != self .PROTOCOL_VERSION :
233+ result = {"ok" : False , "message" : self .tr ("协议版本不匹配" )}
234+ elif not self ._showPairRequestDialog (session , data ):
235+ result = {"ok" : False , "message" : self .tr ("已拒绝配对请求" )}
236+ else :
237+ result = {"ok" : True , "message" : self .tr ("配对成功" ), "token" : self .pairToken }
238+
239+ self ._send (session , {
240+ "type" : BrowserMessageType .PAIR_RESULT ,
241+ "requestId" : requestId ,
242+ ** result ,
243+ })
244+
207245 @staticmethod
208246 def _stringField (data : dict [str , Any ], key : str , default : str = "" ) -> str :
209247 value = data .get (key )
@@ -691,6 +729,10 @@ def _onReceiveMessage(self, message: str):
691729 self ._sendError (session , self .tr ("未知的消息类型" ))
692730 return
693731
732+ if messageType == BrowserMessageType .PAIR_REQUEST :
733+ self ._handlePairRequest (session , data )
734+ return
735+
694736 if messageType == BrowserMessageType .HELLO :
695737 requestId = self ._stringField (data , "requestId" ) or None
696738 if int (data .get ("protocolVersion" ) or 0 ) != self .PROTOCOL_VERSION :
0 commit comments