|
# Uses the inline script metadata Python Enhancment Proposal (PEP 723) |
|
# To install UV: https://docs.astral.sh/uv/getting-started/installation/ |
|
# To run with UV: uv run share_my_wifi_qr_code.py |
|
|
|
# /// script |
|
# requires-python = ">=3.12" |
|
# dependencies = ["qrcode-terminal"] |
|
# /// |
|
|
|
import shutil |
|
import subprocess |
|
import sys |
|
import qrcode_terminal |
|
|
|
|
|
def run(command: list[str]) -> str: |
|
process = subprocess.run(command, stdout=subprocess.PIPE, stderr=subprocess.DEVNULL, text=True) |
|
if process.returncode != 0: |
|
return "" |
|
return process.stdout.strip() |
|
|
|
|
|
def escape(text: str) -> str: |
|
text = text.replace("\\", "\\\\") |
|
text = text.replace(";", "\\;") |
|
text = text.replace(",", "\\,") |
|
text = text.replace(":", "\\:") |
|
text = text.replace('"', '\\"') |
|
return text |
|
|
|
|
|
if shutil.which("nmcli") is None: |
|
print("Missing 'nmcli'. This needs NetworkManager.") |
|
sys.exit(1) |
|
|
|
wifi_device = "" |
|
for line in run(["nmcli", "-t", "-f", "DEVICE,TYPE,STATE", "dev"]).splitlines(): |
|
parts = line.split(":") |
|
if len(parts) >= 3 and parts[1] == "wifi" and parts[2] == "connected": |
|
wifi_device = parts[0] |
|
break |
|
if not wifi_device: |
|
print("No connected Wi-Fi device found.") |
|
sys.exit(1) |
|
|
|
connection_name = "" |
|
for line in run(["nmcli", "-t", "-f", "NAME,DEVICE", "connection", "show", "--active"]).splitlines(): |
|
parts = line.split(":") |
|
if len(parts) == 2 and parts[1] == wifi_device: |
|
connection_name = parts[0] |
|
break |
|
if not connection_name: |
|
print("No active Wi-Fi connection profile found.") |
|
sys.exit(1) |
|
|
|
ssid = run(["nmcli", "-t", "-f", "802-11-wireless.ssid", "connection", "show", connection_name]) |
|
if not ssid: |
|
for line in run(["nmcli", "-t", "-f", "active,ssid", "dev", "wifi"]).splitlines(): |
|
parts = line.split(":") |
|
if len(parts) == 2 and parts[0] == "yes": |
|
ssid = parts[1] |
|
break |
|
if not ssid: |
|
print("Could not determine SSID.") |
|
sys.exit(1) |
|
|
|
security_key_management = run( |
|
["nmcli", "-t", "-f", "802-11-wireless-security.key-mgmt", "connection", "show", connection_name] |
|
) |
|
enterprise_eap = run(["nmcli", "-t", "-f", "802-1x.eap", "connection", "show", connection_name]) |
|
hidden_setting = run(["nmcli", "-t", "-f", "802-11-wireless.hidden", "connection", "show", connection_name]) |
|
|
|
passphrase_psk = run( |
|
["nmcli", "-s", "--show-secrets", "-g", "802-11-wireless-security.psk", "connection", "show", connection_name] |
|
) |
|
passphrase_wep = run( |
|
["nmcli", "-s", "--show-secrets", "-g", "802-11-wireless-security.wep-key0", "connection", "show", connection_name] |
|
) |
|
|
|
if enterprise_eap: |
|
print("Enterprise EAP network. Phone QR join is usually not supported.") |
|
sys.exit(1) |
|
|
|
ssid_escaped = escape(ssid) |
|
hidden_flag = "" |
|
if hidden_setting.strip().lower() == "yes": |
|
hidden_flag = ";H:true" |
|
|
|
wifi_payload = "" |
|
display_password = None # type: str | None |
|
|
|
if passphrase_psk: |
|
display_password = passphrase_psk |
|
wifi_payload = f"WIFI:T:WPA;S:{ssid_escaped};P:{escape(passphrase_psk)}{hidden_flag};;" |
|
|
|
if wifi_payload == "" and passphrase_wep: |
|
display_password = passphrase_wep |
|
wifi_payload = f"WIFI:T:WEP;S:{ssid_escaped};P:{escape(passphrase_wep)}{hidden_flag};;" |
|
|
|
if wifi_payload == "" and not security_key_management: |
|
display_password = "" |
|
wifi_payload = f"WIFI:T:nopass;S:{ssid_escaped}{hidden_flag};;" |
|
|
|
if wifi_payload == "": |
|
wifi_payload = f"WIFI:T:WPA;S:{ssid_escaped}{hidden_flag};;" |
|
|
|
print(f"\nScan to join: {ssid}") |
|
|
|
if display_password is None: |
|
print("Password not readable. If this is a system connection, try: sudo uv run share_my_wifi_qr_code.py") |
|
|
|
if display_password == "": |
|
print("Open network (no password)") |
|
|
|
if display_password not in (None, ""): |
|
print(f"Password: {display_password}") |
|
|
|
qrcode_terminal.draw(wifi_payload) |
|
print() |