@@ -77,6 +77,7 @@ def __init__(
7777 # Mostly 8.x API endpoints, login/status are the same in 6.x
7878 self ._login_urls = {
7979 "default" : f"{ self .base_url } /api/auth" ,
80+ "v6_login_cgi" : f"{ self .base_url } /login.cgi" ,
8081 "v6_alternative" : f"{ self .base_url } /login.cgi?uri=/" ,
8182 }
8283 self ._status_cgi_url = f"{ self .base_url } /status.cgi"
@@ -228,7 +229,7 @@ async def _request_json(
228229 url : str ,
229230 headers : dict [str , Any ] | None = None ,
230231 json_data : dict [str , Any ] | None = None ,
231- form_data : dict [str , Any ] | None = None ,
232+ form_data : dict [str , Any ] | aiohttp . FormData | None = None ,
232233 authenticated : bool = False ,
233234 ct_json : bool = False ,
234235 ct_form : bool = False ,
@@ -321,32 +322,93 @@ async def login(self) -> None:
321322 )
322323 _LOGGER .error ("TESTv6 - Cookie response: %s" , cookieresponse )
323324
324- try : # Alternative URL
325- v6_payload = {
326- "username" : self .username ,
327- "password" : self .password ,
328- "uri" : "/index.cgi" ,
329- }
330- login_headers = {
331- "User-Agent" : "Mozilla/5.0 (X11; Ubuntu; Linux x86_64; rv:88.0) Gecko/20100101 Firefox/88.0" ,
332- "Referer" : self ._login_urls ["v6_alternative" ],
333- }
334-
335- v6_response = await self ._request_json (
336- "POST" ,
337- self ._login_urls ["v6_alternative" ],
338- headers = login_headers ,
339- form_data = v6_payload ,
340- ct_form = True ,
341- authenticated = True ,
342- )
343- _LOGGER .error (
344- "TESTv6 - Trying to authenticate v6 responded in : %s" , v6_response
345- )
346- except AirOSConnectionSetupError as err :
347- raise AirOSConnectionSetupError (
348- "Failed to login to default and alternate AirOS device urls"
349- ) from err
325+ v6_urls_to_try = [
326+ self ._login_urls ["v6_alternative" ],
327+ self ._login_urls ["v6_login_cgi" ],
328+ ]
329+
330+ # Prepare form-urlencoded data (simple dict for 'ct_form=True')
331+ v6_urlencoded_data = {
332+ "uri" : "/index.cgi" ,
333+ "username" : self .username ,
334+ "password" : self .password ,
335+ }
336+
337+ # Prepare multipart/form-data (aiohttp.FormData)
338+ v6_multipart_form_data = aiohttp .FormData ()
339+ v6_multipart_form_data .add_field ("uri" , "/index.cgi" )
340+ v6_multipart_form_data .add_field ("username" , self .username )
341+ v6_multipart_form_data .add_field ("password" , self .password )
342+
343+ login_headers = {
344+ # Removed User-Agent as it's often optional/can be simplified
345+ "Referer" : self ._login_urls ["v6_login_cgi" ],
346+ }
347+
348+ for url_to_try in v6_urls_to_try :
349+ # --- Attempt 1: application/x-www-form-urlencoded (preferred modern method) ---
350+ try :
351+ _LOGGER .error (
352+ "TESTv6 - Trying to authenticate V6 POST to %s with application/x-www-form-urlencoded" ,
353+ url_to_try ,
354+ )
355+ await self ._request_json (
356+ "POST" ,
357+ url_to_try ,
358+ headers = login_headers ,
359+ form_data = v6_urlencoded_data ,
360+ authenticated = True ,
361+ ct_form = True , # Flag to tell _request_json to use form-urlencoded Content-Type
362+ )
363+ except AirOSUrlNotFoundError :
364+ _LOGGER .warning (
365+ "TESTv6 - V6 URL not found (%s) for form-urlencoded, trying multipart." ,
366+ url_to_try ,
367+ )
368+ except AirOSConnectionSetupError as err :
369+ _LOGGER .warning (
370+ "TESTv6 - V6 connection setup failed (%s) for form-urlencoded, trying multipart. Error: %s" ,
371+ url_to_try ,
372+ err ,
373+ )
374+ except AirOSConnectionAuthenticationError :
375+ raise
376+ else :
377+ return # Success
378+
379+ # --- Attempt 2: multipart/form-data (fallback for older/different servers) ---
380+ try :
381+ _LOGGER .error (
382+ "TESTv6 - Trying to authenticate V6 POST to %s with multipart/form-data" ,
383+ url_to_try ,
384+ )
385+ await self ._request_json (
386+ "POST" ,
387+ url_to_try ,
388+ headers = login_headers ,
389+ form_data = v6_multipart_form_data ,
390+ authenticated = True ,
391+ )
392+ except AirOSUrlNotFoundError :
393+ _LOGGER .warning (
394+ "TESTv6 - V6 URL not found (%s) for multipart, trying next URL." ,
395+ url_to_try ,
396+ )
397+ except AirOSConnectionSetupError as err :
398+ _LOGGER .warning (
399+ "TESTv6 - V6 connection setup failed (%s) for multipart, trying next URL. Error: %s" ,
400+ url_to_try ,
401+ err ,
402+ )
403+ except AirOSConnectionAuthenticationError :
404+ raise
405+ else :
406+ return # Success
407+
408+ # If the loop finishes without returning, login failed for all combinations
409+ raise AirOSConnectionSetupError (
410+ "Failed to login to default and alternate AirOS device urls"
411+ )
350412
351413 async def status (self ) -> AirOSDataModel :
352414 """Retrieve status from the device."""
0 commit comments