Ejemplo n.º 1
0
    def redraw(self):
        """Draw file window frame."""
        ft_found = False
        line_ctr = 0
        longest_title = 0
        tty_w = get_tty_w()

        for p in self.packet_list:
            if p.type == 'file' and len(p.assembly_pt_list) > 0:
                title = "{} ({}) from {} ".format(p.f_name, p.f_size,
                                                  p.contact.nick)
                longest_title = max(longest_title, len(title))

        for p in self.packet_list:
            if p.type == 'file' and len(p.assembly_pt_list) > 0:
                line_ctr += 1
                ft_found = True
                title = "{} ({}) from {} ".format(p.f_name, p.f_size,
                                                  p.contact.nick)
                title += (longest_title - len(title)) * ' '

                bar_len = max(tty_w - (4 + len(title)), 1)
                ready = int((len(p.assembly_pt_list) / p.f_packets) * bar_len)
                missing = bar_len - ready
                bar = title + '[' + (ready -
                                     1) * '=' + '>' + missing * ' ' + ']'
                print(bar)

        print_on_previous_line(reps=line_ctr)

        if not ft_found:
            c_print("No file transmissions currently in progress.",
                    head=1,
                    tail=1)
            print_on_previous_line(reps=3)
Ejemplo n.º 2
0
    def redraw_file_win(self) -> None:
        """Draw file transmission window progress bars."""
        # Columns
        c1 = ['File name']
        c2 = ['Size']
        c3 = ['Sender']
        c4 = ['Complete']

        for i, p in enumerate(self.packet_list):
            if p.type == FILE and len(p.assembly_pt_list) > 0:
                c1.append(p.name)
                c2.append(p.size)
                c3.append(p.contact.nick)
                c4.append(f"{len(p.assembly_pt_list) / p.packets * 100:.2f}%")

        if not len(c1) > 1:
            c_print("No file transmissions currently in progress.",
                    head=1,
                    tail=1)
            print_on_previous_line(reps=3, delay=0.1)
            return None

        lst = []
        for name, size, sender, percent, in zip(c1, c2, c3, c4):
            lst.append('{0:{1}} {2:{3}} {4:{5}} {6:{7}}'.format(
                name,
                max(len(v) for v in c1) + CONTACT_LIST_INDENT, size,
                max(len(v) for v in c2) + CONTACT_LIST_INDENT, sender,
                max(len(v) for v in c3) + CONTACT_LIST_INDENT, percent,
                max(len(v) for v in c4) + CONTACT_LIST_INDENT))

        lst.insert(1, get_terminal_width() * '─')

        print('\n' + '\n'.join(lst) + '\n')
        print_on_previous_line(reps=len(lst) + 2, delay=0.1)
Ejemplo n.º 3
0
def init_entropy() -> None:
    """Wait until Kernel CSPRNG is sufficiently seeded.

    Wait until entropy_avail file states that system has at least 512 bits of
    entropy. The headroom allows room for error in accuracy of entropy
    collector's entropy estimator; As long as input has at least 4 bits per
    byte of actual entropy, /dev/urandom will be sufficiently seeded when
    it is allowed to generate keys.
    """
    clear_screen()
    phase("Waiting for Kernel CSPRNG random pool to fill up", head=1)

    ent_avail = 0
    threshold = 512

    while ent_avail < threshold:
        try:
            with open('/proc/sys/kernel/random/entropy_avail') as f:
                value = f.read()
            ent_avail = int(value.strip())
            c_print("{}/{}".format(ent_avail, threshold))
            print_on_previous_line(delay=0.01)
        except (KeyboardInterrupt, EOFError):
            pass

    print_on_previous_line()
    phase("Waiting for Kernel CSPRNG random pool to fill up")
    phase("Done")
Ejemplo n.º 4
0
 def abort_packet(self, message: str) -> None:
     """Process cancel/noise packet."""
     if self.type == FILE and self.origin == ORIGIN_CONTACT_HEADER and self.long_active:
         c_print(message, head=1, tail=1)
         self.clear_file_metadata()
     self.add_masking_packet_to_logfile(
         increase=len(self.assembly_pt_list) + 1)
     self.clear_assembly_packets()
Ejemplo n.º 5
0
def ask_path_cli(prompt_msg: str, get_file: bool = False) -> str:
    """\
    Prompt file location / store dir for
    file with tab-complete supported CLI.

    :param prompt_msg: File selection prompt
    :param get_file:   When True, prompts for file instead of directory
    :return:           Selected directory
    """
    comp = Completer(get_file)
    readline.set_completer_delims(' \t\n;')
    readline.parse_and_bind('tab: complete')
    readline.set_completer(comp.complete)
    print('')

    if get_file:
        while True:
            try:
                path_to_file = input(prompt_msg + ": ")

                if not path_to_file:
                    print_on_previous_line()
                    raise KeyboardInterrupt

                if os.path.isfile(path_to_file):
                    if path_to_file.startswith('./'):
                        path_to_file = path_to_file[2:]
                    print('')
                    return path_to_file

                c_print("File selection error.", head=1, tail=1)
                time.sleep(1.5)
                print_on_previous_line(reps=4)

            except KeyboardInterrupt:
                print_on_previous_line()
                raise FunctionReturn("File selection aborted.")

    else:
        while True:
            try:
                directory = input(prompt_msg + ": ")

                if directory.startswith('./'):
                    directory = directory[2:]

                if not directory.endswith(os.sep):
                    directory += os.sep

                if not os.path.isdir(directory):
                    c_print("Error: Invalid directory.", head=1, tail=1)
                    print_on_previous_line(reps=4, delay=1.5)
                    continue

                return directory

            except KeyboardInterrupt:
                raise FunctionReturn("File path selection aborted.")
Ejemplo n.º 6
0
def box_input(title: str,
              default: str = '',
              head: int = 0,
              tail: int = 0,
              expected_len: int = 0,
              validator: Callable = None,
              validator_args: Any = None) -> str:
    """Display boxed prompt for user with title.

    :param title:          Title for data to prompt
    :param default:        Default return value
    :param head:           Number of new lines to print before input
    :param tail:           Number of new lines to print after input
    :param expected_len    Expected length of input
    :param validator:      Input validator function
    :param validator_args: Arguments required by the validator
    :return:               Input from user
    """
    for _ in range(head):
        print('')

    tty_w = get_tty_w()
    input_len = tty_w - 2 if expected_len == 0 else expected_len + 2

    input_top_line = '┌' + input_len * '─' + '┐'
    input_line = '│' + input_len * ' ' + '│'
    input_bot_line = '└' + input_len * '─' + '┘'

    input_line_indent = (tty_w - len(input_line)) // 2
    input_box_indent = input_line_indent * ' '

    print(input_box_indent + input_top_line)
    print(input_box_indent + input_line)
    print(input_box_indent + input_bot_line)
    print(4 * CURSOR_UP_ONE_LINE)
    print(input_box_indent + '┌─┤' + title + '├')

    user_input = input(input_box_indent + '│ ')

    if user_input == '':
        print(2 * CURSOR_UP_ONE_LINE)
        print(input_box_indent + f'│ {default}')
        user_input = default

    if validator is not None:
        success, error_msg = validator(user_input, validator_args)
        if not success:
            c_print("Error: {}".format(error_msg), head=1)
            print_on_previous_line(reps=4, delay=1.5)
            return box_input(title, default, head, tail, expected_len,
                             validator, validator_args)

    for _ in range(tail):
        print('')

    return user_input
Ejemplo n.º 7
0
def local_key_installed(ts: 'datetime', window_list: 'WindowList',
                        contact_list: 'ContactList') -> None:
    """Clear local key bootstrap process from screen."""
    message = "Successfully completed local key exchange."
    local_win = window_list.get_window(LOCAL_ID)
    local_win.add_new(ts, message)

    box_print(message)
    clear_screen(delay=1)

    if not contact_list.has_contacts():
        c_print("Waiting for new contacts", head=1, tail=1)
Ejemplo n.º 8
0
def local_key_installed(ts: 'datetime', window_list: 'WindowList',
                        contact_list: 'ContactList') -> None:
    """Clear local key bootstrap process from screen."""
    local_win = window_list.get_window('local')
    local_win.print_new(ts, "Created a new local key.", print_=False)

    box_print(["Successfully added a new local key."])
    clear_screen(delay=1)

    if not contact_list.has_contacts():
        clear_screen()
        c_print("Waiting for new contacts", head=1, tail=1)
Ejemplo n.º 9
0
    def redraw(self) -> None:
        """Print all messages received to window."""
        self.clear_window()
        self.unread_messages = 0
        if self.message_log:
            self.previous_msg_ts = self.message_log[0][0]
        else:
            c_print(f"This window for {self.name} is currently empty.",
                    head=1,
                    tail=1)

        for msg_tuple in self.message_log:
            self.print(msg_tuple)
Ejemplo n.º 10
0
def change_baudrate(settings: 'Settings', command: bytes) -> None:
    """Change serial interface baud rate setting on NH."""
    try:
        value = int(command[2:])
        if value not in serial.Serial.BAUDRATES:
            raise ValueError
    except ValueError:
        raise FunctionReturn(
            "Error: Received invalid baud rate value from TxM.")

    settings.serial_baudrate = value
    settings.store_settings()
    c_print("Baud rate will change on restart.", head=1, tail=1)
Ejemplo n.º 11
0
def change_ec_ratio(settings: 'Settings', command: bytes) -> None:
    """Change Reed-Solomon erasure code correction ratio setting on NH."""
    try:
        value = int(command[2:])
        if value < 1 or value > 2**64 - 1:
            raise ValueError
    except ValueError:
        raise FunctionReturn(
            "Error: Received invalid EC ratio value from TxM.")

    settings.serial_error_correction = value
    settings.store_settings()
    c_print("Error correction ratio will change on restart.", head=1, tail=1)
Ejemplo n.º 12
0
def process_local_key(ts: 'datetime', packet: bytes, window_list: 'WindowList',
                      contact_list: 'ContactList', key_list: 'KeyList',
                      settings: 'Settings') -> None:
    """Decrypt local key packet and add local contact/keyset."""
    bootstrap = not key_list.has_local_key()

    try:
        while True:
            clear_screen()
            box_print("Received encrypted local key", tail=1)
            kdk = get_b58_key(B58_LOCAL_KEY, settings)

            try:
                pt = auth_and_decrypt(packet[1:], key=kdk, soft_e=True)
                break
            except nacl.exceptions.CryptoError:
                if bootstrap:
                    raise FunctionReturn(
                        "Error: Incorrect key decryption key.", delay=1.5)
                c_print("Incorrect key decryption key.", head=1)
                clear_screen(delay=1.5)

        key = pt[0:32]
        hek = pt[32:64]
        conf_code = pt[64:65]

        # Add local contact to contact list database
        contact_list.add_contact(LOCAL_ID, LOCAL_ID, LOCAL_ID,
                                 bytes(FINGERPRINT_LEN),
                                 bytes(FINGERPRINT_LEN), False, False, True)

        # Add local keyset to keyset database
        key_list.add_keyset(rx_account=LOCAL_ID,
                            tx_key=key,
                            rx_key=csprng(),
                            tx_hek=hek,
                            rx_hek=csprng())

        box_print(f"Confirmation code for TxM: {conf_code.hex()}", head=1)

        local_win = window_list.get_local_window()
        local_win.add_new(ts, "Added new local key.")

        if bootstrap:
            window_list.active_win = local_win

    except KeyboardInterrupt:
        raise FunctionReturn("Local key setup aborted.",
                             delay=1,
                             head=3,
                             tail_clear=True)
Ejemplo n.º 13
0
def cancel_packet(user_input: 'UserInput',
                  window:     'Window',
                  settings:   'Settings',
                  queues:     Dict[bytes, 'Queue']) -> None:
    """Cancel sent message/file to contact/group."""
    command   = user_input.plaintext
    queue     = dict(cm=queues[MESSAGE_PACKET_QUEUE], cf=queues[FILE_PACKET_QUEUE])[command]
    cancel_pt = dict(cm=M_C_HEADER,                   cf=F_C_HEADER )[command] + bytes(255)
    p_type    = dict(cm='messages',                   cf='files'    )[command]
    cancel    = False

    if settings.session_trickle:
        if not queue.empty():
            cancel = True
            while not queue.empty():
                queue.get()
            log_m_dictionary = dict((c.rx_account, c.log_messages) for c in window)
            queue.put((cancel_pt, log_m_dictionary))

        message = f"Cancelled queues {p_type}." if cancel else f"No {p_type} to cancel."
        c_print(message, head=1, tail=1)

    else:
        p_buffer = []

        while not queue.empty():
            packet, settings, rx_account, tx_account, logging, win = queue.get()

            # Put messages unrelated to active window into buffer
            if win != window.uid:
                p_buffer.append((packet, settings, rx_account, tx_account, logging, win))
            else:
                cancel = True

        # Put cancel packets for each window contact to queue first
        if cancel:
            for c in window:
                print('put cancel packet to queue')
                queue.put((cancel_pt, settings, c.rx_account, c.tx_account, c.log_messages, window.uid))

        # Put buffered tuples back to queue
        for p in p_buffer:
            queue.put(p)

        if cancel:
            message = f"Cancelled queued {p_type} to {window.type} {window.name}."
        else:
            message = f"No {p_type} queued for {window.type} {window.name}"

        c_print(message, head=1, tail=1)
Ejemplo n.º 14
0
    def new_password(cls, purpose: str = "master password") -> str:
        """Prompt user to enter and confirm a new password."""
        password_1 = pwd_prompt(f"Enter a new {purpose}: ", '┌', '┐')
        password_2 = pwd_prompt(f"Confirm the {purpose}: ", '├', '┤')

        if password_1 == password_2:
            return password_1
        else:
            c_print("Error: Passwords did not match. Try again.",
                    head=1,
                    tail=1)
            time.sleep(1)
            print_on_previous_line(reps=7)
            return cls.new_password(purpose)
Ejemplo n.º 15
0
    def __init__(self,
                 return_msg: str,
                 output: bool = True,
                 delay: float = 0,
                 window: Any = None) -> None:
        self.message = return_msg

        if window is None:
            if output:
                clear_screen()
                c_print(self.message, head=1, tail=1)
            time.sleep(delay)
        else:
            window.print_new(datetime.datetime.now(), return_msg)
Ejemplo n.º 16
0
def cancel_packet(user_input: 'UserInput',
                  window:     'TxWindow',
                  settings:   'Settings',
                  queues:     Dict[bytes, 'Queue']) -> None:
    """Cancel sent message/file to contact/group."""

    queue, header, p_type = dict(cm=(queues[MESSAGE_PACKET_QUEUE], M_C_HEADER, 'messages'),
                                 cf=(queues[FILE_PACKET_QUEUE],    F_C_HEADER, 'files'   ))[user_input.plaintext]

    cancel_pt = header + bytes(PADDING_LEN)

    cancel = False
    if settings.session_traffic_masking:
        if queue.qsize() != 0:
            cancel = True
            while queue.qsize() != 0:
                queue.get()
            log_m_dictionary = dict((c.rx_account, c.log_messages) for c in window)
            queue.put((cancel_pt, log_m_dictionary, True))

        message = f"Cancelled queues {p_type}." if cancel else f"No {p_type} to cancel."
        c_print(message, head=1, tail=1)

    else:
        p_buffer = []
        while queue.qsize() != 0:
            q_data  = queue.get()
            win_uid = q_data[6]

            # Put messages unrelated to active window into buffer
            if win_uid != window.uid:
                p_buffer.append(q_data)
            else:
                cancel = True

        # Put cancel packets for each window contact to queue first
        if cancel:
            for c in window:
                queue.put((cancel_pt, settings, c.rx_account, c.tx_account, c.log_messages, window.uid))

        # Put buffered tuples back to queue
        for p in p_buffer:
            queue.put(p)

        if cancel:
            message = f"Cancelled queued {p_type} to {window.type_print} {window.name}."
        else:
            message = f"No {p_type} queued for {window.type_print} {window.name}."

        c_print(message, head=1, tail=1)
Ejemplo n.º 17
0
    def redraw(self, file=None) -> None:
        """Print all messages received to window."""
        self.unread_messages = 0

        if file is None:
            clear_screen()

        if self.message_log:
            self.previous_msg_ts = self.message_log[0][0]
            self.create_handle_dict(self.message_log)
            for msg_tuple in self.message_log:
                self.print(msg_tuple, file)
        else:
            c_print(f"This window for {self.name} is currently empty.",
                    head=1,
                    tail=1)
Ejemplo n.º 18
0
def process_imported_file(ts: 'datetime', packet: bytes,
                          window_list: 'WindowList', settings: 'Settings'):
    """Decrypt and store imported file."""
    while True:
        try:
            print('')
            key = get_b58_key(B58_FILE_KEY, settings)
        except KeyboardInterrupt:
            raise FunctionReturn("File import aborted.", head=2)

        try:
            phase("Decrypting file", head=1)
            file_pt = auth_and_decrypt(packet[1:], key, soft_e=True)
            phase(DONE)
            break
        except (nacl.exceptions.CryptoError, nacl.exceptions.ValueError):
            phase('ERROR', done=True)
            c_print("Invalid decryption key. Try again.")
            print_on_previous_line(reps=7, delay=1.5)
        except KeyboardInterrupt:
            phase('ABORT', done=True)
            raise FunctionReturn("File import aborted.")

    try:
        phase("Decompressing file")
        file_dc = zlib.decompress(file_pt)
        phase(DONE)
    except zlib.error:
        phase('ERROR', done=True)
        raise FunctionReturn("Error: Decompression of file data failed.")

    try:
        f_name = bytes_to_str(file_dc[:PADDED_UTF32_STR_LEN])
    except UnicodeError:
        raise FunctionReturn("Error: Received file name had invalid encoding.")

    if not f_name.isprintable() or not f_name:
        raise FunctionReturn("Error: Received file had an invalid name.")

    f_data = file_dc[PADDED_UTF32_STR_LEN:]
    final_name = store_unique(f_data, DIR_IMPORTED, f_name)

    message = f"Stored imported file as '{final_name}'"
    box_print(message, head=1)

    local_win = window_list.get_local_window()
    local_win.add_new(ts, message)
Ejemplo n.º 19
0
def change_gui_dialog(settings: 'Settings', command: bytes) -> None:
    """Change file selection (GUI/CLI prompt) setting on NH."""
    try:
        value_bytes = command[2:].lower()
        if value_bytes not in [b'true', b'false']:
            raise ValueError
        value = (value_bytes == b'true')
    except ValueError:
        raise FunctionReturn(
            "Error: Received invalid GUI dialog setting value from TxM.")

    settings.disable_gui_dialog = value
    settings.store_settings()

    c_print("Changed setting disable_gui_dialog to {}.".format(value),
            head=1,
            tail=1)
Ejemplo n.º 20
0
    def validate_key_value_pair(key: str, value: str,
                                contact_list: 'ContactList',
                                group_list: 'GroupList') -> None:
        """Check values of some settings in closer detail."""
        if key in [
                'm_members_in_group', 'm_number_of_groups',
                'm_number_of_accnts'
        ]:
            if eval(value) % 10 != 0:
                raise FunctionReturn(
                    "Database padding settings must be divisible by 10.")

        if key == 'm_members_in_group':
            min_size = round_up(group_list.largest_group())
            if eval(value) < min_size:
                raise FunctionReturn(
                    f"Can't set max number of members lower than {min_size}.")

        if key == 'm_number_of_groups':
            min_size = round_up(len(group_list))
            if eval(value) < min_size:
                raise FunctionReturn(
                    f"Can't set max number of groups lower than {min_size}.")

        if key == 'm_number_of_accnts':
            min_size = round_up(len(contact_list))
            if eval(value) < min_size:
                raise FunctionReturn(
                    f"Can't set max number of contacts lower than {min_size}.")

        if key == 'serial_iface_speed':
            if eval(value) not in serial.Serial().BAUDRATES:
                raise FunctionReturn("Specified baud rate is not supported.")
            c_print("Baud rate will change on restart.", head=1, tail=1)

        if key == 'e_correction_ratio':
            if not value.isdigit() or eval(value) < 1:
                raise FunctionReturn(
                    "Invalid value for error correction ratio.")
            c_print("Error correction ratio will change on restart.",
                    head=1,
                    tail=1)

        if key in ['rxm_serial_adapter', 'txm_serial_adapter']:
            c_print("Interface will change on restart.", head=1, tail=1)

        if key in [
                'trickle_connection', 'trickle_stat_delay',
                'trickle_rand_delay'
        ]:
            c_print("Trickle setting will change on restart.", head=1, tail=1)
Ejemplo n.º 21
0
def add_new_contact(contact_list: 'ContactList', group_list: 'GroupList',
                    settings: 'Settings', queues: Dict[bytes, 'Queue'],
                    gateway: 'Gateway') -> None:
    """Prompt for contact account details and initialize desired key exchange method."""
    try:
        if settings.session_trickle:
            raise FunctionReturn("Command disabled during trickle connection.")

        if len(contact_list) >= settings.m_number_of_accnts:
            raise FunctionReturn(
                f"Error: TFC settings only allow {settings.m_number_of_accnts} accounts."
            )

        clear_screen()
        c_print("Add new contact", head=1)

        acco = box_input("Contact account", tail=1,
                         validator=validate_account).strip()
        user = box_input("Your account", tail=1,
                         validator=validate_account).strip()
        defn = acco.split('@')[0].capitalize()
        nick = box_input(f"Contact nick [{defn}]",
                         default=defn,
                         tail=1,
                         validator=validate_nick,
                         validator_args=(contact_list, group_list,
                                         acco)).strip()
        keyx = box_input("Key exchange ([ECDHE],PSK) ",
                         default='ECDHE',
                         tail=1,
                         validator=validate_key_exchange).strip()

        if keyx.lower() in 'ecdhe':
            start_key_exchange(acco, user, nick, contact_list, settings,
                               queues, gateway)

        elif keyx.lower() in 'psk':
            new_psk(acco, user, nick, contact_list, settings, queues)

    except KeyboardInterrupt:
        raise FunctionReturn("Contact creation aborted.")
Ejemplo n.º 22
0
def add_new_contact(contact_list: 'ContactList', group_list: 'GroupList',
                    settings: 'Settings', queues: Dict[bytes,
                                                       'Queue']) -> None:
    """Prompt for contact account details and initialize desired key exchange."""
    try:
        if settings.session_traffic_masking:
            raise FunctionReturn(
                "Error: Command is disabled during traffic masking.")

        if len(contact_list) >= settings.max_number_of_contacts:
            raise FunctionReturn(
                f"Error: TFC settings only allow {settings.max_number_of_contacts} accounts."
            )

        clear_screen()
        c_print("Add new contact", head=1)

        contact_account = box_input("Contact account",
                                    validator=validate_account).strip()
        user_account = box_input("Your account",
                                 validator=validate_account).strip()
        default_nick = contact_account.split('@')[0].capitalize()
        contact_nick = box_input(f"Contact nick [{default_nick}]",
                                 default=default_nick,
                                 validator=validate_nick,
                                 validator_args=(contact_list, group_list,
                                                 contact_account)).strip()
        key_exchange = box_input("Key exchange ([X25519],PSK) ",
                                 default=X25519,
                                 validator=validate_key_exchange).strip()

        if key_exchange.lower() in X25519:
            start_key_exchange(contact_account, user_account, contact_nick,
                               contact_list, settings, queues)

        elif key_exchange.lower() in PSK:
            create_pre_shared_key(contact_account, user_account, contact_nick,
                                  contact_list, settings, queues)

    except KeyboardInterrupt:
        raise FunctionReturn("Contact creation aborted.", head_clear=True)
Ejemplo n.º 23
0
def process_imported_file(ts:          'datetime',
                          packet:      bytes,
                          window_list: 'WindowList'):
    """Decrypt and store imported file."""
    while True:
        try:
            print('')
            key = get_b58_key('imported_file')
            phase("Decrypting file", head=1)
            file_pt = auth_and_decrypt(packet[1:], key, soft_e=True)
            phase("Done")
            break
        except nacl.exceptions.CryptoError:
            c_print("Invalid decryption key. Try again.", head=2)
            print_on_previous_line(reps=6, delay=1.5)
        except KeyboardInterrupt:
            raise FunctionReturn("File import aborted.")

    try:
        phase("Decompressing file")
        file_dc = zlib.decompress(file_pt)
        phase("Done")
    except zlib.error:
        raise FunctionReturn("Decompression of file data failed.")

    try:
        f_name  = bytes_to_str(file_dc[:1024])
    except UnicodeError:
        raise FunctionReturn("Received file had an invalid name.")

    if not f_name.isprintable():
        raise FunctionReturn("Received file had an invalid name.")

    f_data     = file_dc[1024:]
    final_name = store_unique(f_data, DIR_IMPORTED, f_name)

    message = "Stored imported file to {}/{}".format(DIR_IMPORTED, final_name)
    box_print(message, head=1)

    local_win = window_list.get_local_window()
    local_win.print_new(ts, message, print_=False)
Ejemplo n.º 24
0
    def __init__(self,
                 message: str,
                 output: bool = True,
                 delay: float = 0,
                 window: 'RxWindow' = None,
                 head: int = 1,
                 tail: int = 1,
                 head_clear: bool = False,
                 tail_clear: bool = False) -> None:
        self.message = message

        if window is None:
            if output:
                if head_clear:
                    clear_screen()
                c_print(self.message, head=head, tail=tail)
            time.sleep(delay)
            if tail_clear:
                clear_screen()
        else:
            window.add_new(datetime.now(), self.message, output=output)
Ejemplo n.º 25
0
def get_b58_key(k_type: str) -> bytes:
    """Ask user to input Base58 encoded public key from RxM."""
    if k_type == 'pubkey':
        clear_screen()
        c_print("Import public key from RxM", head=1, tail=1)
        c_print("WARNING")
        message_printer(
            "Key exchange will break the HW separation. "
            "Outside specific requests TxM (this computer) "
            "makes, you must never copy any data from "
            "NH/RxM to TxM. Doing so could infect TxM, that "
            "could then later covertly transmit private "
            "keys/messages to adversary on NH.",
            head=1,
            tail=1)
        box_msg = "Enter contact's public key from RxM"
    elif k_type == 'localkey':
        box_msg = "Enter local key decryption key from TxM"
    elif k_type == 'imported_file':
        box_msg = "Enter file decryption key"
    else:
        raise CriticalError("Invalid key type")

    while True:
        pub_key = box_input(box_msg, expected_len=59)
        pub_key = ''.join(pub_key.split())

        try:
            return b58decode(pub_key)
        except ValueError:
            c_print("Checksum error - Check that entered key is correct.",
                    head=1)
            print_on_previous_line(reps=4, delay=1.5)
Ejemplo n.º 26
0
    def new_file_packet(self) -> None:
        """New file transmission handling logic."""
        name = self.name
        was_active = self.long_active
        self.clear_file_metadata()
        self.clear_assembly_packets()

        if self.origin == ORIGIN_USER_HEADER:
            self.add_masking_packet_to_logfile()
            raise FunctionReturn("Ignored file from user.", output=False)

        if not self.contact.file_reception:
            self.add_masking_packet_to_logfile()
            raise FunctionReturn(
                f"Alert! File transmission from {self.contact.nick} but reception is disabled."
            )

        if was_active:
            c_print(
                f"Alert! File '{name}' from {self.contact.nick} never completed.",
                head=1,
                tail=1)
Ejemplo n.º 27
0
def im_outgoing(queues: Dict[bytes, 'Queue'], settings: 'Settings') -> None:
    """\
    Loop that outputs messages and public keys from
    queue and sends them to contacts over Pidgin.
    """
    bus = dbus.SessionBus(private=True)
    obj = bus.get_object("im.pidgin.purple.PurpleService",
                         "/im/pidgin/purple/PurpleObject")
    purple = dbus.Interface(obj, "im.pidgin.purple.PurpleInterface")
    queue = queues[TXM_TO_IM_QUEUE]

    while True:
        with ignored(dbus.exceptions.DBusException, EOFError,
                     KeyboardInterrupt):
            while queue.qsize() == 0:
                time.sleep(0.01)

            header, payload, user, contact = queue.get()

            b64_str = base64.b64encode(payload).decode()
            payload = '|'.join([TFC, header.decode(), b64_str])
            user = user.decode()
            contact = contact.decode()

            user_found = False
            for u in purple.PurpleAccountsGetAllActive():
                if user == purple.PurpleAccountGetUsername(u)[:-1]:
                    user_found = True
                    if settings.relay_to_im_client:
                        new_conv = purple.PurpleConversationNew(1, u, contact)
                        sel_conv = purple.PurpleConvIm(new_conv)
                        purple.PurpleConvImSend(sel_conv, payload)
                    continue

            if not user_found:
                c_print("Error: No user {} found.".format(user),
                        head=1,
                        tail=1)
Ejemplo n.º 28
0
def check_kernel_entropy() -> None:
    """Wait until Kernel CSPRNG is sufficiently seeded.

    Wait until entropy_avail file states that system has at least 512
    bits of entropy. The headroom allows room for error in accuracy of
    entropy collector's entropy estimator; As long as input has at least
    4 bits per byte of actual entropy, kernel CSPRNG will be sufficiently
    seeded when it generates 256-bit keys.
    """
    clear_screen()
    phase("Waiting for Kernel CSPRNG entropy pool to fill up", head=1)

    ent_avail = 0
    while ent_avail < ENTROPY_THRESHOLD:
        with ignored(EOFError, KeyboardInterrupt):
            with open('/proc/sys/kernel/random/entropy_avail') as f:
                value = f.read()
            ent_avail = int(value.strip())
            c_print(f"{ent_avail}/{ENTROPY_THRESHOLD}")
            print_on_previous_line(delay=0.1)

    print_on_previous_line()
    phase("Waiting for Kernel CSPRNG entropy pool to fill up")
    phase(DONE)
Ejemplo n.º 29
0
Archivo: dd.py Proyecto: AJMartel/tfc
def draw_frame(argv: str, message: str, high: bool) -> None:
    """Draw data diode animation frame.

    :param argv:    Arguments for simulator position/orientation
    :param message: Status message to print
    :param high:    Determines signal's state (high/low)
    :return:        None
    """
    l, r, symbol, arrow = dict(txnhlr=('Tx', 'Rx', '>', '→'),
                               nhrxrl=('Tx', 'Rx', '>', '→'),
                               txnhrl=('Rx', 'Tx', '<', '←'),
                               nhrxlr=('Rx', 'Tx', '<', '←'))[argv]

    arrow = ' ' if message == 'Idle' else arrow
    blink = symbol if high else ' '

    offset_from_center = 4
    print(((get_terminal_height() // 2) - offset_from_center) * '\n')

    c_print(message)
    c_print(arrow)
    c_print("─────╮ " + ' ' + " ╭─────")
    c_print(f"  {l} │ " + blink + f" │ {r}  ")
    c_print("─────╯ " + ' ' + " ╰─────")
Ejemplo n.º 30
0
def get_b58_key(key_type: str, settings: 'Settings') -> bytes:
    """Ask user to input Base58 encoded public key from RxM.

    For file keys, use testnet address format instead to
    prevent file injected via import from accidentally
    being decrypted with public key from adversary.
    """
    if key_type == B58_PUB_KEY:
        clear_screen()
        c_print("Import public key from RxM", head=1, tail=1)
        c_print("WARNING")
        message_printer(
            "Outside specific requests TxM (this computer) "
            "makes, you must never copy any data from "
            "NH/RxM to TxM. Doing so could infect TxM, that "
            "could then later covertly transmit private "
            "keys/messages to attacker.",
            head=1,
            tail=1)
        message_printer("You can resend your public key by typing 'resend'",
                        tail=1)
        box_msg = "Enter contact's public key from RxM"
    elif key_type == B58_LOCAL_KEY:
        box_msg = "Enter local key decryption key from TxM"
    elif key_type == B58_FILE_KEY:
        box_msg = "Enter file decryption key"
    else:
        raise CriticalError("Invalid key type")

    while True:
        if settings.local_testing_mode or key_type == B58_FILE_KEY:
            pub_key = box_input(box_msg, expected_len=51)
            small = True
        else:
            pub_key = box_input(box_msg, expected_len=65, key_input=True)
            small = False
        pub_key = ''.join(pub_key.split())

        if key_type == B58_PUB_KEY and pub_key == RESEND:
            return pub_key.encode()

        try:
            return b58decode(pub_key, file_key=(key_type == B58_FILE_KEY))
        except ValueError:
            c_print("Checksum error - Check that entered key is correct.",
                    head=1)
            print_on_previous_line(reps=5 if small else 6, delay=1.5)