feat: 统一 Commilitia Drop 全客户端命名与分发

This commit is contained in:
2026-07-31 22:56:10 +08:00
parent f7b0f04c9c
commit c480f0d1c2
77 changed files with 861 additions and 263 deletions
+3 -3
View File
@@ -135,7 +135,7 @@ final class AuthManager
let verifier = PKCE.randomToken(64)
let challenge = PKCE.challenge(for: verifier)
let state = PKCE.randomToken(24)
let redirectURI = "cdrop://auth-callback"
let redirectURI = "commilitia-drop://auth-callback"
var comp = URLComponents(string: cfg.brokerURL.trimmingTrailingSlash() + "/device/authorize")!
comp.queryItems = [
@@ -144,13 +144,13 @@ final class AuthManager
URLQueryItem(name: "state", value: state),
URLQueryItem(name: "code_challenge", value: challenge),
URLQueryItem(name: "code_challenge_method", value: "S256"),
URLQueryItem(name: "description", value: "Commilitia Drop iOS"),
URLQueryItem(name: "description", value: "Commilitia Drop"),
]
guard let authURL = comp.url else { throw BrokerLoginError.incompleteConfig }
let flow = BrokerAuthFlow()
brokerFlow = flow
let callback = try await flow.run(url: authURL, callbackScheme: "cdrop")
let callback = try await flow.run(url: authURL, callbackScheme: "commilitia-drop")
brokerFlow = nil
if gen != loginGeneration { return }
+8 -5
View File
@@ -8,13 +8,15 @@ import AppKit
#endif
// Broker device-authorization + PKCE desktop/platform/oauth.goiOS
// loopback ASWebAuthenticationSession + scheme cdrop://auth-callback
// 1. GET {broker}/device/authorize?app=cdrop&redirect_uri=cdrop://auth-callback&state&code_challenge&S256
// 2. broker SSO cdrop://auth-callback?code=..&state=..
// loopback ASWebAuthenticationSession + scheme
// commilitia-drop://auth-callback
// 1. GET {broker}/device/authorize?app=commilitia-drop&redirect_uri=commilitia-drop://auth-callback&...
// 2. broker SSO commilitia-drop://auth-callback?code=..&state=..
// 3. POST {broker}/device/token {code, code_verifier, redirect_uri} bootstrap
// 4. POST {api}/api/auth/device-sessionBearer bootstrap cdrop / device_id
//
// broker cdrop redirect_uri cdrop://auth-callback loopback
// broker Commilitia Drop redirect_uri
// commilitia-drop://auth-callback loopback
enum BrokerLoginError: Error
{
@@ -35,7 +37,8 @@ final class BrokerAuthFlow: NSObject, ASWebAuthenticationPresentationContextProv
{
private var session: ASWebAuthenticationSession?
// URLcdrop://auth-callback?code=..&state=.. /
// URLcommilitia-drop://auth-callback?code=..&state=..
// /
func run(url: URL, callbackScheme: String) async throws -> URL
{
try await withCheckedThrowingContinuation
+2 -2
View File
@@ -72,11 +72,11 @@ struct AppRoot: View
{ _, uid in
if let uid { engine.activateRecords(userId: uid) }
}
// Share Extension cdrop://share RootView
// Share Extension commilitia-drop://share
// AppRoot 便 / onAppear
.onOpenURL
{ url in
guard url.scheme == "cdrop", url.host == "share" else { return }
guard url.scheme == "commilitia-drop", url.host == "share" else { return }
engine.loadPendingShares()
}
// AppDelegate +
+13 -13
View File
@@ -193,7 +193,7 @@ final class EngineController: NSObject
private var webView: WKWebView?
private let downloads = DownloadManager()
// id URL cdrop-file://<id>
// id URL commilitia-drop-file://<id>
// WKURLSchemeHandler
private var outgoing: [String: URL] = [:]
@@ -271,7 +271,7 @@ final class EngineController: NSObject
}
// makeWebView WebView __CDROP_BOOT__device_type:"ios"
// cdrop-file scheme JS
// commilitia-drop-file scheme JS
func makeWebView() -> WKWebView
{
if let existing = webView { return existing }
@@ -297,7 +297,7 @@ final class EngineController: NSObject
let cfg = WKWebViewConfiguration()
cfg.userContentController = ucc
cfg.setURLSchemeHandler(self, forURLScheme: "cdrop-file")
cfg.setURLSchemeHandler(self, forURLScheme: "commilitia-drop-file")
// Auth Broker refresh_tokenPOST /api/auth/refresh
// broker cdrop_session cookie URLSession cookie WebView
@@ -672,7 +672,7 @@ final class EngineController: NSObject
webView?.evaluateJavaScript("window.__cdropEngineEvent(\(jsString(name)), \(json));")
}
// sendFile cdrop-file://<id> +
// sendFile commilitia-drop-file://<id> +
func sendFile(to target: String, fileURL: URL)
{
let ref = stageOutgoingFile(fileURL)
@@ -687,7 +687,7 @@ final class EngineController: NSObject
])
}
// Share Extension App Group cdrop://share
// Share Extension App Group commilitia-drop://share
//
var pendingShareFiles: [URL] = []
@@ -730,7 +730,7 @@ final class EngineController: NSObject
}
// #14PhotosPicker PhotosPickerItem loadTransferable
// cdrop-file scheme Range
// commilitia-drop-file scheme
// URL temporaryDirectory nil
func stagePhotoData(_ data: Data, suggestedName: String) -> URL?
{
@@ -743,18 +743,18 @@ final class EngineController: NSObject
catch { return nil }
}
// cdrop-file://<id> URL
// commilitia-drop-file://<id>
// start...Access
private func stageOutgoingFile(_ url: URL) -> String
{
let id = UUID().uuidString
_ = url.startAccessingSecurityScopedResource()
outgoing[id] = url
return "cdrop-file://\(id)"
return "commilitia-drop-file://\(id)"
}
// [start,end) seek base64 bridgeFileSource
// url cdrop-file://<id>id stageOutgoingFile /
// url commilitia-drop-file://<id>id stageOutgoingFile
fileprivate func readOutgoingSlice(url: String, start: Int, end: Int) throws -> String
{
guard let id = URL(string: url)?.host, let fileURL = outgoing[id]
@@ -787,7 +787,7 @@ final class EngineController: NSObject
return e
}
// cdrop-file://<id> Go
// commilitia-drop-file://<id>
// 访 stageOutgoingFile reset Go os.Open
//
private func resolveOutgoingPath(_ ref: String) -> String
@@ -871,7 +871,7 @@ extension EngineController: WKScriptMessageHandler
end: Self.intOf(payload["end"]))
resolve(id: id, ok: true, value: b64)
case "p2pStartOutgoing":
// filePath cdrop-file://<id>
// filePath commilitia-drop-file://<id>
// libwebrtc completion offer + resolveOnMain
let engine = nativeTransferEngine()
let path = resolveOutgoingPath(payload["filePath"] as? String ?? "")
@@ -1133,11 +1133,11 @@ extension EngineController: WKScriptMessageHandler
}
}
// MARK: - schemecdrop-file
// MARK: - schemecommilitia-drop-file
extension EngineController: WKURLSchemeHandler
{
// cdrop-file://<id> JS fetch
// commilitia-drop-file://<id>
// PLAN §2 / R-iOS-4rangeSource `Range` seek
// 206 Partial Content jetsam Range
// 退 Range
@@ -6,7 +6,7 @@ import WebRTC
// WebKit/libwebrtc desktop/NATIVE-TRANSFER.md §7
//
// 线 desktop/enginepion web/src/features/transfer/p2p.ts pion
// / iOS JS DataChannel "cdrop-file"ordered meta/done/ack
// / iOS JS DataChannel "commilitia-drop-file"ordered
// 64KB payload {type, sdp?, candidate?} session.go +
// engine.go Swift ack
//
@@ -39,7 +39,7 @@ protocol P2PEngineDelegate: AnyObject
private enum Wire
{
static let channelName = "cdrop-file"
static let channelName = "commilitia-drop-file"
static let chunkSize = 64 * 1024
static let highWatermark: UInt64 = 16 * 1024 * 1024
static let lowWatermark: UInt64 = 4 * 1024 * 1024
@@ -94,7 +94,7 @@ final class LibWebRtcEngine
}
// StartOutgoing PeerConnection + DataChannel offer filePath
// filePath cdrop-file://<id> completion offer
// filePath commilitia-drop-file://<id> completion offer
// setLocalDescription JS seed p2pIos.ts chain
func startOutgoing(sessionId: String, peerName: String, filePath: String,
iceServersJSON: String, completion: @escaping (Error?) -> Void)
+3 -3
View File
@@ -23,7 +23,7 @@
<string>en</string>
</array>
<key>CFBundleName</key>
<string>$(PRODUCT_NAME)</string>
<string>Commilitia Drop</string>
<key>CFBundlePackageType</key>
<string>APPL</string>
<key>CFBundleShortVersionString</key>
@@ -35,7 +35,7 @@
<string>net.commilitia.Commilitia-Drop</string>
<key>CFBundleURLSchemes</key>
<array>
<string>cdrop</string>
<string>commilitia-drop</string>
</array>
</dict>
</array>
@@ -50,7 +50,7 @@
</dict>
<key>NSBonjourServices</key>
<array>
<string>_cdrop._tcp</string>
<string>_commilitia-drop._tcp</string>
</array>
<key>NSCameraUsageDescription</key>
<string>Commilitia Drop 使用相机扫描二维码登录新设备。</string>
@@ -3,10 +3,11 @@ import Network
// #5iOS 14+ App 访 WKWebView
// WebRTC host 退 srflx / relayWKWebView
// 宿 App 访 _cdrop._tcp
// 宿 App 访
// _commilitia-drop._tcp
// NWBrowser RTCPeerConnection host / mDNS
// browser project.yml
// NSLocalNetworkUsageDescription + NSBonjourServices(_cdrop._tcp)
// NSLocalNetworkUsageDescription + NSBonjourServices(_commilitia-drop._tcp)
enum LocalNetworkPermission
{
private static var browser: NWBrowser?
@@ -18,7 +19,7 @@ enum LocalNetworkPermission
guard browser == nil else { return }
let params = NWParameters()
params.includePeerToPeer = true
let b = NWBrowser(for: .bonjour(type: "_cdrop._tcp", domain: nil), using: params)
let b = NWBrowser(for: .bonjour(type: "_commilitia-drop._tcp", domain: nil), using: params)
b.browseResultsChangedHandler = { _, _ in }
browser = b
b.start(queue: .main)
+4 -4
View File
@@ -97,7 +97,7 @@
"qr.show.nameHint": "Shown to your other devices. ASCII characters only.",
"qr.show.generate": "Generate code",
"qr.show.scanTitle": "Scan to approve",
"qr.show.howto1": "Open the camera or cdrop on another signed-in device.",
"qr.show.howto1": "Open the camera or Commilitia Drop on another signed-in device.",
"qr.show.howto2": "Scan the code above and approve this device.",
"qr.show.waiting": "Waiting for approval…",
"qr.show.approved": "Approved — signing you in…",
@@ -189,11 +189,11 @@
"notify.transfer.failedTitle": "Transfer failed",
"settings.account.title": "Account",
"settings.account.signOut": "Sign out",
"settings.desktop.title": "Desktop",
"settings.desktop.title": "App settings",
"settings.desktop.clipboardSync": "Auto-sync clipboard",
"settings.desktop.clipboardSyncHint": "Copies are uploaded to the cloud, and clipboard updates from your other devices are applied here.",
"settings.desktop.launchAtLogin": "Launch at login",
"settings.desktop.launchAtLoginHint": "Start cdrop in the background after you sign in (lives in the menu bar).",
"settings.desktop.launchAtLoginHint": "Start Commilitia Drop in the background after you sign in (lives in the menu bar or system tray).",
"settings.desktop.downloadDir": "Download folder",
"settings.desktop.downloadDirHint": "Received files are saved here. Leave unset to use the system Downloads folder.",
"settings.desktop.downloadDirChoose": "Change…",
@@ -292,7 +292,7 @@
"errors.messageEmpty": "Message is empty",
"errors.messageOverflow": "Message exceeds 4 KB; send a file instead",
"errors.noReceiver": "No receiver selected",
"errors.devTokenMissing": "Dev mode: VITE_CDROP_DEV_TOKEN is not set in .env.local",
"errors.devTokenMissing": "Dev mode: the development token is not configured in .env.local",
"errors.noAccessToken": "No access token; user must log in",
"errors.clipboardUnavailable": "Browser clipboard API unavailable (requires HTTPS + permission)",
"errors.clipboardOverflow": "Content too large; exceeds {{max}} byte limit",
+4 -4
View File
@@ -97,7 +97,7 @@
"qr.show.nameHint": "此名称会展示给你的其他设备,仅可使用 ASCII 字符。",
"qr.show.generate": "生成二维码",
"qr.show.scanTitle": "用手机扫码批准",
"qr.show.howto1": "在另一台已登录的设备上打开相机或 cdrop。",
"qr.show.howto1": "在另一台已登录的设备上打开相机或 Commilitia Drop。",
"qr.show.howto2": "扫描上方二维码,按提示批准此设备。",
"qr.show.waiting": "等待批准…",
"qr.show.approved": "已批准,正在进入…",
@@ -189,11 +189,11 @@
"notify.transfer.failedTitle": "传输失败",
"settings.account.title": "账号",
"settings.account.signOut": "退出登录",
"settings.desktop.title": "桌面",
"settings.desktop.title": "应用设置",
"settings.desktop.clipboardSync": "剪贴板自动同步",
"settings.desktop.clipboardSyncHint": "复制即上传到云端,并接收其他设备的剪贴板更新。",
"settings.desktop.launchAtLogin": "开机自启",
"settings.desktop.launchAtLoginHint": "登录系统后自动在后台启动 cdrop(菜单栏常驻)。",
"settings.desktop.launchAtLoginHint": "登录系统后自动在后台启动 Commilitia Drop常驻菜单栏或系统托盘)。",
"settings.desktop.downloadDir": "下载目录",
"settings.desktop.downloadDirHint": "接收到的文件保存到此目录;留空则使用系统下载目录。",
"settings.desktop.downloadDirChoose": "更改…",
@@ -292,7 +292,7 @@
"errors.messageEmpty": "消息为空",
"errors.messageOverflow": "消息超过4 KB;请改用文件传输",
"errors.noReceiver": "未选择接收方",
"errors.devTokenMissing": "Dev模式:未在.env.local设置VITE_CDROP_DEV_TOKEN",
"errors.devTokenMissing": "Dev 模式:未在 .env.local 配置开发令牌",
"errors.noAccessToken": "无访问令牌:用户必须先登录",
"errors.clipboardUnavailable": "浏览器不支持剪贴板API(需HTTPS与权限)",
"errors.clipboardOverflow": "内容过大,超过 {{max}} 字节上限",
+4 -4
View File
@@ -97,7 +97,7 @@
"qr.show.nameHint": "此名稱會顯示給你的其他裝置,僅可使用 ASCII 字元。",
"qr.show.generate": "產生 QR 碼",
"qr.show.scanTitle": "用手機掃碼批准",
"qr.show.howto1": "在另一部已登入的裝置上開啟相機或 cdrop。",
"qr.show.howto1": "在另一部已登入的裝置上開啟相機或 Commilitia Drop。",
"qr.show.howto2": "掃描上方 QR 碼,依提示批准此裝置。",
"qr.show.waiting": "等待批准…",
"qr.show.approved": "已批准,正在進入…",
@@ -189,11 +189,11 @@
"notify.transfer.failedTitle": "傳輸失敗",
"settings.account.title": "帳號",
"settings.account.signOut": "登出",
"settings.desktop.title": "桌面",
"settings.desktop.title": "應用程式設定",
"settings.desktop.clipboardSync": "剪貼簿自動同步",
"settings.desktop.clipboardSyncHint": "複製後即上傳雲端,並接收其他裝置的剪貼簿更新。",
"settings.desktop.launchAtLogin": "開機自動啟動",
"settings.desktop.launchAtLoginHint": "登入系統後自動在背景啟動 cdrop(常駐選單列)。",
"settings.desktop.launchAtLoginHint": "登入系統後自動在背景啟動 Commilitia Drop(常駐選單列或系統匣)。",
"settings.desktop.downloadDir": "下載資料夾",
"settings.desktop.downloadDirHint": "接收到的檔案會儲存至此資料夾;留空則使用系統下載資料夾。",
"settings.desktop.downloadDirChoose": "變更…",
@@ -292,7 +292,7 @@
"errors.messageEmpty": "訊息為空",
"errors.messageOverflow": "訊息超過4 KB;請改用檔案傳輸",
"errors.noReceiver": "未選擇接收方",
"errors.devTokenMissing": "Dev模式:未在.env.local設定VITE_CDROP_DEV_TOKEN",
"errors.devTokenMissing": "Dev 模式:未在 .env.local 設定開發權杖",
"errors.noAccessToken": "無存取權杖:使用者必須先登入",
"errors.clipboardUnavailable": "瀏覽器不支援剪貼簿API(需HTTPS與權限)",
"errors.clipboardOverflow": "內容過大,超過 {{max}} 位元組上限",
+1 -1
View File
@@ -80,7 +80,7 @@ struct RootView: View
.opacity(0)
.allowsHitTesting(false)
}
// Share Extension cdrop://share /
// Share Extension commilitia-drop://share /
// SendComposeSheetonSend sendShares
// move pendingShareFiles
.onAppear { engine.loadPendingShares() }