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
13 changes: 7 additions & 6 deletions synology_dsm/exceptions.py
Original file line number Diff line number Diff line change
Expand Up @@ -51,39 +51,40 @@ def __init__(self, api, code, details):
# 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)
7 changes: 5 additions & 2 deletions synology_dsm/synology_dsm.py
Original file line number Diff line number Diff line change
Expand Up @@ -156,9 +156,12 @@ def login(self, otp_code=None):
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"]
Expand Down
6 changes: 6 additions & 0 deletions tests/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,7 @@
from .const import (
ERROR_INSUFFICIENT_USER_PRIVILEGE,
ERROR_AUTH_INVALID_CREDENTIALS,
ERROR_AUTH_MAX_TRIES,
ERROR_AUTH_OTP_AUTHENTICATE_FAILED,
DEVICE_TOKEN,
)
Expand Down Expand Up @@ -105,6 +106,8 @@
VALID_PASSWORD = "valid_password"
VALID_OTP = "123456"

USER_MAX_TRY = "user_max"


class SynologyDSMMock(SynologyDSM):
"""Mocked SynologyDSM."""
Expand Down Expand Up @@ -192,6 +195,9 @@ def _execute_request(self, method, url, params, **kwargs):
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:
Expand Down
16 changes: 16 additions & 0 deletions tests/test_synology_dsm.py
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,7 @@
SynologyDSMLoginInvalidException,
SynologyDSMLogin2SARequiredException,
SynologyDSMLogin2SAFailedException,
SynologyDSMLoginFailedException,
)
from synology_dsm.const import API_AUTH, API_INFO

Expand All @@ -24,6 +25,7 @@
VALID_PASSWORD,
VALID_USER,
VALID_USER_2SA,
USER_MAX_TRY,
)
from .const import SESSION_ID, DEVICE_TOKEN, SYNO_TOKEN

Expand Down Expand Up @@ -222,6 +224,20 @@ def test_login_2sa_failed(self):
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(
Expand Down