user.py 5.5 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189
  1. import sqlmodel
  2. from .apikey import apikey
  3. from .password import password
  4. from .builder import builder
  5. from .code_key import code_key
  6. from .code_key import code_key_manager
  7. class user(sqlmodel.SQLModel, table = True):
  8. """
  9. This represents user in database. All users has own unique nick and api
  10. key. Nick and password is used to login, api key is long, random and
  11. used to access database via API.
  12. """
  13. id: int = sqlmodel.Field(default = None, primary_key = True)
  14. nick: str = sqlmodel.Field(index = True, unique = True)
  15. password: str = sqlmodel.Field(index = False)
  16. apikey: str = sqlmodel.Field(index = True, unique = True)
  17. code_key: str = sqlmodel.Field(index = False)
  18. def key(self, password: str) -> code_key_manager | None:
  19. """
  20. This return crypto key wrapper, to manage, recrypt, encrypt, decrypt
  21. and other with key. It require password, and when code key is not
  22. set, return None.
  23. Parameters:
  24. password (str): Password used to decrypt crypto key
  25. Returns:
  26. (code_key_manager): Crypto key wrapper
  27. """
  28. if self.code_key is None:
  29. return None
  30. return code_key(password = password, crypted_key = self.code_key)
  31. @property
  32. def in_database(self) -> bool:
  33. """ True when user exists in database. """
  34. return self.id is not None
  35. @property
  36. def ready(self) -> bool:
  37. """ True when all fields are filled. """
  38. if self.nick is None:
  39. return False
  40. if self.password is None:
  41. return False
  42. if self.apikey is None:
  43. return False
  44. if self.code_key is None:
  45. return False
  46. return True
  47. def __str__(self) -> str:
  48. """
  49. This function dump user to string, very usefull for debug.
  50. Returns:
  51. (str): User as string
  52. """
  53. result = ""
  54. result = result + "User "
  55. if self.id is not None:
  56. result = result + "(" + str(self.id) + ")"
  57. result = result + "\n"
  58. result = result + "Nick: " + self.nick + "\n"
  59. result = result + "Password: " + self.password + "\n"
  60. result = result + "API key: " + self.apikey + "\n"
  61. result = result + "Code KEY: " + self.code_key + "\n"
  62. return result
  63. class user_builder(builder, target_type = user):
  64. """
  65. This class is responsible for building new user.
  66. """
  67. def __init__(self, target: user | None = None) -> None:
  68. """
  69. This create new user builder. It can be initialized by already
  70. created user. When None create empty user.
  71. Parameters:
  72. target(user | None): Target to initialize builder with
  73. """
  74. super().__init__(target)
  75. self._target.apikey = apikey()
  76. @property
  77. def nick(self) -> str | None:
  78. """
  79. return: str | None - Current nick of the user in builder
  80. """
  81. return self._target.nick
  82. @property
  83. def password(self) -> bool:
  84. """
  85. return: bool - True when password is set, false if not
  86. """
  87. return self._target.password is not None
  88. @nick.setter
  89. def nick(self, target: str) -> None:
  90. """
  91. target: str - New nick for the user
  92. """
  93. self._target.nick = target.upper()
  94. def set_password(
  95. self,
  96. password: str,
  97. old_password: str | None = None
  98. ) -> None:
  99. """
  100. This function set password to user. When only password is given, then
  101. it try to init user, which not have password and crypto key yet. User
  102. which already set password, and crypto key, must being updated with
  103. also old password.
  104. Parameters:
  105. password (str): New password to set
  106. old_password (str | None) = None: Old password, require to recrypt
  107. """
  108. if old_password is None:
  109. self.__init_password(password)
  110. return
  111. self.__change_password(old_password, password)
  112. def __init_password(self, target: str) -> None:
  113. """
  114. This function initialize user with new password. User can not already
  115. have both password, and crypto key. When user already have crypto key
  116. or password, then Exception is raised, to protect crypto key to not
  117. being overwrited.
  118. Parameters:
  119. target (str): New password to set
  120. """
  121. if self._target.password is not None:
  122. raise Exception("Password and code key is already set.")
  123. if self._target.code_key is not None:
  124. raise Exception("Password and code key is already set.")
  125. self._target.password = password(target).result
  126. self._target.code_key = code_key(password = target)
  127. def __change_password(self, old_password: str, new_password: str) -> None:
  128. """
  129. This change password, when user already have password and code key. It
  130. recrypt crypto key, to could use new password for secret decrypting.
  131. Parameters:
  132. old_password (str): Old password
  133. new_password (str): New password to set
  134. """
  135. if old_password == new_password:
  136. raise Exception("New password is same as old password.")
  137. key = self._target.key(old_password)
  138. if key is None or self._target.password is None:
  139. raise Exception("User crypto key is not initialized yet.")
  140. self._target.code_key = key.recrypt(new_password).encrypted
  141. self._target.password = password(new_password).result