Skip to content

Commit

Permalink
Contract tests implemented
Browse files Browse the repository at this point in the history
  • Loading branch information
jguz-pubnub committed Sep 25, 2023
1 parent 78da753 commit 988f8ae
Show file tree
Hide file tree
Showing 7 changed files with 249 additions and 62 deletions.
14 changes: 10 additions & 4 deletions PubNub.xcodeproj/project.pbxproj
Original file line number Diff line number Diff line change
Expand Up @@ -387,6 +387,8 @@
3D758DD62AB48A6A005D2B36 /* CryptorHeaderWithinStreamFinder.swift in Sources */ = {isa = PBXBuildFile; fileRef = 3D758DD42AB48A6A005D2B36 /* CryptorHeaderWithinStreamFinder.swift */; };
3D9134972A1216F7000A5124 /* PubNubPushTargetTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 3D9134962A1216F7000A5124 /* PubNubPushTargetTests.swift */; };
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 */; };
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 */; };
Expand Down Expand Up @@ -920,6 +922,7 @@
3D758DD42AB48A6A005D2B36 /* CryptorHeaderWithinStreamFinder.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = CryptorHeaderWithinStreamFinder.swift; sourceTree = "<group>"; };
3D9134962A1216F7000A5124 /* PubNubPushTargetTests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = PubNubPushTargetTests.swift; sourceTree = "<group>"; };
3DACC7F62AB88F8E00210B14 /* Data+CommonCrypto.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "Data+CommonCrypto.swift"; sourceTree = "<group>"; };
3DBB2C202ABD8053008A100E /* PubNubCryptoModuleContractTestSteps.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = PubNubCryptoModuleContractTestSteps.swift; sourceTree = "<group>"; };
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 = "<group>"; };
793079152667C63700F23B72 /* CODEOWNERS */ = {isa = PBXFileReference; lastKnownFileType = text; path = CODEOWNERS; sourceTree = "<group>"; };
793079172667C63700F23B72 /* validate-yml.js */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.javascript; path = "validate-yml.js"; sourceTree = "<group>"; };
Expand Down Expand Up @@ -1909,6 +1912,7 @@
3D6265D22ABC8E6900FDD5E6 /* Crypto */ = {
isa = PBXGroup;
children = (
3DBB2C202ABD8053008A100E /* PubNubCryptoModuleContractTestSteps.swift */,
);
path = Crypto;
sourceTree = "<group>";
Expand Down Expand Up @@ -3024,6 +3028,7 @@
79407BD2271D4CFA0032076C /* PubNubContractTestCase.swift in Sources */,
79407BDE271D4CFA0032076C /* PubNubPushContractTestSteps.swift in Sources */,
A5115F2B291D5C2700F6ADA1 /* PubNubObjectsContractTests.swift in Sources */,
3DBB2C212ABD8053008A100E /* PubNubCryptoModuleContractTestSteps.swift in Sources */,
79407BE4271D4CFA0032076C /* PubNubFilesContractTestSteps.swift in Sources */,
79407BD8271D4CFA0032076C /* PubNubMessageActionsContractTestSteps.swift in Sources */,
A5115F28291D54F500F6ADA1 /* PubNubObjectsMembershipsContractTestSteps.swift in Sources */,
Expand All @@ -3047,6 +3052,7 @@
79407BD3271D4CFA0032076C /* PubNubContractTestCase.swift in Sources */,
79407BDF271D4CFA0032076C /* PubNubPushContractTestSteps.swift in Sources */,
A5115F2C291D5C2700F6ADA1 /* PubNubObjectsContractTests.swift in Sources */,
3DBB2C222ABD8053008A100E /* PubNubCryptoModuleContractTestSteps.swift in Sources */,
79407BE5271D4CFA0032076C /* PubNubFilesContractTestSteps.swift in Sources */,
79407BD9271D4CFA0032076C /* PubNubMessageActionsContractTestSteps.swift in Sources */,
A5115F29291D54F500F6ADA1 /* PubNubObjectsMembershipsContractTestSteps.swift in Sources */,
Expand Down Expand Up @@ -4075,7 +4081,7 @@
);
HEADER_SEARCH_PATHS = "$(inherited)";
INFOPLIST_FILE = PubNub.xcodeproj/PubNubContractTests_Info.plist;
IPHONEOS_DEPLOYMENT_TARGET = 9.0;
IPHONEOS_DEPLOYMENT_TARGET = 11.0;
LD_RUNPATH_SEARCH_PATHS = (
"$(inherited)",
"@loader_path/../Frameworks",
Expand Down Expand Up @@ -4117,7 +4123,7 @@
);
HEADER_SEARCH_PATHS = "$(inherited)";
INFOPLIST_FILE = PubNub.xcodeproj/PubNubContractTests_Info.plist;
IPHONEOS_DEPLOYMENT_TARGET = 9.0;
IPHONEOS_DEPLOYMENT_TARGET = 11.0;
LD_RUNPATH_SEARCH_PATHS = (
"$(inherited)",
"@loader_path/../Frameworks",
Expand Down Expand Up @@ -4159,7 +4165,7 @@
);
HEADER_SEARCH_PATHS = "$(inherited)";
INFOPLIST_FILE = PubNub.xcodeproj/PubNubContractTests_Info.plist;
IPHONEOS_DEPLOYMENT_TARGET = 9.0;
IPHONEOS_DEPLOYMENT_TARGET = 11.0;
LD_RUNPATH_SEARCH_PATHS = (
"$(inherited)",
"@loader_path/../Frameworks",
Expand Down Expand Up @@ -4202,7 +4208,7 @@
);
HEADER_SEARCH_PATHS = "$(inherited)";
INFOPLIST_FILE = PubNub.xcodeproj/PubNubContractTests_Info.plist;
IPHONEOS_DEPLOYMENT_TARGET = 9.0;
IPHONEOS_DEPLOYMENT_TARGET = 11.0;
LD_RUNPATH_SEARCH_PATHS = (
"$(inherited)",
"@loader_path/../Frameworks",
Expand Down
94 changes: 49 additions & 45 deletions Sources/PubNub/Helpers/Crypto/CryptorModule.swift
Original file line number Diff line number Diff line change
Expand Up @@ -28,8 +28,8 @@
import Foundation

public struct EncryptedStreamResult {
let stream: InputStream
let contentLength: Int
public let stream: InputStream
public let contentLength: Int
}

public struct CryptorModule {
Expand All @@ -40,7 +40,7 @@ public struct CryptorModule {

typealias Base64EncodedString = String

internal init(default cryptor: Cryptor, cryptors: [Cryptor], encoding: String.Encoding = .utf8) {
public init(default cryptor: Cryptor, cryptors: [Cryptor] = [], encoding: String.Encoding = .utf8) {
self.defaultCryptor = cryptor
self.cryptors = cryptors
self.defaultStringEncoding = encoding
Expand All @@ -58,26 +58,27 @@ public struct CryptorModule {
}

public func decrypt(data: Data) -> Result<Data, PubNubError> {
guard let header = try? CryptorHeader.from(data: data) else {
return .failure(PubNubError(
.unknownCryptorError,
additional: ["Unable to decrypt Data due to malformed Cryptor's header"]
))
}
guard let cryptor = cryptor(matching: header) else {
return .failure(PubNubError(
.unknownCryptorError,
additional: ["Cannot find matching Cryptor for \(header.cryptorId())"]
))
}
return cryptor.decrypt(
data: EncryptedData(
metadata: header.metadataIfAny(),
data: data.subdata(in: header.length()..<data.count)
)
)
.mapError {
PubNubError(.decryptionError, underlying: $0)
do {
let header = try CryptorHeader.from(data: data)

guard let cryptor = cryptor(matching: header) else {
return .failure(PubNubError(
.unknownCryptorError,
additional: ["Cannot find matching Cryptor for \(header.cryptorId())"]
))
}
return cryptor.decrypt(
data: EncryptedData(
metadata: header.metadataIfAny(),
data: data.subdata(in: header.length()..<data.count)
)
).mapError {
PubNubError(.decryptionError, underlying: $0)
}
} catch let error as PubNubError {
return .failure(error)
} catch {
return .failure(PubNubError(.unknownCryptorError, additional: ["Cannot decrypt InputStream"]))
}
}

Expand Down Expand Up @@ -108,27 +109,30 @@ public struct CryptorModule {
contentLength: Int,
to outputPath: URL
) -> Result<InputStream, PubNubError> {
guard let readHeaderResponse = try? CryptorHeaderWithinStreamFinder(stream: stream).findHeader() else {
return .failure(PubNubError(
.decryptionError,
additional: ["Unable to decrypt InputStream due to malformed Cryptor's header"]
))
}
guard let cryptor = cryptor(matching: readHeaderResponse.header) else {
return .failure(PubNubError(
.unknownCryptorError,
additional: ["Cannot find matching Cryptor for \(readHeaderResponse.header.cryptorId())"]
))
}
return cryptor.decrypt(
data: EncryptedStreamData(
stream: readHeaderResponse.continuationStream,
contentLength: contentLength - readHeaderResponse.header.length(),
metadata: readHeaderResponse.header.metadataIfAny()
),
outputPath: outputPath
).mapError {
PubNubError(.decryptionError, underlying: $0)
do {
let finder = CryptorHeaderWithinStreamFinder(stream: stream)
let readHeaderResponse = try finder.findHeader()

guard let cryptor = cryptor(matching: readHeaderResponse.header) else {
return .failure(PubNubError(
.unknownCryptorError,
additional: ["Cannot find matching Cryptor for \(readHeaderResponse.header.cryptorId())"]
))
}
return cryptor.decrypt(
data: EncryptedStreamData(
stream: readHeaderResponse.continuationStream,
contentLength: contentLength - readHeaderResponse.header.length(),
metadata: readHeaderResponse.header.metadataIfAny()
),
outputPath: outputPath
).mapError {
PubNubError(.decryptionError, underlying: $0)
}
} catch let error as PubNubError {
return .failure(error)
} catch {
return .failure(PubNubError(.unknownCryptorError, additional: ["Cannot decrypt InputStream"]))
}
}

Expand All @@ -144,7 +148,7 @@ public extension CryptorModule {
CryptorModule(default: AESCBCCryptor(key: key), cryptors: [LegacyCryptor(key: key, withRandomIV: withRandomIV)])
}
static func legacyCryptoModule(with key: String, withRandomIV: Bool = true) -> CryptorModule {
CryptorModule(default: LegacyCryptor(key: key, withRandomIV: withRandomIV), cryptors: [])
CryptorModule(default: LegacyCryptor(key: key, withRandomIV: withRandomIV), cryptors: [AESCBCCryptor(key: key)])
}
}

Expand Down
15 changes: 9 additions & 6 deletions Sources/PubNub/Helpers/Crypto/Header/CryptorHeader.swift
Original file line number Diff line number Diff line change
Expand Up @@ -128,21 +128,24 @@ struct CryptorHeaderParser {
return .none
}
guard let headerVersion = scanner.nextByte() else {
throw PubNubError(.unknownCryptorError, additional: ["Cannot find Crypto header version"])
throw PubNubError(.decryptionError, additional: ["Cannot find CryptorHeader's version byte"])
}
guard (1...1).contains(headerVersion) else {
throw PubNubError(.unknownCryptorError, additional: ["Invalid Crypto header version \(headerVersion)"])
throw PubNubError(.unknownCryptorError, additional: ["Invalid CryptorHeader's version \(headerVersion)"])
}
guard let cryptorId = scanner.nextBytes(4) else {
throw PubNubError(.unknownCryptorError, additional: ["Cannot find Cryptor identifier"])
throw PubNubError(.decryptionError, additional: ["Cannot find Cryptor identifier"])
}
guard let cryptorDataSize = scanner.nextByte() else {
throw PubNubError(.unknownCryptorError, additional: ["Cannot read Cryptor data size"])
throw PubNubError(.decryptionError, additional: ["Cannot read Cryptor data size"])
}
guard let cryptorDefinedData = scanner.nextBytes(Int(try computeCryptorDataSize(with: cryptorDataSize))) else {
throw PubNubError(.unknownCryptorError, additional: ["Cannot retrieve Cryptor defined data"])
throw PubNubError(.decryptionError, additional: ["Cannot retrieve Cryptor defined data"])
}
return .v1(cryptorId: cryptorId.map { $0 }, data: cryptorDefinedData)
return .v1(
cryptorId: cryptorId.map { $0 },
data: cryptorDefinedData
)
}

private func computeCryptorDataSize(with sizeIndicator: UInt8) throws -> UInt16 {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -65,11 +65,14 @@ struct CryptorHeaderWithinStreamFinder {
&buffer,
maxLength: maxLength
)
if numberOfBytesRead > 0 && buffer.count != numberOfBytesRead {
buffer = Array(buffer[0 ..< numberOfBytesRead])
guard numberOfBytesRead > 0 else {
break;
}
if buffer.count != numberOfBytesRead {
content += Array(buffer[0 ..< numberOfBytesRead])
} else {
content += buffer
}
content += buffer

} while numberOfBytesRead < maxLength && stream.hasBytesAvailable;

return Data(
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -229,10 +229,11 @@ public class CryptoInputStream: InputStream {
if finalyse {
var finalBuffer = writeBuffer
let append = cryptedBytesLength > 0


writeBuffer = Array(writeBuffer[..<cryptedBytesLength])

if append {
finalBuffer = [UInt8](repeating: 0, count: cryptorBufferSize)
writeBuffer = Array(writeBuffer[..<cryptedBytesLength])
}

do {
Expand Down
3 changes: 2 additions & 1 deletion Tests/PubNubContractTest/PubNubContractTestCase.swift
Original file line number Diff line number Diff line change
Expand Up @@ -225,7 +225,8 @@ let defaultPublishKey = "demo-36"
PubNubPublishContractTestSteps().setup()
PubNubSubscribeContractTestSteps().setup()
PubNubTimeContractTestSteps().setup()

PubNubCryptoModuleContractTestSteps().setup()

/// Objects acceptance testins.
PubNubObjectsContractTests().setup()
PubNubObjectsChannelMetadataContractTestSteps().setup()
Expand Down
Loading

0 comments on commit 988f8ae

Please sign in to comment.