@capgo/capacitor-updater 7.34.0 → 7.34.2

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.
@@ -72,7 +72,7 @@ public class CapacitorUpdaterPlugin extends Plugin {
72
72
  private static final String[] BREAKING_EVENT_NAMES = { "breakingAvailable", "majorAvailable" };
73
73
  private static final String LAST_FAILED_BUNDLE_PREF_KEY = "CapacitorUpdater.lastFailedBundle";
74
74
 
75
- private final String pluginVersion = "7.34.0";
75
+ private final String pluginVersion = "7.34.2";
76
76
  private static final String DELAY_CONDITION_PREFERENCES = "";
77
77
 
78
78
  private SharedPreferences.Editor editor;
@@ -302,8 +302,11 @@ public class DownloadService extends Worker {
302
302
  }
303
303
 
304
304
  final String finalFileHash = fileHash;
305
+ // Remove .br extension for decompressed files
306
+ boolean isBrotli = fileName.endsWith(".br");
307
+ String finalFileName = isBrotli ? fileName.substring(0, fileName.length() - 3) : fileName;
305
308
  File targetFile = new File(destFolder, fileName);
306
- File cacheFile = new File(cacheFolder, finalFileHash + "_" + new File(fileName).getName());
309
+ File cacheFile = new File(cacheFolder, finalFileHash + "_" + new File(finalFileName).getName());
307
310
  File builtinFile = new File(builtinFolder, fileName);
308
311
 
309
312
  // Ensure parent directories of the target file exist
@@ -589,83 +592,90 @@ public class DownloadService extends Worker {
589
592
  // Create a temporary file for the compressed data
590
593
  File compressedFile = new File(getApplicationContext().getCacheDir(), "temp_" + targetFile.getName() + ".tmp");
591
594
 
592
- try (Response response = sharedClient.newCall(request).execute()) {
593
- if (!response.isSuccessful()) {
594
- sendStatsAsync("download_manifest_file_fail", getInputData().getString(VERSION) + ":" + finalTargetFile.getName());
595
- throw new IOException("Unexpected response code: " + response.code());
596
- }
595
+ try {
596
+ try (Response response = sharedClient.newCall(request).execute()) {
597
+ if (!response.isSuccessful()) {
598
+ sendStatsAsync("download_manifest_file_fail", getInputData().getString(VERSION) + ":" + finalTargetFile.getName());
599
+ throw new IOException("Unexpected response code: " + response.code());
600
+ }
597
601
 
598
- // Download compressed file atomically
599
- ResponseBody responseBody = response.body();
600
- if (responseBody == null) {
601
- throw new IOException("Response body is null");
602
- }
602
+ // Download compressed file atomically
603
+ ResponseBody responseBody = response.body();
604
+ if (responseBody == null) {
605
+ throw new IOException("Response body is null");
606
+ }
603
607
 
604
- // Use OkIO for atomic write
605
- writeFileAtomic(compressedFile, responseBody.byteStream(), null);
608
+ // Use OkIO for atomic write
609
+ writeFileAtomic(compressedFile, responseBody.byteStream(), null);
606
610
 
607
- if (!publicKey.isEmpty() && sessionKey != null && !sessionKey.isEmpty()) {
608
- logger.debug("Decrypting file " + targetFile.getName());
609
- CryptoCipher.decryptFile(compressedFile, publicKey, sessionKey);
610
- }
611
+ if (!publicKey.isEmpty() && sessionKey != null && !sessionKey.isEmpty()) {
612
+ logger.debug("Decrypting file " + targetFile.getName());
613
+ CryptoCipher.decryptFile(compressedFile, publicKey, sessionKey);
614
+ }
611
615
 
612
- // Only decompress if file has .br extension
613
- if (isBrotli) {
614
- // Use new decompression method with atomic write
615
- try (FileInputStream fis = new FileInputStream(compressedFile)) {
616
- byte[] compressedData = new byte[(int) compressedFile.length()];
617
- fis.read(compressedData);
618
- byte[] decompressedData;
619
- try {
620
- decompressedData = decompressBrotli(compressedData, targetFile.getName());
621
- } catch (IOException e) {
622
- sendStatsAsync(
623
- "download_manifest_brotli_fail",
624
- getInputData().getString(VERSION) + ":" + finalTargetFile.getName()
625
- );
626
- throw e;
627
- }
616
+ // Only decompress if file has .br extension
617
+ if (isBrotli) {
618
+ // Use new decompression method with atomic write
619
+ try (FileInputStream fis = new FileInputStream(compressedFile)) {
620
+ byte[] compressedData = new byte[(int) compressedFile.length()];
621
+ fis.read(compressedData);
622
+ byte[] decompressedData;
623
+ try {
624
+ decompressedData = decompressBrotli(compressedData, targetFile.getName());
625
+ } catch (IOException e) {
626
+ sendStatsAsync(
627
+ "download_manifest_brotli_fail",
628
+ getInputData().getString(VERSION) + ":" + finalTargetFile.getName()
629
+ );
630
+ throw e;
631
+ }
628
632
 
629
- // Write decompressed data atomically
630
- try (java.io.ByteArrayInputStream bais = new java.io.ByteArrayInputStream(decompressedData)) {
631
- writeFileAtomic(finalTargetFile, bais, null);
633
+ // Write decompressed data atomically
634
+ try (java.io.ByteArrayInputStream bais = new java.io.ByteArrayInputStream(decompressedData)) {
635
+ writeFileAtomic(finalTargetFile, bais, null);
636
+ }
637
+ }
638
+ } else {
639
+ // Just copy the file without decompression using atomic operation
640
+ try (FileInputStream fis = new FileInputStream(compressedFile)) {
641
+ writeFileAtomic(finalTargetFile, fis, null);
632
642
  }
633
643
  }
634
- } else {
635
- // Just copy the file without decompression using atomic operation
636
- try (FileInputStream fis = new FileInputStream(compressedFile)) {
637
- writeFileAtomic(finalTargetFile, fis, null);
638
- }
639
- }
640
644
 
641
- // Delete the compressed file
642
- compressedFile.delete();
643
- String calculatedHash = CryptoCipher.calcChecksum(finalTargetFile);
644
- CryptoCipher.logChecksumInfo("Calculated checksum", calculatedHash);
645
- CryptoCipher.logChecksumInfo("Expected checksum", expectedHash);
646
-
647
- // Verify checksum
648
- if (calculatedHash.equals(expectedHash)) {
649
- // Only cache if checksum is correct - use atomic copy
650
- try (FileInputStream fis = new FileInputStream(finalTargetFile)) {
651
- writeFileAtomic(cacheFile, fis, expectedHash);
645
+ // Delete the compressed file
646
+ compressedFile.delete();
647
+ String calculatedHash = CryptoCipher.calcChecksum(finalTargetFile);
648
+ CryptoCipher.logChecksumInfo("Calculated checksum", calculatedHash);
649
+ CryptoCipher.logChecksumInfo("Expected checksum", expectedHash);
650
+
651
+ // Verify checksum
652
+ if (calculatedHash.equals(expectedHash)) {
653
+ // Only cache if checksum is correct - use atomic copy
654
+ try (FileInputStream fis = new FileInputStream(finalTargetFile)) {
655
+ writeFileAtomic(cacheFile, fis, expectedHash);
656
+ }
657
+ } else {
658
+ finalTargetFile.delete();
659
+ sendStatsAsync("download_manifest_checksum_fail", getInputData().getString(VERSION) + ":" + finalTargetFile.getName());
660
+ throw new IOException(
661
+ "Checksum verification failed for: " +
662
+ downloadUrl +
663
+ " " +
664
+ targetFile.getName() +
665
+ " expected: " +
666
+ expectedHash +
667
+ " calculated: " +
668
+ calculatedHash
669
+ );
652
670
  }
653
- } else {
654
- finalTargetFile.delete();
655
- sendStatsAsync("download_manifest_checksum_fail", getInputData().getString(VERSION) + ":" + finalTargetFile.getName());
656
- throw new IOException(
657
- "Checksum verification failed for: " +
658
- downloadUrl +
659
- " " +
660
- targetFile.getName() +
661
- " expected: " +
662
- expectedHash +
663
- " calculated: " +
664
- calculatedHash
665
- );
666
671
  }
667
672
  } catch (Exception e) {
668
673
  throw new IOException("Error in downloadAndVerify: " + e.getMessage());
674
+ } finally {
675
+ // Always cleanup the compressed temp file if it still exists
676
+ if (compressedFile.exists()) {
677
+ compressedFile.delete();
678
+ }
669
679
  }
670
680
  }
671
681
 
@@ -54,7 +54,7 @@ public class CapacitorUpdaterPlugin: CAPPlugin, CAPBridgedPlugin {
54
54
  CAPPluginMethod(name: "isShakeMenuEnabled", returnType: CAPPluginReturnPromise)
55
55
  ]
56
56
  public var implementation = CapgoUpdater()
57
- private let pluginVersion: String = "7.34.0"
57
+ private let pluginVersion: String = "7.34.2"
58
58
  static let updateUrlDefault = "https://plugin.capgo.app/updates"
59
59
  static let statsUrlDefault = "https://plugin.capgo.app/stats"
60
60
  static let channelUrlDefault = "https://plugin.capgo.app/channel_self"
@@ -445,10 +445,13 @@ import UIKit
445
445
  }
446
446
  }
447
447
 
448
- let fileNameWithoutPath = (fileName as NSString).lastPathComponent
448
+ // Check if file has .br extension for Brotli decompression
449
+ let isBrotli = fileName.hasSuffix(".br")
450
+ let finalFileName = isBrotli ? String(fileName.dropLast(3)) : fileName
451
+ let fileNameWithoutPath = (finalFileName as NSString).lastPathComponent
449
452
  let cacheFileName = "\(fileHash)_\(fileNameWithoutPath)"
450
453
  let cacheFilePath = cacheFolder.appendingPathComponent(cacheFileName)
451
- let destFilePath = destFolder.appendingPathComponent(fileName)
454
+ let destFilePath = destFolder.appendingPathComponent(finalFileName)
452
455
  let builtinFilePath = builtinFolder.appendingPathComponent(fileName)
453
456
 
454
457
  // Create necessary subdirectories in the destination folder
@@ -502,11 +505,6 @@ import UIKit
502
505
  try FileManager.default.removeItem(at: tempFile)
503
506
  }
504
507
 
505
- // Check if file has .br extension for Brotli decompression
506
- let isBrotli = fileName.hasSuffix(".br")
507
- let finalFileName = isBrotli ? String(fileName.dropLast(3)) : fileName
508
- let destFilePath = destFolder.appendingPathComponent(finalFileName)
509
-
510
508
  if isBrotli {
511
509
  // Decompress the Brotli data
512
510
  guard let decompressedData = self.decompressBrotli(data: finalData, fileName: fileName) else {
@@ -523,6 +521,8 @@ import UIKit
523
521
  CryptoCipher.logChecksumInfo(label: "Calculated checksum", hexChecksum: calculatedChecksum)
524
522
  CryptoCipher.logChecksumInfo(label: "Expected checksum", hexChecksum: fileHash)
525
523
  if calculatedChecksum != fileHash {
524
+ // Delete the corrupt file before throwing error
525
+ try? FileManager.default.removeItem(at: destFilePath)
526
526
  self.sendStats(action: "download_manifest_checksum_fail", versionName: "\(version):\(finalFileName)")
527
527
  throw NSError(domain: "ChecksumError", code: 1, userInfo: [NSLocalizedDescriptionKey: "Computed checksum is not equal to required checksum (\(calculatedChecksum) != \(fileHash)) for file \(fileName) at url \(downloadUrl)"])
528
528
  }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@capgo/capacitor-updater",
3
- "version": "7.34.0",
3
+ "version": "7.34.2",
4
4
  "license": "MPL-2.0",
5
5
  "description": "Live update for capacitor apps",
6
6
  "main": "dist/plugin.cjs.js",