Skip to content

Commit

Permalink
Fixes
Browse files Browse the repository at this point in the history
* Fixed encrypt() and decrypt() methods for PubNub class
* Removed encoding from CryptorModule
  • Loading branch information
jguz-pubnub committed Oct 4, 2023
1 parent c5186ec commit 71416bc
Show file tree
Hide file tree
Showing 2 changed files with 33 additions and 23 deletions.
18 changes: 8 additions & 10 deletions Sources/PubNub/Helpers/Crypto/CryptorModule.swift
Original file line number Diff line number Diff line change
Expand Up @@ -32,7 +32,6 @@ public struct CryptorModule {
private let defaultCryptor: Cryptor
private let cryptors: [Cryptor]
private let legacyCryptorId: CryptorId = []
private let defaultStringEncoding: String.Encoding

typealias Base64EncodedString = String

Expand All @@ -45,11 +44,9 @@ public struct CryptorModule {
/// - Parameters:
/// - default: Primary ``Cryptor`` instance used for encryption and decryption
/// - cryptors: An optional list of ``Cryptor`` instances which older messages/files were encoded
/// - encoding: Default String encoding used when publishing new messages
public init(default cryptor: Cryptor, cryptors: [Cryptor] = [], encoding: String.Encoding = .utf8) {
public init(default cryptor: Cryptor, cryptors: [Cryptor] = []) {
self.defaultCryptor = cryptor
self.cryptors = cryptors
self.defaultStringEncoding = encoding
}

/// Encrypts the given `Data` object
Expand Down Expand Up @@ -148,7 +145,7 @@ public struct CryptorModule {
/// - Parameters:
/// - stream: Stream to encrypt
/// - contentLength: Content length of encoded stream
/// - Returns: A success, storing an ``EncryptedStreamResult`` value if operation succeeds. Otherwise, a failure storing `PubNubError` is returned
/// - Returns: A success, storing a `MultipartInputStream` value if operation succeeds. Otherwise, a failure storing `PubNubError` is returned
public func encrypt(stream: InputStream, contentLength: Int) -> Result<MultipartInputStream, PubNubError> {
guard contentLength > 0 else {
return .failure(PubNubError(
Expand Down Expand Up @@ -187,7 +184,7 @@ public struct CryptorModule {
/// - Parameters:
/// - streamData: A value describing encrypted stream
/// - outputPath: URL where the stream should be decrypted to
/// - Returns: A success, storing a decrypted ``EncryptedStreamResult`` value if operation succeeds. Otherwise, a failure storing `PubNubError` is returned
/// - Returns: A success, storing a decrypted `InputStream` value if operation succeeds. Otherwise, a failure storing `PubNubError` is returned
@discardableResult
public func decrypt(
stream: InputStream,
Expand Down Expand Up @@ -261,8 +258,9 @@ public extension CryptorModule {
/// - key: Key used for encryption/decryption
/// - withRandomIV: A flag describing whether random initialization vector should be used
///
/// This method sets ``AESCBCCryptor`` as the primary object for decryption and encryption. It also instantiates ``LegacyCryptor`` with `withRandomIV`
/// flag in order to decode messages/files that were encoded in old way.
/// This method sets ``AESCBCCryptor`` as the primary object for decryption and encryption. It also
/// instantiates ``LegacyCryptor``under the hood with `withRandomIV`. This way, you can interact with historical
/// messages or messages sent from older clients
static func aesCbcCryptoModule(with key: String, withRandomIV: Bool = true) -> CryptorModule {
CryptorModule(default: AESCBCCryptor(key: key), cryptors: [LegacyCryptor(key: key, withRandomIV: withRandomIV)])
}
Expand Down Expand Up @@ -298,7 +296,7 @@ extension CryptorModule: CustomStringConvertible {

internal extension CryptorModule {
func encrypt(string: String) -> Result<Base64EncodedString, PubNubError> {
guard let data = string.data(using: defaultStringEncoding) else {
guard let data = string.data(using: .utf8) else {
return .failure(PubNubError(
.encryptionFailure,
additional: ["Cannot create Data from provided String"]
Expand All @@ -311,7 +309,7 @@ internal extension CryptorModule {

func decryptedString(from data: Data) -> Result<String, PubNubError> {
decrypt(data: data).flatMap {
if let stringValue = String(data: $0, encoding: defaultStringEncoding) {
if let stringValue = String(data: $0, encoding: .utf8) {
return .success(stringValue)
} else {
return .failure(PubNubError(
Expand Down
38 changes: 25 additions & 13 deletions Sources/PubNub/PubNub.swift
Original file line number Diff line number Diff line change
Expand Up @@ -1247,33 +1247,45 @@ public extension PubNub {
// MARK: - Crypto

extension PubNub {
/// Encrypt some `Data` using the configuration CryptorModule value
/// Encrypt some `Data` using the configuration `CryptorModule` value
/// - Parameter message: The plain text message to be encrypted
/// - Returns: A `Result` containing either the encryped Data or the Crypto Error
func encrypt(message: String) -> Result<Data, Error> {
guard let crypto = configuration.cryptorModule else {
/// - Returns: A `Result` containing either the encryped Data (mapped to Base64-encoded data) or the Crypto Error
public func encrypt(message: String) -> Result<Data, Error> {
guard let cryptorModule = configuration.cryptorModule else {
PubNub.log.error(ErrorDescription.missingCryptoKey)
return .failure(CryptoError.invalidKey)
}

guard let dataMessage = message.data(using: .utf8) else {
return .failure(CryptoError.decodeError)
}

return crypto.encrypt(data: dataMessage)
.mapError { $0 as Error }

return cryptorModule.encrypt(data: dataMessage).map {
$0.base64EncodedData()
}.mapError {
$0 as Error
}
}

/// Decrypt some `Data` using the configuration CryptorModule value
/// - Parameter message: The encrypted `Data` to decrypt
/// - Returns: A `Result` containing either the decrypted plain text message as `Data` or the Crypto Error
func decrypt(data: Data) -> Result<Data, Error> {
guard let crypto = configuration.cryptorModule else {
/// - Returns: A `Result` containing either the decrypted plain text message or the Crypto Error
public func decrypt(data: Data) -> Result<String, Error> {
guard let cryptorModule = configuration.cryptorModule else {
PubNub.log.error(ErrorDescription.missingCryptoKey)
return .failure(CryptoError.invalidKey)
}

return crypto.decrypt(data: data)
guard let base64EncodedData = Data(base64Encoded: data) else {
PubNub.log.error("Cannot create Base64-encoded data")
return .failure(CryptoError.decodeError)
}

return cryptorModule.decrypt(data: base64EncodedData)
.flatMap {
guard let string = String(data: $0, encoding: .utf8) else {
return .failure(PubNubError(.decryptionFailure, additional: ["Cannot create String from received bytes"]))
}
return .success(string)
}
.mapError { $0 as Error }
}
}
Expand Down

0 comments on commit 71416bc

Please sign in to comment.