|
55 | 55 | MAX_EVENTS = 50 |
56 | 56 | MAX_LOG_LINES = 1000 |
57 | 57 |
|
58 | | -# Environment variable configuration (set by xbar) |
59 | | -SHOW_NOTIFICATIONS = os.environ.get("SHOW_NOTIFICATIONS", "true").lower() == "true" |
60 | | -MONITOR_SSH = os.environ.get("MONITOR_SSH", "true").lower() == "true" |
61 | | -MONITOR_SUDO = os.environ.get("MONITOR_SUDO", "true").lower() == "true" |
62 | | -MONITOR_PORTSCAN = os.environ.get("MONITOR_PORTSCAN", "true").lower() == "true" |
63 | | -MONITOR_VNC = os.environ.get("MONITOR_VNC", "true").lower() == "true" |
64 | | -MONITOR_PORTS = os.environ.get("MONITOR_PORTS", "true").lower() == "true" |
| 58 | +# Monitor toggle management |
| 59 | +def get_monitor_overrides() -> Dict[str, bool]: |
| 60 | + """Load monitor toggle overrides from state file.""" |
| 61 | + STATE_DIR.mkdir(parents=True, exist_ok=True) |
| 62 | + overrides_file = STATE_DIR / "monitor_overrides.json" |
| 63 | + if overrides_file.exists(): |
| 64 | + try: |
| 65 | + with open(overrides_file, "r") as f: |
| 66 | + return json.load(f) |
| 67 | + except (json.JSONDecodeError, IOError): |
| 68 | + pass |
| 69 | + return {} |
| 70 | + |
| 71 | +def toggle_monitor(monitor_name: str) -> None: |
| 72 | + """Toggle a monitor on/off by storing override in state.""" |
| 73 | + STATE_DIR.mkdir(parents=True, exist_ok=True) |
| 74 | + overrides_file = STATE_DIR / "monitor_overrides.json" |
| 75 | + |
| 76 | + # Load current overrides |
| 77 | + overrides = get_monitor_overrides() |
| 78 | + |
| 79 | + # Get current effective state (env var default, then override) |
| 80 | + env_default = os.environ.get(monitor_name, "true").lower() == "true" |
| 81 | + current_state = overrides.get(monitor_name, env_default) |
| 82 | + |
| 83 | + # Toggle it |
| 84 | + overrides[monitor_name] = not current_state |
| 85 | + |
| 86 | + # Save |
| 87 | + with open(overrides_file, "w") as f: |
| 88 | + json.dump(overrides, f, indent=2) |
| 89 | + |
| 90 | +def is_monitor_enabled(monitor_name: str, env_default: str = "true") -> bool: |
| 91 | + """Check if a monitor is enabled, considering both env vars and overrides.""" |
| 92 | + env_value = os.environ.get(monitor_name, env_default).lower() == "true" |
| 93 | + overrides = get_monitor_overrides() |
| 94 | + return overrides.get(monitor_name, env_value) |
| 95 | + |
| 96 | +# Environment variable configuration (set by xbar, can be overridden by user toggles) |
| 97 | +SHOW_NOTIFICATIONS = is_monitor_enabled("SHOW_NOTIFICATIONS") |
| 98 | +MONITOR_SSH = is_monitor_enabled("MONITOR_SSH") |
| 99 | +MONITOR_SUDO = is_monitor_enabled("MONITOR_SUDO") |
| 100 | +MONITOR_PORTSCAN = is_monitor_enabled("MONITOR_PORTSCAN") |
| 101 | +MONITOR_VNC = is_monitor_enabled("MONITOR_VNC") |
| 102 | +MONITOR_PORTS = is_monitor_enabled("MONITOR_PORTS") |
65 | 103 | MONITORED_PORTS = os.environ.get("MONITORED_PORTS", "21,445,548,3306,3689,5432") |
66 | | -MONITOR_LISTENING = os.environ.get("MONITOR_LISTENING", "true").lower() == "true" |
67 | | -MONITOR_DOTENV = os.environ.get("MONITOR_DOTENV", "true").lower() == "true" |
68 | | -MONITOR_DANGEROUS_COMMANDS = os.environ.get("MONITOR_DANGEROUS_COMMANDS", "true").lower() == "true" |
69 | | -MONITOR_DNS = os.environ.get("MONITOR_DNS", "true").lower() == "true" |
70 | | -MONITOR_PUBLIC_IP = os.environ.get("MONITOR_PUBLIC_IP", "true").lower() == "true" |
71 | | -MONITOR_LOCAL_IP = os.environ.get("MONITOR_LOCAL_IP", "true").lower() == "true" |
72 | | -MONITOR_MDM = os.environ.get("MONITOR_MDM", "true").lower() == "true" |
73 | | -MONITOR_ARP_SPOOF = os.environ.get("MONITOR_ARP_SPOOF", "true").lower() == "true" |
| 104 | +MONITOR_LISTENING = is_monitor_enabled("MONITOR_LISTENING") |
| 105 | +MONITOR_DOTENV = is_monitor_enabled("MONITOR_DOTENV") |
| 106 | +MONITOR_DANGEROUS_COMMANDS = is_monitor_enabled("MONITOR_DANGEROUS_COMMANDS") |
| 107 | +MONITOR_DNS = is_monitor_enabled("MONITOR_DNS") |
| 108 | +MONITOR_PUBLIC_IP = is_monitor_enabled("MONITOR_PUBLIC_IP") |
| 109 | +MONITOR_LOCAL_IP = is_monitor_enabled("MONITOR_LOCAL_IP") |
| 110 | +MONITOR_MDM = is_monitor_enabled("MONITOR_MDM") |
| 111 | +MONITOR_ARP_SPOOF = is_monitor_enabled("MONITOR_ARP_SPOOF") |
74 | 112 |
|
75 | 113 | # Listening port range to monitor |
76 | 114 | LISTENING_PORT_MIN = 21 |
@@ -1575,43 +1613,34 @@ def format_xbar_output(state: Dict[str, Any], new_events: List[Tuple[str, str, s |
1575 | 1613 | print(f"Last check: {datetime.now().strftime('%H:%M:%S')} | color=#666666 size=11") |
1576 | 1614 | print("---") |
1577 | 1615 |
|
1578 | | - # Active monitors |
| 1616 | + # Active monitors - clickable to toggle |
1579 | 1617 | print("Active Monitors | color=#333333") |
1580 | | - monitors = [] |
1581 | | - if MONITOR_SSH: |
1582 | | - monitors.append("SSH") |
1583 | | - if MONITOR_SUDO: |
1584 | | - monitors.append("Sudo") |
1585 | | - if MONITOR_PORTSCAN: |
1586 | | - monitors.append("Port Scans") |
1587 | | - if MONITOR_VNC: |
1588 | | - monitors.append("VNC") |
1589 | | - if MONITOR_PORTS: |
1590 | | - port_list = ", ".join(str(p) for p in PORTS_TO_MONITOR[:3]) |
1591 | | - if len(PORTS_TO_MONITOR) > 3: |
1592 | | - port_list += f" (+{len(PORTS_TO_MONITOR) - 3})" |
1593 | | - monitors.append(f"Ports: {port_list}") |
1594 | | - if MONITOR_LISTENING: |
1595 | | - monitors.append(f"Listening ({LISTENING_PORT_MIN}-{LISTENING_PORT_MAX})") |
1596 | | - if MONITOR_DOTENV: |
1597 | | - monitors.append(".env Files") |
1598 | | - if MONITOR_DANGEROUS_COMMANDS: |
1599 | | - monitors.append(f"Commands: {', '.join(DANGEROUS_COMMANDS)}") |
1600 | | - if MONITOR_DNS: |
1601 | | - monitors.append("DNS Resolvers") |
1602 | | - if MONITOR_PUBLIC_IP: |
1603 | | - public_ip = state.get("known_public_ip", "?") |
1604 | | - monitors.append(f"Public IP ({public_ip})") |
1605 | | - if MONITOR_LOCAL_IP: |
1606 | | - monitors.append("Local IPs") |
1607 | | - if MONITOR_MDM: |
1608 | | - monitors.append("Kandji/MDM") |
1609 | | - if MONITOR_ARP_SPOOF: |
1610 | | - gateway_mac = state.get("known_gateway_mac", "?")[:8] if state.get("known_gateway_mac") else "?" |
1611 | | - monitors.append(f"ARP Spoofing (GW: {gateway_mac}...)") |
1612 | | - |
1613 | | - for m in monitors: |
1614 | | - print(f"--✓ {m} | color=#228B22 size=12") |
| 1618 | + script_path = os.path.abspath(__file__) |
| 1619 | + |
| 1620 | + # Define all monitors with their display names and environment variable names |
| 1621 | + monitor_configs = [ |
| 1622 | + ("MONITOR_SSH", MONITOR_SSH, "SSH"), |
| 1623 | + ("MONITOR_SUDO", MONITOR_SUDO, "Sudo"), |
| 1624 | + ("MONITOR_PORTSCAN", MONITOR_PORTSCAN, "Port Scans"), |
| 1625 | + ("MONITOR_VNC", MONITOR_VNC, "VNC"), |
| 1626 | + ("MONITOR_PORTS", MONITOR_PORTS, f"Ports: {', '.join(str(p) for p in PORTS_TO_MONITOR[:3])}{f' (+{len(PORTS_TO_MONITOR) - 3})' if len(PORTS_TO_MONITOR) > 3 else ''}"), |
| 1627 | + ("MONITOR_LISTENING", MONITOR_LISTENING, f"Listening ({LISTENING_PORT_MIN}-{LISTENING_PORT_MAX})"), |
| 1628 | + ("MONITOR_DOTENV", MONITOR_DOTENV, ".env Files"), |
| 1629 | + ("MONITOR_DANGEROUS_COMMANDS", MONITOR_DANGEROUS_COMMANDS, f"Commands: {', '.join(DANGEROUS_COMMANDS)}"), |
| 1630 | + ("MONITOR_DNS", MONITOR_DNS, "DNS Resolvers"), |
| 1631 | + ("MONITOR_PUBLIC_IP", MONITOR_PUBLIC_IP, f"Public IP ({state.get('known_public_ip', '?')})"), |
| 1632 | + ("MONITOR_LOCAL_IP", MONITOR_LOCAL_IP, "Local IPs"), |
| 1633 | + ("MONITOR_MDM", MONITOR_MDM, "Kandji/MDM"), |
| 1634 | + ("MONITOR_ARP_SPOOF", MONITOR_ARP_SPOOF, f"ARP Spoofing (GW: {state.get('known_gateway_mac', '?')[:8] if state.get('known_gateway_mac') else '?'}...)"), |
| 1635 | + ] |
| 1636 | + |
| 1637 | + for var_name, is_enabled, display_name in monitor_configs: |
| 1638 | + if is_enabled: |
| 1639 | + # Show enabled monitors with checkmark - clickable to disable |
| 1640 | + print(f"--✓ {display_name} | color=#228B22 size=12 bash={script_path} param1=toggle param2={var_name} terminal=false refresh=true") |
| 1641 | + else: |
| 1642 | + # Show disabled monitors with gray text - clickable to enable |
| 1643 | + print(f"--○ {display_name} | color=#999999 size=12 bash={script_path} param1=toggle param2={var_name} terminal=false refresh=true") |
1615 | 1644 |
|
1616 | 1645 | print("---") |
1617 | 1646 |
|
@@ -1669,6 +1698,13 @@ def format_xbar_output(state: Dict[str, Any], new_events: List[Tuple[str, str, s |
1669 | 1698 |
|
1670 | 1699 | def main(): |
1671 | 1700 | """Main entry point for the xbar plugin.""" |
| 1701 | + # Check if we're being called to toggle a monitor |
| 1702 | + if len(sys.argv) > 1 and sys.argv[1] == "toggle": |
| 1703 | + if len(sys.argv) > 2: |
| 1704 | + monitor_name = sys.argv[2] |
| 1705 | + toggle_monitor(monitor_name) |
| 1706 | + sys.exit(0) |
| 1707 | + |
1672 | 1708 | try: |
1673 | 1709 | # Load state |
1674 | 1710 | state = load_state() |
|
0 commit comments