diff --git a/synology_dsm/exceptions.py b/synology_dsm/exceptions.py index 377d40f..2a0c4b4 100644 --- a/synology_dsm/exceptions.py +++ b/synology_dsm/exceptions.py @@ -51,39 +51,40 @@ class SynologyDSMAPIErrorException(SynologyDSMException): # Login class SynologyDSMLoginFailedException(SynologyDSMException): """Failed to login exception.""" - pass + def __init__(self, code, details=None): + super(SynologyDSMLoginFailedException, self).__init__(API_AUTH, code, details) class SynologyDSMLoginInvalidException(SynologyDSMLoginFailedException): """Invalid password & not admin account exception.""" def __init__(self, username): message = "Invalid password or not admin account: %s" % username - super(SynologyDSMLoginInvalidException, self).__init__(API_AUTH, 400, message) + super(SynologyDSMLoginInvalidException, self).__init__(400, message) class SynologyDSMLoginDisabledAccountException(SynologyDSMLoginFailedException): """Guest & disabled account exception.""" def __init__(self, username): message = "Guest or disabled account: %s" % username - super(SynologyDSMLoginDisabledAccountException, self).__init__(API_AUTH, 401, message) + super(SynologyDSMLoginDisabledAccountException, self).__init__(401, message) class SynologyDSMLoginPermissionDeniedException(SynologyDSMLoginFailedException): """No access to login exception.""" def __init__(self, username): message = "Permission denied for account: %s" % username - super(SynologyDSMLoginPermissionDeniedException, self).__init__(API_AUTH, 402, message) + super(SynologyDSMLoginPermissionDeniedException, self).__init__(402, message) class SynologyDSMLogin2SARequiredException(SynologyDSMLoginFailedException): """2SA required to login exception.""" def __init__(self, username): message = "Two-step authentication required for account: %s" % username - super(SynologyDSMLogin2SARequiredException, self).__init__(API_AUTH, 403, message) + super(SynologyDSMLogin2SARequiredException, self).__init__(403, message) class SynologyDSMLogin2SAFailedException(SynologyDSMLoginFailedException): """2SA code failed exception.""" def __init__(self): message = "Two-step authentication failed, retry with a new pass code" - super(SynologyDSMLogin2SAFailedException, self).__init__(API_AUTH, 404, message) + super(SynologyDSMLogin2SAFailedException, self).__init__(404, message) diff --git a/synology_dsm/synology_dsm.py b/synology_dsm/synology_dsm.py index 71cc4b4..0e12b3e 100644 --- a/synology_dsm/synology_dsm.py +++ b/synology_dsm/synology_dsm.py @@ -156,9 +156,12 @@ class SynologyDSM(object): 401: SynologyDSMLoginDisabledAccountException(self.username), 402: SynologyDSMLoginPermissionDeniedException(self.username), 403: SynologyDSMLogin2SARequiredException(self.username), - 404: SynologyDSMLogin2SAFailedException, + 404: SynologyDSMLogin2SAFailedException(), } - raise switcher.get(result["error"]["code"], SynologyDSMLoginFailedException) + raise switcher.get( + result["error"]["code"], + SynologyDSMLoginFailedException(result["error"]["code"], self.username), + ) # Parse result if valid self._session_id = result["data"]["sid"] diff --git a/tests/__init__.py b/tests/__init__.py index be29abf..4c3cd9a 100644 --- a/tests/__init__.py +++ b/tests/__init__.py @@ -19,6 +19,7 @@ from synology_dsm.const import API_AUTH, API_INFO from .const import ( ERROR_INSUFFICIENT_USER_PRIVILEGE, ERROR_AUTH_INVALID_CREDENTIALS, + ERROR_AUTH_MAX_TRIES, ERROR_AUTH_OTP_AUTHENTICATE_FAILED, DEVICE_TOKEN, ) @@ -105,6 +106,8 @@ VALID_USER_2SA = "valid_user_2sa" VALID_PASSWORD = "valid_password" VALID_OTP = "123456" +USER_MAX_TRY = "user_max" + class SynologyDSMMock(SynologyDSM): """Mocked SynologyDSM.""" @@ -192,6 +195,9 @@ class SynologyDSMMock(SynologyDSM): if VALID_USER in url and VALID_PASSWORD in url: return API_SWITCHER[self.dsm_version]["AUTH_LOGIN"] + if USER_MAX_TRY in url: + return ERROR_AUTH_MAX_TRIES + return ERROR_AUTH_INVALID_CREDENTIALS if self.API_URI in url: diff --git a/tests/test_synology_dsm.py b/tests/test_synology_dsm.py index 1461e49..03bebbd 100644 --- a/tests/test_synology_dsm.py +++ b/tests/test_synology_dsm.py @@ -12,6 +12,7 @@ from synology_dsm.exceptions import ( SynologyDSMLoginInvalidException, SynologyDSMLogin2SARequiredException, SynologyDSMLogin2SAFailedException, + SynologyDSMLoginFailedException, ) from synology_dsm.const import API_AUTH, API_INFO @@ -24,6 +25,7 @@ from . import ( VALID_PASSWORD, VALID_USER, VALID_USER_2SA, + USER_MAX_TRY, ) from .const import SESSION_ID, DEVICE_TOKEN, SYNO_TOKEN @@ -222,6 +224,20 @@ class TestSynologyDSM(TestCase): assert api._syno_token is None assert api._device_token is None + def test_login_basic_failed(self): + """Test basic failed login.""" + api = SynologyDSMMock( + VALID_HOST, VALID_PORT, USER_MAX_TRY, VALID_PASSWORD, VALID_SSL + ) + + with pytest.raises(SynologyDSMLoginFailedException) as error: + api.login() + error_value = error.value.args[0] + assert error_value["api"] == "SYNO.API.Auth" + assert error_value["code"] == 407 + assert error_value["reason"] == "Max Tries (if auto blocking is set to true)" + assert error_value["details"] == USER_MAX_TRY + def test_request_timeout(self): """Test request timeout.""" api = SynologyDSMMock(