From 4706a3f42d2a0778acb4f74994a629ecabaf8445 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E7=8E=8B=E7=81=BC=E6=B4=B2?= Date: Sat, 10 Aug 2019 11:06:59 +0800 Subject: [PATCH 01/31] Release 1.11.11-pre --- Example/SensorsData/Info.plist | 22 +- SensorsAnalyticsSDK.podspec | 12 +- SensorsAnalyticsSDK.xcodeproj/project.pbxproj | 35 ++ SensorsAnalyticsSDK/MessageQueueBySqlite.h | 5 +- SensorsAnalyticsSDK/MessageQueueBySqlite.m | 34 +- SensorsAnalyticsSDK/SAConfigOptions.h | 12 + SensorsAnalyticsSDK/SAConfigOptions.m | 6 + SensorsAnalyticsSDK/SADataEncryptBuilder.h | 54 +++ SensorsAnalyticsSDK/SADataEncryptBuilder.m | 151 +++++++ SensorsAnalyticsSDK/SAEncryptUtils.h | 56 +++ SensorsAnalyticsSDK/SAEncryptUtils.m | 416 ++++++++++++++++++ SensorsAnalyticsSDK/SANetwork.m | 19 +- SensorsAnalyticsSDK/SASDKRemoteConfig.h | 3 + SensorsAnalyticsSDK/SASDKRemoteConfig.m | 1 + .../SensorsAnalyticsSDK+Private.h | 4 +- SensorsAnalyticsSDK/SensorsAnalyticsSDK.h | 11 + SensorsAnalyticsSDK/SensorsAnalyticsSDK.m | 63 ++- 17 files changed, 860 insertions(+), 44 deletions(-) create mode 100644 SensorsAnalyticsSDK/SADataEncryptBuilder.h create mode 100644 SensorsAnalyticsSDK/SADataEncryptBuilder.m create mode 100644 SensorsAnalyticsSDK/SAEncryptUtils.h create mode 100644 SensorsAnalyticsSDK/SAEncryptUtils.m diff --git a/Example/SensorsData/Info.plist b/Example/SensorsData/Info.plist index 5cac609d3..928e8db00 100644 --- a/Example/SensorsData/Info.plist +++ b/Example/SensorsData/Info.plist @@ -20,32 +20,14 @@ ???? CFBundleURLTypes - - CFBundleTypeRole - Editor - CFBundleURLSchemes - - sa8a9ab067 - - - - CFBundleTypeRole - Editor - CFBundleURLName - chenchen - CFBundleURLSchemes - - sa3f6d7cb5 - - CFBundleTypeRole Editor CFBundleURLName - cctest + cqs CFBundleURLSchemes - safda6b8ac + sac799f6b9 diff --git a/SensorsAnalyticsSDK.podspec b/SensorsAnalyticsSDK.podspec index 5f43b9fac..c27e32c04 100644 --- a/SensorsAnalyticsSDK.podspec +++ b/SensorsAnalyticsSDK.podspec @@ -1,7 +1,7 @@ Pod::Spec.new do |s| - s.name = "SensorsAnalyticsSDK" - s.version = "1.11.11" - s.summary = "The official iOS SDK of Sensors Analytics." + s.name = "SensorsAnalyticsSDK-pre" + s.version = "1.11.11-pre" + s.summary = "The official iOS SDK Pre of Sensors Analytics." s.homepage = "http://www.sensorsdata.cn" s.source = { :git => 'https://github.com/sensorsdata/sa-sdk-ios.git', :tag => "v#{s.version}" } s.license = { :type => "Apache License, Version 2.0" } @@ -126,4 +126,10 @@ Pod::Spec.new do |s| f.pod_target_xcconfig = { 'GCC_PREPROCESSOR_DEFINITIONS' => 'SENSORS_ANALYTICS_ENABLE_AUTOTRACK_CHILD_VIEWSCREEN=1'} end + # 开启 SDK 加密 + s.subspec 'ENABLE_ENCRYPTION' do |f| + f.dependency 'SensorsAnalyticsSDK/core' + f.pod_target_xcconfig = { 'GCC_PREPROCESSOR_DEFINITIONS' => 'SENSORS_ANALYTICS_ENABLE_ENCRYPTION=1'} + end + end diff --git a/SensorsAnalyticsSDK.xcodeproj/project.pbxproj b/SensorsAnalyticsSDK.xcodeproj/project.pbxproj index a573dff6e..c3ab65ab5 100644 --- a/SensorsAnalyticsSDK.xcodeproj/project.pbxproj +++ b/SensorsAnalyticsSDK.xcodeproj/project.pbxproj @@ -7,8 +7,12 @@ objects = { /* Begin PBXBuildFile section */ + 4D017F4822E7108000492D75 /* SADataEncryptBuilder.h in Headers */ = {isa = PBXBuildFile; fileRef = 4D017F4622E7108000492D75 /* SADataEncryptBuilder.h */; }; + 4D017F4922E7108000492D75 /* SADataEncryptBuilder.m in Sources */ = {isa = PBXBuildFile; fileRef = 4D017F4722E7108000492D75 /* SADataEncryptBuilder.m */; }; 4D6A189122978F5B00F6B218 /* ElementViewController.m in Sources */ = {isa = PBXBuildFile; fileRef = 4D6A188E22978F5B00F6B218 /* ElementViewController.m */; }; 4D6A189222978F5B00F6B218 /* SAAutoTrackUtilsTest.m in Sources */ = {isa = PBXBuildFile; fileRef = 4D6A188F22978F5B00F6B218 /* SAAutoTrackUtilsTest.m */; }; + 656D61F022EC453100E0DA06 /* SAEncryptUtils.m in Sources */ = {isa = PBXBuildFile; fileRef = 656D61EE22EC453100E0DA06 /* SAEncryptUtils.m */; }; + 656D61F122EC453100E0DA06 /* SAEncryptUtils.h in Headers */ = {isa = PBXBuildFile; fileRef = 656D61EF22EC453100E0DA06 /* SAEncryptUtils.h */; }; CB30C03F22840EC00004061D /* SATypeDescription.m in Sources */ = {isa = PBXBuildFile; fileRef = CB30BFD222840EBF0004061D /* SATypeDescription.m */; }; CB30C04022840EC00004061D /* SASecurityPolicy.m in Sources */ = {isa = PBXBuildFile; fileRef = CB30BFD322840EBF0004061D /* SASecurityPolicy.m */; }; CB30C04222840EC00004061D /* NSString+HashCode.m in Sources */ = {isa = PBXBuildFile; fileRef = CB30BFD522840EBF0004061D /* NSString+HashCode.m */; }; @@ -138,9 +142,14 @@ /* End PBXContainerItemProxy section */ /* Begin PBXFileReference section */ + 4D017F4622E7108000492D75 /* SADataEncryptBuilder.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = SADataEncryptBuilder.h; sourceTree = ""; }; + 4D017F4722E7108000492D75 /* SADataEncryptBuilder.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = SADataEncryptBuilder.m; sourceTree = ""; }; 4D6A188E22978F5B00F6B218 /* ElementViewController.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = ElementViewController.m; sourceTree = ""; }; 4D6A188F22978F5B00F6B218 /* SAAutoTrackUtilsTest.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = SAAutoTrackUtilsTest.m; sourceTree = ""; }; 4D6A189022978F5B00F6B218 /* ElementViewController.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = ElementViewController.h; sourceTree = ""; }; + 4D8CE4C622E872B400829B29 /* Security.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = Security.framework; path = System/Library/Frameworks/Security.framework; sourceTree = SDKROOT; }; + 656D61EE22EC453100E0DA06 /* SAEncryptUtils.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = SAEncryptUtils.m; sourceTree = ""; }; + 656D61EF22EC453100E0DA06 /* SAEncryptUtils.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = SAEncryptUtils.h; sourceTree = ""; }; CB30BD5422840CA40004061D /* SensorsAnalyticsSDK.framework */ = {isa = PBXFileReference; explicitFileType = wrapper.framework; includeInIndex = 0; path = SensorsAnalyticsSDK.framework; sourceTree = BUILT_PRODUCTS_DIR; }; CB30BFD222840EBF0004061D /* SATypeDescription.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = SATypeDescription.m; sourceTree = ""; }; CB30BFD322840EBF0004061D /* SASecurityPolicy.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = SASecurityPolicy.m; sourceTree = ""; }; @@ -290,6 +299,17 @@ /* End PBXFrameworksBuildPhase section */ /* Begin PBXGroup section */ + 4D017F3F22E70A7D00492D75 /* Encrypt */ = { + isa = PBXGroup; + children = ( + 656D61EF22EC453100E0DA06 /* SAEncryptUtils.h */, + 656D61EE22EC453100E0DA06 /* SAEncryptUtils.m */, + 4D017F4622E7108000492D75 /* SADataEncryptBuilder.h */, + 4D017F4722E7108000492D75 /* SADataEncryptBuilder.m */, + ); + name = Encrypt; + sourceTree = ""; + }; 4D6A188D22978F5B00F6B218 /* AutoTrack */ = { isa = PBXGroup; children = ( @@ -300,6 +320,14 @@ path = AutoTrack; sourceTree = ""; }; + 4D8CE4C522E872B400829B29 /* Frameworks */ = { + isa = PBXGroup; + children = ( + 4D8CE4C622E872B400829B29 /* Security.framework */, + ); + name = Frameworks; + sourceTree = ""; + }; CB30BD4A22840CA40004061D = { isa = PBXGroup; children = ( @@ -307,6 +335,7 @@ CB30C31022843D3A0004061D /* SensorsAnalyticsExtension */, CB6EBAE4228551EC003CFBA8 /* SensorsAnalyticsTests */, CB30BD5522840CA40004061D /* Products */, + 4D8CE4C522E872B400829B29 /* Frameworks */, ); sourceTree = ""; }; @@ -328,6 +357,7 @@ CB30C03422840EBF0004061D /* VisualizedAutoTrack */, CB6EBB7622857B4E003CFBA8 /* AutoTrack */, CB30C0AE228410620004061D /* Network */, + 4D017F3F22E70A7D00492D75 /* Encrypt */, CB30C00F22840EBF0004061D /* SAJSONUtil.h */, CB30BFEA22840EBF0004061D /* SAJSONUtil.m */, CB30C03122840EBF0004061D /* MessageQueueBySqlite.h */, @@ -515,6 +545,7 @@ isa = PBXHeadersBuildPhase; buildActionMask = 2147483647; files = ( + 656D61F122EC453100E0DA06 /* SAEncryptUtils.h in Headers */, CB30C06E22840EC00004061D /* SensorsAnalyticsSDK.h in Headers */, CB30C05922840EC00004061D /* SAConfigOptions.h in Headers */, CB30C07822840EC00004061D /* SASecurityPolicy.h in Headers */, @@ -564,6 +595,7 @@ CB30C0A922840EC00004061D /* SAValueTransformers.h in Headers */, CB30C04322840EC00004061D /* UIView+SAHelpers.h in Headers */, CB30C05522840EC00004061D /* NSObject+SensorsAnalyticsDelegate.h in Headers */, + 4D017F4822E7108000492D75 /* SADataEncryptBuilder.h in Headers */, CB30C09122840EC00004061D /* SAAbstractHeatMapMessage.h in Headers */, CB30C09C22840EC00004061D /* SAAlertController.h in Headers */, CB30C04E22840EC00004061D /* SAAbstractDesignerMessage.h in Headers */, @@ -758,9 +790,11 @@ CB30C0A022840EC00004061D /* SAVisualizedAutoTrackSnapshotMessage.m in Sources */, CB30C07422840EC00004061D /* UIView+SAHelpers.m in Sources */, CB30C06422840EC00004061D /* SAAppExtensionDataManager.m in Sources */, + 4D017F4922E7108000492D75 /* SADataEncryptBuilder.m in Sources */, CB30C06722840EC00004061D /* SAEnumDescription.m in Sources */, CB6EBB9E22857BC0003CFBA8 /* UIApplication+AutoTrack.m in Sources */, CB30C05D22840EC00004061D /* SAAlertController.m in Sources */, + 656D61F022EC453100E0DA06 /* SAEncryptUtils.m in Sources */, CB30C06C22840EC00004061D /* MessageQueueBySqlite.m in Sources */, CB30C04F22840EC00004061D /* SAObjectSelector.m in Sources */, ); @@ -925,6 +959,7 @@ DYLIB_COMPATIBILITY_VERSION = 1; DYLIB_CURRENT_VERSION = 1; DYLIB_INSTALL_NAME_BASE = "@rpath"; + GCC_PREPROCESSOR_DEFINITIONS = "$(inherited)"; INFOPLIST_FILE = "$(SRCROOT)/SensorsAnalyticsSDK/Info.plist"; INSTALL_PATH = "$(LOCAL_LIBRARY_DIR)/Frameworks"; IPHONEOS_DEPLOYMENT_TARGET = 8.0; diff --git a/SensorsAnalyticsSDK/MessageQueueBySqlite.h b/SensorsAnalyticsSDK/MessageQueueBySqlite.h index 4a6ce7935..a4bfc69f2 100644 --- a/SensorsAnalyticsSDK/MessageQueueBySqlite.h +++ b/SensorsAnalyticsSDK/MessageQueueBySqlite.h @@ -53,7 +53,7 @@ * * @return 获取的记录所在的数组 */ -- (NSArray *) getFirstRecords:(NSUInteger)recordSize withType:(NSString *)type ; +- (NSArray *)getFirstRecords:(NSUInteger)recordSize withType:(NSString *)type; /** @@ -64,7 +64,7 @@ * * @return 删除是否成功 */ -- (BOOL) removeFirstRecords:(NSUInteger)recordSize withType:(NSString *)type ; +- (BOOL)removeFirstRecords:(NSUInteger)recordSize withType:(NSString *)type; /** * @abstract @@ -90,5 +90,4 @@ */ - (BOOL) vacuum; - @end diff --git a/SensorsAnalyticsSDK/MessageQueueBySqlite.m b/SensorsAnalyticsSDK/MessageQueueBySqlite.m index 2193475e3..0c06f513d 100644 --- a/SensorsAnalyticsSDK/MessageQueueBySqlite.m +++ b/SensorsAnalyticsSDK/MessageQueueBySqlite.m @@ -30,6 +30,7 @@ #import "SensorsAnalyticsSDK.h" #import "SensorsAnalyticsSDK+Private.h" #import "SAConstants+Private.h" + #define MAX_MESSAGE_SIZE 10000 // 最多缓存10000条 @implementation MessageQueueBySqlite { @@ -98,7 +99,13 @@ - (void)addObejct:(id)obj withType:(NSString *)type { return; } } - NSData *jsonData = [_jsonUtil JSONSerializeObject:obj]; + + //支持加密 +#ifdef SENSORS_ANALYTICS_ENABLE_ENCRYPTION + obj = [[SensorsAnalyticsSDK sharedInstance].encryptBuilder encryptionJSONObject:obj] ?: obj; +#endif + + NSData* jsonData = [_jsonUtil JSONSerializeObject:obj]; NSString *jsonString = [[NSString alloc] initWithData:jsonData encoding:NSUTF8StringEncoding]; NSString *query = @"INSERT INTO dataCache(type, content) values(?, ?)"; @@ -146,10 +153,32 @@ - (NSArray *)getFirstRecords:(NSUInteger)recordSize withType:(NSString *)type { options:NSJSONReadingMutableContainers error:&err]; if (!err && eventDict) { +#ifdef SENSORS_ANALYTICS_ENABLE_ENCRYPTION + if (![eventDict.allKeys containsObject:@"ekey"]) { //缓存数据未加密,再加密 + NSDictionary *encryptDic = [[SensorsAnalyticsSDK sharedInstance].encryptBuilder encryptionJSONObject:eventDict]; + if (encryptDic) { + eventDict = [encryptDic mutableCopy]; + } + } + //加密数据上传时间 flush_time + UInt64 time = [[NSDate date] timeIntervalSince1970] * 1000; + [eventDict setValue:@(time) forKey:@"flush_time"]; +#else + + if ([eventDict.allKeys containsObject:@"ekey"]) { //非加密模式,缓存数据已加密,丢弃 + char* idChar = (char*)sqlite3_column_text(stmt, 0); + NSInteger idIndex = [[NSString stringWithUTF8String:idChar] integerValue]; + [self deleteRecordWithId:idIndex]; + continue; + } + + //非加密 UInt64 time = [[NSDate date] timeIntervalSince1970] * 1000; [eventDict setValue:@(time) forKey:SA_EVENT_FLUSH_TIME]; +#endif + [contentArray addObject:[[NSString alloc] initWithData:[_jsonUtil JSONSerializeObject:eventDict] encoding:NSUTF8StringEncoding]]; - } else { + } else { //删除内容为空的数据 char *idChar = (char *)sqlite3_column_text(stmt, 0); NSInteger index = [[NSString stringWithUTF8String:idChar] integerValue]; [self deleteRecordWithId:index]; @@ -162,6 +191,7 @@ - (NSArray *)getFirstRecords:(NSUInteger)recordSize withType:(NSString *)type { SAError(@"Failed to prepare statement, error:%s", sqlite3_errmsg(_database)); return nil; } + return [NSArray arrayWithArray:contentArray]; } diff --git a/SensorsAnalyticsSDK/SAConfigOptions.h b/SensorsAnalyticsSDK/SAConfigOptions.h index 47aef3407..45bd1e226 100644 --- a/SensorsAnalyticsSDK/SAConfigOptions.h +++ b/SensorsAnalyticsSDK/SAConfigOptions.h @@ -111,4 +111,16 @@ NS_ASSUME_NONNULL_BEGIN @end + +/// RSA 公钥秘钥信息 +@interface SASecretKey : NSObject + +/// 秘钥版本 +@property(nonatomic, assign) NSInteger version; + +/// 秘钥值 +@property(nonatomic, copy) NSString *key; + +@end + NS_ASSUME_NONNULL_END diff --git a/SensorsAnalyticsSDK/SAConfigOptions.m b/SensorsAnalyticsSDK/SAConfigOptions.m index d64c2d664..58bacb96e 100644 --- a/SensorsAnalyticsSDK/SAConfigOptions.m +++ b/SensorsAnalyticsSDK/SAConfigOptions.m @@ -96,3 +96,9 @@ - (void)setMaxRequestHourInterval:(NSInteger)maxRequestHourInterval { } @end + + +@implementation SASecretKey + +@end + diff --git a/SensorsAnalyticsSDK/SADataEncryptBuilder.h b/SensorsAnalyticsSDK/SADataEncryptBuilder.h new file mode 100644 index 000000000..d42e16738 --- /dev/null +++ b/SensorsAnalyticsSDK/SADataEncryptBuilder.h @@ -0,0 +1,54 @@ +// +// SADataEncryptBuilder.h +// SensorsAnalyticsSDK +// +// Created by 储强盛 on 2019/7/23. +// Copyright © 2019 SensorsData. All rights reserved. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. +// + + +#import +#import "SAConfigOptions.h" + +NS_ASSUME_NONNULL_BEGIN + +@interface SADataEncryptBuilder : NSObject + +/** + 指定初始化方法,设置 RSA 公钥 + + @param secretKey 公钥配置 + @return 配置对象 + */ +- (instancetype)initWithRSAPublicKey:(nonnull SASecretKey *)secretKey NS_DESIGNATED_INITIALIZER; + +/// 禁用 init 初始化 +- (instancetype)init NS_UNAVAILABLE; + +/// 禁用 new 初始化 ++ (instancetype)new NS_UNAVAILABLE; + +/// 设置公钥 +- (void)updateRSAPublicSecretKey:(nonnull SASecretKey *)secretKey; + +/// 加密数据 +- (nullable NSDictionary *)encryptionJSONObject:(id)obj; + +/// 构造加密的数据结构 +- (nullable NSArray *)buildFlushEncryptionDataWithRecords:(NSArray *)recordArray; + +@end + +NS_ASSUME_NONNULL_END diff --git a/SensorsAnalyticsSDK/SADataEncryptBuilder.m b/SensorsAnalyticsSDK/SADataEncryptBuilder.m new file mode 100644 index 000000000..0e1909143 --- /dev/null +++ b/SensorsAnalyticsSDK/SADataEncryptBuilder.m @@ -0,0 +1,151 @@ +// +// SADataEncryptBuilder.m +// SensorsAnalyticsSDK +// +// Created by 储强盛 on 2019/7/23. +// Copyright © 2019 SensorsData. All rights reserved. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. +// + +#if ! __has_feature(objc_arc) +#error This file must be compiled with ARC. Either turn on ARC for the project or use -fobjc-arc flag on this file. +#endif + + +#import "SADataEncryptBuilder.h" +#import "SAEncryptUtils.h" +#import "SAGzipUtility.h" +#import "SAJSONUtil.h" + +@interface SADataEncryptBuilder() + +@property(nonatomic,strong) SAJSONUtil *jsonUtil; +/// RSA 公钥配置 +@property(nonatomic, strong) SASecretKey *rsaSecretKey; + +///AES 秘钥 +@property(nonatomic, copy) NSData *aesSecretDataKey; +/// RSA 加密后 AES 秘钥 +@property(nonatomic, copy) NSString *rsaEncryptAESKey; +@end + + +@implementation SADataEncryptBuilder + +#pragma mark - initializ +- (instancetype)initWithRSAPublicKey:(SASecretKey *)secretKey { + self = [super init]; + if (self) { + _jsonUtil = [[SAJSONUtil alloc] init]; + [self updateRSAPublicSecretKey:secretKey]; + } + return self; +} + +- (void)updateRSAPublicSecretKey:(nonnull SASecretKey *)secretKey { + if (secretKey.key.length > 0 && ![secretKey.key isEqualToString:self.rsaSecretKey.key]) { + self.rsaSecretKey = secretKey; + + //对秘钥 RSA 加密 + NSData *rsaEncryptData = [SAEncryptUtils RSAEncryptData:self.aesSecretDataKey publicKey:self.rsaSecretKey.key]; + self.rsaEncryptAESKey = [rsaEncryptData base64EncodedStringWithOptions:NSDataBase64EncodingEndLineWithCarriageReturn]; + } +} + +-(NSData *)aesSecretDataKey { + if (!_aesSecretDataKey) { + _aesSecretDataKey = [SAEncryptUtils random16ByteData]; + } + return _aesSecretDataKey; +} + +- (NSString *)rsaEncryptAESKey { + if (!_rsaEncryptAESKey && self.rsaSecretKey.key.length > 0) { + //对秘钥 RSA 加密 + NSData *rsaEncryptData = [SAEncryptUtils RSAEncryptData:self.aesSecretDataKey publicKey:self.rsaSecretKey.key]; + _rsaEncryptAESKey = [rsaEncryptData base64EncodedStringWithOptions:NSDataBase64EncodingEndLineWithCarriageReturn]; + } + return _rsaEncryptAESKey; +} + +- (nullable NSDictionary *)encryptionJSONObject:(id)obj { + if (!self.rsaSecretKey || !self.rsaEncryptAESKey) { + return nil; + } + + NSData *jsonData = [self.jsonUtil JSONSerializeObject:obj]; + NSString *encodingString = [[NSString alloc] initWithData:jsonData encoding:NSUTF8StringEncoding]; + NSData *encodingData = [encodingString dataUsingEncoding:NSUTF8StringEncoding]; + //使用 gzip 进行压缩 + NSData *zippedData = [SAGzipUtility gzipData:encodingData]; + + //AES128 加密 + NSString *encryptString = [SAEncryptUtils AES128EncryptData:zippedData AESKey:self.aesSecretDataKey]; + if (!encryptString) { + return nil; + } + //封装加密的数据结构 + NSMutableDictionary *secretObj = [NSMutableDictionary dictionary]; + secretObj[@"pkv"] = @(self.rsaSecretKey.version); + secretObj[@"ekey"] = self.rsaEncryptAESKey; + secretObj[@"payload"] = encryptString; + return secretObj; +} + +- (nullable NSArray *)buildFlushEncryptionDataWithRecords:(NSArray *)recordArray { + /***** 构造加密数据结构 *****/ + // 字典,方便去重 + NSMutableDictionary *ekeyPayloadsDic = [NSMutableDictionary dictionary]; + + for (NSString *json in recordArray) { + NSData *jsonData = [json dataUsingEncoding:NSUTF8StringEncoding]; + NSDictionary *jsonDic = [NSJSONSerialization JSONObjectWithData:jsonData options:NSJSONReadingMutableContainers error:nil]; + if (jsonDic && [jsonDic.allKeys containsObject:@"ekey"]) { + + NSMutableArray *sameEncryptArray = ekeyPayloadsDic[jsonDic[@"ekey"]]; + if (sameEncryptArray.count == 0) { + sameEncryptArray = [NSMutableArray array]; + [sameEncryptArray addObject:[jsonDic mutableCopy]]; + [ekeyPayloadsDic setObject:sameEncryptArray forKey:jsonDic[@"ekey"]]; + } else { + [sameEncryptArray addObject:[jsonDic mutableCopy]]; + } + } + } + + NSMutableArray *encryptArray = [NSMutableArray array]; + for (NSString *ekey in ekeyPayloadsDic.allKeys) { + NSMutableArray *sameEncryptArray = ekeyPayloadsDic[ekey]; + NSMutableDictionary *encryptDic = [NSMutableDictionary dictionaryWithDictionary:sameEncryptArray.firstObject]; + [encryptDic removeObjectForKey:@"payload"]; + NSMutableArray *sameEncryptPayloads = [NSMutableArray array]; + for (NSDictionary *dic in sameEncryptArray) { + [sameEncryptPayloads addObject:dic[@"payload"]]; + } + encryptDic[@"payloads"] = sameEncryptPayloads; + + NSData *encrypData = [self.jsonUtil JSONSerializeObject:encryptDic]; + NSString *encrypString = [[NSString alloc] initWithData:encrypData encoding:NSUTF8StringEncoding]; + [encryptArray addObject:encrypString]; + } + + if (encryptArray.count > 0) { + NSArray *contentArray = [NSArray arrayWithArray:encryptArray]; + return contentArray; + } else { + return nil; + } +} + +@end diff --git a/SensorsAnalyticsSDK/SAEncryptUtils.h b/SensorsAnalyticsSDK/SAEncryptUtils.h new file mode 100644 index 000000000..0488c446d --- /dev/null +++ b/SensorsAnalyticsSDK/SAEncryptUtils.h @@ -0,0 +1,56 @@ +// +// SAEncryptUtils.h +// SensorsAnalyticsSDK +// +// Created by 储强盛 on 2018/10/31. +// Copyright © 2018 Sensors Data Inc. All rights reserved. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. +// + +#import + +NS_ASSUME_NONNULL_BEGIN + +@interface SAEncryptUtils : NSObject + +/** + RSA 公钥加密 + + @param data 待加密数据 + @param pubKey 公钥 + @return 加密后数据 + */ ++ (nullable NSData *)RSAEncryptData:(NSData *)data publicKey:(NSString *)pubKey; + +#pragma mark - AES + +/** + 随机生成 16 字节秘钥 + @return 秘钥 Byte 数据 + */ ++ (NSData *)random16ByteData; + +/** + AES 128 加密 + + @param data 待加密数据 + @param keyData 秘钥 + @return 加密并 base64 字符 + */ ++ (nullable NSString *)AES128EncryptData:(NSData *)data AESKey:(NSData *)keyData; + +@end + +NS_ASSUME_NONNULL_END + diff --git a/SensorsAnalyticsSDK/SAEncryptUtils.m b/SensorsAnalyticsSDK/SAEncryptUtils.m new file mode 100644 index 000000000..0c4c76719 --- /dev/null +++ b/SensorsAnalyticsSDK/SAEncryptUtils.m @@ -0,0 +1,416 @@ +// +// SAEncryptUtils.m +// SensorsAnalyticsSDK +// +// Created by 储强盛 on 2018/10/31. +// Copyright © 2018 Sensors Data Inc. All rights reserved. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. +// + +#if ! __has_feature(objc_arc) +#error This file must be compiled with ARC. Either turn on ARC for the project or use -fobjc-arc flag on this file. +#endif + + +#import "SAEncryptUtils.h" +#import +#import +#import +#import "SALogger.h" + +@implementation SAEncryptUtils + +static NSString *base64_encode_data(NSData *data) { + data = [data base64EncodedDataWithOptions:NSDataBase64EncodingEndLineWithCarriageReturn]; + NSString *ret = [[NSString alloc] initWithData:data encoding:NSUTF8StringEncoding]; + return ret; +} + +static NSData *base64_decode(NSString *str) { + NSData *data = [[NSData alloc] initWithBase64EncodedString:str options:NSDataBase64DecodingIgnoreUnknownCharacters]; + return data; +} + +#pragma mark - RSA +/** + 公钥加密 + return base64 encoded string + @param originString 原数据 + @param pubKey 公钥 + @return 加密后数据 + */ ++ (NSString *)RSAEncryptString:(NSString *)originString publicKey:(NSString *)pubKey { + NSData *data = [SAEncryptUtils RSAEncryptData:[originString dataUsingEncoding:NSUTF8StringEncoding] publicKey:pubKey]; + NSString *ret = base64_encode_data(data); + return ret; +} + ++ (nullable NSData *)RSAEncryptData:(NSData *)data publicKey:(NSString *)pubKey { + if (!data || !pubKey) { + return nil; + } + SecKeyRef keyRef = [SAEncryptUtils addPublicKey:pubKey]; + if (!keyRef) { + SAError(@"initialize Public SecKeyRef Fail"); + return nil; + } + return [SAEncryptUtils RSAEncryptData:data withKeyRef:keyRef]; +} + +/** + 私钥解密 + @param string 加密后数据 + @param privKey 私钥 + @return 解密数据 + */ ++ (NSString *)RSADecryptString:(NSString *)string privateKey:(NSString *)privKey { + NSData *data = [[NSData alloc] initWithBase64EncodedString:string options:NSDataBase64DecodingIgnoreUnknownCharacters]; + data = [SAEncryptUtils RSADecryptData:data privateKey:privKey]; + NSString *ret = [[NSString alloc] initWithData:data encoding:NSUTF8StringEncoding]; + return ret; +} + ++ (NSData *)RSADecryptData:(NSData *)data privateKey:(NSString *)privKey { + if (!data || !privKey) { + return nil; + } + SecKeyRef keyRef = [SAEncryptUtils addPrivateKey:privKey]; + if (!keyRef) { + SAError(@"initialize Private SecKeyRef Fail"); + return nil; + } + return [SAEncryptUtils RSADecryptData:data withKeyRef:keyRef]; +} + ++ (NSData *)stripPublicKeyHeader:(NSData *)d_key { + // Skip ASN.1 public key header + if (d_key == nil) return(nil); + + unsigned long len = [d_key length]; + if (!len) return(nil); + + unsigned char *c_key = (unsigned char *)[d_key bytes]; + unsigned int idx = 0; + + if (c_key[idx++] != 0x30) return(nil); + + if (c_key[idx] > 0x80) idx += c_key[idx] - 0x80 + 1; + else idx++; + + // PKCS #1 rsaEncryption szOID_RSA_RSA + static unsigned char seqiod[] = + { 0x30, 0x0d, 0x06, 0x09, 0x2a, 0x86, 0x48, 0x86, 0xf7, 0x0d, 0x01, 0x01, + 0x01, 0x05, 0x00 }; + if (memcmp(&c_key[idx], seqiod, 15)) return(nil); + + idx += 15; + + if (c_key[idx++] != 0x03) return(nil); + + if (c_key[idx] > 0x80) idx += c_key[idx] - 0x80 + 1; + else idx++; + + if (c_key[idx++] != '\0') return(nil); + + // Now make a new NSData from this buffer + return([NSData dataWithBytes:&c_key[idx] length:len - idx]); +} + ++ (NSData *)stripPrivateKeyHeader:(NSData *)d_key { + // Skip ASN.1 private key header + if (d_key == nil) return(nil); + + unsigned long len = [d_key length]; + if (!len) return(nil); + + unsigned char *c_key = (unsigned char *)[d_key bytes]; + unsigned int idx = 22; //magic byte at offset 22 + + if (0x04 != c_key[idx++]) return nil; + + //calculate length of the key + unsigned int c_len = c_key[idx++]; + int det = c_len & 0x80; + if (!det) { + c_len = c_len & 0x7f; + } else { + int byteCount = c_len & 0x7f; + if (byteCount + idx > len) { + //rsa length field longer than buffer + return nil; + } + unsigned int accum = 0; + unsigned char *ptr = &c_key[idx]; + idx += byteCount; + while (byteCount) { + accum = (accum << 8) + *ptr; + ptr++; + byteCount--; + } + c_len = accum; + } + // Now make a new NSData from this buffer + return [d_key subdataWithRange:NSMakeRange(idx, c_len)]; +} + ++ (SecKeyRef)addPublicKey:(NSString *)key { + key = [key stringByReplacingOccurrencesOfString:@"\r" withString:@""]; + key = [key stringByReplacingOccurrencesOfString:@"\n" withString:@""]; + key = [key stringByReplacingOccurrencesOfString:@"\t" withString:@""]; + key = [key stringByReplacingOccurrencesOfString:@" " withString:@""]; + + // This will be base64 encoded, decode it. + NSData *data = base64_decode(key); + data = [SAEncryptUtils stripPublicKeyHeader:data]; + if (!data) { + return nil; + } + + //a tag to read/write keychain storage + NSString *tag = @"RSAUtil_PubKey"; + NSData *d_tag = [NSData dataWithBytes:[tag UTF8String] length:[tag length]]; + + // Delete any old lingering key with the same tag + NSMutableDictionary *publicKey = [[NSMutableDictionary alloc] init]; + [publicKey setObject:(__bridge id) kSecClassKey forKey:(__bridge id)kSecClass]; + [publicKey setObject:(__bridge id) kSecAttrKeyTypeRSA forKey:(__bridge id)kSecAttrKeyType]; + [publicKey setObject:d_tag forKey:(__bridge id)kSecAttrApplicationTag]; + SecItemDelete((__bridge CFDictionaryRef)publicKey); + + // Add persistent version of the key to system keychain + [publicKey setObject:data forKey:(__bridge id)kSecValueData]; + [publicKey setObject:(__bridge id) kSecAttrKeyClassPublic forKey:(__bridge id) + kSecAttrKeyClass]; + [publicKey setObject:[NSNumber numberWithBool:YES] forKey:(__bridge id) + kSecReturnPersistentRef]; + + CFTypeRef persistKey = nil; + OSStatus status = SecItemAdd((__bridge CFDictionaryRef)publicKey, &persistKey); + if (persistKey != nil) { + CFRelease(persistKey); + } + if ((status != noErr) && (status != errSecDuplicateItem)) { + return nil; + } + + [publicKey removeObjectForKey:(__bridge id)kSecValueData]; + [publicKey removeObjectForKey:(__bridge id)kSecReturnPersistentRef]; + [publicKey setObject:[NSNumber numberWithBool:YES] forKey:(__bridge id)kSecReturnRef]; + [publicKey setObject:(__bridge id) kSecAttrKeyTypeRSA forKey:(__bridge id)kSecAttrKeyType]; + + // Now fetch the SecKeyRef version of the key + SecKeyRef keyRef = nil; + status = SecItemCopyMatching((__bridge CFDictionaryRef)publicKey, (CFTypeRef *)&keyRef); + if (status != noErr) { + return nil; + } + return keyRef; +} + ++ (SecKeyRef)addPrivateKey:(NSString *)key { + + key = [key stringByReplacingOccurrencesOfString:@"\r" withString:@""]; + key = [key stringByReplacingOccurrencesOfString:@"\n" withString:@""]; + key = [key stringByReplacingOccurrencesOfString:@"\t" withString:@""]; + key = [key stringByReplacingOccurrencesOfString:@" " withString:@""]; + + // This will be base64 encoded, decode it. + NSData *data = base64_decode(key); + data = [SAEncryptUtils stripPrivateKeyHeader:data]; + if (!data) { + return nil; + } + + //a tag to read/write keychain storage + NSString *tag = @"RSAUtil_PrivKey"; + NSData *d_tag = [NSData dataWithBytes:[tag UTF8String] length:[tag length]]; + + // Delete any old lingering key with the same tag + NSMutableDictionary *privateKey = [[NSMutableDictionary alloc] init]; + [privateKey setObject:(__bridge id) kSecClassKey forKey:(__bridge id)kSecClass]; + [privateKey setObject:(__bridge id) kSecAttrKeyTypeRSA forKey:(__bridge id)kSecAttrKeyType]; + [privateKey setObject:d_tag forKey:(__bridge id)kSecAttrApplicationTag]; + SecItemDelete((__bridge CFDictionaryRef)privateKey); + + // Add persistent version of the key to system keychain + [privateKey setObject:data forKey:(__bridge id)kSecValueData]; + [privateKey setObject:(__bridge id) kSecAttrKeyClassPrivate forKey:(__bridge id) + kSecAttrKeyClass]; + [privateKey setObject:[NSNumber numberWithBool:YES] forKey:(__bridge id) + kSecReturnPersistentRef]; + + CFTypeRef persistKey = nil; + OSStatus status = SecItemAdd((__bridge CFDictionaryRef)privateKey, &persistKey); + if (persistKey != nil) { + CFRelease(persistKey); + } + if ((status != noErr) && (status != errSecDuplicateItem)) { + return nil; + } + + [privateKey removeObjectForKey:(__bridge id)kSecValueData]; + [privateKey removeObjectForKey:(__bridge id)kSecReturnPersistentRef]; + [privateKey setObject:[NSNumber numberWithBool:YES] forKey:(__bridge id)kSecReturnRef]; + [privateKey setObject:(__bridge id) kSecAttrKeyTypeRSA forKey:(__bridge id)kSecAttrKeyType]; + + // Now fetch the SecKeyRef version of the key + SecKeyRef keyRef = nil; + status = SecItemCopyMatching((__bridge CFDictionaryRef)privateKey, (CFTypeRef *)&keyRef); + if (status != noErr) { + return nil; + } + return keyRef; +} + +/** Encryption & Decryption with RSA private key */ ++ (NSData *)RSAEncryptData:(NSData *)data withKeyRef:(SecKeyRef) keyRef { + + const uint8_t *srcbuf = (const uint8_t *)[data bytes]; + size_t srclen = (size_t)data.length; + + size_t block_size = SecKeyGetBlockSize(keyRef) * sizeof(uint8_t); + void *outbuf = malloc(block_size); + size_t src_block_size = block_size - 11; + + NSMutableData *ret = [[NSMutableData alloc] init]; + for(int idx=0; idx src_block_size) { + data_len = src_block_size; + } + + size_t outlen = block_size; + OSStatus status = noErr; + + status = SecKeyEncrypt(keyRef, + kSecPaddingPKCS1, + srcbuf + idx, + data_len, + outbuf, + &outlen + ); + if (status != 0) { + SAError(@"SecKeyEncrypt fail. Error Code: %d", status); + ret = nil; + break; + }else{ + [ret appendBytes:outbuf length:outlen]; + } + } + free(outbuf); + CFRelease(keyRef); + return ret; +} + ++ (NSData *)RSADecryptData:(NSData *)data withKeyRef:(SecKeyRef) keyRef { + const uint8_t *srcbuf = (const uint8_t *)[data bytes]; + size_t srclen = (size_t)data.length; + + size_t block_size = SecKeyGetBlockSize(keyRef) * sizeof(uint8_t); + UInt8 *outbuf = malloc(block_size); + size_t src_block_size = block_size; + + NSMutableData *ret = [[NSMutableData alloc] init]; + for(int idx=0; idx src_block_size) { + data_len = src_block_size; + } + + size_t outlen = block_size; + OSStatus status = noErr; + status = SecKeyDecrypt(keyRef, + kSecPaddingNone, + srcbuf + idx, + data_len, + outbuf, + &outlen + ); + if (status != 0) { + SAError(@"SecKeyEncrypt fail. Error Code: %d", (int)status); + ret = nil; + break; + } else { + //the actual decrypted data is in the middle, locate it! + int idxFirstZero = -1; + int idxNextZero = (int)outlen; + for ( int i = 0; i < outlen; i++ ) { + if ( outbuf[i] == 0 ) { + if ( idxFirstZero < 0 ) { + idxFirstZero = i; + } else { + idxNextZero = i; + break; + } + } + } + [ret appendBytes:&outbuf[idxFirstZero+1] length:idxNextZero-idxFirstZero-1]; + } + } + + free(outbuf); + CFRelease(keyRef); + return ret; +} + +#pragma mark - AES +/** + 随机生成 16 字节秘钥 + @return 秘钥 Byte 数据 + */ ++ (NSData *)random16ByteData { + unsigned char buf[16]; + arc4random_buf(buf, sizeof(buf)); + NSData *data = [NSData dataWithBytes:buf length:sizeof(buf)]; + return data; +} + +/** + AES128加密 + */ ++ (nullable NSString *)AES128EncryptData:(NSData *)data AESKey:(NSData *)keyData { + + NSUInteger dataLength = [data length]; + size_t bufferSize = dataLength + kCCBlockSizeAES128; + void *buffer = malloc(bufferSize); + + unsigned char buf[16]; + arc4random_buf(buf, sizeof(buf)); + NSData *ivData = [NSData dataWithBytes:buf length:sizeof(buf)]; + + size_t numBytesEncrypted = 0; + CCCryptorStatus cryptStatus = CCCrypt(kCCEncrypt, kCCAlgorithmAES128, + kCCOptionPKCS7Padding, + [keyData bytes], kCCBlockSizeAES128, + [ivData bytes], + [data bytes], dataLength, + buffer, bufferSize, + &numBytesEncrypted); + if (cryptStatus == kCCSuccess) { + NSData *encryptData = [NSData dataWithBytes:buffer length:numBytesEncrypted]; + NSMutableData *ivEncryptData = [NSMutableData dataWithData:ivData]; + [ivEncryptData appendData:encryptData]; + + free(buffer); + + NSString *encryptString = base64_encode_data(ivEncryptData); + return encryptString; + } else { + free(buffer); + SAError(@"AES128EncryptData fail,Error Code: %d",(int)cryptStatus); + } + return nil; +} + +@end diff --git a/SensorsAnalyticsSDK/SANetwork.m b/SensorsAnalyticsSDK/SANetwork.m index 329eb43a8..67864f900 100644 --- a/SensorsAnalyticsSDK/SANetwork.m +++ b/SensorsAnalyticsSDK/SANetwork.m @@ -154,14 +154,21 @@ - (NSString *)buildFlushJSONStringWithEvents:(NSArray *)events { - (NSURLRequest *)buildFlushRequestWithJSONString:(NSString *)jsonString HTTPMethod:(NSString *)HTTPMethod { NSString *postBody; @try { - // 2. 使用gzip进行压缩 - NSData *zippedData = [SAGzipUtility gzipData:[jsonString dataUsingEncoding:NSUTF8StringEncoding]]; - // 3. base64 - NSString *b64String = [zippedData base64EncodedStringWithOptions:NSDataBase64EncodingEndLineWithCarriageReturn]; + int gzip = 9; // gzip = 9 表示加密编码 + NSString *b64String = [jsonString copy]; +#ifndef SENSORS_ANALYTICS_ENABLE_ENCRYPTION + // 加密数据已经做过 gzip 压缩和 base64 处理了,就不需要再处理。 + gzip = 1; + // 使用gzip进行压缩 + NSData *zippedData = [SAGzipUtility gzipData:[b64String dataUsingEncoding:NSUTF8StringEncoding]]; + // base64 + b64String = [zippedData base64EncodedStringWithOptions:NSDataBase64EncodingEndLineWithCarriageReturn]; +#endif + int hashCode = [b64String sensorsdata_hashCode]; b64String = [b64String stringByAddingPercentEncodingWithAllowedCharacters:[NSCharacterSet alphanumericCharacterSet]]; - - postBody = [NSString stringWithFormat:@"crc=%d&gzip=1&data_list=%@", hashCode, b64String]; + postBody = [NSString stringWithFormat:@"crc=%d&gzip=%d&data_list=%@", hashCode, gzip, b64String]; + } @catch (NSException *exception) { SAError(@"%@ flushByPost format data error: %@", self, exception); return nil; diff --git a/SensorsAnalyticsSDK/SASDKRemoteConfig.h b/SensorsAnalyticsSDK/SASDKRemoteConfig.h index 2cd31e688..b4d9eec01 100644 --- a/SensorsAnalyticsSDK/SASDKRemoteConfig.h +++ b/SensorsAnalyticsSDK/SASDKRemoteConfig.h @@ -29,6 +29,9 @@ static NSInteger kSAAutoTrackModeEnabledAll = 15; @property (nonatomic, assign) BOOL disableDebugMode; @property (nonatomic, assign) NSInteger autoTrackMode;//-1,0,1~15 +//本地保存 SDK 版本号 +@property(nonatomic,copy)NSString *localLibVersion; + + (instancetype)configWithDict:(NSDictionary *)dict; - (instancetype)initWithDict:(NSDictionary *)dict; @end diff --git a/SensorsAnalyticsSDK/SASDKRemoteConfig.m b/SensorsAnalyticsSDK/SASDKRemoteConfig.m index a49138e16..a849ac66a 100644 --- a/SensorsAnalyticsSDK/SASDKRemoteConfig.m +++ b/SensorsAnalyticsSDK/SASDKRemoteConfig.m @@ -48,6 +48,7 @@ - (instancetype)initWithDict:(NSDictionary *)dict{ _v = [dict valueForKey:@"v"]; _disableSDK = [[dict valueForKeyPath:@"configs.disableSDK"] boolValue]; _disableDebugMode = [[dict valueForKeyPath:@"configs.disableDebugMode"] boolValue]; + _localLibVersion = [dict valueForKey:@"localLibVersion"]; NSNumber *autoTrackMode = [dict valueForKeyPath:@"configs.autoTrackMode"]; if (autoTrackMode != nil) { NSInteger iMode = autoTrackMode.integerValue; diff --git a/SensorsAnalyticsSDK/SensorsAnalyticsSDK+Private.h b/SensorsAnalyticsSDK/SensorsAnalyticsSDK+Private.h index 1f4f88842..0c8d29fdc 100644 --- a/SensorsAnalyticsSDK/SensorsAnalyticsSDK+Private.h +++ b/SensorsAnalyticsSDK/SensorsAnalyticsSDK+Private.h @@ -24,7 +24,7 @@ #import #import #import "SANetwork.h" - +#import "SADataEncryptBuilder.h" /** 埋点方式 @@ -82,6 +82,8 @@ typedef NS_ENUM(NSInteger, SensorsAnalyticsTrackType) { @property (nonatomic, strong, readonly) SANetwork *network; +@property(nonatomic, strong, readonly) SADataEncryptBuilder *encryptBuilder; + @end diff --git a/SensorsAnalyticsSDK/SensorsAnalyticsSDK.h b/SensorsAnalyticsSDK/SensorsAnalyticsSDK.h index 62f0d1efe..cfbab7ee4 100755 --- a/SensorsAnalyticsSDK/SensorsAnalyticsSDK.h +++ b/SensorsAnalyticsSDK/SensorsAnalyticsSDK.h @@ -1004,6 +1004,17 @@ NS_ASSUME_NONNULL_BEGIN */ - (void)clearKeychainData; + +#pragma mark - SecretKey +/** + 加载秘钥 + @param secretKey 秘钥数据 + */ +- (void)loadSecretKey:(SASecretKey *)secretKey; + +/// 保存秘钥 +@property (nonatomic, copy) void (^saveSecretKeyCompletion)(SASecretKey * _Nullable secretKey); + @end /** diff --git a/SensorsAnalyticsSDK/SensorsAnalyticsSDK.m b/SensorsAnalyticsSDK/SensorsAnalyticsSDK.m index f23de36c9..4f0596416 100755 --- a/SensorsAnalyticsSDK/SensorsAnalyticsSDK.m +++ b/SensorsAnalyticsSDK/SensorsAnalyticsSDK.m @@ -65,7 +65,7 @@ #import "SAAuxiliaryToolManager.h" -#define VERSION @"1.11.11" +#define VERSION @"1.11.11-pre" static NSUInteger const SA_PROPERTY_LENGTH_LIMITATION = 8191; @@ -181,6 +181,7 @@ @interface SensorsAnalyticsSDK() @property (nonatomic, strong) SASDKRemoteConfig *remoteConfig; @property (nonatomic, strong) SAConfigOptions *configOptions; +@property(nonatomic, strong) SADataEncryptBuilder *encryptBuilder; #ifndef SENSORS_ANALYTICS_DISABLE_TRACK_DEVICE_ORIENTATION @property (nonatomic, strong) SADeviceOrientationManager *deviceOrientationManager; @@ -1098,12 +1099,18 @@ - (void)flushByType:(NSString *)type flushSize:(int)flushSize { SAError(@"Failed to get records from SQLite."); return; } + + NSInteger recordCount = recordArray.count; +#ifdef SENSORS_ANALYTICS_ENABLE_ENCRYPTION + recordArray = [self.encryptBuilder buildFlushEncryptionDataWithRecords:recordArray]; +#endif + // 2、上传获取到的记录。如果数据上传完成,结束递归 if (recordArray.count == 0 || ![self.network flushEvents:recordArray]) { return; } // 3、删除已上传的记录。删除失败,结束递归 - if (![self.messageQueue removeFirstRecords:recordArray.count withType:@"POST"]) { + if (![self.messageQueue removeFirstRecords:recordCount withType:@"POST"]) { SAError(@"Failed to remove records from SQLite."); return; } @@ -3015,7 +3022,7 @@ - (void)applicationDidBecomeActive:(NSNotification *)notification { } [self shouldRequestRemoteConfig]; - + // 是否首次启动 BOOL isFirstStart = NO; if (![[NSUserDefaults standardUserDefaults] boolForKey:SA_HAS_LAUNCHED_ONCE]) { @@ -3252,8 +3259,16 @@ - (id)remoteConfig { } - (void)shouldRequestRemoteConfig { - - //判断是否符合分散 remoteconfig 请求条件 + +#ifdef SENSORS_ANALYTICS_ENABLE_ENCRYPTION + // 如果开启加密,并且未设置公钥(新用户安装或者从未加密版本升级而来),需要及时请求一次远程配置,获取公钥。 + if (!self.encryptBuilder) { + [self requestFunctionalManagermentConfig]; + return; + } +#endif + + //判断是否符合分散 remoteconfig 请求条件 if (self.configOptions.disableRandomTimeRequestRemoteConfig || self.configOptions.maxRequestHourInterval < self.configOptions.minRequestHourInterval) { [self requestFunctionalManagermentConfig]; SALog(@"disableRandomTimeRequestRemoteConfig or minHourInterval and maxHourInterval error,Please check the value"); @@ -3317,12 +3332,27 @@ - (void)requestFunctionalManagermentConfigDelay:(NSTimeInterval) delay index:(NS if (autoTrackMode == nil) { autoTrackMode = [NSNumber numberWithInteger:-1]; } - NSDictionary *configToBeSet = nil; + NSMutableDictionary *configToBeSet = nil; if (v) { - configToBeSet = @{@"v": v, @"configs": @{@"disableSDK": disableSDK, @"disableDebugMode": disableDebugMode, @"autoTrackMode": autoTrackMode}}; + configToBeSet = [NSMutableDictionary dictionaryWithDictionary:@{@"v": v, @"configs": @{@"disableSDK": disableSDK, @"disableDebugMode": disableDebugMode, @"autoTrackMode": autoTrackMode}}]; } else { - configToBeSet = @{@"configs": @{@"disableSDK": disableSDK, @"disableDebugMode": disableDebugMode, @"autoTrackMode": autoTrackMode}}; + configToBeSet = [NSMutableDictionary dictionaryWithDictionary:@{@"configs": @{@"disableSDK": disableSDK, @"disableDebugMode": disableDebugMode, @"autoTrackMode": autoTrackMode}}]; } + + NSDictionary *publicKeyDic = [configDict valueForKeyPath:@"configs.key"]; + if (publicKeyDic) { + SASecretKey *secreKey = [[SASecretKey alloc] init]; + secreKey.version = [publicKeyDic[@"pkv"] integerValue]; + secreKey.key = publicKeyDic[@"public_key"]; + + [self loadSecretKey:secreKey]; + if (self.saveSecretKeyCompletion) { + self.saveSecretKeyCompletion(secreKey); + } + } + + //存储当前 SDK 版本号 + [configToBeSet setValue:self.libVersion forKey:@"localLibVersion"]; [[NSUserDefaults standardUserDefaults] setObject:configToBeSet forKey:SA_SDK_TRACK_CONFIG]; [[NSUserDefaults standardUserDefaults] synchronize]; } @@ -3354,7 +3384,9 @@ - (void)requestFunctionalManagermentConfigWithCompletion:(void(^)(BOOL success, return; } NSURL *url = [NSURL URLWithString:self.configOptions.remoteConfigURL]; - [self.network functionalManagermentConfigWithRemoteConfigURL:url version:self.remoteConfig.v completion:completion]; + BOOL shouldAddVersion = [self.remoteConfig.localLibVersion isEqualToString:self.libVersion] && self.encryptBuilder; + NSString *configVersion = shouldAddVersion ? self.remoteConfig.v : nil; + [self.network functionalManagermentConfigWithRemoteConfigURL:url version:configVersion completion:completion]; } @catch (NSException *e) { SAError(@"%@ error: %@", self, e); } @@ -3438,6 +3470,19 @@ - (SASecurityPolicy *)securityPolicy { return self.network.securityPolicy; } +#pragma mark - SecretKey +- (void)loadSecretKey:(SASecretKey *)secretKey { + if (secretKey.key.length > 0) { + dispatch_async(self.serialQueue, ^{ + if (self.encryptBuilder) { + [self.encryptBuilder updateRSAPublicSecretKey:secretKey]; + } else { + self.encryptBuilder = [[SADataEncryptBuilder alloc] initWithRSAPublicKey:secretKey]; + } + }); + } +} + @end #pragma mark - People analytics From 7d07f99907e8883ad94075f5773fffcb957a6408 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E7=8E=8B=E7=81=BC=E6=B4=B2?= Date: Sat, 10 Aug 2019 11:32:22 +0800 Subject: [PATCH 02/31] Release 1.11.11-pre --- ...podspec => SensorsAnalyticsSDK-pre.podspec | 38 +++++++++---------- 1 file changed, 19 insertions(+), 19 deletions(-) rename SensorsAnalyticsSDK.podspec => SensorsAnalyticsSDK-pre.podspec (85%) diff --git a/SensorsAnalyticsSDK.podspec b/SensorsAnalyticsSDK-pre.podspec similarity index 85% rename from SensorsAnalyticsSDK.podspec rename to SensorsAnalyticsSDK-pre.podspec index c27e32c04..64c837769 100644 --- a/SensorsAnalyticsSDK.podspec +++ b/SensorsAnalyticsSDK-pre.podspec @@ -19,116 +19,116 @@ Pod::Spec.new do |s| # 打开 log s.subspec 'LOG' do |f| - f.dependency 'SensorsAnalyticsSDK/core' + f.dependency 'SensorsAnalyticsSDK-pre/core' f.pod_target_xcconfig = { 'GCC_PREPROCESSOR_DEFINITIONS' => 'SENSORS_ANALYTICS_ENABLE_LOG=1'} end # 自动采集 $referrer s.subspec 'AUTOTRACT_APPVIEWSCREEN_URL' do |f| - f.dependency 'SensorsAnalyticsSDK/core' + f.dependency 'SensorsAnalyticsSDK-pre/core' f.pod_target_xcconfig = { 'GCC_PREPROCESSOR_DEFINITIONS' => 'SENSORS_ANALYTICS_AUTOTRACT_APPVIEWSCREEN_URL=1'} end # 禁用 GPS 定位采集,相关代码不参与编译 s.subspec 'DISABLE_TRACK_GPS' do |f| - f.dependency 'SensorsAnalyticsSDK/core' + f.dependency 'SensorsAnalyticsSDK-pre/core' f.pod_target_xcconfig = { 'GCC_PREPROCESSOR_DEFINITIONS' => 'SENSORS_ANALYTICS_DISABLE_TRACK_GPS=1'} end # 禁用设备方向采集 s.subspec 'DISABLE_TRACK_DEVICE_ORIENTATION' do |f| - f.dependency 'SensorsAnalyticsSDK/core' + f.dependency 'SensorsAnalyticsSDK-pre/core' f.pod_target_xcconfig = { 'GCC_PREPROCESSOR_DEFINITIONS' => 'SENSORS_ANALYTICS_DISABLE_TRACK_DEVICE_ORIENTATION=1'} end # 禁用 debugMode 下弹框提示 s.subspec 'DISABLE_DEBUG_WARNING' do |f| - f.dependency 'SensorsAnalyticsSDK/core' + f.dependency 'SensorsAnalyticsSDK-pre/core' f.pod_target_xcconfig = { 'GCC_PREPROCESSOR_DEFINITIONS' => 'SENSORS_ANALYTICS_DISABLE_DEBUG_WARNING=1'} end # 不采集 UICollectionView 点击事件 s.subspec 'DISABLE_AUTOTRACK_UICOLLECTIONVIEW' do |f| - f.dependency 'SensorsAnalyticsSDK/core' + f.dependency 'SensorsAnalyticsSDK-pre/core' f.pod_target_xcconfig = { 'GCC_PREPROCESSOR_DEFINITIONS' => 'SENSORS_ANALYTICS_DISABLE_AUTOTRACK_UICOLLECTIONVIEW=1'} end # 不采集 UITableView 点击事件 s.subspec 'DISABLE_AUTOTRACK_UITABLEVIEW' do |f| - f.dependency 'SensorsAnalyticsSDK/core' + f.dependency 'SensorsAnalyticsSDK-pre/core' f.pod_target_xcconfig = { 'GCC_PREPROCESSOR_DEFINITIONS' => 'SENSORS_ANALYTICS_DISABLE_AUTOTRACK_UITABLEVIEW=1'} end # 不采集 UIImage 的名称 s.subspec 'DISABLE_AUTOTRACK_UIIMAGE_IMAGENAME' do |f| - f.dependency 'SensorsAnalyticsSDK/core' + f.dependency 'SensorsAnalyticsSDK-pre/core' f.pod_target_xcconfig = { 'GCC_PREPROCESSOR_DEFINITIONS' => 'SENSORS_ANALYTICS_DISABLE_AUTOTRACK_UIIMAGE_IMAGENAME=1'} end # 不采集手势点击事件 s.subspec 'DISABLE_AUTOTRACK_GESTURE' do |f| - f.dependency 'SensorsAnalyticsSDK/core' + f.dependency 'SensorsAnalyticsSDK-pre/core' f.pod_target_xcconfig = { 'GCC_PREPROCESSOR_DEFINITIONS' => 'SENSORS_ANALYTICS_DISABLE_AUTOTRACK_GESTURE=1'} end # 开启 React Native 页面控件的自动采集 $AppClick 事件 s.subspec 'ENABLE_REACT_NATIVE_APPCLICK' do |f| - f.dependency 'SensorsAnalyticsSDK/core' + f.dependency 'SensorsAnalyticsSDK-pre/core' f.pod_target_xcconfig = { 'GCC_PREPROCESSOR_DEFINITIONS' => 'SENSORS_ANALYTICS_REACT_NATIVE=1'} end # 允许使用私有 API s.subspec 'ENABLE_NO_PUBLIC_APIS' do |f| - f.dependency 'SensorsAnalyticsSDK/core' + f.dependency 'SensorsAnalyticsSDK-pre/core' f.pod_target_xcconfig = { 'GCC_PREPROCESSOR_DEFINITIONS' => 'SENSORS_ANALYTICS_ENABLE_NO_PUBLICK_APIS=1'} end # 不采集 UITabBar 点击事件 s.subspec 'DISABLE_AUTOTRACK_UITABBAR' do |f| - f.dependency 'SensorsAnalyticsSDK/core' + f.dependency 'SensorsAnalyticsSDK-pre/core' f.pod_target_xcconfig = { 'GCC_PREPROCESSOR_DEFINITIONS' => 'SENSORS_ANALYTICS_DISABLE_AUTOTRACK_UITABBAR=1'} end # 采集 crash slideAdress 信息,需要打开 enableTrackAppCrash 才生效 s.subspec 'CRASH_SLIDEADDRESS' do |f| - f.dependency 'SensorsAnalyticsSDK/core' + f.dependency 'SensorsAnalyticsSDK-pre/core' f.pod_target_xcconfig = { 'GCC_PREPROCESSOR_DEFINITIONS' => 'SENSORS_ANALYTICS_CRASH_SLIDEADDRESS=1'} end # 不采集 $device_id s.subspec 'DISABLE_AUTOTRACK_DEVICEID' do |f| - f.dependency 'SensorsAnalyticsSDK/core' + f.dependency 'SensorsAnalyticsSDK-pre/core' f.pod_target_xcconfig = { 'GCC_PREPROCESSOR_DEFINITIONS' => 'SENSORS_ANALYTICS_DISABLE_AUTOTRACK_DEVICEID=1'} end # 支持非 UIViewController 实现 UITableView 或 UICollectionView delegate 的点击事件采集 s.subspec 'ENABLE_AUTOTRACK_DIDSELECTROW' do |f| - f.dependency 'SensorsAnalyticsSDK/core' + f.dependency 'SensorsAnalyticsSDK-pre/core' f.pod_target_xcconfig = { 'GCC_PREPROCESSOR_DEFINITIONS' => 'SENSORS_ANALYTICS_ENABLE_AUTOTRACK_DIDSELECTROW=1'} end # trackInstallation 不保存在 keychain,卸载重装会重新触发激活事件 s.subspec 'DISABLE_INSTALLATION_MARK_IN_KEYCHAIN' do |f| - f.dependency 'SensorsAnalyticsSDK/core' + f.dependency 'SensorsAnalyticsSDK-pre/core' f.pod_target_xcconfig = { 'GCC_PREPROCESSOR_DEFINITIONS' => 'SENSORS_ANALYTICS_DISABLE_INSTALLATION_MARK_IN_KEYCHAIN=1'} end # 禁用 keychain # 卸载重装会重新触发激活事件并且匿名 Id 可能会被重置 s.subspec 'DISABLE_KEYCHAIN' do |f| - f.dependency 'SensorsAnalyticsSDK/core' + f.dependency 'SensorsAnalyticsSDK-pre/core' f.pod_target_xcconfig = { 'GCC_PREPROCESSOR_DEFINITIONS' => 'SENSORS_ANALYTICS_DISABLE_KEYCHAIN=1'} end # 支持自动采集 UIViewController 子页面的 $AppViewScreen s.subspec 'ENABLE_CHILD_VIEWSCREEN' do |f| - f.dependency 'SensorsAnalyticsSDK/core' + f.dependency 'SensorsAnalyticsSDK-pre/core' f.pod_target_xcconfig = { 'GCC_PREPROCESSOR_DEFINITIONS' => 'SENSORS_ANALYTICS_ENABLE_AUTOTRACK_CHILD_VIEWSCREEN=1'} end # 开启 SDK 加密 s.subspec 'ENABLE_ENCRYPTION' do |f| - f.dependency 'SensorsAnalyticsSDK/core' + f.dependency 'SensorsAnalyticsSDK-pre/core' f.pod_target_xcconfig = { 'GCC_PREPROCESSOR_DEFINITIONS' => 'SENSORS_ANALYTICS_ENABLE_ENCRYPTION=1'} end From 62236f2c14d36299adbe78ebfbbf139c68fe4004 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E7=8E=8B=E7=81=BC=E6=B4=B2?= Date: Wed, 28 Aug 2019 16:46:46 +0800 Subject: [PATCH 03/31] Release 1.11.12-pre --- Example/SensorsData/AppDelegate.m | 2 +- Example/SensorsData/AutoTrackViewController.m | 14 +- .../SensorsData/Base.lproj/Main.storyboard | 6 +- Example/SensorsData/DemoController.m | 2 +- Example/SensorsDataSwift/AppDelegate.swift | 2 +- SensorsAnalyticsSDK-pre.podspec | 2 +- SensorsAnalyticsSDK.xcodeproj/project.pbxproj | 8 + SensorsAnalyticsSDK/SAConstants+Private.h | 2 +- SensorsAnalyticsSDK/SAConstants.m | 2 +- SensorsAnalyticsSDK/SAWeakPropertyContainer.h | 29 ++++ SensorsAnalyticsSDK/SAWeakPropertyContainer.m | 41 +++++ .../SensorsAnalyticsExceptionHandler.m | 18 ++- SensorsAnalyticsSDK/SensorsAnalyticsSDK.h | 105 ++++++++----- SensorsAnalyticsSDK/SensorsAnalyticsSDK.m | 141 +++++++++++------- .../UIGestureRecognizer+AutoTrack.m | 5 + .../AutoTrack/SAAutoTrackUtilsTest.m | 35 +++++ 16 files changed, 293 insertions(+), 121 deletions(-) create mode 100644 SensorsAnalyticsSDK/SAWeakPropertyContainer.h create mode 100644 SensorsAnalyticsSDK/SAWeakPropertyContainer.m diff --git a/Example/SensorsData/AppDelegate.m b/Example/SensorsData/AppDelegate.m index feeb83a67..8e30054dc 100644 --- a/Example/SensorsData/AppDelegate.m +++ b/Example/SensorsData/AppDelegate.m @@ -38,7 +38,7 @@ - (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:( // options.flushInterval = 10 * 1000; // options.flushBulkSize = 100; options.maxCacheSize = 20000; - [SensorsAnalyticsSDK sharedInstanceWithConfig:options]; + [SensorsAnalyticsSDK startWithConfigOptions:options]; [[SensorsAnalyticsSDK sharedInstance] registerSuperProperties:@{@"AAA":UIDevice.currentDevice.identifierForVendor.UUIDString}]; [[SensorsAnalyticsSDK sharedInstance] registerDynamicSuperProperties:^NSDictionary * _Nonnull{ diff --git a/Example/SensorsData/AutoTrackViewController.m b/Example/SensorsData/AutoTrackViewController.m index 49ebfaea3..e60d5bba6 100644 --- a/Example/SensorsData/AutoTrackViewController.m +++ b/Example/SensorsData/AutoTrackViewController.m @@ -41,10 +41,10 @@ - (void)viewDidLoad { UIBarButtonItem *rightItem = [[UIBarButtonItem alloc] initWithTitle:@"下一页" style:UIBarButtonItemStyleDone target:self action:@selector(nextAction)]; self.navigationItem.rightBarButtonItem = rightItem; - + self.myLabel.userInteractionEnabled = YES; - UITapGestureRecognizer *labelTapGestureRecognizer = [[UITapGestureRecognizer alloc]initWithTarget:self action:@selector(labelTouchUpInside:)]; - [self.myLabel addGestureRecognizer:labelTapGestureRecognizer]; + UILongPressGestureRecognizer *longGestureRecognizer = [[UILongPressGestureRecognizer alloc]initWithTarget:self action:@selector(longTouchUpInside:)]; + [self.myLabel addGestureRecognizer:longGestureRecognizer]; UITapGestureRecognizer *imageViewTapGestureRecognizer = [[UITapGestureRecognizer alloc]initWithTarget:self action:@selector(imageViewTouchUpInside:)]; self.imageView.userInteractionEnabled = YES; @@ -52,8 +52,8 @@ - (void)viewDidLoad { [self.myButton1 setAttributedTitle:[[NSAttributedString alloc]initWithString:@"attributedTitle - button1" attributes:@{ NSFontAttributeName: [UIFont systemFontOfSize:13], NSForegroundColorAttributeName: [UIColor redColor] }] forState:UIControlStateNormal]; - [self.myLabel setAttributedText:[[NSAttributedString alloc]initWithString:@"attributedText" attributes:@{ NSFontAttributeName: [UIFont systemFontOfSize:13], NSForegroundColorAttributeName: [UIColor redColor] }]]; -// self.myLabel.text = @"text----"; + [self.myLabel setAttributedText:[[NSAttributedString alloc]initWithString:@"attributedText-longGesture" attributes:@{ NSFontAttributeName: [UIFont systemFontOfSize:13], NSForegroundColorAttributeName: [UIColor redColor] }]]; + // self.myLabel.text = @"text----"; } -(IBAction)stepperOnClick:(UIStepper*)sender { @@ -76,9 +76,9 @@ - (IBAction)segmentOnClick:(UISegmentedControl *)sender { } --(void) labelTouchUpInside:(UITapGestureRecognizer *)recognizer{ +-(void) longTouchUpInside:(UILongPressGestureRecognizer *)recognizer{ UILabel *label=(UILabel*)recognizer.view; - NSLog(@"%@被点击了",label.text); + NSLog(@"%@手势长按",label.text); } diff --git a/Example/SensorsData/Base.lproj/Main.storyboard b/Example/SensorsData/Base.lproj/Main.storyboard index f9a49116c..1a7026ad6 100644 --- a/Example/SensorsData/Base.lproj/Main.storyboard +++ b/Example/SensorsData/Base.lproj/Main.storyboard @@ -1,11 +1,11 @@ - + - + @@ -225,7 +225,7 @@ -