Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Fixes for PubNub client #160

Merged
merged 7 commits into from
Mar 18, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
11 changes: 9 additions & 2 deletions .pubnub.yml
Original file line number Diff line number Diff line change
@@ -1,9 +1,16 @@
---
name: swift
scm: github.com/pubnub/swift
version: "7.0.0"
version: "7.1.0"
schema: 1
changelog:
- date: 2024-03-18
version: 7.1.0
changes:
- type: bug
text: "Preventing disconnection when subscribing via `PubNub` to a channel that was already subscribed to."
- type: bug
text: "Fixes for computing a hash value in `CryptoModule`."
- date: 2024-02-21
version: 7.0.0
changes:
Expand Down Expand Up @@ -524,7 +531,7 @@ sdks:
- distribution-type: source
distribution-repository: GitHub release
package-name: PubNub
location: https://github.com/pubnub/swift/archive/refs/tags/7.0.0.zip
location: https://github.com/pubnub/swift/archive/refs/tags/7.1.0.zip
supported-platforms:
supported-operating-systems:
macOS:
Expand Down
16 changes: 8 additions & 8 deletions PubNub.xcodeproj/project.pbxproj
Original file line number Diff line number Diff line change
Expand Up @@ -3843,7 +3843,7 @@
"@loader_path/Frameworks",
);
MACOSX_DEPLOYMENT_TARGET = 10.13;
MARKETING_VERSION = 7.0.0;
MARKETING_VERSION = 7.1.0;
MTL_ENABLE_DEBUG_INFO = INCLUDE_SOURCE;
MTL_FAST_MATH = YES;
PRODUCT_BUNDLE_IDENTIFIER = com.pubnub.swift.PubNubUser;
Expand Down Expand Up @@ -3892,7 +3892,7 @@
"@loader_path/Frameworks",
);
MACOSX_DEPLOYMENT_TARGET = 10.13;
MARKETING_VERSION = 7.0.0;
MARKETING_VERSION = 7.1.0;
MTL_ENABLE_DEBUG_INFO = NO;
MTL_FAST_MATH = YES;
PRODUCT_BUNDLE_IDENTIFIER = com.pubnub.swift.PubNubUser;
Expand Down Expand Up @@ -3998,7 +3998,7 @@
"@loader_path/Frameworks",
);
MACOSX_DEPLOYMENT_TARGET = 10.13;
MARKETING_VERSION = 7.0.0;
MARKETING_VERSION = 7.1.0;
MTL_ENABLE_DEBUG_INFO = INCLUDE_SOURCE;
MTL_FAST_MATH = YES;
PRODUCT_BUNDLE_IDENTIFIER = com.pubnub.swift.PubNubSpace;
Expand Down Expand Up @@ -4049,7 +4049,7 @@
"@loader_path/Frameworks",
);
MACOSX_DEPLOYMENT_TARGET = 10.13;
MARKETING_VERSION = 7.0.0;
MARKETING_VERSION = 7.1.0;
MTL_ENABLE_DEBUG_INFO = NO;
MTL_FAST_MATH = YES;
PRODUCT_BUNDLE_IDENTIFIER = com.pubnub.swift.PubNubSpace;
Expand Down Expand Up @@ -4168,7 +4168,7 @@
"@loader_path/Frameworks",
);
MACOSX_DEPLOYMENT_TARGET = 10.13;
MARKETING_VERSION = 7.0.0;
MARKETING_VERSION = 7.1.0;
MTL_ENABLE_DEBUG_INFO = INCLUDE_SOURCE;
MTL_FAST_MATH = YES;
PRODUCT_BUNDLE_IDENTIFIER = com.pubnub.swift.PubNubMembership;
Expand Down Expand Up @@ -4218,7 +4218,7 @@
"@loader_path/Frameworks",
);
MACOSX_DEPLOYMENT_TARGET = 10.13;
MARKETING_VERSION = 7.0.0;
MARKETING_VERSION = 7.1.0;
MTL_ENABLE_DEBUG_INFO = NO;
MTL_FAST_MATH = YES;
PRODUCT_BUNDLE_IDENTIFIER = com.pubnub.swift.PubNubMembership;
Expand Down Expand Up @@ -4696,7 +4696,7 @@
"$(TOOLCHAIN_DIR)/usr/lib/swift/macosx",
);
MACOSX_DEPLOYMENT_TARGET = 10.13;
MARKETING_VERSION = 7.0.0;
MARKETING_VERSION = 7.1.0;
OTHER_CFLAGS = "$(inherited)";
OTHER_LDFLAGS = "$(inherited)";
OTHER_SWIFT_FLAGS = "$(inherited)";
Expand Down Expand Up @@ -4737,7 +4737,7 @@
"$(TOOLCHAIN_DIR)/usr/lib/swift/macosx",
);
MACOSX_DEPLOYMENT_TARGET = 10.13;
MARKETING_VERSION = 7.0.0;
MARKETING_VERSION = 7.1.0;
OTHER_CFLAGS = "$(inherited)";
OTHER_LDFLAGS = "$(inherited)";
OTHER_SWIFT_FLAGS = "$(inherited)";
Expand Down
2 changes: 1 addition & 1 deletion PubNubSwift.podspec
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
Pod::Spec.new do |s|
s.name = 'PubNubSwift'
s.version = '7.0.0'
s.version = '7.1.0'
s.homepage = 'https://github.com/pubnub/swift'
s.documentation_url = 'https://www.pubnub.com/docs/swift-native/pubnub-swift-sdk'
s.authors = { 'PubNub, Inc.' => '[email protected]' }
Expand Down
4 changes: 2 additions & 2 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@
[![Swift Package Manager compatible](https://img.shields.io/badge/Swift%20Package%20Manager-compatible-brightgreen.svg)](https://github.com/apple/swift-package-manager)
[![Carthage Compatible](https://img.shields.io/badge/Carthage-compatible-4BC51D.svg?style=flat)](https://github.com/Carthage/Carthage)
[![Build Status](https://travis-ci.org/pubnub/swift.svg?branch=master)](https://travis-ci.org/pubnub/swift)
[![Codacy Coverage Grade Badge](https://api.codacy.com/project/badge/Grade/d6dbd8cad97d42bbb72c47137e94d6f5)](https://www.codacy.com?utm_source=github.com&utm_medium=referral&utm_content=pubnub/swift&utm_campaign=Badge_Grade)
[![Codacy Badge](https://app.codacy.com/project/badge/Grade/ea96a32a311944eaa09b4c452db4d397)](https://app.codacy.com?utm_source=gh&utm_medium=referral&utm_content=&utm_campaign=Badge_grade)

This is the official PubNub Swift SDK repository.

Expand Down Expand Up @@ -59,7 +59,7 @@ end

> Note: Replace `YOUR_TARGET_NAME` with your target's name.

In the directory containing your `Podfile`. execute the following:
In the directory containing your `Podfile` execute the following:

```bash
pod install
Expand Down
2 changes: 1 addition & 1 deletion Sources/PubNub/Helpers/Constants.swift
Original file line number Diff line number Diff line change
Expand Up @@ -57,7 +57,7 @@ public enum Constant {

static let pubnubSwiftSDKName: String = "PubNubSwift"

static let pubnubSwiftSDKVersion: String = "7.0.0"
static let pubnubSwiftSDKVersion: String = "7.1.0"

static let appBundleId: String = {
if let info = Bundle.main.infoDictionary,
Expand Down
67 changes: 39 additions & 28 deletions Sources/PubNub/Helpers/Crypto/CryptoModule.swift
Original file line number Diff line number Diff line change
Expand Up @@ -15,29 +15,31 @@ public class CryptorModule {
public static func aesCbcCryptoModule(with key: String, withRandomIV: Bool = true) -> CryptoModule {
preconditionFailure("This method is no longer available")
}

public static func legacyCryptoModule(with key: String, withRandomIV: Bool = true) -> CryptoModule {
preconditionFailure("This method is no longer available")
}
}

/// Object capable of encryption/decryption
public struct CryptoModule {
private let defaultCryptor: Cryptor
private let cryptors: [Cryptor]
private let defaultCryptor: any Cryptor
private let cryptors: [any Cryptor]
private let legacyCryptorId: CryptorId = []

typealias Base64EncodedString = String

/// Initializes `CryptoModule` with custom ``Cryptor`` objects capable of encryption and decryption
///
/// Use this constructor if you would like to provide **custom** objects for decryption and encryption and don't want to use PubNub's built-in `Cryptors`.
/// Otherwise, refer to convenience static factory methods such as ``aesCbcCryptoModule(with:withRandomIV:)``
/// and ``legacyCryptoModule(with:withRandomIV:)`` that return `CryptoModule` configured for you.
/// Use this constructor if you would like to provide **custom** objects for decryption and encryption
/// and don't want to use PubNub's built-in `Cryptors`. Otherwise, refer to convenience static factory methods
/// such as ``aesCbcCryptoModule(with:withRandomIV:)``and ``legacyCryptoModule(with:withRandomIV:)``
/// that return `CryptoModule` configured for you.
///
/// - Parameters:
/// - default: Primary ``Cryptor`` instance used for encryption and decryption
/// - cryptors: An optional list of ``Cryptor`` instances which older messages/files were encoded
public init(default cryptor: Cryptor, cryptors: [Cryptor] = []) {
public init(default cryptor: any Cryptor, cryptors: [any Cryptor] = []) {
self.defaultCryptor = cryptor
self.cryptors = cryptors
}
Expand All @@ -46,13 +48,15 @@ public struct CryptoModule {
///
/// - Parameters:
/// - data: Data to encrypt
/// - Returns: A success, storing encrypted `Data` if operation succeeds. Otherwise, a failure storing `PubNubError` is returned
/// - Returns:
/// - **Success**: An encrypted `Data` object
/// - **Failure**: `PubNubError` describing the reason of failure
public func encrypt(data: Data) -> Result<Data, PubNubError> {
guard !data.isEmpty else {
return .failure(PubNubError(
.encryptionFailure,
additional: ["Cannot encrypt empty Data"])
)
additional: ["Cannot encrypt empty Data"]
))
}
return defaultCryptor.encrypt(data: data).map {
if defaultCryptor.id == LegacyCryptor.ID {
Expand All @@ -71,13 +75,15 @@ public struct CryptoModule {
///
/// - Parameters:
/// - data: Data to decrypt
/// - Returns: A success, storing decrypted `Data` if operation succeeds. Otherwise, a failure storing `PubNubError` is returned
/// - Returns:
/// - **Success**: A decrypted `Data` object
/// - **Failure**: `PubNubError` describing the reason of failure
public func decrypt(data: Data) -> Result<Data, PubNubError> {
guard !data.isEmpty else {
return .failure(PubNubError(
.decryptionFailure,
additional: ["Cannot decrypt empty Data in \(String(describing: self))"])
)
additional: ["Cannot decrypt empty Data in \(String(describing: self))"]
))
}
do {
let header = try CryptorHeader.from(data: data)
Expand All @@ -87,7 +93,7 @@ public struct CryptoModule {
.unknownCryptorFailure,
additional: [
"Could not find matching Cryptor for \(header.cryptorId()) while decrypting Data. " +
"Ensure the corresponding instance is registered in \(String(describing: Self.self))"
"Ensure the corresponding instance is registered in \(String(describing: Self.self))"
]
))
}
Expand Down Expand Up @@ -115,8 +121,8 @@ public struct CryptoModule {
if $0.isEmpty {
return .failure(PubNubError(
.decryptionFailure,
additional: ["Decrypting resulted with empty Data"])
)
additional: ["Decrypting resulted with empty Data"]
))
}
return .success($0)
}
Expand All @@ -129,8 +135,8 @@ public struct CryptoModule {
return .failure(PubNubError(
.decryptionFailure,
underlying: error,
additional: ["Cannot decrypt InputStream"])
)
additional: ["Cannot decrypt InputStream"]
))
}
}

Expand All @@ -139,7 +145,9 @@ public struct CryptoModule {
/// - Parameters:
/// - stream: Stream to encrypt
/// - contentLength: Content length of encoded stream
/// - Returns: A success, storing an `InputStream` value if operation succeeds. Otherwise, a failure storing `PubNubError` is returned
/// - Returns:
/// - **Success**: An `InputStream` value
/// - **Failure**: `PubNubError` describing the reason of failure
public func encrypt(stream: InputStream, contentLength: Int) -> Result<InputStream, PubNubError> {
guard contentLength > 0 else {
return .failure(PubNubError(
Expand Down Expand Up @@ -179,7 +187,9 @@ public struct CryptoModule {
/// - stream: Stream to decrypt
/// - contentLength: Content length of encrypted stream
/// - to: URL where the stream should be decrypted to
/// - Returns: A success, storing a decrypted `InputStream` value if operation succeeds. Otherwise, a failure storing `PubNubError` is returned
/// - Returns:
/// - **Success**: A decrypted `InputStream` object
/// - **Failure**: `PubNubError` describing the reason of failure
@discardableResult
public func decrypt(
stream: InputStream,
Expand All @@ -203,7 +213,7 @@ public struct CryptoModule {
.unknownCryptorFailure,
additional: [
"Could not find matching Cryptor for \(readHeaderResp.header.cryptorId()) while decrypting InputStream. " +
"Ensure the corresponding instance is registered in \(String(describing: Self.self))"
"Ensure the corresponding instance is registered in \(String(describing: Self.self))"
]
))
}
Expand All @@ -218,8 +228,8 @@ public struct CryptoModule {
if outputPath.sizeOf == 0 {
return .failure(PubNubError(
.decryptionFailure,
additional: ["Decrypting resulted with an empty File"])
)
additional: ["Decrypting resulted with an empty File"]
))
}
return .success($0)
}
Expand All @@ -237,7 +247,7 @@ public struct CryptoModule {
}
}

private func cryptor(matching header: CryptorHeader) -> Cryptor? {
private func cryptor(matching header: CryptorHeader) -> (any Cryptor)? {
header.cryptorId() == defaultCryptor.id ? defaultCryptor : cryptors.first(where: {
$0.id == header.cryptorId()
})
Expand All @@ -246,7 +256,6 @@ public struct CryptoModule {

/// Convenience methods for creating `CryptoModule`
public extension CryptoModule {

/// Returns **recommended** `CryptoModule` for encryption/decryption
///
/// - Parameters:
Expand Down Expand Up @@ -279,7 +288,9 @@ extension CryptoModule: Equatable {

extension CryptoModule: Hashable {
public func hash(into hasher: inout Hasher) {
hasher.combine(cryptors.map { $0.id })
for cryptor in cryptors {
hasher.combine(cryptor)
}
}
}

Expand All @@ -289,7 +300,7 @@ extension CryptoModule: CustomStringConvertible {
}
}

internal extension CryptoModule {
extension CryptoModule {
func encrypt(string: String) -> Result<Base64EncodedString, PubNubError> {
guard let data = string.data(using: .utf8) else {
return .failure(PubNubError(
Expand All @@ -309,8 +320,8 @@ internal extension CryptoModule {
} else {
return .failure(PubNubError(
.decryptionFailure,
additional: ["Cannot create String from provided Data"])
)
additional: ["Cannot create String from provided Data"]
))
}
}
}
Expand Down
7 changes: 7 additions & 0 deletions Sources/PubNub/Helpers/Crypto/Cryptors/AESCBCCryptor.swift
Original file line number Diff line number Diff line change
Expand Up @@ -147,3 +147,10 @@ public struct AESCBCCryptor: Cryptor {
}
}
}

extension AESCBCCryptor: Hashable {
public func hash(into hasher: inout Hasher) {
hasher.combine(key)
hasher.combine(id)
}
}
2 changes: 1 addition & 1 deletion Sources/PubNub/Helpers/Crypto/Cryptors/Cryptor.swift
Original file line number Diff line number Diff line change
Expand Up @@ -33,7 +33,7 @@ public struct EncryptedStreamData {
public typealias CryptorId = [UInt8]

/// Protocol for all types that encapsulate concrete encryption/decryption operations
public protocol Cryptor {
public protocol Cryptor: Hashable {
/// Unique 4-byte identifier across all `Cryptor`
///
/// - Important: `[0x41, 0x43, 0x52, 0x48]` and `[0x00, 0x00, 0x00, 0x00]` values are reserved
Expand Down
8 changes: 8 additions & 0 deletions Sources/PubNub/Helpers/Crypto/Cryptors/LegacyCryptor.swift
Original file line number Diff line number Diff line change
Expand Up @@ -171,3 +171,11 @@ public struct LegacyCryptor: Cryptor {
}
}
}

extension LegacyCryptor: Hashable {
public func hash(into hasher: inout Hasher) {
hasher.combine(key)
hasher.combine(withRandomIV)
hasher.combine(LegacyCryptor.ID)
}
}
8 changes: 4 additions & 4 deletions Sources/PubNub/PubNub.swift
Original file line number Diff line number Diff line change
Expand Up @@ -1381,9 +1381,9 @@ public extension PubNub {
// MARK: - Crypto

extension PubNub {
/// Encrypt some `Data` using the configuration `CryptoModule` value
/// Encrypts the `Data` object using `CryptoModule` provided in configuration
/// - Parameter message: The plain text message to be encrypted
/// - Returns: A `Result` containing either the encryped Data (mapped to Base64-encoded data) or the Crypto Error
/// - Returns: A `Result` containing either the encryped `Data` (mapped to Base64-encoded data) or the `CryptoError`
public func encrypt(message: String) -> Result<Data, Error> {
guard let cryptoModule = configuration.cryptoModule else {
PubNub.log.error(ErrorDescription.missingCryptoKey)
Expand All @@ -1400,9 +1400,9 @@ extension PubNub {
}
}

/// Decrypt some `Data` using the configuration CryptoModule value
/// Decrypts the given `Data` object using `CryptoModule` provided in `configuration`
/// - Parameter message: The encrypted `Data` to decrypt
/// - Returns: A `Result` containing either the decrypted plain text message or the Crypto Error
/// - Returns: A `Result` containing either the decrypted plain text message or the `CryptoError`
public func decrypt(data: Data) -> Result<String, Error> {
guard let cryptoModule = configuration.cryptoModule else {
PubNub.log.error(ErrorDescription.missingCryptoKey)
Expand Down
Loading
Loading