Skip to content

Commit 3424404

Browse files
authored
Add method to automatically determine EncryptionMethod to use (#50)
1 parent c477a99 commit 3424404

File tree

4 files changed

+45
-5
lines changed

4 files changed

+45
-5
lines changed

README.md

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -112,7 +112,11 @@ asyncio.run(main())
112112

113113
### Determine the EncryptionMethod
114114

115-
(not supported yet)
115+
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.
116+
117+
`get_encryption_method` will return an `EncryptionMethod` when a match is found. Best would be to use this function only during your initial investigation.
118+
119+
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.
116120

117121
### Handle exceptions
118122

sagemcom_api/client.py

Lines changed: 35 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -27,6 +27,7 @@
2727
DEFAULT_USER_AGENT,
2828
XMO_ACCESS_RESTRICTION_ERR,
2929
XMO_AUTHENTICATION_ERR,
30+
XMO_LOGIN_RETRY_ERR,
3031
XMO_MAX_SESSION_COUNT_ERR,
3132
XMO_NO_ERR,
3233
XMO_NON_WRITABLE_PARAMETER_ERR,
@@ -39,6 +40,7 @@
3940
AccessRestrictionException,
4041
AuthenticationException,
4142
BadRequestException,
43+
LoginRetryErrorException,
4244
LoginTimeoutException,
4345
MaximumSessionCountException,
4446
NonWritableParameterException,
@@ -61,7 +63,7 @@ def __init__(
6163
host: str,
6264
username: str,
6365
password: str,
64-
authentication_method: EncryptionMethod,
66+
authentication_method: EncryptionMethod | None = None,
6567
session: ClientSession | None = None,
6668
ssl: bool | None = False,
6769
verify_ssl: bool | None = True,
@@ -78,8 +80,8 @@ def __init__(
7880
self.host = host
7981
self.username = username
8082
self.authentication_method = authentication_method
83+
self.password = password
8184
self._password_hash = self.__generate_hash(password)
82-
8385
self.protocol = "https" if ssl else "http"
8486

8587
self._current_nonce = None
@@ -232,6 +234,9 @@ async def __post(self, url, data):
232234
if action_error_desc == XMO_MAX_SESSION_COUNT_ERR:
233235
raise MaximumSessionCountException(action_error)
234236

237+
if action_error_desc == XMO_LOGIN_RETRY_ERR:
238+
raise LoginRetryErrorException(action_error)
239+
235240
raise UnknownException(action_error)
236241

237242
return result
@@ -267,7 +272,8 @@ async def __api_request_async(self, actions, priority=False):
267272
raise ConnectionError(str(exception)) from exception
268273

269274
async def login(self):
270-
"""TODO."""
275+
"""Login to the SagemCom F@st router using a username and password."""
276+
271277
actions = {
272278
"id": 0,
273279
"method": "logIn",
@@ -296,7 +302,7 @@ async def login(self):
296302
response = await self.__api_request_async([actions], True)
297303
except asyncio.TimeoutError as exception:
298304
raise LoginTimeoutException(
299-
"Request timed-out. This is mainly due to using the wrong encryption method."
305+
"Login request timed-out. This could be caused by using the wrong encryption method, or using a (non) SSL connection."
300306
) from exception
301307

302308
data = self.__get_response(response)
@@ -318,6 +324,31 @@ async def logout(self):
318324
self._server_nonce = ""
319325
self._request_id = -1
320326

327+
async def get_encryption_method(self):
328+
"""Determine which encryption method to use for authentication and set it directly."""
329+
for encryption_method in EncryptionMethod:
330+
try:
331+
self.authentication_method = encryption_method
332+
self._password_hash = self.__generate_hash(
333+
self.password, encryption_method
334+
)
335+
336+
await self.login()
337+
338+
self._server_nonce = ""
339+
self._session_id = 0
340+
self._request_id = -1
341+
342+
return encryption_method
343+
except (
344+
LoginTimeoutException,
345+
AuthenticationException,
346+
LoginRetryErrorException,
347+
):
348+
pass
349+
350+
return None
351+
321352
async def get_value_by_xpath(self, xpath: str, options: dict | None = None) -> dict:
322353
"""
323354
Retrieve raw value from router using XPath.

sagemcom_api/const.py

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -13,3 +13,4 @@
1313
XMO_REQUEST_NO_ERR = "XMO_REQUEST_NO_ERR"
1414
XMO_UNKNOWN_PATH_ERR = "XMO_UNKNOWN_PATH_ERR"
1515
XMO_MAX_SESSION_COUNT_ERR = "XMO_MAX_SESSION_COUNT_ERR"
16+
XMO_LOGIN_RETRY_ERR = "XMO_LOGIN_RETRY_ERR"

sagemcom_api/exceptions.py

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,10 @@ class AuthenticationException(Exception):
1010
"""Raised when authentication is not correct."""
1111

1212

13+
class LoginRetryErrorException(Exception):
14+
"""Raised when too many login retries are attempted."""
15+
16+
1317
class LoginTimeoutException(Exception):
1418
"""Raised when a timeout is encountered during login."""
1519

0 commit comments

Comments
 (0)