设备名与令牌解耦 + iOS Broker 应用内登录 / 消息 / 图库 / 记录持久化 + 三端 bug 修复
设备名与令牌解耦(presence 按 device_id 键控):
- hub 主键改稳定 device_id(presence / online / kick 用之),peer 路由仍按设备名经 hub 内 clientFor 解析——不动传输核心;Client 加 Name + 连接键,PresenceDevice 加 device_id,sse 传 claims.DeviceID,publishPresence 按 device_id 判在线、name 取自 devices 表
- 改名走已有 PATCH /api/devices/{device_id}(不重铸会话、不换 token、不中断 SSE)+ hub.Rename 更新活跃连接名 + 重广播 presence,全端即时无重复项;sessions 列表 name 用 devices 表覆盖 broker Label;web 改名从重铸迁到 PATCH,iOS 设置页即时改名;DeviceItem / DeviceInfo 按 device_id 键控判本机
- 移除「需移除两次」:publishPresence 不再把「有 device_id 但无 devices 行」的 live 连接当在线(吊销后用未过期 token 重连的僵尸),只显示 code-less 连接;合法重登新建行故正常
- revoke 对无 broker 会话的本地行也清(清掉合成测试 / 幽灵设备);跨端吊销 / 断连一律按 device_id Kick
iOS Broker 应用内登录(免扫码):
- BrokerLogin.swift:ASWebAuthenticationSession 跑 broker /device/authorize + /device/token 的 PKCE 设备授权流(对齐桌面 loopback,自定义 scheme cdrop://auth-callback 回调)→ /api/auth/device-session 代铸出带真名 + 稳定 device_id 的设备会话;DeviceIDStore 跨登录复用 device_id 杜绝重登重复
- LoginView 主登录改 broker 账号登录、扫码降级为可展开备选
iOS 功能补全:
- 设备间消息(引擎 main.ts 单条增量过桥 + onNativeEvent sendMessage;EngineController 消息状态 + 新 MessagesView 会话 UI;后端 /api/message 已就绪)
- 图库发送(PhotosPicker 文件 / 图库菜单 → stagePhotoData → 复用 cdrop-file 发送链路;NSPhotoLibraryUsageDescription)
- 传输历史 / 消息记录持久化(RecordsStore 落 Application Support JSON,跨重启存活)+ 长按删除 + 清空(二次确认)
- 进行中传输主动取消 / 立即切中继(详情页两按钮,复用引擎桥命令)
- 身份愈合(引擎 /api/me 取真实显示名经 identityUpdated 回报 Keychain,修扫码登录「用户显示 UUID」)
- 触发本地网络权限(NWBrowser 浏览 _cdrop._tcp)使 WKWebView WebRTC 取 host 候选
iOS 发送 / 启动修复:
- 发送在读文件即失败:引擎在 https 源下 fetch("cdrop-file://") 跨源 + Range 头触发 CORS 预检被拦 → 改走原生桥 bridgeFileSource / readFileSlice(512 KiB 分块 base64),绕开 CORS、整文件仍不整体进内存
- 冷启重开「missing injected session」:EngineWebView.makeUIView 在 boot 注入前确定性接好 auth,消除注入竞态
桌面 bug 修复:
- 登出静默失败:window.confirm 在 Wails WebView 失效(返回 falsy 致动作被静默跳过)→ 跨平台 DOM 确认弹窗(utils/confirm 的 Promise 式 confirmDialog + ui/ConfirmHost 的 Mantine Modal)取代之;登出改 await 先吊销 broker 会话再清本地(桌面 clearDesktopSession 会丢 Go 侧 refresh 的竞态)
- 扫 iOS 登录二维码被拒「不是本站的码」:wails:// 源永不等 https 站点源 → 桌面放宽 parseLinkApprovalUrl 的 origin 等值校验(仍留 /link 路径 + r/c;批准 r/c 一律发往本端后端、外站码只 404,无开放重定向)
- macOS 本地网络权限触发(localnetwork_darwin NWBrowser + Info.plist 键);相机修复(NSCameraUsageDescription)
web / 跨端:
- presence 透传 device_id + 离线检测按 device_id;会话列表随 presence 防抖重拉(已登出设备自动从列表消失,不再需手动刷新);移除设备 / 清剪贴板 / 撤销令牌 / 登出均改 DOM 确认弹窗
分发 / 签名:
- 真机签名从手动 scaffold 改自动 provisioning(删 Signing.xcconfig,project.yml 去 profile specifier,just ios-device 用 -allowProvisioningUpdates + ASC 团队 key);App Group 改名 group.net.commilitia.Commilitia-Drop(含 entitlements)
- hub 测试加 device_id 键控 + 改名解耦回归(-race)
This commit is contained in:
@@ -54,6 +54,9 @@ func (a *App) startup(ctx context.Context) {
|
||||
_ = platform.SetLaunchAtLogin(true)
|
||||
}
|
||||
a.startClipboardSync(ctx)
|
||||
// 触发 macOS 本地网络权限(macOS 15+ 隐私门):使本进程 WKWebView 的 WebRTC 能收集 host /
|
||||
// mDNS 候选、同内网走直连而非 prflx↔prflx 慢路径(见 platform.TriggerLocalNetwork)。其他平台空实现。
|
||||
platform.TriggerLocalNetwork()
|
||||
platform.InstallStatusBar(
|
||||
platform.StatusBarMenu{
|
||||
Title: "cdrop",
|
||||
|
||||
@@ -23,6 +23,14 @@
|
||||
<string>true</string>
|
||||
<key>NSHumanReadableCopyright</key>
|
||||
<string>{{.Info.Copyright}}</string>
|
||||
<key>NSCameraUsageDescription</key>
|
||||
<string>Commilitia Drop 使用相机扫描二维码以登录 / 批准设备。</string>
|
||||
<key>NSLocalNetworkUsageDescription</key>
|
||||
<string>Commilitia Drop 使用本地网络发现同内网设备并建立点对点直连传输。</string>
|
||||
<key>NSBonjourServices</key>
|
||||
<array>
|
||||
<string>_cdrop._tcp</string>
|
||||
</array>
|
||||
{{if .Info.FileAssociations}}
|
||||
<key>CFBundleDocumentTypes</key>
|
||||
<array>
|
||||
|
||||
@@ -23,6 +23,14 @@
|
||||
<string>true</string>
|
||||
<key>NSHumanReadableCopyright</key>
|
||||
<string>{{.Info.Copyright}}</string>
|
||||
<key>NSCameraUsageDescription</key>
|
||||
<string>Commilitia Drop 使用相机扫描二维码以登录 / 批准设备。</string>
|
||||
<key>NSLocalNetworkUsageDescription</key>
|
||||
<string>Commilitia Drop 使用本地网络发现同内网设备并建立点对点直连传输。</string>
|
||||
<key>NSBonjourServices</key>
|
||||
<array>
|
||||
<string>_cdrop._tcp</string>
|
||||
</array>
|
||||
{{if .Info.FileAssociations}}
|
||||
<key>CFBundleDocumentTypes</key>
|
||||
<array>
|
||||
|
||||
@@ -0,0 +1,21 @@
|
||||
//go:build darwin
|
||||
|
||||
package platform
|
||||
|
||||
/*
|
||||
#cgo darwin CFLAGS: -x objective-c -fobjc-arc
|
||||
#cgo darwin LDFLAGS: -framework Network
|
||||
#include <stdlib.h>
|
||||
|
||||
void cdropTriggerLocalNetwork(void);
|
||||
*/
|
||||
import "C"
|
||||
|
||||
// TriggerLocalNetwork 在 macOS 上发起一次 Bonjour 浏览,触发「本地网络」权限请求(macOS 15+ /
|
||||
// Sequoia 起也有本地网络隐私门)。未授权时本进程内的 WKWebView WebRTC 收集不到 host / mDNS 候选
|
||||
// → 同内网传输退到 prflx↔prflx 慢路径(实测桌面→iOS 仅几百 KB/s,而 Chrome 走 host 可达近
|
||||
// 10 MB/s)。授权后 WKWebView 才能拿到本地候选实现直连。仅 macOS 需要;Windows 无此门(见
|
||||
// localnetwork_other.go 的空实现)。幂等:原生侧保活单个 browser。
|
||||
func TriggerLocalNetwork() {
|
||||
C.cdropTriggerLocalNetwork()
|
||||
}
|
||||
@@ -0,0 +1,33 @@
|
||||
#import <Network/Network.h>
|
||||
|
||||
// cdropTriggerLocalNetwork:起一个对 _cdrop._tcp 的 Bonjour 浏览,触发 macOS 本地网络权限弹窗。
|
||||
// WKWebView 自身不会触发该权限请求,须由宿主 App 主动发起一次本地网络访问;授权后本进程内的
|
||||
// WebRTC 才能收集 host / mDNS 候选实现同内网直连(见 localnetwork_darwin.go 注释)。浏览结果本身
|
||||
// 不关心——「发起访问」这一动作即触发授权。保活单个 browser(静态全局,ARC 下持有),幂等。
|
||||
static nw_browser_t gCdropBrowser = nil;
|
||||
|
||||
void cdropTriggerLocalNetwork(void) {
|
||||
if (gCdropBrowser != nil) {
|
||||
return;
|
||||
}
|
||||
nw_browse_descriptor_t descriptor =
|
||||
nw_browse_descriptor_create_bonjour_service("_cdrop._tcp", NULL);
|
||||
nw_parameters_t parameters = nw_parameters_create();
|
||||
nw_parameters_set_include_peer_to_peer(parameters, true);
|
||||
|
||||
nw_browser_t browser = nw_browser_create(descriptor, parameters);
|
||||
nw_browser_set_queue(browser, dispatch_get_main_queue());
|
||||
nw_browser_set_browse_results_changed_handler(
|
||||
browser, ^(nw_browse_result_t old_result, nw_browse_result_t new_result, bool batch_complete) {
|
||||
// 不关心结果;浏览动作本身即触发权限请求。
|
||||
});
|
||||
nw_browser_set_state_changed_handler(
|
||||
browser, ^(nw_browser_state_t state, nw_error_t error) {
|
||||
// 进入 failed/cancelled 时释放,允许下次重试。
|
||||
if (state == nw_browser_state_failed || state == nw_browser_state_cancelled) {
|
||||
gCdropBrowser = nil;
|
||||
}
|
||||
});
|
||||
gCdropBrowser = browser;
|
||||
nw_browser_start(browser);
|
||||
}
|
||||
@@ -0,0 +1,6 @@
|
||||
//go:build !darwin
|
||||
|
||||
package platform
|
||||
|
||||
// TriggerLocalNetwork 仅 macOS 需要(本地网络隐私门)。Windows / Linux 无此门,空实现。
|
||||
func TriggerLocalNetwork() {}
|
||||
Reference in New Issue
Block a user