Пример #1
0
 def delete_contact(self, item):
     """
     Метод удаляющий контакт из серверной и клиентсткой BD.
     После обновления баз данных обновляет и содержимое окна.
     """
     selected = item.selector.currentText()
     try:
         self.transport.remove_contact(selected)
     except ServerError as err:
         self.messages.critical(self, 'Ошибка сервера', err.text)
     except OSError as err:
         if err.errno:
             self.messages.critical(self, 'Ошибка',
                                    'Потеряно соединение с сервером!')
             self.close()
         self.messages.critical(self, 'Ошибка', 'Таймаут соединения!')
     else:
         self.database.del_contact(selected)
         self.clients_list_update()
         client_logger.info(f'Успешно удалён контакт {selected}')
         self.messages.information(self, 'Успех', 'Контакт успешно удалён.')
         item.close()
         # Если удалён активный пользователь, то деактивируем поля ввода.
         if selected == self.current_chat:
             self.current_chat = None
             self.set_disabled_input()
Пример #2
0
    def send_message(self, to, message):
        """Метод отправляющий на сервер сообщения для пользователя."""
        message_dict = {
            CONFIGS['ACTION']: CONFIGS['MESSAGE'],
            CONFIGS['FROM_USER']: self.username,
            CONFIGS['TO_USER']: to,
            CONFIGS['TIME']: time.time(),
            CONFIGS['MESSAGE_TEXT']: message
        }
        client_logger.debug(f'Сформирован словарь сообщения: {message_dict}')

        # Необходимо дождаться освобождения сокета для отправки сообщения
        with socket_lock:
            send_message(self.transport, message_dict, CONFIGS)
            self.process_server_ans(get_message(self.transport, CONFIGS))
            client_logger.info(f'Отправлено сообщение для пользователя {to}')
Пример #3
0
 def add_contact(self, new_contact):
     """
     Метод добавляющий контакт в серверную и клиентсткую BD.
     После обновления баз данных обновляет и содержимое окна.
     """
     try:
         self.transport.add_contact(new_contact)
     except ServerError as err:
         self.messages.critical(self, 'Ошибка сервера', err.text)
     except OSError as err:
         if err.errno:
             self.messages.critical(self, 'Ошибка',
                                    'Потеряно соединение с сервером!')
             self.close()
         self.messages.critical(self, 'Ошибка', 'Таймаут соединения!')
     else:
         self.database.add_contact(new_contact)
         new_contact = QStandardItem(new_contact)
         new_contact.setEditable(False)
         self.contacts_model.appendRow(new_contact)
         client_logger.info(f'Успешно добавлен контакт {new_contact}')
         self.messages.information(self, 'Успех',
                                   'Контакт успешно добавлен.')
Пример #4
0
    def connection_init(self, port, ip):
        """Метод отвечающий за устанновку соединения с сервером."""
        # Инициализация сокета и сообщение серверу о нашем появлении
        self.transport = socket.socket(socket.AF_INET, socket.SOCK_STREAM)

        # Таймаут необходим для освобождения сокета.
        self.transport.settimeout(5)

        # Соединяемся, 5 попыток соединения, флаг успеха ставим в True если
        # удалось
        connected = False
        for i in range(5):
            client_logger.info(f'Попытка подключения №{i + 1}')
            try:
                self.transport.connect((ip, port))
            except (OSError, ConnectionRefusedError):
                pass
            else:
                connected = True
                client_logger.debug("Connection established.")
                break
            time.sleep(1)

        # Если соединится не удалось - исключение
        if not connected:
            client_logger.critical(
                'Не удалось установить соединение с сервером')
            raise ServerError('Не удалось установить соединение с сервером')

        client_logger.debug('Starting auth dialog.')

        # Запускаем процедуру авторизации
        # Получаем хэш пароля
        passwd_bytes = self.password.encode('utf-8')
        salt = self.username.lower().encode('utf-8')
        passwd_hash = hashlib.pbkdf2_hmac('sha512', passwd_bytes, salt, 10000)
        passwd_hash_string = binascii.hexlify(passwd_hash)

        client_logger.debug(f'Passwd hash ready: {passwd_hash_string}')

        # Получаем публичный ключ и декодируем его из байтов
        pubkey = self.keys.publickey().export_key().decode('ascii')

        # Авторизируемся на сервере
        with socket_lock:
            presense = {
                CONFIGS.get('ACTION'): CONFIGS.get('PRESENCE'),
                CONFIGS.get('TIME'): time.time(),
                CONFIGS.get('USER'): {
                    CONFIGS.get('ACCOUNT_NAME'): self.username,
                    CONFIGS.get('PUBLIC_KEY'): pubkey
                }
            }
            client_logger.debug(f"Presence message = {presense}")
            # Отправляем серверу приветственное сообщение.
            try:
                send_message(self.transport, presense, CONFIGS)
                ans = get_message(self.transport, CONFIGS)
                client_logger.debug(f'Server response = {ans}.')
                # Если сервер вернул ошибку, бросаем исключение.
                if CONFIGS.get('RESPONSE') in ans:
                    if ans[CONFIGS.get('RESPONSE')] == 400:
                        raise ServerError(ans[CONFIGS.get('ERROR')])
                    elif ans[CONFIGS.get('RESPONSE')] == 511:
                        # Если всё нормально, то продолжаем процедуру
                        # авторизации.
                        ans_data = ans[CONFIGS.get('DATA')]
                        hash = hmac.new(passwd_hash_string,
                                        ans_data.encode('utf-8'), 'MD5')
                        digest = hash.digest()
                        my_ans = RESPONSE_511
                        my_ans[CONFIGS.get('DATA')] = binascii.b2a_base64(
                            digest).decode('ascii')
                        send_message(self.transport, my_ans, CONFIGS)
                        self.process_server_ans(
                            get_message(self.transport, CONFIGS))
            except (OSError, json.JSONDecodeError) as err:
                client_logger.debug(f'Connection error.', exc_info=err)
                raise ServerError('Сбой соединения в процессе авторизации.')
    start_dialog = UserNameDialog()
    if not client_name or not client_passwd:
        client_app.exec_()
        # Если пользователь ввёл имя и нажал ОК, то сохраняем ведённое и
        # удаляем объект, иначе выходим
        if start_dialog.ok_pressed:
            client_name = start_dialog.client_name.text()
            client_passwd = start_dialog.client_passwd.text()
            client_logger.debug(f'Using USERNAME = {client_name}, '
                                f'PASSWD = {client_passwd}.')
        else:
            exit(0)

    # Записываем логи
    client_logger.info(
        f'Запущен клиент с парамертами: адрес сервера: {server_address} , '
        f'порт: {server_port}, имя пользователя: {client_name}')

    # Загружаем ключи с файла, если же файла нет, то генерируем новую пару.
    dir_path = os.path.dirname(os.path.realpath(__file__))
    key_file = os.path.join(dir_path, f'{client_name}.key')
    if not os.path.exists(key_file):
        keys = RSA.generate(2048, os.urandom)
        with open(key_file, 'wb') as key:
            key.write(keys.export_key())
    else:
        with open(key_file, 'rb') as key:
            keys = RSA.import_key(key.read())

    # keys.publickey().export_key()
    client_logger.debug("Keys sucsessfully loaded.")