@@ -2343,49 +2343,63 @@ async def update_plugin_config(
23432343
23442344@router .post ("/api/plugin/update-token" )
23452345async def plugin_update_token (request : dict , authorization : Optional [str ] = Header (None )):
2346- """Receive modern Google Flow cookies from the Chrome extension ."""
2346+ """Receive a legacy session token and/or modern Google Flow cookies ."""
23472347 await _verify_plugin_connection_token (authorization )
23482348 plugin_config = await db .get_plugin_config ()
23492349
2350+ session_token_raw = request .get ("session_token" )
2351+ if session_token_raw is not None and not isinstance (session_token_raw , str ):
2352+ raise HTTPException (status_code = 400 , detail = "session_token must be a string" )
2353+ session_token = (session_token_raw or "" ).strip ()
2354+ if len (session_token ) > 262144 :
2355+ raise HTTPException (status_code = 413 , detail = "session_token is too large" )
2356+
23502357 google_cookies_raw = request .get ("google_cookies" )
23512358 if google_cookies_raw is not None and not isinstance (google_cookies_raw , str ):
23522359 raise HTTPException (status_code = 400 , detail = "google_cookies must be a string" )
23532360
23542361 google_cookies = (google_cookies_raw or "" ).strip ()
23552362 if len (google_cookies ) > 524288 :
23562363 raise HTTPException (status_code = 413 , detail = "google_cookies is too large" )
2357- if not google_cookies :
2358- raise HTTPException (status_code = 400 , detail = "Missing google_cookies" )
2364+ if not session_token and not google_cookies :
2365+ raise HTTPException (status_code = 400 , detail = "Missing session_token or google_cookies" )
23592366
23602367 proxy_url = str (request .get ("proxy_url" ) or "" ).strip () or None
23612368 login_account_hint = str (request .get ("login_account" ) or "" ).strip () or None
2362- try :
2363- protocol_result = await protocol_loginer .login (
2364- google_cookies ,
2365- proxy = proxy_url ,
2366- email = login_account_hint ,
2367- )
2368- except Exception as exc :
2369- raise HTTPException (
2370- status_code = 400 ,
2371- detail = f"Failed to derive session token from Google cookies: { str (exc )} " ,
2372- ) from exc
23732369
2374- session_token = str (protocol_result .get ("session_token" ) or "" ).strip ()
2375- if not protocol_result .get ("success" ) or not session_token :
2376- error = str (protocol_result .get ("error" ) or "Google session is invalid or expired" )
2377- raise HTTPException (status_code = 400 , detail = f"Invalid Google cookies: { error } " )
2370+ async def derive_session_token_from_cookies () -> str :
2371+ try :
2372+ protocol_result = await protocol_loginer .login (
2373+ google_cookies ,
2374+ proxy = proxy_url ,
2375+ email = login_account_hint ,
2376+ )
2377+ except Exception as exc :
2378+ raise HTTPException (
2379+ status_code = 400 ,
2380+ detail = f"Failed to derive session token from Google cookies: { str (exc )} " ,
2381+ ) from exc
2382+
2383+ derived_token = str (protocol_result .get ("session_token" ) or "" ).strip ()
2384+ if not protocol_result .get ("success" ) or not derived_token :
2385+ error = str (protocol_result .get ("error" ) or "Google session is invalid or expired" )
2386+ raise HTTPException (status_code = 400 , detail = f"Invalid Google cookies: { error } " )
2387+ return derived_token
2388+
2389+ supplied_session_token = bool (session_token )
2390+ if not session_token :
2391+ session_token = await derive_session_token_from_cookies ()
23782392
23792393 # Step 1: Convert ST to AT to get user info (including email)
2380- try :
2381- result = await token_manager .flow_client .st_to_at (session_token )
2394+ async def validate_session_token ( value : str ) :
2395+ result = await token_manager .flow_client .st_to_at (value )
23822396 at = result ["access_token" ]
23832397 expires = result .get ("expires" )
23842398 user_info = result .get ("user" , {})
23852399 email = user_info .get ("email" , "" )
23862400
23872401 if not email :
2388- raise HTTPException ( status_code = 400 , detail = "Failed to get email from session token" )
2402+ raise ValueError ( "Failed to get email from session token" )
23892403
23902404 # Parse expiration time
23912405 from datetime import datetime
@@ -2395,14 +2409,30 @@ async def plugin_update_token(request: dict, authorization: Optional[str] = Head
23952409 at_expires = datetime .fromisoformat (expires .replace ('Z' , '+00:00' ))
23962410 except (TypeError , ValueError ):
23972411 pass
2412+ return at , at_expires , email
23982413
2399- except HTTPException :
2400- raise
2401- except Exception as e :
2402- raise HTTPException (status_code = 400 , detail = f"Invalid session token: { str (e )} " )
2403-
2404- protocol_mode = "protocol"
2405- login_account = login_account_hint or email
2414+ try :
2415+ at , at_expires , email = await validate_session_token (session_token )
2416+ except Exception as direct_error :
2417+ if not supplied_session_token or not google_cookies :
2418+ raise HTTPException (
2419+ status_code = 400 ,
2420+ detail = f"Invalid session token: { str (direct_error )} " ,
2421+ ) from direct_error
2422+
2423+ # Browser profiles can retain an expired legacy ST while their Google
2424+ # cookies are still valid. Fall back to protocol login before failing.
2425+ session_token = await derive_session_token_from_cookies ()
2426+ try :
2427+ at , at_expires , email = await validate_session_token (session_token )
2428+ except Exception as fallback_error :
2429+ raise HTTPException (
2430+ status_code = 400 ,
2431+ detail = f"Invalid session token: { str (fallback_error )} " ,
2432+ ) from fallback_error
2433+
2434+ protocol_mode = "protocol" if google_cookies else "session"
2435+ login_account = email
24062436
24072437 # Step 2: Check if token with this email exists
24082438 existing_token = await db .get_token_by_email (email )
0 commit comments