From c46f6eedbcc18ec17fe353fb5706cedddfbb817c Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Leon=20B=C3=B6ttger?= Date: Wed, 18 Mar 2026 20:05:07 +0100 Subject: [PATCH] Extract pairing proto --- .../Connection/InboundNearbyConnection.swift | 101 ++-- .../Connection/NearbyConnectionManager.swift | 8 +- NearbyShare/Model/DataModel.swift | 25 + .../Model/Protobuf/wire_format.pb.swift | 551 +++++++++++------- .../Model/ProtobufSource/wire_format.proto | 20 +- .../Util/NotificationSyncPairingToken.swift | 6 +- NearbyShare/Util/TrustStore.swift | 37 +- QuickDrop/ViewModel/ReceiveModel.swift | 2 +- 8 files changed, 479 insertions(+), 271 deletions(-) diff --git a/NearbyShare/Connection/InboundNearbyConnection.swift b/NearbyShare/Connection/InboundNearbyConnection.swift index 853c66f..4863991 100644 --- a/NearbyShare/Connection/InboundNearbyConnection.swift +++ b/NearbyShare/Connection/InboundNearbyConnection.swift @@ -32,9 +32,10 @@ class InboundNearbyConnection: NearbyConnection { private var isAuthenticated = false private var peerCertificate: Sharing_Nearby_PublicCertificate? = nil private var mirroredNotificationMetadata: Sharing_Nearby_MirroredNotificationMetadata? - private var isNotificationSyncSetupPing = false + private var pairingMetadata: Sharing_Nearby_PairingMetadata? + private var isPairingSetupRequest = false var isPlainTextTransfer = false - var isMirroredNotificationTransfer = false + var isControlTransfer = false var wasUserRejected = false var delegate: InboundNearbyConnectionDelegate? @@ -606,25 +607,46 @@ class InboundNearbyConnection: NearbyConnection { } #if os(macOS) - if frame.v1.introduction.hasMirroredNotificationMetadata { - isMirroredNotificationTransfer = true - mirroredNotificationMetadata = frame.v1.introduction.mirroredNotificationMetadata - isNotificationSyncSetupPing = mirroredNotificationMetadata?.setupRequest == true - let setupSuccessNotice = mirroredNotificationMetadata?.hasSetupPinHash == true + if frame.v1.introduction.hasMirroredNotificationMetadata || frame.v1.introduction.hasPairingMetadata { + isControlTransfer = true + mirroredNotificationMetadata = frame.v1.introduction.hasMirroredNotificationMetadata + ? frame.v1.introduction.mirroredNotificationMetadata + : nil + pairingMetadata = frame.v1.introduction.hasPairingMetadata + ? frame.v1.introduction.pairingMetadata + : nil + isPairingSetupRequest = pairingMetadata?.setupRequest == true + let hasPairingConfirmation = pairingMetadata?.hasSetupPinHash == true + let pairingUseCase = pairingMetadata.flatMap { PairingUseCase(protoValue: $0.useCase) } guard let device = self.remoteDeviceInfo else { self.rejectTransfer(with: .reject) return } - if !isAuthenticated && !isNotificationSyncSetupPing && !setupSuccessNotice { + if pairingMetadata != nil && pairingUseCase == nil { + self.rejectTransfer(with: .reject) + return + } + + if pairingMetadata != nil, + mirroredNotificationMetadata == nil, + !isPairingSetupRequest, + !hasPairingConfirmation { + self.rejectTransfer(with: .reject) + return + } + + if !isAuthenticated && !isPairingSetupRequest && !hasPairingConfirmation { self.lastError = NearbyError.notificationSyncNotTrusted self.rejectTransfer(with: .reject, markAsUserRejected: false) return } - if setupSuccessNotice { - guard let peerCertificate = peerCertificate else { + if hasPairingConfirmation { + guard let peerCertificate = peerCertificate, + let pairingMetadata, + let pairingUseCase else { self.rejectTransfer(with: .reject) return } @@ -643,15 +665,10 @@ class InboundNearbyConnection: NearbyConnection { return } - guard let metadata = mirroredNotificationMetadata, - metadata.hasSetupPinHash else { - self.rejectTransfer(with: .reject) - return - } - - let matches = TrustStore.shared.confirmPendingNotificationSyncTrust( + let matches = TrustStore.shared.confirmPendingPairingTrust( secretIdHex: peerCertificate.secretID.hex, - pinHash: metadata.setupPinHash + useCase: pairingUseCase, + pinHash: pairingMetadata.setupPinHash ) guard matches else { @@ -667,12 +684,16 @@ class InboundNearbyConnection: NearbyConnection { return } - if !isAuthenticated || isNotificationSyncSetupPing { + if !isAuthenticated || isPairingSetupRequest { + guard let transferType = pairingTransferType(for: pairingUseCase) else { + self.rejectTransfer(with: .reject) + return + } let metadata = TransferMetadata( files: [], id: id, pinCode: pinCode, - transferType: .notificationSync, + transferType: transferType, allowsToBeAddedAsTrustedDevice: true ) @@ -733,23 +754,27 @@ class InboundNearbyConnection: NearbyConnection { } - func submitUserConsent(accepted: Bool, trustDevice: Bool, notificationSyncToken: String? = nil) { - if isNotificationSyncSetupPing, let peerCertificate = peerCertificate { + func submitUserConsent(accepted: Bool, trustDevice: Bool, pairingToken: String? = nil) { + if isPairingSetupRequest, + let peerCertificate = peerCertificate, + let pairingMetadata, + let pairingUseCase = PairingUseCase(protoValue: pairingMetadata.useCase) { let secretIdHex = peerCertificate.secretID.hex if accepted { if TrustStore.shared.findTrustedKey(for: peerCertificate.secretID) == nil { - if let token = notificationSyncToken { - TrustStore.shared.registerPendingNotificationSyncTrust( + if let token = pairingToken { + TrustStore.shared.registerPendingPairingTrust( secretIdHex: secretIdHex, - pinCode: token + pinCode: token, + useCase: pairingUseCase ) } else { - log("[InboundNearbyConnection \(self.id)] Missing notification sync pairing token; pending trust not registered.") - TrustStore.shared.clearPendingNotificationSyncTrust(secretIdHex: secretIdHex) + log("[InboundNearbyConnection \(self.id)] Missing pairing token; pending trust not registered.") + TrustStore.shared.clearPendingPairingTrust(secretIdHex: secretIdHex) } } } else { - TrustStore.shared.clearPendingNotificationSyncTrust(secretIdHex: secretIdHex) + TrustStore.shared.clearPendingPairingTrust(secretIdHex: secretIdHex) } } @@ -773,7 +798,7 @@ class InboundNearbyConnection: NearbyConnection { return } - if !isMirroredNotificationTransfer && isFileTransferRestricted() { + if !isControlTransfer && isFileTransferRestricted() { log("[InboundNearbyConnection \(self.id)] File transfer restrictions detected.") delegate?.showPlusScreen() rejectTransfer() @@ -818,10 +843,11 @@ class InboundNearbyConnection: NearbyConnection { isTransferring = true try sendTransferSetupFrame(frame) - if let mirroredNotificationMetadata { - if !isNotificationSyncSetupPing { - MirroredNotificationPresenter.shared.present(metadata: mirroredNotificationMetadata, senderDeviceName: remoteDeviceInfo?.name) - } + if let mirroredNotificationMetadata, + !isPairingSetupRequest { + MirroredNotificationPresenter.shared.present(metadata: mirroredNotificationMetadata, senderDeviceName: remoteDeviceInfo?.name) + } + if isControlTransfer { try sendDisconnectionAndDisconnect() } } catch { @@ -830,6 +856,15 @@ class InboundNearbyConnection: NearbyConnection { } } + private func pairingTransferType(for useCase: PairingUseCase?) -> TransferMetadata.TransferType? { + switch useCase { + case .notificationSync: + return .notificationSync + case .clipboardSync, .none: + return nil + } + } + private func rejectTransfer(with reason: Sharing_Nearby_ConnectionResponseFrame.Status = .reject, markAsUserRejected: Bool = true) { diff --git a/NearbyShare/Connection/NearbyConnectionManager.swift b/NearbyShare/Connection/NearbyConnectionManager.swift index 90ca70c..2512850 100644 --- a/NearbyShare/Connection/NearbyConnectionManager.swift +++ b/NearbyShare/Connection/NearbyConnectionManager.swift @@ -362,9 +362,9 @@ public class NearbyConnectionManager: NSObject, NetServiceDelegate, InboundNearb func connectionWasTerminated(connection: InboundNearbyConnection, savedFiles: [URL], error: Error?) { incomingConnections.removeValue(forKey: connection.id) - // Notification-sync transfers suppress normal success callbacks, but + // Control transfers suppress normal success callbacks, but // still forward failures so pending consent/error UI can be cleaned up. - if connection.isMirroredNotificationTransfer, error == nil { + if connection.isControlTransfer, error == nil { return } @@ -400,12 +400,12 @@ public class NearbyConnectionManager: NSObject, NetServiceDelegate, InboundNearb transferID: String, accept: Bool, trustDevice: Bool, - notificationSyncToken: String? = nil + pairingToken: String? = nil ) { guard let conn = incomingConnections[transferID] else { return } log("[NearbyConnectionManager] Submitting user consent for transfer \(transferID), accepted: \(accept)") - conn.submitUserConsent(accepted: accept, trustDevice: trustDevice, notificationSyncToken: notificationSyncToken) + conn.submitUserConsent(accepted: accept, trustDevice: trustDevice, pairingToken: pairingToken) } diff --git a/NearbyShare/Model/DataModel.swift b/NearbyShare/Model/DataModel.swift index 40fe7b3..02daec3 100644 --- a/NearbyShare/Model/DataModel.swift +++ b/NearbyShare/Model/DataModel.swift @@ -217,6 +217,31 @@ public struct TransferMetadata { } } +enum PairingUseCase: String { + case notificationSync = "notification_sync" + case clipboardSync = "clipboard_sync" + + var protoValue: Sharing_Nearby_PairingMetadata.UseCase { + switch self { + case .notificationSync: + return .notificationSync + case .clipboardSync: + return .clipboardSync + } + } + + init?(protoValue: Sharing_Nearby_PairingMetadata.UseCase) { + switch protoValue { + case .notificationSync: + self = .notificationSync + case .clipboardSync: + self = .clipboardSync + case .unknown: + return nil + } + } +} + public struct FileMetadata { public let name: String diff --git a/NearbyShare/Model/Protobuf/wire_format.pb.swift b/NearbyShare/Model/Protobuf/wire_format.pb.swift index af65b31..dd61f38 100644 --- a/NearbyShare/Model/Protobuf/wire_format.pb.swift +++ b/NearbyShare/Model/Protobuf/wire_format.pb.swift @@ -403,6 +403,43 @@ struct Sharing_Nearby_MirroredNotificationMetadata: Sendable { /// Clears the value of `postedAtEpochMs`. Subsequent reads from it will return its default value. mutating func clearPostedAtEpochMs() {self._postedAtEpochMs = nil} + var unknownFields = SwiftProtobuf.UnknownStorage() + + init() {} + + fileprivate var _version: Int32? = nil + fileprivate var _notificationKey: String? = nil + fileprivate var _packageName: String? = nil + fileprivate var _appName: String? = nil + fileprivate var _title: String? = nil + fileprivate var _body: String? = nil + fileprivate var _postedAtEpochMs: Int64? = nil +} + +/// NEXT_ID=5 +struct Sharing_Nearby_PairingMetadata: Sendable { + // SwiftProtobuf.Message conformance is added in an extension below. See the + // `Message` and `Message+*Additions` files in the SwiftProtobuf library for + // methods supported on all messages. + + var version: Int32 { + get {return _version ?? 1} + set {_version = newValue} + } + /// Returns true if `version` has been explicitly set. + var hasVersion: Bool {return self._version != nil} + /// Clears the value of `version`. Subsequent reads from it will return its default value. + mutating func clearVersion() {self._version = nil} + + var useCase: Sharing_Nearby_PairingMetadata.UseCase { + get {return _useCase ?? .unknown} + set {_useCase = newValue} + } + /// Returns true if `useCase` has been explicitly set. + var hasUseCase: Bool {return self._useCase != nil} + /// Clears the value of `useCase`. Subsequent reads from it will return its default value. + mutating func clearUseCase() {self._useCase = nil} + var setupRequest: Bool { get {return _setupRequest ?? false} set {_setupRequest = newValue} @@ -423,15 +460,21 @@ struct Sharing_Nearby_MirroredNotificationMetadata: Sendable { var unknownFields = SwiftProtobuf.UnknownStorage() + enum UseCase: Int, SwiftProtobuf.Enum, Swift.CaseIterable { + case unknown = 0 + case notificationSync = 1 + case clipboardSync = 2 + + init() { + self = .unknown + } + + } + init() {} fileprivate var _version: Int32? = nil - fileprivate var _notificationKey: String? = nil - fileprivate var _packageName: String? = nil - fileprivate var _appName: String? = nil - fileprivate var _title: String? = nil - fileprivate var _body: String? = nil - fileprivate var _postedAtEpochMs: Int64? = nil + fileprivate var _useCase: Sharing_Nearby_PairingMetadata.UseCase? = nil fileprivate var _setupRequest: Bool? = nil fileprivate var _setupPinHash: Data? = nil } @@ -607,76 +650,76 @@ struct Sharing_Nearby_Frame: Sendable { } /// NEXT_ID=8 -struct Sharing_Nearby_V1Frame: @unchecked Sendable { +struct Sharing_Nearby_V1Frame: Sendable { // SwiftProtobuf.Message conformance is added in an extension below. See the // `Message` and `Message+*Additions` files in the SwiftProtobuf library for // methods supported on all messages. var type: Sharing_Nearby_V1Frame.FrameType { - get {return _storage._type ?? .unknownFrameType} - set {_uniqueStorage()._type = newValue} + get {return _type ?? .unknownFrameType} + set {_type = newValue} } /// Returns true if `type` has been explicitly set. - var hasType: Bool {return _storage._type != nil} + var hasType: Bool {return self._type != nil} /// Clears the value of `type`. Subsequent reads from it will return its default value. - mutating func clearType() {_uniqueStorage()._type = nil} + mutating func clearType() {self._type = nil} /// At most one of the following fields will be set. var introduction: Sharing_Nearby_IntroductionFrame { - get {return _storage._introduction ?? Sharing_Nearby_IntroductionFrame()} - set {_uniqueStorage()._introduction = newValue} + get {return _introduction ?? Sharing_Nearby_IntroductionFrame()} + set {_introduction = newValue} } /// Returns true if `introduction` has been explicitly set. - var hasIntroduction: Bool {return _storage._introduction != nil} + var hasIntroduction: Bool {return self._introduction != nil} /// Clears the value of `introduction`. Subsequent reads from it will return its default value. - mutating func clearIntroduction() {_uniqueStorage()._introduction = nil} + mutating func clearIntroduction() {self._introduction = nil} var connectionResponse: Sharing_Nearby_ConnectionResponseFrame { - get {return _storage._connectionResponse ?? Sharing_Nearby_ConnectionResponseFrame()} - set {_uniqueStorage()._connectionResponse = newValue} + get {return _connectionResponse ?? Sharing_Nearby_ConnectionResponseFrame()} + set {_connectionResponse = newValue} } /// Returns true if `connectionResponse` has been explicitly set. - var hasConnectionResponse: Bool {return _storage._connectionResponse != nil} + var hasConnectionResponse: Bool {return self._connectionResponse != nil} /// Clears the value of `connectionResponse`. Subsequent reads from it will return its default value. - mutating func clearConnectionResponse() {_uniqueStorage()._connectionResponse = nil} + mutating func clearConnectionResponse() {self._connectionResponse = nil} var pairedKeyEncryption: Sharing_Nearby_PairedKeyEncryptionFrame { - get {return _storage._pairedKeyEncryption ?? Sharing_Nearby_PairedKeyEncryptionFrame()} - set {_uniqueStorage()._pairedKeyEncryption = newValue} + get {return _pairedKeyEncryption ?? Sharing_Nearby_PairedKeyEncryptionFrame()} + set {_pairedKeyEncryption = newValue} } /// Returns true if `pairedKeyEncryption` has been explicitly set. - var hasPairedKeyEncryption: Bool {return _storage._pairedKeyEncryption != nil} + var hasPairedKeyEncryption: Bool {return self._pairedKeyEncryption != nil} /// Clears the value of `pairedKeyEncryption`. Subsequent reads from it will return its default value. - mutating func clearPairedKeyEncryption() {_uniqueStorage()._pairedKeyEncryption = nil} + mutating func clearPairedKeyEncryption() {self._pairedKeyEncryption = nil} var pairedKeyResult: Sharing_Nearby_PairedKeyResultFrame { - get {return _storage._pairedKeyResult ?? Sharing_Nearby_PairedKeyResultFrame()} - set {_uniqueStorage()._pairedKeyResult = newValue} + get {return _pairedKeyResult ?? Sharing_Nearby_PairedKeyResultFrame()} + set {_pairedKeyResult = newValue} } /// Returns true if `pairedKeyResult` has been explicitly set. - var hasPairedKeyResult: Bool {return _storage._pairedKeyResult != nil} + var hasPairedKeyResult: Bool {return self._pairedKeyResult != nil} /// Clears the value of `pairedKeyResult`. Subsequent reads from it will return its default value. - mutating func clearPairedKeyResult() {_uniqueStorage()._pairedKeyResult = nil} + mutating func clearPairedKeyResult() {self._pairedKeyResult = nil} /// NOTE: This field was marked as deprecated in the .proto file. var certificateInfo: Sharing_Nearby_CertificateInfoFrame { - get {return _storage._certificateInfo ?? Sharing_Nearby_CertificateInfoFrame()} - set {_uniqueStorage()._certificateInfo = newValue} + get {return _certificateInfo ?? Sharing_Nearby_CertificateInfoFrame()} + set {_certificateInfo = newValue} } /// Returns true if `certificateInfo` has been explicitly set. - var hasCertificateInfo: Bool {return _storage._certificateInfo != nil} + var hasCertificateInfo: Bool {return self._certificateInfo != nil} /// Clears the value of `certificateInfo`. Subsequent reads from it will return its default value. - mutating func clearCertificateInfo() {_uniqueStorage()._certificateInfo = nil} + mutating func clearCertificateInfo() {self._certificateInfo = nil} /// NOTE: This field was marked as deprecated in the .proto file. var progressUpdate: Sharing_Nearby_ProgressUpdateFrame { - get {return _storage._progressUpdate ?? Sharing_Nearby_ProgressUpdateFrame()} - set {_uniqueStorage()._progressUpdate = newValue} + get {return _progressUpdate ?? Sharing_Nearby_ProgressUpdateFrame()} + set {_progressUpdate = newValue} } /// Returns true if `progressUpdate` has been explicitly set. - var hasProgressUpdate: Bool {return _storage._progressUpdate != nil} + var hasProgressUpdate: Bool {return self._progressUpdate != nil} /// Clears the value of `progressUpdate`. Subsequent reads from it will return its default value. - mutating func clearProgressUpdate() {_uniqueStorage()._progressUpdate = nil} + mutating func clearProgressUpdate() {self._progressUpdate = nil} var unknownFields = SwiftProtobuf.UnknownStorage() @@ -702,65 +745,98 @@ struct Sharing_Nearby_V1Frame: @unchecked Sendable { init() {} - fileprivate var _storage = _StorageClass.defaultInstance + fileprivate var _type: Sharing_Nearby_V1Frame.FrameType? = nil + fileprivate var _introduction: Sharing_Nearby_IntroductionFrame? = nil + fileprivate var _connectionResponse: Sharing_Nearby_ConnectionResponseFrame? = nil + fileprivate var _pairedKeyEncryption: Sharing_Nearby_PairedKeyEncryptionFrame? = nil + fileprivate var _pairedKeyResult: Sharing_Nearby_PairedKeyResultFrame? = nil + fileprivate var _certificateInfo: Sharing_Nearby_CertificateInfoFrame? = nil + fileprivate var _progressUpdate: Sharing_Nearby_ProgressUpdateFrame? = nil } /// An introduction packet sent by the sending side. Contains a list of files /// they'd like to share. -/// NEXT_ID=1002 -struct Sharing_Nearby_IntroductionFrame: Sendable { +/// NEXT_ID=1003 +struct Sharing_Nearby_IntroductionFrame: @unchecked Sendable { // SwiftProtobuf.Message conformance is added in an extension below. See the // `Message` and `Message+*Additions` files in the SwiftProtobuf library for // methods supported on all messages. - var fileMetadata: [Sharing_Nearby_FileMetadata] = [] + var fileMetadata: [Sharing_Nearby_FileMetadata] { + get {return _storage._fileMetadata} + set {_uniqueStorage()._fileMetadata = newValue} + } - var textMetadata: [Sharing_Nearby_TextMetadata] = [] + var textMetadata: [Sharing_Nearby_TextMetadata] { + get {return _storage._textMetadata} + set {_uniqueStorage()._textMetadata = newValue} + } /// The required app package to open the content. May be null. var requiredPackage: String { - get {return _requiredPackage ?? String()} - set {_requiredPackage = newValue} + get {return _storage._requiredPackage ?? String()} + set {_uniqueStorage()._requiredPackage = newValue} } /// Returns true if `requiredPackage` has been explicitly set. - var hasRequiredPackage: Bool {return self._requiredPackage != nil} + var hasRequiredPackage: Bool {return _storage._requiredPackage != nil} /// Clears the value of `requiredPackage`. Subsequent reads from it will return its default value. - mutating func clearRequiredPackage() {self._requiredPackage = nil} + mutating func clearRequiredPackage() {_uniqueStorage()._requiredPackage = nil} - var wifiCredentialsMetadata: [Sharing_Nearby_WifiCredentialsMetadata] = [] + var wifiCredentialsMetadata: [Sharing_Nearby_WifiCredentialsMetadata] { + get {return _storage._wifiCredentialsMetadata} + set {_uniqueStorage()._wifiCredentialsMetadata = newValue} + } - var appMetadata: [Sharing_Nearby_AppMetadata] = [] + var appMetadata: [Sharing_Nearby_AppMetadata] { + get {return _storage._appMetadata} + set {_uniqueStorage()._appMetadata = newValue} + } var startTransfer: Bool { - get {return _startTransfer ?? false} - set {_startTransfer = newValue} + get {return _storage._startTransfer ?? false} + set {_uniqueStorage()._startTransfer = newValue} } /// Returns true if `startTransfer` has been explicitly set. - var hasStartTransfer: Bool {return self._startTransfer != nil} + var hasStartTransfer: Bool {return _storage._startTransfer != nil} /// Clears the value of `startTransfer`. Subsequent reads from it will return its default value. - mutating func clearStartTransfer() {self._startTransfer = nil} + mutating func clearStartTransfer() {_uniqueStorage()._startTransfer = nil} - var streamMetadata: [Sharing_Nearby_StreamMetadata] = [] + var streamMetadata: [Sharing_Nearby_StreamMetadata] { + get {return _storage._streamMetadata} + set {_uniqueStorage()._streamMetadata = newValue} + } var useCase: Sharing_Nearby_IntroductionFrame.SharingUseCase { - get {return _useCase ?? .unknown} - set {_useCase = newValue} + get {return _storage._useCase ?? .unknown} + set {_uniqueStorage()._useCase = newValue} } /// Returns true if `useCase` has been explicitly set. - var hasUseCase: Bool {return self._useCase != nil} + var hasUseCase: Bool {return _storage._useCase != nil} /// Clears the value of `useCase`. Subsequent reads from it will return its default value. - mutating func clearUseCase() {self._useCase = nil} + mutating func clearUseCase() {_uniqueStorage()._useCase = nil} - var previewPayloadIds: [Int64] = [] + var previewPayloadIds: [Int64] { + get {return _storage._previewPayloadIds} + set {_uniqueStorage()._previewPayloadIds = newValue} + } var mirroredNotificationMetadata: Sharing_Nearby_MirroredNotificationMetadata { - get {return _mirroredNotificationMetadata ?? Sharing_Nearby_MirroredNotificationMetadata()} - set {_mirroredNotificationMetadata = newValue} + get {return _storage._mirroredNotificationMetadata ?? Sharing_Nearby_MirroredNotificationMetadata()} + set {_uniqueStorage()._mirroredNotificationMetadata = newValue} } /// Returns true if `mirroredNotificationMetadata` has been explicitly set. - var hasMirroredNotificationMetadata: Bool {return self._mirroredNotificationMetadata != nil} + var hasMirroredNotificationMetadata: Bool {return _storage._mirroredNotificationMetadata != nil} /// Clears the value of `mirroredNotificationMetadata`. Subsequent reads from it will return its default value. - mutating func clearMirroredNotificationMetadata() {self._mirroredNotificationMetadata = nil} + mutating func clearMirroredNotificationMetadata() {_uniqueStorage()._mirroredNotificationMetadata = nil} + + var pairingMetadata: Sharing_Nearby_PairingMetadata { + get {return _storage._pairingMetadata ?? Sharing_Nearby_PairingMetadata()} + set {_uniqueStorage()._pairingMetadata = newValue} + } + /// Returns true if `pairingMetadata` has been explicitly set. + var hasPairingMetadata: Bool {return _storage._pairingMetadata != nil} + /// Clears the value of `pairingMetadata`. Subsequent reads from it will return its default value. + mutating func clearPairingMetadata() {_uniqueStorage()._pairingMetadata = nil} var unknownFields = SwiftProtobuf.UnknownStorage() @@ -777,10 +853,7 @@ struct Sharing_Nearby_IntroductionFrame: Sendable { init() {} - fileprivate var _requiredPackage: String? = nil - fileprivate var _startTransfer: Bool? = nil - fileprivate var _useCase: Sharing_Nearby_IntroductionFrame.SharingUseCase? = nil - fileprivate var _mirroredNotificationMetadata: Sharing_Nearby_MirroredNotificationMetadata? = nil + fileprivate var _storage = _StorageClass.defaultInstance } /// A progress update packet sent by the sending side. Contains transfer progress @@ -1485,7 +1558,7 @@ extension Sharing_Nearby_WifiCredentialsMetadata.SecurityType: SwiftProtobuf._Pr extension Sharing_Nearby_MirroredNotificationMetadata: SwiftProtobuf.Message, SwiftProtobuf._MessageImplementationBase, SwiftProtobuf._ProtoNameProviding { static let protoMessageName: String = _protobuf_package + ".MirroredNotificationMetadata" - static let _protobuf_nameMap = SwiftProtobuf._NameMap(bytecode: "\0\u{1}version\0\u{3}notification_key\0\u{3}package_name\0\u{3}app_name\0\u{1}title\0\u{1}body\0\u{3}posted_at_epoch_ms\0\u{3}setup_request\0\u{3}setup_pin_hash\0") + static let _protobuf_nameMap = SwiftProtobuf._NameMap(bytecode: "\0\u{1}version\0\u{3}notification_key\0\u{3}package_name\0\u{3}app_name\0\u{1}title\0\u{1}body\0\u{3}posted_at_epoch_ms\0\u{c}\u{8}\u{1}\u{c}\u{9}\u{1}") mutating func decodeMessage(decoder: inout D) throws { while let fieldNumber = try decoder.nextFieldNumber() { @@ -1500,8 +1573,6 @@ extension Sharing_Nearby_MirroredNotificationMetadata: SwiftProtobuf.Message, Sw case 5: try { try decoder.decodeSingularStringField(value: &self._title) }() case 6: try { try decoder.decodeSingularStringField(value: &self._body) }() case 7: try { try decoder.decodeSingularInt64Field(value: &self._postedAtEpochMs) }() - case 8: try { try decoder.decodeSingularBoolField(value: &self._setupRequest) }() - case 9: try { try decoder.decodeSingularBytesField(value: &self._setupPinHash) }() default: break } } @@ -1533,12 +1604,6 @@ extension Sharing_Nearby_MirroredNotificationMetadata: SwiftProtobuf.Message, Sw try { if let v = self._postedAtEpochMs { try visitor.visitSingularInt64Field(value: v, fieldNumber: 7) } }() - try { if let v = self._setupRequest { - try visitor.visitSingularBoolField(value: v, fieldNumber: 8) - } }() - try { if let v = self._setupPinHash { - try visitor.visitSingularBytesField(value: v, fieldNumber: 9) - } }() try unknownFields.traverse(visitor: &visitor) } @@ -1550,6 +1615,53 @@ extension Sharing_Nearby_MirroredNotificationMetadata: SwiftProtobuf.Message, Sw if lhs._title != rhs._title {return false} if lhs._body != rhs._body {return false} if lhs._postedAtEpochMs != rhs._postedAtEpochMs {return false} + if lhs.unknownFields != rhs.unknownFields {return false} + return true + } +} + +extension Sharing_Nearby_PairingMetadata: SwiftProtobuf.Message, SwiftProtobuf._MessageImplementationBase, SwiftProtobuf._ProtoNameProviding { + static let protoMessageName: String = _protobuf_package + ".PairingMetadata" + static let _protobuf_nameMap = SwiftProtobuf._NameMap(bytecode: "\0\u{1}version\0\u{3}use_case\0\u{3}setup_request\0\u{3}setup_pin_hash\0") + + mutating func decodeMessage(decoder: inout D) throws { + while let fieldNumber = try decoder.nextFieldNumber() { + // The use of inline closures is to circumvent an issue where the compiler + // allocates stack space for every case branch when no optimizations are + // enabled. https://github.com/apple/swift-protobuf/issues/1034 + switch fieldNumber { + case 1: try { try decoder.decodeSingularInt32Field(value: &self._version) }() + case 2: try { try decoder.decodeSingularEnumField(value: &self._useCase) }() + case 3: try { try decoder.decodeSingularBoolField(value: &self._setupRequest) }() + case 4: try { try decoder.decodeSingularBytesField(value: &self._setupPinHash) }() + default: break + } + } + } + + func traverse(visitor: inout V) throws { + // The use of inline closures is to circumvent an issue where the compiler + // allocates stack space for every if/case branch local when no optimizations + // are enabled. https://github.com/apple/swift-protobuf/issues/1034 and + // https://github.com/apple/swift-protobuf/issues/1182 + try { if let v = self._version { + try visitor.visitSingularInt32Field(value: v, fieldNumber: 1) + } }() + try { if let v = self._useCase { + try visitor.visitSingularEnumField(value: v, fieldNumber: 2) + } }() + try { if let v = self._setupRequest { + try visitor.visitSingularBoolField(value: v, fieldNumber: 3) + } }() + try { if let v = self._setupPinHash { + try visitor.visitSingularBytesField(value: v, fieldNumber: 4) + } }() + try unknownFields.traverse(visitor: &visitor) + } + + static func ==(lhs: Sharing_Nearby_PairingMetadata, rhs: Sharing_Nearby_PairingMetadata) -> Bool { + if lhs._version != rhs._version {return false} + if lhs._useCase != rhs._useCase {return false} if lhs._setupRequest != rhs._setupRequest {return false} if lhs._setupPinHash != rhs._setupPinHash {return false} if lhs.unknownFields != rhs.unknownFields {return false} @@ -1557,6 +1669,10 @@ extension Sharing_Nearby_MirroredNotificationMetadata: SwiftProtobuf.Message, Sw } } +extension Sharing_Nearby_PairingMetadata.UseCase: SwiftProtobuf._ProtoNameProviding { + static let _protobuf_nameMap = SwiftProtobuf._NameMap(bytecode: "\0\u{2}\0UNKNOWN\0\u{1}NOTIFICATION_SYNC\0\u{1}CLIPBOARD_SYNC\0") +} + extension Sharing_Nearby_AppMetadata: SwiftProtobuf.Message, SwiftProtobuf._MessageImplementationBase, SwiftProtobuf._ProtoNameProviding { static let protoMessageName: String = _protobuf_package + ".AppMetadata" static let _protobuf_nameMap = SwiftProtobuf._NameMap(bytecode: "\0\u{3}app_name\0\u{1}size\0\u{3}payload_id\0\u{1}id\0\u{3}file_name\0\u{3}file_size\0\u{3}package_name\0") @@ -1717,14 +1833,86 @@ extension Sharing_Nearby_V1Frame: SwiftProtobuf.Message, SwiftProtobuf._MessageI static let protoMessageName: String = _protobuf_package + ".V1Frame" static let _protobuf_nameMap = SwiftProtobuf._NameMap(bytecode: "\0\u{1}type\0\u{1}introduction\0\u{3}connection_response\0\u{3}paired_key_encryption\0\u{3}paired_key_result\0\u{3}certificate_info\0\u{3}progress_update\0") + mutating func decodeMessage(decoder: inout D) throws { + while let fieldNumber = try decoder.nextFieldNumber() { + // The use of inline closures is to circumvent an issue where the compiler + // allocates stack space for every case branch when no optimizations are + // enabled. https://github.com/apple/swift-protobuf/issues/1034 + switch fieldNumber { + case 1: try { try decoder.decodeSingularEnumField(value: &self._type) }() + case 2: try { try decoder.decodeSingularMessageField(value: &self._introduction) }() + case 3: try { try decoder.decodeSingularMessageField(value: &self._connectionResponse) }() + case 4: try { try decoder.decodeSingularMessageField(value: &self._pairedKeyEncryption) }() + case 5: try { try decoder.decodeSingularMessageField(value: &self._pairedKeyResult) }() + case 6: try { try decoder.decodeSingularMessageField(value: &self._certificateInfo) }() + case 7: try { try decoder.decodeSingularMessageField(value: &self._progressUpdate) }() + default: break + } + } + } + + func traverse(visitor: inout V) throws { + // The use of inline closures is to circumvent an issue where the compiler + // allocates stack space for every if/case branch local when no optimizations + // are enabled. https://github.com/apple/swift-protobuf/issues/1034 and + // https://github.com/apple/swift-protobuf/issues/1182 + try { if let v = self._type { + try visitor.visitSingularEnumField(value: v, fieldNumber: 1) + } }() + try { if let v = self._introduction { + try visitor.visitSingularMessageField(value: v, fieldNumber: 2) + } }() + try { if let v = self._connectionResponse { + try visitor.visitSingularMessageField(value: v, fieldNumber: 3) + } }() + try { if let v = self._pairedKeyEncryption { + try visitor.visitSingularMessageField(value: v, fieldNumber: 4) + } }() + try { if let v = self._pairedKeyResult { + try visitor.visitSingularMessageField(value: v, fieldNumber: 5) + } }() + try { if let v = self._certificateInfo { + try visitor.visitSingularMessageField(value: v, fieldNumber: 6) + } }() + try { if let v = self._progressUpdate { + try visitor.visitSingularMessageField(value: v, fieldNumber: 7) + } }() + try unknownFields.traverse(visitor: &visitor) + } + + static func ==(lhs: Sharing_Nearby_V1Frame, rhs: Sharing_Nearby_V1Frame) -> Bool { + if lhs._type != rhs._type {return false} + if lhs._introduction != rhs._introduction {return false} + if lhs._connectionResponse != rhs._connectionResponse {return false} + if lhs._pairedKeyEncryption != rhs._pairedKeyEncryption {return false} + if lhs._pairedKeyResult != rhs._pairedKeyResult {return false} + if lhs._certificateInfo != rhs._certificateInfo {return false} + if lhs._progressUpdate != rhs._progressUpdate {return false} + if lhs.unknownFields != rhs.unknownFields {return false} + return true + } +} + +extension Sharing_Nearby_V1Frame.FrameType: SwiftProtobuf._ProtoNameProviding { + static let _protobuf_nameMap = SwiftProtobuf._NameMap(bytecode: "\0\u{2}\0UNKNOWN_FRAME_TYPE\0\u{1}INTRODUCTION\0\u{1}RESPONSE\0\u{1}PAIRED_KEY_ENCRYPTION\0\u{1}PAIRED_KEY_RESULT\0\u{1}CERTIFICATE_INFO\0\u{1}CANCEL\0\u{1}PROGRESS_UPDATE\0") +} + +extension Sharing_Nearby_IntroductionFrame: SwiftProtobuf.Message, SwiftProtobuf._MessageImplementationBase, SwiftProtobuf._ProtoNameProviding { + static let protoMessageName: String = _protobuf_package + ".IntroductionFrame" + static let _protobuf_nameMap = SwiftProtobuf._NameMap(bytecode: "\0\u{3}file_metadata\0\u{3}text_metadata\0\u{3}required_package\0\u{3}wifi_credentials_metadata\0\u{3}app_metadata\0\u{3}start_transfer\0\u{3}stream_metadata\0\u{3}use_case\0\u{3}preview_payload_ids\0\u{4}`\u{f}mirrored_notification_metadata\0\u{3}pairing_metadata\0") + fileprivate class _StorageClass { - var _type: Sharing_Nearby_V1Frame.FrameType? = nil - var _introduction: Sharing_Nearby_IntroductionFrame? = nil - var _connectionResponse: Sharing_Nearby_ConnectionResponseFrame? = nil - var _pairedKeyEncryption: Sharing_Nearby_PairedKeyEncryptionFrame? = nil - var _pairedKeyResult: Sharing_Nearby_PairedKeyResultFrame? = nil - var _certificateInfo: Sharing_Nearby_CertificateInfoFrame? = nil - var _progressUpdate: Sharing_Nearby_ProgressUpdateFrame? = nil + var _fileMetadata: [Sharing_Nearby_FileMetadata] = [] + var _textMetadata: [Sharing_Nearby_TextMetadata] = [] + var _requiredPackage: String? = nil + var _wifiCredentialsMetadata: [Sharing_Nearby_WifiCredentialsMetadata] = [] + var _appMetadata: [Sharing_Nearby_AppMetadata] = [] + var _startTransfer: Bool? = nil + var _streamMetadata: [Sharing_Nearby_StreamMetadata] = [] + var _useCase: Sharing_Nearby_IntroductionFrame.SharingUseCase? = nil + var _previewPayloadIds: [Int64] = [] + var _mirroredNotificationMetadata: Sharing_Nearby_MirroredNotificationMetadata? = nil + var _pairingMetadata: Sharing_Nearby_PairingMetadata? = nil // This property is used as the initial default value for new instances of the type. // The type itself is protecting the reference to its storage via CoW semantics. @@ -1735,13 +1923,17 @@ extension Sharing_Nearby_V1Frame: SwiftProtobuf.Message, SwiftProtobuf._MessageI private init() {} init(copying source: _StorageClass) { - _type = source._type - _introduction = source._introduction - _connectionResponse = source._connectionResponse - _pairedKeyEncryption = source._pairedKeyEncryption - _pairedKeyResult = source._pairedKeyResult - _certificateInfo = source._certificateInfo - _progressUpdate = source._progressUpdate + _fileMetadata = source._fileMetadata + _textMetadata = source._textMetadata + _requiredPackage = source._requiredPackage + _wifiCredentialsMetadata = source._wifiCredentialsMetadata + _appMetadata = source._appMetadata + _startTransfer = source._startTransfer + _streamMetadata = source._streamMetadata + _useCase = source._useCase + _previewPayloadIds = source._previewPayloadIds + _mirroredNotificationMetadata = source._mirroredNotificationMetadata + _pairingMetadata = source._pairingMetadata } } @@ -1760,13 +1952,17 @@ extension Sharing_Nearby_V1Frame: SwiftProtobuf.Message, SwiftProtobuf._MessageI // allocates stack space for every case branch when no optimizations are // enabled. https://github.com/apple/swift-protobuf/issues/1034 switch fieldNumber { - case 1: try { try decoder.decodeSingularEnumField(value: &_storage._type) }() - case 2: try { try decoder.decodeSingularMessageField(value: &_storage._introduction) }() - case 3: try { try decoder.decodeSingularMessageField(value: &_storage._connectionResponse) }() - case 4: try { try decoder.decodeSingularMessageField(value: &_storage._pairedKeyEncryption) }() - case 5: try { try decoder.decodeSingularMessageField(value: &_storage._pairedKeyResult) }() - case 6: try { try decoder.decodeSingularMessageField(value: &_storage._certificateInfo) }() - case 7: try { try decoder.decodeSingularMessageField(value: &_storage._progressUpdate) }() + case 1: try { try decoder.decodeRepeatedMessageField(value: &_storage._fileMetadata) }() + case 2: try { try decoder.decodeRepeatedMessageField(value: &_storage._textMetadata) }() + case 3: try { try decoder.decodeSingularStringField(value: &_storage._requiredPackage) }() + case 4: try { try decoder.decodeRepeatedMessageField(value: &_storage._wifiCredentialsMetadata) }() + case 5: try { try decoder.decodeRepeatedMessageField(value: &_storage._appMetadata) }() + case 6: try { try decoder.decodeSingularBoolField(value: &_storage._startTransfer) }() + case 7: try { try decoder.decodeRepeatedMessageField(value: &_storage._streamMetadata) }() + case 8: try { try decoder.decodeSingularEnumField(value: &_storage._useCase) }() + case 9: try { try decoder.decodeRepeatedInt64Field(value: &_storage._previewPayloadIds) }() + case 1001: try { try decoder.decodeSingularMessageField(value: &_storage._mirroredNotificationMetadata) }() + case 1002: try { try decoder.decodeSingularMessageField(value: &_storage._pairingMetadata) }() default: break } } @@ -1779,130 +1975,63 @@ extension Sharing_Nearby_V1Frame: SwiftProtobuf.Message, SwiftProtobuf._MessageI // allocates stack space for every if/case branch local when no optimizations // are enabled. https://github.com/apple/swift-protobuf/issues/1034 and // https://github.com/apple/swift-protobuf/issues/1182 - try { if let v = _storage._type { - try visitor.visitSingularEnumField(value: v, fieldNumber: 1) - } }() - try { if let v = _storage._introduction { - try visitor.visitSingularMessageField(value: v, fieldNumber: 2) - } }() - try { if let v = _storage._connectionResponse { - try visitor.visitSingularMessageField(value: v, fieldNumber: 3) - } }() - try { if let v = _storage._pairedKeyEncryption { - try visitor.visitSingularMessageField(value: v, fieldNumber: 4) - } }() - try { if let v = _storage._pairedKeyResult { - try visitor.visitSingularMessageField(value: v, fieldNumber: 5) - } }() - try { if let v = _storage._certificateInfo { - try visitor.visitSingularMessageField(value: v, fieldNumber: 6) - } }() - try { if let v = _storage._progressUpdate { - try visitor.visitSingularMessageField(value: v, fieldNumber: 7) - } }() - } - try unknownFields.traverse(visitor: &visitor) - } - - static func ==(lhs: Sharing_Nearby_V1Frame, rhs: Sharing_Nearby_V1Frame) -> Bool { - if lhs._storage !== rhs._storage { - let storagesAreEqual: Bool = withExtendedLifetime((lhs._storage, rhs._storage)) { (_args: (_StorageClass, _StorageClass)) in - let _storage = _args.0 - let rhs_storage = _args.1 - if _storage._type != rhs_storage._type {return false} - if _storage._introduction != rhs_storage._introduction {return false} - if _storage._connectionResponse != rhs_storage._connectionResponse {return false} - if _storage._pairedKeyEncryption != rhs_storage._pairedKeyEncryption {return false} - if _storage._pairedKeyResult != rhs_storage._pairedKeyResult {return false} - if _storage._certificateInfo != rhs_storage._certificateInfo {return false} - if _storage._progressUpdate != rhs_storage._progressUpdate {return false} - return true + if !_storage._fileMetadata.isEmpty { + try visitor.visitRepeatedMessageField(value: _storage._fileMetadata, fieldNumber: 1) } - if !storagesAreEqual {return false} - } - if lhs.unknownFields != rhs.unknownFields {return false} - return true - } -} - -extension Sharing_Nearby_V1Frame.FrameType: SwiftProtobuf._ProtoNameProviding { - static let _protobuf_nameMap = SwiftProtobuf._NameMap(bytecode: "\0\u{2}\0UNKNOWN_FRAME_TYPE\0\u{1}INTRODUCTION\0\u{1}RESPONSE\0\u{1}PAIRED_KEY_ENCRYPTION\0\u{1}PAIRED_KEY_RESULT\0\u{1}CERTIFICATE_INFO\0\u{1}CANCEL\0\u{1}PROGRESS_UPDATE\0") -} - -extension Sharing_Nearby_IntroductionFrame: SwiftProtobuf.Message, SwiftProtobuf._MessageImplementationBase, SwiftProtobuf._ProtoNameProviding { - static let protoMessageName: String = _protobuf_package + ".IntroductionFrame" - static let _protobuf_nameMap = SwiftProtobuf._NameMap(bytecode: "\0\u{3}file_metadata\0\u{3}text_metadata\0\u{3}required_package\0\u{3}wifi_credentials_metadata\0\u{3}app_metadata\0\u{3}start_transfer\0\u{3}stream_metadata\0\u{3}use_case\0\u{3}preview_payload_ids\0\u{4}`\u{f}mirrored_notification_metadata\0") - - mutating func decodeMessage(decoder: inout D) throws { - while let fieldNumber = try decoder.nextFieldNumber() { - // The use of inline closures is to circumvent an issue where the compiler - // allocates stack space for every case branch when no optimizations are - // enabled. https://github.com/apple/swift-protobuf/issues/1034 - switch fieldNumber { - case 1: try { try decoder.decodeRepeatedMessageField(value: &self.fileMetadata) }() - case 2: try { try decoder.decodeRepeatedMessageField(value: &self.textMetadata) }() - case 3: try { try decoder.decodeSingularStringField(value: &self._requiredPackage) }() - case 4: try { try decoder.decodeRepeatedMessageField(value: &self.wifiCredentialsMetadata) }() - case 5: try { try decoder.decodeRepeatedMessageField(value: &self.appMetadata) }() - case 6: try { try decoder.decodeSingularBoolField(value: &self._startTransfer) }() - case 7: try { try decoder.decodeRepeatedMessageField(value: &self.streamMetadata) }() - case 8: try { try decoder.decodeSingularEnumField(value: &self._useCase) }() - case 9: try { try decoder.decodeRepeatedInt64Field(value: &self.previewPayloadIds) }() - case 1001: try { try decoder.decodeSingularMessageField(value: &self._mirroredNotificationMetadata) }() - default: break + if !_storage._textMetadata.isEmpty { + try visitor.visitRepeatedMessageField(value: _storage._textMetadata, fieldNumber: 2) } + try { if let v = _storage._requiredPackage { + try visitor.visitSingularStringField(value: v, fieldNumber: 3) + } }() + if !_storage._wifiCredentialsMetadata.isEmpty { + try visitor.visitRepeatedMessageField(value: _storage._wifiCredentialsMetadata, fieldNumber: 4) + } + if !_storage._appMetadata.isEmpty { + try visitor.visitRepeatedMessageField(value: _storage._appMetadata, fieldNumber: 5) + } + try { if let v = _storage._startTransfer { + try visitor.visitSingularBoolField(value: v, fieldNumber: 6) + } }() + if !_storage._streamMetadata.isEmpty { + try visitor.visitRepeatedMessageField(value: _storage._streamMetadata, fieldNumber: 7) + } + try { if let v = _storage._useCase { + try visitor.visitSingularEnumField(value: v, fieldNumber: 8) + } }() + if !_storage._previewPayloadIds.isEmpty { + try visitor.visitRepeatedInt64Field(value: _storage._previewPayloadIds, fieldNumber: 9) + } + try { if let v = _storage._mirroredNotificationMetadata { + try visitor.visitSingularMessageField(value: v, fieldNumber: 1001) + } }() + try { if let v = _storage._pairingMetadata { + try visitor.visitSingularMessageField(value: v, fieldNumber: 1002) + } }() } - } - - func traverse(visitor: inout V) throws { - // The use of inline closures is to circumvent an issue where the compiler - // allocates stack space for every if/case branch local when no optimizations - // are enabled. https://github.com/apple/swift-protobuf/issues/1034 and - // https://github.com/apple/swift-protobuf/issues/1182 - if !self.fileMetadata.isEmpty { - try visitor.visitRepeatedMessageField(value: self.fileMetadata, fieldNumber: 1) - } - if !self.textMetadata.isEmpty { - try visitor.visitRepeatedMessageField(value: self.textMetadata, fieldNumber: 2) - } - try { if let v = self._requiredPackage { - try visitor.visitSingularStringField(value: v, fieldNumber: 3) - } }() - if !self.wifiCredentialsMetadata.isEmpty { - try visitor.visitRepeatedMessageField(value: self.wifiCredentialsMetadata, fieldNumber: 4) - } - if !self.appMetadata.isEmpty { - try visitor.visitRepeatedMessageField(value: self.appMetadata, fieldNumber: 5) - } - try { if let v = self._startTransfer { - try visitor.visitSingularBoolField(value: v, fieldNumber: 6) - } }() - if !self.streamMetadata.isEmpty { - try visitor.visitRepeatedMessageField(value: self.streamMetadata, fieldNumber: 7) - } - try { if let v = self._useCase { - try visitor.visitSingularEnumField(value: v, fieldNumber: 8) - } }() - if !self.previewPayloadIds.isEmpty { - try visitor.visitRepeatedInt64Field(value: self.previewPayloadIds, fieldNumber: 9) - } - try { if let v = self._mirroredNotificationMetadata { - try visitor.visitSingularMessageField(value: v, fieldNumber: 1001) - } }() try unknownFields.traverse(visitor: &visitor) } static func ==(lhs: Sharing_Nearby_IntroductionFrame, rhs: Sharing_Nearby_IntroductionFrame) -> Bool { - if lhs.fileMetadata != rhs.fileMetadata {return false} - if lhs.textMetadata != rhs.textMetadata {return false} - if lhs._requiredPackage != rhs._requiredPackage {return false} - if lhs.wifiCredentialsMetadata != rhs.wifiCredentialsMetadata {return false} - if lhs.appMetadata != rhs.appMetadata {return false} - if lhs._startTransfer != rhs._startTransfer {return false} - if lhs.streamMetadata != rhs.streamMetadata {return false} - if lhs._useCase != rhs._useCase {return false} - if lhs.previewPayloadIds != rhs.previewPayloadIds {return false} - if lhs._mirroredNotificationMetadata != rhs._mirroredNotificationMetadata {return false} + if lhs._storage !== rhs._storage { + let storagesAreEqual: Bool = withExtendedLifetime((lhs._storage, rhs._storage)) { (_args: (_StorageClass, _StorageClass)) in + let _storage = _args.0 + let rhs_storage = _args.1 + if _storage._fileMetadata != rhs_storage._fileMetadata {return false} + if _storage._textMetadata != rhs_storage._textMetadata {return false} + if _storage._requiredPackage != rhs_storage._requiredPackage {return false} + if _storage._wifiCredentialsMetadata != rhs_storage._wifiCredentialsMetadata {return false} + if _storage._appMetadata != rhs_storage._appMetadata {return false} + if _storage._startTransfer != rhs_storage._startTransfer {return false} + if _storage._streamMetadata != rhs_storage._streamMetadata {return false} + if _storage._useCase != rhs_storage._useCase {return false} + if _storage._previewPayloadIds != rhs_storage._previewPayloadIds {return false} + if _storage._mirroredNotificationMetadata != rhs_storage._mirroredNotificationMetadata {return false} + if _storage._pairingMetadata != rhs_storage._pairingMetadata {return false} + return true + } + if !storagesAreEqual {return false} + } if lhs.unknownFields != rhs.unknownFields {return false} return true } diff --git a/NearbyShare/Model/ProtobufSource/wire_format.proto b/NearbyShare/Model/ProtobufSource/wire_format.proto index b429614..9adf0f4 100644 --- a/NearbyShare/Model/ProtobufSource/wire_format.proto +++ b/NearbyShare/Model/ProtobufSource/wire_format.proto @@ -136,8 +136,21 @@ message MirroredNotificationMetadata { optional string title = 5; optional string body = 6; optional int64 posted_at_epoch_ms = 7; - optional bool setup_request = 8; - optional bytes setup_pin_hash = 9; + reserved 8, 9; +} + +// NEXT_ID=5 +message PairingMetadata { + enum UseCase { + UNKNOWN = 0; + NOTIFICATION_SYNC = 1; + CLIPBOARD_SYNC = 2; + } + + optional int32 version = 1 [default = 1]; + optional UseCase use_case = 2 [default = UNKNOWN]; + optional bool setup_request = 3; + optional bytes setup_pin_hash = 4; } // NEXT_ID=8 @@ -225,7 +238,7 @@ message V1Frame { // An introduction packet sent by the sending side. Contains a list of files // they'd like to share. -// NEXT_ID=1002 +// NEXT_ID=1003 message IntroductionFrame { enum SharingUseCase { UNKNOWN = 0; @@ -244,6 +257,7 @@ message IntroductionFrame { optional SharingUseCase use_case = 8; repeated int64 preview_payload_ids = 9; optional MirroredNotificationMetadata mirrored_notification_metadata = 1001; + optional PairingMetadata pairing_metadata = 1002; } // A progress update packet sent by the sending side. Contains transfer progress diff --git a/NearbyShare/Util/NotificationSyncPairingToken.swift b/NearbyShare/Util/NotificationSyncPairingToken.swift index 376c7b7..5ed7d0a 100644 --- a/NearbyShare/Util/NotificationSyncPairingToken.swift +++ b/NearbyShare/Util/NotificationSyncPairingToken.swift @@ -22,14 +22,14 @@ enum NotificationSyncPairingToken { return keyId.hex.lowercased() } - static func qrPayload(token: String, receiverFingerprint: String, useCase: String = "notification_sync") -> String { - "quickdrop://pair?token=\(token)&usecase=\(useCase)&receiver=\(receiverFingerprint)" + static func qrPayload(token: String, receiverFingerprint: String, useCase: PairingUseCase = .notificationSync) -> String { + "quickdrop://pair?token=\(token)&usecase=\(useCase.rawValue)&receiver=\(receiverFingerprint)" } static func makeQrImage( token: String, receiverFingerprint: String, - useCase: String = "notification_sync", + useCase: PairingUseCase = .notificationSync, foregroundColor: CGColor = CGColor(gray: 0, alpha: 1), backgroundColor: CGColor = CGColor(srgbRed: 1, green: 1, blue: 1, alpha: 1) ) -> Image? { diff --git a/NearbyShare/Util/TrustStore.swift b/NearbyShare/Util/TrustStore.swift index f031046..2f5c052 100644 --- a/NearbyShare/Util/TrustStore.swift +++ b/NearbyShare/Util/TrustStore.swift @@ -15,9 +15,9 @@ class TrustStore: ObservableObject { @Published private(set) var trustedCertificates: [String: TrustedCertificate] = [:] private let trustedKeysKey = "com.leonboettger.quickdrop.identity.trustedKeys" - private let pendingNotificationSyncQueue = DispatchQueue(label: "TrustStore.notificationSyncPending") - private var pendingNotificationSyncTrust: [String: PendingNotificationSyncTrust] = [:] - private let pendingNotificationSyncTTL: TimeInterval = 5 * 60 + private let pendingPairingQueue = DispatchQueue(label: "TrustStore.pairingPending") + private var pendingPairingTrust: [String: PendingPairingTrust] = [:] + private let pendingPairingTTL: TimeInterval = 5 * 60 private init() { loadTrustedCertificates() @@ -90,44 +90,48 @@ class TrustStore: ObservableObject { } - // MARK: - Notification Sync Pending Trust + // MARK: - Pending Pairing Trust - func registerPendingNotificationSyncTrust(secretIdHex: String, pinCode: String) { + func registerPendingPairingTrust(secretIdHex: String, pinCode: String, useCase: PairingUseCase) { let normalized = secretIdHex.trimmingCharacters(in: .whitespacesAndNewlines).lowercased() let trimmedPin = pinCode.trimmingCharacters(in: .whitespacesAndNewlines) guard !normalized.isEmpty, !trimmedPin.isEmpty else { return } let pinHash = Self.pinHash(for: trimmedPin) - pendingNotificationSyncQueue.sync { - pendingNotificationSyncTrust[normalized] = PendingNotificationSyncTrust( + pendingPairingQueue.sync { + pendingPairingTrust[normalized] = PendingPairingTrust( + useCase: useCase, pinHash: pinHash, createdAt: Date() ) } } - func confirmPendingNotificationSyncTrust(secretIdHex: String, pinHash: Data) -> Bool { + func confirmPendingPairingTrust(secretIdHex: String, useCase: PairingUseCase, pinHash: Data) -> Bool { let normalized = secretIdHex.trimmingCharacters(in: .whitespacesAndNewlines).lowercased() guard !normalized.isEmpty, !pinHash.isEmpty else { return false } let now = Date() - return pendingNotificationSyncQueue.sync { - guard let pending = pendingNotificationSyncTrust[normalized] else { return false } - pendingNotificationSyncTrust.removeValue(forKey: normalized) - let expired = now.timeIntervalSince(pending.createdAt) > pendingNotificationSyncTTL + return pendingPairingQueue.sync { + guard let pending = pendingPairingTrust[normalized] else { return false } + pendingPairingTrust.removeValue(forKey: normalized) + let expired = now.timeIntervalSince(pending.createdAt) > pendingPairingTTL if expired { return false } + guard pending.useCase == useCase else { + return false + } return pending.pinHash == pinHash } } - func clearPendingNotificationSyncTrust(secretIdHex: String) { + func clearPendingPairingTrust(secretIdHex: String) { let normalized = secretIdHex.trimmingCharacters(in: .whitespacesAndNewlines).lowercased() guard !normalized.isEmpty else { return } - _ = pendingNotificationSyncQueue.sync { - pendingNotificationSyncTrust.removeValue(forKey: normalized) + _ = pendingPairingQueue.sync { + pendingPairingTrust.removeValue(forKey: normalized) } } @@ -140,7 +144,8 @@ class TrustStore: ObservableObject { let certificateData: Data } - struct PendingNotificationSyncTrust: Equatable { + struct PendingPairingTrust: Equatable { + let useCase: PairingUseCase let pinHash: Data let createdAt: Date } diff --git a/QuickDrop/ViewModel/ReceiveModel.swift b/QuickDrop/ViewModel/ReceiveModel.swift index f353a3d..dc12a74 100644 --- a/QuickDrop/ViewModel/ReceiveModel.swift +++ b/QuickDrop/ViewModel/ReceiveModel.swift @@ -121,7 +121,7 @@ class ReceiveModel: ObservableObject, InboundAppDelegate { transferID: transferID, accept: true, trustDevice: false, - notificationSyncToken: pairingToken + pairingToken: pairingToken ) self.hideQuickDropToast(style: .fade) },