1212from .models import Apparatus
1313from .models import ApparatusDetail
1414from .models import Item
15- from .models import SelfAssertedResponse
16- from .models import SignInConfig
1715
1816API_BASE = "https://app.mobilelinkgen.com/api"
1917LOGIN_BASE = "https://generacconnectivity.b2clogin.com/generacconnectivity.onmicrosoft.com/B2C_1A_MobileLink_SignIn"
@@ -32,12 +30,6 @@ class SessionExpiredException(Exception):
3230 pass
3331
3432
35- def get_setting_json (page : str ) -> Mapping [str , Any ] | None :
36- for line in page .splitlines ():
37- if line .startswith ("var SETTINGS = " ) and line .endswith (";" ):
38- return json .loads (line .removeprefix ("var SETTINGS = " ).removesuffix (";" ))
39-
40-
4133class GeneracApiClient :
4234 def __init__ (
4335 self ,
@@ -64,16 +56,13 @@ def __init__(
6456
6557 async def async_get_data (self ) -> dict [str , Item ] | None :
6658 """Get data from the API."""
67- try :
68- if self ._session_cookie :
69- self ._headers ["Cookie" ] = self ._session_cookie
70- self ._logged_in = True
71- elif not self ._logged_in :
72- await self .login ()
73- self ._logged_in = True
74- except SessionExpiredException :
59+ if self ._session_cookie :
60+ self ._headers ["Cookie" ] = self ._session_cookie
61+ self ._logged_in = True
62+ else :
7563 self ._logged_in = False
76- return await self .async_get_data ()
64+ _LOGGER .error ("No session cookie provided, cannot login" )
65+ raise InvalidCredentialsException ("No session cookie provided" )
7766 return await self .get_device_data ()
7867
7968 async def get_device_data (self ):
@@ -128,107 +117,3 @@ async def get_endpoint(self, endpoint: str):
128117 raise
129118 except Exception as ex :
130119 raise IOError () from ex
131-
132- async def login (self ) -> None :
133- """Login to API"""
134- headers = {** self ._headers }
135-
136- login_response = await (
137- await self ._session .get (
138- f"{ API_BASE } /Auth/SignIn?email={ self ._username } " ,
139- headers = headers ,
140- allow_redirects = True ,
141- )
142- ).text ()
143-
144- if await self .submit_form (login_response ):
145- return
146-
147- parse_settings = get_setting_json (login_response )
148- if parse_settings is None :
149- _LOGGER .debug (
150- "Unable to find csrf token in login page:\n %s" , login_response
151- )
152- raise IOError ("Unable to find csrf token in login page" )
153- sign_in_config = from_dict (SignInConfig , parse_settings )
154-
155- form_data = aiohttp .FormData ()
156- form_data .add_field ("request_type" , "RESPONSE" )
157- form_data .add_field ("signInName" , self ._username )
158- form_data .add_field ("password" , self ._password )
159- if sign_in_config .csrf is None or sign_in_config .transId is None :
160- raise IOError (
161- "Missing csrf and/or transId in sign in config %s" , sign_in_config
162- )
163- self .csrf = sign_in_config .csrf
164-
165- headers = {** self ._headers }
166- headers ["X-Csrf-Token" ] = sign_in_config .csrf
167-
168- self_asserted_response = await self ._session .post (
169- f"{ LOGIN_BASE } /SelfAsserted" ,
170- headers = headers ,
171- params = {
172- "tx" : "StateProperties=" + sign_in_config .transId ,
173- "p" : "B2C_1A_SignUpOrSigninOnline" ,
174- },
175- data = form_data ,
176- )
177-
178- if self_asserted_response .status != 200 :
179- raise IOError (
180- f"SelfAsserted: Bad response status: { self_asserted_response .status } "
181- )
182- satxt = await self_asserted_response .text ()
183-
184- sa = from_dict (SelfAssertedResponse , json .loads (satxt ))
185-
186- if sa .status != "200" :
187- raise InvalidCredentialsException ()
188-
189- confirmed_response = await self ._session .get (
190- f"{ LOGIN_BASE } /api/CombinedSigninAndSignup/confirmed" ,
191- headers = headers ,
192- params = {
193- "csrf_token" : sign_in_config .csrf ,
194- "tx" : "StateProperties=" + sign_in_config .transId ,
195- "p" : "B2C_1A_SignUpOrSigninOnline" ,
196- },
197- )
198-
199- if confirmed_response .status != 200 :
200- raise IOError (
201- f"CombinedSigninAndSignup: Bad response status: { confirmed_response .status } "
202- )
203-
204- loginString = await confirmed_response .text ()
205- if not await self .submit_form (loginString ):
206- raise IOError ("Error parsing HTML submit form" )
207-
208- async def submit_form (self , response : str ) -> bool :
209- login_page = BeautifulSoup (response , features = "html.parser" )
210- form = login_page .select ("form" )
211- login_state = login_page .select ("input[name=state]" )
212- login_code = login_page .select ("input[name=code]" )
213-
214- if len (form ) == 0 or len (login_state ) == 0 or len (login_code ) == 0 :
215- _LOGGER .info ("Could not load login page" )
216- return False
217-
218- form = form [0 ]
219- login_state = login_state [0 ]
220- login_code = login_code [0 ]
221-
222- action = form .attrs ["action" ]
223-
224- form_data = aiohttp .FormData ()
225- form_data .add_field ("state" , login_state .attrs ["value" ])
226- form_data .add_field ("code" , login_code .attrs ["value" ])
227-
228- login_response = await self ._session .post (
229- action , data = form_data , headers = self ._headers
230- )
231-
232- if login_response .status != 200 :
233- raise IOError (f"Bad api login response: { login_response .status } " )
234- return True
0 commit comments