def service_update_lists(self): """Метод реализующий отправки сервисного сообщения 205 клиентам.""" for client in self.names: try: sending_message(self.names[client], {RESPONSE: 205}) except OSError: self.remove_client(self.names[client])
def test_sending_message(self): """ Тестируем корректность работы фукции отправки, создадим тестовый сокет и проверим корректность отправки словаря """ # экземпляр тестового словаря, хранит собственно тестовый словарь test_sock_obj = TestSocket(self.test_dictionary_send) # вызов тестируемой функции, результаты будут сохранены в тестовом сокете sending_message(test_sock_obj, self.test_dictionary_send) # проверка корретности кодирования словаря. # сравниваем результат довренного кодирования и результат от тестируемой функции self.assertEqual(test_sock_obj.encoded_message, test_sock_obj.received_message)
def process_message(self, message): """ Метод отправки сообщения клиенту. """ if message[TO] in self.names and self.names[ message[TO]] in self.listen_sockets: try: sending_message(self.names[message[TO]], message) SERVER_LOGGER.info( f'Отправлено сообщение пользователю {message[TO]} от пользователя {message[FROM]}.' ) except OSError: self.remove_client(message[TO]) elif message[TO] in self.names and self.names[ message[TO]] not in self.listen_sockets: SERVER_LOGGER.error( f'Связь с клиентом {message[TO]} была потеряна. Соединение закрыто, доставка невозможна.' ) self.remove_client(self.names[message[TO]]) else: SERVER_LOGGER.error( f'Пользователь {message[TO]} не зарегистрирован на сервере, отправка сообщения невозможна.' )
def autorize_user(self, message, sock): """Метод реализующий авторизцию пользователей.""" # Если имя пользователя уже занято то возвращаем 400 SERVER_LOGGER.debug(f'Start auth process for {message[USER]}') if message[USER][ACCOUNT_NAME] in self.names.keys(): try: SERVER_LOGGER.debug('Username busy, sending 400') sending_message(sock, {RESPONSE: 400, ERROR: 'Bad request'}) except OSError: SERVER_LOGGER.debug('OS Error') pass self.clients.remove(sock) sock.close() # Проверяем что пользователь зарегистрирован на сервере. elif not self.database.check_user(message[USER][ACCOUNT_NAME]): try: SERVER_LOGGER.debug('Unknown username, sending 400') sending_message(sock, { RESPONSE: 400, ERROR: 'Пользователь не зарегистрирован.' }) except OSError: pass self.clients.remove(sock) sock.close() else: SERVER_LOGGER.debug('Correct username, starting passwd check.') # Иначе отвечаем 511 и проводим процедуру авторизации # Словарь - заготовка message_auth = {RESPONSE: 511, DATA: None} # Набор байтов в hex представлении random_str = binascii.hexlify(os.urandom(64)) # В словарь байты нельзя, декодируем (json.dumps -> TypeError) message_auth[DATA] = random_str.decode('ascii') # Создаём хэш пароля и связки с рандомной строкой, сохраняем # серверную версию ключа hash = hmac.new( self.database.get_hash(message[USER][ACCOUNT_NAME]), random_str, 'MD5') digest = hash.digest() SERVER_LOGGER.debug(f'Auth message = {message_auth}') try: # Обмен с клиентом sending_message(sock, message_auth) ans = getting_message(sock) except OSError as err: SERVER_LOGGER.debug('Error in auth, data:', exc_info=err) sock.close() return client_digest = binascii.a2b_base64(ans[DATA]) # Если ответ клиента корректный, то сохраняем его в список # пользователей. if RESPONSE in ans and ans[RESPONSE] == 511 \ and hmac.compare_digest(digest, client_digest): self.names[message[USER][ACCOUNT_NAME]] = sock client_ip, client_port = sock.getpeername() try: sending_message(sock, {RESPONSE: 200}) except OSError: self.remove_client(message[USER][ACCOUNT_NAME]) # добавляем пользователя в список активных и если у него изменился открытый ключ # сохраняем новый self.database.user_login(message[USER][ACCOUNT_NAME], client_ip, client_port, message[USER][PUBLIC_KEY]) else: try: sending_message(sock, { RESPONSE: 400, ERROR: 'Пользователь не зарегистрирован.' }) except OSError: pass self.clients.remove(sock) sock.close()
def process_client_message(self, message, client): """Метод отбработчик поступающих сообщений.""" SERVER_LOGGER.debug(f'Разбор сообщения от клиента : {message}') # Если это сообщение о присутствии, принимаем и отвечаем if ACTION in message and message[ACTION] == PRESENCE \ and TIME in message \ and USER in message: # Если сообщение о присутствии то вызываем функцию авторизации. self.autorize_user(message, client) # Если это сообщение, то отправляем его получателю. elif ACTION in message and message[ACTION] == MESSAGE \ and TO in message \ and TIME in message \ and FROM in message \ and MESSAGE in message \ and self.names[message[FROM]] == client: if message[TO] in self.names: self.database.process_message(message[FROM], message[TO]) self.process_message(message) try: sending_message(client, {RESPONSE: 200}) except OSError: self.remove_client(client) else: try: sending_message(client, { RESPONSE: 400, ERROR: 'Bad request' }) except OSError: pass return # если клиент выходит elif ACTION in message and message[ACTION] == QUIT \ and ACCOUNT_NAME in message \ and self.names[message[ACCOUNT_NAME]] == client: self.remove_client(client) # если это запрос списка контактов elif ACTION in message and message[ACTION] == GET_CONTACTS \ and USER in message and \ self.names[message[USER]] == client: try: sending_message( client, { RESPONSE: 202, LIST_INFO: self.database.get_contacts(message[USER]) }) except OSError: self.remove_client(client) # если это добавление контакта elif ACTION in message and message[ACTION] == ADD_CONTACT \ and ACCOUNT_NAME in message \ and USER in message \ and self.names[message[USER]] == client: self.database.add_contact(message[USER], message[ACCOUNT_NAME]) try: sending_message(client, {RESPONSE: 200}) except OSError: self.remove_client(client) # если это удаление контакта elif ACTION in message and message[ACTION] == REMOVE_CONTACT \ and ACCOUNT_NAME in message \ and USER in message \ and self.names[message[USER]] == client: self.database.remove_contact(message[USER], message[ACCOUNT_NAME]) try: sending_message(client, {RESPONSE: 200}) except OSError: self.remove_client(client) # если это запрос известных пользователей elif ACTION in message and message[ACTION] == USERS_REQUEST and ACCOUNT_NAME in message \ and self.names[message[ACCOUNT_NAME]] == client: try: sending_message( client, { RESPONSE: 202, LIST_INFO: [user[0] for user in self.database.users_list()] }) except OSError: self.remove_client(client) # Если это запрос публичного ключа пользователя elif ACTION in message and message[ACTION] == PUBLIC_KEY_REQUEST \ and ACCOUNT_NAME in message: response = { RESPONSE: 511, DATA: self.database.get_pubkey(message[ACCOUNT_NAME]) } # может быть, что ключа ещё нет (пользователь никогда не логинился, # тогда шлём 400) if response[DATA]: try: sending_message(client, response) except OSError: self.remove_client(client) else: try: sending_message( client, { RESPONSE: 400, ERROR: 'Нет публичного ключа для данного пользователя!' }) except OSError: self.remove_client(client) # Иначе Bad request else: try: sending_message(client, {RESPONSE: 400, ERROR: 'Bad request'}) except OSError: self.remove_client(client)