bootbridge/src/bootbridge/configure.py
2026-01-07 17:01:09 +00:00

110 lines
3.4 KiB
Python

import os
import random
import string
from typing import Any
import petname
import typer
import yaml
from rich.panel import Panel
from rich.prompt import Confirm, Prompt
from bootbridge.settings import CONFIG_PATH, validate_settings
from bootbridge.console import console
from bootbridge.utils import ensure_file
class ConfigureCommand:
settings: dict[str, Any]
old_settings: None | dict[str, Any] = None
def load_old_settings(self):
if os.path.exists(CONFIG_PATH):
if Confirm.ask("Would you like to load existing settings?"):
with open(CONFIG_PATH, "r") as config_file:
self.old_settings = yaml.safe_load(config_file)
def old_setting(
self, key: str, default: Any, current: None | dict[str, Any] = None
) -> Any:
if current is None:
if not (current := self.old_settings):
return default
key_parts = key.split(".")
if len(key_parts) == 1:
try:
return current[key_parts[0]]
except KeyError:
return default
else:
try:
return self.old_setting(
".".join(key_parts[1:]), default, current[key_parts[0]]
)
except KeyError:
return default
def ask_webtunnel(self):
self.ask(
"Enter a URL path",
"bridge.webtunnel.path",
"".join(
random.choice(string.ascii_letters + string.digits)
for _ in range(random.randint(30, 50))
),
)
self.ask(
"Choose a certificate method",
"bridge.webtunnel.certificate",
"zerossl-ip",
choices=["zerossl-ip"],
)
if self.settings["bridge"]["webtunnel"]["certificate"] == "zerossl-ip":
self.ask("Enter your ZeroSSL API token", "zerossl.token", None)
def ask(
self, prompt: str, key: str, default: str | None, choices: list[str] | None = None
) -> None:
result = Prompt.ask(
prompt, default=self.old_setting(key, default), choices=choices
)
key_parts = key.split(".")
current = self.settings
while len(key_parts) > 1:
head = key_parts.pop(0)
if head not in current:
current[head] = {}
current = current[head]
current[key_parts[0]] = result
def save(self):
ensure_file(
CONFIG_PATH,
yaml.dump(self.settings, indent=2),
owner=0,
group=0,
mode=0o600,
)
def run(self):
console.rule("bootbridge configure")
self.load_old_settings()
self.settings = {}
self.ask(
"Enter a nickname",
"bridge.nickname",
petname.Generate(3).title().replace("-", ""),
)
self.ask("Enter contact details", "bridge.contact", "n/a")
self.ask("Choose a transport", "bridge.transport", "webtunnel", ["webtunnel"])
if self.settings["bridge"]["transport"] == "webtunnel":
self.ask_webtunnel()
self.save()
validate_settings()
console.print(
Panel(
":floppy_disk: Configuration saved.\n\n"
":toolbox: Run [bold]bootbridge up[/bold] to bootstrap this bridge."
)
)
raise typer.Exit()