diff --git a/Dockerfile b/Dockerfile index 0da7b46..75f6262 100644 --- a/Dockerfile +++ b/Dockerfile @@ -10,6 +10,7 @@ COPY scripts/dos-shell /usr/local/bin/dos-shell COPY scripts/dos-httpd /usr/local/bin/dos-httpd COPY scripts/prepare-svardos.sh /usr/local/bin/prepare-svardos COPY scripts/start-services.sh /usr/local/bin/start-dos-services +COPY WebPlus_IBM_VGA_8x16.woff /usr/local/share/dos-httpd/WebPlus_IBM_VGA_8x16.woff RUN chmod +x /usr/local/bin/dos-shell /usr/local/bin/dos-httpd /usr/local/bin/start-dos-services /usr/local/bin/prepare-svardos && echo "/usr/local/bin/dos-shell" >> /etc/shells # Create sshd runtime directory diff --git a/README.md b/README.md index 0d90568..220bace 100644 --- a/README.md +++ b/README.md @@ -126,6 +126,7 @@ You can override which binary is used for the Linux side by setting `DOS_LINUX_S | `DOS_SSH_PORT` | `2222` | Host port forwarded to container port 22. | | `DOS_TELNET_PORT` | `2323` | Host port forwarded to container port 23. | | `DOS_HTTP_PORT` | `8080` | Host port forwarded to the web console. | +| `DOS_HTTP_CRT` | `1` | Toggle the CRT styling applied to the web console (`0` to disable). | | `ENABLE_TELNET` | `1` | Toggle BusyBox telnetd. | | `ENABLE_HTTP_CONSOLE` | `1` | Launch the built-in web terminal. | | `TELNET_PORT` | `23` | Port inside the container where telnetd listens. | diff --git a/compose.yml b/compose.yml index ecf4169..b719fff 100644 --- a/compose.yml +++ b/compose.yml @@ -17,6 +17,7 @@ services: TELNET_LOGIN: /bin/login ENABLE_HTTP_CONSOLE: ${ENABLE_HTTP_CONSOLE:-1} DOS_HTTP_PORT: ${DOS_HTTP_PORT:-8080} + DOS_HTTP_CRT: 0 volumes: - ./allowed_repo:/opt/allowed_repo:z - ./config/dos_allowed:/etc/dos_allowed:ro,z diff --git a/scripts/dos-httpd b/scripts/dos-httpd index b4c3c8c..201fc69 100644 --- a/scripts/dos-httpd +++ b/scripts/dos-httpd @@ -28,6 +28,18 @@ from aiohttp import web, WSMsgType LOG = logging.getLogger("dos_httpd") + +def _env_bool(name: str, default: bool) -> bool: + value = os.environ.get(name) + if value is None: + return default + value = value.strip().lower() + if value in {"1", "true", "yes", "on"}: + return True + if value in {"0", "false", "no", "off"}: + return False + return default + HTML_PAGE = """ @@ -36,12 +48,18 @@ HTML_PAGE = """
SvarBox DOS Console
-
+
+
+
@@ -308,13 +510,22 @@ class ShellSession: async def index_handler(_request: web.Request) -> web.StreamResponse: - return web.Response(text=HTML_PAGE, content_type="text/html", headers={"Cache-Control": "no-store"}) + cfg: "AppConfig" = _request.app["config"] + page = HTML_PAGE.replace("__CRT_ENABLED__", "true" if cfg.crt_effect else "false") + return web.Response(text=page, content_type="text/html", headers={"Cache-Control": "no-store"}) async def health_handler(_request: web.Request) -> web.Response: return web.Response(text="ok\n", content_type="text/plain") +async def font_handler(request: web.Request) -> web.StreamResponse: + cfg: "AppConfig" = request.app["config"] + if not os.path.exists(cfg.font_path): + raise web.HTTPNotFound() + return web.FileResponse(path=cfg.font_path, headers={"Cache-Control": "public, max-age=86400"}) + + async def websocket_handler(request: web.Request) -> web.WebSocketResponse: ws = web.WebSocketResponse(heartbeat=30) await ws.prepare(request) @@ -347,13 +558,17 @@ async def websocket_handler(request: web.Request) -> web.WebSocketResponse: class AppConfig: - def __init__(self, user: str, shell_path: str, host: str, port: int, rows: int, cols: int): + FONT_PATH = "/usr/local/share/dos-httpd/WebPlus_IBM_VGA_8x16.woff" + + def __init__(self, user: str, shell_path: str, host: str, port: int, rows: int, cols: int, crt_effect: bool): self.user = user self.shell_path = shell_path self.host = host self.port = port self.default_rows = rows self.default_cols = cols + self.font_path = self.FONT_PATH + self.crt_effect = crt_effect def build_argument_parser() -> argparse.ArgumentParser: @@ -378,6 +593,10 @@ def build_argument_parser() -> argparse.ArgumentParser: choices=["CRITICAL", "ERROR", "WARNING", "INFO", "DEBUG"], help="Log verbosity", ) + default_crt = _env_bool("DOS_HTTP_CRT", True) + parser.set_defaults(crt_effect=default_crt) + parser.add_argument("--crt", dest="crt_effect", action="store_true", help="Enable CRT overlay") + parser.add_argument("--no-crt", dest="crt_effect", action="store_false", help="Disable CRT overlay") return parser @@ -392,6 +611,7 @@ async def create_app(cfg: AppConfig) -> web.Application: [ web.get("/", index_handler), web.get("/healthz", health_handler), + web.get("/assets/WebPlus_IBM_VGA_8x16.woff", font_handler), web.get("/ws", websocket_handler), ] ) @@ -410,6 +630,7 @@ def main() -> None: port=args.port, rows=args.rows, cols=args.cols, + crt_effect=args.crt_effect, ) app = asyncio.run(create_app(cfg)) diff --git a/scripts/start-services.sh b/scripts/start-services.sh index 0fe1624..f74028a 100755 --- a/scripts/start-services.sh +++ b/scripts/start-services.sh @@ -113,6 +113,16 @@ start_http_console() { if [ -n "${DOS_HTTP_LOG_LEVEL:-}" ]; then args+=(--log-level "${DOS_HTTP_LOG_LEVEL}") fi + if [ -n "${DOS_HTTP_CRT:-}" ]; then + case "${DOS_HTTP_CRT,,}" in + 0|false|no|off) + args+=(--no-crt) + ;; + 1|true|yes|on) + args+=(--crt) + ;; + esac + fi set +e "${DOS_HTTPD_BIN}" "${args[@]}" &