diff --git a/CleverTap-iOS-SDK.podspec b/CleverTap-iOS-SDK.podspec index c385c8f2..08aeb94a 100644 --- a/CleverTap-iOS-SDK.podspec +++ b/CleverTap-iOS-SDK.podspec @@ -13,7 +13,7 @@ s.resource_bundles = {'CleverTapSDK' => ['CleverTapSDK/*.{xcprivacy}']} s.ios.dependency 'SDWebImage', '~> 5.11' s.ios.resource_bundle = {'CleverTapSDK' => ['CleverTapSDK/**/*.{png,xib,html}', 'CleverTapSDK/**/*.xcdatamodeld']} s.ios.deployment_target = '9.0' -s.ios.source_files = 'CleverTapSDK/**/*.{h,m}' +s.ios.source_files = 'CleverTapSDK/**/*.{h,m,swift}' s.ios.exclude_files = 'CleverTapSDK/include/**/*.h' s.ios.public_header_files = 'CleverTapSDK/CleverTap.h', 'CleverTapSDK/CleverTap+SSLPinning.h','CleverTapSDK/CleverTap+Inbox.h', 'CleverTapSDK/CleverTapInstanceConfig.h', 'CleverTapSDK/CleverTapBuildInfo.h', 'CleverTapSDK/CleverTapEventDetail.h', 'CleverTapSDK/CleverTapInAppNotificationDelegate.h', 'CleverTapSDK/CleverTapSyncDelegate.h', 'CleverTapSDK/CleverTapTrackedViewController.h', 'CleverTapSDK/CleverTapUTMDetail.h', 'CleverTapSDK/CleverTapJSInterface.h', 'CleverTapSDK/CleverTap+DisplayUnit.h', 'CleverTapSDK/CleverTap+FeatureFlags.h', 'CleverTapSDK/CleverTap+ProductConfig.h', 'CleverTapSDK/CleverTapPushNotificationDelegate.h', 'CleverTapSDK/CleverTapURLDelegate.h', 'CleverTapSDK/CleverTap+InAppNotifications.h', 'CleverTapSDK/CleverTap+SCDomain.h', 'CleverTapSDK/CleverTap+PushPermission.h', 'CleverTapSDK/InApps/CTLocalInApp.h', 'CleverTapSDK/CleverTap+CTVar.h', 'CleverTapSDK/ProductExperiences/CTVar.h', 'CleverTapSDK/LeanplumCT.h', 'CleverTapSDK/InApps/CustomTemplates/CTInAppTemplateBuilder.h', 'CleverTapSDK/InApps/CustomTemplates/CTAppFunctionBuilder.h', 'CleverTapSDK/InApps/CustomTemplates/CTTemplatePresenter.h', 'CleverTapSDK/InApps/CustomTemplates/CTTemplateProducer.h', 'CleverTapSDK/InApps/CustomTemplates/CTCustomTemplateBuilder.h', 'CleverTapSDK/InApps/CustomTemplates/CTCustomTemplate.h', 'CleverTapSDK/InApps/CustomTemplates/CTTemplateContext.h', 'CleverTapSDK/InApps/CustomTemplates/CTCustomTemplatesManager.h', 'CleverTapSDK/InApps/CustomTemplates/CTJsonTemplateProducer.h' s.tvos.deployment_target = '9.0' diff --git a/CleverTapSDK.xcodeproj/project.pbxproj b/CleverTapSDK.xcodeproj/project.pbxproj index 1df10405..abd0e079 100644 --- a/CleverTapSDK.xcodeproj/project.pbxproj +++ b/CleverTapSDK.xcodeproj/project.pbxproj @@ -151,6 +151,7 @@ 07FD65A2223BC26300A845B7 /* CTCoverViewController~iphoneland.xib in Resources */ = {isa = PBXBuildFile; fileRef = 07FD65A1223BC26300A845B7 /* CTCoverViewController~iphoneland.xib */; }; 07FD65A4223BCB8200A845B7 /* CTCoverViewController~ipadland.xib in Resources */ = {isa = PBXBuildFile; fileRef = 07FD65A3223BCB8200A845B7 /* CTCoverViewController~ipadland.xib */; }; 0B5564562C25946C00B87284 /* CTUserInfoMigratorTest.m in Sources */ = {isa = PBXBuildFile; fileRef = 0B5564552C25946C00B87284 /* CTUserInfoMigratorTest.m */; }; + 0B80D41B2D4A111900521AD9 /* CTEncryptor.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0B80D41A2D4A111900521AD9 /* CTEncryptor.swift */; }; 0B995A4A2C36AEDC00AF6006 /* CTLocalDataStoreTests.m in Sources */ = {isa = PBXBuildFile; fileRef = 0B995A492C36AEDC00AF6006 /* CTLocalDataStoreTests.m */; }; 1F1C18806B7F29B3374F2448 /* libPods-shared-CleverTapSDKTestsApp.a in Frameworks */ = {isa = PBXBuildFile; fileRef = E303560B5EE1D154C1E3D9EF /* libPods-shared-CleverTapSDKTestsApp.a */; }; 32394C1F29FA251E00956058 /* CTEventBuilderTest.m in Sources */ = {isa = PBXBuildFile; fileRef = 32394C1E29FA251E00956058 /* CTEventBuilderTest.m */; }; @@ -769,6 +770,7 @@ 07FD65A1223BC26300A845B7 /* CTCoverViewController~iphoneland.xib */ = {isa = PBXFileReference; lastKnownFileType = file.xib; path = "CTCoverViewController~iphoneland.xib"; sourceTree = ""; }; 07FD65A3223BCB8200A845B7 /* CTCoverViewController~ipadland.xib */ = {isa = PBXFileReference; lastKnownFileType = file.xib; path = "CTCoverViewController~ipadland.xib"; sourceTree = ""; }; 0B5564552C25946C00B87284 /* CTUserInfoMigratorTest.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = CTUserInfoMigratorTest.m; sourceTree = ""; }; + 0B80D41A2D4A111900521AD9 /* CTEncryptor.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = CTEncryptor.swift; sourceTree = ""; }; 0B995A492C36AEDC00AF6006 /* CTLocalDataStoreTests.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = CTLocalDataStoreTests.m; sourceTree = ""; }; 0CA46771B6F202E37DAC9F70 /* Pods-shared-CleverTapSDKTestsApp.debug.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-shared-CleverTapSDKTestsApp.debug.xcconfig"; path = "Target Support Files/Pods-shared-CleverTapSDKTestsApp/Pods-shared-CleverTapSDKTestsApp.debug.xcconfig"; sourceTree = ""; }; 129AEC403AFA828F591B756E /* Pods-shared-CleverTapSDKTests.release.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-shared-CleverTapSDKTests.release.xcconfig"; path = "Target Support Files/Pods-shared-CleverTapSDKTests/Pods-shared-CleverTapSDKTests.release.xcconfig"; sourceTree = ""; }; @@ -1330,6 +1332,16 @@ name = Frameworks; sourceTree = ""; }; + 0B80D4192D4A10EB00521AD9 /* Encryption */ = { + isa = PBXGroup; + children = ( + 4803951A2A7ABAD200C4D254 /* CTAES.h */, + 480395192A7ABAD200C4D254 /* CTAES.m */, + 0B80D41A2D4A111900521AD9 /* CTEncryptor.swift */, + ); + path = Encryption; + sourceTree = ""; + }; 4847D16B2CCB9018008DC327 /* EventDatabase */ = { isa = PBXGroup; children = ( @@ -1754,11 +1766,10 @@ D0C7BBBF207D82C0001345EF /* CleverTapSDK */ = { isa = PBXGroup; children = ( + 0B80D4192D4A10EB00521AD9 /* Encryption */, 4847D16B2CCB9018008DC327 /* EventDatabase */, 6B9E95B62C2AE6740002D557 /* FileDownload */, 3242D7DA2B1DDA2E00A5E37A /* PrivacyInfo.xcprivacy */, - 4803951A2A7ABAD200C4D254 /* CTAES.h */, - 480395192A7ABAD200C4D254 /* CTAES.m */, 4808030D292EB4FB00C06E2F /* CleverTap+PushPermission.h */, 4E838C4429A0C94B00ED0875 /* CleverTap+CTVar.h */, 4E64855A287440BA00C2F409 /* AmazonRootCA1.cer */, @@ -2296,6 +2307,7 @@ }; D0C7BBBC207D82C0001345EF = { CreatedOnToolsVersion = 9.3; + LastSwiftMigration = 1610; }; }; }; @@ -2769,6 +2781,7 @@ 4E49AE55275D24570074A774 /* CTValidationResultStack.m in Sources */, D01A0895207EC2D400423D6F /* CleverTapInstanceConfig.m in Sources */, 071EB4C8217F6427008F0FAB /* CTDismissButton.m in Sources */, + 0B80D41B2D4A111900521AD9 /* CTEncryptor.swift in Sources */, 6BB778C82BECEC2700A41628 /* CTCustomTemplateInAppData.m in Sources */, 4EF0D5472AD84BCA0044C48F /* CTSessionManager.m in Sources */, 4EB3638B2C087A8200C00AE2 /* CTUserInfoMigrator.m in Sources */, @@ -3211,6 +3224,7 @@ isa = XCBuildConfiguration; buildSettings = { APPLICATION_EXTENSION_API_ONLY = YES; + CLANG_ENABLE_MODULES = YES; CLANG_WARN_QUOTED_INCLUDE_IN_FRAMEWORK_HEADER = NO; CODE_SIGN_IDENTITY = ""; CODE_SIGN_STYLE = Manual; @@ -3249,6 +3263,8 @@ "PROVISIONING_PROFILE_SPECIFIER[sdk=macosx*]" = ""; SKIP_INSTALL = YES; SUPPORTS_MACCATALYST = NO; + SWIFT_OPTIMIZATION_LEVEL = "-Onone"; + SWIFT_VERSION = 6.0; TARGETED_DEVICE_FAMILY = "1,2"; }; name = Debug; @@ -3257,6 +3273,7 @@ isa = XCBuildConfiguration; buildSettings = { APPLICATION_EXTENSION_API_ONLY = YES; + CLANG_ENABLE_MODULES = YES; CLANG_WARN_QUOTED_INCLUDE_IN_FRAMEWORK_HEADER = NO; CODE_SIGN_IDENTITY = ""; CODE_SIGN_STYLE = Manual; @@ -3286,6 +3303,7 @@ "PROVISIONING_PROFILE_SPECIFIER[sdk=macosx*]" = ""; SKIP_INSTALL = YES; SUPPORTS_MACCATALYST = NO; + SWIFT_VERSION = 6.0; TARGETED_DEVICE_FAMILY = "1,2"; }; name = Release; diff --git a/CleverTapSDK/Encryption/AESCrypt.h b/CleverTapSDK/Encryption/AESCrypt.h new file mode 100644 index 00000000..07057f6c --- /dev/null +++ b/CleverTapSDK/Encryption/AESCrypt.h @@ -0,0 +1,17 @@ +// +// AESCrypt.h +// Pods +// +// Created by Kushagra Mishra on 29/01/25. +// +#import +#import + +@interface AESCrypt : NSObject + ++ (NSData *)AES128WithOperation:(CCOperation)operation + key:(NSString *)key + identifier:(NSString *)identifier + data:(NSData *)data; + +@end diff --git a/CleverTapSDK/Encryption/AESCrypt.m b/CleverTapSDK/Encryption/AESCrypt.m new file mode 100644 index 00000000..778e6796 --- /dev/null +++ b/CleverTapSDK/Encryption/AESCrypt.m @@ -0,0 +1,53 @@ +// +// AESCrypt.m +// Pods +// +// Created by Kushagra Mishra on 29/01/25. +// +#import "AESCrypt.h" + +@implementation AESCrypt : NSObject + ++ (NSData *)AES128WithOperation:(CCOperation)operation + key:(NSString *)key + identifier:(NSString *)identifier + data:(NSData *)data { + // Note: The key will be 0's but we intentionally are keeping it this way to maintain + // compatibility. The correct code is: + // char keyPtr[[key length] + 1]; + char keyCString[kCCKeySizeAES128 + 1]; + memset(keyCString, 0, sizeof(keyCString)); + [key getCString:keyCString maxLength:sizeof(keyCString) encoding:NSUTF8StringEncoding]; + + char identifierCString[kCCBlockSizeAES128 + 1]; + memset(identifierCString, 0, sizeof(identifierCString)); + [identifier getCString:identifierCString + maxLength:sizeof(identifierCString) + encoding:NSUTF8StringEncoding]; + + size_t outputAvailableSize = [data length] + kCCBlockSizeAES128; + void *output = malloc(outputAvailableSize); + + size_t outputMovedSize = 0; + CCCryptorStatus cryptStatus = CCCrypt(operation, + kCCAlgorithmAES128, + kCCOptionPKCS7Padding, + keyCString, + kCCBlockSizeAES128, + identifierCString, + [data bytes], + [data length], + output, + outputAvailableSize, + &outputMovedSize); + + if (cryptStatus != kCCSuccess) { + NSLog(@"Failed to encode/decode the string with error code: %d", cryptStatus); + free(output); + return nil; + } + + return [NSData dataWithBytesNoCopy:output length:outputMovedSize]; +} + +@end diff --git a/CleverTapSDK/Encryption/AESGCMCrypt.swift b/CleverTapSDK/Encryption/AESGCMCrypt.swift new file mode 100644 index 00000000..2a69c7a8 --- /dev/null +++ b/CleverTapSDK/Encryption/AESGCMCrypt.swift @@ -0,0 +1,95 @@ +// +// AESGCMCrypt.swift +// Pods +// +// Created by Kushagra Mishra on 29/01/25. +// + +import Foundation +import CryptoKit + +@objc public enum AESGCMEncryptionErrorCode: Int { + case encryptionFailed + case decryptionFailed + case invalidData + case dataNotFound +} + +@objcMembers +class AESGCMCryptResult: NSObject { + let iv: Data + let data: Data + + init(iv: Data, data: Data) { + self.iv = iv + self.data = data + super.init() + } +} + +@objc enum CryptError: Int, Error { + case invalidMode = 0 + case keyGenerationFailed = 1 + case encryptionFailed = 2 + case decryptionFailed = 3 + case ivRequired = 4 +} + +@available(iOS 13, *) +@objcMembers +class AESGCMCrypt: NSObject { + private let keyIdentifier = "your.key.identifier" + private static let ivSize = 12 + + private func generateOrGetKey() throws -> SymmetricKey { + if let existingKey = try? getKeyFromKeychain() { + return existingKey + } + + let newKey = SymmetricKey(size: .bits256) + try storeKeyInKeychain(newKey) + return newKey + } + + func performCryptOperation(mode: Bool, data: Data, iv: Data? = nil) throws -> AESGCMCryptResult { + let key = try generateOrGetKey() + + if mode { // Encrypt + let nonce = try AES.GCM.Nonce(data: iv ?? Data()) + let sealedBox = try AES.GCM.seal(data, using: key, nonce: nonce) + + return AESGCMCryptResult( + iv: sealedBox.nonce.withUnsafeBytes { Data($0) }, + data: sealedBox.ciphertext + sealedBox.tag + ) + } else { // Decrypt + guard let iv = iv else { + throw CryptError.ivRequired + } + + let tagLength = 16 + let ciphertext = data.dropLast(tagLength) + let tag = data.suffix(tagLength) + + let nonce = try AES.GCM.Nonce(data: iv) + let sealedBox = try AES.GCM.SealedBox( + nonce: nonce, + ciphertext: ciphertext, + tag: tag + ) + + let decryptedData = try AES.GCM.open(sealedBox, using: key) + return AESGCMCryptResult(iv: iv, data: decryptedData) + } + } + + + private func storeKeyInKeychain(_ key: SymmetricKey) throws { + // Implement secure key storage in Keychain + } + + private func getKeyFromKeychain() throws -> SymmetricKey? { + // Implement secure key retrieval from Keychain + return nil + } +} diff --git a/CleverTapSDK/CTAES.h b/CleverTapSDK/Encryption/CTAES.h similarity index 100% rename from CleverTapSDK/CTAES.h rename to CleverTapSDK/Encryption/CTAES.h diff --git a/CleverTapSDK/CTAES.m b/CleverTapSDK/Encryption/CTAES.m similarity index 77% rename from CleverTapSDK/CTAES.m rename to CleverTapSDK/Encryption/CTAES.m index b9371550..10d6735e 100644 --- a/CleverTapSDK/CTAES.m +++ b/CleverTapSDK/Encryption/CTAES.m @@ -3,6 +3,9 @@ #import "CTConstants.h" #import "CTPreferences.h" #import "CTUtils.h" +#import "AESCrypt.h" +#import "CTEncryptor.h" + NSString *const kENCRYPTION_KEY = @"CLTAP_ENCRYPTION_KEY"; NSString *const kCRYPT_KEY_PREFIX = @"Lq3fz"; @@ -129,53 +132,20 @@ - (NSString *)getDecryptedString:(NSString *)identifier { - (NSData *)convertData:(NSData *)data withOperation:(CCOperation)operation { - NSData *outputData = [self AES128WithOperation:operation - key:[self generateKeyPassword] - identifier:CLTAP_ENCRYPTION_IV - data:data]; - return outputData; -} - -- (NSData *)AES128WithOperation:(CCOperation)operation - key:(NSString *)key - identifier:(NSString *)identifier - data:(NSData *)data { - // Note: The key will be 0's but we intentionally are keeping it this way to maintain - // compatibility. The correct code is: - // char keyPtr[[key length] + 1]; - char keyCString[kCCKeySizeAES128 + 1]; - memset(keyCString, 0, sizeof(keyCString)); - [key getCString:keyCString maxLength:sizeof(keyCString) encoding:NSUTF8StringEncoding]; - - char identifierCString[kCCBlockSizeAES128 + 1]; - memset(identifierCString, 0, sizeof(identifierCString)); - [identifier getCString:identifierCString - maxLength:sizeof(identifierCString) - encoding:NSUTF8StringEncoding]; - - size_t outputAvailableSize = [data length] + kCCBlockSizeAES128; - void *output = malloc(outputAvailableSize); - - size_t outputMovedSize = 0; - CCCryptorStatus cryptStatus = CCCrypt(operation, - kCCAlgorithmAES128, - kCCOptionPKCS7Padding, - keyCString, - kCCBlockSizeAES128, - identifierCString, - [data bytes], - [data length], - output, - outputAvailableSize, - &outputMovedSize); - - if (cryptStatus != kCCSuccess) { - CleverTapLogStaticInternal(@"Failed to encode/deocde the string with error code: %d", cryptStatus); - free(output); - return nil; +// NSData *outputData = [AESCrypt AES128WithOperation:operation +// key:[self generateKeyPassword] +// identifier:CLTAP_ENCRYPTION_IV +// data:data]; + NSError *error = nil; + BOOL keyGenerated = [CTEncryptor generateKeyWithError:&error]; + if (!keyGenerated) { + NSLog(@"Error generating key: %@", error); + } + NSData *outputData = [CTEncryptor performCryptOperation:data error:&error]; + if (error) { + NSLog(@"Encryption failed: %@", error.localizedDescription); } - - return [NSData dataWithBytesNoCopy:output length:outputMovedSize]; + return outputData; } - (NSString *)getCachedKey:(NSString *)value { diff --git a/CleverTapSDK/Encryption/CTEncryptor.h b/CleverTapSDK/Encryption/CTEncryptor.h new file mode 100644 index 00000000..d7fa3414 --- /dev/null +++ b/CleverTapSDK/Encryption/CTEncryptor.h @@ -0,0 +1,23 @@ +// +// EncryptionBridge.h +// Pods +// +// Created by Kushagra Mishra on 29/01/25. +// +#import +#import + +NS_ASSUME_NONNULL_BEGIN + +@interface CTEncryptor : NSObject + +// Key Management ++ (BOOL)generateKeyWithError:(NSError **)error; ++ (BOOL)deleteKeyWithError:(NSError **)error; + +// Encryption/Decryption ++ (NSString * _Nullable)performCryptOperation:(NSString *)string error:(NSError **)error; + +@end + +NS_ASSUME_NONNULL_END diff --git a/CleverTapSDK/Encryption/CTEncryptor.m b/CleverTapSDK/Encryption/CTEncryptor.m new file mode 100644 index 00000000..ae1980da --- /dev/null +++ b/CleverTapSDK/Encryption/CTEncryptor.m @@ -0,0 +1,81 @@ +// EncryptionBridge.m +#import "CTEncryptor.h" +#import "AESCrypt.h" +#if __has_include() +#import +#else +#import "CleverTapSDK-Swift.h" +#endif + +@implementation CTEncryptor + ++ (BOOL)generateKeyWithError:(NSError **)error { + @try { + return [CTKeychainManager getOrGenerateKeyAndReturnError:error]; + } @catch (NSError *caughtError) { + if (error) { + *error = caughtError; + } + return NO; + } +} + ++ (BOOL)deleteKeyWithError:(NSError **)error { + @try { + return [CTKeychainManager deleteKeyAndReturnError:error]; + } @catch (NSError *caughtError) { + if (error) { + *error = caughtError; + } + return NO; + } +} + + ++ (NSData * _Nullable)performCryptOperation:(NSData *)data error:(NSError **)error { + @try { + if (@available(iOS 13, *)) { + AESGCMCrypt *aesgcmcryptor = [[AESGCMCrypt alloc] init]; + NSError *error = nil; + + // For encryption (mode = YES) + AESGCMCryptResult *result = [aesgcmcryptor performCryptOperationWithMode:YES + data:data + iv:nil + error:&error]; + if (error) { + NSLog(@"Encryption failed: %@", error.localizedDescription); + return nil; + } + + // For decryption (mode = NO) + AESGCMCryptResult *decryptResult = [aesgcmcryptor performCryptOperationWithMode:NO + data:result.data + iv:result.iv + error:&error]; + if (error) { + NSLog(@"Decryption failed: %@", error.localizedDescription); + return nil; + } + + return result.data; + } else { + // Handle earlier iOS versions if needed +// NSData *outputData = [AESCrypt AES128WithOperation:kCCEncrypt +// key:[self generateKeyPassword] +// identifier:CLTAP_ENCRYPTION_IV +// data:data]; + } + } @catch (NSError *caughtError) { + if (error) { + *error = caughtError; + } + return nil; + } + return nil; +} + + + + +@end diff --git a/CleverTapSDK/Encryption/CTKeychainManager.swift b/CleverTapSDK/Encryption/CTKeychainManager.swift new file mode 100644 index 00000000..da813bd9 --- /dev/null +++ b/CleverTapSDK/Encryption/CTKeychainManager.swift @@ -0,0 +1,86 @@ +import Foundation +import Security +import CryptoKit + +@objc public enum KeychainErrorCode: Int { + case keyGenerationFailed + case keychainError + case keyNotFound +} + +@objc public class CTKeychainManager: NSObject { + // MARK: - Constants + private static let keyAlias = "com.clevertap.encryption.key" + + @objc(getOrGenerateKeyAndReturnError:) + public static func getOrGenerateKey() throws -> Data { + // First try to load existing key + if let existingKey = try? loadKeyFromKeychain() { + return existingKey + } + + // If no key exists, generate and store new one + return try generateAndStoreKey() + } + + private static func generateAndStoreKey() throws -> Data { + // Generate random key data + var keyData = Data(count: 32) // 256 bits + let result = keyData.withUnsafeMutableBytes { bytes in + SecRandomCopyBytes(kSecRandomDefault, 32, bytes.baseAddress!) + } + + guard result == errSecSuccess else { + throw NSError(domain: "KeychainManager", code: KeychainErrorCode.keyGenerationFailed.rawValue) + } + + // Store key in keychain + let query: [String: Any] = [ + kSecClass as String: kSecClassGenericPassword, + kSecAttrAccount as String: keyAlias, + kSecValueData as String: keyData, + kSecAttrAccessible as String: kSecAttrAccessibleAfterFirstUnlock, + kSecAttrService as String: Bundle.main.bundleIdentifier ?? "com.default.app" + ] + + let status = SecItemAdd(query as CFDictionary, nil) + guard status == errSecSuccess else { + throw NSError(domain: "KeychainManager", code: KeychainErrorCode.keychainError.rawValue) + } + + return keyData + } + + @objc public static func loadKeyFromKeychain() throws -> Data { + let query: [String: Any] = [ + kSecClass as String: kSecClassGenericPassword, + kSecAttrAccount as String: keyAlias, + kSecReturnData as String: true, + kSecAttrService as String: Bundle.main.bundleIdentifier ?? "com.default.app" + ] + + var result: AnyObject? + let status = SecItemCopyMatching(query as CFDictionary, &result) + + guard status == errSecSuccess, + let keyData = result as? Data else { + throw NSError(domain: "KeychainManager", code: KeychainErrorCode.keyNotFound.rawValue) + } + + return keyData + } + + @objc(deleteKeyAndReturnError:) + public static func deleteKey() throws { + let query: [String: Any] = [ + kSecClass as String: kSecClassGenericPassword, + kSecAttrAccount as String: keyAlias, + kSecAttrService as String: Bundle.main.bundleIdentifier ?? "com.default.app" + ] + + let status = SecItemDelete(query as CFDictionary) + guard status == errSecSuccess || status == errSecItemNotFound else { + throw NSError(domain: "KeychainManager", code: KeychainErrorCode.keychainError.rawValue) + } + } +} diff --git a/SwiftStarter/SwiftStarter/Supporting Files/Info.plist b/SwiftStarter/SwiftStarter/Supporting Files/Info.plist index e50b15fd..b186c057 100644 --- a/SwiftStarter/SwiftStarter/Supporting Files/Info.plist +++ b/SwiftStarter/SwiftStarter/Supporting Files/Info.plist @@ -19,9 +19,9 @@ CFBundleVersion 1 CleverTapAccountID - RKW-R77-KW6Z + 6Z6-7W8-5Z6Z CleverTapToken - aa2-032 + b0a-616 LSRequiresIPhoneOS UILaunchStoryboardName