"""Shared helpers: autocomplete-token mapping, uids, loading harvested forms.""" import glob import gzip import hashlib import json AC_MAP = { "username": "username", "email": "email", "current-password": "current-password", "new-password": "new-password", "one-time-code": "one-time-code", "tel": "tel", "tel-national": "tel", "tel-local": "tel", "tel-country-code": "tel", "tel-area-code": "tel", "tel-extension": "tel", "tel-local-prefix": "tel", "tel-local-suffix": "tel", "name": "name", "given-name": "given-name", "additional-name": "given-name", "family-name": "family-name", "organization": "organization", "street-address": "street-address", "address-line1": "street-address", "address-line2": "address-line2", "address-line3": "address-line2", "address-level2": "address-level2", "address-level1": "address-level1", "postal-code": "postal-code", "country": "country", "country-name": "country", "cc-name": "cc-name", "cc-given-name": "cc-name", "cc-family-name": "cc-name", "cc-number": "cc-number", "cc-exp": "cc-exp", "cc-exp-month": "cc-exp-month", "cc-exp-year": "cc-exp-year", "cc-csc": "cc-csc", "bday": "bday", "bday-day": "bday", "bday-month": "bday", "bday-year": "bday", } AC_SKIP = {"section-", "shipping", "billing", "home", "work", "mobile", "fax", "pager", "webauthn"} def ac_label(ac: str): """Map an autocomplete attribute to a Zap field label, or None when it carries no field meaning.""" toks = [t for t in (ac or "").lower().replace('"', "").split() if t] toks = [t for t in toks if not t.startswith("section-") and t not in AC_SKIP] if len(toks) != 1: return None return AC_MAP.get(toks[0]) def uid(row) -> str: return hashlib.sha1(f"{row['url']}#{row['fidx']}".encode()).hexdigest()[:16] def load_forms(pattern): for path in sorted(glob.glob(pattern)): with gzip.open(path, "rt") as f: for line in f: row = json.loads(line) row["uid"] = uid(row) yield row