def test_all_changes_are_new_on_first_delta(capsys, monkeypatch):
    """The first delta marks all resolved domains as 'new'."""
    monkeypatch.setattr('dnstwister.repository.db', patches.SimpleKVDatabase())
    monkeypatch.setattr(
        'dnstwister.tools.dnstwist.DomainFuzzer', patches.SimpleFuzzer
    )
    monkeypatch.setattr(
        'dnstwister.tools.resolve', lambda domain: ('999.999.999.999', False)
    )
    repository = dnstwister.repository

    domain = 'www.example.com'

    worker_deltas.process_domain(domain)
    assert capsys.readouterr()[0] != ''

    resolution_report = repository.get_resolution_report(domain)
    assert resolution_report == {
        'www.example.co': {'ip': '999.999.999.999', 'tweak': 'Pretend'}
    }

    delta_report = repository.get_delta_report(domain)
    assert delta_report == {
        'deleted': [],
        'new': [('www.example.co', '999.999.999.999')],
        'updated': []
    }
def test_updated_ip_is_noted_in_delta(capsys, monkeypatch):
    """IP updates are marked as 'updated'."""
    monkeypatch.setattr('dnstwister.repository.db', patches.SimpleKVDatabase())
    monkeypatch.setattr(
        'dnstwister.tools.dnstwist.DomainFuzzer', patches.SimpleFuzzer
    )
    monkeypatch.setattr(
        'dnstwister.tools.resolve', lambda domain: ('999.999.999.999', False)
    )
    repository = dnstwister.repository

    domain = 'www.example.com'

    worker_deltas.process_domain(domain)

    monkeypatch.setattr(
        'dnstwister.tools.resolve', lambda domain: ('000.999.999.999', False)
    )

    # Mark the entry as 'old' to ensure it is re-run
    old_date = datetime.datetime.now() - datetime.timedelta(days=10)
    db_key = 'delta_report_updated:{}'.format(domain)
    repository.db._data[db_key] = old_date.strftime('%Y-%m-%dT%H:%M:%SZ')

    worker_deltas.process_domain(domain)
    delta_report = repository.get_delta_report(domain)
    assert delta_report == {
        'deleted': [],
        'updated': [('www.example.co', '999.999.999.999', '000.999.999.999')],
        'new': []
    }
def test_old_style_resolution_reports_are_updated(capsys, monkeypatch):
    """Test the migration to the more feature-rich reports works."""
    monkeypatch.setattr('dnstwister.repository.db', patches.SimpleKVDatabase())
    monkeypatch.setattr(
        'dnstwister.tools.dnstwist.DomainFuzzer', patches.SimpleFuzzer
    )
    monkeypatch.setattr(
        'dnstwister.tools.resolve', lambda domain: ('999.999.999.999', False)
    )
    repository = dnstwister.repository

    domain = 'www.example.com'

    # Pre-load an old-style resolution report
    db_key = 'resolution_report:{}'.format(domain)
    repository.db._data[db_key] = {'www.example.co': '127.0.0.1'}

    worker_deltas.process_domain(domain)

    delta_report = repository.get_delta_report(domain)
    assert delta_report == {
        'deleted': [],
        'updated': [('www.example.co', '127.0.0.1', '999.999.999.999')],
        'new': []
    }
def test_invalid_domain_is_unregistered(capsys, monkeypatch):
    """Invalid domains are tidied up."""
    monkeypatch.setattr('dnstwister.repository.db', patches.SimpleKVDatabase())
    repository = dnstwister.repository

    invalid_domain = '3j88??ASd'

    assert not repository.is_domain_registered(invalid_domain)

    repository.register_domain(invalid_domain)
    assert repository.is_domain_registered(invalid_domain)

    worker_deltas.process_domain(invalid_domain)
    assert not repository.is_domain_registered(invalid_domain)

    expected_output = 'Unregistering (invalid) {}\n'.format(invalid_domain)
    assert capsys.readouterr()[0] == expected_output
def test_new_domain_is_marked_as_read(capsys, monkeypatch):
    """New domain is marked as read at first pass."""
    monkeypatch.setattr('dnstwister.repository.db', patches.SimpleKVDatabase())
    monkeypatch.setattr(
        'dnstwister.tools.dnstwist.DomainFuzzer', patches.SimpleFuzzer
    )
    monkeypatch.setattr(
        'dnstwister.tools.resolve', lambda domain: ('999.999.999.999', False)
    )
    repository = dnstwister.repository

    domain = 'www.example.com'

    assert repository.delta_report_updated(domain) is None

    worker_deltas.process_domain(domain)
    assert repository.delta_report_updated(domain) is not None
    assert capsys.readouterr()[0] != ''
def test_old_domain_is_unregistered(capsys, monkeypatch):
    """Long-time unread domains are unregistered."""
    monkeypatch.setattr('dnstwister.repository.db', patches.SimpleKVDatabase())
    repository = dnstwister.repository

    domain = 'www.example.com'
    old_date = datetime.datetime.now() - datetime.timedelta(days=10)

    assert repository.delta_report_last_read(domain) is None

    repository.mark_delta_report_as_read(domain, old_date)
    assert repository.delta_report_last_read(domain) == old_date.replace(
        microsecond=0
    )

    worker_deltas.process_domain(domain)
    assert repository.delta_report_last_read(domain) is None

    expected_output = 'Unregistering (not read > 7 days) {}\n'.format(domain)
    assert capsys.readouterr()[0] == expected_output
def test_subscription_email_timing(capsys, monkeypatch):
    """Test that email subscriptions and delta reporting are in sync.

    A bug was found where, because signing up registers for delta reporting
    and the email is sent as soon as the report is generated, it is possible
    to send 2 emails between delta reports.
    """

    # Patch away
    monkeypatch.setattr("dnstwister.repository.db", patches.SimpleKVDatabase())
    monkeypatch.setattr("dnstwister.tools.dnstwist.DomainFuzzer", patches.SimpleFuzzer)
    monkeypatch.setattr("dnstwister.tools.resolve", lambda domain: ("999.999.999.999", False))
    emailer = patches.NoEmailer()
    monkeypatch.setattr("worker_email.emailer", emailer)

    repository = dnstwister.repository

    # Settings
    domain = "www.example.com"
    sub_id = "1234"
    email = "*****@*****.**"

    # We start with an unregistered domain.
    assert not repository.is_domain_registered(domain)

    # Subscribe a new user.
    repository.subscribe_email(sub_id, email, domain)

    # Subscribing a user does not register the domain.
    assert not repository.is_domain_registered(domain)

    # Process the subscription.
    sub_data = repository.db.data["email_sub:{}".format(sub_id)]
    worker_email.process_sub(sub_id, sub_data)

    # We won't have sent any emails.
    assert emailer.sent_emails == []

    # But the domain is now registered for delta reporting.
    assert repository.is_domain_registered(domain)

    # So let's do a delta report.
    worker_deltas.process_domain(domain)

    # Process the subscription again.
    sub_data = repository.db.data["email_sub:{}".format(sub_id)]
    worker_email.process_sub(sub_id, sub_data)

    # And we've sent an email.
    assert len(emailer.sent_emails) == 1

    # Now we "let" a bit over 24 hours pass since the email was sent and the
    # report was updated.
    passed_time = datetime.timedelta(hours=24, minutes=1)
    repository.update_last_email_sub_sent_date(sub_id, datetime.datetime.now() - passed_time)
    delta_report = repository.get_delta_report(domain)
    repository.update_delta_report(domain, delta_report, datetime.datetime.now() - passed_time)

    # Now we run the email worker for the sub *before* the delta report.
    worker_email.process_sub(sub_id, sub_data)

    # We've not sent an extra email because it's more than 23 hours since the
    # last delta report.
    assert len(emailer.sent_emails) == 1

    # As soon as the delta report is ran again we can send another email.
    monkeypatch.setattr("dnstwister.tools.resolve", lambda domain: ("999.999.999.222", False))
    worker_deltas.process_domain(domain)
    worker_email.process_sub(sub_id, sub_data)
    assert len(emailer.sent_emails) == 2

    # And the emails are different.
    assert emailer.sent_emails[0] != emailer.sent_emails[1]