110 lines
3.4 KiB
Python
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()
|