# webcmd **Repository Path**: nachao/webcmd ## Basic Information - **Project Name**: webcmd - **Description**: No description available - **Primary Language**: Unknown - **License**: Not specified - **Default Branch**: master - **Homepage**: None - **GVP Project**: No ## Statistics - **Stars**: 1 - **Forks**: 0 - **Created**: 2026-09-28 - **Last Updated**: 2026-10-09 ## Categories & Tags **Categories**: Uncategorized **Tags**: None ## README # web-cmd Windows 本地网页控制台:托盘常驻程序 + 网页终端,可在浏览器里操作本机 `cmd.exe` (基于 ConPTY,真交互终端)。公网地址 `https://cmd-.frp.fangna.tech/` 中的 `code` **每次启动重新随机生成(16 位)**,所以**默认不需要密码**——地址本身就是钥匙,关掉程序即失效。 ## 运行(开发) ```powershell pip install -r requirements.txt python app\main.py ``` 启动后: 1. 系统托盘出现 web-cmd 图标; 2. 隧道就绪后会自动用浏览器打开公网地址;也可**单击托盘图标**随时打开; 3. 右键托盘图标弹出菜单(复制公网地址 / 退出); 4. 页面直接进入交互式命令行(无需输密码)。 ## 命令行客户端(webcmd,npm 包) 把任意一台机器的**本地命令行**直接接到运行 web-cmd 的那台机器上,无需 SSH、无需开放端口, 走 443/WSS,办公室网络一般放行。**零依赖**(自实现 RFC6455),Windows / macOS / Linux 通用。 ```bash npm i -g webcmd --registry http://npm.fangna.tech/ # 或免安装:npx --registry http://npm.fangna.tech/ webcmd cmd-xxxx ``` ```bash webcmd cmd-8f3k2m9q0p1r7x4t # 裸 code 自动补 .frp.fangna.tech webcmd https://cmd-xxxx.frp.fangna.tech/ # 完整地址 webcmd <地址> <密码> # 服务端设了 WEB_CMD_PASSWORD 时 webcmd <地址> --exec "dir" # 跑一条命令就退出(脚本友好) webcmd <地址> --quiet # 不回显本地状态行 echo dir | webcmd <地址> # 管道模式(stdin 逐行执行) ``` - 交互模式下按 **Ctrl+]** 退出。需要 **Node ≥ 16**。 - 源码:`client-node/`(`bin/webcmd.js` + `lib/ws.js`);发布:该目录 `npm publish`。 - 另有 Python 版 `client/webcmd_client.py`(仅保留源码,不再分发 exe)。 ## 产品页与下载 `https://webcmd.fangna.tech/` 为产品页(中/英双语、含 ChangeLog): | 产物 | 说明 | |------|------| | `download/web-cmd-<版本>-win64.zip` | GUI 托盘程序(约 40 MB,文件名带版本号) | | `webcmd`(npm) | 命令行客户端,发布在 `npm.fangna.tech` | 服务器上静态目录 `/var/www/webcmd/`,nginx 块 `/etc/nginx/conf.d/webcmd.fangna.tech.conf` (`/download/` 需显式声明 zip/exe 的 types 与 `default_type`,否则 `.exe` 会被当 zip 返回)。 打包发布产物:`powershell -File tools\pack_release.ps1`(自动带版本号并打印 SHA256, 随后**自动部署**到服务器并**自动 commit + push**;只打包用 `-NoDeploy`, 部署了不推送用 `-NoPush`,只部署用 `tools\deploy_release.ps1`,只推送用 `tools\push_release.ps1`)。 ## 打包 ```powershell .\build.ps1 # 产物:dist\web-cmd\web-cmd.exe ``` 打包脚本会自动补入 pywinpty ConPTY 后端依赖的 `winpty\OpenConsole.exe` 与 `winpty-agent.exe`(`--collect-all` 会漏收这两个 .exe),并排除未使用的重量级依赖。 ## 环境变量(可选) | 变量 | 作用 | |------|------| | `WEB_CMD_PASSWORD=xxxxxx` | **启用密码认证**(默认关闭)。设置后浏览器需先输密码才能进终端,公网地址泄漏也进不去 | | `WEB_CMD_FRP_SERVER` / `WEB_CMD_FRP_PORT` / `WEB_CMD_FRP_TOKEN` / `WEB_CMD_FRP_DOMAIN` | frps 连接信息(也可写 `%APPDATA%\web-cmd\frp.json`,见下) | | `WEB_CMD_NO_BROWSER=1` | 启动时不自动打开浏览器 | | `WEB_CMD_NO_TUNNEL=1` | 不启动公网隧道(仅本机访问) | | `WEB_CMD_PORT=8790` | 指定起始端口(被占用仍会顺延) | | `WEB_CMD_SHELL=a\x1fb\x1fc` | 自定义 shell 与参数(`\x1f` 分隔),默认 `cmd.exe /Q /K chcp 65001>nul` | | `PYWINPTY_BACKEND` | 强制 pywinpty 后端(默认自动) | ## 公网访问 启动后(未设 `WEB_CMD_NO_TUNNEL`)会拉起 frpc 隧道,地址形如: ``` https://cmd-<16 位随机码>.frp.fangna.tech/ ``` - `code` **每次启动重新生成**,所以地址每次都不同;关掉程序地址立即失效(已实测旧地址返回 404)。 - 单击托盘图标直接打开该地址;右键菜单可「复制公网地址」。 - 链路:浏览器 → 服务器 nginx(443 通配证书) → frps → frpc → 本机 web-cmd。frp 原生支持 WebSocket。 - **首次运行会弹一次 UAC**:`frpc.exe` 被 Defender 判为 `PUA:Win32/FRProxy`, 需提权把它加入 Defender 排除(按文件路径)。点「是」后后续启动不再弹。 - 断线自动重连;退出托盘程序会一并结束 frpc 进程。 - 重复启动只会保留最后一个实例(新实例接管,旧的与其 frpc 会被结束)。 ## 接入自己的 frps frps 地址与 token 属部署方私有信息,**不写进代码/发布包**。程序按以下优先级读取: 1. 环境变量 `WEB_CMD_FRP_SERVER` / `WEB_CMD_FRP_PORT` / `WEB_CMD_FRP_TOKEN` / `WEB_CMD_FRP_DOMAIN` 2. `%APPDATA%\web-cmd\frp.json`(推荐;UTF-8,带不带 BOM 都行): ```json { "serverAddr": "1.2.3.4", "serverPort": 7000, "authToken": "你的 frps token", "domainSuffix": "frp.example.com" } ``` 3. 都没有 → 隧道禁用(仅本机可用),托盘状态显示「未配置隧道」。 `domainSuffix` 决定生成的公网地址 `https://cmd-./`;服务端需把该域名的 `*.domainSuffix` 解析到 frps 的 vhost 端口,并配好证书(或用 nginx 终止 TLS)。 ## 设计要点 - 服务只监听 `127.0.0.1`,对外暴露完全由隧道决定(`WEB_CMD_NO_TUNNEL=1` 即纯本机); - **单实例**:后启动的实例会先结束已在运行的旧实例(及其 frpc),只保留一个托盘图标; - 网页终端带**断线自动重连**(指数退避,状态条显示重连倒计时),重连后开新会话; - 托盘:单击打开控制台;右键菜单精简为 打开控制台 / 复制公网地址 / **开机自启动(勾选项)** / 退出(启用密码后才有 显示访问密码 / 重新生成密码); - **开机自启动**写当前用户注册表 `HKCU\...\CurrentVersion\Run`(免管理员,不需要计划任务); 打包版注册 exe 自身路径,源码版注册 `pythonw.exe app\main.py`。程序被移动后需重新勾选一次。 - 密码(如启用)仅存内存。 ## 安全提醒 本程序会执行本机命令,等价于一个远程 shell。**默认靠"地址即密钥"保护**: - `code` 为 16 位 `[a-z0-9]`(约 82 bit),暴力猜不可行; - 但 URL 会以明文出现在 TLS SNI、DNS 查询、服务器 nginx/frps 日志与浏览器历史中, 且**谁拿到 URL 谁就能完全控制本机**——不要把地址发到不受控的地方; - 需要第二道门时,设 `WEB_CMD_PASSWORD` 启用密码认证(连续 5 次错误锁定 60 秒)。 ## 测试 ```powershell # 源码版端到端(密码模式 6 项 + 无密码模式 2 项) python tools\selftest.py # 打包版端到端(需先启动 exe) python tools\exe_e2e.py 8791 ``` ## 排障 - 打包后终端无输出 / 子进程秒退且退出码为 `3221225786`(`0xC000013A`): 说明 ConPTY 缺少 `OpenConsole.exe`,用 `build.ps1` 重新打包即可(脚本已处理)。 - 首次运行弹 UAC、日志出现 `launch blocked: PermissionError`: 这是 Defender 拦 `frpc.exe`(`PUA:Win32/FRProxy`),点「是」授权即可,之后不再弹。 若点了「否」,重启程序会再次申请。隧道日志见 `%TEMP%\web-cmd-tunnel.log`。 - 错误日志写入 `%TEMP%\web-cmd.log`。