예제 #1
0
    def load_settings(self) -> None:
        """Load settings from the encrypted database."""
        with open(self.file_name, 'rb') as f:
            ct_bytes = f.read()

        pt_bytes = auth_and_decrypt(ct_bytes,
                                    self.master_key.master_key,
                                    database=self.file_name)

        # Update settings based on plaintext byte string content
        for key in self.key_list:

            attribute = self.__getattribute__(key)

            if isinstance(attribute, bool):
                value = bytes_to_bool(
                    pt_bytes[0])  # type: Union[bool, int, float]
                pt_bytes = pt_bytes[ENCODED_BOOLEAN_LENGTH:]

            elif isinstance(attribute, int):
                value = bytes_to_int(pt_bytes[:ENCODED_INTEGER_LENGTH])
                pt_bytes = pt_bytes[ENCODED_INTEGER_LENGTH:]

            elif isinstance(attribute, float):
                value = bytes_to_double(pt_bytes[:ENCODED_FLOAT_LENGTH])
                pt_bytes = pt_bytes[ENCODED_FLOAT_LENGTH:]

            else:
                raise CriticalError(
                    "Invalid data type in settings default values.")

            setattr(self, key, value)
예제 #2
0
파일: db_settings.py 프로젝트: savg110/tfc
    def load_settings(self) -> None:
        """Load settings from the encrypted database."""
        pt_bytes = self.database.load_database()

        # Update settings based on plaintext byte string content
        for key in self.key_list:

            attribute = self.__getattribute__(key)

            if isinstance(attribute, bool):
                value    = bytes_to_bool(pt_bytes[0])  # type: Union[bool, int, float]
                pt_bytes = pt_bytes[ENCODED_BOOLEAN_LENGTH:]

            elif isinstance(attribute, int):
                value    = bytes_to_int(pt_bytes[:ENCODED_INTEGER_LENGTH])
                pt_bytes = pt_bytes[ENCODED_INTEGER_LENGTH:]

            elif isinstance(attribute, float):
                value    = bytes_to_double(pt_bytes[:ENCODED_FLOAT_LENGTH])
                pt_bytes = pt_bytes[ENCODED_FLOAT_LENGTH:]

            else:
                raise CriticalError("Invalid data type in settings default values.")

            setattr(self, key, value)
예제 #3
0
파일: db_settings.py 프로젝트: barleyj/tfc
    def load_settings(self) -> None:
        """Load settings from encrypted database."""
        ensure_dir(f'{DIR_USER_DATA}/')
        with open(self.file_name, 'rb') as f:
            ct_bytes = f.read()

        pt_bytes = auth_and_decrypt(ct_bytes, self.master_key.master_key)

        # Update settings based on plaintext byte string content
        for i, key in enumerate(self.key_list):

            attribute = self.__getattribute__(key)

            if isinstance(attribute, bool):
                value = bytes_to_bool(
                    pt_bytes[0])  # type: Union[bool, int, float, str]
                pt_bytes = pt_bytes[1:]

            elif isinstance(attribute, int):
                value = bytes_to_int(pt_bytes[:8])
                pt_bytes = pt_bytes[8:]

            elif isinstance(attribute, float):
                value = bytes_to_double(pt_bytes[:8])
                pt_bytes = pt_bytes[8:]

            elif isinstance(attribute, str):
                value = bytes_to_str(pt_bytes[:1024])
                pt_bytes = pt_bytes[
                    1024:]  # 255 * 4 = 1020. The four additional bytes is the UTF-32 BOM.

            else:
                raise CriticalError(
                    "Invalid data type in settings default values.")

            setattr(self, key, value)
예제 #4
0
 def test_bytes_to_double(self):
     self.assertEqual(bytes_to_double(bytes.fromhex('000000000000f03f')),
                      1.0)
     self.assertEqual(bytes_to_double(bytes.fromhex('9a9999999999f13f')),
                      1.1)
예제 #5
0
 def test_bytes_to_double(self):
     self.assertEqual(
         bytes_to_double(binascii.unhexlify('000000000000f03f')), 1.0)
     self.assertEqual(
         bytes_to_double(binascii.unhexlify('9a9999999999f13f')), 1.1)
예제 #6
0
def process_message(ts:                 'datetime',
                    assembly_packet_ct: bytes,
                    window_list:        'WindowList',
                    packet_list:        'PacketList',
                    contact_list:       'ContactList',
                    key_list:           'KeyList',
                    group_list:         'GroupList',
                    settings:           'Settings',
                    master_key:         'MasterKey') -> None:
    """Process received private / group message.

    Group management messages have automatic formatting and window
    redirection based on group configuration managed by user.
    """
    assembly_packet, account, origin = decrypt_assembly_packet(assembly_packet_ct, window_list, contact_list, key_list)

    p_type = 'file' if assembly_packet[:1].isupper() else 'message'
    packet = packet_list.get_packet(account, origin, p_type)
    packet.add_packet(assembly_packet)

    if not packet.is_complete:
        return None

    if p_type == 'file':
        packet.assemble_and_store_file()

        if contact_list.get_contact(account).log_messages and settings.log_dummy_file_a_p:
            # Store placeholder data.
            for _ in packet.assembly_pt_list:
                place_holder = F_S_HEADER + bytes(255)
                write_log_entry(place_holder, account, settings, master_key, origin)

    if p_type == 'message':
        assembled = packet.assemble_message_packet()
        header    = assembled[:1]
        assembled = assembled[1:]

        # Messages to group

        if header == GROUP_MESSAGE_HEADER:

            try:
                timestamp = bytes_to_double(assembled[:8])
            except struct.error:
                raise FunctionReturn("Received an invalid group timestamp.")

            try:
                group_name = assembled[8:].split(US_BYTE)[0].decode()
            except (UnicodeError, IndexError):
                raise FunctionReturn("Group name had invalid encoding.")

            try:
                group_message = assembled[8:].split(US_BYTE)[1]
            except (ValueError, IndexError):
                raise FunctionReturn("Received an invalid group message.")

            if not group_list.has_group(group_name):
                raise FunctionReturn("Received message to unknown group.", output=False)

            window = window_list.get_window(group_name)
            group  = group_list.get_group(group_name)

            if not group.has_member(account):
                raise FunctionReturn("Group message to group contact is not member of.", output=False)

            if window.has_contact(account):
                # All copies of group messages user sends to members contain same timestamp header.
                # This allows RxM to ignore copies of messages sent by the user.
                if origin == ORIGIN_USER_HEADER:
                    if window.group_timestamp == timestamp:
                        return None
                    window.group_timestamp = timestamp
                window.print_new(ts, group_message.decode(), account, origin)

                if group_list.get_group(group_name).log_messages:
                    for p in packet.assembly_pt_list:
                        write_log_entry(p, account, settings, master_key, origin)
            return None

        # Messages to contact

        else:
            if header == PRIVATE_MESSAGE_HEADER:
                window = window_list.get_window(account)
                window.print_new(ts, assembled.decode(), account, origin)

            # Group management messages
            else:
                local_win = window_list.get_local_window()
                nick      = contact_list.get_contact(account).nick

                group_name, *members = [f.decode() for f in assembled.split(US_BYTE)]

                # Ignore group management messages from user
                if origin == ORIGIN_USER_HEADER:
                    return None

                if header == GROUP_MSG_INVITATION_HEADER:
                    action = 'invited you to'
                    if group_list.has_group(group_name) and group_list.get_group(group_name).has_member(account):
                        action  = 'joined'
                    message = ["{} has {} group '{}'".format(nick, action, group_name)]  # type: List[str]
                    lw_msg  =  "{} has {} group '{}'".format(nick, action, group_name)   # type: str

                    # Print group management message
                    if members:
                        message[0] += " with following members:"
                        known       = [contact_list.get_contact(m).nick for m in members if contact_list.has_contact(m)]
                        unknown     = [m for m in members if not contact_list.has_contact(m)]
                        just_len    = len(max(known + unknown, key=len))
                        message    += ["  * {}".format(m.ljust(just_len)) for m in (known + unknown)]
                        lw_msg     += " with members " + ", ".join(known + unknown)

                    box_print(message, head=1, tail=1)

                    # Persistent message in cmd window
                    local_win.print_new(ts, lw_msg, print_=False)

                elif header in [GROUP_MSG_ADD_NOTIFY_HEADER, GROUP_MSG_MEMBER_RM_HEADER]:
                    action   = "added following member(s) to" if header == GROUP_MSG_ADD_NOTIFY_HEADER else "removed following member(s) from"
                    message_ = ["{} has {} group {}: ".format(nick, action, group_name)]  # type: List[str]
                    lw_msg_  =  "{} has {} group {}: ".format(nick, action, group_name)   # type: str

                    if members:
                        known     = [contact_list.get_contact(m).nick for m in members if contact_list.has_contact(m)]
                        unknown   = [m for m in members if not contact_list.has_contact(m)]
                        just_len  = len(max(known + unknown, key=len))
                        lw_msg_  += ", ".join(known + unknown)
                        message_ += ["  * {}".format(m.ljust(just_len)) for m in (known + unknown)]

                        box_print(message_, head=1, tail=1)
                        local_win.print_new(ts, lw_msg_, print_=False)

                elif header == GROUP_MSG_EXIT_GROUP_HEADER:
                    box_print(["{} has left group {}.".format(nick, group_name), '', 'Warning',
                               "Unless you remove the contact from the group, they",
                               "can still decrypt messages you send to the group."],
                              head=1, tail=1)
                else:
                    raise FunctionReturn(f"Message from had invalid header.")

            if contact_list.get_contact(account).log_messages:
                for p in packet.assembly_pt_list:
                    write_log_entry(p, account, settings, master_key, origin)