这是当前仓库状态对应的说明文档。仓库包含 Windows 机台客户端、Node.js 管理服务、离线签名与打包工具、挂载调试工具,以及新的 Flutter 管理客户端。
旧版可操作 Web 管理前端已经移除;VHDSelectServer 根路径 / 现在只提供轻量的客户端下载与连接提示页,不再提供可操作的浏览器管理界面。
📖 安装与使用指南:https://lannamokia.github.io/vhdmount/
-
VHDMounter
- 基于 .NET 8 WPF 的 Windows 客户端,默认发布为 win-x64 自包含单文件。
- 扫描本地与可移动介质中的 VHD,按配置可向服务端请求目标关键词,并把目标卷绑定到
M:\。 - 依据 VHD 文件名选择启动目录:包含
SDHD时优先查找bin,其他情况查找package。 - 首次启动使用
start.bat;异常重启时优先使用start_game.bat,否则回退到start.bat。 - 监控目标进程关键字
sinmai、chusanapp、mu3。 - 可选机台日志上报链路:本地写入
machine-log-spool.jsonl,再通过 WebSocket 上传到服务端。
-
VHDMounter_Maimoller
- 由
EnableHidMenuFeatures=true构建出的增强变体。 - 在基础版之上额外编译 Maimoller HID、系统菜单、系统设置和系统信息采集相关模块。
- 由
-
VHDSelectServer
- 基于 Node.js/Express 的管理服务。
- 提供初始化流程、管理员登录、OTP step-up、机台管理、可信注册证书管理、审计日志和机台日志查询/导出。
- 支持 Docker 内置 PostgreSQL 或外部 PostgreSQL。
- 数据库结构通过
schema_version+migrations/统一迁移。
-
Updater
- 负责应用离线更新包、替换主程序文件并重新拉起主程序。
- 会优先尝试重新启动
VHDMounter_Maimoller.exe,找不到时再回退到VHDMounter.exe。
-
VHDMountAdminTools
- 独立 Windows WPF 桌面工具,离线生成更新签名密钥、
trusted_keys.pem、manifest.json、manifest.sig。 - 生成预配置注册证书包:
.pfx、.pem、.trust.json和可直接粘贴到客户端配置中的.client-config.ini片段。 - 默认生成的更新清单有效期为 3 天,默认
minVersion为1.7.0。 - 当前版本的同等功能已迁移至 Flutter 管理客户端 Windows 桌面端的"离线工具"页(密钥生成、清单打包、证书包、软件部署打包),可直接在管理客户端内完成签名与打包,无需再单独运行此工具。
- 独立 Windows WPF 桌面工具,离线生成更新签名密钥、
-
EVHDMountTester
- 调试用命令行工具,验证
encrypted-vhd-mount.exe挂载 EVHD 到指定挂载点,并可继续验证解密后 VHD 绑定到目标盘符(默认M:\)。
- 调试用命令行工具,验证
-
vhd_mount_admin_flutter
- 跨平台管理客户端,负责初始化、登录、OTP 验证、机台管理、证书管理、审计查看、部署管理和安全设置。
- 当前工程已包含 Windows、Android 和 iOS 平台骨架;iOS 构建仍需 macOS + Xcode。
- 已集成 OTP 自动守卫:高敏操作触发时自动弹窗,验证成功后透明重试原始操作。
- 服务端支持多 TOTP 密钥架构;客户端在设置页提供"TOTP 密钥管理"区域用于添加 / 注销认证器密钥。
- Windows 桌面端集成"离线工具"页(仅在
Platform.isWindows且已认证时显示),等价于 VHDMountAdminTools 的全部能力 + 软件部署本地打包器。 - 证书页面提供"生成证书"按钮(仅 Windows 桌面),生成成功后自动调用
addTrustedCertificate导入服务端信任列表。
vhdmount/
├── .github/workflows/ # CI 工作流
├── docs/ # 规划与实现报告
├── scripts/
│ └── build.bat # 本地发布脚本
├── src/
│ └── VHDMounter/ # 主客户端源码与默认配置模板
├── Updater/ # 更新器
├── VHDMountAdminTools/ # 离线管理工具
├── EVHDMountTester/ # EVHD/VHD 挂载调试工具
├── VHDMounter.Tests/ # xUnit 测试
├── VHDSelectServer/ # 管理服务、Docker 与迁移脚本
├── vhd_mount_admin_flutter/ # Flutter 管理客户端
├── artifacts/local-publish/ # 本地脚本发布输出
├── single/ # 便于拷贝的本地整合输出
├── VHDMounter.csproj # 主客户端工程
└── vhdmount.sln # .NET 解决方案
- Windows 10/11,客户端运行需要管理员权限。
- 从源码构建 .NET 项目需要 .NET 8 SDK。
- 直接运行 VHDSelectServer 需要 Node.js 18+。
- 使用容器部署服务端需要 Docker 20.10+ 和 Compose 2+。
- 外部数据库模式需要 PostgreSQL 15+。
- 开发 Flutter 管理端需要 Flutter stable;工程当前要求满足
pubspec.yaml中的 Dart SDK 约束(^3.11.4)。
Docker 部署(推荐):
cd VHDSelectServer
docker compose up --build -d
docker compose logs -f仓库自带的 docker-compose.yml 默认把宿主机 8082 映射到容器内 8080,因此本机访问地址默认是 http://127.0.0.1:8082。
如果需要把服务配置持久化到宿主机,请映射父目录到 /app/config,让实际可写配置落在子目录 /app/config/data:
volumes:
- ./config:/app/config
environment:
- CONFIG_ROOT_DIR=/app/config
- CONFIG_PATH=/app/config/data如果需要把内置 PostgreSQL 数据持久化到宿主机,请映射父目录到 /var/lib/postgresql/data,不要直接把宿主机目录当作 cluster 根目录使用:
volumes:
- ./postgres-data:/var/lib/postgresql/data
environment:
- POSTGRES_DATA_DIR=/var/lib/postgresql/data/pgdata本地直接运行:
cd VHDSelectServer
npm install
npm run migrate
npm start直接运行时默认监听 http://127.0.0.1:8080。
首次部署后的初始化流程:
- 调用
GET /api/init/status确认是否已初始化。 - 调用
POST /api/init/prepare获取 OTP 绑定信息。 - 调用
POST /api/init/complete提交管理员密码、Session Secret、数据库配置、允许的 Origin 和可信注册证书。
推荐使用仓库内的 Flutter 管理客户端完成初始化,而不是手工拼接请求。
从源码本地构建:
scripts\build.bat该脚本会:
- 发布基础版
VHDMounter.exe - 发布增强版
VHDMounter_Maimoller.exe - 发布
Updater.exe - 发布
VHDMountAdminTools.exe - 构建并打包 Flutter Windows 管理端
vhd_mount_admin_windows.zip - 把以上产物与
vhdmonter_config.ini复制到single/ - 同时保留完整发布目录到
artifacts/local-publish/
生成后的主程序应以管理员身份运行:
single\VHDMounter.exe
single\VHDMounter_Maimoller.execd vhd_mount_admin_flutter
flutter pub get
flutter run -d windows附加说明:
- Android 可使用
flutter run -d android。 - iOS 工程骨架已在仓库内,但运行和打包仍需 macOS + Xcode。
- Android 模拟器访问本机服务时通常使用
http://10.0.2.2:端口;如果服务端按仓库默认 Compose 运行,端口就是8082。
默认模板位于 src/VHDMounter/vhdmonter_config.ini:
[Settings]
ServerBaseUrl=http://127.0.0.1:8080
EnableRemoteSelection=false
RegistrationCertificatePath=
RegistrationCertificatePassword=
MachineId=MACHINE_001
EnableProtectionCheck=false
ProtectionCheckInterval=500
EnableLogUpload=false
MachineLogUploadIntervalMs=3000
MachineLogUploadBatchSize=200
MachineLogUploadMaxSpoolBytes=52428800说明:
- 构建与发布时复制到输出目录的权威模板来自
src/VHDMounter/vhdmonter_config.ini。 - 当前推荐配置项是
ServerBaseUrl。客户端会基于它自动派生以下固定端点:/api/boot-image-select/api/evhd-envelope/api/protect/ws/machine-log
- 为兼容旧部署,客户端仍能从历史配置项
BootImageSelectUrl、EvhdEnvelopeUrl、ProtectionCheckUrl、MachineLogServerIp/MachineLogServerPort反推出服务端基地址,但新的模板不再写这些旧字段。 - 如果你使用仓库自带的
docker-compose.yml默认端口映射,请把ServerBaseUrl改成http://127.0.0.1:8082,或者自行修改 Compose 端口。 EnableLogUpload=true时,客户端会在应用目录生成machine-log-spool.jsonl和machine-log-client.log。
- 目标 VHD 挂载后会绑定到
M:\。 - 如果系统先给候选卷分配了其他盘符,客户端会先清理已有盘符,再把卷重新绑定到
M:\。 - 目标启动目录按 VHD 文件名决定:
SDHD对应bin,其余默认查找package。 - 初次启动使用
start.bat;当检测到目标进程退出时,重启顺序为:start_game.bat优先,start.bat兜底。 - 运行日志写入应用目录下的
vhdmounter.log,达到 10 MiB 后循环覆盖。 - 若存在卷标为
NXLOG的可移动设备,客户端会把最新日志复制到该设备根目录。
VHDMountAdminTools用于生成更新签名密钥、trusted_keys.pem、更新清单和注册证书包。- 主程序启动时会检查卷标为
NX_INS的可移动设备,寻找manifest.json/manifest.sig(支持根目录或updates/子目录)。 - 验签通过后,更新文件会被复制到本地
staging/目录,再拉起Updater.exe。 Updater完成替换后会写入update_done.flag,并重新拉起当前可用的主程序变体。
- 旧 Web 管理界面已删除,服务根路径
/仅返回下载/连接提示页。 GET /api/status与GET /api/health现在只返回最小状态信息:success、status、initialized、pendingInitialization、databaseReady。GET /api/init/status在匿名访问时只返回最小初始化状态;更详细的管理信息只在已登录会话下返回。- 管理接口采用 Session 登录,敏感操作额外要求 OTP step-up。
- OTP 绑定支持两步式轮换:
POST /api/auth/otp/rotate/preparePOST /api/auth/otp/rotate/complete
- 服务端支持多 TOTP 密钥架构:
totpKeys数组替代旧的单totpSecret字段,旧配置在加载时自动迁移为单元素数组(type 为authenticator,名称 "初始认证器")。- 每个密钥包含
id、name、type(authenticator;历史biometric条目仍兼容存量数据但客户端不再生成新的)、platform、secret、createdAt、lastUsedAt。 verifyTotp遍历所有活跃密钥,任一匹配即视为成功,并更新该密钥的lastUsedAt。- 至少保留一个
authenticator类型密钥,最后一个不可被注销。 - OTP 轮换(rotate)会全量重置为单个新
authenticator密钥。
- 机台日志链路已落地:服务端支持实时接收、分页查询和导出机台日志,并可配置日志保留策略。
- 数据库结构通过
migrations/001_*.sql、002_*.sql之类的版本文件管理;应用启动和npm run migrate走同一套迁移逻辑。
公开接口:
GET /api/statusGET /api/healthGET /api/init/statusGET /api/boot-image-select?machineId=...GET /api/protect?machineId=...GET /api/evhd-envelope?machineId=...
初始化与认证:
POST /api/init/preparePOST /api/init/completePOST /api/auth/loginGET /api/auth/checkPOST /api/auth/logoutPOST /api/auth/change-passwordPOST /api/auth/otp/verifyGET /api/auth/otp/statusPOST /api/auth/otp/rotate/preparePOST /api/auth/otp/rotate/completeGET /api/auth/otp/keys(列出当前活跃 TOTP 密钥,不含 secret,仅需登录态)POST /api/auth/otp/keys(注册新密钥,type 为authenticator;服务端仍接受biometric以兼容历史客户端,但当前 UI 不再生成此类型;仅创建时返回一次secret+otpauthUrl,需 OTP step-up)DELETE /api/auth/otp/keys/:keyId(注销指定密钥;保护最后一个authenticator类型密钥不被删除,需 OTP step-up)
设置与机台日志:
GET /api/settings/default-vhdPOST /api/settings/default-vhdPOST /api/set-vhd(兼容旧入口,行为同上)GET /api/settings/log-retentionPOST /api/settings/log-retentionGET /api/machine-log-sessionsGET /api/machine-logsGET /api/machine-logs/export
机台、证书与审计:
GET /api/machinesPOST /api/machinesDELETE /api/machines/:machineIdPOST /api/machines/:machineId/vhdPOST /api/machines/:machineId/evhd-passwordPOST /api/machines/:machineId/keysPOST /api/machines/:machineId/approvePOST /api/machines/:machineId/revokeGET /api/security/trusted-certificatesPOST /api/security/trusted-certificatesDELETE /api/security/trusted-certificates/:fingerprintGET /api/auditGET /api/evhd-password/plain?machineId=...&reason=...
说明:证书管理、明文查询、日志导出等高敏感接口要求已登录会话,且部分接口必须先完成 OTP step-up。
应用与配置目录:
PORT:服务端口,默认8080NODE_ENV:运行模式CONFIG_ROOT_DIR:配置根目录CONFIG_PATH:实际安全配置目录,默认通常设为CONFIG_ROOT_DIR下的data子目录MACHINE_REGISTRATION_RATE_LIMIT_MAX:机台公钥注册接口在 10 分钟窗口内的单机限流阈值,默认20AUDIT_LOG_MAX_BYTES:单个审计日志文件最大字节数,默认 5 MiBAUDIT_LOG_MAX_FILES:审计日志最大保留文件数,默认 5
数据库:
USE_EMBEDDED_DBDB_HOSTDB_PORTDB_NAMEDB_USERDB_PASSWORDDB_MAX_CONNECTIONSDB_IDLE_TIMEOUTDB_CONNECTION_TIMEOUTDB_SSLPOSTGRES_DATA_DIR
本地验证命令:
dotnet test VHDMounter.Tests\VHDMounter.Tests.csproj
cd VHDSelectServer
npm test
cd ..\vhd_mount_admin_flutter
flutter analyze
flutter testGitHub Actions:
-
.github/workflows/build.yml- 在
main、dev、feature/software-deployment、maimoller_control_test分支和所有标签上构建。 - 产出四个 ZIP:
VHDMounter、VHDMounter_Maimoller、Updater、VHDMountAdminTools。 - 标签构建时附带
CHECKSUMS.sha256并上传到 GitHub Release。
- 在
-
.github/workflows/flutter-admin-client.yml- 在 Flutter 目录或工作流文件变更时触发。
- 构建 Windows ZIP、Android release APK、iOS unsigned IPA。
- 标签构建时汇总产物并上传到 GitHub Release。
- Android release 签名通过
ANDROID_KEYSTORE_BASE64、ANDROID_KEYSTORE_PASSWORD、ANDROID_KEY_ALIAS、ANDROID_KEY_PASSWORD注入;tag 构建缺少这些变量时会直接失败,避免发布 debug-signed APK。
-
.github/workflows/docker-image.yml- 在
VHDSelectServer/**相关变更的 push / pull_request 时构建 Docker 镜像并上传.tgzartifact。 - 在 tag push 时构建版本镜像并推送到 DockerHub,同时上传镜像归档 artifact。
- 在
-
EVHD 挂载相关软件与源代码仅提供给认证合作伙伴,用于受控环境下的机台数据保护等功能。
-
普通用户无需配置或使用 EVHD,请直接将 VHD 文件放入设备(本地或 USB),客户端会自动扫描并挂载使用。
-
本开源仓库不包含 EVHD 挂载相关软件的源代码;如需使用,请联系项目维护方完成合作伙伴认证流程。
-
客户端模板中的
ServerBaseUrl默认值是直跑服务的http://127.0.0.1:8080,不是仓库默认 Docker Compose 的宿主机端口。 -
打包后的 .NET 程序默认是 win-x64 自包含单文件,部署时通常不需要额外安装 .NET Runtime。
本项目主体代码以 MIT License 授权。
本项目 src/VHDMounter/ 目录下的 HID 输入处理相关模块(MaimollerInputService.cs、MaimollerInputModels.cs 等)部分代码改编自 AquaMai,该项目以 Apache License, Version 2.0 授权。
- Copyright 2024 MuNET Team
- 原始仓库:https://github.com/MuNET-OSS/AquaMai
上述文件保留了原始的 Apache 2.0 版权声明,完整许可证文本请参阅 third-party-licenses/LICENSE-APACHE-2.0。