* Extract the Wi-Fi QR share card into its own omarchy.wifiqr panel plugin omarchy-network-qr now leads with an iface/security/ssid meta line, so a bare summon self-detects the connection and the plugin owns the whole share flow. The network panel loses its overlay lifecycle: with no centered card left inside it, the shadowed open/close collapses back to the stock panel behavior, and the QR button just summons the plugin -- which a clone or third-party plugin can replace, like the speed test. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com> * Keep canceled QR and password runs from leaking into their replacements Copilot review: the cancellation guards dropped in onExited while the canceled run's collectors were still allowed to fire, so a stale stderr could shadow a successful regeneration and a stale password could be revealed under a new network's card. The guards now stay up until the next run launches, good output settles any earlier error, and a bare re-summon no longer inherits the previous card's SSID. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com> --------- Co-authored-by: Claude Fable 5 <noreply@anthropic.com>
96 lines
3.5 KiB
Bash
Executable File
96 lines
3.5 KiB
Bash
Executable File
#!/bin/bash
|
|
|
|
# omarchy:summary=Generate a Wi-Fi QR matrix for the shell
|
|
# omarchy:group=network
|
|
# omarchy:args=[--meta] [interface]
|
|
|
|
set -euo pipefail
|
|
|
|
# --meta is opt-in so pre-existing consumers of the bare matrix (cloned
|
|
# network widgets from before the share card became its own plugin) keep
|
|
# parsing this output.
|
|
interface=""
|
|
emit_meta=false
|
|
for arg in "$@"; do
|
|
case "$arg" in
|
|
--meta) emit_meta=true ;;
|
|
*) interface=$arg ;;
|
|
esac
|
|
done
|
|
if [[ -z $interface ]]; then
|
|
# Prefer the default-route device: it is the connection the panel and the
|
|
# menu's visibility gate describe. Fall back to the first connected Wi-Fi
|
|
# device. nmcli localizes state names, so pin the locale, and the prefix
|
|
# match accepts states like "connected (externally)".
|
|
route_device=$(ip route get 1.1.1.1 2>/dev/null | awk '{ for (i = 1; i <= NF; i++) if ($i == "dev") { print $(i + 1); exit } }')
|
|
if [[ -n $route_device && -d /sys/class/net/$route_device/wireless ]]; then
|
|
interface=$route_device
|
|
else
|
|
interface=$(LC_ALL=C nmcli -t -f DEVICE,TYPE,STATE device status 2>/dev/null |
|
|
awk -F: '$2 == "wifi" && $3 ~ /^connected/ { print $1; exit }')
|
|
fi
|
|
fi
|
|
[[ -n $interface ]] || { echo "No active Wi-Fi connection" >&2; exit 1; }
|
|
uuid=$(nmcli --get-values GENERAL.CON-UUID device show "$interface" | head -n 1)
|
|
[[ -n $uuid && $uuid != "--" ]] || { echo "No active Wi-Fi connection" >&2; exit 1; }
|
|
|
|
mapfile -t fields < <(nmcli --show-secrets --escape no --get-values \
|
|
802-11-wireless.ssid,802-11-wireless-security.key-mgmt,802-11-wireless-security.psk,802-11-wireless.hidden,802-11-wireless-security.wep-key0 \
|
|
connection show uuid "$uuid")
|
|
|
|
ssid=${fields[0]:-}
|
|
key_management=${fields[1]:-}
|
|
password=${fields[2]:-}
|
|
hidden=${fields[3]:-no}
|
|
wep_key=${fields[4]:-}
|
|
|
|
[[ -n $ssid ]] || { echo "Could not read the Wi-Fi name" >&2; exit 1; }
|
|
[[ $key_management != *eap* && $key_management != *ieee8021x* ]] || {
|
|
echo "Enterprise Wi-Fi cannot be shared with a password QR code" >&2
|
|
exit 1
|
|
}
|
|
|
|
escape_wifi_qr() {
|
|
local value=$1
|
|
value=${value//\\/\\\\}
|
|
value=${value//;/\\;}
|
|
value=${value//,/\\,}
|
|
value=${value//:/\\:}
|
|
printf '%s' "$value"
|
|
}
|
|
|
|
if [[ -n $key_management && $key_management != "none" ]]; then
|
|
[[ -n $password ]] || { echo "Could not read the Wi-Fi password" >&2; exit 1; }
|
|
security=WPA
|
|
elif [[ -n $wep_key ]]; then
|
|
# NetworkManager models WEP as key-mgmt "none" plus a wep-key; encoding it
|
|
# as an open network would produce a QR that silently fails to join.
|
|
password=$wep_key
|
|
security=WEP
|
|
else
|
|
security=nopass
|
|
fi
|
|
|
|
payload="WIFI:T:$security;S:$(escape_wifi_qr "$ssid");P:$(escape_wifi_qr "$password");"
|
|
[[ $hidden == "yes" ]] && payload+="H:true;"
|
|
payload+=";"
|
|
|
|
# Metadata header ahead of the matrix: the interface that was shared, the
|
|
# security type, and the SSID last so it may contain tabs. The share card
|
|
# renders its title and password row from this line, and a self-detected
|
|
# summon learns which interface to fetch the password for.
|
|
[[ $emit_meta == "true" ]] && printf 'meta\t%s\t%s\t%s\n' "$interface" "$security" "$ssid"
|
|
|
|
# ASCII uses two characters per module. Collapse each pair to one 0/1 value
|
|
# so the shell can render a square matrix directly with native QML rectangles.
|
|
# Margin 4 is the spec quiet zone; the card surround is dark, so this white
|
|
# border is all the scanner gets.
|
|
ascii=$(printf '%s' "$payload" | qrencode --type ASCII --margin 4 --output -)
|
|
while IFS= read -r line; do
|
|
row=
|
|
for ((column = 0; column < ${#line}; column += 2)); do
|
|
[[ ${line:column:2} == *#* ]] && row+=1 || row+=0
|
|
done
|
|
printf '%s\n' "$row"
|
|
done <<<"$ascii"
|