diff --git a/.pubnub.yml b/.pubnub.yml index 0b562024..5e4a7574 100644 --- a/.pubnub.yml +++ b/.pubnub.yml @@ -1,9 +1,14 @@ --- name: swift scm: github.com/pubnub/swift -version: "6.2.2" +version: "6.2.3" schema: 1 changelog: + - date: 2023-11-28 + version: 6.2.3 + changes: + - type: bug + text: "Handle unencrypted message while getting it with CryptoModule configured." - date: 2023-10-30 version: 6.2.2 changes: @@ -507,7 +512,7 @@ sdks: - distribution-type: source distribution-repository: GitHub release package-name: PubNub - location: https://github.com/pubnub/swift/archive/refs/tags/6.2.2.zip + location: https://github.com/pubnub/swift/archive/refs/tags/6.2.3.zip supported-platforms: supported-operating-systems: macOS: diff --git a/PubNub.xcodeproj/project.pbxproj b/PubNub.xcodeproj/project.pbxproj index f940b031..8351d92a 100644 --- a/PubNub.xcodeproj/project.pbxproj +++ b/PubNub.xcodeproj/project.pbxproj @@ -389,6 +389,7 @@ 3DACC7F72AB88F8E00210B14 /* Data+CommonCrypto.swift in Sources */ = {isa = PBXBuildFile; fileRef = 3DACC7F62AB88F8E00210B14 /* Data+CommonCrypto.swift */; }; 3DBB2C212ABD8053008A100E /* PubNubCryptoModuleContractTestSteps.swift in Sources */ = {isa = PBXBuildFile; fileRef = 3DBB2C202ABD8053008A100E /* PubNubCryptoModuleContractTestSteps.swift */; }; 3DBB2C222ABD8053008A100E /* PubNubCryptoModuleContractTestSteps.swift in Sources */ = {isa = PBXBuildFile; fileRef = 3DBB2C202ABD8053008A100E /* PubNubCryptoModuleContractTestSteps.swift */; }; + 3DFB01942B0E30EE00146B57 /* subscription_encrypted_message_success.json in Resources */ = {isa = PBXBuildFile; fileRef = 3DFB01932B0E30EE00146B57 /* subscription_encrypted_message_success.json */; }; 4C2A8D84BCD39B07A66FD9B4 /* Pods_PubNubContractTests.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 1E7F3D449F2D66FC29674EF6 /* Pods_PubNubContractTests.framework */; }; 79407BD2271D4CFA0032076C /* PubNubContractTestCase.swift in Sources */ = {isa = PBXBuildFile; fileRef = 79407BBF271D4CFA0032076C /* PubNubContractTestCase.swift */; }; 79407BD3271D4CFA0032076C /* PubNubContractTestCase.swift in Sources */ = {isa = PBXBuildFile; fileRef = 79407BBF271D4CFA0032076C /* PubNubContractTestCase.swift */; }; @@ -924,6 +925,7 @@ 3DACC7F62AB88F8E00210B14 /* Data+CommonCrypto.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "Data+CommonCrypto.swift"; sourceTree = ""; }; 3DBB2C202ABD8053008A100E /* PubNubCryptoModuleContractTestSteps.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = PubNubCryptoModuleContractTestSteps.swift; sourceTree = ""; }; 3DE632651BA8B2E27ACFC4AD /* Pods-PubNubContractTestsBeta.release.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-PubNubContractTestsBeta.release.xcconfig"; path = "Target Support Files/Pods-PubNubContractTestsBeta/Pods-PubNubContractTestsBeta.release.xcconfig"; sourceTree = ""; }; + 3DFB01932B0E30EE00146B57 /* subscription_encrypted_message_success.json */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.json; path = subscription_encrypted_message_success.json; sourceTree = ""; }; 793079152667C63700F23B72 /* CODEOWNERS */ = {isa = PBXFileReference; lastKnownFileType = text; path = CODEOWNERS; sourceTree = ""; }; 793079172667C63700F23B72 /* validate-yml.js */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.javascript; path = "validate-yml.js"; sourceTree = ""; }; 793079182667C63700F23B72 /* validate-pubnub-yml.yml */ = {isa = PBXFileReference; lastKnownFileType = text.yaml; path = "validate-pubnub-yml.yml"; sourceTree = ""; }; @@ -1320,6 +1322,7 @@ isa = PBXGroup; children = ( 359287C423185EEE0046F7A2 /* subscription_success.json */, + 3DFB01932B0E30EE00146B57 /* subscription_encrypted_message_success.json */, 35C6B6DF22F513D80054F242 /* subscription_mixed_success.json */, 359287BE23183DBB0046F7A2 /* subscription_signal_success.json */, 359287C023183E4A0046F7A2 /* subscription_presence_success.json */, @@ -2637,6 +2640,7 @@ 35FE941422EFB7C10051C455 /* unknownEndpointError.json in Resources */, 35FE93F122EF93A90051C455 /* serverCertificateUntrusted.json in Resources */, 35A6C79A22FBC2AD00E97CC5 /* groups_delete_success.json in Resources */, + 3DFB01942B0E30EE00146B57 /* subscription_encrypted_message_success.json in Resources */, 35293A872369F0230049A71F /* addMessageAction_error_400.json in Resources */, 35FE93F622EF93A90051C455 /* cannotParseResponse.json in Resources */, 35A6C79C22FBC2D100E97CC5 /* groups_channels_add_success.json in Resources */, @@ -3436,7 +3440,7 @@ "@executable_path/Frameworks", "@loader_path/Frameworks", ); - MARKETING_VERSION = 6.2.2; + MARKETING_VERSION = 6.2.3; MTL_ENABLE_DEBUG_INFO = INCLUDE_SOURCE; MTL_FAST_MATH = YES; PRODUCT_BUNDLE_IDENTIFIER = com.pubnub.swift.PubNubUser; @@ -3483,7 +3487,7 @@ "@executable_path/Frameworks", "@loader_path/Frameworks", ); - MARKETING_VERSION = 6.2.2; + MARKETING_VERSION = 6.2.3; MTL_ENABLE_DEBUG_INFO = NO; MTL_FAST_MATH = YES; PRODUCT_BUNDLE_IDENTIFIER = com.pubnub.swift.PubNubUser; @@ -3583,7 +3587,7 @@ "@executable_path/Frameworks", "@loader_path/Frameworks", ); - MARKETING_VERSION = 6.2.2; + MARKETING_VERSION = 6.2.3; MTL_ENABLE_DEBUG_INFO = INCLUDE_SOURCE; MTL_FAST_MATH = YES; PRODUCT_BUNDLE_IDENTIFIER = com.pubnub.swift.PubNubSpace; @@ -3632,7 +3636,7 @@ "@executable_path/Frameworks", "@loader_path/Frameworks", ); - MARKETING_VERSION = 6.2.2; + MARKETING_VERSION = 6.2.3; MTL_ENABLE_DEBUG_INFO = NO; MTL_FAST_MATH = YES; PRODUCT_BUNDLE_IDENTIFIER = com.pubnub.swift.PubNubSpace; @@ -3745,7 +3749,7 @@ "@executable_path/Frameworks", "@loader_path/Frameworks", ); - MARKETING_VERSION = 6.2.2; + MARKETING_VERSION = 6.2.3; MTL_ENABLE_DEBUG_INFO = INCLUDE_SOURCE; MTL_FAST_MATH = YES; PRODUCT_BUNDLE_IDENTIFIER = com.pubnub.swift.PubNubMembership; @@ -3793,7 +3797,7 @@ "@executable_path/Frameworks", "@loader_path/Frameworks", ); - MARKETING_VERSION = 6.2.2; + MARKETING_VERSION = 6.2.3; MTL_ENABLE_DEBUG_INFO = NO; MTL_FAST_MATH = YES; PRODUCT_BUNDLE_IDENTIFIER = com.pubnub.swift.PubNubMembership; @@ -4253,7 +4257,7 @@ "$(inherited)", "$(TOOLCHAIN_DIR)/usr/lib/swift/macosx", ); - MARKETING_VERSION = 6.2.2; + MARKETING_VERSION = 6.2.3; OTHER_CFLAGS = "$(inherited)"; OTHER_LDFLAGS = "$(inherited)"; OTHER_SWIFT_FLAGS = "$(inherited)"; @@ -4292,7 +4296,7 @@ "$(inherited)", "$(TOOLCHAIN_DIR)/usr/lib/swift/macosx", ); - MARKETING_VERSION = 6.2.2; + MARKETING_VERSION = 6.2.3; OTHER_CFLAGS = "$(inherited)"; OTHER_LDFLAGS = "$(inherited)"; OTHER_SWIFT_FLAGS = "$(inherited)"; diff --git a/PubNubSwift.podspec b/PubNubSwift.podspec index 12157800..726bb165 100644 --- a/PubNubSwift.podspec +++ b/PubNubSwift.podspec @@ -1,6 +1,6 @@ Pod::Spec.new do |s| s.name = 'PubNubSwift' - s.version = '6.2.2' + s.version = '6.2.3' s.homepage = 'https://github.com/pubnub/swift' s.documentation_url = 'https://www.pubnub.com/docs/swift-native/pubnub-swift-sdk' s.authors = { 'PubNub, Inc.' => 'support@pubnub.com' } diff --git a/Sources/PubNub/Helpers/Constants.swift b/Sources/PubNub/Helpers/Constants.swift index ceaeae69..aa29d619 100644 --- a/Sources/PubNub/Helpers/Constants.swift +++ b/Sources/PubNub/Helpers/Constants.swift @@ -57,7 +57,7 @@ public enum Constant { static let pubnubSwiftSDKName: String = "PubNubSwift" - static let pubnubSwiftSDKVersion: String = "6.2.2" + static let pubnubSwiftSDKVersion: String = "6.2.3" static let appBundleId: String = { if let info = Bundle.main.infoDictionary, diff --git a/Sources/PubNub/Models/PubNubMessage.swift b/Sources/PubNub/Models/PubNubMessage.swift index e8ee729c..d12a070b 100644 --- a/Sources/PubNub/Models/PubNubMessage.swift +++ b/Sources/PubNub/Models/PubNubMessage.swift @@ -38,7 +38,9 @@ public protocol PubNubMessage { var metadata: JSONCodable? { get set } /// The type of message that was received var messageType: PubNubMessageType { get set } - + /// An error (if any) occured while getting this message + var error: PubNubError? { get set } + /// Allows for transcoding between different MessageEvent types init(from other: PubNubMessage) throws } @@ -69,16 +71,17 @@ public extension PubNubMessage { /// The default implementation of the `PubNubMessage` protocol public struct PubNubMessageBase: PubNubMessage, Codable, Hashable { - var concretePayload: AnyJSON public var publisher: String? - var concreteMessageActions: [PubNubMessageActionBase] public var channel: String public var subscription: String? public var published: Timetoken - var concreteMetadata: AnyJSON? - public var messageType: PubNubMessageType - + public var error: PubNubError? + + var concretePayload: AnyJSON + var concreteMessageActions: [PubNubMessageActionBase] + var concreteMetadata: AnyJSON? + public var payload: JSONCodable { get { return concretePayload } set { @@ -109,7 +112,8 @@ public struct PubNubMessageBase: PubNubMessage, Codable, Hashable { subscription: other.subscription, published: other.published, metadata: other.metadata?.codableValue, - messageType: other.messageType + messageType: other.messageType, + error: other.error ) } @@ -122,7 +126,8 @@ public struct PubNubMessageBase: PubNubMessage, Codable, Hashable { subscription: subscribe.subscription, published: subscribe.publishTimetoken.timetoken, metadata: subscribe.metadata, - messageType: subscribe.messageType.asPubNubMessageType + messageType: subscribe.messageType.asPubNubMessageType, + error: subscribe.error ) } @@ -141,7 +146,8 @@ public struct PubNubMessageBase: PubNubMessage, Codable, Hashable { subscription: nil, published: history.timetoken, metadata: history.meta, - messageType: history.messageType ?? .unknown + messageType: history.messageType ?? .unknown, + error: history.error ) } @@ -153,16 +159,55 @@ public struct PubNubMessageBase: PubNubMessage, Codable, Hashable { subscription: String?, published: Timetoken, metadata: AnyJSON?, - messageType: PubNubMessageType = .unknown + messageType: PubNubMessageType = .unknown, + error: PubNubError? = nil ) { - concretePayload = payload - concreteMessageActions = actions + self.concretePayload = payload + self.concreteMessageActions = actions self.publisher = publisher self.channel = channel self.subscription = subscription self.published = published - concreteMetadata = metadata + self.concreteMetadata = metadata self.messageType = messageType + self.error = error + } + + public func encode(to encoder: Encoder) throws { + var container = encoder.container(keyedBy: CodingKeys.self) + + try container.encode(self.concretePayload, forKey: .concretePayload) + try container.encodeIfPresent(self.publisher, forKey: .publisher) + try container.encode(self.concreteMessageActions, forKey: .concreteMessageActions) + try container.encode(self.channel, forKey: .channel) + try container.encodeIfPresent(self.subscription, forKey: .subscription) + try container.encode(self.published, forKey: .published) + try container.encodeIfPresent(self.concreteMetadata, forKey: .concreteMetadata) + try container.encode(self.messageType, forKey: .messageType) + } + + enum CodingKeys: CodingKey { + case concretePayload + case publisher + case concreteMessageActions + case channel + case subscription + case published + case concreteMetadata + case messageType + } + + public init(from decoder: Decoder) throws { + let container = try decoder.container(keyedBy: CodingKeys.self) + + self.concretePayload = try container.decode(AnyJSON.self, forKey: .concretePayload) + self.publisher = try container.decodeIfPresent(String.self, forKey: .publisher) + self.concreteMessageActions = try container.decode([PubNubMessageActionBase].self, forKey: .concreteMessageActions) + self.channel = try container.decode(String.self, forKey: .channel) + self.subscription = try container.decodeIfPresent(String.self, forKey: .subscription) + self.published = try container.decode(Timetoken.self, forKey: .published) + self.concreteMetadata = try container.decodeIfPresent(AnyJSON.self, forKey: .concreteMetadata) + self.messageType = try container.decode(PubNubMessageType.self, forKey: .messageType) } } diff --git a/Sources/PubNub/Networking/Routers/HistoryRouter.swift b/Sources/PubNub/Networking/Routers/HistoryRouter.swift index fdd728fa..f4594803 100644 --- a/Sources/PubNub/Networking/Routers/HistoryRouter.swift +++ b/Sources/PubNub/Networking/Routers/HistoryRouter.swift @@ -190,13 +190,36 @@ struct MessageHistoryResponseDecoder: ResponseDecoder { timetoken: message.timetoken, meta: message.meta, uuid: message.uuid, - messageType: message.messageType + messageType: message.messageType, + error: nil ) case .failure(let error): - PubNub.log.error("History message failed to decrypt due to \(error)") + messages[index] = MessageHistoryMessagePayload( + message: message.message, + timetoken: message.timetoken, + meta: message.meta, + uuid: message.uuid, + messageType: message.messageType, + error: error + ) + PubNub.log.warn("History message failed to decrypt due to \(error)") } + } else { + messages[index] = MessageHistoryMessagePayload( + message: message.message, + timetoken: message.timetoken, + meta: message.meta, + uuid: message.uuid, + messageType: message.messageType, + error: PubNubError( + .decryptionFailure, + additional: ["Cannot decrypt message due to invalid Base-64 input"] + ) + ) } } + + return messages } @@ -284,6 +307,7 @@ struct MessageHistoryMessagePayload: Codable { let uuid: String? let messageType: PubNubMessageType? let actions: RawMessageAction + let error: PubNubError? init( message: JSONCodable, @@ -291,7 +315,8 @@ struct MessageHistoryMessagePayload: Codable { meta: JSONCodable? = nil, uuid: String?, messageType: PubNubMessageType?, - actions: RawMessageAction = [:] + actions: RawMessageAction = [:], + error: PubNubError? ) { self.message = message.codableValue self.timetoken = timetoken @@ -299,6 +324,7 @@ struct MessageHistoryMessagePayload: Codable { self.messageType = messageType self.meta = meta?.codableValue self.actions = actions + self.error = error } enum CodingKeys: String, CodingKey { @@ -319,6 +345,7 @@ struct MessageHistoryMessagePayload: Codable { messageType = try container.decodeIfPresent(PubNubMessageType.self, forKey: .messageType) timetoken = Timetoken(try container.decode(String.self, forKey: .timetoken)) ?? 0 actions = try container.decodeIfPresent(RawMessageAction.self, forKey: .actions) ?? [:] + error = nil } public func encode(to encoder: Encoder) throws { diff --git a/Sources/PubNub/Networking/Routers/SubscribeRouter.swift b/Sources/PubNub/Networking/Routers/SubscribeRouter.swift index c1c3172a..e1212fd8 100644 --- a/Sources/PubNub/Networking/Routers/SubscribeRouter.swift +++ b/Sources/PubNub/Networking/Routers/SubscribeRouter.swift @@ -120,21 +120,25 @@ struct SubscribeDecoder: ResponseDecoder { } func decrypt(_ cryptoModule: CryptoModule, message: SubscribeMessagePayload) -> SubscribeMessagePayload { - // Convert base64 string into Data + var message = message + // Convert Base64 string into Data if let messageData = message.payload.dataOptional { // If a message fails we just return the original and move on switch cryptoModule.decryptedString(from: messageData) { case .success(let decodedString): // Create mutable copy of payload - var message = message message.payload = AnyJSON(reverse: decodedString) return message case .failure(let error): - PubNub.log.error("Subscribe message failed to decrypt due to \(error)") + PubNub.log.warn("Subscribe message failed to decrypt due to \(error)") + message.error = error return message } } - + message.error = PubNubError( + .decryptionFailure, + additional: ["Cannot decrypt message due to invalid Base-64 input"] + ) return message } @@ -250,6 +254,7 @@ public struct SubscribeMessagePayload: Codable, Hashable { public let originTimetoken: SubscribeCursor? public let publishTimetoken: SubscribeCursor public let metadata: AnyJSON? + public var error: PubNubError? enum CodingKeys: String, CodingKey { case shard = "a" @@ -304,7 +309,8 @@ public struct SubscribeMessagePayload: Codable, Hashable { subscribeKey: String, originTimetoken: SubscribeCursor?, publishTimetoken: SubscribeCursor, - meta: AnyJSON? + meta: AnyJSON?, + error: PubNubError? ) { self.shard = shard self.subscription = subscription @@ -316,7 +322,8 @@ public struct SubscribeMessagePayload: Codable, Hashable { self.subscribeKey = subscribeKey self.originTimetoken = originTimetoken self.publishTimetoken = publishTimetoken - metadata = meta + self.metadata = meta + self.error = error } public init(from decoder: Decoder) throws { @@ -349,6 +356,7 @@ public struct SubscribeMessagePayload: Codable, Hashable { } channel = fullChannel.trimmingPresenceChannelSuffix + error = nil } public func encode(to encoder: Encoder) throws { diff --git a/Tests/PubNubTests/Mocking/Responses/Subscribe/subscription_encrypted_message_success.json b/Tests/PubNubTests/Mocking/Responses/Subscribe/subscription_encrypted_message_success.json new file mode 100644 index 00000000..415430fd --- /dev/null +++ b/Tests/PubNubTests/Mocking/Responses/Subscribe/subscription_encrypted_message_success.json @@ -0,0 +1,23 @@ +{ + "code": 200, + "body": { + "t": { + "t": "15614817397807903", + "r": 2 + }, + "m": [ + { + "a": "1", + "f": 514, + "i": "db9c5e39-7c95-40f5-8d71-125765b6f561", + "p": { + "t": "15614814456537442", + "r": 2 + }, + "k": "demo", + "c": "TestChannel", + "d": "UE5FRAFBQ1JIEGOmGQMIMXD+91V+5hTxm7p7uEUhEEYohYLQz5fEGITC" + } + ] + } +} diff --git a/Tests/PubNubTests/Networking/Routers/HistoryRouterTests.swift b/Tests/PubNubTests/Networking/Routers/HistoryRouterTests.swift index 53d763e8..594a8ea2 100644 --- a/Tests/PubNubTests/Networking/Routers/HistoryRouterTests.swift +++ b/Tests/PubNubTests/Networking/Routers/HistoryRouterTests.swift @@ -21,7 +21,6 @@ final class HistoryRouterTests: XCTestCase { ) let testChannel = "TestChannel" - let testSingleChannel = ["TestChannel"] let testMultiChannels = ["TestChannel", "OtherTestChannel"] } @@ -188,15 +187,14 @@ extension HistoryRouterTests { var configWithCipher = config configWithCipher.cryptoModule = CryptoModule.legacyCryptoModule(with: "NotTheRightKey", withRandomIV: false) - let pubnub = PubNub(configuration: config, session: sessions.session) + let pubnub = PubNub(configuration: configWithCipher, session: sessions.session) pubnub.fetchMessageHistory(for: testMultiChannels) { result in switch result { case let .success((messagesByChannel, next)): let channelMessages = messagesByChannel[self.testChannel] XCTAssertNotNil(channelMessages) - XCTAssertEqual( - channelMessages?.first?.payload.dataOptional?.base64EncodedString(), "s3+CcEE2QZ/Lh9CaPieJnQ==" - ) + XCTAssertEqual(channelMessages?.first?.payload.dataOptional?.base64EncodedString(), "s3+CcEE2QZ/Lh9CaPieJnQ==") + XCTAssertTrue((channelMessages ?? []).reduce(into: true) { $0 = $0 && $1.error?.reason == .decryptionFailure }) XCTAssertEqual(next?.start, 15_657_268_328_421_957) case let .failure(error): XCTFail("Fetch History request failed with error: \(error.localizedDescription)") diff --git a/Tests/PubNubTests/Networking/Routers/SubscribeRouterTests.swift b/Tests/PubNubTests/Networking/Routers/SubscribeRouterTests.swift index c4488b41..e8389e17 100644 --- a/Tests/PubNubTests/Networking/Routers/SubscribeRouterTests.swift +++ b/Tests/PubNubTests/Networking/Routers/SubscribeRouterTests.swift @@ -887,6 +887,124 @@ extension SubscribeRouterTests { defer { listener.cancel() } wait(for: [statusExpect], timeout: 1.0) } +} + +// MARK: - Subscription with CryptoModule enabled + +extension SubscribeRouterTests { + func testSubscribe_DecryptNonEncryptedMessage() { + let messageExpect = XCTestExpectation(description: "Message Event") + + guard let session = try? MockURLSession.mockSession( + for: ["subscription_message_success", "cancelled"] + ).session else { + return XCTFail("Could not create mock url session") + } + + let config = PubNubConfiguration( + publishKey: "pubKey", + subscribeKey: "subKey", + userId: "userId", + cryptoModule: CryptoModule.aesCbcCryptoModule(with: "pubnubenigma") + ) + let pubNubWithMockedSession = PubNub( + configuration: config, + subscribeSession: session + ) + + let listener = SubscriptionListener() + + listener.didReceiveMessage = { [weak self, pubNubWithMockedSession] message in + XCTAssertEqual(message.channel, self?.testChannel) + XCTAssertEqual(message.payload.stringOptional, "Test Message") + XCTAssertTrue(message.error?.reason == .decryptionFailure) + + pubNubWithMockedSession.unsubscribeAll() + messageExpect.fulfill() + } + + pubNubWithMockedSession.add(listener) + pubNubWithMockedSession.subscribe(to: [testChannel]) + + defer { listener.cancel() } + wait(for: [messageExpect], timeout: 1.0) + } + + func testSubscribe_DecryptEncryptedMessage() { + let messageExpect = XCTestExpectation(description: "Message Event") + + guard let session = try? MockURLSession.mockSession( + for: ["subscription_encrypted_message_success", "cancelled"] + ).session else { + return XCTFail("Could not create mock url session") + } + + let config = PubNubConfiguration( + publishKey: "pubKey", + subscribeKey: "subKey", + userId: "userId", + cryptoModule: CryptoModule.aesCbcCryptoModule(with: "pubnubenigma") + ) + let pubNubWithMockedSession = PubNub( + configuration: config, + subscribeSession: session + ) + + let listener = SubscriptionListener() + + listener.didReceiveMessage = { [weak self, pubNubWithMockedSession] message in + XCTAssertEqual(message.channel, self?.testChannel) + XCTAssertEqual(message.payload.stringOptional, "Test Message") + XCTAssertNil(message.error) + + pubNubWithMockedSession.unsubscribeAll() + messageExpect.fulfill() + } + + pubNubWithMockedSession.add(listener) + pubNubWithMockedSession.subscribe(to: [testChannel]) + defer { listener.cancel() } + wait(for: [messageExpect], timeout: 1.0) + } + + func testSubscribe_DecryptEncryptedMessageWithMismatchedKey() { + let messageExpect = XCTestExpectation(description: "Message Event") + + guard let session = try? MockURLSession.mockSession( + for: ["subscription_encrypted_message_success", "cancelled"] + ).session else { + return XCTFail("Could not create mock url session") + } + + let config = PubNubConfiguration( + publishKey: "pubKey", + subscribeKey: "subKey", + userId: "userId", + cryptoModule: CryptoModule.aesCbcCryptoModule(with: "lorem-ipsum-dolor-sit-amet") + ) + let pubNubWithMockedSession = PubNub( + configuration: config, + subscribeSession: session + ) + + let listener = SubscriptionListener() + + listener.didReceiveMessage = { [weak self, pubNubWithMockedSession] message in + XCTAssertEqual(message.channel, self?.testChannel) + XCTAssertEqual(message.payload.stringOptional, "UE5FRAFBQ1JIEGOmGQMIMXD+91V+5hTxm7p7uEUhEEYohYLQz5fEGITC") + XCTAssertTrue(message.error?.reason == .decryptionFailure) + + pubNubWithMockedSession.unsubscribeAll() + messageExpect.fulfill() + } + + pubNubWithMockedSession.add(listener) + pubNubWithMockedSession.subscribe(to: [testChannel]) + + defer { listener.cancel() } + wait(for: [messageExpect], timeout: 1.0) + } + // swiftlint:disable:next file_length }