Repository navigation
Releases: devShuai/specus
Release list
v2.1.0
Specus v2.1.0 是一次网页界面版本:管理后台与公开页面改用设计规范自己的组件重写,互传页重新设计。服务端、客户端的协议、配置与数据库都没有变化,v2.0.0 的客户端与本版服务端互通。
管理后台
- 外框:
- 侧栏是浮起的玻璃面板,可以收起成只剩图标,底部是「跟随系统 / 浅色 / 深色」外观切换。
- 顶栏透明,搜索框找页面与常用操作(
/或 Ctrl/⌘ K 打开,方向键选择,回车进入),右上角是帮助与个人菜单的圆按钮。 - 页面上方是同组页面的区域页签,例如客户端、消息、端口映射、HTTP 路由、客户端下载之间一键切换。
- 手机上侧栏收进左侧抽屉。
- 每个页面按同一结构排布:页头(标题、一句说明、页面操作)→ 视图页签 → 带区块标题的内容。数字卡只放在数字是重点的页面顶部;表格在手机上叠成一条一条;列表上方是玻璃筛选条和结果数。
- 时间写法统一:24 小时内写「3 分钟前」,悬停显示完整时间,更早的写
2026-10-23 16:02;用时写「3 分 20 秒」。状态一律是带文字的标签,出错提示写原因和下一步。 - 工作台:待处理问题逐条写清下一步与受影响的服务;常用与最近打开是紧凑的行;全部服务是带类型与设备状态的表格。
- 概览:一排数字卡;日流量图可以在图表和表格之间切换,悬停或用方向键查看每天的数值;客户端流量排行带占比条。
- 流量使用:HTTP 记录用玻璃筛选条检索,仍是点「搜索」或回车才发起查询;详情对话框、TCP 帧与媒体采集列表同样改版。
- 连接记录:按客户端、结果与时间范围筛选,结果标签与在线时长,分页。
- 客户端:带编号的接入步骤,只按已读取的数据标记完成与下一步;接入凭证与实例表格,危险操作放在最后。
- 消息:左侧客户端列表、右侧对话;附件是文件行,上传时显示进度。
- HTTP 路由:发布表单的访问范围改为「受保护访问 / 公开访问」两张选项卡片;连通性检查按「已配置 → 设备在线 → 目标可达 → 访问成功」逐段显示,停在哪一段就写那一段的下一步;分享与编辑对话框随之改版。
- 私有组网:顶部四张数字卡(全局开关、设备、会话、直连占比),下面是设备、服务、出口分流、活跃会话、ACL、NAT 诊断的视图页签;NAT 诊断分阶段给出结果。
- 系统管理、产品指标、客户端下载与帮助文档同样改版;帮助文档的快速开始是编号步骤,代码块带复制按钮,常见问题可以折叠。
公开页面
- 落地页保留引水渠主视觉,下面是能力卡片、拓扑与原理卡片;去掉了背景网格、扫描线与数据包动画。
- 登录 / 注册对话框改为 44px 的大输入框、登录与注册的分段切换、整宽主按钮,错误以提示条显示。登录方式、OIDC 流程与校验不变。
- 客户端下载页先给出与当前设备匹配的安装方式(macOS 为 Homebrew 命令卡片),展开后每个平台一张表格,带架构、版本、大小与可复制的 SHA-256。
- NAT 检测:检测球保留,结果、难度量表与验证链路改为卡片与分阶段列表,高级设置可以折叠。
- 临时 HTTP 分享的落地页改为居中的状态卡片,写明原因和下一步。
互传页重新设计
- 页面就是三步:选择接收方 → 选择内容 → 发送。
- 接收方是设备卡片,显示名字、末 4 位标识与「直连 / 中继 / 连接中 / 离线」标签,可以用方向键选择。正在寻找时显示「正在寻找附近设备」,发现失败时给出重试与输入配对码。房间里只有自己时,二维码与配对码直接显示在页面上。
- 选择内容分「文字与链接 / 文件 / 多人白板」:
- 文件先进入待发送列表(类型图标、大小、移除),按发送按钮才发出;发送按钮写明会发生什么,例如「发送 3 个文件给 Beta · 9ef7」,不能发送时写明原因,例如「先选择接收设备」。
- 文件可以拖到页面任意位置,遮罩会写明要发给谁,Esc 取消;在页面任意位置粘贴只加入待发送内容,不会自动发出;文字框里 Ctrl/⌘ Enter 发送。
- 传输任务直接列在页面上,显示进度、速度、剩余时间与已用时间,可以取消或重试;可续传的传输用同样的样式。原来的「传输任务」弹窗与设备操作面板不再需要。
- 收到的文件和文字进入「收到的内容」,带数量、发送方与时间,可以保存、预览或复制;收到新内容时有提示。
- 手机上各部分自上而下排列,发送按钮固定在底部,触控目标不小于 44px,320px 宽度不出现横向滚动。
- 网络、协议、加密、分块续传、配额与权限逻辑没有改动。
升级说明
- 只需升级服务端即可用上新界面:Java、Go、.NET 服务端包内置管理后台与公开页面。C 服务端从
SPECUS_STATIC_ROOT提供页面,需要指向本版构建出的前端;用 OpenResty 托管静态文件的部署需要换上本版的前端文件。 - 客户端不需要升级。v2.0.0 与本版的 Java、Go、.NET、Android 客户端行为一致。
- 互传的行为变化:选择文件后不再立即进入发送确认,而是先进入待发送列表,点发送按钮才开始;与升级前打开的旧页面互传不受影响。
验证与已知限制
- 前端单元测试 676 项;产品与互传的浏览器回归分别 12 项与 29 项(新增键盘发送、页面任意位置粘贴与拖放、待发送时离开页面的提醒等检查),均在 Chromium 中运行。页面在 1440 与 390 宽度、浅色与深色下逐页检查过截图。
- Safari、Firefox 与真机手机浏览器没有做人工验收。
- 专业流程图编辑器的页面没有改版;流量页的媒体播放器仍用原来的图标;TCP 帧列表仍没有检索条。
- 其余已知限制与 v2.0.0 相同,见 v2.0.0 发布说明。
- 沿用全端发布流程;发布不代表已部署到运行中的服务器。Homebrew cask 在 devShuai/homebrew-specus 中另行更新。
What's Changed
- Rebuild the web pages on the Liquid Glass components and redesign 互传 by @devShuai in #354
- Release v2.1.0 by @devShuai in #355
Full Changelog: v2.0.0...v2.1.0
v2.0.0
Specus v2.0.0 是 v1.2.6 之后的第一个正式版本,包含此后合入 main 的全部改动。原计划的 v1.2.7 没有发布,它的出口分流一期内容并入本版,版本号从 1.2 升到 2.0。本版的主体是 Peer 出口分流(IPv4/IPv6 地址与网段、域名规则与系统 DNS 接管)、四个界面统一改版、服务工作台与 HTTP 发布相关的新能力,以及一批 Peer Mesh、账号授权与数据库修复。控制协议仍为 v2,帧格式不变;需要两端都升级的能力见「升级说明」。
界面全新设计
- 四个界面改用同一套设计:浅色毛玻璃材质、唯一的系统蓝强调色、大圆角、胶囊式标签页与状态标签、系统字体,支持浅色与深色。
- 管理后台及其公开页面(互传、客户端下载、NAT 检测、登录落地页):悬浮玻璃侧栏,每个面板以 30px 页头开始,表单标签放在输入框上方,提示改为深色玻璃浮层;菜单里的 emoji 换成线条图标。
- CLI 本地管理页(Go、Java、.NET 共用同一份页面):新的玻璃侧栏、卡片与分段控件,跟随系统深色模式;768px 以下改为顶部标签栏。页面行为与 CSP 不变。
- Windows 桌面客户端(WPF)与 Android 客户端按同一套设计令牌改换样式与布局,功能与绑定不变:WPF 改为悬浮侧栏、胶囊页签与卡片,保留原有的深浅主题切换(玻璃只是半透明色,没有背景模糊);Android 改为卡片、胶囊分段切换与状态标签,跟随系统深色模式。
- 去掉内置的 Inter 字体,改用系统字体栈。各端令牌的位置与改界面时的规则见 界面设计系统。
Peer 出口分流
- 消费端按规则把指定目标的流量经已授权的对端设备(出口)访问,应用无需逐个配置代理;未命中规则的流量照常从本机出去。Java、Go、.NET 客户端都可作为消费端与出口;消费端支持 Linux、Windows、macOS,Android 不提供出口分流。关联 #42。
- 规则写在客户端配置的
peerEgressRules,三端共用;动作分egress、direct、block,前缀更长者优先,单条规则可停用。保存规则与启用接管分开:总开关peerEgressEnabled默认false,关闭时规则只保存、不接管,config validate、启动日志与状态都会明确提示。 - 出口由服务端租户总开关与每台设备的出口策略共同控制,目的规则默认全部拒绝,并与基础 Peer ACL 取交集;回环、链路本地与云元数据、组播广播、组网网段与本部署的控制端点永远拒绝。服务端保存策略时按出口的读法校验目的规则(#99),策略变更立即推送给在线设备。
- 命中规则而出口不可用时阻断,不回退到本机直连:TCP 立即复位,UDP 收到主机不可达,已建立的连接在出口离线或规则改动时被复位。出口未被提供给本机、对端运行的客户端不支持出口时同样阻断并说明原因;服务端不下发出口目录时提示服务端可能过旧(#121)。
- 路由接管只写运行期路由表(Linux
ip route,Windows ActiveStore,macOSroute,重启后不存在),不改防火墙与内核转发参数;只装精确前缀,前缀已被占用时拒绝并报告占用者,不抢占。虚拟网卡就绪后才应用,每 5 秒按对端、中继与控制连接重算,并对照真实路由表补回消失或指错的条目;控制连接断开只挂起,不撤路由、不关网卡,真正退出时才撤回;崩溃留下的路由在下次启动时按安装记录收回。 - 出口用用户态连接栈终结连接、用普通 socket 连接目标,不做内核转发;Windows 与 macOS 上出站 socket 绑定到隧道之外的接口,Linux 上打
SO_MARK 0x5350。 - 出口到消费端方向遵守消费端通告的接收窗口,每流有发送预算,并对目标 socket 施加背压,大响应完整送达(#74);租户开关关闭等撤权后,已建立的流立即被切断(#75);RTT 取样按 Karn 规则,丢包时不会长时间停滞(#108);消费端立即复用刚关闭连接的源端口时,新连接不必等 SYN 重传(#256)。
- 出口按消费设备限制新建流速率(可突发 128 条,之后每秒 64 条,#119),并向服务端上报计数(#125);消费端流表有界,结束或空闲的流会被回收(#102)。
- 管理入口:管理后台「私有组网 → 出口分流」页(总开关、出口策略与活动,#97);Windows 桌面端「出口分流」页(规则、接管开关、按配置预演与连通测试、运行状态,#96);CLI
egress、egress rules|rule …、egress enable|disable、egress test,以及本地管理页的「出口规则」页与出口状态面板(#98)。 - 使用与排查见 出口分流使用说明,线协议见 peer-egress.md。
出口分流:域名规则与系统 DNS 接管
- 打开
peerEgressDnsTakeover(默认关闭,需同时打开peerEgressEnabled)后,规则可写精确域名或*.example.com。命中的查询由消费端用 fake-IP 应答(默认池198.18.0.0/15),流量到达时把域名交给出口,由出口在自己的网络里解析、授权并连接。不打开时域名规则照旧被拒绝,不会在启动时解析成 IP。 - 出口策略新增按名字授权的
domainRules(#126)。出口解析出的地址仍要过永远拒绝清单与目标范围,解析到元数据或内网地址的名字照样被拒。 - 这是整个功能里唯一修改系统设置的部分:Linux 经 systemd-resolved 或改写
/etc/resolv.conf,macOS 用networksetup,Windows 添加一条 NRPT 规则。改动前写事务日志~/.specus/egress-dns-journal.json,退出时改回,被强杀后在下次启动或执行egress dns restore时回滚。开关与状态用egress dns enable|disable|status|restore。 - 可识别边界:应用自带 DoH/DoT、使用系统缓存或直接硬编码 IP 时,域名规则不会命中,这类流量只能靠 IP/CIDR 规则覆盖。规范见 peer-egress-dns.md。
出口分流:IPv6
- 消费端规则与出口策略的目的规则都可写 IPv6 地址与前缀,服务端按 RFC 5952 规范形式保存(#243);名字没有 A 记录时出口按 AAAA 记录拨号(#244)。
- 三个客户端都实现了消费端 IPv6 数据面(#245):设备的 IPv6 地址由组网 IPv4 推出(
fd53:7065:6375:7300::/96),IPv6 包原样经 SPEG1 交给声明了ipv6PacketCapable的出口;路由接管、旁路、漂移修复与明确失败按地址族分开进行,egress test接受 IPv6 地址。 peerMeshMtu低于 1280 或设备地址没能配到虚拟网卡上时没有 IPv6 数据面,IPv6 规则以EGRESS_RULE_IPV6_UNSUPPORTED不生效,IPv4 不受影响。fake-IP 的 DNS 应答对 AAAA 仍回 NODATA;组网设备之间仍只走 IPv4。
Peer 组网修复
- Go 与 .NET 服务端此前转发信令时丢掉
sourceKeyEpoch:经这两个服务端的任意两台设备能建立会话、探通直连路径,但数据一个字节都过不去。Java 与 C 服务端不受影响(#72)。 - Go 客户端在 Linux 上此前读不到虚拟网卡的任何数据包(网卡显示 UP 但不交付);.NET 客户端在 Linux 上释放后立即重建同名网卡偶发
EBUSY(#72)。 - 四个服务端在设备离线后向同租户对端推送花名册;Go 与 .NET 服务端不再因信令投递不到而断开发送方的控制连接(#72、#169)。
- Go、Java、.NET、Android:对端重启后忘掉旧路径,改用新进程的地址;直连健康时不再因中继探测在两条路径之间来回切换。Go 客户端在组网未运行时收到会话信令不再崩溃(#136)。
服务工作台与 HTTP 发布
以下各项来自 #38,各有独立契约,四个服务端(Java、Go、.NET、C)与管理后台都已实现:
- 服务工作台(#143):常用服务、最近打开与由现有列表推导的待处理问题,按登录身份保存在服务端;管理后台登录后默认进入工作台。
- 服务连通性检查(#135、#140):对单条 HTTP route 显式发起一次有界检查,按「已配置 → 设备在线 → 目标可达 → 访问成功」逐段给出结果码;不带凭据、不读响应体、不写流量明细,并有限流。见 service-connectivity-check.md。
- 临时 HTTP 分享(#144):为受 Basic 保护的 route 签发有效期必填、可撤销、带审计的访问链接,走独立的
/http-share/{shareId}/路径;默认只读,令牌只存哈希,撤销后下一次请求返回 410,在途流约 2 秒内被切断。 - 产品指标(#146):默认关闭,由租户管理员确认说明后开启;只记录接入里程碑与互传结果的按日汇总计数,不采集凭证、文件名、文本内容或内网地址,按日计数保留 180 天,可随时清除;运营方可用部署级开关整体禁用。
浏览器互传
- 两个浏览器页面之间的直连文件传输支持分块续传(#142):1 MiB 分块逐块 SHA-256 校验,断线后在会话内续传,重复块幂等。接收方选择写入本机存储时,刷新页面后也能续传,单文件上限 2 GiB;只在内存中接收时仍为 128 MiB。发送方刷新后需要重新选择同一文件,内容变化时停止。
- 四个服务端为
/transfer、/download、/nat-detect、/diagram、/diagram-embed提供直接入口,刷新页面或打开带参数的邀请链接不再失效(#288)。
账号、授权与安全修复
- HTTP route 公网入口在没有服务端记录、route 已停用或客户端已停用时一律返回 404(四端,#137);删除或停用 route、停用/改名/删除客户端之后,客户端可靠地停止转发,服务端断开被停用、改名或删除的客户端的连接(#165)。规则见 http-route.md。
- 客户端 token 只登录签发它的账户:Go 与 C 服务端此前按名字解析,客户端被删除后新建同名客户端,旧机器会以新账户身份登录(#178)。
- 管理账号(management-accounts.md):Go、.NET、C 的登录名改为按租户唯一,与 Java 一致(#198);token 带账号键
uid,删除后重建同名账号不会继承旧 token,删除账号时释放其邮箱(#223)并处理其名下数据(#235);账号停用、角色变化或删除时撤销其管理 WebSocket(#249)。 - 公网 502 不再回显客户端 RST 的 reason,其中可能含内网地址(#130);C 服务端管理用户的修改与删除限定在调用者租户内(#139);并发创建分享不再突破每条 route 的数量上限(#150)。
- 依赖:Spring Boot 4.1.1(Spring Framework 7.0.9,#221)、jackson-databind 2.21.7 / 3.1.7(#106)、.NET 服务端固定
System.Security.Cryptography.Pkcs10.0.13(CVE-2026-84008,#284)、Go 模块强制使用已修补的工具链(#271),以及前端 npm 补丁(#288)。
服务端对齐与稳定性
- 控制协议:修正 Go、.NET、C 服务端登录前后的顺序竞态(#164、#170、#179、#188);一帧写失败或中途被取消后关闭连接,不再在半帧之后继续写(#247);会让单条
NAT_CONTROL超过 1 MiB 的映射或 route 在创建、启用时以 400 拒绝,写失败的手动下发按离线返回 409(#208、#231、#239);四个服务端与 Java、Go、.NET 客户端按 RFC 8259 严格读取 NAT 元数据(#350)。 - Direct HTTP / WebSocket:Java 服务端 route WebSocket 的浏览器消息上限从 8 KiB 提到 16 MiB;浏览器不发 CLOSE 就断开时,Java 与 Go 服务端复位设备侧的流(#337、#338、#349);.NET 服务端队列满或收到迟到帧时只重置该 HTTP 流(#175);连通性检查不再断开设备的数据连接(#149)。
- 客户端数据连接:Java 客户端遇到慢上游、或一条流连不上本地目标时,不再影响整条数据连接(#82、#129);.NET 客户端 NAT 流从等待转为活动时不再丢流或乱序(#78);Android 修正 Direct HTTP 响应尾部与 FIN 丢失、流关闭竞态与桥接 I/O 问题(#230、#252、#269、#291)。
- 数据库:Java 服务端修正 SQLite 约束异常与 BLOB 读取、PostgreSQL 迁移与 HTTP 明细列类型、MySQL/MariaDB 行宽与 LOB 列类型;.NET 服务端修正 MySQL、MariaDB、PostgreSQL 的初始化与迁移(#278、#280、#282),CI 用真实的 MySQL、MariaDB、PostgreSQL 测试;Go 服务端按 Java 的方式保存并展示 HTTP body(#210);.NET 与 C 服务端给已存在的 Elasticsearch 索引补上 binary body 映射(#204、#215)。
- CLI:状态文件写入失败后每秒重试,不再永久停止发布(#109);Go 客户端在 Windows 上改用 ACL API 检查文件私有性,不再每秒启动 PowerShell(#95)。
C 服务端(实验性)
- 继续按 Java 全量对齐(#35):OIDC 用 JWKS 校验 ID Token 并签发本地 token(#145),客户端登录 nonce 防重放与登录响应
nettyTls(#133),Direct WebSocket 完整 SWS2 状态机(#122),以及 NAT 流语义、媒体采集、互传、Peer Mesh 与 TURN、管理 API 清单的逐项对齐。 - 新增 Redis 经 TLS(
rediss://)与 Sentinel 的协调(#341)、/actuator/metrics(#342)、控制连接频率限制(#348)。Java、Go、.NET、Android 客户端经 C 服务端的端到端测试已进入 CI。 - #35 仍未完成,C 服务端不作为 Java 服务端的完整替代。
升级说明
- 出口分流需要服务端与消费端、出口两侧的客户端都升级到本版。旧客户端登录时不声明出口能力,服务端不会给它下发出口策略,不影响其既有组网与服务共享。
- 经 Go 或 .NET 服务端的 Peer Mesh 数据面需要升级服务端才能连通(见「Peer 组网修复」)。
- 服务连通性检查需要设备运行本版客户端,旧客户端只能得到「无法判定」。分块续传需要两端都是新页面;与升级前打开的旧页面互传时,128 MiB 以内走旧流程,更大的文件被取消并提示对方刷新。
- 默认关闭:出口分流(租户开关与消费端
peerEgressEnabled)、DNS 接管、产品指标。 - 行为变化:没有服务端记录的 HTTP route 不再按公开处理,一律 404,只保留 C 服务端的
SPECUS_HTTP_ROUTES;删除仍拥有客户端或接入凭证的管理账号返回 409,需先删除或转移,目前没有转移接口(#237);非默认租户中新建的管理账号必须在登录框填写租户 ID,升级前已有的账号不填租户仍可登录。 - 数据库结构在启动时自动迁移。Go、.NET、C 服务端上,同一租户内若有两个管理账号的登录名在去首尾空白、转小写后相同,迁移拒绝启动,需先处理。升级前签发的管理 token 在过期前仍然有效,续期后带上
uid。 - 出口消费端需要创建虚拟网卡(
peerMeshDevice不能是默认的noop),并以管理员或 root 运行(Linux 也可用CAP_NET_ADMIN)。Java 客户端用java -jar启动时无需改动;自己拼 classpath 或用服务包装器启动的,需要加--add-exports java.base/sun.nio.ch=ALL-UNNAMED,否则 Windows 与 macOS 上作为出口时所有连接都会被拒绝。 - 使用
deploy/openresty/specus.conf的反向代理需要加入新的location ^~ /http-share/,否则临时 HTTP 分享会落到前端页面上。 - Go 服务端的
SPECUS_NETTY_MAX_FRAME_SIZE不能小于 1048587,否则启动失败;默认值 32 MiB 不受影响(#239)。 - C 服务端:Redis URI 按 Lettuce 的规则解析,带下划线的主机名加端口、密码中未转义的
@/#/?现在会导致启动失败(#341);客户端配置的connectionRateLimitPerMinute开始在控制登录时生效(#348)。 - 多实例部署滚动升级期间,旧实例不处理新增的管理身份撤销事件,其上已打开的管理 WebSocket 要到断开时才结束。
- 从源码构建 Go 客户端与服务端需要 Go 1.27.3 或更新的已修补版本,
go.mod强制这一下限。
分发
- 沿用全端发布流程,提供客户端、服务端、STUN 与签名 Android 包;发布不代表已部署到运行中的服务器。
- Homebrew cask 在单独的 devShuai/homebrew-specus 仓库中另行更新;cask 更新后,已有安装执行
brew update和brew upgrade --cask specus-client。
验证与已知限制
- CI:四个服务端的完整测试在相关 PR 上运行;Java、Go、.NET、Android 客户端经 C 服务端跑 NAT、Direct HTTP/WebSocket、TLS 与 Peer Mesh 端到端测试;CLI 本地管理页与命令矩阵在 Windows 与 Ubuntu 上覆盖三端。出口分流的规则、授权、帧、路由读写、出站 socket 选择与 DNS 接管命令由共享测试向量钉住,期望值来自独立的 Python 参考实现。
- Linux 出口实验室(真机实验室)在网络命名空间里用真实虚拟网卡跑三种消费端 × 三种出口共 9 种组合:TCP/UDP、8 MiB 上下行与并发流、2% 丢包、撤权与故障注入后的防泄漏检查、DNS 接管与强杀后恢复,并按 #50 事先约定的阈值设性能门槛。实验室只用 Go 服务端,不覆盖 IPv6。
- 跨平台真机验收(#50)尚未完成:Windows 的路由安装、撤销与回滚(IPv4 与 IPv6)没有在真机上执行过;macOS 的安装路径在 CI 的 macOS 真机上验证过,但指向回环接口而不是 utun,IPv6 路由与地址安装未验证;Windows NRPT 与 macOS
networksetup的 DNS 接管、出口经 IPv6 出网都还没有真机验收。#42 与 #245 保持打开。 - 出口分流的其他限制:下行是固定窗口加背压,不是自适应拥塞控制;出口没有字节带宽限制;不转发 ICMP;不支持多跳出口链,拒绝
0.0.0.0/0与::/0;目标看到的通常是出口所在网络的公网出口地址,不承诺等于出口设备自身地址;路由表被改后最多 5 秒内补回,这期间命中规则的目标会从本机直连出去,Linux 只对照主表,策略路由导走的流量发现不了。 - #38 的工作台、连通性检查、临时分享、分块续传与产品指标已实现,尚未完成部署验收;分块续传的跨浏览器、跨 NAT 与移动端验收未做。
- Windows 桌面端与 Android 的连接可靠性与首次接入问题(#40)仍待真机验收。删除客户端不会清理其 Peer Mesh 设备记录与 ACL(#237)。
What's Changed
- feat(peer-egress): authorise a peer as a network egress across all four servers by @devShuai in #53
- feat(peer-egress): P2 Go egress user-space connection stack and authorization enforcement by @devShuai in #54
- feat(peer-egress): P3 消费端规则引擎、路由接管与数据面 by @devShuai in #55
- feat(peer-egress): P4 Java 与 .NET 纯逻辑层对齐 by @devShuai in #57
- feat(peer-egress): P4 路由接管移植到 Java 与 .NET by @devShuai in #58
- feat(peer-egress): P4 消费端数据面移植到 Java 与 .NET by @devShuai in #59
- feat(peer-egress): P4 出口端数据面移植到 Java 与 .NET by @devShuai in #60
- feat(peer-egress): P4 出口数据面接进 Peer Mesh by @devShuai in htt...
v1.2.6
三端 CLI 本地管理页
- Java / Go / .NET 新增
ui --config PATH [--no-open] [--port PORT],使用同一份离线页面资源,不需要安装桌面客户端或 Node 服务。 - 支持首次配置、离线校验、保留 JSONC 注释及未知字段的保存、显式连接/断开/重新连接;保存不会自动登录或改变运行中的连接。
- 凭据不回显,留空保留原值或 env:/file: 引用;通过内容版本检查防止覆盖外部修改,使用私有临时文件及原子替换。
- 管理端口仅监听 127.0.0.1,采用一次性连接码及内存会话,校验 Host/Origin,不开放通用文件、命令或代理接口。
- 三端共用同配置管理锁;其他 CLI 实例仅只读展示,不接管、不误停。关闭浏览器不停止隧道,退出管理服务会取消其拥有的连接。
- 区分 HTTP 登录、控制认证和转发通道就绪;设备/服务目录不表示目标业务已通过可达性探测。
其他修复及分发
- Java / Go / .NET 开发构建不再误提示降级到正式版;Windows 桌面客户端修正字体字重、回退及下拉框文字渲染。
- Java Tomcat 更新到 11.0.25;修正 C server 测试脚本向严格 CLI 传递无效 Spring 参数的问题。
- 三端显式保护 Windows 管理员环境下新建的配置及状态文件所有者,兼容运行器默认 Administrators 所有者,同时不放宽已有文件的私有权限检查。
- 沿用全端发布流程,提供客户端、服务端、STUN 与签名 Android 包;发布不代表已部署到运行中的服务器。
- Homebrew cask 随本次发布更新 Mac arm64 / x64 的 Go CLI。安装后运行
specus-client ui --config ./client.jsonc;已有安装可执行brew update和brew upgrade --cask specus-client。
验证与已知限制
- 本地回归:Go 三个包通过;Java 客户端 136 项通过、1 项 Windows 权限机制相关跳过;.NET 客户端 340 项通过。
- 三端 Windows 真实进程与 Chrome 基础矩阵各 38 项,并验证跨语言竞争锁;WSL Ubuntu 三端各 29 项,包含 SIGINT 与锁清理。Java/.NET 原有 CLI Windows 矩阵各 32 项通过。
- 按维护者要求,#41 以本地管理页 v1 的三端交付关闭,不将扩展需求或未测场景伪装为已完成。更多高级配置、主动诊断/安全日志、SSH 体验、macOS 浏览器/读屏及 Windows 控制台人工验收仍属后续工作。#40 的原生 GUI 真机验收保持独立。
- 首期页面只编辑服务地址、凭据及 noop/auto 网卡模式,复杂字段使用外部编辑器。刷新需用终端新连接码重新授权;stdin 已关闭或会话达到上限时需重启管理服务。遗留管理锁需确认原 PID 退出后手动清理。
- 本地页面不是公网或多人管理后台;不支持接管已有 CLI、服务安装或互传。详细安全和生命周期边界见 CLI 使用说明。
Full Changelog: v1.2.5...v1.2.6
v1.2.5
客户端联合更新
- Java、Go、.NET CLI:统一命令易用性、生命周期诊断、认证错误处理及状态查询行为,详见 #39。
- Windows 桌面客户端:网络变化和睡眠恢复触发重连,提供立即重试与托盘后台/退出选择;保留具体错误原因,区分控制认证和转发通道就绪。
- Windows 界面默认展示共享服务,配置与诊断分层,日志折叠;改善小窗口分页和操作按钮布局。
- Android:按 VPN/非 VPN 用途调整前台服务类型;增加网络变化重连、有界多地址连接、错误分类、后台状态/消息/草稿恢复。
- Android 互传增加在线设备选择与单条消息结果,失败保留内容,不把提交当作送达;ACK 结果未知时不自动重复发送。页面按设备、互传和设置分区,支持明暗主题、键盘避让和更大的触控目标。
- 本次沿用全端发布流程,同时提供服务端及 STUN 构建;本次发布不代表已部署到运行中的服务器。
已知限制与待验收
按维护者决定先发布,图形客户端验收跟踪 #40 保持开放:
- Android 15+ 真机 VPN/非 VPN 长期后台、Wi-Fi/蜂窝切换,以及 Windows 真实睡眠恢复、托盘退出和高 DPI 交互尚未完成全面验收。
- Android 模拟器和 Windows 离屏布局截图不替代真实设备测试;尚未测量首次连接成功率、长期在线率或通道就绪后的服务可访问率。
- Android 消息只保留本次应用进程最近 100 条;退出进程后的历史不持久化。手动重发前应确认对方未收到;“已提交”不表示已送达或已读。
- 非 VPN 常驻服务使用 specialUse;如通过 Google Play 分发,仍需相应用途审核。
本地回归:.NET 327 项核心测试和 1 项 WPF 布局测试、Android 207 项 JVM 测试和 8 项模拟器设备测试、.NET CLI Windows 32 项及 Linux 33 项进程检查通过。发布流水线另执行各端构建/测试、Android 受保护签名及 SHA-256 产物校验。
Full Changelog: v1.2.4...v1.2.5
v1.2.4
v1.2.3
Direct HTTP WebSocket 与按路由 TLS 校验。
Highlights
/http/上带Upgrade: websocket的 GET 不再被 RestController 当成普通 HTTP 转发(DSH 会回 426 Upgrade Required),握手改走 NAT 隧道 WebSocket handler- 普通 GET 仍由
HttpSpecusController处理;Spring 7 的 WebSocket 映射不再对非升级请求返回 400 Can Upgrade only to WebSocket - HTTP 路由可单独配置上游 TLS 校验(私有 CA、证书钉扎、或显式跳过),不再绑死进程级策略
Notes
- Android 仍使用与 v1.1.0 起同一把生产签名钥匙
- C server 仍为冻结兼容子集
- macOS Homebrew:
brew upgrade --cask specus-client(tapdevShuai/specus)
Full Changelog: v1.2.2...v1.2.3
v1.2.2
v1.2.1
HTTP 映射修复。
Highlights
- Go 客户端忽略已关闭 HTTP/NAT 流上的迟到 WINDOW_UPDATE,避免 data/control 成对掉线后页面资源 502「客户端不在线」
- Java 与 .NET 管理页安全头跳过 Direct HTTP
/http/**,映射 SPA(如 DSH)的内联脚本和路径改写 polyfill 不再被门户 CSP 拦截
Notes
- Android 仍使用与 v1.1.0 / v1.2.0 同一把生产签名钥匙
- C server 仍为冻结兼容子集
Full Changelog: v1.2.0...v1.2.1
v1.2.0
Peer Mesh 服务发现 v2 与 #15–#22 修复,以及自 v1.1.0 以来的依赖/工具链升级。
Highlights
- 数据面强制服务级 ACL;目录 TTL 续租与 revision tombstone;在线 CRUD 立即推送 peer-config 并关旧桥
- .NET 目录状态不再随 Scoped 服务销毁;ACL 变更与新 Peer 登录同步全量目录
- 协议/Schema 对齐(peer service discovery v2)、目标地址收紧、桥接与 report 限额
- 管理页与客户端 UI 状态同步
- 含安全补丁的依赖升级,以及 Go / .NET / Java / admin-web 工具链前移
- Android 生产签名 APK(v2/v3,RSA 4096,与 v1.1.0 同一把钥匙)
Notes
- Android 上传密钥仍是本机
~/.specus/android-release/,GitHubrelease-signing环境。后续版本必须使用同一把钥匙,否则无法覆盖安装。 - C server 仍为冻结兼容子集。
Full Changelog: v1.1.0...v1.2.0
v1.1.0
Peer Mesh 本地服务发现(默认关闭)、客户端更新通道,以及自 v1.0.0 以来的安全加固。
Highlights
- 租户「Peer 服务共享」总开关默认关闭;session 级目录、Peer-only TCP/UDP 桥、可选 mDNS 导入与服务级 ACL
- 客户端版本目录、GitHub Releases 下载页、安全更新流程
- TLS 校验、加盐密码、登录限流、trusted-proxy 客户端 IP
- Android 生产签名 APK(v2,RSA 4096)
Notes
- Android 上传密钥保存在本机
~/.specus/android-release/,并已写入 GitHubrelease-signing环境 secrets。后续版本必须使用同一把钥匙,否则无法覆盖安装。 - C server 仍为冻结兼容子集。
Full Changelog: v1.0.0...v1.1.0