Exemple #1
0
    def test_box_input(self):
        builtins.input = lambda x: 'mock_input'
        self.assertEqual(box_input('test title'), 'mock_input')
        self.assertEqual(
            box_input('test title', head=1, tail=1, expected_len=20),
            'mock_input')

        builtins.input = lambda x: ''
        self.assertEqual(
            box_input('test title',
                      head=1,
                      tail=1,
                      default='mock_input',
                      expected_len=20), 'mock_input')

        def test_validator(string, *_):
            if string == 'ok':
                return True, ''
            else:
                print(string)
                return False, 'Error'

        input_list = ['bad', 'ok']
        gen = iter(input_list)

        def mock_input(_):
            return str(next(gen))

        builtins.input = mock_input
        self.assertEqual(box_input('test title', validator=test_validator),
                         'ok')
Exemple #2
0
 def test_box_input(self):
     self.assertEqual(box_input('test title'), 'mock_input')
     self.assertEqual(box_input('test title', head=1, expected_len=20),
                      'mock_input')
     self.assertEqual(
         box_input('test title',
                   head=1,
                   default='mock_input',
                   expected_len=20), 'mock_input')
     self.assertEqual(
         box_input('test title', validator=self.mock_validator), 'ok')
Exemple #3
0
 def test_box_input(self, *_: Any) -> None:
     self.assertEqual(box_input('test title'), 'mock_input')
     self.assertEqual(box_input('test title', head=1, expected_len=20),
                      'mock_input')
     self.assertEqual(
         box_input('test title',
                   head=1,
                   default='mock_input',
                   expected_len=20), 'mock_input')
     self.assertEqual(
         box_input('test title',
                   validator=lambda string, *_: ''
                   if string == 'ok' else 'Error'), 'ok')
Exemple #4
0
def get_onion_address_from_user(onion_address_user: str,
                                queues: 'QueueDict') -> str:
    """Get contact's Onion Address from user."""
    while True:
        onion_address_contact = box_input("Contact account",
                                          expected_len=ONION_ADDRESS_LENGTH)
        error_msg = validate_onion_addr(onion_address_contact,
                                        onion_address_user)

        if error_msg:
            m_print(error_msg, head=1)
            print_on_previous_line(reps=5, delay=1)

            if error_msg not in [
                    "Error: Invalid account length.",
                    "Error: Account must be in lower case.",
                    "Error: Can not add reserved account.",
                    "Error: Can not add own account."
            ]:
                relay_command = UNENCRYPTED_DATAGRAM_HEADER + UNENCRYPTED_ACCOUNT_CHECK + onion_address_contact.encode(
                )
                queue_to_nc(relay_command, queues[RELAY_PACKET_QUEUE])
            continue

        return onion_address_contact
Exemple #5
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.")
Exemple #6
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)
Exemple #7
0
    def setup(self) -> None:
        """Prompt the user to enter initial serial interface setting.

        Ensure that the serial interface is available before proceeding.
        """
        if not self.local_testing_mode and not self.qubes:
            name = {
                TX: TRANSMITTER,
                NC: RELAY,
                RX: RECEIVER
            }[self.software_operation]

            self.use_serial_usb_adapter = yes(
                f"Use USB-to-serial/TTL adapter for {name} Computer?",
                head=1,
                tail=1)

            if self.use_serial_usb_adapter:
                for f in sorted(os.listdir('/dev/')):
                    if f.startswith('ttyUSB'):
                        return None
                m_print("Error: USB-to-serial/TTL adapter not found.")
                self.setup()
            else:
                if self.built_in_serial_interface not in sorted(
                        os.listdir('/dev/')):
                    m_print(
                        f"Error: Serial interface /dev/{self.built_in_serial_interface} not found."
                    )
                    self.setup()

        if self.qubes and self.software_operation != RX:

            # Check if IP address was stored by the installer.
            if os.path.isfile(QUBES_RX_IP_ADDR_FILE):
                cached_ip = open(QUBES_RX_IP_ADDR_FILE).read().strip()
                os.remove(QUBES_RX_IP_ADDR_FILE)

                if validate_ip_address(cached_ip) == '':
                    self.rx_udp_ip = cached_ip
                    return

            # If we reach this point, no cached IP was found, prompt for IP address from the user.
            rx_device, short = ('Networked',
                                'NET') if self.software_operation == TX else (
                                    'Destination', 'DST')
            m_print(f"Enter the IP address of the {rx_device} Computer",
                    head=1,
                    tail=1)
            self.rx_udp_ip = box_input(f"{short} IP-address",
                                       expected_len=15,
                                       validator=validate_ip_address,
                                       tail=1)
Exemple #8
0
def add_new_contact(contact_list: 'ContactList', group_list: 'GroupList',
                    settings: 'Settings', queues: 'QueueDict',
                    onion_service: 'OnionService') -> None:
    """Prompt for contact account details and initialize desired key exchange.

    This function requests the minimum amount of data about the
    recipient as possible. The TFC account of contact is the same as the
    Onion URL of contact's v3 Tor Onion Service. Since the accounts are
    random and hard to remember, the user has to choose a nickname for
    their contact. Finally, the user must select the key exchange method:
    ECDHE for convenience in a pre-quantum world, or PSK for situations
    where physical key exchange is possible, and ciphertext must remain
    secure even after sufficient QTMs are available to adversaries.

    Before starting the key exchange, Transmitter Program exports the
    public key of contact's Onion Service to Relay Program on their
    Networked Computer so that a connection to the contact can be
    established.
    """
    try:
        if settings.traffic_masking:
            raise SoftError(
                "Error: Command is disabled during traffic masking.",
                head_clear=True)

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

        m_print("Add new contact", head=1, bold=True, head_clear=True)

        m_print([
            "Your TFC account is", onion_service.user_onion_address, '',
            "Warning!", "Anyone who knows this account",
            "can see when your TFC is online"
        ],
                box=True)

        contact_address = get_onion_address_from_user(
            onion_service.user_onion_address, queues)
        onion_pub_key = onion_address_to_pub_key(contact_address)

        contact_nick = box_input(
            "Contact nick",
            expected_len=
            ONION_ADDRESS_LENGTH,  # Limited to 255 but such long nick is unpractical.
            validator=validate_nick,
            validator_args=(contact_list, group_list, onion_pub_key)).strip()

        key_exchange = box_input(f"Key exchange ([{ECDHE}],PSK) ",
                                 default=ECDHE,
                                 expected_len=28,
                                 validator=validate_key_exchange).strip()

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

        if key_exchange.upper() in ECDHE:
            start_key_exchange(onion_pub_key, contact_nick, contact_list,
                               settings, queues)

        elif key_exchange.upper() in PSK:
            create_pre_shared_key(onion_pub_key, contact_nick, contact_list,
                                  settings, onion_service, queues)

    except (EOFError, KeyboardInterrupt):
        raise SoftError("Contact creation aborted.",
                        head=2,
                        delay=1,
                        tail_clear=True)