errors.py 2.7 KB

1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889909192
  1. # Copyright (c) 2020 Tulir Asokan
  2. #
  3. # This Source Code Form is subject to the terms of the Mozilla Public
  4. # License, v. 2.0. If a copy of the MPL was not distributed with this
  5. # file, You can obtain one at http://mozilla.org/MPL/2.0/.
  6. from typing import Any, Dict, Optional
  7. class RPCError(Exception):
  8. pass
  9. class UnexpectedError(RPCError):
  10. pass
  11. class UnexpectedResponse(RPCError):
  12. def __init__(self, resp_type: str, data: Any) -> None:
  13. super().__init__(f"Got unexpected response type {resp_type}")
  14. self.resp_type = resp_type
  15. self.data = data
  16. class NotConnected(RPCError):
  17. pass
  18. class ResponseError(RPCError):
  19. def __init__(self, data: Dict[str, Any], error_type: Optional[str] = None,
  20. message_override: Optional[str] = None) -> None:
  21. self.data = data
  22. msg = message_override or data["message"]
  23. if error_type:
  24. msg = f"{error_type}: {msg}"
  25. super().__init__(msg)
  26. class TimeoutException(ResponseError):
  27. pass
  28. class UnknownIdentityKey(ResponseError):
  29. pass
  30. class CaptchaRequired(ResponseError):
  31. pass
  32. class AuthorizationFailedException(ResponseError):
  33. pass
  34. class UserAlreadyExistsError(ResponseError):
  35. def __init__(self, data: Dict[str, Any]) -> None:
  36. super().__init__(data, message_override="You're already logged in")
  37. class RequestValidationFailure(ResponseError):
  38. def __init__(self, data: Dict[str, Any]) -> None:
  39. results = data["validationResults"]
  40. result_str = ", ".join(results) if isinstance(results, list) else str(results)
  41. super().__init__(data, message_override=result_str)
  42. response_error_types = {
  43. "invalid_request": RequestValidationFailure,
  44. "TimeoutException": TimeoutException,
  45. "UserAlreadyExists": UserAlreadyExistsError,
  46. "RequestValidationFailure": RequestValidationFailure,
  47. "UnknownIdentityKey": UnknownIdentityKey,
  48. "CaptchaRequired": CaptchaRequired,
  49. "AuthorizationFailedException": AuthorizationFailedException,
  50. # TODO add rest from https://gitlab.com/signald/signald/-/tree/main/src/main/java/io/finn/signald/exceptions
  51. }
  52. def make_response_error(data: Dict[str, Any]) -> ResponseError:
  53. error_data = data["error"]
  54. if isinstance(error_data, str):
  55. error_data = {"message": error_data}
  56. elif not isinstance(error_data, dict):
  57. error_data = {"message": str(error_data)}
  58. if "message" not in error_data:
  59. error_data["message"] = "no message, see signald logs"
  60. error_type = data.get("error_type")
  61. try:
  62. error_class = response_error_types[error_type]
  63. except KeyError:
  64. return ResponseError(error_data, error_type=error_type)
  65. else:
  66. return error_class(error_data)