예제 #1
0
def federated_ursulas(ursula_federated_test_config):
    if MOCK_KNOWN_URSULAS_CACHE:
        raise RuntimeError(
            "Ursulas cache was unclear at fixture loading time. "
            "Did you use one of the ursula maker functions without cleaning up?"
        )
        # MOCK_KNOWN_URSULAS_CACHE.clear()

    _ursulas = make_federated_ursulas(
        ursula_config=ursula_federated_test_config,
        quantity=NUMBER_OF_URSULAS_IN_DEVELOPMENT_NETWORK)

    # Since we mutate this list in some tests, it's not enough to remember and remove the Ursulas; we have to remember them by port.
    # The same is true of blockchain_ursulas below.
    _ports_to_remove = [ursula.rest_interface.port for ursula in _ursulas]
    yield _ursulas

    for port in _ports_to_remove:
        if port in MOCK_KNOWN_URSULAS_CACHE:
            test_logger.debug(
                f"Removing {port} ({MOCK_KNOWN_URSULAS_CACHE[port]}).")
            del MOCK_KNOWN_URSULAS_CACHE[port]

    for u in _ursulas:
        u.stop()
        u._finalize()

    # Pytest will hold on to this object, need to clear it manually.
    # See https://github.com/pytest-dev/pytest/issues/5642
    _ursulas.clear()
예제 #2
0
def test_hendrix_handles_content_length_validation(ursula_federated_test_config):
    node = make_federated_ursulas(ursula_config=ursula_federated_test_config, quantity=1).pop()
    node_deployer = node.get_deployer()

    node_deployer.addServices()
    node_deployer.catalogServers(node_deployer.hendrix)
    node_deployer.start()

    def check_node_rejects_large_posts(node):
        too_much_data = os.urandom(100 * 1024)
        response = requests.post(
            "https://{}/consider_arrangement".format(node.rest_url()),
            data=too_much_data, verify=False)
        assert response.status_code > 400
        assert response.reason == "Request Entity Too Large"
        return node

    def check_node_accepts_normal_posts(node):
        a_normal_arrangement = os.urandom(49 * 1024)  # 49K, the limit is 50K
        response = requests.post(
            "https://{}/consider_arrangement".format(node.rest_url()),
            data=a_normal_arrangement, verify=False)
        assert response.status_code >= 500  # it still fails because we are sending random bytes
        assert response.reason != "Request Entity Too Large"  # but now we are running nucypher code
        return node

    yield threads.deferToThread(check_node_rejects_large_posts, node)
    yield threads.deferToThread(check_node_accepts_normal_posts, node)
예제 #3
0
def fleet_of_highperf_mocked_ursulas(ursula_federated_test_config, request):
    # good_serials = _determine_good_serials(10000, 50000)
    try:
        quantity = request.param
    except AttributeError:
        quantity = 5000  # Bigass fleet by default; that's kinda the point.
    with GlobalLoggerSettings.pause_all_logging_while():
        with mock_secret_source():
            with mock_cert_storage, mock_cert_loading, mock_rest_app_creation, mock_cert_generation, mock_remember_node, mock_message_verification:
                _ursulas = make_federated_ursulas(
                    ursula_config=ursula_federated_test_config,
                    quantity=quantity,
                    know_each_other=False)
                all_ursulas = {u.checksum_address: u for u in _ursulas}

                for ursula in _ursulas:
                    # FIXME #2588: FleetSensor should not own fully-functional Ursulas.
                    # It only needs to see whatever public info we can normally get via REST.
                    # Also sharing mutable Ursulas like that can lead to unpredictable results.
                    ursula.known_nodes.current_state._nodes = all_ursulas
                    ursula.known_nodes.current_state.checksum = b"This is a fleet state checksum..".hex(
                    )
    yield _ursulas

    for ursula in _ursulas:
        del MOCK_KNOWN_URSULAS_CACHE[ursula.rest_interface.port]
예제 #4
0
def test_federated_nodes_connect_via_tls_and_verify(
        ursula_federated_test_config):
    node = make_federated_ursulas(ursula_config=ursula_federated_test_config,
                                  quantity=1).pop()
    node_deployer = node.get_deployer()

    node_deployer.addServices()
    node_deployer.catalogServers(node_deployer.hendrix)
    node_deployer.start()

    cert = node_deployer.cert.to_cryptography()
    cert_bytes = cert.public_bytes(serialization.Encoding.PEM)

    def check_node_with_cert(node, cert_file):
        response = requests.get("https://{}/public_information".format(
            node.rest_url()),
                                verify=cert_file)
        ursula = Ursula.from_bytes(response.content)
        assert ursula == node

    try:
        with open("test-cert", "wb") as f:
            f.write(cert_bytes)
        yield threads.deferToThread(check_node_with_cert, node, "test-cert")
    finally:
        os.remove("test-cert")
예제 #5
0
def test_one_node_stores_a_bunch_of_others(federated_ursulas, ursula_federated_test_config):
    the_chosen_seednode = list(federated_ursulas)[2]  # ...neo?
    seed_node = the_chosen_seednode.seed_node_metadata()

    newcomer = make_federated_ursulas(
        ursula_config=ursula_federated_test_config,
        quantity=1,
        know_each_other=False,
        save_metadata=True,
        seed_nodes=[seed_node]).pop()

    assert not newcomer.known_nodes

    newcomer.start_learning_loop(now=True)

    def start_lonely_learning_loop():
        newcomer.start_learning_loop()
        start = maya.now()
        # Loop until the_chosen_seednode is in storage.
        while the_chosen_seednode not in newcomer.node_storage.all(federated_only=True):
            passed = maya.now() - start
            if passed.seconds > 2:
                pytest.fail("Didn't find the seed node.")

    yield deferToThread(start_lonely_learning_loop)

    assert list(newcomer.known_nodes)
    assert len(list(newcomer.known_nodes)) == len(list(newcomer.node_storage.all(True)))
    assert set(list(newcomer.known_nodes)) == set(list(newcomer.node_storage.all(True)))
예제 #6
0
def test_ursula_serves_statics(ursula_federated_test_config):

    with tempfile.TemporaryDirectory() as STATICS_DIR:
        os.environ['NUCYPHER_STATIC_FILES_ROOT'] = STATICS_DIR

        node = make_federated_ursulas(
            ursula_config=ursula_federated_test_config, quantity=1).pop()
        node_deployer = node.get_deployer()

        node_deployer.addServices()
        node_deployer.catalogServers(node_deployer.hendrix)
        node_deployer.start()

        cert = node_deployer.cert.to_cryptography()
        cert_bytes = cert.public_bytes(serialization.Encoding.PEM)

        def check_static_service(node, cert_file):

            response = requests.get(
                "https://{}/statics/test-never-make-a-file-with-this-name.js".
                format(node.rest_url()),
                verify=cert_file)
            assert response.status_code == 200
            assert "I am Javascript" in response.text
            assert response.headers['Content-Type'] == 'application/javascript'
            return node

        def check_static_file_not_there(node, cert_file):

            response = requests.get(
                "https://{}/statics/no-file-by-this-name.js".format(
                    node.rest_url()),
                verify=cert_file)
            assert response.status_code == 404
            return node

        try:
            with open("test-cert", "wb") as f:
                f.write(cert_bytes)
            Path(STATICS_DIR).mkdir(exist_ok=True)
            with open(
                    Path(STATICS_DIR,
                         'test-never-make-a-file-with-this-name.js'),
                    'w+') as fout:
                fout.write("console.log('I am Javascript')\n")
                fout.close()
            yield threads.deferToThread(check_static_service, node,
                                        "test-cert")
            yield threads.deferToThread(check_static_file_not_there, node,
                                        "test-cert")
        finally:
            Path("test-cert").unlink()
예제 #7
0
def fleet_of_highperf_mocked_ursulas(ursula_federated_test_config, request):
    try:
        quantity = request.param
    except AttributeError:
        quantity = 5000  # Bigass fleet by default; that's kinda the point.
    with GlobalLoggerSettings.pause_all_logging_while():
        with mock_secret_source():
            with mock_cert_storage, mock_cert_loading, mock_rest_app_creation, mock_cert_generation, mock_remember_node, mock_message_verification:
                _ursulas = make_federated_ursulas(ursula_config=ursula_federated_test_config,
                                                  quantity=quantity, know_each_other=False)
                all_ursulas = {u.checksum_address: u for u in _ursulas}
                for ursula in _ursulas:
                    ursula.known_nodes._nodes = all_ursulas
                    ursula.known_nodes.checksum = b"This is a fleet state checksum..".hex()
    return _ursulas
예제 #8
0
def federated_ursulas(ursula_federated_test_config):
    if MOCK_KNOWN_URSULAS_CACHE:
        raise RuntimeError(
            "Ursulas cache was unclear at fixture loading time.  Did you use one of the ursula maker functions without cleaning up?"
        )
    _ursulas = make_federated_ursulas(
        ursula_config=ursula_federated_test_config,
        quantity=NUMBER_OF_URSULAS_IN_DEVELOPMENT_NETWORK)
    # Since we mutate this list in some tests, it's not enough to remember and remove the Ursulas; we have to remember them by port.
    # The same is true of blockchain_ursulas below.
    _ports_to_remove = [ursula.rest_interface.port for ursula in _ursulas]
    yield _ursulas

    for port in _ports_to_remove:
        test_logger.debug(
            f"Removing {port} ({MOCK_KNOWN_URSULAS_CACHE[port]}).")
        del MOCK_KNOWN_URSULAS_CACHE[port]

    for u in _ursulas:
        u.stop()
예제 #9
0
def test_new_federated_ursula_announces_herself(ursula_federated_test_config):
    ursula_in_a_house, ursula_with_a_mouse = make_federated_ursulas(
        ursula_config=ursula_federated_test_config,
        quantity=2,
        know_each_other=False,
        network_middleware=MockRestMiddleware())

    # Neither Ursula knows about the other.
    assert ursula_in_a_house.known_nodes == ursula_with_a_mouse.known_nodes

    ursula_in_a_house.remember_node(ursula_with_a_mouse)

    # OK, now, ursula_in_a_house knows about ursula_with_a_mouse, but not vice-versa.
    assert ursula_with_a_mouse in ursula_in_a_house.known_nodes
    assert ursula_in_a_house not in ursula_with_a_mouse.known_nodes

    # But as ursula_in_a_house learns, she'll announce herself to ursula_with_a_mouse.
    ursula_in_a_house.learn_from_teacher_node()

    assert ursula_with_a_mouse in ursula_in_a_house.known_nodes
    assert ursula_in_a_house in ursula_with_a_mouse.known_nodes
예제 #10
0
def fleet_of_highperf_mocked_ursulas(ursula_federated_test_config, request):
    # good_serials = _determine_good_serials(10000, 50000)
    try:
        quantity = request.param
    except AttributeError:
        quantity = 5000  # Bigass fleet by default; that's kinda the point.
    with GlobalLoggerSettings.pause_all_logging_while():
        with mock_secret_source():
            with mock_cert_storage, mock_cert_loading, mock_rest_app_creation, mock_cert_generation, mock_remember_node, mock_message_verification:
                _ursulas = make_federated_ursulas(
                    ursula_config=ursula_federated_test_config,
                    quantity=quantity,
                    know_each_other=False)
                all_ursulas = {u.checksum_address: u for u in _ursulas}

                for ursula in _ursulas:
                    ursula.known_nodes.current_state._nodes = all_ursulas
                    ursula.known_nodes.current_state.checksum = b"This is a fleet state checksum..".hex(
                    )
    yield _ursulas

    for ursula in _ursulas:
        del MOCK_KNOWN_URSULAS_CACHE[ursula.rest_interface.port]
예제 #11
0
def federated_ursulas(ursula_federated_test_config):
    _ursulas = make_federated_ursulas(
        ursula_config=ursula_federated_test_config,
        quantity=NUMBER_OF_URSULAS_IN_DEVELOPMENT_NETWORK)
    yield _ursulas
예제 #12
0
def test_emit_warning_upon_new_version(ursula_federated_test_config, caplog):
    nodes = make_federated_ursulas(ursula_config=ursula_federated_test_config,
                                   quantity=3,
                                   know_each_other=False)
    teacher, learner, new_node = nodes

    learner.remember_node(teacher)
    teacher.remember_node(learner)
    teacher.remember_node(new_node)

    new_node.TEACHER_VERSION = learner.LEARNER_VERSION + 1

    warnings = []

    def warning_trapper(event):
        if event['log_level'] == LogLevel.warn:
            warnings.append(event)

    globalLogPublisher.addObserver(warning_trapper)
    learner.learn_from_teacher_node()

    assert len(warnings) == 1
    assert warnings[0]['log_format'] == learner.unknown_version_message.format(
        new_node, new_node.TEACHER_VERSION, learner.LEARNER_VERSION)

    # Now let's go a little further: make the version totally unrecognizable.

    # First, there's enough garbage to at least scrape a potential checksum address
    fleet_snapshot = os.urandom(32 + 4)
    random_bytes = os.urandom(50)  # lots of garbage in here
    future_version = learner.LEARNER_VERSION + 42
    version_bytes = future_version.to_bytes(2, byteorder="big")
    crazy_bytes = fleet_snapshot + VariableLengthBytestring(version_bytes +
                                                            random_bytes)
    signed_crazy_bytes = bytes(teacher.stamp(crazy_bytes))

    Response = namedtuple("MockResponse", ("content", "status_code"))
    response = Response(content=signed_crazy_bytes + crazy_bytes,
                        status_code=200)

    learner._current_teacher_node = teacher
    learner.network_middleware.get_nodes_via_rest = lambda *args, **kwargs: response
    learner.learn_from_teacher_node()

    # If you really try, you can read a node representation from the garbage
    accidental_checksum = to_checksum_address(random_bytes[:20])
    accidental_nickname = nickname_from_seed(accidental_checksum)[0]
    accidental_node_repr = Character._display_name_template.format(
        "Ursula", accidental_nickname, accidental_checksum)

    assert len(warnings) == 2
    assert warnings[1]['log_format'] == learner.unknown_version_message.format(
        accidental_node_repr, future_version, learner.LEARNER_VERSION)

    # This time, however, there's not enough garbage to assume there's a checksum address...
    random_bytes = os.urandom(2)
    crazy_bytes = fleet_snapshot + VariableLengthBytestring(version_bytes +
                                                            random_bytes)
    signed_crazy_bytes = bytes(teacher.stamp(crazy_bytes))

    response = Response(content=signed_crazy_bytes + crazy_bytes,
                        status_code=200)

    learner._current_teacher_node = teacher
    learner.learn_from_teacher_node()

    assert len(warnings) == 3
    # ...so this time we get a "really unknown version message"
    assert warnings[2][
        'log_format'] == learner.really_unknown_version_message.format(
            future_version, learner.LEARNER_VERSION)

    globalLogPublisher.removeObserver(warning_trapper)