Releases
v2.2.10
Compare
Sorry, something went wrong.
No results found
Added
WebUI 备份功能:配置目录备份/恢复到 S3 兼容对象存储(Cloudflare R2 / AWS S3 / MinIO) (fork). 侧边栏新增「备份」页(设置表单 + 上次备份状态 + 立即备份 + 云端备份列表的恢复/下载/删除)与 8 个 API 端点(GET/POST /api/backup/config、POST /api/backup/test、POST /api/backup/run、GET /api/backup/list、GET /api/backup/download、POST /api/backup/restore、POST /api/backup/delete)。实现为两个新模块:webui/s3.js——最小化 S3 客户端(手写 AWS SigV4 签名 + node:https,仅实现备份所需的 Put/Get/List/Delete/Test 五操作,path-style 寻址,不引入 5MB+ 的 AWS SDK;R2 region 固定 auto);webui/backup.js——备份服务。备份设置存 <userBasePath>/backup.json(独立于主配置树 :凭据不随 GET /api/config 泄露、不被整树回写流程篡改,也不进备份本体)。备份内容为整个配置目录 tar.gz 打包(自动排除 logs/、xray/、running.json、*.pid、*.log、*.bak-*、backup.json 本体;GNU tar 与 bsdtar 的 ./ 前缀差异用双份排除模式兼容),对象命名 <prefix>/<hostname>/<时间戳>.tar.gz——多台机器共用同一 bucket 互不覆盖,保留份数(keepLast,0=不清理)也按主机前缀清理最旧;可选 AES-256-GCM 加密(scrypt 派生密钥,DSBK 头含 salt/iv/tag,备份含 CA 私钥强烈建议开启 ),恢复时校验 gzip 魔数与 tar 完整性、当前 config.json 先留 .bak-restore-<ts> 安全副本再解包覆盖,needsRestart: true 提示重启生效(前端接既有 POST /api/service/restart)。定时备份为插件启动的 10 分钟周期检查(到达 intervalHours 间隔且配置完整才执行;schedule.enabled 每 tick 实时读盘,改设置无需重启)。secret 掩码语义:GET 返回 ******,POST 回传掩码或不传即保留旧值(口令传空串显式清除);POST /api/backup/test 支持「先测试再保存」——body 携带未保存设置,掩码 secretAccessKey 自动回退已保存值。测试 :新增 test/backup.test.js 21 用例(SigV4 对本地假 S3 HTTP 服务的真实签名请求断言——Authorization 格式/credential scope/signedHeaders/payloadHash/path-style URI 编码/查询串排序/403 错误透传、加解密往返+防篡改、打包排除清单实测、保留份数按主机隔离清理、恢复回环+安全副本、口令缺失/错误提示、非法 key(跨前缀/..)拒绝、调度 tick 到期执行/未到期跳过/关闭后不执行)+ webui.test.js 备份路由组 9 用例(mock 注入 context.backupApi(同 xrayApi 注入模式):脱敏读写、数组 body 400、400 BACKUP_NOT_CONFIGURED 与 502 BACKUP_UPSTREAM_FAILED 错误映射、恢复 key 缺失 400、下载流 attachment 头、未知备份路由 404 兜底;期间抓出真 bug——GET /api/backup/list 路由漏 await 异步 listBackups() 把 Promise 序列化成 {})。webui 70 passing、主套件 193 passing。真实 Cloudflare R2 全链路实测打通:控制台创建存储桶(dev-sidecar)→ 创建最小权限 Account API 令牌(对象读和写、仅限该桶)→ WebUI 配置(测试连接 → 保存 → 立即备份)→ R2 控制台与 WebUI 列表双侧确认加密归档上云;操作教程见 doc/wiki/备份到Cloudflare R2使用说明.md(含新机灾备与常见问题)。Windows 兼容(三平台发布 CI 直接暴露的坑):GNU tar 会把带盘符的归档路径 C:\... 误判为远程主机语法(Cannot connect to C: resolve failed),tar 的 -f 参数统一改用裸文件名 + cwd 定位(GNU tar / bsdtar 双兼容),修后三平台 CI 全绿。
export 节点导出新增 alive=true:live observatory 实时存活过滤(下游反馈) (fork). 下游(CharmHyper_Register)实测:available=true 过滤出的 351 个"可用"节点随机抽 60 个全部 SYN 挂起——缓存 delay 来自 Stage3 探测快照、最长落后一天,available 只保证"某次探测时活过",不等于"现在活着";同一时间点 observatory 实时探测 20/20 alive 且手动起独立 xray 出口验证通过,但这些实时活节点因缓存 delay 过时沉在 smart 排序(delay 升序)尾部,顺序遍历的消费方根本取不到。新增 alive=true 查询参数:从 live xray metricsPort 的 /debug/vars 读 observatory 实时状态,经插件 getLiveNodeFingerprints() 的 tag→fingerprint 映射(无需解析 outbound)关联缓存行(readCacheEntriesByFingerprints)——meta.delay 用 observatory 实时值排序与展示(覆盖过时的缓存 delay),meta 新增 lastTry(最近探测 unix 秒时间戳,判断存活数据新鲜度);可与 available(连败阈值)/maxDelay(按实时 delay 判断)/country/owner/sort/shuffle/limit/offset 组合,total = 过滤后存活总数;xray 未运行时 HTTP 200 + total=0 + reason=xray_not_running(data 为对应 format 的空结构)。消费方可从"拉全池本地 shuffle 逐个实测(平均 25 个命中)"改为 alive=true&shuffle=true&limit=30 轻量拉取。测试 :webui.test.js 新增 8 用例(mock /debug/vars + fingerprint 映射:实时 delay 覆盖与排序、available 连败阈值、maxFailureStreak 放宽、maxDelay 实时过滤、country 过滤、offset/limit 分页、shuffle 组合、xray 未跑空集+reason)。
WebUI 配置页图形化编辑 + 侧边栏布局:textarea 嵌入 JSON 全部替换为结构化表单 (fork). 规划见 doc/webui-config-refactor-plan.md。顶部标签页改为左侧侧边栏(品牌区 + 导航 + 底部版本号/WS 连接状态点,窄屏回退横条);配置页重构为左侧 14 分区导航 + 右侧表单(加速服务/拦截规则/Xray 插件/DNS/域名白名单/预设 IP/代理排除/梯子/网络检测/Git·Node·Pip/远程配置/WebUI/应用与日志/原始 JSON 只读),控件经 data-path 路径绑定直写 draft(增删行才重渲染,不打断输入),带未保存更改计数、放弃更改、每分区恢复默认。拦截规则(server.intercepts)做三级结构化编辑器:域名列表(搜索/添加/重命名/删除,metaInfo 过滤,config.json 有覆盖的域名带"用户"标记)→ 路径正则行(new RegExp 实时校验着色,失焦重命名)→ 动作字段编辑器——proxy(+backup/test)、sni、redirect、abort、success、script、tampermonkeyScript、请求/响应头替换行编辑([remove] 哨兵提示)、缓存族数值+单位下拉(读时识别已用键,cacheSeconds/Minutes/Hours/Days/Weeks/Months/Years)、desc/remark,未知键折叠"高级字段"逐键兜底编辑不丢数据;值可为 null 墓碑(屏蔽默认/远程继承)→ 显示"已屏蔽"标记可恢复继承。全部修改持久化到 ~/.dev-sidecar/config.json(用户覆盖层,合并优先级最高),语义与 GUI configApi.save 完全一致——删除远程/默认配置来源的条目时 doDiff 写 null 墓碑、合并时剥除(已用真实 configApi 在隔离 HOME 验证:删除远程来源域名 → config.json 落 null → 重载后生效配置消失);remote_config_personal.json5 不被程序改写,保持手工注释。被 config.json 覆盖的字段/域名显示"用户"来源徽章(新端点 GET /api/config/user)。保存后若 plugin.xray.*/server.setting.xrayPort 变更且 Xray 运行中,自动调 POST /api/xray/restart(GUI applyBefore 同款)。新端点:GET /api/config/user(用户覆盖层+远程元信息)、POST /api/config/reset(分区恢复默认,key 白名单正则防任意路径)、POST /api/xray/restart;api() 携带 Bearer token + 401 弹框重试(远程 token 访问此前无法保存);routes.js 静态路径加仓库内回退(开发态无需安装)。测试 :webui.test.js 新增"webui config view / reset / restart routes"组 5 用例 + write-ops 组改造 4 用例(整树/局部树 400、configFromFiles 剥离断言、intercepts 子树替换断言),webui 61 passing;生产 31182 真机全链路验证(PUT 无损回环 config.json 落盘前后完全一致、编辑-放弃回环、来源徽章对真实 config.json 命中、xray restart 端点 8s 恢复 20 节点且 sticky 正确 re-apply)。deb 重新构建部署:electron:build --linux deb → dpkg -i。
Fixed
修复 export shuffle=true 在候选池小于 limit 时完全失效(下游反馈) (fork). 下游实测同参数两次调用(间隔 31s,已过 30s 响应缓存窗口)返回顺序完全相同,与 shuffle=false 行为一致;配合 available=true 的过时 delay 数据,固定顺序导致顺序遍历的消费方反复在同一批 smart 排序头部的死节点上空转(3 轮 × 30 节点全部失败)。根因:打乱逻辑带 result.length > limit 守卫——仅当候选数大于 limit 才执行 Fisher-Yates,而消费方场景是 available 池 351 条 < limit=500,打乱被整体跳过,smart 排序固定原序返回(下游猜测的"候选池 ≥ 2N 时抽样被跳过"方向相反:是池子 ≤ limit 时不打乱)。修复:shuffle=true 无条件打乱,候选池不足 limit 时同样全量随机排序。真机以消费方原始参数(available=true&maxFailureStreak=5&sort=smart&shuffle=true&limit=500)复现:三次调用首节点各不相同(其中一次恰好随机到反馈文档中的原固定首节点 vless://58c1b245-...,证明同一池子仅随机化生效)。测试 :webui.test.js 回归用例——4 节点池(< limit=100)连续 12 次 shuffle=true 调用断言出现 >1 种排列(4 节点 24 种排列,12 次全同序概率 ~1e-15)。
修复 WebUI 配置保存的删除静默失效:PUT /api/config 由 merge 改整树 save 语义 (fork). 原实现 PUT /api/config → globalConfig.update(body):lodash.mergeWith 无法表达"删除键"——前端删掉的域名在 merge 阶段复活、doDiff 视为无变化不落盘,任何删除操作都静默失效 (GUI 不受影响,它直接调 configApi.save(整树));PUT /api/intercepts、/api/presetiplist 同病(对象子树 merge 删除失效),PUT /api/xray/rules 因数组整体替换恰好幸存。修复:PUT /api/config 改 configApi.save(整树)(body 必须含 app/server/plugin 顶层键,局部树 400,防未携带子树被墓碑化误删);其余三者改为 clone 当前树 → lodash.set 整体替换子树 → save,删除经子树替换正确墓碑化。配套两处运行态剥离:GET /api/config 剥离 Xray 自动注入条目(desc === 'Auto-injected by Xray Plugin')与 configFromFiles 调试快照(模块加载时烘焙进默认配置的合并副本,不剥离则前端把运行态当用户配置回写产生幽灵 diff);PUT 时恢复 configFromFiles 快照再 save(真实 doDiff 以含此键的默认配置为基线,缺失会被墓碑化为 configFromFiles: null 写进 config.json——GUI 的 draft 未剥离故无此问题,WebUI 的 GET 剥离造成的不对称在此补齐)。测试 :webui 61 passing、主套件 172 passing 无回归;真机 PUT 无损回环验证 config.json 落盘前后字节级一致。
Changed
工作区包版本号 bump(core/gui/mitmproxy/cli 2.2.9 → 2.2.10),/api/version 随之生效 (fork). 下游靠版本号探测 export 能力(v2.2.9 已把 /api/version 对齐 core package.json 实际版本,此前运行中服务报旧版本号导致下游误判能力缺失),本次 export 契约新增 alive=true 与 shuffle 行为修复将随 2.2.10 发布生效;deb 文件名随之变为 DevSidecar-2.2.10-amd64.deb。webui 测试套件 74 passing(+9)、主套件 172 passing 无回归。
WebUI 探测页出站节点详情表"地址/端口"列改为"服务器/出口"列 (fork). 20 个 live 节点实测仅 3 个出口 IP(16 个共享同一 OVH 落地)——入口地址各异的 CF 中转变体让旧表"地址"列看起来每个节点出口都不一样,产生误导。"地址"(入口连接点)与"端口"合并为"服务器"列(IP:端口 形式),腾出的"出口"列直接显示缓存元数据的 egress IP(为空显示 -),多节点共享出口一眼可见;表排序键 addr/port 同步改为 server/exitip。出口 IP 数据后端 /api/xray/nodes 的 nodeMetadata 本就返回(无需后端改动),仅前端 renderStage1Table 消费。已部署本机实测:出口列 51.159.163.185/51.15.243.182 交替出现,集中性直观可见。Stage1 卡片"当前选择"右侧同主题新增"出口地址"格,显示当前 balancer 选中节点的 egress IP(随轮询刷新)。
You can’t perform that action at this time.