Lock down the local release console
This commit is contained in:
@@ -4,6 +4,7 @@
|
||||
from __future__ import annotations
|
||||
|
||||
import argparse
|
||||
import ipaddress
|
||||
from pathlib import Path
|
||||
import secrets
|
||||
import sys
|
||||
@@ -11,12 +12,31 @@ import sys
|
||||
from govoplan_release.workspace import DEFAULT_WORKSPACE_ROOT
|
||||
|
||||
|
||||
def loopback_host(value: str) -> str:
|
||||
try:
|
||||
address = ipaddress.ip_address(value)
|
||||
except ValueError as exc:
|
||||
raise argparse.ArgumentTypeError(
|
||||
"release console host must be a numeric loopback address"
|
||||
) from exc
|
||||
if not address.is_loopback:
|
||||
raise argparse.ArgumentTypeError(
|
||||
"release console refuses non-loopback hosts without an authenticated "
|
||||
"TLS deployment boundary"
|
||||
)
|
||||
return value
|
||||
|
||||
|
||||
def main() -> int:
|
||||
parser = argparse.ArgumentParser(description=__doc__)
|
||||
parser.add_argument("--host", default="127.0.0.1", help="Bind host. Defaults to 127.0.0.1.")
|
||||
parser.add_argument(
|
||||
"--host",
|
||||
type=loopback_host,
|
||||
default="127.0.0.1",
|
||||
help="Numeric loopback bind address. Defaults to 127.0.0.1.",
|
||||
)
|
||||
parser.add_argument("--port", type=int, default=8765, help="Bind port. Defaults to 8765.")
|
||||
parser.add_argument("--workspace-root", type=Path, default=DEFAULT_WORKSPACE_ROOT)
|
||||
parser.add_argument("--no-token", action="store_true", help="Disable the local API token guard.")
|
||||
args = parser.parse_args()
|
||||
|
||||
try:
|
||||
@@ -28,13 +48,13 @@ def main() -> int:
|
||||
from server.app import create_app
|
||||
|
||||
workspace_root = args.workspace_root.expanduser().resolve()
|
||||
token = None if args.no_token else secrets.token_urlsafe(24)
|
||||
token = secrets.token_urlsafe(24)
|
||||
app = create_app(workspace_root=workspace_root, token=token)
|
||||
url = f"http://{args.host}:{args.port}/"
|
||||
if token:
|
||||
# URL fragments are never sent in HTTP requests. The WebUI transfers
|
||||
# this one-time bootstrap token to sessionStorage and clears the hash.
|
||||
url = f"{url}#token={token}"
|
||||
display_host = f"[{args.host}]" if ":" in args.host else args.host
|
||||
url = f"http://{display_host}:{args.port}/"
|
||||
# URL fragments are never sent in HTTP requests. The WebUI transfers
|
||||
# this one-time bootstrap token to sessionStorage and clears the hash.
|
||||
url = f"{url}#token={token}"
|
||||
print("GovOPlaN release console")
|
||||
print(f" workspace: {workspace_root}")
|
||||
print(f" url: {url}")
|
||||
|
||||
Reference in New Issue
Block a user