from .user import user from .user import user_builder from .user_loader import user_loader from .application_part import application_part from .validators import nick_validator from .validators import password_validator class application_user(application_part): """ This class is part of the app, which is responsible for user api endpoints, like registering users, login to app, change nick and others. To full responses and parameters documentation, see api documentation. """ def get(self, apikey: str) -> dict: """ This return information about user, like nick or code_key, to use in end-to-end encryption. Parameters: apikey (str): Apikey of the user Returns: (dict): Information about user """ with self.__loader as loader: user = loader.get_by_apikey(apikey) if user is None: return self._fail_no_apikey() return self._success_response( nick = user.nick, password = user.password, apikey = user.apikey, code_key = user.code_key ) def register(self, nick: str, password: str) -> dict: """ This register new user, by password and nick. It check that nick is not in use, also validate password and nick. ApiKey and code_key would be generate by operating system random generator. Parameters: nick (str): Nick of the new user password (str): Password of the new user Returns: (dict): Response to generate json """ validate = self._validation( "nick", nick_validator(nick) ) validate = validate or self._validation( "password", password_validator(password) ) if validate is not None: return validate builder = user_builder() builder.nick = nick builder.set_password(password) with self.__loader as loader: new_user = builder.result if loader.nick_in_use(new_user.nick): return self._fail_response(cause = "Nick already in use.") if loader.register(new_user): return self._apikey_response(new_user.apikey) return self._fail_response(cause = "Other database error.") def login(self, nick: str, password: str) -> dict: """ This function login user. To operate client apps require apikey. This endpoint would return apikey, when valid nick and password had been provided. Parameters: nick (str): Nick of the user password (str): Passworrd of the user Returns: (dict): Result with apikey or error on fail """ with self.__loader as loader: user = loader.login(nick, password) if user is None: return self._fail_response(cause = "Bad login or password.") return self._apikey_response(user.apikey) def unregister(self, apikey: str, password: str) -> dict: """ This function drop user from database. It require password as second validation, and of course apikey to identify user. Parameters: apikey (str): ApiKey of the user to drop password (str): Password of the user to drop Returns: (dict): Result of the operation as to generate json response """ with self.__loader as loader: user = loader.get_by_apikey(apikey) if user is None: return self._fail_no_apikey() if not user_builder(user).check_password(password): return self._fail_bad_password() loader.unregister(user) return self._success_response() def apikey_refresh(self, apikey: str) -> dict: """ This function refresh apikey. It is useable when want to logout all devices which store apikey to stay logged in. Parameters: apikey (str): ApiKey of the user to refresh apikey Returns: (dict): Result of the operation, with new apikey when success """ with self.__loader as loader: user = loader.get_by_apikey(apikey) if user is None: return self._fail_no_apikey() builder = user_builder(user) builder.refresh_apikey() new_user = builder.result if not loader.save(new_user): return self._fail_response(cause = "Database error.") return self._apikey_response(new_user.apikey) def change_password( self, apikey: str, old_password: str, new_password: str ) -> dict: """ This function change password of the user. It require also old password, to decrypt key, which would be re-encrypt by new password. Of course new password would be validated before set. Parameters: apikey (str): ApiKey of the user to work on old_password (str): Old password of the user new_password (str): New password which would be set Returns: (dict): Result of the operation to create response """ validate = self._validation( "password", password_validator(new_password) ) if validate is not None: return validate with self.__loader as loader: user = loader.get_by_apikey(apikey) if user is None: return self._fail_no_apikey() builder = user_builder(user) if not builder.set_password(new_password, old_password): return self._fail_bad_password() new_user = builder.result loader.save(new_user) return self._apikey_response(new_user.apikey) def change_nick(self, apikey: str, nick: str) -> dict: """ This function would change nick of the user. It also check that nick is not in use, and validate that nick is not bad formated. Parameters: apikey (str): ApiKey of the user to work on nick (str): New nick for the user Returns: (dict): Result of the operation to create response """ validation = self._validation( "nick", nick_validator(nick) ) if validation is not None: return validation with self.__loader as loader: user = loader.get_by_apikey(apikey) if user is None: return self._fail_no_apikey() if loader.nick_in_use(nick): return self._fail_response(cause = "Nick already in use.") builder = user_builder(user) builder.nick = nick new_user = builder.result if not loader.save(new_user): return self._fail_response(cause = "Other database error.") return self._success_response() @property def __loader(self) -> user_loader: """ This return new user_loader with database connector. """ return user_loader(self._connector)