Example #1
0
def test_get_external_ip_from_known_nodes_with_one_known_node(
        mock_requests, mock_network):
    sensor = FleetSensor(domain=mock_network)
    sensor._nodes['0xdeadbeef'] = Dummy()
    assert len(sensor) == 1
    get_external_ip_from_known_nodes(known_nodes=sensor)
    # skipped because there are too few known nodes
    mock_requests.assert_not_called()
Example #2
0
def test_learner_restores_metadata_from_storage(lonely_ursula_maker, tmpdir):
    # Create a local file-based node storage
    root = tmpdir.mkdir("known_nodes")
    metadata = root.mkdir("metadata")
    certs = root.mkdir("certs")
    old_storage = LocalFileBasedNodeStorage(federated_only=True,
                                            metadata_dir=metadata,
                                            certificates_dir=certs,
                                            storage_root=root)

    # Use the ursula maker with this storage so it's populated with nodes from one domain
    _some_ursulas = lonely_ursula_maker(domain="fistro",
                                        node_storage=old_storage,
                                        know_each_other=True,
                                        quantity=3,
                                        save_metadata=True)

    # Create a pair of new learners in a different domain, using the previous storage, and learn from it
    new_learners = lonely_ursula_maker(domain="duodenal",
                                       node_storage=old_storage,
                                       quantity=2,
                                       know_each_other=True,
                                       save_metadata=False)
    learner, buddy = new_learners
    buddy._Learner__known_nodes = FleetSensor(domain="fistro")

    # The learner shouldn't learn about any node from the first domain, since it's different.
    learner.learn_from_teacher_node()
    for restored_node in learner.known_nodes:
        assert restored_node.mature().domain == learner.domain

    # In fact, since the storage only contains nodes from a different domain,
    # the learner should only know its buddy from the second domain.
    assert set(learner.known_nodes) == {buddy}
Example #3
0
def test_node_client_get_state_metadata(tempfile_path):
    # Add some node data
    node_storage = CrawlerNodeStorage(storage_filepath=tempfile_path)
    state_1 = create_random_mock_state(seed=1)
    state_2 = create_random_mock_state(seed=2)
    state_3 = create_random_mock_state(seed=3)

    state_list = [state_1, state_2, state_3]
    for state in state_list:
        state_dict = FleetSensor.abridged_state_details(state)
        node_storage.store_state_metadata(state=state_dict)

    node_db_client = CrawlerStorageClient(db_filepath=tempfile_path)
    result = node_db_client.get_previous_states_metadata(limit=len(state_list))

    state_list.sort(key=lambda x: x.updated.epoch,
                    reverse=True)  # sorted by timestamp in descending order
    assert len(result) == len(state_list)

    # verify result
    # "result" of form of a list of state_info dictionaries
    for idx, value in enumerate(result):
        expected_row = convert_state_to_display_values(state_list[idx])
        for info_idx, column in enumerate(CrawlerNodeStorage.STATE_DB_SCHEMA):
            assert value[
                column[0]] == expected_row[info_idx], f"{column[0]} matches"
Example #4
0
def test_blockchain_ursula_stamp_verification_tolerance(blockchain_ursulas, mocker):
    #
    # Setup
    #

    lonely_blockchain_learner, blockchain_teacher, unsigned, *the_others = list(blockchain_ursulas)

    warnings = []

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

    # Make a bad identity evidence
    unsigned._Teacher__decentralized_identity_evidence = unsigned._Teacher__decentralized_identity_evidence[:-5] + (b'\x00' * 5)
    # Reset the metadata cache
    unsigned._metadata = None

    # Wipe known nodes!
    lonely_blockchain_learner._Learner__known_nodes = FleetSensor(domain=TEMPORARY_DOMAIN)
    lonely_blockchain_learner._current_teacher_node = blockchain_teacher
    lonely_blockchain_learner.remember_node(blockchain_teacher)

    globalLogPublisher.addObserver(warning_trapper)
    lonely_blockchain_learner.learn_from_teacher_node(eager=True)
    globalLogPublisher.removeObserver(warning_trapper)

    # We received one warning during learning, and it was about this very matter.
    assert len(warnings) == 1
    warning = warnings[0]['log_format']
    assert str(unsigned) in warning
    assert "Verification Failed" in warning  # TODO: Cleanup logging templates

    # TODO: Buckets!  #567
    # assert unsigned not in lonely_blockchain_learner.known_nodes

    # minus 2: self and the unsigned ursula.
    # assert len(lonely_blockchain_learner.known_nodes) == len(blockchain_ursulas) - 2
    assert blockchain_teacher in lonely_blockchain_learner.known_nodes

    # Learn about a node with a badly signed payload

    def bad_bytestring_of_known_nodes():
        # Signing with the learner's signer instead of the teacher's signer
        response_payload = MetadataResponsePayload(timestamp_epoch=blockchain_teacher.known_nodes.timestamp.epoch,
                                                   announce_nodes=[])
        response = MetadataResponse(signer=lonely_blockchain_learner.stamp.as_umbral_signer(),
                                    payload=response_payload)
        return bytes(response)

    mocker.patch.object(blockchain_teacher, 'bytestring_of_known_nodes', bad_bytestring_of_known_nodes)

    globalLogPublisher.addObserver(warning_trapper)
    lonely_blockchain_learner.learn_from_teacher_node(eager=True)
    globalLogPublisher.removeObserver(warning_trapper)

    assert len(warnings) == 2
    warning = warnings[1]['log_format']
    assert str(blockchain_teacher) in warning
    assert "Failed to verify MetadataResponse from Teacher" in warning  # TODO: Cleanup logging templates
def test_blockchain_alice_finds_ursula_via_rest(blockchain_alice, blockchain_ursulas):
    # Imagine alice knows of nobody.
    blockchain_alice._Learner__known_nodes = FleetSensor(domain=TEMPORARY_DOMAIN)

    blockchain_alice.remember_node(blockchain_ursulas[0])
    blockchain_alice.learn_from_teacher_node()
    assert len(blockchain_alice.known_nodes) == len(blockchain_ursulas)

    for ursula in blockchain_ursulas:
        assert ursula in blockchain_alice.known_nodes
def test_get_external_ip_default_unknown_network():
    unknown_domain = 'thisisnotarealdomain'

    # Without fleet sensor
    with pytest.raises(UnknownIPAddress):
        determine_external_ip_address(network=unknown_domain)

    # with fleet sensor
    sensor = FleetSensor(domain=unknown_domain)
    with pytest.raises(UnknownIPAddress):
        determine_external_ip_address(known_nodes=sensor, network=unknown_domain)
Example #7
0
def test_get_external_ip_cascade_failure(mocker, mock_network, mock_requests):
    first = mocker.patch(
        'nucypher.utilities.networking.get_external_ip_from_known_nodes',
        return_value=None)
    second = mocker.patch(
        'nucypher.utilities.networking.get_external_ip_from_default_teacher',
        return_value=None)
    third = mocker.patch(
        'nucypher.utilities.networking.get_external_ip_from_centralized_source',
        return_value=None)

    sensor = FleetSensor(domain=mock_network)
    sensor._nodes['0xdeadbeef'] = Dummy()

    with pytest.raises(UnknownIPAddress,
                       match='External IP address detection failed'):
        determine_external_ip_address(network=mock_network, known_nodes=sensor)

    first.assert_called_once()
    second.assert_called_once()
    third.assert_called_once()
Example #8
0
def test_get_external_ip_from_known_nodes(mock_client, mock_network):

    # Setup FleetSensor
    sensor = FleetSensor(domain=mock_network)
    sample_size = 3
    sensor._nodes['0xdeadbeef'] = Dummy()
    sensor._nodes['0xdeadllama'] = Dummy()
    sensor._nodes['0xdeadmouse'] = Dummy()
    assert len(sensor) == sample_size

    # First sampled node replies
    get_external_ip_from_known_nodes(known_nodes=sensor,
                                     sample_size=sample_size)
    assert mock_client.call_count == 1
    mock_client.call_count = 0  # reset

    # All sampled nodes dont respond
    mock_client.return_value = Dummy.BadResponse
    get_external_ip_from_known_nodes(known_nodes=sensor,
                                     sample_size=sample_size)
    assert mock_client.call_count == sample_size
Example #9
0
def test_get_external_ip_from_known_nodes_client(mocker, mock_client,
                                                 mock_network):

    # Setup FleetSensor
    sensor = FleetSensor(domain=mock_network)
    sample_size = 3
    sensor._nodes['0xdeadbeef'] = Dummy()
    sensor._nodes['0xdeadllama'] = Dummy()
    sensor._nodes['0xdeadmouse'] = Dummy()
    assert len(sensor) == sample_size

    # Setup HTTP Client
    mocker.patch.object(Ursula, 'from_teacher_uri', return_value=Dummy())
    teacher_uri = RestMiddleware.TEACHER_NODES[mock_network][0]

    get_external_ip_from_known_nodes(known_nodes=sensor,
                                     sample_size=sample_size)
    assert mock_client.call_count == 1  # first node responded

    function, endpoint = mock_client.call_args[0]
    assert function.__name__ == 'get'
    assert endpoint == f'https://{teacher_uri}/ping'
Example #10
0
def test_get_external_ip_from_known_nodes_with_one_known_node(mock_requests):
    sensor = FleetSensor(domain=MOCK_NETWORK)
    sensor.record_node(Dummy(b'deadbeefdeadbeefdead'))
    sensor.record_fleet_state()
    assert len(sensor) == 1
    get_external_ip_from_known_nodes(known_nodes=sensor)
    # skipped because there are too few known nodes
    mock_requests.assert_not_called()
Example #11
0
def test_blockchain_ursula_stamp_verification_tolerance(
        blockchain_ursulas, mocker):
    #
    # Setup
    #

    lonely_blockchain_learner, blockchain_teacher, unsigned, *the_others = list(
        blockchain_ursulas)

    warnings = []

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

    #
    # Attempt to verify unsigned stamp
    #
    unsigned._Teacher__decentralized_identity_evidence = NOT_SIGNED

    # Wipe known nodes!
    lonely_blockchain_learner._Learner__known_nodes = FleetSensor(
        domain=TEMPORARY_DOMAIN)
    lonely_blockchain_learner._current_teacher_node = blockchain_teacher
    lonely_blockchain_learner.remember_node(blockchain_teacher)

    globalLogPublisher.addObserver(warning_trapper)
    lonely_blockchain_learner.learn_from_teacher_node(eager=True)
    globalLogPublisher.removeObserver(warning_trapper)

    # We received one warning during learning, and it was about this very matter.
    assert len(warnings) == 1
    warning = warnings[0]['log_format']
    assert str(unsigned) in warning
    assert "stamp is unsigned" in warning  # TODO: Cleanup logging templates

    # TODO: Buckets!  #567
    # assert unsigned not in lonely_blockchain_learner.known_nodes

    # minus 2: self and the unsigned ursula.
    # assert len(lonely_blockchain_learner.known_nodes) == len(blockchain_ursulas) - 2
    assert blockchain_teacher in lonely_blockchain_learner.known_nodes

    # Learn about a node with a badly signed payload
    mocker.patch.object(lonely_blockchain_learner,
                        'verify_from',
                        side_effect=Learner.InvalidSignature)
    lonely_blockchain_learner.learn_from_teacher_node(eager=True)
    assert len(lonely_blockchain_learner.
               suspicious_activities_witnessed['vladimirs']) == 1
Example #12
0
def test_storage_store_state_metadata(sqlite_connection):
    node_storage = CrawlerNodeStorage(storage_filepath=IN_MEMORY_FILEPATH)

    state = create_specific_mock_state()

    # Store state data
    node_storage.store_state_metadata(state=FleetSensor.abridged_state_details(state))

    result = sqlite_connection.execute(f"SELECT * FROM {CrawlerNodeStorage.STATE_DB_NAME}").fetchall()
    assert len(result) == 1
    for row in result:
        verify_mock_state_matches_row(state, row)

    # update state
    new_now = state.updated.add(minutes=5)
    updated_state = create_specific_mock_state(updated=new_now)
    node_storage.store_state_metadata(state=FleetSensor.abridged_state_details(updated_state))

    # ensure same item gets updated
    result = sqlite_connection.execute(f"SELECT * FROM {CrawlerNodeStorage.STATE_DB_NAME}").fetchall()
    assert len(result) == 1  # state data is updated not added
    for row in result:
        verify_mock_state_matches_row(updated_state, row)
def test_get_external_ip_from_known_nodes(mock_client):

    # Setup FleetSensor
    sensor = FleetSensor(domain=MOCK_NETWORK)
    sample_size = 3
    sensor.record_node(Dummy('0xdeadbeef'))
    sensor.record_node(Dummy('0xdeadllama'))
    sensor.record_node(Dummy('0xdeadmouse'))
    sensor.record_fleet_state()
    assert len(sensor) == sample_size

    # First sampled node replies
    get_external_ip_from_known_nodes(known_nodes=sensor, sample_size=sample_size)
    assert mock_client.call_count == 1
    mock_client.call_count = 0  # reset

    # All sampled nodes dont respond
    mock_client.return_value = Dummy.BadResponse
    get_external_ip_from_known_nodes(known_nodes=sensor, sample_size=sample_size)
    assert mock_client.call_count == sample_size
Example #14
0
def test_storage_db_clear_not_metadata(sqlite_connection):
    node_storage = CrawlerNodeStorage(storage_filepath=IN_MEMORY_FILEPATH)

    # store some data
    node = create_random_mock_node()
    node_storage.store_node_metadata(node=node)

    state = create_specific_mock_state()
    node_storage.store_state_metadata(state=FleetSensor.abridged_state_details(state))

    teacher_checksum = '0x123456789'
    node_storage.store_current_teacher(teacher_checksum)

    verify_all_db_tables(sqlite_connection, expect_empty=False)

    # only clear certificates data
    node_storage.clear(metadata=False, certificates=True)

    # db tables should not have been cleared
    verify_all_db_tables(sqlite_connection, expect_empty=False)
Example #15
0
def test_get_external_ip_from_known_nodes_client(mocker, mock_client):

    # Setup FleetSensor
    sensor = FleetSensor(domain=MOCK_NETWORK)
    sample_size = 3
    sensor.record_node(Dummy(b'deadbeefdeadbeefdead'))
    sensor.record_node(Dummy(b'deadllamadeadllamade'))
    sensor.record_node(Dummy(b'deadmousedeadmousede'))
    sensor.record_fleet_state()
    assert len(sensor) == sample_size

    # Setup HTTP Client
    mocker.patch.object(Ursula,
                        'from_teacher_uri',
                        return_value=Dummy(b'deadporkdeadporkdead'))
    teacher_uri = TEACHER_NODES[MOCK_NETWORK][0]

    get_external_ip_from_known_nodes(known_nodes=sensor,
                                     sample_size=sample_size)
    assert mock_client.call_count == 1  # first node responded

    function, endpoint = mock_client.call_args[0]
    assert function.__name__ == 'get'
    assert endpoint == f'https://{teacher_uri}/ping'
Example #16
0
def test_get_external_ip_from_empty_known_nodes(mock_requests):
    sensor = FleetSensor(domain=MOCK_NETWORK)
    assert len(sensor) == 0
    get_external_ip_from_known_nodes(known_nodes=sensor)
    # skipped because there are no known nodes
    mock_requests.assert_not_called()