Commit Graph

26 Commits

Author SHA1 Message Date
Gloridust
94b591e0b2 fix(critical): xsettingsd Xft/DPI 单位错误 —— v1.2.9~v1.3.1 微信公众号/附件秒关、浏览器黑屏的总根因
XSETTINGS 规范中 Xft/DPI 的单位是「DPI×1024」(96 DPI 应写 98304),#101 引入的 xsettingsd
配置误写成 96 → 所有 Chromium 内核应用把 DPI 读成 96/1024≈0.09 → 缩放因子≈0 → 显示变换
矩阵 [0 0 0 0;…] 不可逆(transform.cc NOTREACHED)→ GPU/viz 进程连崩 3 次 → 窗口/应用退出:
- 微信内嵌 CEF:点公众号/附件/小程序 → 窗口秒关/白屏(issue #111,日志与本地复现完全吻合)
- 系统 Chromium:整个浏览器崩溃循环 → 黑屏(v1.3.1 的 --force-device-scale-factor=1 只救了
  能加 flag 的 Chromium,是治症状;微信 CEF 无法加 flag,必须修 XSETTINGS 源头)
A/B 实证:Xft/DPI 96 → 裸 chromium 立崩(同款堆栈);改 98304 → 存活。两处写入点均已修
(docker/autostart 每次开机重写 + 面板 applyXsettingsFont 实时下发)。

配套修复本轮反馈的其余问题:
- 磁盘暴涨("1TB 没了"):实例容器注入 LogConfig 20m×2(默认 json-file 无上限,崩溃循环
  每 2s 刷错顶满磁盘);compose 面板同配;微信 crashinfo 崩溃转储 1 天过期清理;
  一键升级完成后清理悬空(<none>)旧镜像并记录释放空间。
- 一键升级"卡死":改异步——立即返回、后台顺序执行、前端轮询进度(n/总数·当前实例);
  镜像统一只拉一次(原每实例各拉一次,受限网络下每次都等停滞超时)。

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-07-06 23:31:24 +08:00
Gloridust
db894cfcff feat(update): 实例镜像落后检测 + 一键升级全部 + 壁纸缺工具友好报错
面板与实例是两套镜像:更新面板不会动实例,用户常"更新了面板、实例还旧"(如设壁纸报 127)。补齐:
- 后端:latestInstanceImageId + instanceOutdated(运行镜像 != 本地最新即落后);
  GET /instances/upgrade-status(落后清单)、POST /instances/upgrade-all(逐个升级落后实例)。
- 前端:管理页顶部横幅「有 N 个实例可升级 + 一键升级全部实例」,每张实例卡加「可升级」角标;
  关于页面板更新后也提示"另有 N 个实例镜像可升级"(更新面板≠更新实例)。
- 壁纸:applyBackground 前置检查 xwallpaper,旧镜像缺失时提示"请先在管理升级实例"而非退出码 127。

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-07-05 01:15:30 +08:00
Gloridust
ed45957b4a feat(update): 开发版允许一键「升级到正式版」
旧逻辑 hasUpdate 需当前版本能解析为语义化 vX.Y.Z,dev-<sha> 开发版永远拿不到更新入口。
现:version.ts 增 isDev(当前非正式版),开发版只要查到任一正式发布即 hasUpdate=true;
About 面板对开发版把按钮/提示改为「升级到正式版」(自更新拉 :latest 即最新发布)。

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-07-05 00:16:19 +08:00
d1y
c9ef07eb56 feat(panel): 桌面壁纸与字体管理
- 上传/应用/清除壁纸,缩略图预览
- 上传/安装/删除字体,fc-cache 刷新
- fontconfig 别名配置 + xsettingsd 实时生效
- 移除 hook-fontconfig,改为重启提示
- 切换 tsinghua 安全更新源
- 安装 xwallpaper/imagemagick/xsettingsd 依赖
2026-06-30 00:17:41 +08:00
Gloridust
8e15556e6f feat(panel): 子账号改用户名(#89)
管理页每个子账号新增「改名」:弹窗输入新用户名(3-20 位字母/数字/下划线,查重),
保存即改登录名;会话以 userId 为准,改名后保持登录、下次用新名登录。

- store.renameUser(查重 + 写入)
- POST /api/admin/users/:id/rename(管理员,格式校验)
- api.renameUser + Admin 的 RenameUser 弹窗

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-06-26 10:25:05 +08:00
Gloridust
335b839e9a feat(dark): 面板/实例统一深色开关(portal 实时切换)+ 修复 KasmVNC 致命崩溃自愈
实例深色不再靠 GTK_THEME(微信 Chromium 内核不吃),改用 freedesktop 桌面 portal:
每个实例常驻 session D-Bus + xdg-desktop-portal(gtk 后端) + dconf(固定总线地址),
面板顶栏主题开关(管理员)统一控制面板 + 实例深色,持久化进 accounts.json,并对运行中实例
docker exec woc-dark.sh 实时切换 color-scheme(微信据 SettingChanged 实时重绘),无需改 env。

- docker/Dockerfile: 装 xdg-desktop-portal(+gtk) / dconf / gsettings / dbus-x11(单独成层)
- docker/autostart: woc_setup_portal 常驻 portal,初始明暗由 WOC_DARK 决定
- docker/woc-dark.sh: 面板经 exec 调用,实时改 gsettings color-scheme
- store.ts: 持久化 desktopDark;docker.ts: envList 读它 + setInstanceDark;index.ts: /api/desktop-theme
- AppShell 主题开关接 setDesktopTheme(含 auto 跟随系统联动);移除 WOC_INSTANCE_DARK env

KasmVNC 客户端 bundle 长跑空闲后偶发 'lastActiveAt' 致命崩溃 → 仅在其致命错误浮层出现时
做一次干净整页重载(安全重连路径,非激进 churn),5min 限 4 次防死循环。

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-06-19 02:11:47 +08:00
Gloridust
f939538113 feat(panel): 面板内「一键更新面板」(自更新 + 失败回滚)
面板本身的更新此前必须去 docker/飞牛手动 pull + 重建。现支持在「关于」里一键更新(仅在检测到
新版时出现,管理员可见):

- 机制:面板先拉新镜像,再派生一个临时 helper 容器(用新镜像 + docker.sock)重建 woc-panel:
  停旧 → 按旧容器配置(env 用「新镜像 baked + compose 注入」合并,保留 Labels/HostConfig/网络)
  用新镜像重建 → 起来 → 稳定运行检查;失败则回滚旧镜像。helper 干完退出。
- 最坏情况(helper 也挂)用户 docker compose up -d 即可恢复(与手动一致)。
- 已本地实测:成功路径(重建后稳定、env/网络/label 保留)+ 回滚路径(坏镜像→回滚救活),
  且全程不影响真 woc-panel。
- 新增 POST /api/admin/version/self-update + api.selfUpdatePanel + 「关于」按钮。

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-06-19 02:11:47 +08:00
Gloridust
94e3400c93 feat: 客户端连接日志 + 自愈放宽预热窗口(避免误打断刚启动的实例)
诊断包实锤:刚创建/重启的实例 KasmVNC 需约 10-15s 预热,期间 nginx 已能回 101 但 ws 接收器
还没就绪(容器日志 0 条 got client connection)→ noVNC 拿到 ws 却收不到 RFB,反复 connecting→
掉线→重连。之前 15s 阈值会在预热期就整页重连/请求重启,反而拖长"正在连接"。

- 自愈阈值 15s→30s,先让预热 + noVNC 自带重连自行连上,不过早打断。
- 新增客户端连接日志(回传服务端,[client] 前缀,与 [vnc] 服务端日志对齐):
  VNC 状态变化(connected/connecting/reconnecting/disconnected)、整页重连、请求重启、回前台重连、
  iframe 加载 —— 下次卡死即可看清"到底是 noVNC 在重连、还是我们的逻辑在重载、还是服务端没起来"。
- 新增 POST /api/instances/:id/clientlog(需访问权,限长)。

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-06-15 22:55:44 +08:00
Gloridust
c0af1d766a feat: 实例卡死自愈——客户端多次干净重连失败即请求重启容器
实测确认:KasmVNC 的 ws 接收器会偶发卡死(nginx 仍能serve 静态页让 noVNC 显示"正在连接",
但新 ws 永远 accept 不了;强刷新、重启面板均无效,只有重启实例容器能恢复)。这是 KasmVNC
基础镜像层的问题,面板无法直接修复,故改为可靠检测 + 自动重启兜底。

- 客户端健康监测(7d9b5ac,依赖可靠的 noVNC_connected class)干净重载 2 次仍连不上后,
  调 POST /api/instances/:id/heal 请求重启该实例(数据保留),再整页重载连到全新容器。
  客户端 + 服务端各 3 分钟限频,防重启风暴。
- heal 接口:需对该实例有访问权(让被卡住的用户能自助恢复,不必等管理员)。
- 放弃 /websockify 合成 WebSocket 探活:KasmVNC 握手挑剔(返回 404),且无法在健康态验证卡死探测,
  改用客户端可靠的连接态信号驱动恢复。

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-06-15 16:23:35 +08:00
Gloridust
9929a72be1 feat(panel): 全局日志系统 + 一键诊断包导出
单实例「日志」只记录该实例日志,无从排查跨实例/容器层面的问题(首个实例创建卡死、
打开实例黑屏不可用、升级失败等)。新增面板级全局日志 + 一键诊断包:

- logs.ts(新):统一持久化日志(面板数据卷,跨重建保留)。实例日志原语从 docker.ts
  迁来;新增 appendPanelLog/readPanelLog、按时间裁剪 filterSince、一年保留 pruneOldLogs、
  时间范围 24h/7d/30d/1y。无 docker 依赖避免循环。
- 仪表化:实例创建(含镜像拉取前后,定位首次拉取卡死)、删除、启停、重启、升级、
  应用安装/更新、看门狗自愈 均写入面板全局日志(同时回显 stdout)。
- docker.ts buildDiagnostics:打包 system.txt(Docker/镜像/系统)+ panel.log +
  instances/<id>.log(容器状态 inspect + 持久日志 + 实时日志)+ containers.txt(全部
  woc-* 容器清单,含残留),手搓多文件 tar.gz(沿用既有无依赖 tar 风格)。
- 路由:GET /api/admin/diagnostics?range=(导出 tar.gz)、GET /api/admin/panel-log?range=;
  启动 + 每 24h 跑 pruneOldLogs。
- 前端:管理页「诊断与日志」区——时间范围(24h默认/7d/30d/1y) + 导出诊断包 + 查看面板日志。

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-06-15 00:48:36 +08:00
Gloridust
7293285d1a feat(panel): 显示构建版本号 + 自动检测新版(Docker Hub/GHCR 红点)
管理界面此前看不到面板版本,也无从知道有没有新版可升。现在:

- 构建时把版本号烤进面板镜像:Dockerfile 新增 ARG/ENV WOC_VERSION(放末尾不
  破坏依赖缓存);release.yml 用 git tag 注入(vX.Y.Z,手动触发为 dev-<sha>),
  仅面板镜像消费;build-local.sh 支持 --build-arg(默认 dev)。
- 后端 version.ts:best-effort 查询 Docker Hub 与 GHCR 上 woc-panel 的语义化
  标签取最大值,与当前版本比对;启动后 4s 首检 + 每 6h 复检 + 接口惰性触发,
  失败静默(离线/被墙/私有源不报错、不显红点)。命名空间从 WOC_WECHAT_IMAGE 推断。
- 接口:GET /api/version(任意登录用户读缓存)、POST /api/admin/version/check
  (管理员手动重查)。
- 前端:管理页「关于」卡显示当前版本/最新版/升级提示/检查更新/发布日志链接;
  侧栏「管理」入口在有新版时点红点(仅管理员)。

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-06-14 22:40:17 +08:00
Gloridust
1c230316ed feat(v1.2.0): 自定义实例图标——内置精选 + 上传裁剪
- AppIcon:内置精选平台图标(微信/Chromium/Telegram/小红书/抖音/B站/微博/知乎/YouTube/通用)+ ICON_CHOICES。
- 编辑器(管理菜单「图标」):选内置图标 / 上传图片用 react-easy-crop 方形裁剪→128px PNG / 恢复默认。
- 后端 setInstanceIcon + /api/admin/instances/:id/icon(仅 admin;icon=builtin:<key>/data:图片/空,限 ~225KB)。
- 新增依赖 react-easy-crop。

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-06-14 19:41:40 +08:00
Gloridust
1ffc6d7e1d feat(v1.2.0): 实例头像由首字母改为按应用类型的图标(自定义图标铺底)
新增 AppIcon.tsx(InstanceIcon + 内置 SVG 图标:微信/Chromium/Telegram/通用),侧栏与主页
卡片头像改用它(按 appType 出默认图标;data: 图片 / builtin:<key> 优先)。
新增 Instance.icon 字段 + publicInstance 下发,为「自定义图标(内置选择 + 上传裁剪)」铺底。
侧栏/主页标题「微信实例」→「实例」,主页副文案按应用名泛化。

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-06-14 19:01:03 +08:00
Gloridust
1da52bfb96 feat(v1.2.0): UI 按应用类型泛化(不再到处写死「微信」)
新增 APP_PROFILES(label/needsInstall/enterHint/updateLabel)+ appProfile()。
- 实例卡片:状态副文案、"进入实例"提示、安装/更新按钮均按 appType 显示;Chromium 已烤进镜像
  (needsInstall=false)故不显示"下载安装/更新",状态直接"已就绪"。
- 桌面页:连接提示语用 enterHint(微信=扫码登录,Chromium=直接使用);安装中/未安装提示、iframe
  标题、文件传输/剪贴板/输入条文案改为应用名或通用"应用/桌面"。
- 列表区"微信实例"→"实例"、空状态泛化。

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-06-14 18:19:03 +08:00
Gloridust
b7fd778ab1 feat(v1.2.0): 多应用平台——创建实例时选 微信/Telegram(+Chromium/自定义占位)
镜像层(向后兼容,微信路径零改动):
- app-defs.sh:按 appType 给出 APP_BIN/APP_LAUNCH/APP_NAME(缺省回退微信)。
- app-ctl.sh:通用安装/状态分发;wechat 委托回 wechat-ctl.sh;telegram 下载官方 portable tar.xz。
- autostart:读 /config/.woc-app 选择启动哪个应用,读不到回退微信(老实例零改动)。
- 02-woc-app 钩子:把容器环境 WOC_APP_TYPE 落到 /config/.woc-app(缺则不写→回退微信)。
- Dockerfile:加 xz-utils(telegram 解压)+ COPY 新脚本。

后端:envList 透传 WOC_APP_TYPE(+自定义启动命令);triggerWechat/wechatStatus 改走
app-ctl.sh <appType>(微信行为不变);创建实例路由接受 appType。

前端:新建实例对话框加「应用类型」选择器(微信默认 / Telegram;Chromium、自定义标记"即将支持"禁用)。

本轮 Telegram(x86_64) 端到端可用;Chromium(待 apt 烤镜像) 与 自定义(待上传流) 下一轮。

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-06-14 17:38:15 +08:00
Gloridust
8ab5375ded feat(desktop): 输入法双模式切换(无感 / 转发)+ 深度修复无感丢字
nav 栏可切「无感输入」(直接在微信里打中文)/「转发输入」(底部输入条,默认),偏好持久化。
无感:enable_ime=true,compositionend 捕获中文经 xdotool 转发;并用有序队列把"转发未完成期间"
的后续可见字符 + 回车/退格串行送出,彻底消除"中文走异步、数字走 keysym 抢跑"的"你好123→23"丢字;
队列空闲不干预,英文/数字仍走原生 keysym 零延迟。新增 /api/instances/:id/key(xdotool 单键)。

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-06-14 15:15:05 +08:00
Gloridust
1c34777353 feat(panel): 管理员数据卷管理(整卷备份/恢复 + 文件浏览器)
管理页 → 实例「管理」→ 数据卷(仅 admin)。解决大量用户"把 PC 微信数据迁移上 docker"的诉求。

- 整卷备份:流式打包 /config 为 .tar.gz 下载(大文件不入内存);恢复:上传覆盖回 /config。
  machine-id 存在卷内随包迁移 → 跨 woc 实例恢复可保留聊天记录。
- 文件浏览器:浏览/上传/上传并解压(.tar/.tar.gz)/下载/改名/移动/删除;PC 数据打包上传解压后重启实例。
- 全程在运行中的实例上操作(exec + docker cp,运行容器才可 exec);恢复为全量覆盖,强提示并建议重启。
- 安全:仅 admin;路径严格限制在 /config、禁止 .. 穿越;上传落地为 abc 属主。
- docker.ts 抽出 extractSingleFileFromTar 复用(PAX 头跳过),新增 list/mkdir/move/delete/upload/
  extract/download/backup(stream)/restore;index.ts 加 9 个 /volume 管理路由;前端 VolumeManager 弹窗
  + 线性 SVG 图标(替代渲染不一致的 emoji);新增 doc/数据卷管理.md。

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-06-13 22:01:41 +08:00
Gloridust
8fd147bccc fix(P0): unique persistent machine-id per instance + manual reset
All instances shared the image-baked machine-id (a67bf09f...), so Tencent
saw every WechatOnCloud account worldwide as one "device" — a textbook
device-farm signal triggering risk control and the forced-logout loop
reported across old and new versions.

- docker/woc-identity.sh: new /custom-cont-init.d/00-woc-identity hook —
  generates a unique machine-id on first start, persists it in the data
  volume (survives restart/upgrade/recreate), writes /etc/machine-id +
  /var/lib/dbus/machine-id, removes /.dockerenv. Existing instances get a
  fresh unique id on first upgraded start (volume lacks the file).
- regenInstanceMachineId + POST /api/admin/instances/:id/regen-machine-id:
  roll a brand-new device id and restart, for accounts re-flagged by risk
  control. Gated on the hook being present (old image → instructs upgrade).
- Admin 实例卡片「安全」弹窗新增「重置设备 ID 并重启」。

Verified: two fresh containers get distinct machine-ids; id persists across
restart; regen (rm persisted file + restart) yields a new persistent id.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-06-06 01:41:45 +08:00
Gloridust
ba8fe96486 feat: delet old docker 2026-06-04 17:42:06 +08:00
Gloridust
d99c3b8bf6 fix ram 2026-06-04 17:33:00 +08:00
huglemon
6df7d8c7cf fix: add CJK IME paste fallback 2026-06-03 00:08:47 +08:00
Gloridust
4f582f2c5e fix Chinese input & copyboard & log 2026-06-02 19:46:28 +08:00
Gloridust
49b785ff9f fix autostart 2026-06-01 19:42:35 +08:00
Gloridust
1555e60072 update ui and fix vnc v1.1.0 2026-06-01 17:31:57 +08:00
Gloridust
17ba168764 feat: 音视频/文件传输 + 产品 UX 改进 + 镜像源可切换
媒体链路(生产 HTTPS 下可用,含降级)
- 音频(听):PulseAudio + KasmVNC 工具条,开箱即用
- 麦克风(说):virtmic 管道源已就绪,运行时需 HTTPS(非 HTTPS 前端提示)
- 摄像头(视频):docker.ts 条件化 v4l2 设备直通 + 加 video 组;无设备/无 HTTPS 时优雅降级,音频麦克风不受影响
- WOC_VIDEO_DEVICES 显式指定或经 /host-dev 自动探测

文件传输(原生拖拽)
- 面板侧拖拽上传 + 下载:dockerode putArchive/getArchive 到实例 ~/Desktop(持久卷)
- 纯 JS 单文件 tar 编解码(免依赖),文本/二进制均无损;全程走面板鉴权与权限校验

安全 & UX
- 默认密码告警条 + mustChangePassword 追踪(兼容旧账号文件迁移)
- 会话过期(401) 自动跳登录;桌面连接 loading 态
- 停止/未创建实例一键启动(新增 /api/admin/instances/:id/start)
- 统一牛奶布艺弹窗 + Toast,替换 Admin 原生 alert/confirm/prompt
- 密码可见切换;实例重命名;退出二次确认;空状态改用品牌终端图标

其它
- gen-icons 生成终端风格图标(此前仅空白绿块,影响 Docker/CI 产物)
- 镜像源可切换 WOC_IMAGE_PREFIX(国内反代/ACR);品牌名「云微」
- 文档:.env.example / docker-compose 增加音视频(v4l2loopback/HTTPS)、镜像源、视频设备说明

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-05-31 10:56:33 +08:00
Gloridust
5c5e9c8540 update 2026-05-29 22:00:23 +08:00