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)
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)
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()
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)
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)
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)
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)
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)
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)
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)
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)
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()