@capgo/capacitor-updater 7.0.37 → 7.0.38

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.
@@ -57,7 +57,7 @@ public class CapacitorUpdaterPlugin extends Plugin {
57
57
  private static final String statsUrlDefault = "https://plugin.capgo.app/stats";
58
58
  private static final String channelUrlDefault = "https://plugin.capgo.app/channel_self";
59
59
 
60
- private final String PLUGIN_VERSION = "7.0.37";
60
+ private final String PLUGIN_VERSION = "7.0.38";
61
61
  private static final String DELAY_CONDITION_PREFERENCES = "";
62
62
 
63
63
  private SharedPreferences.Editor editor;
@@ -192,24 +192,6 @@ public class CryptoCipherV2 {
192
192
  }
193
193
  }
194
194
 
195
- public static String decryptChecksum(String checksum, String publicKey, String version) throws IOException {
196
- if (publicKey.isEmpty()) {
197
- Log.e(CapacitorUpdater.TAG, "The public key is empty");
198
- return checksum;
199
- }
200
- try {
201
- byte[] checksumBytes = Base64.decode(checksum, Base64.DEFAULT);
202
- PublicKey pKey = CryptoCipherV2.stringToPublicKey(publicKey);
203
- byte[] decryptedChecksum = CryptoCipherV2.decryptRSA(checksumBytes, pKey);
204
- // return Base64.encodeToString(decryptedChecksum, Base64.DEFAULT);
205
- String result = Base64.encodeToString(decryptedChecksum, Base64.DEFAULT);
206
- return result.replaceAll("\\s", ""); // Remove all whitespace, including newlines
207
- } catch (GeneralSecurityException e) {
208
- Log.e(CapacitorUpdater.TAG, "decryptChecksum fail: " + e.getMessage());
209
- throw new IOException("Decryption failed: " + e.getMessage());
210
- }
211
- }
212
-
213
195
  public static String calcChecksum(File file) {
214
196
  final int BUFFER_SIZE = 1024 * 1024 * 5; // 5 MB buffer size
215
197
  MessageDigest digest;
@@ -377,8 +377,16 @@ public class DownloadService extends Worker {
377
377
 
378
378
  Request request = new Request.Builder().url(downloadUrl).build();
379
379
 
380
+ // Check if file is a Brotli file
381
+ boolean isBrotli = targetFile.getName().endsWith(".br");
382
+
383
+ // Create final target file with .br extension removed if it's a Brotli file
384
+ File finalTargetFile = isBrotli
385
+ ? new File(targetFile.getParentFile(), targetFile.getName().substring(0, targetFile.getName().length() - 3))
386
+ : targetFile;
387
+
380
388
  // Create a temporary file for the compressed data
381
- File compressedFile = new File(getApplicationContext().getCacheDir(), "temp_" + targetFile.getName() + ".br");
389
+ File compressedFile = new File(getApplicationContext().getCacheDir(), "temp_" + targetFile.getName() + ".tmp");
382
390
 
383
391
  try (Response response = client.newCall(request).execute()) {
384
392
  if (!response.isSuccessful()) {
@@ -405,21 +413,27 @@ public class DownloadService extends Worker {
405
413
  CryptoCipherV2.decryptFile(compressedFile, publicKey, sessionKey);
406
414
  }
407
415
 
408
- // Use new decompression method
409
- byte[] compressedData = Files.readAllBytes(compressedFile.toPath());
410
- byte[] decompressedData = decompressBrotli(compressedData, targetFile.getName());
411
- Files.write(targetFile.toPath(), decompressedData);
416
+ // Only decompress if file has .br extension
417
+ if (isBrotli) {
418
+ // Use new decompression method
419
+ byte[] compressedData = Files.readAllBytes(compressedFile.toPath());
420
+ byte[] decompressedData = decompressBrotli(compressedData, targetFile.getName());
421
+ Files.write(finalTargetFile.toPath(), decompressedData);
422
+ } else {
423
+ // Just copy the file without decompression
424
+ Files.copy(compressedFile.toPath(), finalTargetFile.toPath(), java.nio.file.StandardCopyOption.REPLACE_EXISTING);
425
+ }
412
426
 
413
427
  // Delete the compressed file
414
428
  compressedFile.delete();
415
- String calculatedHash = CryptoCipherV2.calcChecksum(targetFile);
429
+ String calculatedHash = CryptoCipherV2.calcChecksum(finalTargetFile);
416
430
 
417
431
  // Verify checksum
418
432
  if (calculatedHash.equals(expectedHash)) {
419
433
  // Only cache if checksum is correct
420
- copyFile(targetFile, cacheFile);
434
+ copyFile(finalTargetFile, cacheFile);
421
435
  } else {
422
- targetFile.delete();
436
+ finalTargetFile.delete();
423
437
  throw new IOException(
424
438
  "Checksum verification failed for: " +
425
439
  downloadUrl +
@@ -340,7 +340,7 @@ import UIKit
340
340
 
341
341
  if !self.publicKey.isEmpty && !sessionKey.isEmpty {
342
342
  do {
343
- fileHash = try CryptoCipherV2.decryptChecksum(checksum: fileHash, publicKey: self.publicKey, version: version)
343
+ fileHash = try CryptoCipherV2.decryptChecksum(checksum: fileHash, publicKey: self.publicKey)
344
344
  } catch {
345
345
  downloadError = error
346
346
  print("\(CapacitorUpdater.TAG) CryptoCipherV2.decryptChecksum error \(id) \(fileName) error: \(error)")
@@ -403,11 +403,18 @@ import UIKit
403
403
  try FileManager.default.removeItem(at: tempFile)
404
404
  }
405
405
 
406
- // Decompress the Brotli data
407
- guard let decompressedData = self.decompressBrotli(data: finalData, fileName: fileName) else {
408
- throw NSError(domain: "BrotliDecompressionError", code: 1, userInfo: [NSLocalizedDescriptionKey: "Failed to decompress Brotli data for file \(fileName) at url \(downloadUrl)"])
406
+ // Check if file has .br extension for Brotli decompression
407
+ let isBrotli = fileName.hasSuffix(".br")
408
+ let finalFileName = isBrotli ? String(fileName.dropLast(3)) : fileName
409
+ let destFilePath = destFolder.appendingPathComponent(finalFileName)
410
+
411
+ if isBrotli {
412
+ // Decompress the Brotli data
413
+ guard let decompressedData = self.decompressBrotli(data: finalData, fileName: fileName) else {
414
+ throw NSError(domain: "BrotliDecompressionError", code: 1, userInfo: [NSLocalizedDescriptionKey: "Failed to decompress Brotli data for file \(fileName) at url \(downloadUrl)"])
415
+ }
416
+ finalData = decompressedData
409
417
  }
410
- finalData = decompressedData
411
418
 
412
419
  try finalData.write(to: destFilePath)
413
420
  if !self.publicKey.isEmpty && !sessionKey.isEmpty {
@@ -423,7 +430,7 @@ import UIKit
423
430
 
424
431
  completedFiles += 1
425
432
  self.notifyDownload(id: id, percent: self.calcTotalPercent(percent: Int((Double(completedFiles) / Double(totalFiles)) * 100), min: 10, max: 70))
426
- print("\(CapacitorUpdater.TAG) downloadManifest \(id) \(fileName) downloaded, decompressed\(!self.publicKey.isEmpty && !sessionKey.isEmpty ? ", decrypted" : ""), and cached")
433
+ print("\(CapacitorUpdater.TAG) downloadManifest \(id) \(fileName) downloaded\(isBrotli ? ", decompressed" : "")\(!self.publicKey.isEmpty && !sessionKey.isEmpty ? ", decrypted" : ""), and cached")
427
434
  } catch {
428
435
  downloadError = error
429
436
  NSLog("\(CapacitorUpdater.TAG) downloadManifest \(id) \(fileName) error: \(error.localizedDescription)")
@@ -45,7 +45,7 @@ public class CapacitorUpdaterPlugin: CAPPlugin, CAPBridgedPlugin {
45
45
  CAPPluginMethod(name: "getNextBundle", returnType: CAPPluginReturnPromise)
46
46
  ]
47
47
  public var implementation = CapacitorUpdater()
48
- private let PLUGIN_VERSION: String = "7.0.37"
48
+ private let PLUGIN_VERSION: String = "7.0.38"
49
49
  static let updateUrlDefault = "https://plugin.capgo.app/updates"
50
50
  static let statsUrlDefault = "https://plugin.capgo.app/stats"
51
51
  static let channelUrlDefault = "https://plugin.capgo.app/channel_self"
@@ -291,7 +291,7 @@ public class CapacitorUpdaterPlugin: CAPPlugin, CAPBridgedPlugin {
291
291
  DispatchQueue.global(qos: .background).async {
292
292
  do {
293
293
  let next = try self.implementation.download(url: url!, version: version, sessionKey: sessionKey)
294
- checksum = try CryptoCipherV2.decryptChecksum(checksum: checksum, publicKey: self.implementation.publicKey, version: version)
294
+ checksum = try CryptoCipherV2.decryptChecksum(checksum: checksum, publicKey: self.implementation.publicKey)
295
295
  if (checksum != "" || self.implementation.publicKey != "") && next.getChecksum() != checksum {
296
296
  print("\(CapacitorUpdater.TAG) Error checksum", next.getChecksum(), checksum)
297
297
  self.implementation.sendStats(action: "checksum_fail", versionName: next.getVersionName())
@@ -805,7 +805,7 @@ public class CapacitorUpdaterPlugin: CAPPlugin, CAPBridgedPlugin {
805
805
  self.endBackGroundTaskWithNotif(msg: "Latest version is in error state. Aborting update.", latestVersionName: latestVersionName, current: current)
806
806
  return
807
807
  }
808
- res.checksum = try CryptoCipherV2.decryptChecksum(checksum: res.checksum, publicKey: self.implementation.publicKey, version: latestVersionName)
808
+ res.checksum = try CryptoCipherV2.decryptChecksum(checksum: res.checksum, publicKey: self.implementation.publicKey)
809
809
  if res.checksum != "" && next.getChecksum() != res.checksum && res.manifest == nil {
810
810
  print("\(CapacitorUpdater.TAG) Error checksum", next.getChecksum(), res.checksum)
811
811
  self.implementation.sendStats(action: "checksum_fail", versionName: next.getVersionName())
@@ -10,7 +10,7 @@ import BigInt
10
10
 
11
11
  public struct CryptoCipherV2 {
12
12
 
13
- public static func decryptChecksum(checksum: String, publicKey: String, version: String) throws -> String {
13
+ public static func decryptChecksum(checksum: String, publicKey: String) throws -> String {
14
14
  if publicKey.isEmpty {
15
15
  print("\(CapacitorUpdater.TAG) The public key is empty")
16
16
  return checksum
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@capgo/capacitor-updater",
3
- "version": "7.0.37",
3
+ "version": "7.0.38",
4
4
  "license": "MPL-2.0",
5
5
  "description": "Live update for capacitor apps",
6
6
  "main": "dist/plugin.cjs.js",