From b98b113b889f60db5cb463da66f662202e3b754c Mon Sep 17 00:00:00 2001 From: Peter Steinberger Date: Tue, 17 Feb 2026 23:47:34 +0100 Subject: [PATCH] fix(ios): harden share relay routing and delivery guards --- .../ShareExtension/ShareViewController.swift | 38 +++++++++++++++---- apps/ios/Sources/Model/NodeAppModel.swift | 9 ++--- 2 files changed, 34 insertions(+), 13 deletions(-) diff --git a/apps/ios/ShareExtension/ShareViewController.swift b/apps/ios/ShareExtension/ShareViewController.swift index 0f720f16a9..1181641e33 100644 --- a/apps/ios/ShareExtension/ShareViewController.swift +++ b/apps/ios/ShareExtension/ShareViewController.swift @@ -203,8 +203,7 @@ final class ShareViewController: UIViewController { message: "share extension does not support node invoke")) }) } catch { - let text = error.localizedDescription.lowercased() - let expectsLegacyClientId = text.contains("invalid connect params") && text.contains("/client/id") + let expectsLegacyClientId = self.shouldRetryWithLegacyClientId(error) guard expectsLegacyClientId else { throw error } try await gateway.connect( url: url, @@ -238,16 +237,20 @@ final class ShareViewController: UIViewController { var key: String? } + let deliveryChannel = config.deliveryChannel?.trimmingCharacters(in: .whitespacesAndNewlines) + let deliveryTo = config.deliveryTo?.trimmingCharacters(in: .whitespacesAndNewlines) + let canDeliverToRoute = (deliveryChannel?.isEmpty == false) && (deliveryTo?.isEmpty == false) + let params = AgentRequestPayload( message: message, sessionKey: config.sessionKey, thinking: "low", - deliver: true, + deliver: canDeliverToRoute, attachments: attachments.isEmpty ? nil : attachments, - receipt: true, - receiptText: "Just received your iOS share + request, working on it.", - to: config.deliveryTo, - channel: config.deliveryChannel, + receipt: canDeliverToRoute, + receiptText: canDeliverToRoute ? "Just received your iOS share + request, working on it." : nil, + to: canDeliverToRoute ? deliveryTo : nil, + channel: canDeliverToRoute ? deliveryChannel : nil, timeoutSeconds: nil, key: UUID().uuidString) let data = try JSONEncoder().encode(params) @@ -271,6 +274,27 @@ final class ShareViewController: UIViewController { _ = try await gateway.request(method: "node.event", paramsJSON: nodeEventParams, timeoutSeconds: 25) } + private func shouldRetryWithLegacyClientId(_ error: Error) -> Bool { + if let gatewayError = error as? GatewayResponseError { + let code = gatewayError.code.lowercased() + let message = gatewayError.message.lowercased() + let pathValue = (gatewayError.details["path"]?.value as? String)?.lowercased() ?? "" + let mentionsClientIdPath = + message.contains("/client/id") || message.contains("client id") + || pathValue.contains("/client/id") + let isInvalidConnectParams = + (code.contains("invalid") && code.contains("connect")) + || message.contains("invalid connect params") + if isInvalidConnectParams && mentionsClientIdPath { + return true + } + } + + let text = error.localizedDescription.lowercased() + return text.contains("invalid connect params") + && (text.contains("/client/id") || text.contains("client id")) + } + private func showStatus(_ text: String) { DispatchQueue.main.async { let label: UILabel diff --git a/apps/ios/Sources/Model/NodeAppModel.swift b/apps/ios/Sources/Model/NodeAppModel.swift index d1f136d3b4..8297a22b7f 100644 --- a/apps/ios/Sources/Model/NodeAppModel.swift +++ b/apps/ios/Sources/Model/NodeAppModel.swift @@ -480,8 +480,8 @@ final class NodeAppModel { token: relay.token, password: relay.password, sessionKey: self.mainSessionKey, - deliveryChannel: relay.deliveryChannel ?? self.shareDeliveryChannel, - deliveryTo: relay.deliveryTo ?? self.shareDeliveryTo)) + deliveryChannel: self.shareDeliveryChannel, + deliveryTo: self.shareDeliveryTo)) } } @@ -1982,10 +1982,7 @@ extension NodeAppModel { let exactMatch = sorted.first { row in row.key == currentKey && normalize(row.lastChannel) != nil && normalize(row.lastTo) != nil } - let fallback = sorted.first { row in - normalize(row.lastChannel) != nil && normalize(row.lastTo) != nil - } - let selected = exactMatch ?? fallback + let selected = exactMatch let channel = normalize(selected?.lastChannel) let to = normalize(selected?.lastTo)