diff --git a/app/errors.py b/app/errors.py index b951eb16..113b248f 100644 --- a/app/errors.py +++ b/app/errors.py @@ -121,3 +121,10 @@ class AccountAlreadyLinkedToAnotherUserException(LinkException): class AccountIsUsingAliasAsEmail(LinkException): def __init__(self): super().__init__("Your account has an alias as it's email address") + + +class ProtonAccountNotVerified(LinkException): + def __init__(self): + super().__init__( + "The Proton account you are trying to use has not been verified" + ) diff --git a/app/proton/proton_client.py b/app/proton/proton_client.py index 9f4beac5..f06325b8 100644 --- a/app/proton/proton_client.py +++ b/app/proton/proton_client.py @@ -7,11 +7,12 @@ from typing import Optional from app.account_linking import SLPlan, SLPlanType from app.config import PROTON_EXTRA_HEADER_NAME, PROTON_EXTRA_HEADER_VALUE +from app.errors import ProtonAccountNotVerified from app.log import LOG _APP_VERSION = "OauthClient_1.0.0" -PROTON_ERROR_CODE_NOT_EXISTS = 2501 +PROTON_ERROR_CODE_HV_NEEDED = 9001 PLAN_FREE = 1 PLAN_PREMIUM = 2 @@ -57,6 +58,15 @@ def convert_access_token(access_token_response: str) -> AccessCredentials: ) +def handle_response_not_ok(status: int, body: dict, text: str) -> Exception: + if status == HTTPStatus.UNPROCESSABLE_ENTITY: + res_code = body.get("Code") + if res_code == PROTON_ERROR_CODE_HV_NEEDED: + return ProtonAccountNotVerified() + + return Exception(f"Unexpected status code. Wanted 200 and got {status}: " + text) + + class ProtonClient(ABC): @abstractmethod def get_user(self) -> Optional[UserInformation]: @@ -124,11 +134,11 @@ class HttpProtonClient(ProtonClient): @staticmethod def __validate_response(res: Response) -> dict: status = res.status_code - if status != HTTPStatus.OK: - raise Exception( - f"Unexpected status code. Wanted 200 and got {status}: " + res.text - ) as_json = res.json() + if status != HTTPStatus.OK: + raise HttpProtonClient.__handle_response_not_ok( + status=status, body=as_json, text=res.text + ) res_code = as_json.get("Code") if not res_code or res_code != 1000: raise Exception( diff --git a/tests/proton/test_proton_client.py b/tests/proton/test_proton_client.py index 3879e760..154cc0af 100644 --- a/tests/proton/test_proton_client.py +++ b/tests/proton/test_proton_client.py @@ -1,5 +1,7 @@ import pytest +from http import HTTPStatus +from app.errors import ProtonAccountNotVerified from app.proton import proton_client @@ -19,3 +21,30 @@ def test_convert_access_token_not_containing_invalid_length(): for case in cases: with pytest.raises(Exception): proton_client.convert_access_token(case) + + +def test_handle_response_not_ok_account_not_verified(): + res = proton_client.handle_response_not_ok( + status=HTTPStatus.UNPROCESSABLE_ENTITY, + body={"Code": proton_client.PROTON_ERROR_CODE_HV_NEEDED}, + text="", + ) + assert isinstance(res, ProtonAccountNotVerified) + + +def test_handle_response_unprocessable_entity_not_account_not_verified(): + error_text = "some error text" + res = proton_client.handle_response_not_ok( + status=HTTPStatus.UNPROCESSABLE_ENTITY, body={"Code": 4567}, text=error_text + ) + assert error_text in res.args[0] + + +def test_handle_response_not_ok_unknown_error(): + error_text = "some error text" + res = proton_client.handle_response_not_ok( + status=123, + body={"Code": proton_client.PROTON_ERROR_CODE_HV_NEEDED}, + text=error_text, + ) + assert error_text in res.args[0]