78 lines
1.8 KiB
Python
Executable File
78 lines
1.8 KiB
Python
Executable File
#!/usr/bin/env python3
|
|
from typing import Optional
|
|
import sys
|
|
import subprocess
|
|
import requests
|
|
import pydantic
|
|
|
|
|
|
class Server(pydantic.BaseModel):
|
|
public_key: str
|
|
endpoint: str
|
|
|
|
|
|
class ServerConfig(pydantic.BaseModel):
|
|
servers: list[Server]
|
|
current: Server
|
|
private_key: str
|
|
|
|
|
|
def offline():
|
|
try:
|
|
requests.head("https://1.1.1.1", timeout=1)
|
|
except IOError:
|
|
return True
|
|
else:
|
|
return False
|
|
|
|
|
|
def select_server() -> Optional[ServerConfig]:
|
|
try:
|
|
servers = ServerConfig.parse_file(
|
|
"/snacks/wireguard/servers.json", encoding="utf-8"
|
|
)
|
|
except (IOError, pydantic.ValidationError):
|
|
return None
|
|
servers.servers.append(servers.current)
|
|
servers.current = servers.servers.pop(0)
|
|
return servers
|
|
|
|
|
|
def write_json(servers: ServerConfig):
|
|
try:
|
|
with open("/snacks/wireguard/servers.json", mode="w", encoding="utf-8") as f:
|
|
f.write(servers.json(indent=4))
|
|
except IOError:
|
|
pass
|
|
|
|
|
|
def write_wg(server: Server, private_key: str):
|
|
wg_conf = (
|
|
"[Interface]\n"
|
|
f"privatekey = {private_key}\n\n"
|
|
"[Peer]\n"
|
|
f"publickey = {server.public_key}\n"
|
|
f"endpoint = {server.endpoint}\n"
|
|
"persistentkeepalive = 20\n"
|
|
"allowedips = 0.0.0.0/0, ::/0\n"
|
|
)
|
|
|
|
try:
|
|
with open("/snacks/wireguard/wg.conf", mode="w", encoding="utf-8") as f:
|
|
f.write(wg_conf)
|
|
except IOError:
|
|
pass
|
|
|
|
|
|
def main():
|
|
if ((len(sys.argv) == 2 and sys.argv[1] == "--force") or offline()) and (
|
|
servers := select_server()
|
|
):
|
|
write_json(servers)
|
|
write_wg(servers.current, servers.private_key)
|
|
subprocess.run(["systemctl", "restart", "vpnclient-wg"], check=False)
|
|
|
|
|
|
if __name__ == "__main__":
|
|
main()
|