diff --git a/README.md b/README.md index 85fdf4e..01ec20c 100644 --- a/README.md +++ b/README.md @@ -112,7 +112,11 @@ asyncio.run(main()) ### Determine the EncryptionMethod -(not supported yet) +If you are not sure which encryption method to use, you can leave it empty or pass `None` and use `get_encryption_method` to determine the encryption method. + +`get_encryption_method` will return an `EncryptionMethod` when a match is found. Best would be to use this function only during your initial investigation. + +This function will throw a `LoginTimeoutException` when no match is found, since this is still a HTTP Time Out. This could caused by the wrong encryption method, but also by trying to connect to an inaccessible host. ### Handle exceptions diff --git a/sagemcom_api/client.py b/sagemcom_api/client.py index afa71d2..b4fea4c 100644 --- a/sagemcom_api/client.py +++ b/sagemcom_api/client.py @@ -1,4 +1,5 @@ """Client to communicate with Sagemcom F@st internal APIs.""" + from __future__ import annotations import asyncio @@ -26,6 +27,7 @@ DEFAULT_USER_AGENT, XMO_ACCESS_RESTRICTION_ERR, XMO_AUTHENTICATION_ERR, + XMO_LOGIN_RETRY_ERR, XMO_MAX_SESSION_COUNT_ERR, XMO_NO_ERR, XMO_NON_WRITABLE_PARAMETER_ERR, @@ -38,6 +40,7 @@ AccessRestrictionException, AuthenticationException, BadRequestException, + LoginRetryErrorException, LoginTimeoutException, MaximumSessionCountException, NonWritableParameterException, @@ -60,7 +63,7 @@ def __init__( host: str, username: str, password: str, - authentication_method: EncryptionMethod, + authentication_method: EncryptionMethod | None = None, session: ClientSession | None = None, ssl: bool | None = False, verify_ssl: bool | None = True, @@ -77,8 +80,8 @@ def __init__( self.host = host self.username = username self.authentication_method = authentication_method + self.password = password self._password_hash = self.__generate_hash(password) - self.protocol = "https" if ssl else "http" self._current_nonce = None @@ -229,6 +232,9 @@ async def __post(self, url, data): if action_error_desc == XMO_MAX_SESSION_COUNT_ERR: raise MaximumSessionCountException(action_error) + if action_error_desc == XMO_LOGIN_RETRY_ERR: + raise LoginRetryErrorException(action_error) + raise UnknownException(action_error) return result @@ -264,7 +270,8 @@ async def __api_request_async(self, actions, priority=False): raise ConnectionError(str(exception)) from exception async def login(self): - """TODO.""" + """Login to the SagemCom F@st router using a username and password.""" + actions = { "id": 0, "method": "logIn", @@ -293,7 +300,7 @@ async def login(self): response = await self.__api_request_async([actions], True) except asyncio.TimeoutError as exception: raise LoginTimeoutException( - "Request timed-out. This is mainly due to using the wrong encryption method." + "Login request timed-out. This could be caused by using the wrong encryption method, or using a (non) SSL connection." ) from exception data = self.__get_response(response) @@ -315,6 +322,31 @@ async def logout(self): self._server_nonce = "" self._request_id = -1 + async def get_encryption_method(self): + """Determine which encryption method to use for authentication and set it directly.""" + for encryption_method in EncryptionMethod: + try: + self.authentication_method = encryption_method + self._password_hash = self.__generate_hash( + self.password, encryption_method + ) + + await self.login() + + self._server_nonce = "" + self._session_id = 0 + self._request_id = -1 + + return encryption_method + except ( + LoginTimeoutException, + AuthenticationException, + LoginRetryErrorException, + ): + pass + + return None + async def get_value_by_xpath(self, xpath: str, options: dict | None = None) -> dict: """ Retrieve raw value from router using XPath. diff --git a/sagemcom_api/const.py b/sagemcom_api/const.py index 7475eb2..f0add30 100644 --- a/sagemcom_api/const.py +++ b/sagemcom_api/const.py @@ -1,4 +1,5 @@ """Constants for the Sagemcom F@st client.""" + API_ENDPOINT = "/cgi/json-req" DEFAULT_TIMEOUT = 7 @@ -12,3 +13,4 @@ XMO_REQUEST_NO_ERR = "XMO_REQUEST_NO_ERR" XMO_UNKNOWN_PATH_ERR = "XMO_UNKNOWN_PATH_ERR" XMO_MAX_SESSION_COUNT_ERR = "XMO_MAX_SESSION_COUNT_ERR" +XMO_LOGIN_RETRY_ERR = "XMO_LOGIN_RETRY_ERR" diff --git a/sagemcom_api/exceptions.py b/sagemcom_api/exceptions.py index e99b07b..3906745 100644 --- a/sagemcom_api/exceptions.py +++ b/sagemcom_api/exceptions.py @@ -10,6 +10,10 @@ class AuthenticationException(Exception): """Raised when authentication is not correct.""" +class LoginRetryErrorException(Exception): + """Raised when too many login retries are attempted.""" + + class LoginTimeoutException(Exception): """Raised when a timeout is encountered during login."""