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