def auth(self, response: Message): """Метод, отвечающий за авторизацию на сервере""" if response.action == REGISTER or response.action == AUTH: try: if response.action == REGISTER: data = { ACTION: REGISTER, FROM: self.user_name, TEXT: self.password } self.send(Message(**data)) response = receive(self.__sock, self.__logger)[0] # Получаем публичный ключ и декодируем его из байтов pubkey = self.keys.publickey().export_key().decode( 'ascii') if self.keys else None # Запускаем процедуру авторизации # Получаем хэш пароля passwd_bytes = self.password.encode('utf-8') salt = self.user_name.lower().encode('utf-8') passwd_hash = hashlib.pbkdf2_hmac('sha512', passwd_bytes, salt, 10000) passwd_hash_string = binascii.hexlify(passwd_hash) # Если сервер вернул ошибку, бросаем исключение. if response.response: if response.response == FORBIDDEN: raise ServerError(response.text) elif response.response == OK: # Если всё нормально, # то продолжаем процедуру авторизации. ans_data = response.text hash_str = hmac.new(passwd_hash_string, ans_data.encode('utf-8')) digest = hash_str.digest() request_data = { ACTION: AUTH, FROM: self.user_name, TEXT: binascii.b2a_base64(digest).decode('ascii'), USER: pubkey } self.send(Message(**request_data)) responses = receive(self.__sock, self.__logger) if responses and responses[0].response == OK: info_msg = f'Клиент запущен ({self.user_name}).' print(info_msg) self.__logger.info(info_msg) return True else: return False except OSError: raise ServerError('Сбой соединения в процессе авторизации.')
def interact(self): while True: try: num = abs( int( input(' | '.join([ f'{key}. {action["name"]}' for key, action in enumerate(self.__actions, 0) ]) + ' | Выберите действие: '))) if 0 <= num <= len(self.__actions): start = self.__actions[num] else: raise ValueError if start[ACTION] == 'exit': raise KeyboardInterrupt params = {ACTION: start[ACTION]} if 'params' in start: for param in start['params']: p = str(input(f'Выберите параметр "{param}": ')) params[param] = p print() break except ValueError: pass return Message(**params)
def load_contacts(self): """Метод загрузки списка контактов""" data = {ACTION: GET_CONTACTS, FROM: self.user_name} request = Message(data) self.send(request) time.sleep(1) messages = receive(self.__sock, self.__logger) return messages or False
def __check_presence(self): """Метод проверки соединения""" data = {ACTION: PRESENCE, FROM: self.__user_name} request = Message(data) self.send(request) messages = receive(self.__sock, self.__logger) return messages[0] if messages and messages[0].response == OK \ else False
def send_message(self, to, message): """ Метод, составляющий запрос на отправку сообщения контакту. :param to: Имя контакта :param message: Сообщение :return: """ data = {ACTION: SEND_MSG, TO: to, TEXT: message} self.__client.send(Message(**data))
def user_list_update(self): """ Метод, составляющий запрос на получение списка подключённых клиентов. :return: """ self.__client.logger.debug( f'Запрос списка известных пользователей {self.__client.user_name}') data = { ACTION: GET_CONNECTED, } self.__client.send(Message(**data))
def remove_contact(self, contact): """ Метод, составляющий запрос на удаление контакта :param contact: Имя контакта :return: """ self.__client.logger.debug(f'Удаление контакта {contact}') data = { ACTION: DEL_CONTACT, USER: contact, } self.__client.send(Message(**data))
def add_contact(self, contact): """ Метод, составляющий запрос на добавление контакта. :param contact: Имя контакта :return: """ self.__client.logger.debug(f'Создание контакта {contact}') data = { ACTION: ADD_CONTACT, USER: contact, } self.__client.send(Message(**data))
def key_request(self, user_name): """ Метод, составляющий запрос на получение открытого ключа контакта. :param user_name: Имя контакта :return: """ data = { ACTION: PUBLIC_KEY_REQUEST, FROM: self.user_name, USER: user_name } self.__client.send(Message(**data))
def key_request(self, user_name): """ Метод, составляющий запрос на получение открытого ключа контакта. :param user_name: Имя контакта :return: """ data = { ACTION: PUBLIC_KEY_REQUEST, FROM: self.user_name, USER: user_name } with socket_lock: self.__client.send(Message(**data)) responses = receive(self.__client.sock, self.__client.logger) if responses: response = responses[0] if response.response and response.text: return response.text self.__client.logger.error( f'Не удалось получить ключ собеседника{user_name}.')
def key_request(self, user_name: str) -> str: """ Метод получающий открытый ключ контакта с сервера. :param user_name: Имя контакта :return: """ data = { ACTION: PUBLIC_KEY_REQUEST, FROM: self.__client.user_name, USER: user_name } with socket_lock: self.__client.send(Message(**data)) responses = receive(self.__client.sock, self.__client.logger) if responses: response = responses[0] if response.response and response.text: return response.text self.__client.logger.error( f'Не удалось получить ключ собеседника{user_name}.')
def interact(self) -> Message: """ Метод взаимодействия с пользователем. :return: """ while True: try: params = {} num = abs(int(input('Выберите действие: '))) if 0 <= num <= len(self.__actions): start = self.__actions[num] else: raise ValueError if start[ACTION] == 'exit': raise KeyboardInterrupt elif start[ACTION] == 'help': print(self.__help_info) continue params = {ACTION: start[ACTION]} if 'params' in start: for param in start['params']: p = str(input(f'Выберите параметр "{param}": ')) params[param] = p if start[ACTION] == ADD_CONTACT: self.__repo.add_contact(params[USER]) elif start[ACTION] == DEL_CONTACT: self.__repo.del_contact(params[USER]) elif start[ACTION] == SEND_MSG: if params[TO] == '' or params[TO] == '*': to = ', '.join(self.__repo.get_contacts()) else: to = params[TO] self.__repo.save_message(to, "out", params[TEXT]) break except ValueError: print('Действие не распознано, попробуйте еще раз...') pass return Message(**params)
async def run_action(self, request: Message): """ Метод, обрабатывающий сообщения от клиента :param request: Сообщение клиента :return: Созданные ответы """ if request.action in (PRESENCE, REGISTER, AUTH): return self.auth(request) elif request.action == SEND_MSG: contacts = request.destination.replace(' ', '').split(',') if len(contacts) == 1 and (not contacts[0] or contacts[0] == '*'): contacts = self.__repo.get_contact_list(request.sender) if len(contacts) == 1 and contacts[0] == 'Общий_чат': contacts = self.__repo.users_list(active=True) contacts.remove(request.sender) self.__repo.add_general_chat_history(request.sender, request.text) request.sender = 'Общий_чат' responses = [] for contact in contacts: data = { ACTION: SEND_MSG, TEXT: request.text, TO: contact, FROM: request.sender, } self.__repo.process_message(request.sender, contact) responses.append(success(**data)) return responses elif request.action == GET_CONTACTS: names = self.__repo.get_contact_list(request.sender) count = len(names) data = { ACTION: GET_CONTACTS, QUANTITY: count, } responses = [accepted(**data)] for contact in names: data = { ACTION: GET_CONTACTS, USER: contact, } responses.append(accepted(**data)) return responses elif request.action == GET_CONNECTED: names = self.__repo.users_list(active=True) responses = [] for contact in names: data = { ACTION: GET_CONNECTED, USER: contact, } responses.append(accepted(**data)) return responses # Если это запрос публичного ключа пользователя elif request.action == PUBLIC_KEY_REQUEST and request.user: data = { ACTION: PUBLIC_KEY_REQUEST, TEXT: self.__repo.get_pubkey(request.user) } if data[TEXT]: return success(**data) else: return error('Нет публичного ключа для данного пользователя') elif request.action == ADD_CONTACT: if request.sender == request.user: return error('Нельзя добавить себя') try: self.__repo.add_contact(request.sender, request.user) return success() except Exception: return error('Контакта не существует') elif request.action == DEL_CONTACT: try: self.__repo.remove_contact(request.sender, request.user) return success() except Exception: return error('Контакта не существует') elif request.action == ERROR: return error('Ошибка действия') else: return error('Действие недоступно')
def __check_presence(self): data = {ACTION: PRESENCE, FROM: self.__user_name} request = Message(data) self.send(request) messages = receive(self.__sock, self.__logger) return messages[0].response == OK if messages else False