@onekeyfe/react-native-jpush 0.0.0-stage → 6.7.0-23
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/LICENSE +21 -0
- package/README.md +56 -2
- package/ReactNativeJpush.podspec +66 -0
- package/android/CMakeLists.txt +24 -0
- package/android/build.gradle +144 -0
- package/android/fcm/build.gradle +36 -0
- package/android/fcm/consumer-rules.pro +2 -0
- package/android/fcm/src/main/AndroidManifest.xml +25 -0
- package/android/fcm/src/main/java/com/onekey/jpush/fcm/FcmInitProvider.java +25 -0
- package/android/fcm/src/main/java/com/onekey/jpush/fcm/FcmMessagingService.java +84 -0
- package/android/fcm/src/main/java/com/onekey/jpush/fcm/FcmPushManager.java +69 -0
- package/android/fcm/src/test/java/com/onekey/jpush/fcm/FcmAdapterTest.java +684 -0
- package/android/fcm/src/test/java/com/onekey/jpush/fcm/FcmManifestTest.java +54 -0
- package/android/gradle.properties +4 -0
- package/android/src/main/AndroidManifest.xml +143 -0
- package/android/src/main/cpp/cpp-adapter.cpp +6 -0
- package/android/src/main/java/cn/android/service/JTransitActivity.java +19 -0
- package/android/src/main/java/cn/jiguang/android/BuildConfig.java +10 -0
- package/android/src/main/java/cn/jiguang/android/IDataShare.java +190 -0
- package/android/src/main/java/cn/jiguang/api/BaseLogger.java +82 -0
- package/android/src/main/java/cn/jiguang/api/JAction.java +22 -0
- package/android/src/main/java/cn/jiguang/api/JActionExtra.java +21 -0
- package/android/src/main/java/cn/jiguang/api/JAnalyticsAction.java +11 -0
- package/android/src/main/java/cn/jiguang/api/JCoreInterface.java +228 -0
- package/android/src/main/java/cn/jiguang/api/JCoreManager.java +156 -0
- package/android/src/main/java/cn/jiguang/api/JDispatchAction.java +66 -0
- package/android/src/main/java/cn/jiguang/api/MultiSpHelper.java +114 -0
- package/android/src/main/java/cn/jiguang/api/ReportCallBack.java +9 -0
- package/android/src/main/java/cn/jiguang/api/SdkType.java +13 -0
- package/android/src/main/java/cn/jiguang/api/utils/JCollectionAuth.java +28 -0
- package/android/src/main/java/cn/jiguang/core/JCoreCrypto.java +545 -0
- package/android/src/main/java/cn/jiguang/core/JCoreStorage.java +737 -0
- package/android/src/main/java/cn/jiguang/core/JCoreTcpEngine.java +1395 -0
- package/android/src/main/java/cn/jiguang/core/JCoreWireCodec.java +1716 -0
- package/android/src/main/java/cn/jiguang/internal/ActionManager.java +63 -0
- package/android/src/main/java/cn/jiguang/internal/JConstants.java +61 -0
- package/android/src/main/java/cn/jiguang/internal/JCoreHelperAction.java +12 -0
- package/android/src/main/java/cn/jiguang/internal/JCoreInternalHelper.java +102 -0
- package/android/src/main/java/cn/jiguang/net/DefaultHostVerifier.java +40 -0
- package/android/src/main/java/cn/jiguang/net/HttpRequest.java +78 -0
- package/android/src/main/java/cn/jiguang/net/HttpResponse.java +48 -0
- package/android/src/main/java/cn/jiguang/net/HttpUtils.java +106 -0
- package/android/src/main/java/cn/jiguang/plugins/core/JCoreModule.java +91 -0
- package/android/src/main/java/cn/jiguang/plugins/core/JCorePackage.java +27 -0
- package/android/src/main/java/cn/jiguang/plugins/push/JPushModule.java +773 -0
- package/android/src/main/java/cn/jiguang/plugins/push/JPushPackage.java +25 -0
- package/android/src/main/java/cn/jiguang/plugins/push/common/JConstants.java +88 -0
- package/android/src/main/java/cn/jiguang/plugins/push/common/JLogger.java +122 -0
- package/android/src/main/java/cn/jiguang/plugins/push/helper/JPushHelper.java +710 -0
- package/android/src/main/java/cn/jiguang/plugins/push/receiver/JPushBroadcastReceiver.java +37 -0
- package/android/src/main/java/cn/jiguang/plugins/push/receiver/JPushModuleReceiver.java +264 -0
- package/android/src/main/java/cn/jiguang/plugins/service/JCoreModuleService.java +7 -0
- package/android/src/main/java/cn/jpush/android/api/BasicPushNotificationBuilder.java +83 -0
- package/android/src/main/java/cn/jpush/android/api/CallBackParams.java +50 -0
- package/android/src/main/java/cn/jpush/android/api/CmdMessage.java +33 -0
- package/android/src/main/java/cn/jpush/android/api/CustomMessage.java +28 -0
- package/android/src/main/java/cn/jpush/android/api/CustomPushNotificationBuilder.java +81 -0
- package/android/src/main/java/cn/jpush/android/api/DefaultPushNotificationBuilder.java +90 -0
- package/android/src/main/java/cn/jpush/android/api/InAppSlotParams.java +65 -0
- package/android/src/main/java/cn/jpush/android/api/InstrumentedActivity.java +17 -0
- package/android/src/main/java/cn/jpush/android/api/InstrumentedListActivity.java +17 -0
- package/android/src/main/java/cn/jpush/android/api/JPushInterface.java +490 -0
- package/android/src/main/java/cn/jpush/android/api/JPushMessage.java +121 -0
- package/android/src/main/java/cn/jpush/android/api/JThirdPlatFormInterface.java +247 -0
- package/android/src/main/java/cn/jpush/android/api/MultiActionsNotificationBuilder.java +72 -0
- package/android/src/main/java/cn/jpush/android/api/NotificationCustomButton.java +50 -0
- package/android/src/main/java/cn/jpush/android/api/NotificationMessage.java +67 -0
- package/android/src/main/java/cn/jpush/android/api/PushNotificationBuilder.java +13 -0
- package/android/src/main/java/cn/jpush/android/api/TagAliasCallback.java +8 -0
- package/android/src/main/java/cn/jpush/android/data/JPushCollectControl.java +96 -0
- package/android/src/main/java/cn/jpush/android/data/JPushConfig.java +79 -0
- package/android/src/main/java/cn/jpush/android/data/JPushConfigEx.java +41 -0
- package/android/src/main/java/cn/jpush/android/data/JPushLocalNotification.java +155 -0
- package/android/src/main/java/cn/jpush/android/helper/JCoreHelper.java +70 -0
- package/android/src/main/java/cn/jpush/android/helper/Logger.java +82 -0
- package/android/src/main/java/cn/jpush/android/local/ActionHelper.java +1293 -0
- package/android/src/main/java/cn/jpush/android/local/ActivityLifeCallBack.java +47 -0
- package/android/src/main/java/cn/jpush/android/local/JPushAction.java +67 -0
- package/android/src/main/java/cn/jpush/android/local/JPushConstants.java +34 -0
- package/android/src/main/java/cn/jpush/android/local/JPushResponse.java +26 -0
- package/android/src/main/java/cn/jpush/android/local/ProxyActivityAction.java +34 -0
- package/android/src/main/java/cn/jpush/android/service/AlarmReceiver.java +15 -0
- package/android/src/main/java/cn/jpush/android/service/BActivity.java +19 -0
- package/android/src/main/java/cn/jpush/android/service/DActivity.java +19 -0
- package/android/src/main/java/cn/jpush/android/service/DaemonService.java +17 -0
- package/android/src/main/java/cn/jpush/android/service/DataProvider.java +136 -0
- package/android/src/main/java/cn/jpush/android/service/DataShare.java +129 -0
- package/android/src/main/java/cn/jpush/android/service/DownloadProvider.java +139 -0
- package/android/src/main/java/cn/jpush/android/service/InitProvider.java +48 -0
- package/android/src/main/java/cn/jpush/android/service/JCommonService.java +79 -0
- package/android/src/main/java/cn/jpush/android/service/JNotifyActivity.java +28 -0
- package/android/src/main/java/cn/jpush/android/service/JPushMessageReceiver.java +94 -0
- package/android/src/main/java/cn/jpush/android/service/PushReceiver.java +26 -0
- package/android/src/main/java/cn/jpush/android/service/PushService.java +28 -0
- package/android/src/main/java/cn/jpush/android/service/SchedulerReceiver.java +17 -0
- package/android/src/main/java/cn/jpush/android/service/TagAliasReceiver.java +11 -0
- package/android/src/main/java/cn/jpush/android/service/WakedResultReceiver.java +24 -0
- package/android/src/main/java/cn/jpush/android/ui/FullScreenView.java +11 -0
- package/android/src/main/java/cn/jpush/android/ui/PopWinActivity.java +16 -0
- package/android/src/main/java/cn/jpush/android/ui/PushActivity.java +27 -0
- package/android/src/main/java/cn/jpush/android/ui/RoundedImageView.java +63 -0
- package/android/src/main/java/cn/jpush/android/ui/ShadowViewCard.java +56 -0
- package/android/src/main/java/cn/jpush/android/ups/ICallbackResult.java +5 -0
- package/android/src/main/java/cn/jpush/android/ups/JPushUPSManager.java +37 -0
- package/android/src/main/java/cn/jpush/android/ups/TokenResult.java +47 -0
- package/android/src/main/java/cn/jpush/android/ups/UPSRegisterCallBack.java +4 -0
- package/android/src/main/java/cn/jpush/android/ups/UPSTurnCallBack.java +4 -0
- package/android/src/main/java/cn/jpush/android/ups/UPSUnRegisterCallBack.java +4 -0
- package/android/src/main/java/com/margelo/nitro/reactnativejpush/ReactNativeJpush.kt +455 -0
- package/android/src/main/java/com/margelo/nitro/reactnativejpush/ReactNativeJpushPackage.kt +50 -0
- package/android/src/main/res/values/jpush_string.xml +7 -0
- package/android/src/main/res/values/jpush_style.xml +22 -0
- package/android/src/test/java/com/margelo/nitro/reactnativejpush/JPushCloudHandshakeTest.java +110 -0
- package/android/src/test/java/com/margelo/nitro/reactnativejpush/JPushHandshakeFailureTest.java +73 -0
- package/android/src/test/java/com/margelo/nitro/reactnativejpush/ReactNativeJpushProtocolTest.java +908 -0
- package/ios/ReactNativeJpush.swift +522 -0
- package/ios/bridge/RCTJCoreModule.h +5 -0
- package/ios/bridge/RCTJCoreModule.m +31 -0
- package/ios/bridge/RCTJPushEventQueue.h +14 -0
- package/ios/bridge/RCTJPushEventQueue.m +23 -0
- package/ios/bridge/RCTJPushModule.h +37 -0
- package/ios/bridge/RCTJPushModule.m +1165 -0
- package/ios/include/JCOREService.h +3 -0
- package/ios/include/JGCOREAPI.h +14 -0
- package/ios/include/JGInforCollectionAuth.h +17 -0
- package/ios/include/JGInforCollectionAuthItems.h +2 -0
- package/ios/include/JGPushNotificationTrigger.h +2 -0
- package/ios/include/JPUSHService.h +359 -0
- package/ios/jcore/JCOREConfiguration.h +141 -0
- package/ios/jcore/JCOREConfiguration.m +703 -0
- package/ios/jcore/JCORECrypto.h +73 -0
- package/ios/jcore/JCORECrypto.m +649 -0
- package/ios/jcore/JCORESisResolver.h +56 -0
- package/ios/jcore/JCORESisResolver.m +525 -0
- package/ios/jcore/JCORETcpSession.h +42 -0
- package/ios/jcore/JCORETcpSession.m +956 -0
- package/ios/jcore/JCOREWireProtocol.h +274 -0
- package/ios/jcore/JCOREWireProtocol.m +1453 -0
- package/ios/jpush/JPUSHModels.m +214 -0
- package/ios/jpush/JPUSHNotificationManager.h +34 -0
- package/ios/jpush/JPUSHNotificationManager.m +360 -0
- package/ios/jpush/JPUSHService.m +794 -0
- package/ios/tests/ReactNativeJpushTests.m +148 -0
- package/lib/module/ReactNativeJpush.nitro.js +4 -0
- package/lib/module/ReactNativeJpush.nitro.js.map +1 -0
- package/lib/module/index.js +801 -0
- package/lib/module/index.js.map +1 -0
- package/lib/module/package.json +1 -0
- package/lib/typescript/package.json +1 -0
- package/lib/typescript/src/ReactNativeJpush.nitro.d.ts +60 -0
- package/lib/typescript/src/ReactNativeJpush.nitro.d.ts.map +1 -0
- package/lib/typescript/src/index.d.ts +235 -0
- package/lib/typescript/src/index.d.ts.map +1 -0
- package/nitro.json +23 -0
- package/nitrogen/generated/android/c++/JFunc_void_bool.hpp +75 -0
- package/nitrogen/generated/android/c++/JFunc_void_std__string_std__string.hpp +76 -0
- package/nitrogen/generated/android/c++/JHybridReactNativeJpushSpec.cpp +310 -0
- package/nitrogen/generated/android/c++/JHybridReactNativeJpushSpec.hpp +115 -0
- package/nitrogen/generated/android/kotlin/com/margelo/nitro/reactnativejpush/Func_void_bool.kt +78 -0
- package/nitrogen/generated/android/kotlin/com/margelo/nitro/reactnativejpush/Func_void_std__string_std__string.kt +78 -0
- package/nitrogen/generated/android/kotlin/com/margelo/nitro/reactnativejpush/HybridReactNativeJpushSpec.kt +274 -0
- package/nitrogen/generated/android/kotlin/com/margelo/nitro/reactnativejpush/reactnativejpushOnLoad.kt +35 -0
- package/nitrogen/generated/android/reactnativejpush+autolinking.cmake +81 -0
- package/nitrogen/generated/android/reactnativejpush+autolinking.gradle +27 -0
- package/nitrogen/generated/android/reactnativejpushOnLoad.cpp +58 -0
- package/nitrogen/generated/android/reactnativejpushOnLoad.hpp +34 -0
- package/nitrogen/generated/ios/ReactNativeJpush+autolinking.rb +62 -0
- package/nitrogen/generated/ios/ReactNativeJpush-Swift-Cxx-Bridge.cpp +49 -0
- package/nitrogen/generated/ios/ReactNativeJpush-Swift-Cxx-Bridge.hpp +147 -0
- package/nitrogen/generated/ios/ReactNativeJpush-Swift-Cxx-Umbrella.hpp +46 -0
- package/nitrogen/generated/ios/ReactNativeJpushAutolinking.mm +33 -0
- package/nitrogen/generated/ios/ReactNativeJpushAutolinking.swift +26 -0
- package/nitrogen/generated/ios/c++/HybridReactNativeJpushSpecSwift.cpp +11 -0
- package/nitrogen/generated/ios/c++/HybridReactNativeJpushSpecSwift.hpp +402 -0
- package/nitrogen/generated/ios/swift/Func_void_bool.swift +46 -0
- package/nitrogen/generated/ios/swift/Func_void_std__string_std__string.swift +46 -0
- package/nitrogen/generated/ios/swift/HybridReactNativeJpushSpec.swift +107 -0
- package/nitrogen/generated/ios/swift/HybridReactNativeJpushSpec_cxx.swift +723 -0
- package/nitrogen/generated/shared/c++/HybridReactNativeJpushSpec.cpp +73 -0
- package/nitrogen/generated/shared/c++/HybridReactNativeJpushSpec.hpp +116 -0
- package/package.json +174 -4
- package/src/ReactNativeJpush.nitro.ts +93 -0
- package/src/index.tsx +1090 -0
|
@@ -0,0 +1,1453 @@
|
|
|
1
|
+
#import "JCOREWireProtocol.h"
|
|
2
|
+
#import "JCOREConfiguration.h"
|
|
3
|
+
#import "JCORECrypto.h"
|
|
4
|
+
#if __has_include(<UIKit/UIKit.h>)
|
|
5
|
+
#import <UIKit/UIKit.h>
|
|
6
|
+
#endif
|
|
7
|
+
|
|
8
|
+
static NSString *const kJCOREReportRsaPublicKey =
|
|
9
|
+
@"MIGfMA0GCSqGSIb3DQEBAQUAA4GNADCBiQKBgQCGHnOJjf1yD7SOWt0w4q5ZqER+VMOTJ9oPh+"
|
|
10
|
+
@"9TNgW8WpXwCklSLxFDM46eHWzT2TV46gZ0A6xTNVHKX4zAW621jfb6qzljTvwzM5Cxa5n2440kU8HF/"
|
|
11
|
+
@"EDu04yqUpWCsNXs+jQD4R2gjGE203LW87fBivmfq0mxPvIR94UdKf10YQIDAQAB";
|
|
12
|
+
|
|
13
|
+
static void JCoreAppendUInt8(NSMutableData *data, uint8_t value) {
|
|
14
|
+
[data appendBytes:&value length:sizeof(uint8_t)];
|
|
15
|
+
}
|
|
16
|
+
|
|
17
|
+
static void JCoreAppendUInt16(NSMutableData *data, uint16_t value) {
|
|
18
|
+
uint16_t be = CFSwapInt16HostToBig(value);
|
|
19
|
+
[data appendBytes:&be length:sizeof(uint16_t)];
|
|
20
|
+
}
|
|
21
|
+
|
|
22
|
+
static void JCoreAppendUInt32(NSMutableData *data, uint32_t value) {
|
|
23
|
+
uint32_t be = CFSwapInt32HostToBig(value);
|
|
24
|
+
[data appendBytes:&be length:sizeof(uint32_t)];
|
|
25
|
+
}
|
|
26
|
+
|
|
27
|
+
static void JCoreAppendUInt64(NSMutableData *data, uint64_t value) {
|
|
28
|
+
uint64_t be = CFSwapInt64HostToBig(value);
|
|
29
|
+
[data appendBytes:&be length:sizeof(uint64_t)];
|
|
30
|
+
}
|
|
31
|
+
|
|
32
|
+
static void JCoreAppendString(NSMutableData *data, NSString *string) {
|
|
33
|
+
NSData *utf8 = [string ?: @"" dataUsingEncoding:NSUTF8StringEncoding];
|
|
34
|
+
uint16_t len = (uint16_t)MIN((NSUInteger)UINT16_MAX, utf8.length);
|
|
35
|
+
JCoreAppendUInt16(data, len);
|
|
36
|
+
if (len > 0) {
|
|
37
|
+
[data appendBytes:utf8.bytes length:len];
|
|
38
|
+
}
|
|
39
|
+
}
|
|
40
|
+
|
|
41
|
+
static BOOL JCoreReadUInt8(NSData *data, NSUInteger *offset, uint8_t *outValue) {
|
|
42
|
+
if (*offset + 1 > data.length) {
|
|
43
|
+
return NO;
|
|
44
|
+
}
|
|
45
|
+
[data getBytes:outValue range:NSMakeRange(*offset, 1)];
|
|
46
|
+
*offset += 1;
|
|
47
|
+
return YES;
|
|
48
|
+
}
|
|
49
|
+
|
|
50
|
+
static BOOL JCoreReadUInt16(NSData *data, NSUInteger *offset, uint16_t *outValue) {
|
|
51
|
+
if (*offset + 2 > data.length) {
|
|
52
|
+
return NO;
|
|
53
|
+
}
|
|
54
|
+
uint16_t raw = 0;
|
|
55
|
+
[data getBytes:&raw range:NSMakeRange(*offset, 2)];
|
|
56
|
+
*outValue = CFSwapInt16BigToHost(raw);
|
|
57
|
+
*offset += 2;
|
|
58
|
+
return YES;
|
|
59
|
+
}
|
|
60
|
+
|
|
61
|
+
static BOOL JCoreReadUInt32(NSData *data, NSUInteger *offset, uint32_t *outValue) {
|
|
62
|
+
if (*offset + 4 > data.length) {
|
|
63
|
+
return NO;
|
|
64
|
+
}
|
|
65
|
+
uint32_t raw = 0;
|
|
66
|
+
[data getBytes:&raw range:NSMakeRange(*offset, 4)];
|
|
67
|
+
*outValue = CFSwapInt32BigToHost(raw);
|
|
68
|
+
*offset += 4;
|
|
69
|
+
return YES;
|
|
70
|
+
}
|
|
71
|
+
|
|
72
|
+
static BOOL JCoreReadUInt64(NSData *data, NSUInteger *offset, uint64_t *outValue) {
|
|
73
|
+
if (*offset + 8 > data.length) {
|
|
74
|
+
return NO;
|
|
75
|
+
}
|
|
76
|
+
uint64_t raw = 0;
|
|
77
|
+
[data getBytes:&raw range:NSMakeRange(*offset, 8)];
|
|
78
|
+
*outValue = CFSwapInt64BigToHost(raw);
|
|
79
|
+
*offset += 8;
|
|
80
|
+
return YES;
|
|
81
|
+
}
|
|
82
|
+
|
|
83
|
+
static NSString *JCoreReadString(NSData *data, NSUInteger *offset) {
|
|
84
|
+
uint16_t len = 0;
|
|
85
|
+
if (!JCoreReadUInt16(data, offset, &len)) {
|
|
86
|
+
return nil;
|
|
87
|
+
}
|
|
88
|
+
if (*offset + len > data.length) {
|
|
89
|
+
return nil;
|
|
90
|
+
}
|
|
91
|
+
NSData *slice = [data subdataWithRange:NSMakeRange(*offset, len)];
|
|
92
|
+
*offset += len;
|
|
93
|
+
return [[NSString alloc] initWithData:slice encoding:NSUTF8StringEncoding] ?: @"";
|
|
94
|
+
}
|
|
95
|
+
|
|
96
|
+
@implementation JCOREWireFrame
|
|
97
|
+
@end
|
|
98
|
+
|
|
99
|
+
@implementation JCORERegisterResponse
|
|
100
|
+
@end
|
|
101
|
+
|
|
102
|
+
@implementation JCORELoginResponse
|
|
103
|
+
@end
|
|
104
|
+
|
|
105
|
+
@implementation JCOREPushEnvelope
|
|
106
|
+
@end
|
|
107
|
+
|
|
108
|
+
@implementation JCORECtrlEnvelope
|
|
109
|
+
@end
|
|
110
|
+
|
|
111
|
+
@implementation JCORELiveActivityResponse
|
|
112
|
+
@end
|
|
113
|
+
|
|
114
|
+
@implementation JCOREWireProtocol
|
|
115
|
+
|
|
116
|
+
#pragma mark - Body Encryption & Decryption
|
|
117
|
+
|
|
118
|
+
+ (nullable NSData *)encryptBodyData:(NSData *)plainData
|
|
119
|
+
withSeed:(uint64_t)seed
|
|
120
|
+
algorithm:(uint8_t)algorithm {
|
|
121
|
+
NSData *input = plainData ?: [NSData data];
|
|
122
|
+
NSString *key = [JCORECrypto generateSeedKey:seed];
|
|
123
|
+
NSString *ivStr = [key substringToIndex:MIN((NSUInteger)16, key.length)];
|
|
124
|
+
if (algorithm == 2) {
|
|
125
|
+
return [JCORECrypto sm4CBCEncryptData:input withKey:key iv:ivStr.UTF8String];
|
|
126
|
+
}
|
|
127
|
+
return [JCORECrypto aesCbcEncrypt:input key:key iv:ivStr.UTF8String keySize:32];
|
|
128
|
+
}
|
|
129
|
+
|
|
130
|
+
+ (nullable NSData *)decryptBodyData:(NSData *)cipherData
|
|
131
|
+
withSeed:(uint64_t)seed
|
|
132
|
+
algorithm:(uint8_t)algorithm {
|
|
133
|
+
if (cipherData.length == 0) {
|
|
134
|
+
return [NSData data];
|
|
135
|
+
}
|
|
136
|
+
NSString *key = [JCORECrypto generateSeedKey:seed];
|
|
137
|
+
NSString *ivStr = [key substringToIndex:MIN((NSUInteger)16, key.length)];
|
|
138
|
+
if (algorithm == 2) {
|
|
139
|
+
return [JCORECrypto sm4CBCDecryptData:cipherData withKey:key iv:ivStr.UTF8String];
|
|
140
|
+
}
|
|
141
|
+
return [JCORECrypto aesCbcDecrypt:cipherData key:key iv:ivStr.UTF8String keySize:32];
|
|
142
|
+
}
|
|
143
|
+
|
|
144
|
+
#pragma mark - Outbound Client -> Server Framing (24-byte header)
|
|
145
|
+
|
|
146
|
+
+ (NSData *)encodeClientFrameWithCommand:(uint8_t)command
|
|
147
|
+
version:(uint8_t)version
|
|
148
|
+
requestId:(uint16_t)requestId
|
|
149
|
+
sessionId:(uint32_t)sessionId
|
|
150
|
+
uid:(uint64_t)uid
|
|
151
|
+
algorithm:(uint8_t)algorithm
|
|
152
|
+
bodyData:(NSData *)bodyData {
|
|
153
|
+
uint8_t effectiveAlg = (algorithm == 2) ? 2 : 1;
|
|
154
|
+
uint32_t seedOrSid = sessionId;
|
|
155
|
+
uint64_t packetUid = uid;
|
|
156
|
+
|
|
157
|
+
if (command == JCOREWireCommandRegister) {
|
|
158
|
+
packetUid = 0;
|
|
159
|
+
if (seedOrSid == 0) {
|
|
160
|
+
uint64_t savedSeed = [JCOREConfiguration shared].lastRegisterSeed;
|
|
161
|
+
if (savedSeed > 0 && savedSeed <= UINT32_MAX) {
|
|
162
|
+
seedOrSid = (uint32_t)savedSeed;
|
|
163
|
+
} else {
|
|
164
|
+
seedOrSid = (arc4random() % 10000000U) + 1U;
|
|
165
|
+
[JCOREConfiguration shared].lastRegisterSeed = seedOrSid;
|
|
166
|
+
}
|
|
167
|
+
} else {
|
|
168
|
+
[JCOREConfiguration shared].lastRegisterSeed = seedOrSid;
|
|
169
|
+
}
|
|
170
|
+
}
|
|
171
|
+
|
|
172
|
+
uint64_t encryptionSeed = (command == JCOREWireCommandRegister || packetUid == 0)
|
|
173
|
+
? (uint64_t)seedOrSid
|
|
174
|
+
: packetUid;
|
|
175
|
+
|
|
176
|
+
NSData *encryptedBody = [self encryptBodyData:(bodyData ?: [NSData data])
|
|
177
|
+
withSeed:encryptionSeed
|
|
178
|
+
algorithm:effectiveAlg];
|
|
179
|
+
if (encryptedBody == nil) {
|
|
180
|
+
return nil;
|
|
181
|
+
}
|
|
182
|
+
|
|
183
|
+
uint16_t totalLength = (uint16_t)(24 + encryptedBody.length);
|
|
184
|
+
NSMutableData *packet = [NSMutableData dataWithCapacity:totalLength];
|
|
185
|
+
JCoreAppendUInt16(packet, (uint16_t)(totalLength | 0x8000));
|
|
186
|
+
JCoreAppendUInt8(packet, version);
|
|
187
|
+
JCoreAppendUInt8(packet, command);
|
|
188
|
+
JCoreAppendUInt8(packet, effectiveAlg);
|
|
189
|
+
JCoreAppendUInt8(packet, 0); // flag
|
|
190
|
+
JCoreAppendUInt32(packet, 0); // reserved
|
|
191
|
+
JCoreAppendUInt16(packet, requestId);
|
|
192
|
+
JCoreAppendUInt32(packet, seedOrSid);
|
|
193
|
+
JCoreAppendUInt64(packet, packetUid);
|
|
194
|
+
if (encryptedBody.length > 0) {
|
|
195
|
+
[packet appendData:encryptedBody];
|
|
196
|
+
}
|
|
197
|
+
return packet;
|
|
198
|
+
}
|
|
199
|
+
|
|
200
|
+
+ (NSData *)encodeFrameWithCommand:(uint8_t)command
|
|
201
|
+
version:(uint8_t)version
|
|
202
|
+
requestId:(uint16_t)requestId
|
|
203
|
+
sessionId:(uint32_t)sessionId
|
|
204
|
+
uid:(uint64_t)uid
|
|
205
|
+
bodyData:(NSData *)bodyData {
|
|
206
|
+
uint8_t alg = [JCOREConfiguration shared].encryptionAlgorithm;
|
|
207
|
+
if (alg != 1 && alg != 2) {
|
|
208
|
+
alg = 1;
|
|
209
|
+
}
|
|
210
|
+
return [self encodeClientFrameWithCommand:command
|
|
211
|
+
version:version
|
|
212
|
+
requestId:requestId
|
|
213
|
+
sessionId:sessionId
|
|
214
|
+
uid:uid
|
|
215
|
+
algorithm:alg
|
|
216
|
+
bodyData:bodyData];
|
|
217
|
+
}
|
|
218
|
+
|
|
219
|
+
#pragma mark - Inbound Server -> Client Framing (20-byte header)
|
|
220
|
+
|
|
221
|
+
+ (NSData *)encodeServerFrameWithCommand:(uint8_t)command
|
|
222
|
+
version:(uint8_t)version
|
|
223
|
+
requestId:(uint16_t)requestId
|
|
224
|
+
uid:(uint64_t)uid
|
|
225
|
+
algorithm:(uint8_t)algorithm
|
|
226
|
+
statusCode:(uint16_t)statusCode
|
|
227
|
+
bodyData:(NSData *)bodyData {
|
|
228
|
+
uint8_t effectiveAlg = (algorithm == 2) ? 2 : 1;
|
|
229
|
+
NSMutableData *plainBody = [NSMutableData data];
|
|
230
|
+
|
|
231
|
+
BOOL isServerPushOrCtrl = (command == JCOREWireCommandPushMessage ||
|
|
232
|
+
command == JCOREWireCommandCtrlCommand);
|
|
233
|
+
BOOL isTagOrAlias = (command == JCOREWireCommandTagOperation ||
|
|
234
|
+
command == JCOREWireCommandAliasOperation);
|
|
235
|
+
|
|
236
|
+
if (isServerPushOrCtrl) {
|
|
237
|
+
if (bodyData.length > 0) {
|
|
238
|
+
[plainBody appendData:bodyData];
|
|
239
|
+
}
|
|
240
|
+
} else if (isTagOrAlias) {
|
|
241
|
+
if (bodyData.length > 0) {
|
|
242
|
+
[plainBody appendData:bodyData];
|
|
243
|
+
} else {
|
|
244
|
+
JCoreAppendUInt16(plainBody, statusCode);
|
|
245
|
+
}
|
|
246
|
+
} else {
|
|
247
|
+
if (bodyData.length == 0) {
|
|
248
|
+
JCoreAppendUInt16(plainBody, statusCode);
|
|
249
|
+
} else {
|
|
250
|
+
[plainBody appendData:bodyData];
|
|
251
|
+
if (statusCode != 0 && plainBody.length >= 2) {
|
|
252
|
+
uint16_t existingStatus = 0;
|
|
253
|
+
NSUInteger zeroOffset = 0;
|
|
254
|
+
JCoreReadUInt16(plainBody, &zeroOffset, &existingStatus);
|
|
255
|
+
if (existingStatus == 0) {
|
|
256
|
+
uint16_t beStatus = CFSwapInt16HostToBig(statusCode);
|
|
257
|
+
[plainBody replaceBytesInRange:NSMakeRange(0, 2) withBytes:&beStatus length:2];
|
|
258
|
+
}
|
|
259
|
+
}
|
|
260
|
+
}
|
|
261
|
+
}
|
|
262
|
+
|
|
263
|
+
uint64_t encryptionSeed = uid;
|
|
264
|
+
if (command == JCOREWireCommandRegister) {
|
|
265
|
+
uint64_t regSeed = [JCOREConfiguration shared].lastRegisterSeed;
|
|
266
|
+
encryptionSeed = (regSeed != 0) ? regSeed : uid;
|
|
267
|
+
} else if (encryptionSeed == 0) {
|
|
268
|
+
encryptionSeed = [JCOREConfiguration shared].lastRegisterSeed;
|
|
269
|
+
}
|
|
270
|
+
|
|
271
|
+
NSData *encryptedBody = [self encryptBodyData:plainBody
|
|
272
|
+
withSeed:encryptionSeed
|
|
273
|
+
algorithm:effectiveAlg];
|
|
274
|
+
if (encryptedBody == nil) {
|
|
275
|
+
return nil;
|
|
276
|
+
}
|
|
277
|
+
|
|
278
|
+
uint16_t totalLength = (uint16_t)(20 + encryptedBody.length);
|
|
279
|
+
NSMutableData *packet = [NSMutableData dataWithCapacity:totalLength];
|
|
280
|
+
JCoreAppendUInt16(packet, (uint16_t)(totalLength | 0x8000));
|
|
281
|
+
JCoreAppendUInt8(packet, version);
|
|
282
|
+
JCoreAppendUInt8(packet, command);
|
|
283
|
+
JCoreAppendUInt8(packet, effectiveAlg);
|
|
284
|
+
JCoreAppendUInt8(packet, 0); // flag
|
|
285
|
+
JCoreAppendUInt32(packet, 0); // reserved
|
|
286
|
+
JCoreAppendUInt16(packet, requestId);
|
|
287
|
+
JCoreAppendUInt64(packet, uid);
|
|
288
|
+
if (encryptedBody.length > 0) {
|
|
289
|
+
[packet appendData:encryptedBody];
|
|
290
|
+
}
|
|
291
|
+
return packet;
|
|
292
|
+
}
|
|
293
|
+
|
|
294
|
+
+ (NSData *)encodeFrameWithCommand:(uint8_t)command
|
|
295
|
+
version:(uint8_t)version
|
|
296
|
+
requestId:(uint16_t)requestId
|
|
297
|
+
sessionId:(uint32_t)sessionId
|
|
298
|
+
uid:(uint64_t)uid
|
|
299
|
+
statusCode:(uint16_t)statusCode
|
|
300
|
+
bodyData:(NSData *)bodyData {
|
|
301
|
+
(void)sessionId;
|
|
302
|
+
uint8_t alg = [JCOREConfiguration shared].encryptionAlgorithm;
|
|
303
|
+
if (alg != 1 && alg != 2) {
|
|
304
|
+
alg = 1;
|
|
305
|
+
}
|
|
306
|
+
return [self encodeServerFrameWithCommand:command
|
|
307
|
+
version:version
|
|
308
|
+
requestId:requestId
|
|
309
|
+
uid:uid
|
|
310
|
+
algorithm:alg
|
|
311
|
+
statusCode:statusCode
|
|
312
|
+
bodyData:bodyData];
|
|
313
|
+
}
|
|
314
|
+
|
|
315
|
+
#pragma mark - Stream Decoders
|
|
316
|
+
|
|
317
|
+
+ (nullable JCOREWireFrame *)decodeClientSingleFrame:(NSData *)frameBytes {
|
|
318
|
+
if (frameBytes.length < 24) {
|
|
319
|
+
return nil;
|
|
320
|
+
}
|
|
321
|
+
NSUInteger cursor = 2;
|
|
322
|
+
uint8_t version = 0;
|
|
323
|
+
uint8_t command = 0;
|
|
324
|
+
uint8_t algorithm = 1;
|
|
325
|
+
uint8_t flag = 0;
|
|
326
|
+
uint32_t reserved = 0;
|
|
327
|
+
uint16_t requestId = 0;
|
|
328
|
+
uint32_t seedOrSid = 0;
|
|
329
|
+
uint64_t packetUid = 0;
|
|
330
|
+
|
|
331
|
+
if (!JCoreReadUInt8(frameBytes, &cursor, &version) ||
|
|
332
|
+
!JCoreReadUInt8(frameBytes, &cursor, &command) ||
|
|
333
|
+
!JCoreReadUInt8(frameBytes, &cursor, &algorithm) ||
|
|
334
|
+
!JCoreReadUInt8(frameBytes, &cursor, &flag) ||
|
|
335
|
+
!JCoreReadUInt32(frameBytes, &cursor, &reserved) ||
|
|
336
|
+
!JCoreReadUInt16(frameBytes, &cursor, &requestId) ||
|
|
337
|
+
!JCoreReadUInt32(frameBytes, &cursor, &seedOrSid) ||
|
|
338
|
+
!JCoreReadUInt64(frameBytes, &cursor, &packetUid)) {
|
|
339
|
+
return nil;
|
|
340
|
+
}
|
|
341
|
+
|
|
342
|
+
if (command == JCOREWireCommandRegister && seedOrSid != 0) {
|
|
343
|
+
[JCOREConfiguration shared].lastRegisterSeed = seedOrSid;
|
|
344
|
+
}
|
|
345
|
+
|
|
346
|
+
NSData *rawBody = frameBytes.length > 24
|
|
347
|
+
? [frameBytes subdataWithRange:NSMakeRange(24, frameBytes.length - 24)]
|
|
348
|
+
: [NSData data];
|
|
349
|
+
|
|
350
|
+
uint64_t seed = (command == JCOREWireCommandRegister || packetUid == 0)
|
|
351
|
+
? (uint64_t)seedOrSid
|
|
352
|
+
: packetUid;
|
|
353
|
+
|
|
354
|
+
NSData *decodedBody = [self decryptBodyData:rawBody withSeed:seed algorithm:algorithm];
|
|
355
|
+
if (decodedBody == nil) {
|
|
356
|
+
return nil;
|
|
357
|
+
}
|
|
358
|
+
|
|
359
|
+
JCOREWireFrame *frame = [[JCOREWireFrame alloc] init];
|
|
360
|
+
frame.version = version;
|
|
361
|
+
frame.command = command;
|
|
362
|
+
frame.algorithm = algorithm;
|
|
363
|
+
frame.flags = flag;
|
|
364
|
+
frame.requestId = requestId;
|
|
365
|
+
frame.sessionId = seedOrSid;
|
|
366
|
+
frame.uid = packetUid;
|
|
367
|
+
frame.statusCode = 0;
|
|
368
|
+
frame.bodyData = decodedBody;
|
|
369
|
+
return frame;
|
|
370
|
+
}
|
|
371
|
+
|
|
372
|
+
+ (nullable JCOREWireFrame *)decodeServerSingleFrame:(NSData *)frameBytes
|
|
373
|
+
defaultUid:(uint64_t)defaultUid {
|
|
374
|
+
if (frameBytes.length < 20) {
|
|
375
|
+
return nil;
|
|
376
|
+
}
|
|
377
|
+
NSUInteger cursor = 2;
|
|
378
|
+
uint8_t version = 0;
|
|
379
|
+
uint8_t command = 0;
|
|
380
|
+
uint8_t algorithm = 1;
|
|
381
|
+
uint8_t flag = 0;
|
|
382
|
+
uint32_t reserved = 0;
|
|
383
|
+
uint16_t requestId = 0;
|
|
384
|
+
uint64_t packetUid = 0;
|
|
385
|
+
|
|
386
|
+
if (!JCoreReadUInt8(frameBytes, &cursor, &version) ||
|
|
387
|
+
!JCoreReadUInt8(frameBytes, &cursor, &command) ||
|
|
388
|
+
!JCoreReadUInt8(frameBytes, &cursor, &algorithm) ||
|
|
389
|
+
!JCoreReadUInt8(frameBytes, &cursor, &flag) ||
|
|
390
|
+
!JCoreReadUInt32(frameBytes, &cursor, &reserved) ||
|
|
391
|
+
!JCoreReadUInt16(frameBytes, &cursor, &requestId) ||
|
|
392
|
+
!JCoreReadUInt64(frameBytes, &cursor, &packetUid)) {
|
|
393
|
+
return nil;
|
|
394
|
+
}
|
|
395
|
+
|
|
396
|
+
NSData *rawBody = frameBytes.length > 20
|
|
397
|
+
? [frameBytes subdataWithRange:NSMakeRange(20, frameBytes.length - 20)]
|
|
398
|
+
: [NSData data];
|
|
399
|
+
|
|
400
|
+
uint64_t lastRegSeed = [JCOREConfiguration shared].lastRegisterSeed;
|
|
401
|
+
uint64_t primarySeed = 0;
|
|
402
|
+
if (command == JCOREWireCommandRegister) {
|
|
403
|
+
primarySeed = (lastRegSeed != 0) ? lastRegSeed : (packetUid != 0 ? packetUid : defaultUid);
|
|
404
|
+
} else {
|
|
405
|
+
primarySeed = (packetUid != 0) ? packetUid : (defaultUid != 0 ? defaultUid : lastRegSeed);
|
|
406
|
+
}
|
|
407
|
+
|
|
408
|
+
NSData *decodedBody = [self decryptBodyData:rawBody withSeed:primarySeed algorithm:algorithm];
|
|
409
|
+
if (decodedBody == nil && packetUid != 0 && packetUid != primarySeed) {
|
|
410
|
+
decodedBody = [self decryptBodyData:rawBody withSeed:packetUid algorithm:algorithm];
|
|
411
|
+
}
|
|
412
|
+
if (decodedBody == nil && defaultUid != 0 && defaultUid != primarySeed && defaultUid != packetUid) {
|
|
413
|
+
decodedBody = [self decryptBodyData:rawBody withSeed:defaultUid algorithm:algorithm];
|
|
414
|
+
}
|
|
415
|
+
if (decodedBody == nil && lastRegSeed != 0 && lastRegSeed != primarySeed) {
|
|
416
|
+
decodedBody = [self decryptBodyData:rawBody withSeed:lastRegSeed algorithm:algorithm];
|
|
417
|
+
}
|
|
418
|
+
if (decodedBody == nil) {
|
|
419
|
+
return nil;
|
|
420
|
+
}
|
|
421
|
+
|
|
422
|
+
if ((flag & 0x01) != 0 && decodedBody.length >= 2) {
|
|
423
|
+
const uint8_t *b = decodedBody.bytes;
|
|
424
|
+
if (b[0] == 0x1f && b[1] == 0x8b) {
|
|
425
|
+
NSData *unzipped = [JCORECrypto gzipDecompress:decodedBody];
|
|
426
|
+
if (unzipped != nil) {
|
|
427
|
+
decodedBody = unzipped;
|
|
428
|
+
}
|
|
429
|
+
}
|
|
430
|
+
}
|
|
431
|
+
|
|
432
|
+
uint16_t statusCode = 0;
|
|
433
|
+
if (command != JCOREWireCommandPushMessage && command != JCOREWireCommandCtrlCommand) {
|
|
434
|
+
if (command == JCOREWireCommandTagOperation || command == JCOREWireCommandAliasOperation) {
|
|
435
|
+
if (decodedBody.length == 2) {
|
|
436
|
+
NSUInteger scOffset = 0;
|
|
437
|
+
JCoreReadUInt16(decodedBody, &scOffset, &statusCode);
|
|
438
|
+
}
|
|
439
|
+
} else if (decodedBody.length >= 2) {
|
|
440
|
+
NSUInteger scOffset = 0;
|
|
441
|
+
JCoreReadUInt16(decodedBody, &scOffset, &statusCode);
|
|
442
|
+
}
|
|
443
|
+
}
|
|
444
|
+
|
|
445
|
+
JCOREWireFrame *frame = [[JCOREWireFrame alloc] init];
|
|
446
|
+
frame.version = version;
|
|
447
|
+
frame.command = command;
|
|
448
|
+
frame.algorithm = algorithm;
|
|
449
|
+
frame.flags = flag;
|
|
450
|
+
frame.requestId = requestId;
|
|
451
|
+
frame.sessionId = 0;
|
|
452
|
+
frame.uid = packetUid;
|
|
453
|
+
frame.statusCode = statusCode;
|
|
454
|
+
frame.bodyData = decodedBody;
|
|
455
|
+
return frame;
|
|
456
|
+
}
|
|
457
|
+
|
|
458
|
+
+ (NSArray<JCOREWireFrame *> *)decodeServerFramesFromStreamBuffer:(NSMutableData *)streamBuffer
|
|
459
|
+
defaultUid:(uint64_t)defaultUid {
|
|
460
|
+
NSMutableArray<JCOREWireFrame *> *frames = [NSMutableArray array];
|
|
461
|
+
while (streamBuffer.length >= 20) {
|
|
462
|
+
const uint8_t *bytes = streamBuffer.bytes;
|
|
463
|
+
uint16_t rawLen = ((uint16_t)bytes[0] << 8) | bytes[1];
|
|
464
|
+
uint16_t frameLen = rawLen & 0x7FFF;
|
|
465
|
+
if (frameLen < 20 || frameLen > 65535) {
|
|
466
|
+
[streamBuffer setLength:0];
|
|
467
|
+
break;
|
|
468
|
+
}
|
|
469
|
+
if (streamBuffer.length < frameLen) {
|
|
470
|
+
break;
|
|
471
|
+
}
|
|
472
|
+
NSData *frameBytes = [streamBuffer subdataWithRange:NSMakeRange(0, frameLen)];
|
|
473
|
+
[streamBuffer replaceBytesInRange:NSMakeRange(0, frameLen) withBytes:NULL length:0];
|
|
474
|
+
|
|
475
|
+
JCOREWireFrame *frame = [self decodeServerSingleFrame:frameBytes defaultUid:defaultUid];
|
|
476
|
+
if (frame != nil) {
|
|
477
|
+
[frames addObject:frame];
|
|
478
|
+
}
|
|
479
|
+
}
|
|
480
|
+
return frames;
|
|
481
|
+
}
|
|
482
|
+
|
|
483
|
+
+ (NSArray<JCOREWireFrame *> *)decodeClientFramesFromStreamBuffer:(NSMutableData *)streamBuffer {
|
|
484
|
+
NSMutableArray<JCOREWireFrame *> *frames = [NSMutableArray array];
|
|
485
|
+
while (streamBuffer.length >= 24) {
|
|
486
|
+
const uint8_t *bytes = streamBuffer.bytes;
|
|
487
|
+
uint16_t rawLen = ((uint16_t)bytes[0] << 8) | bytes[1];
|
|
488
|
+
uint16_t frameLen = rawLen & 0x7FFF;
|
|
489
|
+
if (frameLen < 24 || frameLen > 65535) {
|
|
490
|
+
[streamBuffer setLength:0];
|
|
491
|
+
break;
|
|
492
|
+
}
|
|
493
|
+
if (streamBuffer.length < frameLen) {
|
|
494
|
+
break;
|
|
495
|
+
}
|
|
496
|
+
NSData *frameBytes = [streamBuffer subdataWithRange:NSMakeRange(0, frameLen)];
|
|
497
|
+
[streamBuffer replaceBytesInRange:NSMakeRange(0, frameLen) withBytes:NULL length:0];
|
|
498
|
+
|
|
499
|
+
JCOREWireFrame *frame = [self decodeClientSingleFrame:frameBytes];
|
|
500
|
+
if (frame != nil) {
|
|
501
|
+
[frames addObject:frame];
|
|
502
|
+
}
|
|
503
|
+
}
|
|
504
|
+
return frames;
|
|
505
|
+
}
|
|
506
|
+
|
|
507
|
+
+ (NSArray<JCOREWireFrame *> *)decodeFramesFromStreamBuffer:(NSMutableData *)streamBuffer
|
|
508
|
+
uid:(uint64_t)uid {
|
|
509
|
+
NSMutableArray<JCOREWireFrame *> *frames = [NSMutableArray array];
|
|
510
|
+
while (streamBuffer.length >= 20) {
|
|
511
|
+
const uint8_t *bytes = streamBuffer.bytes;
|
|
512
|
+
uint16_t rawLen = ((uint16_t)bytes[0] << 8) | bytes[1];
|
|
513
|
+
uint16_t frameLen = rawLen & 0x7FFF;
|
|
514
|
+
if (frameLen < 20 || frameLen > 65535) {
|
|
515
|
+
[streamBuffer setLength:0];
|
|
516
|
+
break;
|
|
517
|
+
}
|
|
518
|
+
if (streamBuffer.length < frameLen) {
|
|
519
|
+
break;
|
|
520
|
+
}
|
|
521
|
+
NSData *frameBytes = [streamBuffer subdataWithRange:NSMakeRange(0, frameLen)];
|
|
522
|
+
[streamBuffer replaceBytesInRange:NSMakeRange(0, frameLen) withBytes:NULL length:0];
|
|
523
|
+
|
|
524
|
+
JCOREWireFrame *frame = nil;
|
|
525
|
+
if (frameLen >= 24 && ((frameLen - 24) % 16 == 0)) {
|
|
526
|
+
frame = [self decodeClientSingleFrame:frameBytes];
|
|
527
|
+
} else {
|
|
528
|
+
frame = [self decodeServerSingleFrame:frameBytes defaultUid:uid];
|
|
529
|
+
}
|
|
530
|
+
if (frame != nil) {
|
|
531
|
+
[frames addObject:frame];
|
|
532
|
+
}
|
|
533
|
+
}
|
|
534
|
+
return frames;
|
|
535
|
+
}
|
|
536
|
+
|
|
537
|
+
#pragma mark - Register (cmd = 0, ver = 30)
|
|
538
|
+
|
|
539
|
+
+ (NSData *)buildRegisterPayloadWithAppKey:(NSString *)appKey
|
|
540
|
+
channel:(NSString *)channel
|
|
541
|
+
bundleIdHash:(NSString *)bundleId {
|
|
542
|
+
JCOREConfiguration *config = [JCOREConfiguration shared];
|
|
543
|
+
NSString *systemVersion = [config osVersionString];
|
|
544
|
+
NSString *modelName = [config modelNameString];
|
|
545
|
+
NSString *appVersion = [config appVersionString];
|
|
546
|
+
NSString *effectiveBundleId = bundleId.length > 0 ? bundleId : [config bundleIdentifierString];
|
|
547
|
+
NSString *deviceId = config.deviceID;
|
|
548
|
+
NSString *fakeImei = [config fakeIMEI];
|
|
549
|
+
|
|
550
|
+
NSString *keyString = [NSString stringWithFormat:@"%@$$ $$%@$$%@",
|
|
551
|
+
fakeImei ?: @"",
|
|
552
|
+
effectiveBundleId ?: @"",
|
|
553
|
+
appKey ?: @""];
|
|
554
|
+
NSString *clientString = [NSString stringWithFormat:@"%@$$%@$$ $$ $$%@$$6.0.0|||5.2.0||||$$ $$ $$ $$ $$1",
|
|
555
|
+
systemVersion ?: @"",
|
|
556
|
+
modelName ?: @"",
|
|
557
|
+
channel.length > 0 ? channel : @"App Store"];
|
|
558
|
+
NSString *deviceToken = config.deviceTokenHex ?: @"";
|
|
559
|
+
NSString *voipToken = config.voipTokenHex ?: @"";
|
|
560
|
+
NSString *tokenString = (deviceToken.length == 0 && voipToken.length == 0)
|
|
561
|
+
? @" "
|
|
562
|
+
: [NSString stringWithFormat:@"%@$$%@", deviceToken, voipToken];
|
|
563
|
+
NSString *advertisingString = config.advertisingIdentifier.length > 0
|
|
564
|
+
? config.advertisingIdentifier
|
|
565
|
+
: @" ";
|
|
566
|
+
NSString *deviceString = [NSString stringWithFormat:@"1$$%@", deviceId ?: @""];
|
|
567
|
+
|
|
568
|
+
NSMutableData *body = [NSMutableData data];
|
|
569
|
+
JCoreAppendString(body, keyString); // 1. key
|
|
570
|
+
JCoreAppendString(body, appVersion ?: @""); // 2. appVersion
|
|
571
|
+
JCoreAppendString(body, clientString); // 3. client
|
|
572
|
+
JCoreAppendString(body, tokenString); // 4. token
|
|
573
|
+
JCoreAppendString(body, advertisingString); // 5. advertising
|
|
574
|
+
JCoreAppendUInt8(body, config.buildType); // 6. buildType (0=debug, 1=release)
|
|
575
|
+
JCoreAppendUInt8(body, config.apsType); // 7. apsType (0=dev, 1=prod)
|
|
576
|
+
JCoreAppendUInt8(body, 1); // 8. platform (1=iOS)
|
|
577
|
+
JCoreAppendString(body, deviceString); // 9. device ("1$${deviceID}")
|
|
578
|
+
JCoreAppendUInt32(body, 1); // 10. integrateBusiness (1=push)
|
|
579
|
+
JCoreAppendString(body, @""); // 11. account
|
|
580
|
+
return body;
|
|
581
|
+
}
|
|
582
|
+
|
|
583
|
+
+ (NSData *)buildRegisterResponsePayloadWithStatusCode:(uint16_t)statusCode
|
|
584
|
+
uid:(uint64_t)uid
|
|
585
|
+
password:(NSString *)password
|
|
586
|
+
registrationID:(NSString *)registrationID
|
|
587
|
+
deviceID:(NSString *)deviceID {
|
|
588
|
+
NSMutableData *body = [NSMutableData data];
|
|
589
|
+
JCoreAppendUInt16(body, statusCode);
|
|
590
|
+
if (statusCode == 0) {
|
|
591
|
+
JCoreAppendUInt64(body, uid);
|
|
592
|
+
JCoreAppendString(body, password ?: @"");
|
|
593
|
+
JCoreAppendString(body, registrationID ?: @"");
|
|
594
|
+
JCoreAppendString(body, deviceID ?: @"");
|
|
595
|
+
}
|
|
596
|
+
return body;
|
|
597
|
+
}
|
|
598
|
+
|
|
599
|
+
+ (NSData *)buildRegisterResponsePayloadWithUid:(uint64_t)uid
|
|
600
|
+
password:(NSString *)password
|
|
601
|
+
registrationID:(NSString *)registrationID {
|
|
602
|
+
return [self buildRegisterResponsePayloadWithStatusCode:0
|
|
603
|
+
uid:uid
|
|
604
|
+
password:password
|
|
605
|
+
registrationID:registrationID
|
|
606
|
+
deviceID:[JCOREConfiguration shared].deviceID];
|
|
607
|
+
}
|
|
608
|
+
|
|
609
|
+
+ (JCORERegisterResponse *)parseRegisterResponse:(JCOREWireFrame *)frame {
|
|
610
|
+
if (frame == nil) {
|
|
611
|
+
return nil;
|
|
612
|
+
}
|
|
613
|
+
JCORERegisterResponse *response = [[JCORERegisterResponse alloc] init];
|
|
614
|
+
response.statusCode = frame.statusCode;
|
|
615
|
+
|
|
616
|
+
NSData *body = frame.bodyData;
|
|
617
|
+
if (body.length < 2) {
|
|
618
|
+
return response;
|
|
619
|
+
}
|
|
620
|
+
|
|
621
|
+
NSUInteger offset = 0;
|
|
622
|
+
uint16_t bodyStatus = 0;
|
|
623
|
+
if (!JCoreReadUInt16(body, &offset, &bodyStatus)) {
|
|
624
|
+
return response;
|
|
625
|
+
}
|
|
626
|
+
response.statusCode = bodyStatus;
|
|
627
|
+
if (bodyStatus != 0 || body.length < offset + 8) {
|
|
628
|
+
return response;
|
|
629
|
+
}
|
|
630
|
+
|
|
631
|
+
uint64_t uid = 0;
|
|
632
|
+
if (!JCoreReadUInt64(body, &offset, &uid)) {
|
|
633
|
+
return response;
|
|
634
|
+
}
|
|
635
|
+
response.uid = uid;
|
|
636
|
+
response.password = JCoreReadString(body, &offset);
|
|
637
|
+
response.registrationID = JCoreReadString(body, &offset);
|
|
638
|
+
if (offset + 2 <= body.length) {
|
|
639
|
+
response.deviceID = JCoreReadString(body, &offset);
|
|
640
|
+
}
|
|
641
|
+
return response;
|
|
642
|
+
}
|
|
643
|
+
|
|
644
|
+
#pragma mark - Login (cmd = 1, ver = 27)
|
|
645
|
+
|
|
646
|
+
+ (NSData *)buildLoginPayloadWithPassword:(NSString *)password
|
|
647
|
+
appKey:(NSString *)appKey {
|
|
648
|
+
JCOREConfiguration *config = [JCOREConfiguration shared];
|
|
649
|
+
NSString *passwordMd5 = [JCORECrypto md5Hex:password ?: @""];
|
|
650
|
+
NSString *modelName = [config modelNameString];
|
|
651
|
+
NSString *appVersion = [config appVersionString];
|
|
652
|
+
NSString *systemVersion = [config osVersionString];
|
|
653
|
+
NSString *countryCode = [[NSLocale currentLocale] objectForKey:NSLocaleCountryCode] ?: @"CN";
|
|
654
|
+
|
|
655
|
+
NSMutableData *body = [NSMutableData data];
|
|
656
|
+
JCoreAppendUInt32(body, 105); // Fixed magic 0x00000069
|
|
657
|
+
JCoreAppendString(body, passwordMd5); // MD5(password)
|
|
658
|
+
JCoreAppendUInt32(body, 0x00050200); // Core SDK version 5.2.0
|
|
659
|
+
JCoreAppendString(body, appKey ?: @""); // appKey
|
|
660
|
+
JCoreAppendUInt8(body, 1); // platform = 1 (iOS)
|
|
661
|
+
JCoreAppendUInt32(body, 0); // idc
|
|
662
|
+
JCoreAppendUInt8(body, config.apsType); // apsType (1=prod, 0=dev)
|
|
663
|
+
JCoreAppendUInt8(body, config.buildType); // buildType (0=debug, 1=release)
|
|
664
|
+
JCoreAppendString(body, [NSString stringWithFormat:@"$$%@$$%@$$ ", modelName, appVersion]);
|
|
665
|
+
JCoreAppendString(body, @"5.2.0|6.0.0"); // versions
|
|
666
|
+
JCoreAppendUInt16(body, 0); // connectInfo
|
|
667
|
+
JCoreAppendString(body, @"|||1$$0$$0$$0"); // extInfo
|
|
668
|
+
JCoreAppendString(body, [NSString stringWithFormat:@"%@;;%@", systemVersion, countryCode]);
|
|
669
|
+
return body;
|
|
670
|
+
}
|
|
671
|
+
|
|
672
|
+
+ (NSData *)buildLoginResponsePayloadWithStatusCode:(uint16_t)statusCode
|
|
673
|
+
sessionId:(uint32_t)sessionId
|
|
674
|
+
serverVersion:(uint16_t)serverVersion
|
|
675
|
+
errorMessage:(NSString *)errorMessage
|
|
676
|
+
serverTimestamp:(uint32_t)serverTimestamp
|
|
677
|
+
idc:(int8_t)idc {
|
|
678
|
+
NSMutableData *body = [NSMutableData data];
|
|
679
|
+
JCoreAppendUInt16(body, statusCode);
|
|
680
|
+
if (statusCode == 0) {
|
|
681
|
+
JCoreAppendUInt32(body, sessionId);
|
|
682
|
+
JCoreAppendUInt16(body, serverVersion);
|
|
683
|
+
JCoreAppendString(body, errorMessage ?: @"");
|
|
684
|
+
JCoreAppendUInt32(body, serverTimestamp);
|
|
685
|
+
JCoreAppendUInt8(body, (uint8_t)idc);
|
|
686
|
+
} else {
|
|
687
|
+
JCoreAppendString(body, errorMessage ?: @"");
|
|
688
|
+
}
|
|
689
|
+
return body;
|
|
690
|
+
}
|
|
691
|
+
|
|
692
|
+
+ (NSData *)buildLoginResponsePayloadWithSessionId:(uint32_t)sessionId
|
|
693
|
+
serverVersion:(uint16_t)serverVersion
|
|
694
|
+
serverTimestamp:(uint32_t)serverTimestamp {
|
|
695
|
+
return [self buildLoginResponsePayloadWithStatusCode:0
|
|
696
|
+
sessionId:sessionId
|
|
697
|
+
serverVersion:serverVersion
|
|
698
|
+
errorMessage:@""
|
|
699
|
+
serverTimestamp:serverTimestamp
|
|
700
|
+
idc:0];
|
|
701
|
+
}
|
|
702
|
+
|
|
703
|
+
+ (JCORELoginResponse *)parseLoginResponse:(JCOREWireFrame *)frame {
|
|
704
|
+
if (frame == nil) {
|
|
705
|
+
return nil;
|
|
706
|
+
}
|
|
707
|
+
JCORELoginResponse *response = [[JCORELoginResponse alloc] init];
|
|
708
|
+
response.statusCode = frame.statusCode;
|
|
709
|
+
|
|
710
|
+
NSData *body = frame.bodyData;
|
|
711
|
+
if (body.length < 2) {
|
|
712
|
+
return response;
|
|
713
|
+
}
|
|
714
|
+
|
|
715
|
+
NSUInteger offset = 0;
|
|
716
|
+
uint16_t bodyStatus = 0;
|
|
717
|
+
if (!JCoreReadUInt16(body, &offset, &bodyStatus)) {
|
|
718
|
+
return response;
|
|
719
|
+
}
|
|
720
|
+
response.statusCode = bodyStatus;
|
|
721
|
+
if (bodyStatus != 0) {
|
|
722
|
+
if (offset + 2 <= body.length) {
|
|
723
|
+
response.errorMessage = JCoreReadString(body, &offset);
|
|
724
|
+
}
|
|
725
|
+
return response;
|
|
726
|
+
}
|
|
727
|
+
if (body.length < offset + 6) {
|
|
728
|
+
return response;
|
|
729
|
+
}
|
|
730
|
+
|
|
731
|
+
uint32_t sid = 0;
|
|
732
|
+
uint16_t serverVer = 0;
|
|
733
|
+
uint32_t serverTime = 0;
|
|
734
|
+
JCoreReadUInt32(body, &offset, &sid);
|
|
735
|
+
JCoreReadUInt16(body, &offset, &serverVer);
|
|
736
|
+
NSString *errMsg = JCoreReadString(body, &offset);
|
|
737
|
+
JCoreReadUInt32(body, &offset, &serverTime);
|
|
738
|
+
uint8_t idcByte = 0;
|
|
739
|
+
if (JCoreReadUInt8(body, &offset, &idcByte)) {
|
|
740
|
+
response.idc = (int8_t)idcByte;
|
|
741
|
+
}
|
|
742
|
+
response.sessionId = sid;
|
|
743
|
+
response.serverVersion = serverVer;
|
|
744
|
+
response.errorMessage = errMsg;
|
|
745
|
+
response.serverTimestamp = serverTime;
|
|
746
|
+
return response;
|
|
747
|
+
}
|
|
748
|
+
|
|
749
|
+
#pragma mark - Heartbeat (cmd = 2, ver = 8)
|
|
750
|
+
|
|
751
|
+
+ (NSData *)buildHeartbeatPayloadWithPushStopped:(BOOL)pushStopped {
|
|
752
|
+
NSMutableData *body = [NSMutableData dataWithCapacity:8];
|
|
753
|
+
uint32_t sdkFlag = 1;
|
|
754
|
+
uint8_t appState = pushStopped ? 0 : 1;
|
|
755
|
+
uint16_t beatInterval = 290;
|
|
756
|
+
uint8_t beatType = 1;
|
|
757
|
+
JCoreAppendUInt32(body, sdkFlag);
|
|
758
|
+
JCoreAppendUInt8(body, appState);
|
|
759
|
+
JCoreAppendUInt16(body, beatInterval);
|
|
760
|
+
JCoreAppendUInt8(body, beatType);
|
|
761
|
+
return body;
|
|
762
|
+
}
|
|
763
|
+
|
|
764
|
+
#pragma mark - PushMessage (cmd = 3, ver = 4) & MessageReceipt (cmd = 4, ver = 3)
|
|
765
|
+
|
|
766
|
+
+ (NSData *)buildPushMessagePayloadWithMessageType:(uint8_t)messageType
|
|
767
|
+
messageId:(uint64_t)messageId
|
|
768
|
+
content:(NSString *)content {
|
|
769
|
+
NSMutableData *body = [NSMutableData data];
|
|
770
|
+
JCoreAppendUInt8(body, messageType);
|
|
771
|
+
JCoreAppendUInt64(body, messageId);
|
|
772
|
+
JCoreAppendString(body, content ?: @"");
|
|
773
|
+
return body;
|
|
774
|
+
}
|
|
775
|
+
|
|
776
|
+
+ (JCOREPushEnvelope *)parsePushEnvelope:(JCOREWireFrame *)frame {
|
|
777
|
+
if (frame.bodyData.length < 11) {
|
|
778
|
+
return nil;
|
|
779
|
+
}
|
|
780
|
+
NSUInteger offset = 0;
|
|
781
|
+
uint8_t msgType = 0;
|
|
782
|
+
uint64_t msgId = 0;
|
|
783
|
+
if (!JCoreReadUInt8(frame.bodyData, &offset, &msgType) ||
|
|
784
|
+
!JCoreReadUInt64(frame.bodyData, &offset, &msgId)) {
|
|
785
|
+
return nil;
|
|
786
|
+
}
|
|
787
|
+
NSString *content = JCoreReadString(frame.bodyData, &offset);
|
|
788
|
+
JCOREPushEnvelope *envelope = [[JCOREPushEnvelope alloc] init];
|
|
789
|
+
envelope.messageType = msgType;
|
|
790
|
+
envelope.messageId = msgId;
|
|
791
|
+
envelope.content = content;
|
|
792
|
+
if (content.length > 0) {
|
|
793
|
+
NSArray<NSString *> *segments = [content componentsSeparatedByString:@"\n"];
|
|
794
|
+
NSString *jsonCandidate = segments.lastObject ?: content;
|
|
795
|
+
NSData *jsonData = [jsonCandidate dataUsingEncoding:NSUTF8StringEncoding];
|
|
796
|
+
id parsed = [NSJSONSerialization JSONObjectWithData:jsonData options:0 error:nil];
|
|
797
|
+
if ([parsed isKindOfClass:[NSDictionary class]]) {
|
|
798
|
+
envelope.jsonPayload = parsed;
|
|
799
|
+
}
|
|
800
|
+
}
|
|
801
|
+
return envelope;
|
|
802
|
+
}
|
|
803
|
+
|
|
804
|
+
+ (NSData *)buildMessageAckPayloadWithStatusCode:(uint16_t)statusCode
|
|
805
|
+
messageType:(uint8_t)messageType
|
|
806
|
+
messageId:(uint64_t)messageId
|
|
807
|
+
msgData:(NSString *)msgData {
|
|
808
|
+
NSMutableData *body = [NSMutableData data];
|
|
809
|
+
JCoreAppendUInt16(body, statusCode);
|
|
810
|
+
JCoreAppendUInt8(body, messageType);
|
|
811
|
+
JCoreAppendUInt64(body, messageId);
|
|
812
|
+
if (msgData != nil) {
|
|
813
|
+
JCoreAppendString(body, msgData);
|
|
814
|
+
}
|
|
815
|
+
return body;
|
|
816
|
+
}
|
|
817
|
+
|
|
818
|
+
+ (NSData *)buildMessageAckPayloadWithMessageType:(uint8_t)messageType
|
|
819
|
+
messageId:(uint64_t)messageId {
|
|
820
|
+
return [self buildMessageAckPayloadWithStatusCode:0
|
|
821
|
+
messageType:messageType
|
|
822
|
+
messageId:messageId
|
|
823
|
+
msgData:nil];
|
|
824
|
+
}
|
|
825
|
+
|
|
826
|
+
+ (BOOL)parseMessageAckFrame:(JCOREWireFrame *)frame
|
|
827
|
+
outMessageType:(uint8_t *)outMessageType
|
|
828
|
+
outMessageId:(uint64_t *)outMessageId {
|
|
829
|
+
if (frame.bodyData.length < 11) {
|
|
830
|
+
return NO;
|
|
831
|
+
}
|
|
832
|
+
NSUInteger offset = 0;
|
|
833
|
+
uint16_t statusCode = 0;
|
|
834
|
+
uint8_t msgType = 0;
|
|
835
|
+
uint64_t msgId = 0;
|
|
836
|
+
if (!JCoreReadUInt16(frame.bodyData, &offset, &statusCode) ||
|
|
837
|
+
!JCoreReadUInt8(frame.bodyData, &offset, &msgType) ||
|
|
838
|
+
!JCoreReadUInt64(frame.bodyData, &offset, &msgId)) {
|
|
839
|
+
return NO;
|
|
840
|
+
}
|
|
841
|
+
if (outMessageType != NULL) {
|
|
842
|
+
*outMessageType = msgType;
|
|
843
|
+
}
|
|
844
|
+
if (outMessageId != NULL) {
|
|
845
|
+
*outMessageId = msgId;
|
|
846
|
+
}
|
|
847
|
+
return YES;
|
|
848
|
+
}
|
|
849
|
+
|
|
850
|
+
#pragma mark - DeviceToken (cmd = 13, ver = 3) & VoIP Token (cmd = 33, ver = 2)
|
|
851
|
+
|
|
852
|
+
+ (NSData *)buildDeviceTokenPayloadWithTokenHex:(NSString *)tokenHex {
|
|
853
|
+
JCOREConfiguration *config = [JCOREConfiguration shared];
|
|
854
|
+
NSMutableData *body = [NSMutableData data];
|
|
855
|
+
JCoreAppendString(body, tokenHex ?: @"");
|
|
856
|
+
JCoreAppendUInt8(body, config.buildType);
|
|
857
|
+
JCoreAppendUInt8(body, config.apsType);
|
|
858
|
+
JCoreAppendUInt8(body, 1);
|
|
859
|
+
return body;
|
|
860
|
+
}
|
|
861
|
+
|
|
862
|
+
+ (NSString *)parseDeviceTokenFromFrame:(JCOREWireFrame *)frame {
|
|
863
|
+
if (frame.bodyData.length < 2) {
|
|
864
|
+
return nil;
|
|
865
|
+
}
|
|
866
|
+
NSUInteger offset = 0;
|
|
867
|
+
return JCoreReadString(frame.bodyData, &offset);
|
|
868
|
+
}
|
|
869
|
+
|
|
870
|
+
+ (NSData *)buildVoipTokenPayloadWithTokenHex:(NSString *)tokenHex {
|
|
871
|
+
JCOREConfiguration *config = [JCOREConfiguration shared];
|
|
872
|
+
NSMutableData *body = [NSMutableData data];
|
|
873
|
+
JCoreAppendString(body, tokenHex ?: @"");
|
|
874
|
+
JCoreAppendUInt8(body, 1);
|
|
875
|
+
JCoreAppendUInt8(body, config.buildType);
|
|
876
|
+
JCoreAppendUInt8(body, config.apsType);
|
|
877
|
+
return body;
|
|
878
|
+
}
|
|
879
|
+
|
|
880
|
+
+ (NSString *)parseVoipTokenFromFrame:(JCOREWireFrame *)frame {
|
|
881
|
+
if (frame.bodyData.length < 2) {
|
|
882
|
+
return nil;
|
|
883
|
+
}
|
|
884
|
+
NSUInteger offset = 0;
|
|
885
|
+
return JCoreReadString(frame.bodyData, &offset);
|
|
886
|
+
}
|
|
887
|
+
|
|
888
|
+
#pragma mark - LiveActivity Token (cmd = 39, ver = 1)
|
|
889
|
+
|
|
890
|
+
+ (NSData *)buildLiveActivityPayloadWithTokenHex:(NSString *)tokenHex
|
|
891
|
+
aliasOrAttributesType:(NSString *)aliasOrAttributesType
|
|
892
|
+
isPushToken:(BOOL)isPushToken {
|
|
893
|
+
JCOREConfiguration *config = [JCOREConfiguration shared];
|
|
894
|
+
NSMutableData *body = [NSMutableData data];
|
|
895
|
+
JCoreAppendString(body, tokenHex ?: @"");
|
|
896
|
+
JCoreAppendString(body, aliasOrAttributesType ?: @"");
|
|
897
|
+
JCoreAppendUInt8(body, isPushToken ? 1 : 0);
|
|
898
|
+
JCoreAppendUInt8(body, config.buildType);
|
|
899
|
+
JCoreAppendUInt8(body, config.apsType);
|
|
900
|
+
JCoreAppendUInt8(body, 1);
|
|
901
|
+
return body;
|
|
902
|
+
}
|
|
903
|
+
|
|
904
|
+
+ (NSData *)buildLiveActivityResponsePayloadWithStatusCode:(uint16_t)statusCode
|
|
905
|
+
alias:(NSString *)alias {
|
|
906
|
+
NSMutableData *body = [NSMutableData data];
|
|
907
|
+
JCoreAppendUInt16(body, statusCode);
|
|
908
|
+
JCoreAppendString(body, alias ?: @"");
|
|
909
|
+
return body;
|
|
910
|
+
}
|
|
911
|
+
|
|
912
|
+
+ (NSInteger)mapLiveActivityStatusCode:(uint16_t)statusCode {
|
|
913
|
+
switch (statusCode) {
|
|
914
|
+
case 0:
|
|
915
|
+
return 0;
|
|
916
|
+
case 3900:
|
|
917
|
+
return 6039;
|
|
918
|
+
case 3901:
|
|
919
|
+
return 6040;
|
|
920
|
+
case 3902:
|
|
921
|
+
return 6042;
|
|
922
|
+
case 3950:
|
|
923
|
+
return 6041;
|
|
924
|
+
default:
|
|
925
|
+
return (NSInteger)statusCode;
|
|
926
|
+
}
|
|
927
|
+
}
|
|
928
|
+
|
|
929
|
+
+ (JCORELiveActivityResponse *)parseLiveActivityResponse:(JCOREWireFrame *)frame {
|
|
930
|
+
if (frame == nil) {
|
|
931
|
+
return nil;
|
|
932
|
+
}
|
|
933
|
+
JCORELiveActivityResponse *resp = [[JCORELiveActivityResponse alloc] init];
|
|
934
|
+
resp.statusCode = frame.statusCode;
|
|
935
|
+
if (frame.bodyData.length >= 2) {
|
|
936
|
+
NSUInteger offset = 0;
|
|
937
|
+
uint16_t bodyStatus = 0;
|
|
938
|
+
if (JCoreReadUInt16(frame.bodyData, &offset, &bodyStatus)) {
|
|
939
|
+
resp.statusCode = bodyStatus;
|
|
940
|
+
}
|
|
941
|
+
if (offset + 2 <= frame.bodyData.length) {
|
|
942
|
+
resp.alias = JCoreReadString(frame.bodyData, &offset);
|
|
943
|
+
}
|
|
944
|
+
}
|
|
945
|
+
resp.mappedErrorCode = [self mapLiveActivityStatusCode:resp.statusCode];
|
|
946
|
+
return resp;
|
|
947
|
+
}
|
|
948
|
+
|
|
949
|
+
#pragma mark - CtrlCommand (cmd = 25, ver = 1)
|
|
950
|
+
|
|
951
|
+
+ (NSData *)buildCtrlCommandPayloadWithRequestId:(uint64_t)requestId
|
|
952
|
+
jsonPayload:(NSDictionary *)jsonPayload {
|
|
953
|
+
NSMutableData *body = [NSMutableData data];
|
|
954
|
+
JCoreAppendUInt64(body, requestId);
|
|
955
|
+
NSData *jsonData = [NSJSONSerialization isValidJSONObject:jsonPayload]
|
|
956
|
+
? [NSJSONSerialization dataWithJSONObject:jsonPayload options:0 error:nil]
|
|
957
|
+
: nil;
|
|
958
|
+
NSString *jsonString = jsonData != nil
|
|
959
|
+
? [[NSString alloc] initWithData:jsonData encoding:NSUTF8StringEncoding]
|
|
960
|
+
: @"{}";
|
|
961
|
+
JCoreAppendString(body, jsonString);
|
|
962
|
+
return body;
|
|
963
|
+
}
|
|
964
|
+
|
|
965
|
+
+ (JCORECtrlEnvelope *)parseCtrlEnvelope:(JCOREWireFrame *)frame {
|
|
966
|
+
if (frame.bodyData.length < 10) {
|
|
967
|
+
return nil;
|
|
968
|
+
}
|
|
969
|
+
NSUInteger offset = 0;
|
|
970
|
+
uint64_t reqId = 0;
|
|
971
|
+
if (!JCoreReadUInt64(frame.bodyData, &offset, &reqId)) {
|
|
972
|
+
return nil;
|
|
973
|
+
}
|
|
974
|
+
NSString *rawJson = JCoreReadString(frame.bodyData, &offset);
|
|
975
|
+
JCORECtrlEnvelope *env = [[JCORECtrlEnvelope alloc] init];
|
|
976
|
+
env.requestId = reqId;
|
|
977
|
+
env.rawJson = rawJson;
|
|
978
|
+
if (rawJson.length > 0) {
|
|
979
|
+
NSData *data = [rawJson dataUsingEncoding:NSUTF8StringEncoding];
|
|
980
|
+
id parsed = [NSJSONSerialization JSONObjectWithData:data options:0 error:nil];
|
|
981
|
+
if ([parsed isKindOfClass:[NSDictionary class]]) {
|
|
982
|
+
env.jsonPayload = parsed;
|
|
983
|
+
}
|
|
984
|
+
}
|
|
985
|
+
return env;
|
|
986
|
+
}
|
|
987
|
+
|
|
988
|
+
+ (NSData *)buildCtrlAckPayloadWithStatusCode:(uint16_t)statusCode
|
|
989
|
+
requestId:(uint64_t)requestId {
|
|
990
|
+
NSMutableData *body = [NSMutableData dataWithCapacity:10];
|
|
991
|
+
JCoreAppendUInt16(body, statusCode);
|
|
992
|
+
JCoreAppendUInt64(body, requestId);
|
|
993
|
+
return body;
|
|
994
|
+
}
|
|
995
|
+
|
|
996
|
+
#pragma mark - User Property / MobileNumber / SDKVersion (cmd = 26, ver = 0)
|
|
997
|
+
|
|
998
|
+
+ (NSData *)buildMobileNumberPayload:(NSString *)mobileNumber {
|
|
999
|
+
NSMutableData *body = [NSMutableData data];
|
|
1000
|
+
JCoreAppendUInt8(body, 7); // property type 7 = mobile number
|
|
1001
|
+
JCoreAppendUInt8(body, 1); // version = 1
|
|
1002
|
+
JCoreAppendString(body, mobileNumber ?: @"");
|
|
1003
|
+
return body;
|
|
1004
|
+
}
|
|
1005
|
+
|
|
1006
|
+
+ (NSString *)parseMobileNumberFromFrame:(JCOREWireFrame *)frame {
|
|
1007
|
+
if (frame.bodyData.length < 4) {
|
|
1008
|
+
return nil;
|
|
1009
|
+
}
|
|
1010
|
+
NSUInteger offset = 2;
|
|
1011
|
+
return JCoreReadString(frame.bodyData, &offset);
|
|
1012
|
+
}
|
|
1013
|
+
|
|
1014
|
+
+ (NSData *)buildSdkVersionPropertyPayload:(NSString *)sdkVersion {
|
|
1015
|
+
NSMutableData *body = [NSMutableData data];
|
|
1016
|
+
JCoreAppendUInt8(body, 1); // property type 1 = JPush SDK version
|
|
1017
|
+
JCoreAppendUInt8(body, 1); // version = 1
|
|
1018
|
+
JCoreAppendString(body, sdkVersion ?: @"6.0.0");
|
|
1019
|
+
return body;
|
|
1020
|
+
}
|
|
1021
|
+
|
|
1022
|
+
#pragma mark - Tags (cmd = 28, ver = 1), Alias (cmd = 29, ver = 1), User Properties (cmd = 38, ver = 1)
|
|
1023
|
+
|
|
1024
|
+
+ (NSData *)buildTagOperationPayloadWithOperator:(NSString *)opString
|
|
1025
|
+
tags:(NSArray<NSString *> *)tags
|
|
1026
|
+
currPage:(NSInteger)currPage {
|
|
1027
|
+
NSMutableDictionary *dict = [NSMutableDictionary dictionary];
|
|
1028
|
+
dict[@"platform"] = @"i";
|
|
1029
|
+
dict[@"op"] = opString ?: @"set";
|
|
1030
|
+
if (tags != nil && ![opString isEqualToString:@"clean"] && ![opString isEqualToString:@"get"]) {
|
|
1031
|
+
dict[@"tags"] = tags;
|
|
1032
|
+
}
|
|
1033
|
+
if ([opString isEqualToString:@"get"] || currPage > 0) {
|
|
1034
|
+
dict[@"curr"] = @(currPage > 0 ? currPage : 1);
|
|
1035
|
+
}
|
|
1036
|
+
return [self buildJsonCommandPayload:dict];
|
|
1037
|
+
}
|
|
1038
|
+
|
|
1039
|
+
+ (NSData *)buildAliasOperationPayloadWithOperator:(NSString *)opString
|
|
1040
|
+
alias:(NSString *)alias {
|
|
1041
|
+
NSMutableDictionary *dict = [NSMutableDictionary dictionary];
|
|
1042
|
+
dict[@"platform"] = @"i";
|
|
1043
|
+
dict[@"op"] = opString ?: @"set";
|
|
1044
|
+
if (alias.length > 0 && ![opString isEqualToString:@"del"] && ![opString isEqualToString:@"get"]) {
|
|
1045
|
+
dict[@"alias"] = alias;
|
|
1046
|
+
}
|
|
1047
|
+
return [self buildJsonCommandPayload:dict];
|
|
1048
|
+
}
|
|
1049
|
+
|
|
1050
|
+
+ (NSData *)buildUserPropertiesPayloadWithOperator:(NSString *)opString
|
|
1051
|
+
properties:(NSDictionary *)properties {
|
|
1052
|
+
NSMutableDictionary *dict = [NSMutableDictionary dictionary];
|
|
1053
|
+
dict[@"op"] = opString ?: @"set";
|
|
1054
|
+
dict[@"data"] = properties ?: @{};
|
|
1055
|
+
return [self buildJsonCommandPayload:dict];
|
|
1056
|
+
}
|
|
1057
|
+
|
|
1058
|
+
+ (NSData *)buildUserPropertiesResponsePayloadWithStatusCode:(uint16_t)statusCode
|
|
1059
|
+
jsonPayload:(NSDictionary *)jsonPayload {
|
|
1060
|
+
NSMutableData *body = [NSMutableData data];
|
|
1061
|
+
JCoreAppendUInt16(body, statusCode);
|
|
1062
|
+
if (jsonPayload != nil && [NSJSONSerialization isValidJSONObject:jsonPayload]) {
|
|
1063
|
+
NSData *jsonData = [NSJSONSerialization dataWithJSONObject:jsonPayload options:0 error:nil];
|
|
1064
|
+
NSString *jsonString = [[NSString alloc] initWithData:jsonData encoding:NSUTF8StringEncoding] ?: @"{}";
|
|
1065
|
+
JCoreAppendString(body, jsonString);
|
|
1066
|
+
} else {
|
|
1067
|
+
JCoreAppendString(body, @"{}");
|
|
1068
|
+
}
|
|
1069
|
+
return body;
|
|
1070
|
+
}
|
|
1071
|
+
|
|
1072
|
+
+ (NSData *)buildJsonCommandPayload:(NSDictionary *)payload {
|
|
1073
|
+
NSMutableData *body = [NSMutableData data];
|
|
1074
|
+
NSData *jsonData = [NSJSONSerialization isValidJSONObject:payload]
|
|
1075
|
+
? [NSJSONSerialization dataWithJSONObject:payload options:0 error:nil]
|
|
1076
|
+
: nil;
|
|
1077
|
+
NSString *jsonString = jsonData != nil
|
|
1078
|
+
? [[NSString alloc] initWithData:jsonData encoding:NSUTF8StringEncoding]
|
|
1079
|
+
: @"{}";
|
|
1080
|
+
JCoreAppendString(body, jsonString);
|
|
1081
|
+
return body;
|
|
1082
|
+
}
|
|
1083
|
+
|
|
1084
|
+
+ (NSDictionary *)parseJsonBodyFromFrame:(JCOREWireFrame *)frame {
|
|
1085
|
+
if (frame.bodyData.length == 0) {
|
|
1086
|
+
return nil;
|
|
1087
|
+
}
|
|
1088
|
+
NSData *body = frame.bodyData;
|
|
1089
|
+
|
|
1090
|
+
// 1. Try reading length-prefixed string at offset 0 (Tags/Alias request & response, Properties request)
|
|
1091
|
+
NSUInteger offset = 0;
|
|
1092
|
+
NSString *jsonString = JCoreReadString(body, &offset);
|
|
1093
|
+
if (jsonString.length > 0) {
|
|
1094
|
+
NSData *data = [jsonString dataUsingEncoding:NSUTF8StringEncoding];
|
|
1095
|
+
id obj = [NSJSONSerialization JSONObjectWithData:data options:0 error:nil];
|
|
1096
|
+
if ([obj isKindOfClass:[NSDictionary class]]) {
|
|
1097
|
+
return obj;
|
|
1098
|
+
}
|
|
1099
|
+
}
|
|
1100
|
+
|
|
1101
|
+
// 2. Try reading length-prefixed string at offset 2 (after 2-byte statusCode in Properties response)
|
|
1102
|
+
if (body.length > 4) {
|
|
1103
|
+
NSUInteger offsetAfterStatus = 2;
|
|
1104
|
+
NSString *jsonAfterStatus = JCoreReadString(body, &offsetAfterStatus);
|
|
1105
|
+
if (jsonAfterStatus.length > 0) {
|
|
1106
|
+
NSData *data = [jsonAfterStatus dataUsingEncoding:NSUTF8StringEncoding];
|
|
1107
|
+
id obj = [NSJSONSerialization JSONObjectWithData:data options:0 error:nil];
|
|
1108
|
+
if ([obj isKindOfClass:[NSDictionary class]]) {
|
|
1109
|
+
return obj;
|
|
1110
|
+
}
|
|
1111
|
+
}
|
|
1112
|
+
}
|
|
1113
|
+
|
|
1114
|
+
// 3. Fallback: raw UTF-8 JSON body
|
|
1115
|
+
id rawObj = [NSJSONSerialization JSONObjectWithData:body options:0 error:nil];
|
|
1116
|
+
return [rawObj isKindOfClass:[NSDictionary class]] ? rawObj : nil;
|
|
1117
|
+
}
|
|
1118
|
+
|
|
1119
|
+
+ (NSData *)buildPushControlPayloadWithStopped:(BOOL)stopped {
|
|
1120
|
+
NSDictionary *dict = @{
|
|
1121
|
+
@"type": @"notif_state",
|
|
1122
|
+
@"enabled": @(!stopped),
|
|
1123
|
+
@"itime": @((uint64_t)[[NSDate date] timeIntervalSince1970]),
|
|
1124
|
+
};
|
|
1125
|
+
return [self buildJsonCommandPayload:dict];
|
|
1126
|
+
}
|
|
1127
|
+
|
|
1128
|
+
@end
|
|
1129
|
+
|
|
1130
|
+
#pragma mark - HTTP Reporter (Part 4.4)
|
|
1131
|
+
|
|
1132
|
+
@interface JCOREHttpReporter ()
|
|
1133
|
+
@property (nonatomic, strong) NSURLSession *reportSession;
|
|
1134
|
+
@end
|
|
1135
|
+
|
|
1136
|
+
@implementation JCOREHttpReporter
|
|
1137
|
+
|
|
1138
|
+
+ (instancetype)shared {
|
|
1139
|
+
static JCOREHttpReporter *instance = nil;
|
|
1140
|
+
static dispatch_once_t onceToken;
|
|
1141
|
+
dispatch_once(&onceToken, ^{
|
|
1142
|
+
instance = [[JCOREHttpReporter alloc] init];
|
|
1143
|
+
});
|
|
1144
|
+
return instance;
|
|
1145
|
+
}
|
|
1146
|
+
|
|
1147
|
+
- (instancetype)init {
|
|
1148
|
+
self = [super init];
|
|
1149
|
+
if (self) {
|
|
1150
|
+
NSURLSessionConfiguration *cfg = [NSURLSessionConfiguration ephemeralSessionConfiguration];
|
|
1151
|
+
cfg.timeoutIntervalForRequest = 10.0;
|
|
1152
|
+
cfg.timeoutIntervalForResource = 15.0;
|
|
1153
|
+
_reportSession = [NSURLSession sessionWithConfiguration:cfg];
|
|
1154
|
+
}
|
|
1155
|
+
return self;
|
|
1156
|
+
}
|
|
1157
|
+
|
|
1158
|
+
+ (NSDictionary *)buildReportEnvelopeWithContentItems:(NSArray<NSDictionary *> *)items {
|
|
1159
|
+
JCOREConfiguration *config = [JCOREConfiguration shared];
|
|
1160
|
+
return @{
|
|
1161
|
+
@"platform": @"i",
|
|
1162
|
+
@"uid": @(config.uid),
|
|
1163
|
+
@"app_key": config.appKey ?: @"",
|
|
1164
|
+
@"sdk_ver": @"5.2.0",
|
|
1165
|
+
@"core_sdk_ver": @"5.2.0",
|
|
1166
|
+
@"os_ver": [config osVersionString],
|
|
1167
|
+
@"model": [config modelNameString],
|
|
1168
|
+
@"bundle_id": [config bundleIdentifierString],
|
|
1169
|
+
@"ver": [config appVersionString],
|
|
1170
|
+
@"content": items ?: @[],
|
|
1171
|
+
};
|
|
1172
|
+
}
|
|
1173
|
+
|
|
1174
|
+
+ (NSURLRequest *)buildHttpReportRequestWithURL:(NSURL *)url
|
|
1175
|
+
contentItems:(NSArray<NSDictionary *> *)items
|
|
1176
|
+
uid:(uint64_t)uid
|
|
1177
|
+
password:(NSString *)password
|
|
1178
|
+
appKey:(NSString *)appKey
|
|
1179
|
+
outAesKey:(NSString **)outAesKey {
|
|
1180
|
+
if (url == nil) {
|
|
1181
|
+
return nil;
|
|
1182
|
+
}
|
|
1183
|
+
NSMutableDictionary *envelope = [[self buildReportEnvelopeWithContentItems:items] mutableCopy];
|
|
1184
|
+
envelope[@"uid"] = @(uid);
|
|
1185
|
+
envelope[@"app_key"] = appKey ?: @"";
|
|
1186
|
+
|
|
1187
|
+
NSData *jsonData = [NSJSONSerialization dataWithJSONObject:envelope options:0 error:nil];
|
|
1188
|
+
if (jsonData.length == 0) {
|
|
1189
|
+
return nil;
|
|
1190
|
+
}
|
|
1191
|
+
NSData *compressed = [JCORECrypto gzipCompress:jsonData];
|
|
1192
|
+
if (compressed.length == 0) {
|
|
1193
|
+
return nil;
|
|
1194
|
+
}
|
|
1195
|
+
|
|
1196
|
+
uint32_t seed = (arc4random() % 10000000U) + 1U;
|
|
1197
|
+
NSString *aesKey = [JCORECrypto generateSeedKey:seed];
|
|
1198
|
+
if (outAesKey != NULL) {
|
|
1199
|
+
*outAesKey = aesKey;
|
|
1200
|
+
}
|
|
1201
|
+
|
|
1202
|
+
NSData *encryptedBody = [JCORECrypto aes256CBCEncryptWithFixedHttpIV:compressed key:aesKey];
|
|
1203
|
+
if (encryptedBody.length == 0) {
|
|
1204
|
+
return nil;
|
|
1205
|
+
}
|
|
1206
|
+
|
|
1207
|
+
NSString *bodySha1 = [JCORECrypto sha1Hex:encryptedBody];
|
|
1208
|
+
NSString *pwdMd5 = [JCORECrypto md5Hex:password ?: @""];
|
|
1209
|
+
NSString *tokenInput = [NSString stringWithFormat:@"%llu%@%@", uid, pwdMd5, bodySha1];
|
|
1210
|
+
NSString *authToken = [JCORECrypto sha1HexForString:tokenInput];
|
|
1211
|
+
NSString *rawAuth = [NSString stringWithFormat:@"%llu:%@:%@", uid, authToken, aesKey];
|
|
1212
|
+
NSString *base64Auth = [[rawAuth dataUsingEncoding:NSUTF8StringEncoding] base64EncodedStringWithOptions:0];
|
|
1213
|
+
|
|
1214
|
+
NSMutableURLRequest *request = [NSMutableURLRequest requestWithURL:url
|
|
1215
|
+
cachePolicy:NSURLRequestReloadIgnoringLocalCacheData
|
|
1216
|
+
timeoutInterval:10.0];
|
|
1217
|
+
request.HTTPMethod = @"POST";
|
|
1218
|
+
request.HTTPBody = encryptedBody;
|
|
1219
|
+
[request setValue:[NSString stringWithFormat:@"Basic %@", base64Auth] forHTTPHeaderField:@"Authorization"];
|
|
1220
|
+
[request setValue:(appKey ?: @"") forHTTPHeaderField:@"X-App-Key"];
|
|
1221
|
+
[request setValue:@"application/octet-stream" forHTTPHeaderField:@"Content-Type"];
|
|
1222
|
+
[request setValue:@"application/jason" forHTTPHeaderField:@"Accept"];
|
|
1223
|
+
return request;
|
|
1224
|
+
}
|
|
1225
|
+
|
|
1226
|
+
+ (NSDictionary *)verifyAndDecryptHttpReportBody:(NSData *)bodyData
|
|
1227
|
+
authorizationHeader:(NSString *)authHeader
|
|
1228
|
+
expectedUid:(uint64_t)expectedUid
|
|
1229
|
+
password:(NSString *)password {
|
|
1230
|
+
if (bodyData.length == 0 || ![authHeader hasPrefix:@"Basic "]) {
|
|
1231
|
+
return nil;
|
|
1232
|
+
}
|
|
1233
|
+
NSString *b64 = [authHeader substringFromIndex:6];
|
|
1234
|
+
NSData *decodedAuthData = [[NSData alloc] initWithBase64EncodedString:b64 options:0];
|
|
1235
|
+
NSString *decodedAuth = [[NSString alloc] initWithData:decodedAuthData encoding:NSUTF8StringEncoding];
|
|
1236
|
+
NSArray<NSString *> *parts = [decodedAuth componentsSeparatedByString:@":"];
|
|
1237
|
+
if (parts.count != 3) {
|
|
1238
|
+
return nil;
|
|
1239
|
+
}
|
|
1240
|
+
uint64_t headerUid = strtoull(parts[0].UTF8String, NULL, 10);
|
|
1241
|
+
if (expectedUid != 0 && headerUid != expectedUid) {
|
|
1242
|
+
return nil;
|
|
1243
|
+
}
|
|
1244
|
+
NSString *authToken = parts[1];
|
|
1245
|
+
NSString *aesKey = parts[2];
|
|
1246
|
+
|
|
1247
|
+
NSString *bodySha1 = [JCORECrypto sha1Hex:bodyData];
|
|
1248
|
+
NSString *pwdMd5 = [JCORECrypto md5Hex:password ?: @""];
|
|
1249
|
+
NSString *expectedToken = [JCORECrypto sha1HexForString:[NSString stringWithFormat:@"%llu%@%@", headerUid, pwdMd5, bodySha1]];
|
|
1250
|
+
if (![authToken isEqualToString:expectedToken]) {
|
|
1251
|
+
return nil;
|
|
1252
|
+
}
|
|
1253
|
+
|
|
1254
|
+
NSData *decryptedCompressed = [JCORECrypto aes256CBCDecryptWithFixedHttpIV:bodyData key:aesKey];
|
|
1255
|
+
if (decryptedCompressed.length == 0) {
|
|
1256
|
+
return nil;
|
|
1257
|
+
}
|
|
1258
|
+
NSData *jsonData = [JCORECrypto gzipDecompress:decryptedCompressed];
|
|
1259
|
+
if (jsonData.length == 0) {
|
|
1260
|
+
return nil;
|
|
1261
|
+
}
|
|
1262
|
+
id obj = [NSJSONSerialization JSONObjectWithData:jsonData options:0 error:nil];
|
|
1263
|
+
return [obj isKindOfClass:[NSDictionary class]] ? obj : nil;
|
|
1264
|
+
}
|
|
1265
|
+
|
|
1266
|
+
+ (NSURLRequest *)buildBadgeReportRequestWithBaseURL:(NSURL *)baseURL
|
|
1267
|
+
badgeValue:(NSInteger)badgeValue
|
|
1268
|
+
uid:(uint64_t)uid
|
|
1269
|
+
appKey:(NSString *)appKey
|
|
1270
|
+
outAesKey16:(NSString **)outAesKey16 {
|
|
1271
|
+
NSString *baseStr = baseURL.absoluteString.length > 0
|
|
1272
|
+
? baseURL.absoluteString
|
|
1273
|
+
: @"https://ali-stats.jpush.cn/v3/push/sdk/badge";
|
|
1274
|
+
NSString *urlStr = [NSString stringWithFormat:@"%@%@platform=i&uid=%llu&value=%ld",
|
|
1275
|
+
baseStr,
|
|
1276
|
+
([baseStr containsString:@"?"] ? @"&" : @"?"),
|
|
1277
|
+
uid,
|
|
1278
|
+
(long)badgeValue];
|
|
1279
|
+
NSURL *fullURL = [NSURL URLWithString:urlStr];
|
|
1280
|
+
if (fullURL == nil) {
|
|
1281
|
+
return nil;
|
|
1282
|
+
}
|
|
1283
|
+
|
|
1284
|
+
uint32_t seed = (arc4random() % 10000000U) + 1U;
|
|
1285
|
+
NSString *seedKey32 = [JCORECrypto generateSeedKey:seed];
|
|
1286
|
+
NSString *aesKey16 = [seedKey32 substringToIndex:16];
|
|
1287
|
+
if (outAesKey16 != NULL) {
|
|
1288
|
+
*outAesKey16 = aesKey16;
|
|
1289
|
+
}
|
|
1290
|
+
|
|
1291
|
+
NSString *rsaEncryptedKey = [JCORECrypto rsaEncryptString:aesKey16 publicKeyBase64:kJCOREReportRsaPublicKey] ?: @"";
|
|
1292
|
+
NSString *rawAuth = [NSString stringWithFormat:@"%@:%@", appKey ?: @"", rsaEncryptedKey];
|
|
1293
|
+
NSString *authHeaderValue = [NSString stringWithFormat:@"Basic %@",
|
|
1294
|
+
[[rawAuth dataUsingEncoding:NSUTF8StringEncoding] base64EncodedStringWithOptions:0]];
|
|
1295
|
+
|
|
1296
|
+
uint64_t timestampMs = (uint64_t)([[NSDate date] timeIntervalSince1970] * 1000.0);
|
|
1297
|
+
uint64_t timestampSec = timestampMs / 1000ULL;
|
|
1298
|
+
NSString *timestampStr = [NSString stringWithFormat:@"%llu", timestampMs];
|
|
1299
|
+
|
|
1300
|
+
NSInteger clampedBadge = badgeValue < 0 ? 0 : badgeValue;
|
|
1301
|
+
NSDictionary *badgeDict = @{
|
|
1302
|
+
@"platform": @"i",
|
|
1303
|
+
@"uid": @(uid),
|
|
1304
|
+
@"app_key": appKey ?: @"",
|
|
1305
|
+
@"badge": @(clampedBadge),
|
|
1306
|
+
@"content": @{@"badge": @(clampedBadge)},
|
|
1307
|
+
@"itime": @(timestampSec),
|
|
1308
|
+
};
|
|
1309
|
+
NSData *badgeJsonData = [NSJSONSerialization dataWithJSONObject:badgeDict options:0 error:nil];
|
|
1310
|
+
NSData *encryptedBadge = [JCORECrypto aes128CBCEncryptData:badgeJsonData
|
|
1311
|
+
key16:aesKey16
|
|
1312
|
+
iv16:@"0000000000000000"];
|
|
1313
|
+
NSString *bodyString = [encryptedBadge base64EncodedStringWithOptions:0] ?: @"";
|
|
1314
|
+
|
|
1315
|
+
NSString *hmacKey = [JCORECrypto md5Hex:[NSString stringWithFormat:@"%@%@", appKey ?: @"", timestampStr]];
|
|
1316
|
+
NSString *signInput = [NSString stringWithFormat:@"%@%@1.0%@", authHeaderValue, timestampStr, bodyString];
|
|
1317
|
+
NSString *signHex = [JCORECrypto hmacSHA256HexWithKey:hmacKey content:signInput];
|
|
1318
|
+
|
|
1319
|
+
NSMutableURLRequest *request = [NSMutableURLRequest requestWithURL:fullURL
|
|
1320
|
+
cachePolicy:NSURLRequestReloadIgnoringLocalCacheData
|
|
1321
|
+
timeoutInterval:10.0];
|
|
1322
|
+
request.HTTPMethod = @"POST";
|
|
1323
|
+
request.HTTPBody = [bodyString dataUsingEncoding:NSUTF8StringEncoding];
|
|
1324
|
+
[request setValue:authHeaderValue forHTTPHeaderField:@"Authorization"];
|
|
1325
|
+
[request setValue:@"1.0" forHTTPHeaderField:@"x-jg-version"];
|
|
1326
|
+
[request setValue:timestampStr forHTTPHeaderField:@"x-jg-timestamp"];
|
|
1327
|
+
[request setValue:signHex forHTTPHeaderField:@"x-jg-sign"];
|
|
1328
|
+
[request setValue:@"text/plain;charset=UTF-8" forHTTPHeaderField:@"Content-Type"];
|
|
1329
|
+
return request;
|
|
1330
|
+
}
|
|
1331
|
+
|
|
1332
|
+
+ (NSDictionary *)verifyAndDecryptBadgeReportHeaders:(NSDictionary<NSString *, NSString *> *)headers
|
|
1333
|
+
bodyString:(NSString *)bodyString
|
|
1334
|
+
appKey:(NSString *)appKey
|
|
1335
|
+
aesKey16:(NSString *)aesKey16 {
|
|
1336
|
+
NSString *auth = headers[@"Authorization"] ?: headers[@"authorization"];
|
|
1337
|
+
NSString *version = headers[@"x-jg-version"] ?: headers[@"X-Jg-Version"];
|
|
1338
|
+
NSString *timestamp = headers[@"x-jg-timestamp"] ?: headers[@"X-Jg-Timestamp"];
|
|
1339
|
+
NSString *sign = headers[@"x-jg-sign"] ?: headers[@"X-Jg-Sign"];
|
|
1340
|
+
if (auth.length == 0 || ![version isEqualToString:@"1.0"] || timestamp.length == 0 || sign.length == 0) {
|
|
1341
|
+
return nil;
|
|
1342
|
+
}
|
|
1343
|
+
|
|
1344
|
+
NSString *hmacKey = [JCORECrypto md5Hex:[NSString stringWithFormat:@"%@%@", appKey ?: @"", timestamp]];
|
|
1345
|
+
NSString *expectedSign = [JCORECrypto hmacSHA256HexWithKey:hmacKey
|
|
1346
|
+
content:[NSString stringWithFormat:@"%@%@1.0%@", auth, timestamp, bodyString ?: @""]];
|
|
1347
|
+
if (![sign isEqualToString:expectedSign]) {
|
|
1348
|
+
return nil;
|
|
1349
|
+
}
|
|
1350
|
+
|
|
1351
|
+
if (bodyString.length > 0 && aesKey16.length == 16) {
|
|
1352
|
+
NSData *cipherData = [[NSData alloc] initWithBase64EncodedString:bodyString options:0];
|
|
1353
|
+
NSData *plainData = [JCORECrypto aes128CBCDecryptData:cipherData
|
|
1354
|
+
key16:aesKey16
|
|
1355
|
+
iv16:@"0000000000000000"];
|
|
1356
|
+
if (plainData.length > 0) {
|
|
1357
|
+
id obj = [NSJSONSerialization JSONObjectWithData:plainData options:0 error:nil];
|
|
1358
|
+
if ([obj isKindOfClass:[NSDictionary class]]) {
|
|
1359
|
+
return obj;
|
|
1360
|
+
}
|
|
1361
|
+
}
|
|
1362
|
+
}
|
|
1363
|
+
return @{@"verified": @YES};
|
|
1364
|
+
}
|
|
1365
|
+
|
|
1366
|
+
- (void)sendHttpReportItems:(NSArray<NSDictionary *> *)items
|
|
1367
|
+
completion:(void (^)(BOOL, NSInteger))completion {
|
|
1368
|
+
JCOREConfiguration *config = [JCOREConfiguration shared];
|
|
1369
|
+
if (config.uid == 0 || config.appKey.length == 0) {
|
|
1370
|
+
if (completion) {
|
|
1371
|
+
completion(NO, -1);
|
|
1372
|
+
}
|
|
1373
|
+
return;
|
|
1374
|
+
}
|
|
1375
|
+
NSString *urlStr = config.httpReportUrl;
|
|
1376
|
+
if (urlStr.length == 0) {
|
|
1377
|
+
NSString *firstAddr = config.httpsReportAddresses.firstObject ?: config.httpReportAddresses.firstObject;
|
|
1378
|
+
if (firstAddr.length > 0) {
|
|
1379
|
+
urlStr = [firstAddr hasPrefix:@"http"] ? firstAddr : [NSString stringWithFormat:@"https://%@/v3/report", firstAddr];
|
|
1380
|
+
} else {
|
|
1381
|
+
urlStr = @"https://stats.jpush.cn/v3/report";
|
|
1382
|
+
}
|
|
1383
|
+
}
|
|
1384
|
+
NSURL *url = [NSURL URLWithString:urlStr];
|
|
1385
|
+
NSURLRequest *req = [JCOREHttpReporter buildHttpReportRequestWithURL:url
|
|
1386
|
+
contentItems:items
|
|
1387
|
+
uid:config.uid
|
|
1388
|
+
password:config.password ?: @""
|
|
1389
|
+
appKey:config.appKey
|
|
1390
|
+
outAesKey:NULL];
|
|
1391
|
+
if (req == nil) {
|
|
1392
|
+
if (completion) {
|
|
1393
|
+
completion(NO, -1);
|
|
1394
|
+
}
|
|
1395
|
+
return;
|
|
1396
|
+
}
|
|
1397
|
+
[[self.reportSession dataTaskWithRequest:req
|
|
1398
|
+
completionHandler:^(NSData *data, NSURLResponse *response, NSError *error) {
|
|
1399
|
+
(void)data;
|
|
1400
|
+
NSInteger status = [response isKindOfClass:[NSHTTPURLResponse class]]
|
|
1401
|
+
? [(NSHTTPURLResponse *)response statusCode]
|
|
1402
|
+
: 0;
|
|
1403
|
+
BOOL ok = (error == nil && status == 200);
|
|
1404
|
+
if (completion) {
|
|
1405
|
+
completion(ok, status);
|
|
1406
|
+
}
|
|
1407
|
+
}] resume];
|
|
1408
|
+
}
|
|
1409
|
+
|
|
1410
|
+
- (void)reportBadgeValue:(NSInteger)badgeValue
|
|
1411
|
+
completion:(void (^)(BOOL, NSInteger))completion {
|
|
1412
|
+
JCOREConfiguration *config = [JCOREConfiguration shared];
|
|
1413
|
+
if (config.uid == 0 || config.appKey.length == 0) {
|
|
1414
|
+
if (completion) {
|
|
1415
|
+
completion(NO, -1);
|
|
1416
|
+
}
|
|
1417
|
+
return;
|
|
1418
|
+
}
|
|
1419
|
+
NSString *urlStr = config.httpReportUrl;
|
|
1420
|
+
if (urlStr.length == 0) {
|
|
1421
|
+
NSString *firstAddr = config.httpsReportAddresses.firstObject ?: config.httpReportAddresses.firstObject;
|
|
1422
|
+
if (firstAddr.length > 0) {
|
|
1423
|
+
urlStr = [firstAddr hasPrefix:@"http"] ? firstAddr : [NSString stringWithFormat:@"https://%@/v3/push/sdk/badge", firstAddr];
|
|
1424
|
+
} else {
|
|
1425
|
+
urlStr = @"https://ali-stats.jpush.cn/v3/push/sdk/badge";
|
|
1426
|
+
}
|
|
1427
|
+
}
|
|
1428
|
+
NSURL *baseUrl = [NSURL URLWithString:urlStr];
|
|
1429
|
+
NSURLRequest *req = [JCOREHttpReporter buildBadgeReportRequestWithBaseURL:baseUrl
|
|
1430
|
+
badgeValue:badgeValue
|
|
1431
|
+
uid:config.uid
|
|
1432
|
+
appKey:config.appKey ?: @""
|
|
1433
|
+
outAesKey16:NULL];
|
|
1434
|
+
if (req == nil) {
|
|
1435
|
+
if (completion) {
|
|
1436
|
+
completion(NO, -1);
|
|
1437
|
+
}
|
|
1438
|
+
return;
|
|
1439
|
+
}
|
|
1440
|
+
[[self.reportSession dataTaskWithRequest:req
|
|
1441
|
+
completionHandler:^(NSData *data, NSURLResponse *response, NSError *error) {
|
|
1442
|
+
(void)data;
|
|
1443
|
+
NSInteger status = [response isKindOfClass:[NSHTTPURLResponse class]]
|
|
1444
|
+
? [(NSHTTPURLResponse *)response statusCode]
|
|
1445
|
+
: 0;
|
|
1446
|
+
BOOL ok = (error == nil && status == 200);
|
|
1447
|
+
if (completion) {
|
|
1448
|
+
completion(ok, status);
|
|
1449
|
+
}
|
|
1450
|
+
}] resume];
|
|
1451
|
+
}
|
|
1452
|
+
|
|
1453
|
+
@end
|