Make Wi-Fi semi-declarative
This commit is contained in:
parent
bc53468373
commit
96dea140be
5 changed files with 125 additions and 126 deletions
|
|
@ -9,7 +9,6 @@ into a format readable by Nix.
|
|||
# sha256 = "sha256:1la36n2f31j9s03v847ig6ny9lr875q3g7smnq33dcsmf2i5gd92";
|
||||
# }
|
||||
|
||||
import hashlib
|
||||
import json
|
||||
import os
|
||||
import subprocess
|
||||
|
|
@ -20,46 +19,6 @@ import yaml
|
|||
|
||||
PASSWORD_STORE = os.environ["PASSWORD_STORE_DIR"]
|
||||
SUBFOLDER = "wifi"
|
||||
SEPARATE_PASSWORDS = True
|
||||
|
||||
|
||||
class Password:
|
||||
all: list["Password"] = list()
|
||||
|
||||
def __init__(self, path: str, content: str):
|
||||
self.path = path
|
||||
self.content = content
|
||||
|
||||
Password.all.append(self)
|
||||
|
||||
def var(self) -> str:
|
||||
# return self.path.split("/")[-1].upper()
|
||||
m = hashlib.sha256()
|
||||
m.update(self.path.encode())
|
||||
return "p" + m.hexdigest().upper()
|
||||
|
||||
def val(self) -> str:
|
||||
return self.content
|
||||
|
||||
def exists(self) -> bool:
|
||||
return not not self.content
|
||||
|
||||
def key(self) -> str:
|
||||
if SEPARATE_PASSWORDS:
|
||||
return f"@{self.var()}@"
|
||||
else:
|
||||
return self.val()
|
||||
|
||||
@classmethod
|
||||
def vars(cls) -> dict[str, str]:
|
||||
vars = dict()
|
||||
for password in cls.all:
|
||||
if not password.content:
|
||||
continue
|
||||
var = password.var()
|
||||
assert var not in vars, f"Duplicate key: {var}"
|
||||
vars[var] = password.val()
|
||||
return vars
|
||||
|
||||
|
||||
def list_networks() -> list[str]:
|
||||
|
|
@ -75,28 +34,11 @@ def list_networks() -> list[str]:
|
|||
file = filename[:-4]
|
||||
path = os.path.join(SUBFOLDER, file)
|
||||
paths.append(path)
|
||||
paths.sort()
|
||||
return paths
|
||||
|
||||
|
||||
def format_wpa_supplicant_conf(conf: dict, indent: str = "") -> str:
|
||||
lines = []
|
||||
for k, v in conf.items():
|
||||
if isinstance(v, str):
|
||||
val = '"' + v.replace('"', '\\"') + '"'
|
||||
elif isinstance(v, Password):
|
||||
val = v.key()
|
||||
elif isinstance(v, list):
|
||||
assert all(
|
||||
map(lambda i: isinstance(i, str), v)
|
||||
), "Only list of strings supported"
|
||||
val = " ".join(v)
|
||||
else:
|
||||
val = str(v)
|
||||
lines.append(f"{indent}{k}={val}")
|
||||
return "\n".join(lines)
|
||||
|
||||
|
||||
networks = {}
|
||||
networks: list[dict[str, str | list[str] | int]] = list()
|
||||
for path in list_networks():
|
||||
proc = subprocess.run(["pass", path], stdout=subprocess.PIPE)
|
||||
proc.check_returncode()
|
||||
|
|
@ -104,61 +46,24 @@ for path in list_networks():
|
|||
raw = proc.stdout.decode()
|
||||
split = raw.split("\n")
|
||||
|
||||
password = Password(path, split[0])
|
||||
password = split[0]
|
||||
data = yaml.safe_load("\n".join(split[1:])) or dict()
|
||||
# print(path, data) # DEBUG
|
||||
|
||||
# Helpers to prevent repetition
|
||||
suffixes = data.pop("suffixes", [""])
|
||||
data.setdefault("key_mgmt", ["WPA-PSK"] if password.exists() else ["NONE"])
|
||||
data.setdefault("key_mgmt", ["WPA-PSK"] if password else ["NONE"])
|
||||
if password:
|
||||
if any(map(lambda m: "PSK" in m.split("-"), data["key_mgmt"])):
|
||||
data["psk"] = password
|
||||
if "NONE" in data["key_mgmt"]:
|
||||
data["wep_key0"] = password
|
||||
if any(map(lambda m: "EAP" in m.split("-"), data["key_mgmt"])):
|
||||
data["password"] = password
|
||||
assert "ssid" in data, f"{path}: Missing SSID"
|
||||
|
||||
# # Output wpa_supplicant conf, for debug
|
||||
# for suffix in suffixes:
|
||||
# wpas = data.copy()
|
||||
# wpas["ssid"] += suffix
|
||||
# print(f"# {path}")
|
||||
# print("network={")
|
||||
# print(format_wpa_supplicant_conf(wpas, indent=" "))
|
||||
# print("}")
|
||||
# print()
|
||||
|
||||
# Convert to nix configuration
|
||||
ssid = data.pop("ssid")
|
||||
network = {}
|
||||
key_mgmt = data.pop("key_mgmt", None)
|
||||
psk = data.pop("psk", None)
|
||||
priority = data.pop("priority", None)
|
||||
# No support for hidden
|
||||
# No support for extraConfig (all is assumed to be auth)
|
||||
if key_mgmt:
|
||||
network["authProtocols"] = key_mgmt
|
||||
if psk:
|
||||
network["psk"] = psk.key()
|
||||
if data:
|
||||
raise NotImplementedError(
|
||||
f"{path}: Unhandled non-auth extra: {data}"
|
||||
)
|
||||
else:
|
||||
if data:
|
||||
network["auth"] = format_wpa_supplicant_conf(data)
|
||||
if priority:
|
||||
network["priority"] = int(priority)
|
||||
data.setdefault("disabled", 0)
|
||||
|
||||
for suffix in suffixes:
|
||||
networks[ssid + suffix] = network
|
||||
network = data.copy()
|
||||
network["ssid"] += suffix
|
||||
networks.append(network)
|
||||
|
||||
with open("wireless_networks.json", "w") as fd:
|
||||
json.dump(networks, fd, indent=4)
|
||||
|
||||
with open("wireless_networks.env", "w") as fd:
|
||||
if SEPARATE_PASSWORDS:
|
||||
for k, v in Password.vars().items():
|
||||
print(f'{k}="{v}"', file=fd)
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue