@onekeyfe/react-native-bundle-update 3.0.95 → 3.0.96

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.
@@ -0,0 +1,22 @@
1
+ package com.margelo.nitro.reactnativebundleupdate
2
+
3
+ internal object BundleStorageSchemaPolicy {
4
+ const val METADATA_KEY = "storageSchemaVersion"
5
+ const val SUPPORTED_VERSION = "mmkv-v1"
6
+ const val LEDGER_PREFS_NAME = "onekey_native_storage_migration"
7
+ private val ledgerKeys = listOf("app-storage-v1", "jotai-storage-v1")
8
+
9
+ fun isCompatible(
10
+ declaredVersion: String?,
11
+ readMigrationLedger: (String) -> String?,
12
+ ): Boolean {
13
+ if (!declaredVersion.isNullOrEmpty()) {
14
+ return declaredVersion == SUPPORTED_VERSION
15
+ }
16
+
17
+ // Old apps do not write this ledger and may keep using unmarked bundles.
18
+ // Any non-empty state (including an interrupted migration or reset)
19
+ // forbids returning to the retained AsyncStorage database.
20
+ return ledgerKeys.none { key -> !readMigrationLedger(key).isNullOrEmpty() }
21
+ }
22
+ }
@@ -428,7 +428,8 @@ object BundleUpdateStoreAndroid {
428
428
  return key == METADATA_REQUIRES_BACKGROUND_BUNDLE_KEY ||
429
429
  key == METADATA_BACKGROUND_PROTOCOL_VERSION_KEY ||
430
430
  key == METADATA_REQUIRES_COMMON_BUNDLE_KEY ||
431
- key == METADATA_BUNDLE_FORMAT_KEY
431
+ key == METADATA_BUNDLE_FORMAT_KEY ||
432
+ key == BundleStorageSchemaPolicy.METADATA_KEY
432
433
  }
433
434
 
434
435
  private fun getFileMetadataEntries(metadata: Map<String, String>): Map<String, String> {
@@ -458,6 +459,17 @@ object BundleUpdateStoreAndroid {
458
459
  return metadata[METADATA_BACKGROUND_PROTOCOL_VERSION_KEY] ?: ""
459
460
  }
460
461
 
462
+ private fun validateStorageSchemaCompatibility(context: Context, metadata: Map<String, String>): Boolean {
463
+ val compatible = BundleStorageSchemaPolicy.isCompatible(metadata[BundleStorageSchemaPolicy.METADATA_KEY]) { key ->
464
+ context.getSharedPreferences(BundleStorageSchemaPolicy.LEDGER_PREFS_NAME, Context.MODE_PRIVATE)
465
+ .getString(key, null)
466
+ }
467
+ if (!compatible) {
468
+ OneKeyLog.error("BundleUpdate", "Bundle storage schema is incompatible with the native migration state")
469
+ }
470
+ return compatible
471
+ }
472
+
461
473
  fun readMetadataFileSha256(signature: String?): String? {
462
474
  if (signature.isNullOrEmpty()) return null
463
475
 
@@ -635,6 +647,17 @@ object BundleUpdateStoreAndroid {
635
647
  }
636
648
  }
637
649
 
650
+ fun validateBundlePairCompatibility(
651
+ context: Context,
652
+ bundleDir: String,
653
+ metadata: Map<String, String>,
654
+ ): Boolean {
655
+ return validateStorageSchemaCompatibility(context, metadata) &&
656
+ validateBundlePairCompatibility(bundleDir, metadata)
657
+ }
658
+
659
+ // Retain the original layout-validator signature for existing native callers.
660
+ // Startup and extracted-bundle validation use the context overload.
638
661
  fun validateBundlePairCompatibility(bundleDir: String, metadata: Map<String, String>): Boolean {
639
662
  val mainBundleFile = File(bundleDir, MAIN_JS_BUNDLE_FILE_NAME)
640
663
  if (!mainBundleFile.exists()) {
@@ -706,6 +729,12 @@ object BundleUpdateStoreAndroid {
706
729
  // startup.
707
730
  cachedValidatedBundleInfo?.let { cached ->
708
731
  if (cached.currentBundleVersion == currentBundleVersion) {
732
+ // Migration state can change while the native bundle cache survives
733
+ // a JS runtime reload. Recheck the ledger without repeating hashes.
734
+ if (!validateStorageSchemaCompatibility(context, cached.metadata)) {
735
+ invalidateValidatedBundleInfoCache()
736
+ return null
737
+ }
709
738
  return cached
710
739
  }
711
740
  }
@@ -774,7 +803,7 @@ object BundleUpdateStoreAndroid {
774
803
  return null
775
804
  }
776
805
 
777
- if (!validateBundlePairCompatibility(bundleDir, metadata)) {
806
+ if (!validateBundlePairCompatibility(context, bundleDir, metadata)) {
778
807
  return null
779
808
  }
780
809
 
@@ -1727,7 +1756,7 @@ class ReactNativeBundleUpdate : HybridReactNativeBundleUpdateSpec() {
1727
1756
  BundleUpdateStoreAndroid.deleteDir(destinationDir)
1728
1757
  throw Exception("Extracted files verification against metadata failed")
1729
1758
  }
1730
- if (!BundleUpdateStoreAndroid.validateBundlePairCompatibility(destination, metadata)) {
1759
+ if (!BundleUpdateStoreAndroid.validateBundlePairCompatibility(context, destination, metadata)) {
1731
1760
  OneKeyLog.error("BundleUpdate", "verifyBundleASC: bundle pair compatibility check failed")
1732
1761
  BundleUpdateStoreAndroid.deleteDir(destinationDir)
1733
1762
  throw Exception("Bundle pair compatibility check failed")
@@ -2308,7 +2337,7 @@ n2DMz6gqk326W6SFynYtvuiXo7wG4Cmn3SuIU8xfv9rJqunpZGYchMd7nZektmEJ
2308
2337
  OneKeyLog.error("BundleUpdate", "verifyExtractedBundle: file integrity check failed")
2309
2338
  throw Exception("File integrity check failed")
2310
2339
  }
2311
- if (!BundleUpdateStoreAndroid.validateBundlePairCompatibility(bundlePath.absolutePath, metadata)) {
2340
+ if (!BundleUpdateStoreAndroid.validateBundlePairCompatibility(context, bundlePath.absolutePath, metadata)) {
2312
2341
  OneKeyLog.error("BundleUpdate", "verifyExtractedBundle: bundle pair compatibility check failed")
2313
2342
  throw Exception("Bundle pair compatibility check failed")
2314
2343
  }
@@ -0,0 +1,22 @@
1
+ enum BundleStorageSchemaPolicy {
2
+ static let metadataKey = "storageSchemaVersion"
3
+ static let supportedVersion = "mmkv-v1"
4
+ static let ledgerPrefix = "onekey_native_storage_migration_"
5
+ private static let ledgerKeys = ["app-storage-v1", "jotai-storage-v1"]
6
+
7
+ static func isCompatible(
8
+ declaredVersion: String?,
9
+ readMigrationLedger: (String) -> String?
10
+ ) -> Bool {
11
+ if let declaredVersion, !declaredVersion.isEmpty {
12
+ return declaredVersion == supportedVersion
13
+ }
14
+
15
+ // Old apps do not write this ledger and may keep using unmarked bundles.
16
+ // Any non-empty state (including an interrupted migration or reset)
17
+ // forbids returning to the retained AsyncStorage database.
18
+ return !ledgerKeys.contains { key in
19
+ !(readMigrationLedger(ledgerPrefix + key) ?? "").isEmpty
20
+ }
21
+ }
22
+ }
@@ -439,7 +439,8 @@ public class BundleUpdateStore: NSObject {
439
439
  key == metadataRequiresBackgroundBundleKey ||
440
440
  key == metadataBackgroundProtocolVersionKey ||
441
441
  key == metadataRequiresCommonBundleKey ||
442
- key == metadataBundleFormatKey
442
+ key == metadataBundleFormatKey ||
443
+ key == BundleStorageSchemaPolicy.metadataKey
443
444
  }
444
445
 
445
446
  private static func metadataStringValue(
@@ -474,6 +475,17 @@ public class BundleUpdateStore: NSObject {
474
475
  return false
475
476
  }
476
477
 
478
+ private static func validateStorageSchemaCompatibility(_ metadata: [String: Any]) -> Bool {
479
+ let declaredVersion = metadataStringValue(metadata, key: BundleStorageSchemaPolicy.metadataKey)
480
+ let compatible = BundleStorageSchemaPolicy.isCompatible(declaredVersion: declaredVersion) { key in
481
+ UserDefaults.standard.string(forKey: key)
482
+ }
483
+ if !compatible {
484
+ OneKeyLog.error("BundleUpdate", "Bundle storage schema is incompatible with the native migration state")
485
+ }
486
+ return compatible
487
+ }
488
+
477
489
  private static func fileMetadataEntries(
478
490
  from metadata: [String: Any],
479
491
  ) -> [String: String] {
@@ -567,6 +579,9 @@ public class BundleUpdateStore: NSObject {
567
579
  bundleDirPath: String,
568
580
  metadata: [String: Any],
569
581
  ) -> Bool {
582
+ if !validateStorageSchemaCompatibility(metadata) {
583
+ return false
584
+ }
570
585
  let mainBundlePath = (bundleDirPath as NSString)
571
586
  .appendingPathComponent(mainBundleEntryFileName)
572
587
  guard FileManager.default.fileExists(atPath: mainBundlePath) else {
@@ -647,6 +662,12 @@ public class BundleUpdateStore: NSObject {
647
662
  cachedValidatedBundleInfoLock.lock()
648
663
  if let cached = cachedValidatedBundleInfo, cached.currentBundleVersion == currentBundleVer {
649
664
  cachedValidatedBundleInfoLock.unlock()
665
+ // Migration state can change while the native bundle cache survives
666
+ // a JS runtime reload. Recheck the ledger without repeating hashes.
667
+ if !validateStorageSchemaCompatibility(cached.metadata) {
668
+ invalidateValidatedBundleInfoCache()
669
+ return nil
670
+ }
650
671
  return cached
651
672
  }
652
673
  cachedValidatedBundleInfoLock.unlock()
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@onekeyfe/react-native-bundle-update",
3
- "version": "3.0.95",
3
+ "version": "3.0.96",
4
4
  "description": "react-native-bundle-update",
5
5
  "main": "./lib/module/index.js",
6
6
  "types": "./lib/typescript/src/index.d.ts",