MCPcopy Create free account
hub / github.com/Cats-Team/AdRules / RuleValidator

Class RuleValidator

script/compressor.py:61–198  ·  view source on GitHub ↗

Port of the JavaScript Validator class. Performs strict validation and cleans up invalid rules + preceding comments.

Source from the content-addressed store, hash-verified

59# --- Logic Ported from JavaScript (Validator) ---
60
61class RuleValidator:
62 """
63 Port of the JavaScript Validator class.
64 Performs strict validation and cleans up invalid rules + preceding comments.
65 """
66 def __init__(self, allow_ip: bool = False):
67 self.allow_ip = allow_ip
68 self._prev_removed = False
69
70 @staticmethod
71 def is_comment(line: str) -> bool:
72 return line.lstrip().startswith(('!', '#'))
73
74 def _valid_hostname(self, hostname: str, rule_text: str, has_limit_mod: bool) -> bool:
75 """Checks if hostname is valid. Imitates tldts logic with standard lib."""
76 hostname = hostname.strip().lower()
77
78 if not hostname:
79 return False
80
81 # IP Check
82 is_ip = bool(re.match(r"^\d{1,3}(\.\d{1,3}){3}$", hostname))
83 if is_ip and not self.allow_ip:
84 logger.debug(f"Invalid hostname (IP not allowed): {hostname} in {rule_text}")
85 return False
86
87 # Public Suffix Check (Heuristic approximation for stdlib)
88 if '.' not in hostname and not is_ip and not has_limit_mod and hostname != "localhost":
89 logger.debug(f"Matching whole TLD/Suffix not allowed: {hostname} in {rule_text}")
90 return False
91
92 return True
93
94 def _valid_etc_hosts(self, rule: str) -> bool:
95 parts = rule.split()
96 # Remove comments/IP
97 hosts = [p for p in parts if not p.startswith(('#', '!'))]
98 if len(hosts) < 2:
99 return False
100
101 hostnames = hosts[1:] # 0 is IP
102 return all(self._valid_hostname(h, rule, False) for h in hostnames)
103
104 def _valid_adblock(self, rule: str) -> bool:
105 # 1. Parse Modifiers (Simplified parser)
106 has_limit_mod = False
107 if '$' in rule:
108 try:
109 base, opts = rule.split('$', 1)
110 options = opts.split(',')
111 for opt in options:
112 name = opt.split('=', 1)[0].strip()
113 if name not in SUPPORTED_MODIFIERS:
114 logger.debug(f"Unsupported modifier {name}: {rule}")
115 return False
116 if name in ANY_PATTERN_MODIFIER:
117 has_limit_mod = True
118 except ValueError:

Callers 1

mainFunction · 0.85

Calls

no outgoing calls

Tested by

no test coverage detected