From 6e62009260f5eccb2ff352f38f1be214d1a7ac7e Mon Sep 17 00:00:00 2001
From: ciddwd <2117971372@qq.com>
Date: Wed, 10 Jun 2026 15:19:09 +0800
Subject: [PATCH] =?UTF-8?q?fix(remote-input):=20=E5=85=A8=E9=9D=A2?=
=?UTF-8?q?=E8=87=AA=E5=AE=A1=E2=80=94=E2=80=94=E4=BF=AE=E5=A4=8D=202=20?=
=?UTF-8?q?=E4=B8=AA=20HIGH=20=E7=AB=9E=E6=80=81=E4=B8=8E=E4=B8=80?=
=?UTF-8?q?=E6=89=B9=E4=B8=AD=E5=8D=B1=E9=97=AE=E9=A2=98?=
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit
按评审机器人的维度(安全/并发/资源/错误处理/边界)对远程输入全部改动面
做了一轮地毯式自审,修复如下:
Rust 核心(2 HIGH + 3 medium):
- [HIGH] start_remote_dictation TOCTOU:busy 预检查与 remote_source_active
置位原在锁外,竞态输家把残留标志泄给抢先启动的本地会话(被劫持进远程
分支:不开麦克风、听写全文经 remote:result 泄给手机)。新增
begin_session_with_source(remote),busy 判定与置位移入 begin_session_state
同一临界区(与本地路径同构);busy 时返回 Err(REMOTE_BUSY) 供手机回执。
- [HIGH] 服务关停/重置 PIN 不撤销存量连接:连接任务是裸 spawn,shutdown 只
停 accept loop,已配对手机仍能录音落字。新增 watch 关停广播,shutdown 时
断开全部存量 WS 连接(旧 handle 被覆盖时靠 sender drop 自动生效)。
- end_session 新增 RemoteFlagsJanitor(Drop 兜底):十余处终结路径统一在
会话回 Idle 时清远程标志;同时修复 double-stop 过早清标志导致「仅回传」
失效与 remote:result 丢失(phase 非 Idle 不清)。
- stop/cancel_remote_dictation 加守卫:手机 stop/断连不再能终止 PC 用户
正在进行的本地听写。
- refresh_remote_server 串行化(异步锁 + 代数):连点开关/连改端口不再交错
启动、误报 port-in-use;中间代直接让位只跑最后一轮。
- WS 主循环加 keepalive(30s Ping / 90s 无上行断开):手机息屏不发 FIN 时
半开连接与录音会话不再悬挂;PCM 单帧加 64KB 上限防认证后 DoS。
- 私钥 remote-key-v4.der 在 Unix 下收紧为 0600。
H5 录音页(4 medium + 1 low):
- getUserMedia 超时后迟到 resolve 用代际计数作废,不再泄漏麦克风轨道;
- hold 按下立即松手不再发孤立 stop(startSent 配对),transcribing/polishing
加 30s 客户端兜底超时,UI 不再可能永久卡「识别中…」;
- iOS 来电/Siri 后的 'interrupted' 状态改为非 running 即 resume;
- sessionStorage 被禁时写后读回校验,根除无限 reload 循环;
- readyTimer/busyTimer 统一跟踪清理,杜绝迟到定时器错盖新状态。
设置页(2 medium + 1 low):
- listen() 异步注册 vs 卸载竞态:注册完成若已卸载立即退订;
- 端口输入改草稿+失焦提交:不再逐键重启服务,clamp 对齐 [1024,65535],
取整防 u16 反序列化失败;
- 重置 PIN 用命令返回值本地更新,不再撞异步重启窗口闪烁,并加错误处理。
验证:cargo check 0 错误;cargo test --lib 508 过(5 例失败为基线既有 asr
mock);tsc 通过;node --check app.js 通过。
---
openless-all/app/src-tauri/src/coordinator.rs | 61 ++++++++----
.../src/coordinator/dictation_end.rs | 20 ++++
.../src/coordinator/dictation_session.rs | 29 +++++-
.../src-tauri/src/remote_server/assets/app.js | 96 +++++++++++++++++--
.../app/src-tauri/src/remote_server/mod.rs | 61 +++++++++++-
.../src/pages/settings/RemoteInputSection.tsx | 65 +++++++++----
6 files changed, 286 insertions(+), 46 deletions(-)
diff --git a/openless-all/app/src-tauri/src/coordinator.rs b/openless-all/app/src-tauri/src/coordinator.rs
index 64099eaf..6c19b141 100644
--- a/openless-all/app/src-tauri/src/coordinator.rs
+++ b/openless-all/app/src-tauri/src/coordinator.rs
@@ -9,7 +9,7 @@
//! insertion, persists history, emits `capsule:state` events to the capsule
//! window.
-use std::sync::atomic::{AtomicBool, Ordering};
+use std::sync::atomic::{AtomicBool, AtomicU64, Ordering};
use std::sync::mpsc;
use std::sync::Arc;
use std::time::Instant;
@@ -257,6 +257,12 @@ pub(crate) struct Inner {
remote_audio_sink: Mutex