@capgo/capacitor-updater 5.10.0 → 5.31.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.
@@ -71,7 +71,7 @@ public class CapacitorUpdaterPlugin extends Plugin {
71
71
  private static final String[] BREAKING_EVENT_NAMES = { "breakingAvailable", "majorAvailable" };
72
72
  private static final String LAST_FAILED_BUNDLE_PREF_KEY = "CapacitorUpdater.lastFailedBundle";
73
73
 
74
- private final String pluginVersion = "5.10.0";
74
+ private final String pluginVersion = "5.31.0";
75
75
  private static final String DELAY_CONDITION_PREFERENCES = "";
76
76
 
77
77
  private SharedPreferences.Editor editor;
@@ -703,6 +703,7 @@ public class CapacitorUpdaterPlugin extends Plugin {
703
703
  }
704
704
  }
705
705
  this.implementation.cleanupDownloadDirectories(allowedIds);
706
+ this.implementation.cleanupDeltaCache();
706
707
  }
707
708
  this.editor.putString("LatestNativeBuildVersion", this.currentBuildVersion);
708
709
  this.editor.apply();
@@ -491,6 +491,23 @@ public class CapgoUpdater {
491
491
  }
492
492
  }
493
493
 
494
+ public void cleanupDeltaCache() {
495
+ if (this.activity == null) {
496
+ logger.warn("Activity is null, skipping delta cache cleanup");
497
+ return;
498
+ }
499
+ final File cacheFolder = new File(this.activity.getCacheDir(), "capgo_downloads");
500
+ if (!cacheFolder.exists()) {
501
+ return;
502
+ }
503
+ try {
504
+ this.deleteDirectory(cacheFolder);
505
+ logger.info("Cleaned up delta cache folder");
506
+ } catch (IOException e) {
507
+ logger.error("Failed to cleanup delta cache: " + e.getMessage());
508
+ }
509
+ }
510
+
494
511
  public void cleanupDownloadDirectories(final Set<String> allowedIds) {
495
512
  if (this.documentsDir == null) {
496
513
  logger.warn("Documents directory is null, skipping download cleanup");
@@ -179,18 +179,43 @@ public class CryptoCipher {
179
179
  }
180
180
  }
181
181
 
182
+ private static byte[] hexStringToByteArray(String s) {
183
+ int len = s.length();
184
+ byte[] data = new byte[len / 2];
185
+ for (int i = 0; i < len; i += 2) {
186
+ data[i / 2] = (byte) ((Character.digit(s.charAt(i), 16) << 4) + Character.digit(s.charAt(i + 1), 16));
187
+ }
188
+ return data;
189
+ }
190
+
182
191
  public static String decryptChecksum(String checksum, String publicKey) throws IOException {
183
192
  if (publicKey.isEmpty()) {
184
193
  logger.error("No encryption set (public key) ignored");
185
194
  return checksum;
186
195
  }
187
196
  try {
188
- byte[] checksumBytes = Base64.decode(checksum, Base64.DEFAULT);
197
+ // TODO: remove this in a month or two
198
+ // Determine if input is hex or base64 encoded
199
+ // Hex strings only contain 0-9 and a-f, while base64 contains other characters
200
+ byte[] checksumBytes;
201
+ if (checksum.matches("^[0-9a-fA-F]+$")) {
202
+ // Hex encoded (new format from CLI for plugin versions >= 5.30.0, 6.30.0, 7.30.0)
203
+ checksumBytes = hexStringToByteArray(checksum);
204
+ } else {
205
+ // TODO: remove backwards compatibility
206
+ // Base64 encoded (old format for backwards compatibility)
207
+ checksumBytes = Base64.decode(checksum, Base64.DEFAULT);
208
+ }
189
209
  PublicKey pKey = CryptoCipher.stringToPublicKey(publicKey);
190
210
  byte[] decryptedChecksum = CryptoCipher.decryptRSA(checksumBytes, pKey);
191
- // return Base64.encodeToString(decryptedChecksum, Base64.DEFAULT);
192
- String result = Base64.encodeToString(decryptedChecksum, Base64.DEFAULT);
193
- return result.replaceAll("\\s", ""); // Remove all whitespace, including newlines
211
+ // Return as hex string to match calcChecksum output format
212
+ StringBuilder hexString = new StringBuilder();
213
+ for (byte b : decryptedChecksum) {
214
+ String hex = Integer.toHexString(0xff & b);
215
+ if (hex.length() == 1) hexString.append('0');
216
+ hexString.append(hex);
217
+ }
218
+ return hexString.toString();
194
219
  } catch (GeneralSecurityException e) {
195
220
  logger.error("decryptChecksum fail: " + e.getMessage());
196
221
  throw new IOException("Decryption failed: " + e.getMessage());
@@ -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 = "5.10.0"
57
+ private let pluginVersion: String = "5.31.0"
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"
@@ -366,6 +366,7 @@ public class CapacitorUpdaterPlugin: CAPPlugin, CAPBridgedPlugin {
366
366
  return id.isEmpty ? nil : id
367
367
  })
368
368
  implementation.cleanupDownloadDirectories(allowedIds: allowedIds)
369
+ implementation.cleanupDeltaCache()
369
370
  }
370
371
  UserDefaults.standard.set(self.currentBuildVersion, forKey: "LatestNativeBuildVersion")
371
372
  UserDefaults.standard.synchronize()
@@ -975,6 +975,19 @@ import UIKit
975
975
  return self.delete(id: id, removeInfo: true)
976
976
  }
977
977
 
978
+ public func cleanupDeltaCache() {
979
+ let fileManager = FileManager.default
980
+ guard fileManager.fileExists(atPath: cacheFolder.path) else {
981
+ return
982
+ }
983
+ do {
984
+ try fileManager.removeItem(at: cacheFolder)
985
+ logger.info("Cleaned up delta cache folder")
986
+ } catch {
987
+ logger.error("Failed to cleanup delta cache: \(error.localizedDescription)")
988
+ }
989
+ }
990
+
978
991
  public func cleanupDownloadDirectories(allowedIds: Set<String>) {
979
992
  let bundleRoot = libraryDir.appendingPathComponent(bundleDirectory)
980
993
  let fileManager = FileManager.default
@@ -15,15 +15,47 @@ public struct CryptoCipher {
15
15
  self.logger = logger
16
16
  }
17
17
 
18
+ private static func hexStringToData(_ hex: String) -> Data? {
19
+ var data = Data()
20
+ var hexIterator = hex.makeIterator()
21
+ while let c1 = hexIterator.next(), let c2 = hexIterator.next() {
22
+ guard let byte = UInt8(String([c1, c2]), radix: 16) else {
23
+ return nil
24
+ }
25
+ data.append(byte)
26
+ }
27
+ return data
28
+ }
29
+
30
+ private static func isHexString(_ str: String) -> Bool {
31
+ let hexCharacterSet = CharacterSet(charactersIn: "0123456789abcdefABCDEF")
32
+ return str.unicodeScalars.allSatisfy { hexCharacterSet.contains($0) }
33
+ }
34
+
18
35
  public static func decryptChecksum(checksum: String, publicKey: String) throws -> String {
19
36
  if publicKey.isEmpty {
20
37
  logger.info("No encryption set (public key) ignored")
21
38
  return checksum
22
39
  }
23
40
  do {
24
- guard let checksumBytes = Data(base64Encoded: checksum) else {
25
- logger.error("Cannot decode checksum as base64: \(checksum)")
26
- throw CustomError.cannotDecode
41
+ // Determine if input is hex or base64 encoded
42
+ // Hex strings only contain 0-9 and a-f, while base64 contains other characters
43
+ let checksumBytes: Data
44
+ if isHexString(checksum) {
45
+ // Hex encoded (new format from CLI for plugin versions >= 5.30.0, 6.30.0, 7.30.0)
46
+ guard let hexData = hexStringToData(checksum) else {
47
+ logger.error("Cannot decode checksum as hex: \(checksum)")
48
+ throw CustomError.cannotDecode
49
+ }
50
+ checksumBytes = hexData
51
+ } else {
52
+ // TODO: remove backwards compatibility
53
+ // Base64 encoded (old format for backwards compatibility)
54
+ guard let base64Data = Data(base64Encoded: checksum) else {
55
+ logger.error("Cannot decode checksum as base64: \(checksum)")
56
+ throw CustomError.cannotDecode
57
+ }
58
+ checksumBytes = base64Data
27
59
  }
28
60
 
29
61
  if checksumBytes.isEmpty {
@@ -41,7 +73,8 @@ public struct CryptoCipher {
41
73
  throw NSError(domain: "Failed to decrypt session key data", code: 2, userInfo: nil)
42
74
  }
43
75
 
44
- return decryptedChecksum.base64EncodedString()
76
+ // Return as hex string to match calcChecksum output format
77
+ return decryptedChecksum.map { String(format: "%02x", $0) }.joined()
45
78
  } catch {
46
79
  logger.error("decryptChecksum fail: \(error.localizedDescription)")
47
80
  throw CustomError.cannotDecode
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@capgo/capacitor-updater",
3
- "version": "5.10.0",
3
+ "version": "5.31.0",
4
4
  "license": "MPL-2.0",
5
5
  "description": "Live update for capacitor apps",
6
6
  "main": "dist/plugin.cjs.js",