| """Code related to blocklists."""
|
| from dataclasses import dataclass
|
| import requests
|
| import logging
|
|
|
| logger = logging.getLogger(__name__)
|
|
|
|
|
| @dataclass
|
| class BlocklistData:
|
| """Dataclass for online blocklist requests, including usernames and etag."""
|
|
|
| users: list[str]
|
| etag: str | None
|
|
|
|
|
| def _parse_block_list_from_url(url: str, old_data: BlocklistData) -> BlocklistData:
|
| headers = {"If-None-Match": old_data.etag} if old_data.etag else {}
|
| response = requests.get(url, headers=headers, timeout=15)
|
|
|
| response.raise_for_status()
|
|
|
| if response.status_code == 304:
|
| return old_data
|
|
|
| block_list = [username for line in response.text.strip().splitlines() if (username := line.strip())]
|
|
|
| return BlocklistData(block_list, response.headers.get("ETag"))
|
|
|
|
|
| class OnlineBlocklist:
|
| """Manage online blocklists."""
|
|
|
| def __init__(self, urls: list[str]) -> None:
|
| """Initialize the OnlineBlockList class."""
|
| self.blocklist: dict[str, BlocklistData] = {url : BlocklistData([], None) for url in urls}
|
| self.refresh()
|
|
|
| def refresh(self) -> None:
|
| """Pull updated blocklists from the list of blocklist urls."""
|
| logger.info(f"Refreshing {len(self.blocklist)} online blocklists")
|
|
|
| for url, data in self.blocklist.items():
|
| try:
|
| self.blocklist[url] = _parse_block_list_from_url(url, data)
|
| except Exception:
|
| logger.warning(f"Failed to refresh online blocklist {url}")
|
|
|
| def __contains__(self, item: str) -> bool:
|
| """Check if an username is in the blocklist."""
|
| return any(item in blocklist.users for blocklist in self.blocklist.values())
|
|
|