An expansion list of labels guesses which subdomains exist; a '*' entry makes the guess unnecessary. parse_expansions now reports (labels, wildcard, rejected) instead of silently keeping junk, expand_entry keeps the base domain plus the configured labels and leaves '*.base' as a pattern when the wildcard is on, and the policy grows the 'allowed' masks the desktop resolver needs to serve exceptions.
166 lines
6.9 KiB
Python
166 lines
6.9 KiB
Python
"""Blocking policy: when it is on, and what is on the list."""
|
|
|
|
from __future__ import annotations
|
|
|
|
from app.services import blocker_service, pomodoro, settings_service
|
|
|
|
|
|
def test_disabled_blocker_blocks_nothing(session, settings):
|
|
pomodoro.start(session, settings, kind="work")
|
|
policy = blocker_service.policy(session, settings)
|
|
assert policy["active"] is False and policy["domains"] == []
|
|
|
|
|
|
def test_during_work_mode_follows_the_timer(session, settings):
|
|
settings.blocker.enabled = True
|
|
settings.blocker.blocked_domains = ["youtube.com"]
|
|
settings_service.save_settings(session, settings)
|
|
|
|
assert blocker_service.policy(session, settings)["active"] is False
|
|
|
|
pomodoro.start(session, settings, kind="work")
|
|
policy = blocker_service.policy(session, settings)
|
|
assert policy["active"] is True
|
|
assert "www.youtube.com" in policy["domains"]
|
|
|
|
pomodoro.complete(session, settings, auto_next=False)
|
|
assert blocker_service.policy(session, settings)["active"] is False
|
|
|
|
|
|
def test_breaks_do_not_block_unless_asked(session, settings):
|
|
settings.blocker.enabled = True
|
|
settings_service.save_settings(session, settings)
|
|
pomodoro.start(session, settings, kind="short_break")
|
|
assert blocker_service.policy(session, settings)["active"] is False
|
|
|
|
settings.blocker.block_during_breaks = True
|
|
settings_service.save_settings(session, settings)
|
|
assert blocker_service.policy(session, settings)["active"] is True
|
|
|
|
|
|
def test_always_mode_ignores_the_timer(session, settings):
|
|
settings.blocker.enabled = True
|
|
settings.blocker.mode = "always"
|
|
settings_service.save_settings(session, settings)
|
|
assert blocker_service.policy(session, settings)["active"] is True
|
|
|
|
|
|
def test_allowlist_wins_over_the_blocklist(session, settings):
|
|
settings.blocker.blocked_domains = ["youtube.com"]
|
|
settings.blocker.allowed_domains = ["m.youtube.com"]
|
|
hosts = blocker_service.expand_domains(settings)
|
|
assert "youtube.com" in hosts
|
|
assert "m.youtube.com" not in hosts
|
|
|
|
|
|
def test_events_are_grouped_for_the_report(session, settings):
|
|
for _ in range(3):
|
|
blocker_service.record_event(session, settings, kind="domain", target="YouTube.com")
|
|
blocker_service.record_event(session, settings, kind="app", target="steam")
|
|
summary = blocker_service.events_for_day(session, settings)
|
|
assert summary["total"] == 4
|
|
assert summary["by_target"][0] == {"target": "youtube.com", "count": 3}
|
|
|
|
|
|
def test_masked_subdomains_are_expanded(session, settings):
|
|
"""A hosts file has no wildcards, so `*.x` has to become real names."""
|
|
settings.blocker.blocked_domains = ["*.google.com"]
|
|
settings.blocker.subdomain_expansions = ["www", "mail"]
|
|
hosts = blocker_service.expand_domains(settings)
|
|
assert hosts == ["google.com", "www.google.com", "mail.google.com"]
|
|
|
|
|
|
def test_allow_masks_carve_holes_in_block_masks(session, settings):
|
|
settings.blocker.blocked_domains = ["*.google.com", "reddit.com"]
|
|
settings.blocker.subdomain_expansions = ["www", "docs"]
|
|
settings.blocker.allowed_domains = ["docs.*", "m.reddit.com"]
|
|
hosts = blocker_service.expand_domains(settings)
|
|
assert "docs.google.com" not in hosts
|
|
assert "m.reddit.com" not in hosts
|
|
assert "www.google.com" in hosts and "reddit.com" in hosts
|
|
|
|
|
|
def test_patterns_a_hosts_file_cannot_express_are_reported(session, settings):
|
|
settings.blocker.blocked_domains = ["*gram*", "youtube.com", "*.x.com"]
|
|
assert blocker_service.unexpandable_masks(settings) == ["*gram*"]
|
|
hosts = blocker_service.expand_domains(settings)
|
|
assert "youtube.com" in hosts and "x.com" in hosts
|
|
|
|
|
|
def test_app_masks_are_passed_through_untouched(session, settings):
|
|
"""Process matching happens on the desktop, where globs work directly."""
|
|
settings.blocker.enabled = True
|
|
settings.blocker.mode = "always"
|
|
settings.blocker.blocked_apps = ["steam*", "*discord*"]
|
|
settings_service.save_settings(session, settings)
|
|
policy = blocker_service.policy(session, settings)
|
|
assert policy["apps"] == ["steam*", "*discord*"]
|
|
|
|
|
|
def test_a_wildcard_means_every_subdomain(session, settings):
|
|
"""`*` in the expansion list is the user asking for all of them.
|
|
|
|
It used to be refused (it is not a DNS label), which left `*.telegram.org`
|
|
expanded to just the bare domain with a red banner beside it. Now the labels
|
|
still expand, the pattern is handed to the clients that can match masks, and
|
|
only entries that are neither a label nor `*` are refused.
|
|
"""
|
|
settings.blocker.blocked_domains = ["*.telegram.org"]
|
|
settings.blocker.subdomain_expansions = ["*", "web", "", "not a label"]
|
|
|
|
expansion = blocker_service.parse_expansions(settings.blocker.subdomain_expansions)
|
|
assert expansion.labels == ["web"]
|
|
assert expansion.wildcard is True
|
|
assert expansion.rejected == ["not a label"]
|
|
|
|
hosts = blocker_service.expand_domains(settings)
|
|
assert hosts == ["telegram.org", "web.telegram.org"]
|
|
assert not any("*" in host for host in hosts)
|
|
|
|
# The pattern comes back too: a hosts file cannot say "every subdomain", so
|
|
# the desktop app's resolver stub and the phone's URL matcher take it.
|
|
assert blocker_service.unexpandable_masks(settings) == ["*.telegram.org"]
|
|
|
|
|
|
def test_without_a_wildcard_the_pattern_stays_in_the_expansion_list(session, settings):
|
|
"""`*.x.com` alone means the configured labels, not a wildcard — nothing else."""
|
|
settings.blocker.blocked_domains = ["*.google.com"]
|
|
settings.blocker.subdomain_expansions = ["www", "mail"]
|
|
|
|
assert blocker_service.unexpandable_masks(settings) == []
|
|
assert blocker_service.expand_domains(settings) == [
|
|
"google.com",
|
|
"www.google.com",
|
|
"mail.google.com",
|
|
]
|
|
|
|
|
|
def test_the_policy_reports_expansions_it_had_to_refuse(session, settings):
|
|
settings.blocker.enabled = True
|
|
settings.blocker.mode = "always"
|
|
settings.blocker.blocked_domains = ["*.telegram.org"]
|
|
settings.blocker.subdomain_expansions = ["*", ".."]
|
|
|
|
result = blocker_service.policy(session, settings)
|
|
assert result["invalid_expansions"] == [".."]
|
|
assert result["domains"] == ["telegram.org"]
|
|
assert result["unexpandable"] == ["*.telegram.org"]
|
|
|
|
|
|
def test_the_policy_carries_the_allow_masks_for_the_stub(session, settings):
|
|
"""The desktop app answers DNS for a whole zone, so it needs the exceptions.
|
|
|
|
Without them the resolver stub would sinkhole `music.youtube.com` along with
|
|
everything else under a wildcarded domain — an exception that works over the
|
|
hosts file but not over DNS is an exception nobody will trust.
|
|
"""
|
|
settings.blocker.enabled = True
|
|
settings.blocker.mode = "always"
|
|
settings.blocker.blocked_domains = ["*.youtube.com"]
|
|
settings.blocker.allowed_domains = [" music.youtube.com ", "*.docs.google.com"]
|
|
|
|
result = blocker_service.policy(session, settings)
|
|
assert result["allowed"] == ["music.youtube.com", "*.docs.google.com"]
|
|
assert "music.youtube.com" not in result["domains"]
|
|
assert "m.youtube.com" in result["all_domains"]
|