feat: add persistence and audit trails
This commit is contained in:
1 parent
d381c02946
commit
2f2e9ab3e3
9 files changed
+633
-151
No files matched your search
@@ -0,0 +1,84 @@
|
||||
from __future__ import annotations
|
||||
|
||||
import json
|
||||
import os
|
||||
from pathlib import Path
|
||||
from typing import Iterable, Sequence
|
||||
|
||||
DEFAULT_BLOCKED_PORTS = frozenset({22, 23, 2375, 2376, 2377, 6443, 2377, 9000})
|
||||
|
||||
|
||||
class TunnelPolicy:
|
||||
def __init__(self, whitelist: frozenset[int] | None, blocklist: frozenset[int]) -> None:
|
||||
self.whitelist = whitelist
|
||||
self.blocklist = blocklist
|
||||
|
||||
@classmethod
|
||||
def load(cls) -> "TunnelPolicy":
|
||||
whitelist_inputs: list[int] = []
|
||||
blocklist_inputs: list[int] = []
|
||||
|
||||
env_whitelist = os.environ.get("TUNNEL_WHITELIST")
|
||||
if env_whitelist:
|
||||
whitelist_inputs.extend(_parse_port_sequence(env_whitelist))
|
||||
|
||||
env_blocklist = os.environ.get("TUNNEL_BLOCKLIST")
|
||||
if env_blocklist:
|
||||
blocklist_inputs.extend(_parse_port_sequence(env_blocklist))
|
||||
|
||||
whitelist_file = os.environ.get("TUNNEL_WHITELIST_FILE")
|
||||
if whitelist_file:
|
||||
whitelist_inputs.extend(_load_ports_from_file(whitelist_file, "whitelist"))
|
||||
|
||||
blocklist_file = os.environ.get("TUNNEL_BLOCKLIST_FILE")
|
||||
if blocklist_file:
|
||||
blocklist_inputs.extend(_load_ports_from_file(blocklist_file, "blocklist"))
|
||||
|
||||
whitelist = frozenset(whitelist_inputs) if whitelist_inputs else None
|
||||
blocklist = frozenset(blocklist_inputs) or DEFAULT_BLOCKED_PORTS
|
||||
return cls(whitelist=whitelist, blocklist=blocklist)
|
||||
|
||||
def is_port_allowed(self, port: int) -> tuple[bool, str | None]:
|
||||
if port in self.blocklist:
|
||||
return False, f"Porta {port} in lista sensibile/protetta"
|
||||
if self.whitelist is not None and port not in self.whitelist:
|
||||
return False, f"Porta {port} non presente nella whitelist"
|
||||
return True, None
|
||||
|
||||
|
||||
def _parse_port_sequence(value: str) -> Sequence[int]:
|
||||
cleaned = [item.strip() for item in value.replace(";", ",").split(",") if item.strip()]
|
||||
ports: list[int] = []
|
||||
for bit in cleaned:
|
||||
try:
|
||||
ports.append(int(bit, 10))
|
||||
except ValueError:
|
||||
continue
|
||||
return ports
|
||||
|
||||
|
||||
def _load_ports_from_file(path: str, key: str) -> Sequence[int]:
|
||||
try:
|
||||
raw = Path(path).read_text(encoding="utf-8")
|
||||
except OSError:
|
||||
return []
|
||||
try:
|
||||
parsed = json.loads(raw)
|
||||
except json.JSONDecodeError:
|
||||
return []
|
||||
if isinstance(parsed, dict):
|
||||
target = parsed.get(key)
|
||||
return _normalize_numeric_sequence(target)
|
||||
return _normalize_numeric_sequence(parsed)
|
||||
|
||||
|
||||
def _normalize_numeric_sequence(value: Iterable | None) -> Sequence[int]:
|
||||
if not value:
|
||||
return []
|
||||
ports: list[int] = []
|
||||
for entry in value:
|
||||
try:
|
||||
ports.append(int(entry))
|
||||
except (TypeError, ValueError):
|
||||
continue
|
||||
return ports
|
||||
Reference in new issue
Block a user