Пример #1
0
def contact_rem(onion_pub_key: bytes, ts: 'datetime',
                window_list: 'WindowList', contact_list: 'ContactList',
                group_list: 'GroupList', key_list: 'KeyList',
                settings: 'Settings', master_key: 'MasterKey') -> None:
    """Remove contact from Receiver Program."""
    key_list.remove_keyset(onion_pub_key)
    window_list.remove_window(onion_pub_key)
    short_addr = pub_key_to_short_address(onion_pub_key)

    try:
        contact = contact_list.get_contact_by_pub_key(onion_pub_key)
    except StopIteration:
        raise FunctionReturn(
            f"Receiver has no account '{short_addr}' to remove.")

    nick = contact.nick
    in_group = any([g.remove_members([onion_pub_key]) for g in group_list])

    contact_list.remove_contact_by_pub_key(onion_pub_key)

    message = f"Removed {nick} ({short_addr}) from contacts{' and groups' if in_group else ''}."
    m_print(message, bold=True, head=1, tail=1)

    local_win = window_list.get_local_window()
    local_win.add_new(ts, message)

    remove_logs(contact_list, group_list, settings, master_key, onion_pub_key)
Пример #2
0
def remove_log(cmd_data:     bytes,
               contact_list: 'ContactList',
               group_list:   'GroupList',
               settings:     'Settings',
               master_key:   'MasterKey'
               ) -> None:
    """Remove log entries for contact or group."""
    remove_logs(contact_list, group_list, settings, master_key, selector=cmd_data)
Пример #3
0
def remove_contact(user_input: 'UserInput', window: 'TxWindow',
                   contact_list: 'ContactList', group_list: 'GroupList',
                   settings: 'Settings', queues: Dict[bytes, 'Queue'],
                   master_key: 'MasterKey') -> None:
    """Remove contact on TxM/RxM."""
    if settings.session_traffic_masking:
        raise FunctionReturn(
            "Error: Command is disabled during traffic masking.")

    try:
        selection = user_input.plaintext.split()[1]
    except IndexError:
        raise FunctionReturn("Error: No account specified.")

    if not yes(f"Remove {selection} completely?", head=1):
        raise FunctionReturn("Removal of contact aborted.")

    rm_logs = yes(f"Also remove logs for {selection}?", head=1)

    # Load account if selector was nick
    if selection in contact_list.get_list_of_nicks():
        selection = contact_list.get_contact(selection).rx_account

    packet = CONTACT_REMOVE_HEADER + selection.encode()
    queue_command(packet, settings, queues[COMMAND_PACKET_QUEUE])

    if rm_logs:
        packet = LOG_REMOVE_HEADER + selection.encode()
        queue_command(packet, settings, queues[COMMAND_PACKET_QUEUE])
        with ignored(FunctionReturn):
            remove_logs(selection, settings, master_key)

    queues[KEY_MANAGEMENT_QUEUE].put((KDB_REMOVE_ENTRY_HEADER, selection))

    if selection in contact_list.get_list_of_accounts():
        contact_list.remove_contact(selection)
        box_print(f"Removed {selection} from contacts.", head=1, tail=1)
    else:
        box_print(f"TxM has no {selection} to remove.", head=1, tail=1)

    if any([g.remove_members([selection]) for g in group_list]):
        box_print(f"Removed {selection} from group(s).", tail=1)

    if window.type == WIN_TYPE_CONTACT:
        if selection == window.uid:
            window.deselect_window()

    if window.type == WIN_TYPE_GROUP:
        for c in window:
            if selection == c.rx_account:
                window.update_group_win_members(group_list)

                # If last member from group is removed, deselect group.
                # Deselection is not done in update_group_win_members
                # because it would prevent selecting the empty group
                # for group related commands such as notifications.
                if not window.window_contacts:
                    window.deselect_window()
Пример #4
0
    def test_removal_of_group_logs(self):
        # Setup
        short_msg = b"Lorem ipsum dolor sit amet, consectetur adipiscing elit."

        for p in assembly_packet_creator(MESSAGE, self.msg, group_name='test_group'):
            write_log_entry(p, '*****@*****.**',   self.settings, self.masterkey)
            write_log_entry(p, '*****@*****.**', self.settings, self.masterkey)

        for p in assembly_packet_creator(MESSAGE, short_msg, group_name='test_group'):
            write_log_entry(p, '*****@*****.**',   self.settings, self.masterkey)
            write_log_entry(p, '*****@*****.**', self.settings, self.masterkey)

        for p in assembly_packet_creator(MESSAGE, short_msg):
            write_log_entry(p, '*****@*****.**', self.settings, self.masterkey)

        for p in assembly_packet_creator(MESSAGE, self.msg):
            write_log_entry(p, '*****@*****.**', self.settings, self.masterkey)

        for p in assembly_packet_creator(MESSAGE, short_msg, group_name='test_group_2'):
            write_log_entry(p, '*****@*****.**', self.settings, self.masterkey)

        # Add an orphaned 'append' assembly packet that the function should skip
        write_log_entry(M_A_HEADER + bytes(PADDING_LEN), '*****@*****.**', self.settings, self.masterkey)

        # Add packet cancelled half-way
        packets = assembly_packet_creator(MESSAGE, self.msg, group_name='test_group')
        packets = packets[2:] + [M_C_HEADER + bytes(PADDING_LEN)]
        for p in packets:
            write_log_entry(p, '*****@*****.**', self.settings, self.masterkey)

        # Add a group management message for different group that the function should keep
        message = US_BYTE.join([b'test_group_2', b'*****@*****.**'])
        for p in assembly_packet_creator(MESSAGE, message, header=GROUP_MSG_INVITEJOIN_HEADER):
            write_log_entry(p, '*****@*****.**', self.settings, self.masterkey)

        # Add a group management message for group that the function should remove
        message = US_BYTE.join([b'test_group', b'*****@*****.**'])
        for p in assembly_packet_creator(MESSAGE, message, header=GROUP_MSG_INVITEJOIN_HEADER):
            write_log_entry(p, '*****@*****.**', self.settings, self.masterkey)

        for p in assembly_packet_creator(MESSAGE, self.msg, group_name='test_group_2'):
            write_log_entry(p, '*****@*****.**', self.settings, self.masterkey)

        # Test
        self.assertEqual(os.path.getsize(f'{DIR_USER_DATA}ut_logs'), 21*LOG_ENTRY_LENGTH)

        self.assertIsNone(remove_logs('test_group', self.settings, self.masterkey))
        self.assertEqual(os.path.getsize(f'{DIR_USER_DATA}ut_logs'), 9*LOG_ENTRY_LENGTH)

        self.assertIsNone(remove_logs('test_group_2', self.settings, self.masterkey))
        self.assertFR(f"Found no log entries for contact '*****@*****.**'",
                      remove_logs, '*****@*****.**', self.settings, self.masterkey)
Пример #5
0
def group_rm_group(group_name: str,
                   contact_list: 'ContactList',
                   group_list: 'GroupList',
                   settings: 'Settings',
                   queues: 'QueueDict',
                   master_key: 'MasterKey',
                   _: Optional[bytes] = None) -> None:
    """Remove the group with its members."""
    if not yes(f"Remove group '{group_name}'?", abort=False):
        raise FunctionReturn("Group removal aborted.",
                             head=0,
                             delay=1,
                             tail_clear=True)

    if group_name in group_list.get_list_of_group_names():
        group_id = group_list.get_group(group_name).group_id
    else:
        try:
            group_id = b58decode(group_name)
        except ValueError:
            raise FunctionReturn("Error: Invalid group name/ID.",
                                 head_clear=True)

    command = LOG_REMOVE + group_id
    queue_command(command, settings, queues)

    command = GROUP_DELETE + group_id
    queue_command(command, settings, queues)

    if group_list.has_group(group_name):
        with ignored(FunctionReturn):
            remove_logs(contact_list, group_list, settings, master_key,
                        group_id)
    else:
        raise FunctionReturn(
            f"Transmitter has no group '{group_name}' to remove.")

    group = group_list.get_group(group_name)
    if not group.empty() and yes("Notify members about leaving the group?",
                                 abort=False):
        exit_packet = (GROUP_MSG_EXIT_GROUP_HEADER + group.group_id +
                       b''.join(group.get_list_of_member_pub_keys()))
        queue_to_nc(exit_packet, queues[RELAY_PACKET_QUEUE])

    group_list.remove_group_by_name(group_name)
    raise FunctionReturn(f"Removed group '{group_name}'.",
                         head=0,
                         delay=1,
                         tail_clear=True,
                         bold=True)
Пример #6
0
def remove_contact(user_input: 'UserInput', window: 'TxWindow',
                   contact_list: 'ContactList', group_list: 'GroupList',
                   settings: 'Settings', queues: 'QueueDict',
                   master_key: 'MasterKey') -> None:
    """Remove contact from TFC."""
    if settings.traffic_masking:
        raise SoftError("Error: Command is disabled during traffic masking.",
                        head_clear=True)

    try:
        selection = user_input.plaintext.split()[1]
    except IndexError:
        raise SoftError("Error: No account specified.", head_clear=True)

    if not yes(f"Remove contact '{selection}'?", abort=False, head=1):
        raise SoftError("Removal of contact aborted.",
                        head=0,
                        delay=1,
                        tail_clear=True)

    if selection in contact_list.contact_selectors():
        onion_pub_key = contact_list.get_contact_by_address_or_nick(
            selection).onion_pub_key

    else:
        if validate_onion_addr(selection):
            raise SoftError("Error: Invalid selection.",
                            head=0,
                            delay=1,
                            tail_clear=True)
        onion_pub_key = onion_address_to_pub_key(selection)

    receiver_command = CONTACT_REM + onion_pub_key
    queue_command(receiver_command, settings, queues)

    with ignored(SoftError):
        remove_logs(contact_list, group_list, settings, master_key,
                    onion_pub_key)

    queues[KEY_MANAGEMENT_QUEUE].put((KDB_REMOVE_ENTRY_HEADER, onion_pub_key))

    relay_command = UNENCRYPTED_DATAGRAM_HEADER + UNENCRYPTED_REM_CONTACT + onion_pub_key
    queue_to_nc(relay_command, queues[RELAY_PACKET_QUEUE])

    target = determine_target(selection, onion_pub_key, contact_list)

    if any([g.remove_members([onion_pub_key]) for g in group_list]):
        m_print(f"Removed {target} from group(s).", tail=1)

    check_for_window_deselection(onion_pub_key, window, group_list)
Пример #7
0
def remove_log(user_input: 'UserInput', contact_list: 'ContactList',
               group_list: 'GroupList', settings: 'Settings',
               queues: 'QueueDict', master_key: 'MasterKey') -> None:
    """Remove log entries for contact or group."""
    try:
        selection = user_input.plaintext.split()[1]
    except IndexError:
        raise FunctionReturn("Error: No contact/group specified.",
                             head_clear=True)

    if not yes(f"Remove logs for {selection}?", abort=False, head=1):
        raise FunctionReturn("Log file removal aborted.",
                             tail_clear=True,
                             delay=1,
                             head=0)

    # Determine selector (group ID or Onion Service public key) from command parameters
    if selection in contact_list.contact_selectors():
        selector = contact_list.get_contact_by_address_or_nick(
            selection).onion_pub_key

    elif selection in group_list.get_list_of_group_names():
        selector = group_list.get_group(selection).group_id

    elif len(selection) == ONION_ADDRESS_LENGTH:
        if validate_onion_addr(selection):
            raise FunctionReturn("Error: Invalid account.", head_clear=True)
        selector = onion_address_to_pub_key(selection)

    elif len(selection) == GROUP_ID_ENC_LENGTH:
        try:
            selector = b58decode(selection)
        except ValueError:
            raise FunctionReturn("Error: Invalid group ID.", head_clear=True)

    else:
        raise FunctionReturn("Error: Unknown selector.", head_clear=True)

    # Remove logs that match the selector
    command = LOG_REMOVE + selector
    queue_command(command, settings, queues)

    remove_logs(contact_list, group_list, settings, master_key, selector)
Пример #8
0
def remove_log(user_input: 'UserInput', contact_list: 'ContactList',
               settings: 'Settings', c_queue: 'Queue',
               master_key: 'MasterKey') -> None:
    """Remove log entries for contact."""
    try:
        selection = user_input.plaintext.split()[1]
    except IndexError:
        raise FunctionReturn("Error: No contact/group specified.")

    if not yes(f"Remove logs for {selection}?", head=1):
        raise FunctionReturn("Logfile removal aborted.")

    # Swap specified nick to rx_account
    if selection in contact_list.get_list_of_nicks():
        selection = contact_list.get_contact(selection).rx_account

    command = LOG_REMOVE_HEADER + selection.encode()
    queue_command(command, settings, c_queue)

    remove_logs(selection, settings, master_key)
Пример #9
0
def remove_log(user_input: 'UserInput', contact_list: 'ContactList',
               group_list: 'GroupList', settings: 'Settings',
               queues: 'QueueDict', master_key: 'MasterKey') -> None:
    """Remove log entries for contact or group."""
    try:
        selection = user_input.plaintext.split()[1]
    except IndexError:
        raise SoftError("Error: No contact/group specified.", head_clear=True)

    if not yes(f"Remove logs for {selection}?", abort=False, head=1):
        raise SoftError("Log file removal aborted.",
                        tail_clear=True,
                        delay=1,
                        head=0)

    selector = determine_selector(selection, contact_list, group_list)

    # Remove logs that match the selector
    command = LOG_REMOVE + selector
    queue_command(command, settings, queues)

    remove_logs(contact_list, group_list, settings, master_key, selector)
Пример #10
0
    def test_removal_of_contact_logs(self):
        # Setup
        short_msg = b"Lorem ipsum dolor sit amet, consectetur adipiscing elit."

        for p in assembly_packet_creator(MESSAGE, self.msg):
            write_log_entry(p, '*****@*****.**',   self.settings, self.masterkey)
            write_log_entry(p, '*****@*****.**', self.settings, self.masterkey)

        for p in assembly_packet_creator(MESSAGE, short_msg):
            write_log_entry(p, '*****@*****.**',   self.settings, self.masterkey)
            write_log_entry(p, '*****@*****.**', self.settings, self.masterkey)

        # Test
        self.assertEqual(os.path.getsize(f'{DIR_USER_DATA}ut_logs'), 8*LOG_ENTRY_LENGTH)

        self.assertIsNone(remove_logs('*****@*****.**', self.settings, self.masterkey))
        self.assertEqual(os.path.getsize(f'{DIR_USER_DATA}ut_logs'), 4*LOG_ENTRY_LENGTH)

        self.assertIsNone(remove_logs('*****@*****.**', self.settings, self.masterkey))
        self.assertEqual(os.path.getsize(f'{DIR_USER_DATA}ut_logs'), 0)

        self.assertFR(f"Found no log entries for contact '*****@*****.**'",
                      remove_logs, '*****@*****.**', self.settings, self.masterkey)
Пример #11
0
def remove_log(cmd_data: bytes, settings: 'Settings',
               master_key: 'MasterKey') -> None:
    """Remove log entries for contact."""
    window_name = cmd_data.decode()
    remove_logs(window_name, settings, master_key)
Пример #12
0
def remove_contact(user_input: 'UserInput', window: 'TxWindow',
                   contact_list: 'ContactList', group_list: 'GroupList',
                   settings: 'Settings', queues: 'QueueDict',
                   master_key: 'MasterKey') -> None:
    """Remove contact from TFC."""
    if settings.traffic_masking:
        raise FunctionReturn(
            "Error: Command is disabled during traffic masking.",
            head_clear=True)

    try:
        selection = user_input.plaintext.split()[1]
    except IndexError:
        raise FunctionReturn("Error: No account specified.", head_clear=True)

    if not yes(f"Remove contact '{selection}'?", abort=False, head=1):
        raise FunctionReturn("Removal of contact aborted.",
                             head=0,
                             delay=1,
                             tail_clear=True)

    if selection in contact_list.contact_selectors():
        onion_pub_key = contact_list.get_contact_by_address_or_nick(
            selection).onion_pub_key

    else:
        if validate_onion_addr(selection):
            raise FunctionReturn("Error: Invalid selection.",
                                 head=0,
                                 delay=1,
                                 tail_clear=True)
        else:
            onion_pub_key = onion_address_to_pub_key(selection)

    receiver_command = CONTACT_REM + onion_pub_key
    queue_command(receiver_command, settings, queues)

    with ignored(FunctionReturn):
        remove_logs(contact_list, group_list, settings, master_key,
                    onion_pub_key)

    queues[KEY_MANAGEMENT_QUEUE].put((KDB_REMOVE_ENTRY_HEADER, onion_pub_key))

    relay_command = UNENCRYPTED_DATAGRAM_HEADER + UNENCRYPTED_REM_CONTACT + onion_pub_key
    queue_to_nc(relay_command, queues[RELAY_PACKET_QUEUE])

    if onion_pub_key in contact_list.get_list_of_pub_keys():
        contact = contact_list.get_contact_by_pub_key(onion_pub_key)
        target = f"{contact.nick} ({contact.short_address})"
        contact_list.remove_contact_by_pub_key(onion_pub_key)
        m_print(f"Removed {target} from contacts.", head=1, tail=1)
    else:
        target = f"{selection[:TRUNC_ADDRESS_LENGTH]}"
        m_print(f"Transmitter has no {target} to remove.", head=1, tail=1)

    if any([g.remove_members([onion_pub_key]) for g in group_list]):
        m_print(f"Removed {target} from group(s).", tail=1)

    if window.type == WIN_TYPE_CONTACT:
        if onion_pub_key == window.uid:
            window.deselect()

    if window.type == WIN_TYPE_GROUP:
        for c in window:
            if c.onion_pub_key == onion_pub_key:
                window.update_window(group_list)

                # If the last member of the group is removed, deselect
                # the group. Deselection is not done in
                # update_group_win_members because it would prevent
                # selecting the empty group for group related commands
                # such as notifications.
                if not window.window_contacts:
                    window.deselect()