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 = """
-
+
+
+
@@ -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[@]}" &