diff --git a/.config/eww/modules/network.yuck##hostname.normandy b/.config/eww/modules/network.yuck##hostname.normandy new file mode 100644 index 0000000..cf95775 --- /dev/null +++ b/.config/eww/modules/network.yuck##hostname.normandy @@ -0,0 +1,194 @@ +(deflisten network--data + `~/.config/eww/modules/network/network.py`) + +(defwidget network--wlan [device] + (box :orientation "h" + :halign "start" + :space-evenly false + :spacing 0 + (label :class "offline" + :visible {network--data["network"][device]["offline"]} + :text "offline") + (label :visible {network--data["network"][device]["connecting"]} + :class "highlight" + :text "connecting...") + (label :visible {network--data["network"][device]["online"]} + :class "special" + :text "${network--data['wifi']['ssid']}"))) + +(defwidget network--lan [device] + (box :orientation "h" + :halign "start" + :space-evenly false + :spacing 0 + (label :class "offline" + :visible {network--data["network"][device]["offline"]} + :text "offline") + (label :visible {network--data["network"][device]["connecting"]} + :class "highlight" + :text "connecting...") + (label :visible {network--data["network"][device]["online"] && !network--data.network[device].connecting} + :class "special" + :text "${network--data['network'][device]['ip4_addr']}/${network--data['network'][device]['ip4_prefix']}"))) + +(defwidget network--proxy-vpn [device ?required] + (box :orientation "h" + :halign "start" + :space-evenly false + :spacing 0 + :visible {network--data["network"][device]["exists"] || required} + (label :class "highlight" + :text "- insecure" + :visible {! network--data["network"][device]["exists"]}) + (label :class "green" + :text "- secured" + :visible {network--data["network"][device]["exists"]}))) + +(defwidget proxy-network [device] + (box :orientation "v" + :halign "start" + :space-evenly false + :spacing 0 + (label :class "green" + :text "connected" + :visible {network--data.network[device].exists}) + (label :class "offline" + :text "offline" + :visible {!network--data.network[device].exists}) + "proxy vpn")) + +(defwidget vpn-network [] + (box :orientation "v" + :halign "start" + :space-evenly false + :spacing 0 + (label :class "highlight" + :text "offline" + :visible {! network--data["network"]["ezrinet"]["exists"] || ! network--data["connected"]}) + (label :class "green" + :text "connected" + :visible {network--data["network"]["ezrinet"]["exists"] && network--data["connected"]}) + "personal network")) + +(defwidget network [] + (box :orientation "v" + :halign "start" + :space-evenly false + :spacing 0 + (box :orientation "h" + :halign "center" + :space-evenly false + :spacing 10 + (network--lan :device "insight") + (network--proxy-vpn :device "wg-mullvad" :required {!network--data.trusted})) + "communications")) + +(defwidget network-details [] + (box :orientation "v" + :halign "start" + :class "module" + :space-evenly false + :spacing 5 + :width 200 + (box :orientation "h" + :halign "center" + :class "nebula" + :spacing 10 + :space-evenly false + (label :text "Comms" + :class "medium special")) + (centerbox :orientation "h" + :halign "start" + :class "nebula" + :spacing 10 + :width 200 + :space-evenly false + (box :halign "start" + "Status:") + "" + (box :halign "end" + (label :text "Online" + :class "green" + :visible {network--data.connected}) + (label :text "Offline" + :class "highlight" + :visible {!network--data.connected}))) + (centerbox :orientation "h" + :halign "start" + :class "nebula" + :spacing 10 + :width 200 + :space-evenly false + (box :halign "start" + "VPN:") + "" + (box :halign "end" + (label :text "Connected" + :class "green" + :visible {network--data.network.ezrinet.online && network--data.connected}) + (label :text "Offline" + :class "highlight" + :visible {!network--data.network.ezrinet.exists}))) + (centerbox :orientation "h" + :halign "start" + :class "nebula" + :spacing 10 + :width 200 + :space-evenly false + (box :halign "start" + "Proxy:") + "" + (box :halign "end" + (label :text "Connected" + :class "green" + :visible {network--data.network.wg-mullvad.online}) + (label :text "Offline" + :class "highlight" + :visible {!network--data.network.wg-mullvad.exists}))) + (centerbox :orientation "h" + :halign "start" + :class "nebula" + :spacing 10 + :width 200 + :space-evenly false + (box :halign "start" + "Wi-Fi:") + "" + (box :halign "end" + (label :text {network--data.wifi.ssid} + :limit-width 12 + :class "green" + :visible {network--data.wifi.connected}) + (label :text "Offline" + :class "offline" + :visible {!network--data.wifi.connected}))) + (centerbox :orientation "h" + :halign "start" + :spacing 10 + :width 200 + :class "nebula" + :space-evenly false + (box :valign "start" + :halign "start" + "Addrs:") + "" + (box :valign "start" + :halign "end" + :visible {network--data.connected} + :orientation "v" + (for addr in {network--data.ip4_addrs} + (box :class "special" + :halign "end" + {addr})) + (box :visible {!network--data.connected} + :class "offline" + "none"))) + ;; (box :orientation "h" + ;; :halign "start" + ;; :class "nebula" + ;; :spacing 10 + ;; :space-evenly false + ;; (label :text "Addr:") + ;; (label :text {network--data.network[device].ip4_addr} + ;; :class "medium special")))) + )) diff --git a/.config/eww/scripts/network.py##hostname.normandy b/.config/eww/scripts/network.py##hostname.normandy new file mode 100644 index 0000000..4b71007 --- /dev/null +++ b/.config/eww/scripts/network.py##hostname.normandy @@ -0,0 +1,64 @@ +#!/usr/bin/env python3 + +import subprocess +import json +import sys +from time import sleep + +TRUSTED_NETWORKS = ['honnouji', 'honnouji_2.4'] + +def wifi(): + ssid_cmd = subprocess.run(['iwgetid', '-r'], capture_output = True) + if ssid_cmd.returncode != 0: + return {"connected": False, "ssid": None} + return {"connected": True, "ssid": ssid_cmd.stdout.decode('utf-8').strip()} + +def netdev(device: str): + ip_cmd = subprocess.run(['ip', '-j', 'addr', 'show', device], capture_output = True) + if ip_cmd.returncode != 0: + sys.stderr.write(ip_cmd.stdout.decode('utf-8')) + return {"exists": False, "online": False} + ip_data = json.loads(ip_cmd.stdout.decode('utf-8'))[0] + ip4_addr = "" + ip4_prefix_length = 24 + addr4_info = list(filter(lambda addr: addr.get("family") == "inet", ip_data["addr_info"])) + if len(addr4_info) >= 1: + ip4_addr = addr4_info[0]["local"] + ip4_prefix_length = addr4_info[0]["prefixlen"] + online = ip_data["operstate"] == "UP" or ip4_addr != "" + connecting = ip_data["operstate"] != "DOWN" and (ip4_addr == "" or not online) + return { + "exists": True, + "online": online, + "connecting": connecting, + "offline": not online and not connecting, + "ip4_addr": ip4_addr, + "ip4_prefix": ip4_prefix_length + } + +def trusted(ssid: str | None): + # Don't throw up an "INSECURE" alert when offline + if not ssid: + return True + return ssid in TRUSTED_NETWORKS + +while True: + insight = netdev('insight') + wlan0 = netdev('wlan0') + wifi_data = wifi() + connected = insight['exists'] and insight['online'] or wifi_data['connected'] + networks = { + "insight": insight, + "wlan0": netdev("wlan0"), + "ezrinet": netdev("ezrinet"), + "wg-mullvad": netdev("wg-mullvad"), + } + result = { + 'connected': connected, + "network": networks, + 'wifi': wifi_data, + "trusted": True, + "ip4_addrs": [ network.get('ip4_addr') for network in networks.values() if network.get('ip4_addr', "") != "" ] + } + print(json.dumps(result), flush=True) + sleep(1)