Spaces:
Sleeping
Sleeping
| """Normalization helpers used by the evaluators. | |
| Each function is intentionally tiny and side-effect-free so the | |
| 1v1 verifier and the regular /evaluate endpoint can call the same code | |
| and stay in lock-step. | |
| """ | |
| import re | |
| def normalize_vuln_key(s: str) -> str: | |
| """Canonicalise a typed vulnerability key. | |
| Rules: | |
| - lowercase | |
| - trim | |
| - replace spaces / underscores with dashes | |
| - strip surrounding punctuation | |
| """ | |
| if not s: | |
| return "" | |
| s = s.strip().lower() | |
| s = re.sub(r"[\s_]+", "-", s) | |
| s = re.sub(r"[^a-z0-9\-]", "", s) | |
| return s | |
| def normalize_str(s: str) -> str: | |
| return (s or "").strip().lower() | |
| def ip_matches(user_ip: str, expected_ip: str) -> bool: | |
| """Loose IP match: trim, lowercase, ignore trailing port or zone id.""" | |
| u = normalize_str(user_ip).split("/")[0] | |
| e = normalize_str(expected_ip).split("/")[0] | |
| return u == e and u != "" | |
| def ioc_matches(user_ioc: str, expected_ioc: str) -> bool: | |
| """IOC match: case-insensitive substring.""" | |
| u = normalize_str(user_ioc) | |
| e = normalize_str(expected_ioc) | |
| if not u or not e: | |
| return False | |
| return e in u or u in e | |
| def timestamp_close(user_ts: str, expected_ts: str) -> bool: | |
| """Timestamp match: exact OR every alphanumeric token of the expected | |
| timestamp appears in the user input (lenient by design).""" | |
| u = normalize_str(user_ts) | |
| e = normalize_str(expected_ts) | |
| if not u or not e: | |
| return False | |
| if u == e: | |
| return True | |
| # Try day-hour match (e.g., "15/Dec" or "Mar 12" or "2024-11-08") | |
| e_tokens = re.findall(r"[a-zA-Z]+|\d+", e) | |
| if not e_tokens: | |
| return False | |
| return all(tok.lower() in u for tok in e_tokens[:2]) | |