Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
6 changes: 5 additions & 1 deletion README.md
Original file line number Diff line number Diff line change
Expand Up @@ -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

Expand Down
40 changes: 36 additions & 4 deletions sagemcom_api/client.py
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
"""Client to communicate with Sagemcom F@st internal APIs."""

from __future__ import annotations

import asyncio
Expand Down Expand Up @@ -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,
Expand All @@ -38,6 +40,7 @@
AccessRestrictionException,
AuthenticationException,
BadRequestException,
LoginRetryErrorException,
LoginTimeoutException,
MaximumSessionCountException,
NonWritableParameterException,
Expand All @@ -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,
Expand All @@ -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
Expand Down Expand Up @@ -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
Expand Down Expand Up @@ -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",
Expand Down Expand Up @@ -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)
Expand All @@ -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.
Expand Down
2 changes: 2 additions & 0 deletions sagemcom_api/const.py
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
"""Constants for the Sagemcom F@st client."""

API_ENDPOINT = "/cgi/json-req"

DEFAULT_TIMEOUT = 7
Expand All @@ -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"
4 changes: 4 additions & 0 deletions sagemcom_api/exceptions.py
Original file line number Diff line number Diff line change
Expand Up @@ -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."""

Expand Down