def update_users_list(self):
     """Метод обновления списка пользователей. Отправляет запрос на сервер, по получении овтета - обновляет БД"""
     send_message(self.client_socket, self.get_users_msg())
     CLIENT_LOGGER.info(f'Отправлено get_users сообщение')
     answer = self.get_response_safe()
     if answer is not False:
         self.database.load_known_users(answer[ALERT])
 def update_contacts_list(self):
     """Метод обновления списка контактов. Отправляет запрос на сервер, по получении овтета - обновляет БД"""
     send_message(self.client_socket, self.get_contacts_msg())
     CLIENT_LOGGER.info(f'Отправлено get_contacts сообщение')
     answer = self.get_response_safe()
     if answer is not False:
         for contact in answer[ALERT]:
             self.database.add_contact(contact)
 def pubkey_request(self, username):
     """Метод отправки запроса публичного ключа и получения ответа"""
     send_message(self.client_socket, self.get_pubkey_msg(username))
     ans = self.get_response_safe()
     if RESPONSE in ans and ans[RESPONSE] == RESPCODE_AUTH_REQUIRED:
         return ans[KEY]
     else:
         CLIENT_LOGGER.error(f'Не удалось получить ключ собеседника {username}.')
    def preauthorize_user(self, name, client_socket, pubkey):
        """Метод для предавторизации пользователя"""
        if name in self.client_names.keys():
            SERVER_LOGGER.error('Имя пользователя уже занято')
            response = protocol.SERVER_RESPONSE_BAD_REQUEST
            response[ALERT] = 'Имя пользователя уже занято'
            send_message(client_socket, response)
            self.clients.remove(client_socket)
            client_socket.close()
            return

        elif not self.database.check_user(name):
            SERVER_LOGGER.error('Пользователь не зарегистрирован')
            response = protocol.SERVER_RESPONSE_BAD_REQUEST
            response[ALERT] = 'Пользователь не зарегистрирован'
            send_message(client_socket, response)
            self.clients.remove(client_socket)
            client_socket.close()
            return

        message = AUTHENTICATE_REQUIRED_MSG
        rand_msg = binascii.hexlify(os.urandom(64))
        message[DATA] = rand_msg.decode('ascii')
        print(self.database.get_passwd(name))

        hash_pwd = hmac.new(self.database.get_passwd(name), rand_msg, 'MD5')
        print(hash_pwd)
        digest = hash_pwd.digest()
        print(digest)
        send_message(client_socket, message)

        ans = get_message(client_socket)
        client_digest = binascii.a2b_base64(ans[USER][PASSWORD])

        if ACTION in ans and ans[ACTION] == AUTHENTICATE:
            if hmac.compare_digest(digest, client_digest):
                SERVER_LOGGER.debug(f'Ответ на {PRESENCE} корректный')
                # self.messages.append(('', create_login_message(msg[USER][ACCOUNT_NAME])))
                self.client_names[name] = client_socket
                cli_ip, cli_port = client_socket.getpeername()
                self.database.user_login(name, cli_ip, cli_port, pubkey)
                return RESPCODE_OK
            else:
                SERVER_LOGGER.error('Пароль не верен')
                response = protocol.SERVER_RESPONSE_BAD_REQUEST
                response[ALERT] = 'Пароль не верен'
                send_message(client_socket, response)
                self.clients.remove(client_socket)
                client_socket.close()
                return
        else:
            SERVER_LOGGER.error('Некорректный запрос на аутентификацию!')
            response = protocol.SERVER_RESPONSE_BAD_REQUEST
            response[ALERT] = 'Некорректный запрос на аутентификацию!'
            send_message(client_socket, response)
            self.clients.remove(client_socket)
            client_socket.close()
            return
    def run(self):
        """Основной цикл работы Сервера"""
        self.__init_socket()
        while True:
            try:
                client_sock, addr = self.socket.accept()
            except OSError:
                pass
            else:
                SERVER_LOGGER.info(f'Входящее подключение с адреса: {addr}')
                self.clients.append(client_sock)

            recv_data_lst = []
            send_data_lst = []
            err_lst = []

            try:
                if self.clients:
                    recv_data_lst, send_data_lst, err_lst = select(
                        self.clients, self.clients, [], 0)
            except OSError:
                pass

            if recv_data_lst:
                for client in recv_data_lst:
                    try:
                        inc_msg = get_message(client)
                        SERVER_LOGGER.debug('Получено сообщение:' f'{inc_msg}')
                        resp_code = self.process_incoming_message(
                            inc_msg, client)
                        if resp_code is not None:
                            resp_msg = create_response(resp_code)
                            SERVER_LOGGER.info('Отправлен ответ:'
                                               f'{resp_msg}')
                            send_message(client, resp_msg)

                    except ValueError as e:
                        _error = f'Ошибка декодирования сообщения от клиента {e}'
                        SERVER_LOGGER.error(_error)
                        send_message(
                            client,
                            create_response(RESPCODE_SERVER_ERROR, _error))
                    except Exception as e:
                        SERVER_LOGGER.error(
                            f'Клиент {client.getpeername()} отключился! {e}')
                        print(e)
                        self.clients.remove(client)

            if send_data_lst and self.messages:
                for msg in self.messages:
                    try:
                        self.process_message(msg, send_data_lst)
                    except Exception as e:
                        SERVER_LOGGER.info(
                            f'Обработка сообщения прошла неуспешно! {e}')
                self.messages.clear()
 def process_message(self, msg, conn_socks, add_contact=1):
     """Обработка сообщения. Отправка его адресату, если адресата нет - отправка всем активным клиентам."""
     msg_body = msg[1]
     if TO in msg_body:
         if msg_body[TO] in self.client_names:
             if self.client_names[msg_body[TO]] in conn_socks:
                 try:
                     send_message(self.client_names[msg_body[TO]], msg_body)
                     SERVER_LOGGER.debug(
                         f'Сообщение {msg_body} было успешно отправлено юзеру {msg_body[TO]}'
                     )
                     if msg_body[FROM] != 'system':
                         self.database.process_message(
                             msg_body[FROM], msg_body[TO])
                     if add_contact:
                         self.database.add_user_contact(
                             msg_body[FROM], msg_body[TO])
                         self.database.add_user_contact(
                             msg_body[TO], msg_body[FROM])
                     return
                 except:
                     # todo: При внезапном разрыве соединения, новым клиентам не удается подключиться
                     SERVER_LOGGER.error(f'Клиент отключился')
                     del self.client_names[msg_body[TO]]
             else:
                 # todo: При внезапном разрыве соединения, новым клиентам не удается подключиться и не чистится имя
                 SERVER_LOGGER.error(
                     f'Соединение с {self.client_names[msg_body[TO]].getpeername()} разорвано!'
                 )
                 self.clients.remove(self.client_names[msg_body[TO]])
                 self.database.user_logout(msg_body[TO])
                 del self.client_names[msg_body[TO]]
         else:
             SERVER_LOGGER.error(
                 f'пользователь {msg_body[TO]} не зарегистрирован в чате')
             return
     else:
         for name in self.client_names.keys():
             if msg[1][FROM] == name:
                 continue
             msg[1][TO] = name
             self.process_message(msg, conn_socks, add_contact=0)
         return
 def __init_connection(self, ip, port):
     """Метод инициализации подключения к серверу"""
     self.client_socket = socket(AF_INET, SOCK_STREAM)
     try:
         self.client_socket.connect((ip, port))
         CLIENT_LOGGER.info(f'Исходящее подключение к серверу: {ip}:{port}')
     except OSError as e:
         CLIENT_LOGGER.critical(e)
         sys.exit(1)
     else:
         send_message(self.client_socket, self.create_presence())
         CLIENT_LOGGER.info(f'Отправлено presence сообщение')
         answer = self.get_response_safe()
         if not answer:
             exit(1)
         elif RESPONSE in answer and not answer[RESPONSE] == RESPCODE_AUTH_REQUIRED:
             exit(1)
         else:
             send_message(self.client_socket, self.create_authenticate())
             CLIENT_LOGGER.info(f'Отправлено authenticate сообщение')
             time.sleep(3)
             CLIENT_LOGGER.info(f'Прошло 3 секунды...')
             if not self.get_response_safe():
                 exit(1)
Esempio n. 8
0
    def test_send_incorrect_message(self):
        test_socket = TestSocket(self.test_msg_send)
        send_message(test_socket, self.test_msg_send)

        self.assertRaises(ValueError, send_message, test_socket,
                          self.test_incorrect_msg_send)
Esempio n. 9
0
    def test_send_ok_message(self):
        test_socket = TestSocket(self.test_msg_send)
        send_message(test_socket, self.test_msg_send)

        self.assertEqual(test_socket.encoded_msg, test_socket.received_msg)
Esempio n. 10
0
    def process_incoming_message(self, msg, client=None):
        """Метод обработки входящего сообщения"""
        if ACTION in msg:
            if msg[ACTION] == PRESENCE:
                if msg.keys() != protocol.PRESENCE_MSG_CLIENT.keys():
                    SERVER_LOGGER.error(
                        'В запросе присутствуют лишние поля или отсутствуют нужные!'
                    )
                    return RESPCODE_BAD_REQ
                if msg[USER].keys() != protocol.PRESENCE_MSG_CLIENT[USER].keys(
                ):
                    SERVER_LOGGER.error(f'В запросе неверный объект {USER}!')
                    return RESPCODE_BAD_REQ
                SERVER_LOGGER.debug(
                    f'Сообщение {PRESENCE} корректное. Проверка пользователя')
                return self.preauthorize_user(msg[USER][ACCOUNT_NAME], client,
                                              msg[USER][PUBLIC_KEY])

            elif msg[ACTION] == GET_PUBLIC_KEY:
                if msg.keys() != protocol.GET_PUBKEY_REQ_MSG.keys():
                    SERVER_LOGGER.error(
                        'В запросе присутствуют лишние поля или отсутствуют нужные!'
                    )
                    return RESPCODE_BAD_REQ
                SERVER_LOGGER.debug(f'Сообщение {GET_PUBLIC_KEY} корректное')
                pubkey = self.database.get_pubkey(msg[USER])
                if pubkey:
                    send_message(client, create_pubkey_message(pubkey))
                else:
                    send_message(
                        client,
                        create_response(
                            RESPCODE_BAD_REQ,
                            f'Публичный ключ для пользователя {msg[USER]} не найден'
                        ))
                return

            elif msg[ACTION] == MSG:
                if msg.keys() != protocol.CHAT_MSG_CLIENT.keys():
                    if msg.keys() != protocol.CHAT_USER_MSG_CLIENT.keys():
                        SERVER_LOGGER.error(
                            'В запросе присутствуют лишние поля или отсутствуют нужные!'
                        )
                        print(protocol.CHAT_MSG_CLIENT.keys())
                        return RESPCODE_BAD_REQ
                SERVER_LOGGER.debug(f'Сообщение {MSG} корректное')
                self.messages.append((msg[FROM], msg))
                return

            elif msg[ACTION] == GET_USERS:
                if msg.keys() != protocol.GET_USERS_MSG.keys():
                    SERVER_LOGGER.error(
                        'В запросе присутствуют лишние поля или отсутствуют нужные!'
                    )
                    return RESPCODE_BAD_REQ
                SERVER_LOGGER.debug(f'Сообщение {GET_USERS} корректное')
                users = self.database.users_list()
                send_message(client, create_users_contacts_message(users))
                return

            elif msg[ACTION] == GET_CONTACTS:
                if msg.keys() != protocol.GET_USER_CONTACTS_MSG.keys():
                    SERVER_LOGGER.error(
                        'В запросе присутствуют лишние поля или отсутствуют нужные!'
                    )
                    return RESPCODE_BAD_REQ
                SERVER_LOGGER.debug(f'Сообщение {GET_CONTACTS} корректное')
                contacts = self.database.get_user_contact_list(msg[USER_LOGIN])
                send_message(client, create_users_contacts_message(contacts))
                return

            elif msg[ACTION] == ADD_CONTACT:
                if msg.keys() != protocol.ADD_USER_CONTACT_MSG.keys():
                    SERVER_LOGGER.error(
                        'В запросе присутствуют лишние поля или отсутствуют нужные!'
                    )
                    return RESPCODE_BAD_REQ
                self.database.add_user_contact(msg[USER_LOGIN], msg[USER_ID])
                SERVER_LOGGER.debug(f'Сообщение {ADD_CONTACT} корректное')
                return RESPCODE_OK

            elif msg[ACTION] == REMOVE_CONTACT:
                if msg.keys() != protocol.REMOVE_USER_CONTACT_MSG.keys():
                    SERVER_LOGGER.error(
                        'В запросе присутствуют лишние поля или отсутствуют нужные!'
                    )
                    return RESPCODE_BAD_REQ
                self.database.remove_user_contact(msg[USER_LOGIN],
                                                  msg[USER_ID])
                SERVER_LOGGER.debug(f'Сообщение {REMOVE_CONTACT} корректное')
                return RESPCODE_OK

            elif msg[ACTION] == EXIT:
                SERVER_LOGGER.debug(f'Клиент {msg[FROM]} покинул чатик')
                # self.messages.append(('', create_logout_message(msg[FROM])))
                self.database.user_logout(msg[FROM])
                del self.client_names[msg[FROM]]
                return

            else:
                SERVER_LOGGER.error(
                    f'Такое значение {ACTION} {msg[ACTION]} не поддерживается!'
                )
                return RESPCODE_BAD_REQ

        else:
            SERVER_LOGGER.error(f'{ACTION} отсутствует в сообщении')
            return RESPCODE_BAD_REQ
Esempio n. 11
0
 def remove_contact(self, user_contact):
     """Метод отправки запроса на удаление контакта"""
     return send_message(self.client_socket, self.create_remove_contact_msg(user_contact))
Esempio n. 12
0
 def add_contact(self, user_contact):
     """Метод отправки запроса на добавление контакта"""
     return send_message(self.client_socket, self.create_add_contact_msg(user_contact))
Esempio n. 13
0
 def exit_(self):
     """Метод отправки сообщения на выход пользователя из чата"""
     return send_message(self.client_socket, self.create_exit_message())
Esempio n. 14
0
 def send_message(self, user_to, message_txt):
     """Метод отправки созданного сообщения"""
     return send_message(self.client_socket, self.create_message(user_to, message_txt))