react-native-instantpay-code-push 1.2.6 → 2.0.0
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/README.md +2 -2
- package/ios/IpayCodePush/Private/BundleFileStorageService.swift +1 -1
- package/ios/IpayCodePush/Private/InstantpayCodePush.mm +16 -16
- package/ios/IpayCodePush/Private/IpayCodePushHelper.swift +2 -2
- package/ios/IpayCodePush/Private/IpayCodePushImpl.swift +39 -0
- package/ios/IpayCodePush/Private/SignatureVerifier.swift +168 -15
- package/lib/module/checkForUpdate.js +0 -4
- package/lib/module/checkForUpdate.js.map +1 -1
- package/lib/typescript/src/checkForUpdate.d.ts.map +1 -1
- package/package.json +1 -1
- package/src/checkForUpdate.ts +0 -5
package/README.md
CHANGED
|
@@ -126,7 +126,7 @@ class MainApplication : Application(), ReactApplication {
|
|
|
126
126
|
Open modify your ```AppDelegate.swift:```
|
|
127
127
|
|
|
128
128
|
```
|
|
129
|
-
import
|
|
129
|
+
import InstantpayCodePush //👈 import this package
|
|
130
130
|
|
|
131
131
|
@main
|
|
132
132
|
class AppDelegate: RCTAppDelegate {
|
|
@@ -137,7 +137,7 @@ class AppDelegate: RCTAppDelegate {
|
|
|
137
137
|
RCTBundleURLProvider.sharedSettings().jsBundleURL(forBundleRoot: "index")
|
|
138
138
|
#else
|
|
139
139
|
Bundle.main.url(forResource: "main", withExtension: "jsbundle") //❌ remove this
|
|
140
|
-
|
|
140
|
+
InstantpayCodePush.bundleURL() //👈 add this
|
|
141
141
|
#endif
|
|
142
142
|
}
|
|
143
143
|
|
|
@@ -469,7 +469,7 @@ class BundleFileStorageService: BundleStorageService {
|
|
|
469
469
|
IpayCodePushHelper.logPrint(classTag: CLASS_TAG, log: "Directory contents: \(contents)")
|
|
470
470
|
|
|
471
471
|
// Check for iOS bundle file directly
|
|
472
|
-
let iosBundlePath = (directoryPath as NSString).appendingPathComponent("index.ios.bundle")
|
|
472
|
+
let iosBundlePath = (directoryPath as NSString).appendingPathComponent(".ipay-bundle/bundle/index.ios.bundle")
|
|
473
473
|
if self.fileSystem.fileExists(atPath: iosBundlePath) {
|
|
474
474
|
IpayCodePushHelper.logPrint(classTag: CLASS_TAG, log: "Found iOS bundle atPath: \(iosBundlePath)")
|
|
475
475
|
return .success(iosBundlePath)
|
|
@@ -43,14 +43,14 @@ NSNotificationName const IpayCodePushDownloadDidFinishNotification = @"IpayCodeP
|
|
|
43
43
|
|
|
44
44
|
// Clean up observers when module is invalidated or deallocated
|
|
45
45
|
- (void)invalidate {
|
|
46
|
-
RCTLogInfo(@"[InstantpayCodePush.mm] invalidate called, removing observers.");
|
|
46
|
+
//RCTLogInfo(@"[InstantpayCodePush.mm] invalidate called, removing observers.");
|
|
47
47
|
[[NSNotificationCenter defaultCenter] removeObserver:self];
|
|
48
48
|
// Swift side should handle KVO observer removal for its tasks
|
|
49
49
|
[super invalidate];
|
|
50
50
|
}
|
|
51
51
|
|
|
52
52
|
- (void)dealloc {
|
|
53
|
-
RCTLogInfo(@"[InstantpayCodePush.mm] dealloc called, removing observers.");
|
|
53
|
+
//RCTLogInfo(@"[InstantpayCodePush.mm] dealloc called, removing observers.");
|
|
54
54
|
[[NSNotificationCenter defaultCenter] removeObserver:self];
|
|
55
55
|
}
|
|
56
56
|
|
|
@@ -95,17 +95,17 @@ RCT_EXPORT_MODULE();
|
|
|
95
95
|
// Convert timestamp (milliseconds) to UUID v7
|
|
96
96
|
uint64_t timestampMs = [customValue longLongValue];
|
|
97
97
|
uuid = [self generateUUIDv7FromTimestamp:timestampMs];
|
|
98
|
-
RCTLogInfo(@"[InstantpayCodePush.mm] Using timestamp %@ as MIN_BUNDLE_ID: %@", customValue, uuid);
|
|
98
|
+
//RCTLogInfo(@"[InstantpayCodePush.mm] Using timestamp %@ as MIN_BUNDLE_ID: %@", customValue, uuid);
|
|
99
99
|
} else {
|
|
100
100
|
// Use as UUID directly
|
|
101
101
|
uuid = customValue;
|
|
102
|
-
RCTLogInfo(@"[InstantpayCodePush.mm] Using custom MIN_BUNDLE_ID from Info.plist: %@", uuid);
|
|
102
|
+
//RCTLogInfo(@"[InstantpayCodePush.mm] Using custom MIN_BUNDLE_ID from Info.plist: %@", uuid);
|
|
103
103
|
}
|
|
104
104
|
return;
|
|
105
105
|
}
|
|
106
106
|
|
|
107
107
|
// Step 3: Fallback to default logic (26-hour subtraction)
|
|
108
|
-
RCTLogInfo(@"[InstantpayCodePush.mm] No custom MIN_BUNDLE_ID found, using default calculation");
|
|
108
|
+
//RCTLogInfo(@"[InstantpayCodePush.mm] No custom MIN_BUNDLE_ID found, using default calculation");
|
|
109
109
|
|
|
110
110
|
NSString *compileDateStr = [NSString stringWithFormat:@"%s %s", __DATE__, __TIME__];
|
|
111
111
|
NSDateFormatter *formatter = [[NSDateFormatter alloc] init];
|
|
@@ -117,7 +117,7 @@ RCT_EXPORT_MODULE();
|
|
|
117
117
|
NSDate *buildDate = [formatter dateFromString:compileDateStr];
|
|
118
118
|
|
|
119
119
|
if (!buildDate) {
|
|
120
|
-
RCTLogWarn(@"[InstantpayCodePush.mm] Could not parse build date: %@", compileDateStr);
|
|
120
|
+
//RCTLogWarn(@"[InstantpayCodePush.mm] Could not parse build date: %@", compileDateStr);
|
|
121
121
|
uuid = @"00000000-0000-0000-0000-000000000000";
|
|
122
122
|
return;
|
|
123
123
|
}
|
|
@@ -218,7 +218,7 @@ RCT_EXPORT_MODULE();
|
|
|
218
218
|
|
|
219
219
|
- (void)handleDownloadCompletion:(NSNotification *)notification {
|
|
220
220
|
NSURLSessionTask *task = notification.object; // Task that finished
|
|
221
|
-
RCTLogInfo(@"[InstantpayCodePush.mm] Received download completion notification for task: %@", task.originalRequest.URL);
|
|
221
|
+
//RCTLogInfo(@"[InstantpayCodePush.mm] Received download completion notification for task: %@", task.originalRequest.URL);
|
|
222
222
|
// Swift side handles KVO observer removal internally now when task finishes.
|
|
223
223
|
// No specific cleanup needed here based on this notification anymore.
|
|
224
224
|
}
|
|
@@ -247,21 +247,21 @@ RCT_EXPORT_MODULE();
|
|
|
247
247
|
|
|
248
248
|
- (void)reload:(RCTPromiseResolveBlock)resolve
|
|
249
249
|
reject:(RCTPromiseRejectBlock)reject {
|
|
250
|
-
RCTLogInfo(@"[InstantpayCodePush.mm] IpayCodePush requested a reload");
|
|
250
|
+
//RCTLogInfo(@"[InstantpayCodePush.mm] IpayCodePush requested a reload");
|
|
251
251
|
dispatch_async(dispatch_get_main_queue(), ^{
|
|
252
252
|
@try {
|
|
253
253
|
IpayCodePushImpl *impl = [InstantpayCodePush sharedImpl];
|
|
254
254
|
NSURL *bundleURL = [impl bundleURLWithBundle:[NSBundle mainBundle]];
|
|
255
|
-
RCTLogInfo(@"[InstantpayCodePush.mm] Reloading with bundle URL: %@", bundleURL);
|
|
255
|
+
//RCTLogInfo(@"[InstantpayCodePush.mm] Reloading with bundle URL: %@", bundleURL);
|
|
256
256
|
if (bundleURL && super.bridge) {
|
|
257
257
|
[super.bridge setValue:bundleURL forKey:@"bundleURL"];
|
|
258
258
|
} else if (!super.bridge) {
|
|
259
|
-
RCTLogWarn(@"[InstantpayCodePush.mm] Bridge is nil, cannot set bundleURL for reload.");
|
|
259
|
+
//RCTLogWarn(@"[InstantpayCodePush.mm] Bridge is nil, cannot set bundleURL for reload.");
|
|
260
260
|
}
|
|
261
261
|
RCTTriggerReloadCommandListeners(@"IpayCodePush requested a reload");
|
|
262
262
|
resolve(nil);
|
|
263
263
|
} @catch (NSError *error) {
|
|
264
|
-
RCTLogError(@"[InstantpayCodePush.mm] Failed to reload: %@", error);
|
|
264
|
+
//RCTLogError(@"[InstantpayCodePush.mm] Failed to reload: %@", error);
|
|
265
265
|
reject(@"RELOAD_ERROR", error.description, error);
|
|
266
266
|
}
|
|
267
267
|
});
|
|
@@ -270,7 +270,7 @@ RCT_EXPORT_MODULE();
|
|
|
270
270
|
- (void)updateBundle:(JS::NativeInstantpayCodePush::UpdateBundleParams &)params
|
|
271
271
|
resolve:(RCTPromiseResolveBlock)resolve
|
|
272
272
|
reject:(RCTPromiseRejectBlock)reject {
|
|
273
|
-
NSLog(@"[InstantpayCodePush.mm] updateBundle called.");
|
|
273
|
+
//NSLog(@"[InstantpayCodePush.mm] updateBundle called.");
|
|
274
274
|
NSMutableDictionary *paramDict = [NSMutableDictionary dictionary];
|
|
275
275
|
if (params.bundleId()) {
|
|
276
276
|
paramDict[@"bundleId"] = params.bundleId();
|
|
@@ -291,27 +291,27 @@ RCT_EXPORT_MODULE();
|
|
|
291
291
|
if (params.bundleId()) {
|
|
292
292
|
bundleId = params.bundleId();
|
|
293
293
|
}
|
|
294
|
-
NSLog(@"[InstantpayCodePush.mm] notifyAppReady called with bundleId: %@", bundleId);
|
|
294
|
+
//NSLog(@"[InstantpayCodePush.mm] notifyAppReady called with bundleId: %@", bundleId);
|
|
295
295
|
IpayCodePushImpl *impl = [InstantpayCodePush sharedImpl];
|
|
296
296
|
return [impl notifyAppReadyWithBundleId:bundleId];
|
|
297
297
|
}
|
|
298
298
|
|
|
299
299
|
- (NSArray<NSString *> *)getCrashHistory {
|
|
300
|
-
NSLog(@"[InstantpayCodePush.mm] getCrashHistory called");
|
|
300
|
+
//NSLog(@"[InstantpayCodePush.mm] getCrashHistory called");
|
|
301
301
|
IpayCodePushImpl *impl = [InstantpayCodePush sharedImpl];
|
|
302
302
|
NSArray<NSString *> *crashHistory = [impl getCrashHistory];
|
|
303
303
|
return crashHistory ?: @[];
|
|
304
304
|
}
|
|
305
305
|
|
|
306
306
|
- (NSNumber *)clearCrashHistory {
|
|
307
|
-
NSLog(@"[InstantpayCodePush.mm] clearCrashHistory called");
|
|
307
|
+
//NSLog(@"[InstantpayCodePush.mm] clearCrashHistory called");
|
|
308
308
|
IpayCodePushImpl *impl = [InstantpayCodePush sharedImpl];
|
|
309
309
|
BOOL result = [impl clearCrashHistory];
|
|
310
310
|
return @(result);
|
|
311
311
|
}
|
|
312
312
|
|
|
313
313
|
- (NSString *)getBaseURL {
|
|
314
|
-
NSLog(@"[InstantpayCodePush.mm] getBaseURL called");
|
|
314
|
+
//NSLog(@"[InstantpayCodePush.mm] getBaseURL called");
|
|
315
315
|
IpayCodePushImpl *impl = [InstantpayCodePush sharedImpl];
|
|
316
316
|
NSString *baseURL = [impl getBaseURL];
|
|
317
317
|
return baseURL ?: @"";
|
|
@@ -21,7 +21,7 @@ import os
|
|
|
21
21
|
return
|
|
22
22
|
}
|
|
23
23
|
|
|
24
|
-
let fullTagName = "\(MAIN_LOG_TAG) \(classTag)"
|
|
24
|
+
let fullTagName = "\(MAIN_LOG_TAG) \(classTag) \(String(describing: log))"
|
|
25
25
|
|
|
26
26
|
if let isEnableLog: Bool = Bundle.main.object(forInfoDictionaryKey: "IpayCodePush_Log") as! Bool? {
|
|
27
27
|
if(isEnableLog){
|
|
@@ -36,7 +36,7 @@ import os
|
|
|
36
36
|
return
|
|
37
37
|
}
|
|
38
38
|
|
|
39
|
-
let fullTagName = "\(MAIN_LOG_TAG) \(classTag)"
|
|
39
|
+
let fullTagName = "\(MAIN_LOG_TAG) \(classTag) \(String(describing: log))"
|
|
40
40
|
|
|
41
41
|
if let isEnableLog: Bool = Bundle.main.object(forInfoDictionaryKey: "IpayCodePush_Log") as! Bool? {
|
|
42
42
|
if(isEnableLog){
|
|
@@ -170,7 +170,46 @@ import React
|
|
|
170
170
|
}
|
|
171
171
|
fileUrl = url
|
|
172
172
|
}
|
|
173
|
+
|
|
174
|
+
//Verify Bundle Url Signature
|
|
175
|
+
let decryptSignatureData = SignatureVerifier.decryptSignatureUrl(bundleUrl: fileUrlString)
|
|
176
|
+
|
|
177
|
+
if (decryptSignatureData == nil){
|
|
178
|
+
let error = NSError(domain: "IpayCodePush", code: 0,
|
|
179
|
+
userInfo: [NSLocalizedDescriptionKey: "Invalid 'fileUrl' Signature: \(String(describing: fileUrl))"])
|
|
180
|
+
reject("INVALID_URL_SIGNATURE", error.localizedDescription, error)
|
|
181
|
+
return
|
|
182
|
+
}
|
|
183
|
+
|
|
184
|
+
// Convert String → Data
|
|
185
|
+
if let jsonData = decryptSignatureData!.data(using: .utf8) {
|
|
186
|
+
|
|
187
|
+
do {
|
|
188
|
+
let json = try JSONSerialization.jsonObject(
|
|
189
|
+
with: jsonData,
|
|
190
|
+
options: []
|
|
191
|
+
)
|
|
173
192
|
|
|
193
|
+
if let dictionary = json as? [String: Any] {
|
|
194
|
+
|
|
195
|
+
guard let url = URL(string: dictionary["bundleUrl"] as! String) else {
|
|
196
|
+
let error = NSError(domain: "IpayCodePush", code: 0,
|
|
197
|
+
userInfo: [NSLocalizedDescriptionKey: "Invalid bundle 'fileUrl' provided: \(dictionary["bundleUrl"] as! String)"])
|
|
198
|
+
reject("INVALID_FILE_URL", error.localizedDescription, error)
|
|
199
|
+
return
|
|
200
|
+
}
|
|
201
|
+
fileUrl = url
|
|
202
|
+
}
|
|
203
|
+
} catch {
|
|
204
|
+
let error = NSError(domain: "IpayCodePush", code: 0,
|
|
205
|
+
userInfo: [NSLocalizedDescriptionKey: "JSON parse error: Signature"])
|
|
206
|
+
reject("INVALID_URL_SIGNATURE", error.localizedDescription, error)
|
|
207
|
+
return
|
|
208
|
+
}
|
|
209
|
+
}
|
|
210
|
+
|
|
211
|
+
IpayCodePushHelper.logPrint(classTag: CLASS_TAG, log: "Bundle Url signature is valid : \(String(describing: fileUrl))")
|
|
212
|
+
|
|
174
213
|
// Extract fileHash if provided
|
|
175
214
|
let fileHash = data["fileHash"] as? String
|
|
176
215
|
|
|
@@ -7,6 +7,8 @@
|
|
|
7
7
|
|
|
8
8
|
import Foundation
|
|
9
9
|
import Security
|
|
10
|
+
import CommonCrypto
|
|
11
|
+
import LocalAuthentication
|
|
10
12
|
|
|
11
13
|
/// Prefix for signed file hash format.
|
|
12
14
|
private let SIGNED_HASH_PREFIX = "sig:"
|
|
@@ -360,15 +362,18 @@ public class SignatureVerifier {
|
|
|
360
362
|
* Get Device Public Key of generated KeyChain
|
|
361
363
|
*/
|
|
362
364
|
public static func getDevicePublicKeyBase64() -> String? {
|
|
365
|
+
|
|
366
|
+
if let privateKey = getPrivateKey() {
|
|
367
|
+
return exportPublicKeyBase64(from: privateKey)
|
|
368
|
+
}
|
|
363
369
|
|
|
364
|
-
|
|
365
|
-
|
|
370
|
+
// Generate key
|
|
371
|
+
guard let privateKey = generateKeyChain() else {
|
|
372
|
+
IpayCodePushHelper.logPrint(classTag: CLASS_TAG, log: "Key generation failed")
|
|
373
|
+
return nil
|
|
366
374
|
}
|
|
367
375
|
|
|
368
|
-
|
|
369
|
-
generateKeyChain()
|
|
370
|
-
guard let newKey = getPrivateKey() else { return nil }
|
|
371
|
-
return exportPublicKeyBase64(from: newKey)
|
|
376
|
+
return exportPublicKeyBase64(from: privateKey)
|
|
372
377
|
}
|
|
373
378
|
|
|
374
379
|
/**
|
|
@@ -376,21 +381,35 @@ public class SignatureVerifier {
|
|
|
376
381
|
* using the KeyPairGenerator API.
|
|
377
382
|
*/
|
|
378
383
|
|
|
379
|
-
private static func generateKeyChain() ->
|
|
384
|
+
private static func generateKeyChain() -> SecKey? {
|
|
380
385
|
|
|
381
386
|
let tagData = KEY_ALIAS.data(using: .utf8)!
|
|
382
387
|
|
|
388
|
+
let access = SecAccessControlCreateWithFlags(
|
|
389
|
+
nil,
|
|
390
|
+
kSecAttrAccessibleAfterFirstUnlockThisDeviceOnly,
|
|
391
|
+
[],
|
|
392
|
+
nil
|
|
393
|
+
)
|
|
394
|
+
|
|
383
395
|
let attributes: [String: Any] = [
|
|
384
396
|
kSecAttrKeyType as String: kSecAttrKeyTypeRSA,
|
|
385
397
|
kSecAttrKeySizeInBits as String: 2048,
|
|
386
|
-
kSecAttrTokenID as String: kSecAttrTokenIDSecureEnclave,
|
|
387
398
|
kSecPrivateKeyAttrs as String: [
|
|
388
399
|
kSecAttrIsPermanent as String: true,
|
|
389
|
-
kSecAttrApplicationTag as String: tagData
|
|
400
|
+
kSecAttrApplicationTag as String: tagData,
|
|
401
|
+
kSecAttrAccessControl as String: access as Any
|
|
390
402
|
]
|
|
391
403
|
]
|
|
392
404
|
|
|
393
|
-
|
|
405
|
+
var error: Unmanaged<CFError>?
|
|
406
|
+
let privateKey = SecKeyCreateRandomKey(attributes as CFDictionary, &error)
|
|
407
|
+
|
|
408
|
+
if let error = error {
|
|
409
|
+
IpayCodePushHelper.logPrint(classTag: CLASS_TAG, log: "Key generation error: \(error.takeRetainedValue() as Any)")
|
|
410
|
+
}
|
|
411
|
+
|
|
412
|
+
return privateKey
|
|
394
413
|
}
|
|
395
414
|
|
|
396
415
|
/**
|
|
@@ -408,8 +427,14 @@ public class SignatureVerifier {
|
|
|
408
427
|
]
|
|
409
428
|
|
|
410
429
|
var item: CFTypeRef?
|
|
411
|
-
SecItemCopyMatching(query as CFDictionary, &item)
|
|
412
|
-
|
|
430
|
+
let status = SecItemCopyMatching(query as CFDictionary, &item)
|
|
431
|
+
|
|
432
|
+
if status != errSecSuccess {
|
|
433
|
+
IpayCodePushHelper.logPrint(classTag: CLASS_TAG, log: "Key fetch error: \(status)")
|
|
434
|
+
return nil
|
|
435
|
+
}
|
|
436
|
+
|
|
437
|
+
return (item as! SecKey)
|
|
413
438
|
}
|
|
414
439
|
|
|
415
440
|
/**
|
|
@@ -417,10 +442,138 @@ public class SignatureVerifier {
|
|
|
417
442
|
*/
|
|
418
443
|
private static func exportPublicKeyBase64(from privateKey: SecKey) -> String? {
|
|
419
444
|
|
|
420
|
-
guard let publicKey = SecKeyCopyPublicKey(privateKey) else {
|
|
421
|
-
|
|
445
|
+
guard let publicKey = SecKeyCopyPublicKey(privateKey) else {
|
|
446
|
+
IpayCodePushHelper.logPrint(classTag: CLASS_TAG, log: "Cannot get public key")
|
|
447
|
+
return nil
|
|
448
|
+
}
|
|
449
|
+
|
|
450
|
+
var error: Unmanaged<CFError>?
|
|
451
|
+
guard let data = SecKeyCopyExternalRepresentation(publicKey, &error) as Data? else {
|
|
452
|
+
IpayCodePushHelper.logPrint(classTag: CLASS_TAG, log: "Export error: \(error?.takeRetainedValue() as Any)")
|
|
453
|
+
return nil
|
|
454
|
+
}
|
|
455
|
+
|
|
456
|
+
//return data.base64EncodedString()
|
|
457
|
+
|
|
458
|
+
// 🔥 Wrap PKCS1 key into SPKI format
|
|
459
|
+
let spkiHeader: [UInt8] = [
|
|
460
|
+
0x30, 0x82, 0x01, 0x22,
|
|
461
|
+
0x30, 0x0D,
|
|
462
|
+
0x06, 0x09,
|
|
463
|
+
0x2A, 0x86, 0x48, 0x86,
|
|
464
|
+
0xF7, 0x0D, 0x01, 0x01,
|
|
465
|
+
0x01, 0x05, 0x00,
|
|
466
|
+
0x03, 0x82, 0x01, 0x0F,
|
|
467
|
+
0x00
|
|
468
|
+
]
|
|
469
|
+
|
|
470
|
+
var spkiData = Data(spkiHeader)
|
|
471
|
+
spkiData.append(data)
|
|
472
|
+
|
|
473
|
+
return spkiData.base64EncodedString()
|
|
474
|
+
}
|
|
475
|
+
|
|
476
|
+
// MARK: - Hybrid Decrypt (RSA + AES)
|
|
477
|
+
|
|
478
|
+
/**
|
|
479
|
+
* Decrypt signature from bundle Url.
|
|
480
|
+
* @param bundleUrl The signed url
|
|
481
|
+
* @return plan Url to downlaod Bundle
|
|
482
|
+
*/
|
|
483
|
+
public static func decryptSignatureUrl(bundleUrl: String) -> String? {
|
|
484
|
+
|
|
485
|
+
IpayCodePushHelper.logPrint(classTag: CLASS_TAG, log: "Signed Bundle URL: \(bundleUrl)")
|
|
486
|
+
|
|
487
|
+
var queryParameters: [String: String] = [:]
|
|
488
|
+
|
|
489
|
+
// 1. Create a URL object from the string.
|
|
490
|
+
if let url = URL(string: bundleUrl),
|
|
491
|
+
// 2. Create a URLComponents object from the URL.
|
|
492
|
+
let urlComponents = URLComponents(url: url, resolvingAgainstBaseURL: false),
|
|
493
|
+
// 3. Access the array of URLQueryItem objects.
|
|
494
|
+
let queryItems = urlComponents.queryItems {
|
|
495
|
+
|
|
496
|
+
// 4. Iterate through the query items and populate the dictionary.
|
|
497
|
+
for item in queryItems {
|
|
498
|
+
queryParameters[item.name] = item.value
|
|
499
|
+
}
|
|
500
|
+
}
|
|
501
|
+
|
|
502
|
+
IpayCodePushHelper.logPrint(classTag: CLASS_TAG, log: "Parsed URL: \(queryParameters)")
|
|
503
|
+
|
|
504
|
+
if(queryParameters.isEmpty){
|
|
505
|
+
return nil
|
|
506
|
+
}
|
|
507
|
+
|
|
508
|
+
let signatureData = queryParameters["signatureData"]!
|
|
509
|
+
|
|
510
|
+
let encryptedKey = queryParameters["itemData"]!
|
|
511
|
+
|
|
512
|
+
let rawIv = queryParameters["raw"]!
|
|
513
|
+
|
|
514
|
+
guard let privateKey = getPrivateKey() else {
|
|
515
|
+
IpayCodePushHelper.logPrint(classTag: CLASS_TAG, log: "Private key not found to decrypt")
|
|
516
|
+
return nil
|
|
517
|
+
}
|
|
518
|
+
|
|
519
|
+
//Decode Base64
|
|
520
|
+
guard let encryptedKeyData = Data(base64Encoded: encryptedKey),
|
|
521
|
+
let ivData = Data(base64Encoded: rawIv),
|
|
522
|
+
let encryptedData = Data(base64Encoded: signatureData)
|
|
523
|
+
else {
|
|
524
|
+
IpayCodePushHelper.logPrint(classTag: CLASS_TAG, log: "Base64 decode failed in decryptSignatureUrl")
|
|
525
|
+
return nil
|
|
526
|
+
}
|
|
527
|
+
|
|
528
|
+
//RSA Decrypt AES Key (PKCS1)
|
|
529
|
+
var error: Unmanaged<CFError>?
|
|
530
|
+
guard let aesKeyData = SecKeyCreateDecryptedData(
|
|
531
|
+
privateKey,
|
|
532
|
+
.rsaEncryptionPKCS1,
|
|
533
|
+
encryptedKeyData as CFData,
|
|
534
|
+
&error
|
|
535
|
+
) as Data? else {
|
|
536
|
+
IpayCodePushHelper.logPrint(classTag: CLASS_TAG, log: "RSA decrypt failed: \(error?.takeRetainedValue() as Any)")
|
|
537
|
+
return nil
|
|
538
|
+
}
|
|
539
|
+
|
|
540
|
+
//AES-256-CBC Decrypt
|
|
541
|
+
guard aesKeyData.count == 32 else {
|
|
542
|
+
IpayCodePushHelper.logPrint(classTag: CLASS_TAG, log: "AES key must be 32 bytes (256-bit)")
|
|
543
|
+
return nil
|
|
544
|
+
}
|
|
545
|
+
|
|
546
|
+
var outLength = Int(0)
|
|
547
|
+
let outputData = NSMutableData(length: encryptedData.count + kCCBlockSizeAES128)!
|
|
548
|
+
|
|
549
|
+
let status = encryptedData.withUnsafeBytes { encryptedBytes in
|
|
550
|
+
aesKeyData.withUnsafeBytes { keyBytes in
|
|
551
|
+
ivData.withUnsafeBytes { ivBytes in
|
|
552
|
+
|
|
553
|
+
CCCrypt(
|
|
554
|
+
CCOperation(kCCDecrypt),
|
|
555
|
+
CCAlgorithm(kCCAlgorithmAES),
|
|
556
|
+
CCOptions(kCCOptionPKCS7Padding),
|
|
557
|
+
keyBytes.baseAddress,
|
|
558
|
+
aesKeyData.count,
|
|
559
|
+
ivBytes.baseAddress,
|
|
560
|
+
encryptedBytes.baseAddress,
|
|
561
|
+
encryptedData.count,
|
|
562
|
+
outputData.mutableBytes,
|
|
563
|
+
outputData.length,
|
|
564
|
+
&outLength
|
|
565
|
+
)
|
|
566
|
+
}
|
|
567
|
+
}
|
|
568
|
+
}
|
|
422
569
|
|
|
423
|
-
|
|
570
|
+
if status == kCCSuccess {
|
|
571
|
+
outputData.length = outLength
|
|
572
|
+
return String(data: outputData as Data, encoding: .utf8)
|
|
573
|
+
} else {
|
|
574
|
+
IpayCodePushHelper.logPrint(classTag: CLASS_TAG, log: "AES decrypt failed: \(status)")
|
|
575
|
+
return nil
|
|
576
|
+
}
|
|
424
577
|
}
|
|
425
578
|
|
|
426
579
|
}
|
|
@@ -11,10 +11,6 @@ export async function checkForUpdate(options) {
|
|
|
11
11
|
console.log('checkForUpdate : Running in dev mode');
|
|
12
12
|
return null;
|
|
13
13
|
}
|
|
14
|
-
if (Platform.OS == 'ios') {
|
|
15
|
-
console.log("Under Development in iOS Platform");
|
|
16
|
-
return null;
|
|
17
|
-
}
|
|
18
14
|
if (!["ios", "android"].includes(Platform.OS)) {
|
|
19
15
|
options.onError?.(new IpayCodePushError("IpayCodePush is only supported on iOS and Android"));
|
|
20
16
|
return null;
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"names":["Platform","IpayCodePushError","getAppVersion","getBundleId","getChannel","getFingerprintHash","getMinBundleId","updateBundle","checkForUpdate","options","__DEV__","debug","console","log","
|
|
1
|
+
{"version":3,"names":["Platform","IpayCodePushError","getAppVersion","getBundleId","getChannel","getFingerprintHash","getMinBundleId","updateBundle","checkForUpdate","options","__DEV__","debug","console","log","includes","OS","onError","currentAppVersion","platform","currentBundleId","minBundleId","channel","fingerprintHash","resolver","checkUpdate","updateInfo","appVersion","bundleId","updateStrategy","requestHeaders","requestTimeout","error","id","fileUrl","fileHash","status"],"sourceRoot":"../../src","sources":["checkForUpdate.ts"],"mappings":";;AAAA,SAASA,QAAQ,QAAQ,cAAc;AACvC,SAASC,iBAAiB,QAAQ,YAAS;AAE3C,SACIC,aAAa,EACbC,WAAW,EACXC,UAAU,EACVC,kBAAkB,EAClBC,cAAc,EACdC,YAAY,QACT,aAAU;;AAkCjB;;AAKA,OAAO,eAAeC,cAAcA,CAChCC,OAAsC,EACF;EACpC,IAAIC,OAAO,IAAI,CAACD,OAAO,CAACE,KAAK,EAAE;IAC3BC,OAAO,CAACC,GAAG,CAAC,sCAAsC,CAAC;IACnD,OAAO,IAAI;EACf;EAEA,IAAI,CAAC,CAAC,KAAK,EAAE,SAAS,CAAC,CAACC,QAAQ,CAACd,QAAQ,CAACe,EAAE,CAAC,EAAE;IAC3CN,OAAO,CAACO,OAAO,GACX,IAAIf,iBAAiB,CAAC,mDAAmD,CAC7E,CAAC;IACD,OAAO,IAAI;EACf;EAEA,MAAMgB,iBAAiB,GAAGf,aAAa,CAAC,CAAC;EACzC,MAAMgB,QAAQ,GAAGlB,QAAQ,CAACe,EAAuB;EACjD,MAAMI,eAAe,GAAGhB,WAAW,CAAC,CAAC;EACrC,MAAMiB,WAAW,GAAGd,cAAc,CAAC,CAAC;EACpC,MAAMe,OAAO,GAAGjB,UAAU,CAAC,CAAC;EAE5B,IAAI,CAACa,iBAAiB,EAAE;IACpBR,OAAO,CAACO,OAAO,GAAG,IAAIf,iBAAiB,CAAC,2BAA2B,CAAC,CAAC;IACrE,OAAO,IAAI;EACf;EAEA,MAAMqB,eAAe,GAAGjB,kBAAkB,CAAC,CAAC;EAE5C,IAAI,CAACI,OAAO,CAACc,QAAQ,EAAEC,WAAW,EAAE;IAChCf,OAAO,CAACO,OAAO,GACX,IAAIf,iBAAiB,CAAC,yCAAyC,CACnE,CAAC;IACD,OAAO,IAAI;EACf;EAEA,IAAIwB,UAAgC,GAAG,IAAI;EAE3C,IAAI;IACAA,UAAU,GAAG,MAAMhB,OAAO,CAACc,QAAQ,CAACC,WAAW,CAAC;MAC5CN,QAAQ;MACRQ,UAAU,EAAET,iBAAiB;MAC7BU,QAAQ,EAAER,eAAe;MACzBC,WAAW;MACXC,OAAO;MACPO,cAAc,EAAEnB,OAAO,CAACmB,cAAc;MACtCN,eAAe;MACfO,cAAc,EAAEpB,OAAO,CAACoB,cAAc;MACtCC,cAAc,EAAErB,OAAO,CAACqB;IAC5B,CAAC,CAAC;EACN,CAAC,CAAC,OAAOC,KAAK,EAAE;IACZtB,OAAO,CAACO,OAAO,GAAGe,KAAc,CAAC;IACjC,OAAO,IAAI;EACf;EAEA,IAAI,CAACN,UAAU,EAAE;IACb,OAAO,IAAI;EACf;EAEA,OAAO;IACH,GAAGA,UAAU;IACblB,YAAY,EAAE,MAAAA,CAAA,KAAY;MACtB,OAAOA,YAAY,CAAC;QAChBoB,QAAQ,EAAEF,UAAU,CAACO,EAAE;QACvBC,OAAO,EAAER,UAAU,CAACQ,OAAO;QAC3BC,QAAQ,EAAET,UAAU,CAACS,QAAQ;QAC7BC,MAAM,EAAEV,UAAU,CAACU;MACvB,CAAC,CAAC;IACN;EACJ,CAAC;AACL","ignoreList":[]}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"checkForUpdate.d.ts","sourceRoot":"","sources":["../../../src/checkForUpdate.ts"],"names":[],"mappings":"AAYA,OAAO,KAAK,EAAE,oBAAoB,EAAE,aAAa,EAAE,MAAM,SAAS,CAAC;AAGnE,MAAM,WAAW,qBAAqB;IAClC;;;;;OAKG;IACH,cAAc,EAAE,YAAY,GAAG,aAAa,CAAC;IAE7C,cAAc,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC;IAExC,OAAO,CAAC,EAAE,CAAC,KAAK,EAAE,KAAK,KAAK,IAAI,CAAC;IACjC;;;OAGG;IACH,cAAc,CAAC,EAAE,MAAM,CAAC;IAExB,KAAK,CAAC,EAAE,OAAO,CAAC;CACnB;AAED,MAAM,MAAM,oBAAoB,GAAG,aAAa,GAAG;IAC/C;;;OAGG;IACH,YAAY,EAAE,MAAM,OAAO,CAAC,OAAO,CAAC,CAAC;CACxC,CAAC;AAGF,MAAM,WAAW,6BAA8B,SAAQ,qBAAqB;IACxE,QAAQ,EAAE,oBAAoB,CAAC;CAClC;AAED,wBAAsB,cAAc,CAChC,OAAO,EAAE,6BAA6B,GACvC,OAAO,CAAC,oBAAoB,GAAG,IAAI,CAAC,
|
|
1
|
+
{"version":3,"file":"checkForUpdate.d.ts","sourceRoot":"","sources":["../../../src/checkForUpdate.ts"],"names":[],"mappings":"AAYA,OAAO,KAAK,EAAE,oBAAoB,EAAE,aAAa,EAAE,MAAM,SAAS,CAAC;AAGnE,MAAM,WAAW,qBAAqB;IAClC;;;;;OAKG;IACH,cAAc,EAAE,YAAY,GAAG,aAAa,CAAC;IAE7C,cAAc,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC;IAExC,OAAO,CAAC,EAAE,CAAC,KAAK,EAAE,KAAK,KAAK,IAAI,CAAC;IACjC;;;OAGG;IACH,cAAc,CAAC,EAAE,MAAM,CAAC;IAExB,KAAK,CAAC,EAAE,OAAO,CAAC;CACnB;AAED,MAAM,MAAM,oBAAoB,GAAG,aAAa,GAAG;IAC/C;;;OAGG;IACH,YAAY,EAAE,MAAM,OAAO,CAAC,OAAO,CAAC,CAAC;CACxC,CAAC;AAGF,MAAM,WAAW,6BAA8B,SAAQ,qBAAqB;IACxE,QAAQ,EAAE,oBAAoB,CAAC;CAClC;AAED,wBAAsB,cAAc,CAChC,OAAO,EAAE,6BAA6B,GACvC,OAAO,CAAC,oBAAoB,GAAG,IAAI,CAAC,CAmEtC"}
|
package/package.json
CHANGED
package/src/checkForUpdate.ts
CHANGED
|
@@ -55,11 +55,6 @@ export async function checkForUpdate(
|
|
|
55
55
|
return null;
|
|
56
56
|
}
|
|
57
57
|
|
|
58
|
-
if(Platform.OS == 'ios'){
|
|
59
|
-
console.log("Under Development in iOS Platform");
|
|
60
|
-
return null;
|
|
61
|
-
}
|
|
62
|
-
|
|
63
58
|
if (!["ios", "android"].includes(Platform.OS)) {
|
|
64
59
|
options.onError?.(
|
|
65
60
|
new IpayCodePushError("IpayCodePush is only supported on iOS and Android"),
|