@hot-updater/react-native 1.0.0-rc.4 → 1.0.0-rc.40

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.
Files changed (306) hide show
  1. package/android/build.gradle +13 -2
  2. package/android/proguard-rules.pro +8 -2
  3. package/android/src/bridge/BridgeReactInstance.kt +38 -0
  4. package/android/src/bridgeless/BridgeReactInstance.kt +24 -0
  5. package/android/src/main/java/com/hotupdater/ActivityStartGate.kt +94 -0
  6. package/android/src/main/java/com/hotupdater/BuiltInAssetResolver.kt +286 -0
  7. package/android/src/main/java/com/hotupdater/BundleFileStorageService.kt +1064 -844
  8. package/android/src/main/java/com/hotupdater/BundleMetadata.kt +50 -11
  9. package/android/src/main/java/com/hotupdater/FileManagerService.kt +45 -0
  10. package/android/src/main/java/com/hotupdater/HotUpdaterException.kt +287 -22
  11. package/android/src/main/java/com/hotupdater/HotUpdaterImpl.kt +46 -30
  12. package/android/src/main/java/com/hotupdater/HotUpdaterRecoveryManager.kt +75 -192
  13. package/android/src/main/java/com/hotupdater/HotUpdaterRecoveryState.kt +64 -0
  14. package/android/src/main/java/com/hotupdater/InstallIdentityService.kt +37 -0
  15. package/android/src/main/java/com/hotupdater/KeyValueStorageService.kt +86 -0
  16. package/android/src/main/java/com/hotupdater/NetworkState.kt +31 -0
  17. package/android/src/main/java/com/hotupdater/NoBackupStorage.kt +17 -0
  18. package/android/src/main/java/com/hotupdater/OkHttpDownloadService.kt +127 -50
  19. package/android/src/main/java/com/hotupdater/ReactNativeValueConverters.kt +34 -0
  20. package/android/src/main/java/com/hotupdater/TarArchiveInputStream.kt +214 -375
  21. package/android/src/main/java/com/hotupdater/TarBrArchiveExtractor.kt +119 -0
  22. package/android/src/newarch/HotUpdater.kt +7 -9
  23. package/android/src/newarch/HotUpdaterModule.kt +109 -84
  24. package/android/src/newarch/JavaScriptExceptionHooks.kt +48 -0
  25. package/android/src/newarch/ReactIntegrationManager.kt +6 -32
  26. package/android/src/oldarch/HotUpdater.kt +7 -9
  27. package/android/src/oldarch/HotUpdaterModule.kt +98 -74
  28. package/android/src/oldarch/HotUpdaterSpec.kt +4 -6
  29. package/android/src/oldarch/JavaScriptExceptionHooks.kt +71 -0
  30. package/ios/HotUpdater/Internal/BrotliFileDecompressor.swift +167 -0
  31. package/ios/HotUpdater/Internal/BuiltInAssetResolver.swift +196 -0
  32. package/ios/HotUpdater/Internal/BundleFileStorageService.swift +1032 -1116
  33. package/ios/HotUpdater/Internal/BundleMetadata.swift +61 -54
  34. package/ios/HotUpdater/Internal/FileManagerService.swift +48 -0
  35. package/ios/HotUpdater/Internal/FileUtilities.swift +64 -0
  36. package/ios/HotUpdater/Internal/HotUpdater-Bridging-Header.h +0 -1
  37. package/ios/HotUpdater/Internal/HotUpdater.mm +32 -67
  38. package/ios/HotUpdater/Internal/HotUpdaterImpl.swift +229 -73
  39. package/ios/HotUpdater/Internal/KeyValueStorageService.swift +71 -0
  40. package/ios/HotUpdater/Internal/NotificationExtension.swift +0 -2
  41. package/ios/HotUpdater/Internal/TarArchiveExtractor.swift +182 -311
  42. package/ios/HotUpdater/Internal/URLSessionDownloadService.swift +119 -71
  43. package/ios/HotUpdater/Internal/UpdateFailure.swift +390 -0
  44. package/ios/HotUpdater/Recovery/HotUpdaterRecovery.h +16 -0
  45. package/ios/HotUpdater/Recovery/HotUpdaterRecovery.mm +83 -0
  46. package/ios/HotUpdater/Recovery/HotUpdaterRecoveryHooks.mm +49 -0
  47. package/lib/commonjs/appReady.js +102 -0
  48. package/lib/commonjs/appReady.js.map +1 -0
  49. package/lib/commonjs/checkForUpdate.js +120 -68
  50. package/lib/commonjs/checkForUpdate.js.map +1 -1
  51. package/lib/commonjs/clientPlugin.js +13 -0
  52. package/lib/commonjs/clientPlugin.js.map +1 -0
  53. package/lib/commonjs/error.js +4 -13
  54. package/lib/commonjs/error.js.map +1 -1
  55. package/lib/commonjs/fetchJSON.js +16 -27
  56. package/lib/commonjs/fetchJSON.js.map +1 -1
  57. package/lib/commonjs/fetchUpdateResponse.js +60 -0
  58. package/lib/commonjs/fetchUpdateResponse.js.map +1 -0
  59. package/lib/commonjs/httpClient.js +63 -94
  60. package/lib/commonjs/httpClient.js.map +1 -1
  61. package/lib/commonjs/index.js +71 -18
  62. package/lib/commonjs/index.js.map +1 -1
  63. package/lib/commonjs/native.js +74 -60
  64. package/lib/commonjs/native.js.map +1 -1
  65. package/lib/commonjs/pluginHost.js +45 -0
  66. package/lib/commonjs/pluginHost.js.map +1 -0
  67. package/lib/commonjs/releaseCatalogCache.js +36 -87
  68. package/lib/commonjs/releaseCatalogCache.js.map +1 -1
  69. package/lib/commonjs/sdkVersion.js +1 -1
  70. package/lib/commonjs/sdkVersion.js.map +1 -1
  71. package/lib/commonjs/specs/NativeHotUpdater.js.map +1 -1
  72. package/lib/commonjs/store.js +3 -10
  73. package/lib/commonjs/store.js.map +1 -1
  74. package/lib/commonjs/updateError.js +145 -0
  75. package/lib/commonjs/updateError.js.map +1 -0
  76. package/lib/commonjs/wrap.js +43 -26
  77. package/lib/commonjs/wrap.js.map +1 -1
  78. package/lib/module/appReady.js +95 -0
  79. package/lib/module/appReady.js.map +1 -0
  80. package/lib/module/checkForUpdate.js +113 -63
  81. package/lib/module/checkForUpdate.js.map +1 -1
  82. package/lib/module/clientPlugin.js +4 -0
  83. package/lib/module/clientPlugin.js.map +1 -0
  84. package/lib/module/error.js +4 -13
  85. package/lib/module/error.js.map +1 -1
  86. package/lib/module/fetchJSON.js +14 -26
  87. package/lib/module/fetchJSON.js.map +1 -1
  88. package/lib/module/fetchUpdateResponse.js +55 -0
  89. package/lib/module/fetchUpdateResponse.js.map +1 -0
  90. package/lib/module/httpClient.js +62 -93
  91. package/lib/module/httpClient.js.map +1 -1
  92. package/lib/module/index.js +58 -20
  93. package/lib/module/index.js.map +1 -1
  94. package/lib/module/native.js +67 -53
  95. package/lib/module/native.js.map +1 -1
  96. package/lib/module/pluginHost.js +36 -0
  97. package/lib/module/pluginHost.js.map +1 -0
  98. package/lib/module/releaseCatalogCache.js +32 -82
  99. package/lib/module/releaseCatalogCache.js.map +1 -1
  100. package/lib/module/sdkVersion.js +1 -1
  101. package/lib/module/sdkVersion.js.map +1 -1
  102. package/lib/module/specs/NativeHotUpdater.js.map +1 -1
  103. package/lib/module/store.js +3 -10
  104. package/lib/module/store.js.map +1 -1
  105. package/lib/module/updateError.js +139 -0
  106. package/lib/module/updateError.js.map +1 -0
  107. package/lib/module/wrap.js +43 -26
  108. package/lib/module/wrap.js.map +1 -1
  109. package/lib/typescript/commonjs/appReady.d.ts +21 -0
  110. package/lib/typescript/commonjs/appReady.d.ts.map +1 -0
  111. package/lib/typescript/commonjs/checkForUpdate.d.ts +16 -4
  112. package/lib/typescript/commonjs/checkForUpdate.d.ts.map +1 -1
  113. package/lib/typescript/commonjs/clientPlugin.d.ts +2 -0
  114. package/lib/typescript/commonjs/clientPlugin.d.ts.map +1 -0
  115. package/lib/typescript/commonjs/error.d.ts +4 -13
  116. package/lib/typescript/commonjs/error.d.ts.map +1 -1
  117. package/lib/typescript/commonjs/fetchJSON.d.ts +5 -5
  118. package/lib/typescript/commonjs/fetchJSON.d.ts.map +1 -1
  119. package/lib/typescript/commonjs/fetchUpdateResponse.d.ts +14 -0
  120. package/lib/typescript/commonjs/fetchUpdateResponse.d.ts.map +1 -0
  121. package/lib/typescript/commonjs/httpClient.d.ts +4 -33
  122. package/lib/typescript/commonjs/httpClient.d.ts.map +1 -1
  123. package/lib/typescript/commonjs/index.d.ts +4 -8
  124. package/lib/typescript/commonjs/index.d.ts.map +1 -1
  125. package/lib/typescript/commonjs/native.d.ts +29 -22
  126. package/lib/typescript/commonjs/native.d.ts.map +1 -1
  127. package/lib/typescript/commonjs/pluginHost.d.ts +4 -0
  128. package/lib/typescript/commonjs/pluginHost.d.ts.map +1 -0
  129. package/lib/typescript/commonjs/releaseCatalogCache.d.ts +8 -14
  130. package/lib/typescript/commonjs/releaseCatalogCache.d.ts.map +1 -1
  131. package/lib/typescript/commonjs/sdkVersion.d.ts +1 -1
  132. package/lib/typescript/commonjs/sdkVersion.d.ts.map +1 -1
  133. package/lib/typescript/commonjs/specs/NativeHotUpdater.d.ts +35 -47
  134. package/lib/typescript/commonjs/specs/NativeHotUpdater.d.ts.map +1 -1
  135. package/lib/typescript/commonjs/store.d.ts +1 -3
  136. package/lib/typescript/commonjs/store.d.ts.map +1 -1
  137. package/lib/typescript/commonjs/types.d.ts +1 -1
  138. package/lib/typescript/commonjs/types.d.ts.map +1 -1
  139. package/lib/typescript/commonjs/updateError.d.ts +26 -0
  140. package/lib/typescript/commonjs/updateError.d.ts.map +1 -0
  141. package/lib/typescript/commonjs/wrap.d.ts.map +1 -1
  142. package/lib/typescript/commonjs/wrap.types.d.ts +6 -7
  143. package/lib/typescript/commonjs/wrap.types.d.ts.map +1 -1
  144. package/lib/typescript/module/appReady.d.ts +21 -0
  145. package/lib/typescript/module/appReady.d.ts.map +1 -0
  146. package/lib/typescript/module/checkForUpdate.d.ts +16 -4
  147. package/lib/typescript/module/checkForUpdate.d.ts.map +1 -1
  148. package/lib/typescript/module/clientPlugin.d.ts +2 -0
  149. package/lib/typescript/module/clientPlugin.d.ts.map +1 -0
  150. package/lib/typescript/module/error.d.ts +4 -13
  151. package/lib/typescript/module/error.d.ts.map +1 -1
  152. package/lib/typescript/module/fetchJSON.d.ts +5 -5
  153. package/lib/typescript/module/fetchJSON.d.ts.map +1 -1
  154. package/lib/typescript/module/fetchUpdateResponse.d.ts +14 -0
  155. package/lib/typescript/module/fetchUpdateResponse.d.ts.map +1 -0
  156. package/lib/typescript/module/httpClient.d.ts +4 -33
  157. package/lib/typescript/module/httpClient.d.ts.map +1 -1
  158. package/lib/typescript/module/index.d.ts +4 -8
  159. package/lib/typescript/module/index.d.ts.map +1 -1
  160. package/lib/typescript/module/native.d.ts +29 -22
  161. package/lib/typescript/module/native.d.ts.map +1 -1
  162. package/lib/typescript/module/pluginHost.d.ts +4 -0
  163. package/lib/typescript/module/pluginHost.d.ts.map +1 -0
  164. package/lib/typescript/module/releaseCatalogCache.d.ts +8 -14
  165. package/lib/typescript/module/releaseCatalogCache.d.ts.map +1 -1
  166. package/lib/typescript/module/sdkVersion.d.ts +1 -1
  167. package/lib/typescript/module/sdkVersion.d.ts.map +1 -1
  168. package/lib/typescript/module/specs/NativeHotUpdater.d.ts +35 -47
  169. package/lib/typescript/module/specs/NativeHotUpdater.d.ts.map +1 -1
  170. package/lib/typescript/module/store.d.ts +1 -3
  171. package/lib/typescript/module/store.d.ts.map +1 -1
  172. package/lib/typescript/module/types.d.ts +1 -1
  173. package/lib/typescript/module/types.d.ts.map +1 -1
  174. package/lib/typescript/module/updateError.d.ts +26 -0
  175. package/lib/typescript/module/updateError.d.ts.map +1 -0
  176. package/lib/typescript/module/wrap.d.ts.map +1 -1
  177. package/lib/typescript/module/wrap.types.d.ts +6 -7
  178. package/lib/typescript/module/wrap.types.d.ts.map +1 -1
  179. package/package.json +7 -4
  180. package/src/appReady.ts +141 -0
  181. package/src/checkForUpdate.ts +145 -86
  182. package/src/clientPlugin.ts +18 -0
  183. package/src/error.ts +4 -14
  184. package/src/fetchJSON.ts +14 -30
  185. package/src/fetchUpdateResponse.ts +60 -0
  186. package/src/httpClient.ts +88 -159
  187. package/src/index.ts +90 -24
  188. package/src/native.ts +98 -102
  189. package/src/pluginHost.ts +47 -0
  190. package/src/releaseCatalogCache.ts +43 -172
  191. package/src/sdkVersion.ts +1 -1
  192. package/src/specs/NativeHotUpdater.ts +34 -48
  193. package/src/store.ts +2 -23
  194. package/src/types.ts +1 -1
  195. package/src/updateError.ts +167 -0
  196. package/src/wrap.tsx +57 -26
  197. package/src/wrap.types.ts +6 -7
  198. package/android/src/main/java/com/hotupdater/DecompressService.kt +0 -89
  199. package/android/src/main/java/com/hotupdater/DecompressionStrategy.kt +0 -26
  200. package/android/src/main/java/com/hotupdater/TarBrDecompressionStrategy.kt +0 -117
  201. package/android/src/main/java/com/hotupdater/TarGzDecompressionStrategy.kt +0 -117
  202. package/android/src/main/java/com/hotupdater/ZipDecompressionStrategy.kt +0 -192
  203. package/android/src/test/java/com/hotupdater/BsdiffPatchTest.kt +0 -46
  204. package/android/src/test/java/com/hotupdater/BundleFileStorageServiceTest.kt +0 -799
  205. package/android/src/test/java/com/hotupdater/HotUpdaterImplTest.kt +0 -273
  206. package/android/src/test/java/com/hotupdater/NativeConfigUtilsTest.kt +0 -20
  207. package/android/src/test/java/com/hotupdater/OkHttpDownloadServiceTest.kt +0 -111
  208. package/android/src/test/java/com/hotupdater/RelativePathResolverTest.kt +0 -41
  209. package/android/src/test/java/com/hotupdater/ReleaseCatalogCacheServiceTest.kt +0 -118
  210. package/android/src/test/java/com/hotupdater/TarArchiveInputStreamTest.kt +0 -68
  211. package/ios/HotUpdater/Internal/ArchiveExtractionUtilities.swift +0 -178
  212. package/ios/HotUpdater/Internal/DecompressService.swift +0 -112
  213. package/ios/HotUpdater/Internal/DecompressionStrategy.swift +0 -22
  214. package/ios/HotUpdater/Internal/StreamingTarArchiveExtractor.swift +0 -370
  215. package/ios/HotUpdater/Internal/TarBrDecompressionStrategy.swift +0 -39
  216. package/ios/HotUpdater/Internal/TarGzDecompressionStrategy.swift +0 -59
  217. package/ios/HotUpdater/Internal/ZipArchiveExtractor.swift +0 -482
  218. package/ios/HotUpdater/Internal/ZipDecompressionStrategy.swift +0 -56
  219. package/lib/commonjs/catalogCacheNative.spec.js +0 -31
  220. package/lib/commonjs/catalogCacheNative.spec.js.map +0 -1
  221. package/lib/commonjs/checkForUpdate.releaseCatalog.spec.js +0 -616
  222. package/lib/commonjs/checkForUpdate.releaseCatalog.spec.js.map +0 -1
  223. package/lib/commonjs/httpClient.spec.js +0 -102
  224. package/lib/commonjs/httpClient.spec.js.map +0 -1
  225. package/lib/commonjs/index.spec.js +0 -302
  226. package/lib/commonjs/index.spec.js.map +0 -1
  227. package/lib/commonjs/iosInterop.spec.js +0 -18
  228. package/lib/commonjs/iosInterop.spec.js.map +0 -1
  229. package/lib/commonjs/native.spec.js +0 -883
  230. package/lib/commonjs/native.spec.js.map +0 -1
  231. package/lib/commonjs/notifyAppReadyInsights.boundary.spec.js +0 -218
  232. package/lib/commonjs/notifyAppReadyInsights.boundary.spec.js.map +0 -1
  233. package/lib/commonjs/notifyAppReadyInsights.js +0 -133
  234. package/lib/commonjs/notifyAppReadyInsights.js.map +0 -1
  235. package/lib/commonjs/notifyAppReadyInsights.spec.js +0 -246
  236. package/lib/commonjs/notifyAppReadyInsights.spec.js.map +0 -1
  237. package/lib/commonjs/notifyAppReadyInsights.test-utils.js +0 -24
  238. package/lib/commonjs/notifyAppReadyInsights.test-utils.js.map +0 -1
  239. package/lib/commonjs/notifyAppReadyInsights.transport.spec.js +0 -117
  240. package/lib/commonjs/notifyAppReadyInsights.transport.spec.js.map +0 -1
  241. package/lib/commonjs/releaseCatalogCache.spec.js +0 -195
  242. package/lib/commonjs/releaseCatalogCache.spec.js.map +0 -1
  243. package/lib/commonjs/releaseCatalogCacheNativeContract.spec.js +0 -64
  244. package/lib/commonjs/releaseCatalogCacheNativeContract.spec.js.map +0 -1
  245. package/lib/commonjs/store.notification.spec.js +0 -76
  246. package/lib/commonjs/store.notification.spec.js.map +0 -1
  247. package/lib/commonjs/store.spec.js +0 -316
  248. package/lib/commonjs/store.spec.js.map +0 -1
  249. package/lib/commonjs/wrap.spec.js +0 -329
  250. package/lib/commonjs/wrap.spec.js.map +0 -1
  251. package/lib/module/catalogCacheNative.spec.js +0 -31
  252. package/lib/module/catalogCacheNative.spec.js.map +0 -1
  253. package/lib/module/checkForUpdate.releaseCatalog.spec.js +0 -615
  254. package/lib/module/checkForUpdate.releaseCatalog.spec.js.map +0 -1
  255. package/lib/module/httpClient.spec.js +0 -102
  256. package/lib/module/httpClient.spec.js.map +0 -1
  257. package/lib/module/index.spec.js +0 -301
  258. package/lib/module/index.spec.js.map +0 -1
  259. package/lib/module/iosInterop.spec.js +0 -18
  260. package/lib/module/iosInterop.spec.js.map +0 -1
  261. package/lib/module/native.spec.js +0 -882
  262. package/lib/module/native.spec.js.map +0 -1
  263. package/lib/module/notifyAppReadyInsights.boundary.spec.js +0 -217
  264. package/lib/module/notifyAppReadyInsights.boundary.spec.js.map +0 -1
  265. package/lib/module/notifyAppReadyInsights.js +0 -128
  266. package/lib/module/notifyAppReadyInsights.js.map +0 -1
  267. package/lib/module/notifyAppReadyInsights.spec.js +0 -245
  268. package/lib/module/notifyAppReadyInsights.spec.js.map +0 -1
  269. package/lib/module/notifyAppReadyInsights.test-utils.js +0 -18
  270. package/lib/module/notifyAppReadyInsights.test-utils.js.map +0 -1
  271. package/lib/module/notifyAppReadyInsights.transport.spec.js +0 -116
  272. package/lib/module/notifyAppReadyInsights.transport.spec.js.map +0 -1
  273. package/lib/module/releaseCatalogCache.spec.js +0 -195
  274. package/lib/module/releaseCatalogCache.spec.js.map +0 -1
  275. package/lib/module/releaseCatalogCacheNativeContract.spec.js +0 -64
  276. package/lib/module/releaseCatalogCacheNativeContract.spec.js.map +0 -1
  277. package/lib/module/store.notification.spec.js +0 -77
  278. package/lib/module/store.notification.spec.js.map +0 -1
  279. package/lib/module/store.spec.js +0 -315
  280. package/lib/module/store.spec.js.map +0 -1
  281. package/lib/module/wrap.spec.js +0 -330
  282. package/lib/module/wrap.spec.js.map +0 -1
  283. package/lib/typescript/commonjs/notifyAppReadyInsights.d.ts +0 -13
  284. package/lib/typescript/commonjs/notifyAppReadyInsights.d.ts.map +0 -1
  285. package/lib/typescript/commonjs/notifyAppReadyInsights.test-utils.d.ts +0 -8
  286. package/lib/typescript/commonjs/notifyAppReadyInsights.test-utils.d.ts.map +0 -1
  287. package/lib/typescript/module/notifyAppReadyInsights.d.ts +0 -13
  288. package/lib/typescript/module/notifyAppReadyInsights.d.ts.map +0 -1
  289. package/lib/typescript/module/notifyAppReadyInsights.test-utils.d.ts +0 -8
  290. package/lib/typescript/module/notifyAppReadyInsights.test-utils.d.ts.map +0 -1
  291. package/src/catalogCacheNative.spec.ts +0 -63
  292. package/src/checkForUpdate.releaseCatalog.spec.ts +0 -612
  293. package/src/httpClient.spec.ts +0 -132
  294. package/src/index.spec.ts +0 -337
  295. package/src/iosInterop.spec.ts +0 -30
  296. package/src/native.spec.ts +0 -945
  297. package/src/notifyAppReadyInsights.boundary.spec.ts +0 -234
  298. package/src/notifyAppReadyInsights.spec.ts +0 -243
  299. package/src/notifyAppReadyInsights.test-utils.ts +0 -31
  300. package/src/notifyAppReadyInsights.transport.spec.ts +0 -130
  301. package/src/notifyAppReadyInsights.ts +0 -194
  302. package/src/releaseCatalogCache.spec.ts +0 -282
  303. package/src/releaseCatalogCacheNativeContract.spec.ts +0 -80
  304. package/src/store.notification.spec.ts +0 -92
  305. package/src/store.spec.ts +0 -372
  306. package/src/wrap.spec.ts +0 -406
@@ -1,117 +0,0 @@
1
- package com.hotupdater
2
-
3
- import android.util.Log
4
- import com.hotupdater.vendor.brotli.dec.BrotliInputStream
5
- import java.io.BufferedInputStream
6
- import java.io.File
7
- import java.io.FileInputStream
8
- import java.io.FileOutputStream
9
-
10
- /**
11
- * Strategy for handling TAR+Brotli compressed files
12
- * Uses native Brotli decoder and custom TAR parser
13
- */
14
- class TarBrDecompressionStrategy : DecompressionStrategy {
15
- companion object {
16
- private const val TAG = "TarBrStrategy"
17
- private const val MIN_FILE_SIZE = 10L
18
- }
19
-
20
- override fun isValid(filePath: String): Boolean {
21
- val file = File(filePath)
22
-
23
- if (!file.exists() || file.length() < MIN_FILE_SIZE) {
24
- Log.d(TAG, "Invalid file: doesn't exist or too small (${file.length()} bytes)")
25
- return false
26
- }
27
-
28
- return try {
29
- FileInputStream(file).use { fileInputStream ->
30
- BufferedInputStream(fileInputStream).use { bufferedInputStream ->
31
- BrotliInputStream(bufferedInputStream).use { brotliInputStream ->
32
- TarArchiveInputStream(brotliInputStream).use { tarInputStream ->
33
- val firstEntry = tarInputStream.getNextEntry()
34
- val isValid = firstEntry != null
35
-
36
- if (!isValid) {
37
- Log.d(TAG, "Invalid file: tar archive has no entries")
38
- }
39
-
40
- isValid
41
- }
42
- }
43
- }
44
- }
45
- } catch (e: Exception) {
46
- Log.d(TAG, "Invalid file: Brotli/TAR validation failed - ${e.message}")
47
- false
48
- }
49
- }
50
-
51
- override fun decompress(
52
- filePath: String,
53
- destinationPath: String,
54
- progressCallback: (Double) -> Unit,
55
- ): Boolean =
56
- try {
57
- val destinationDir = File(destinationPath)
58
- if (!destinationDir.exists()) {
59
- destinationDir.mkdirs()
60
- }
61
-
62
- val sourceFile = File(filePath)
63
- val totalSize = sourceFile.length()
64
- var processedBytes = 0L
65
-
66
- Log.d(TAG, "Extracting tar.br file: $filePath")
67
-
68
- FileInputStream(filePath).use { fileInputStream ->
69
- BufferedInputStream(fileInputStream).use { bufferedInputStream ->
70
- BrotliInputStream(bufferedInputStream).use { brotliInputStream ->
71
- TarArchiveInputStream(brotliInputStream).use { tarInputStream ->
72
- var entry = tarInputStream.getNextEntry()
73
-
74
- while (entry != null) {
75
- val file = RelativePathResolver.resolveInside(destinationDir, entry.name)
76
-
77
- if (file == null) {
78
- Log.w(TAG, "Skipping potentially malicious tar entry: ${entry.name}")
79
- entry = tarInputStream.getNextEntry()
80
- continue
81
- }
82
-
83
- if (entry.isDirectory) {
84
- file.mkdirs()
85
- } else {
86
- file.parentFile?.mkdirs()
87
-
88
- FileOutputStream(file).use { output ->
89
- val buffer = ByteArray(8 * 1024)
90
- var bytesRead: Int
91
-
92
- while (tarInputStream.read(buffer).also { bytesRead = it } != -1) {
93
- output.write(buffer, 0, bytesRead)
94
- processedBytes += bytesRead
95
- }
96
- }
97
- }
98
-
99
- val progress = processedBytes.toDouble() / (totalSize * 2.0)
100
- progressCallback.invoke(progress.coerceIn(0.0, 1.0))
101
-
102
- entry = tarInputStream.getNextEntry()
103
- }
104
- }
105
- }
106
- }
107
- }
108
-
109
- Log.d(TAG, "Successfully extracted tar.br file")
110
- progressCallback.invoke(1.0)
111
- true
112
- } catch (e: Exception) {
113
- Log.d(TAG, "Failed to extract tar.br file: ${e.message}")
114
- e.printStackTrace()
115
- false
116
- }
117
- }
@@ -1,117 +0,0 @@
1
- package com.hotupdater
2
-
3
- import android.util.Log
4
- import java.io.BufferedInputStream
5
- import java.io.File
6
- import java.io.FileInputStream
7
- import java.io.FileOutputStream
8
- import java.util.zip.GZIPInputStream
9
-
10
- /**
11
- * Strategy for handling TAR+GZIP compressed files
12
- * Uses native GZIP decoder and custom TAR parser
13
- */
14
- class TarGzDecompressionStrategy : DecompressionStrategy {
15
- companion object {
16
- private const val TAG = "TarGzStrategy"
17
- private const val MIN_FILE_SIZE = 10L
18
- }
19
-
20
- override fun isValid(filePath: String): Boolean {
21
- val file = File(filePath)
22
-
23
- if (!file.exists() || file.length() < MIN_FILE_SIZE) {
24
- Log.d(TAG, "Invalid file: doesn't exist or too small (${file.length()} bytes)")
25
- return false
26
- }
27
-
28
- try {
29
- FileInputStream(file).use { fis ->
30
- val header = ByteArray(2)
31
- if (fis.read(header) != 2) {
32
- Log.d(TAG, "Invalid file: cannot read header")
33
- return false
34
- }
35
-
36
- // Check GZIP magic bytes (0x1F 0x8B)
37
- val isGzip = header[0] == 0x1F.toByte() && header[1] == 0x8B.toByte()
38
- if (!isGzip) {
39
- Log.d(
40
- TAG,
41
- "Invalid file: wrong magic bytes (expected 0x1F 0x8B, got 0x${header[0].toString(16)} 0x${header[1].toString(16)})",
42
- )
43
- }
44
- return isGzip
45
- }
46
- } catch (e: Exception) {
47
- Log.d(TAG, "Invalid file: error reading header: ${e.message}")
48
- return false
49
- }
50
- }
51
-
52
- override fun decompress(
53
- filePath: String,
54
- destinationPath: String,
55
- progressCallback: (Double) -> Unit,
56
- ): Boolean =
57
- try {
58
- val destinationDir = File(destinationPath)
59
- if (!destinationDir.exists()) {
60
- destinationDir.mkdirs()
61
- }
62
-
63
- val sourceFile = File(filePath)
64
- val totalSize = sourceFile.length()
65
- var processedBytes = 0L
66
-
67
- Log.d(TAG, "Extracting tar.gz file: $filePath")
68
-
69
- FileInputStream(filePath).use { fileInputStream ->
70
- BufferedInputStream(fileInputStream).use { bufferedInputStream ->
71
- GZIPInputStream(bufferedInputStream).use { gzipInputStream ->
72
- TarArchiveInputStream(gzipInputStream).use { tarInputStream ->
73
- var entry = tarInputStream.getNextEntry()
74
-
75
- while (entry != null) {
76
- val file = RelativePathResolver.resolveInside(destinationDir, entry.name)
77
-
78
- if (file == null) {
79
- Log.w(TAG, "Skipping potentially malicious tar entry: ${entry.name}")
80
- entry = tarInputStream.getNextEntry()
81
- continue
82
- }
83
-
84
- if (entry.isDirectory) {
85
- file.mkdirs()
86
- } else {
87
- file.parentFile?.mkdirs()
88
-
89
- FileOutputStream(file).use { output ->
90
- val buffer = ByteArray(8 * 1024)
91
- var bytesRead: Int
92
-
93
- while (tarInputStream.read(buffer).also { bytesRead = it } != -1) {
94
- output.write(buffer, 0, bytesRead)
95
- processedBytes += bytesRead
96
- }
97
- }
98
- }
99
-
100
- val progress = processedBytes.toDouble() / (totalSize * 2.0)
101
- progressCallback.invoke(progress.coerceIn(0.0, 1.0))
102
-
103
- entry = tarInputStream.getNextEntry()
104
- }
105
- }
106
- }
107
- }
108
- }
109
-
110
- Log.d(TAG, "Successfully extracted tar.gz file")
111
- progressCallback.invoke(1.0)
112
- true
113
- } catch (e: Exception) {
114
- Log.e(TAG, "Error extracting tar.gz file: ${e.message}", e)
115
- false
116
- }
117
- }
@@ -1,192 +0,0 @@
1
- package com.hotupdater
2
-
3
- import android.util.Log
4
- import java.io.BufferedInputStream
5
- import java.io.File
6
- import java.io.FileInputStream
7
- import java.io.FileOutputStream
8
- import java.io.IOException
9
- import java.util.zip.CRC32
10
- import java.util.zip.ZipEntry
11
- import java.util.zip.ZipException
12
- import java.util.zip.ZipFile
13
- import java.util.zip.ZipInputStream
14
-
15
- /**
16
- * Strategy for handling ZIP compressed files
17
- */
18
- class ZipDecompressionStrategy : DecompressionStrategy {
19
- companion object {
20
- private const val TAG = "ZipStrategy"
21
- private const val MIN_ZIP_SIZE = 22L
22
- }
23
-
24
- override fun isValid(filePath: String): Boolean {
25
- val file = File(filePath)
26
-
27
- if (!file.exists() || file.length() < MIN_ZIP_SIZE) {
28
- Log.d(TAG, "Invalid ZIP: file doesn't exist or too small (${file.length()} bytes)")
29
- return false
30
- }
31
-
32
- try {
33
- FileInputStream(file).use { fis ->
34
- val header = ByteArray(4)
35
- if (fis.read(header) != 4) {
36
- Log.d(TAG, "Invalid ZIP: cannot read header")
37
- return false
38
- }
39
-
40
- // ZIP magic bytes: 0x50 0x4B 0x03 0x04 ("PK\u0003\u0004")
41
- val expectedMagic = byteArrayOf(0x50.toByte(), 0x4B.toByte(), 0x03.toByte(), 0x04.toByte())
42
-
43
- if (!header.contentEquals(expectedMagic)) {
44
- val headerHex = header.joinToString(" ") { "0x%02X".format(it) }
45
- Log.d(TAG, "Invalid ZIP: wrong magic bytes (expected 0x50 0x4B 0x03 0x04, got $headerHex)")
46
- return false
47
- }
48
- }
49
- } catch (e: Exception) {
50
- Log.d(TAG, "Invalid ZIP: error reading file: ${e.message}")
51
- return false
52
- }
53
-
54
- try {
55
- ZipFile(file).use { zipFile ->
56
- val entries = zipFile.entries()
57
- if (!entries.hasMoreElements()) {
58
- Log.d(TAG, "Invalid ZIP: no entries found")
59
- return false
60
- }
61
-
62
- val firstEntry = entries.nextElement()
63
- zipFile.getInputStream(firstEntry).use { stream ->
64
- val buffer = ByteArray(1024)
65
- stream.read(buffer)
66
- }
67
- }
68
- return true
69
- } catch (e: ZipException) {
70
- Log.d(TAG, "Invalid ZIP: ZIP structure error: ${e.message}")
71
- return false
72
- } catch (e: Exception) {
73
- Log.d(TAG, "Invalid ZIP: validation error: ${e.message}")
74
- return false
75
- }
76
- }
77
-
78
- override fun decompress(
79
- filePath: String,
80
- destinationPath: String,
81
- progressCallback: (Double) -> Unit,
82
- ): Boolean {
83
- return try {
84
- val destinationDir = File(destinationPath)
85
- if (!destinationDir.exists()) {
86
- destinationDir.mkdirs()
87
- }
88
-
89
- // Calculate total bytes to extract for accurate progress reporting
90
- val totalBytes =
91
- try {
92
- ZipFile(File(filePath)).use { zipFile ->
93
- zipFile
94
- .entries()
95
- .asSequence()
96
- .filter { !it.isDirectory }
97
- .sumOf { it.size }
98
- }
99
- } catch (e: Exception) {
100
- Log.d(TAG, "Failed to calculate total bytes: ${e.message}")
101
- 0L
102
- }
103
-
104
- if (totalBytes == 0L) {
105
- Log.d(TAG, "No content found in ZIP")
106
- return false
107
- }
108
-
109
- Log.d(TAG, "Extracting $totalBytes bytes from ZIP")
110
-
111
- var extractedFileCount = 0
112
- var extractedBytes = 0L
113
- var lastReportedProgress = 0.0
114
-
115
- FileInputStream(filePath).use { fileInputStream ->
116
- BufferedInputStream(fileInputStream).use { bufferedInputStream ->
117
- ZipInputStream(bufferedInputStream).use { zipInputStream ->
118
- var entry: ZipEntry? = zipInputStream.nextEntry
119
- while (entry != null) {
120
- val file =
121
- try {
122
- RelativePathResolver.resolveInside(destinationDir, entry.name)
123
- } catch (e: IOException) {
124
- Log.w(TAG, "Failed to resolve canonical path for zip entry: ${entry.name}", e)
125
- null
126
- }
127
-
128
- if (file == null) {
129
- Log.w(TAG, "Skipping potentially malicious zip entry: ${entry.name}")
130
- entry = zipInputStream.nextEntry
131
- continue
132
- }
133
-
134
- if (entry.isDirectory) {
135
- file.mkdirs()
136
- } else {
137
- file.parentFile?.mkdirs()
138
-
139
- val crc = CRC32()
140
- FileOutputStream(file).use { output ->
141
- val buffer = ByteArray(8 * 1024)
142
- var bytesRead: Int
143
-
144
- while (zipInputStream.read(buffer).also { bytesRead = it } != -1) {
145
- output.write(buffer, 0, bytesRead)
146
- crc.update(buffer, 0, bytesRead)
147
-
148
- // Track bytes written for byte-based progress
149
- extractedBytes += bytesRead
150
-
151
- // Report progress more frequently (every 1%)
152
- val currentProgress = extractedBytes.toDouble() / totalBytes
153
- if (currentProgress - lastReportedProgress >= 0.01) {
154
- progressCallback.invoke(currentProgress)
155
- lastReportedProgress = currentProgress
156
- }
157
- }
158
- }
159
-
160
- if (entry.crc != -1L && crc.value != entry.crc) {
161
- Log.w(TAG, "CRC mismatch for ${entry.name}: expected ${entry.crc}, got ${crc.value}")
162
- file.delete()
163
- return false
164
- }
165
-
166
- extractedFileCount++
167
- }
168
-
169
- zipInputStream.closeEntry()
170
- entry = zipInputStream.nextEntry
171
- }
172
- }
173
- }
174
- }
175
-
176
- if (extractedFileCount == 0) {
177
- Log.d(TAG, "No files extracted from ZIP")
178
- return false
179
- }
180
-
181
- Log.d(TAG, "Successfully extracted $extractedFileCount files ($extractedBytes bytes)")
182
- progressCallback.invoke(1.0)
183
- true
184
- } catch (e: ZipException) {
185
- Log.d(TAG, "ZIP extraction failed: ${e.message}")
186
- false
187
- } catch (e: Exception) {
188
- Log.d(TAG, "Failed to unzip file: ${e.message}")
189
- false
190
- }
191
- }
192
- }
@@ -1,46 +0,0 @@
1
- package com.hotupdater
2
-
3
- import org.junit.Assert.assertArrayEquals
4
- import org.junit.Assert.assertFalse
5
- import org.junit.Assert.assertThrows
6
- import org.junit.Assert.assertTrue
7
- import org.junit.Rule
8
- import org.junit.Test
9
- import org.junit.rules.TemporaryFolder
10
- import java.util.Base64
11
-
12
- class BsdiffPatchTest {
13
- @get:Rule
14
- val temporaryFolder = TemporaryFolder()
15
-
16
- @Test
17
- fun `applies bsdiff patch and verifies patched output hash`() {
18
- val base = "console.log(\"base bundle\");\n".toByteArray()
19
- val expected = "console.log(\"patched bundle\");\n".toByteArray()
20
- val patch = Base64.getDecoder().decode(BSDIFF_PATCH_FIXTURE_BASE64)
21
- val baseFile = temporaryFolder.newFile("base.bundle").apply { writeBytes(base) }
22
- val patchFile = temporaryFolder.newFile("patch.bsdiff").apply { writeBytes(patch) }
23
- val outputFile = temporaryFolder.newFile("output.bundle")
24
-
25
- BsdiffPatch.apply(baseFile, patchFile, outputFile)
26
-
27
- assertArrayEquals(expected, outputFile.readBytes())
28
- assertTrue(HashUtils.verifyHash(outputFile, HashUtils.calculateSHA256(outputFile)))
29
- assertFalse(HashUtils.verifyHash(outputFile, HashUtils.calculateSHA256(baseFile)))
30
- }
31
-
32
- @Test
33
- fun `rejects invalid bsdiff patch`() {
34
- val base = "console.log(\"base bundle\");\n".toByteArray()
35
- val invalidPatch = "not-a-bsdiff-patch-with-header".toByteArray()
36
-
37
- assertThrows(IllegalArgumentException::class.java) {
38
- BsdiffPatch.apply(base, invalidPatch)
39
- }
40
- }
41
-
42
- companion object {
43
- private const val BSDIFF_PATCH_FIXTURE_BASE64 =
44
- "RU5EU0xFWS9CU0RJRkY0Mx8AAAAAAAAAQlpoOTFBWSZTWb12MIEAAAB5gEQYAADQYQAIPsXOACAAIo0A0NAaNCgAGgZMgHAtYscVxxRtTt4nmaj70g4gQSF5+T4u5IpwoSF67GEC"
45
- }
46
- }