@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.
- package/android/src/main/java/ee/forgr/capacitor_updater/CapacitorUpdaterPlugin.java +1 -0
- package/android/src/main/java/ee/forgr/capacitor_updater/CapgoUpdater.java +17 -0
- package/android/src/main/java/ee/forgr/capacitor_updater/CryptoCipherV2.java +31 -6
- package/ios/Sources/CapacitorUpdaterPlugin/CapacitorUpdaterPlugin.swift +1 -0
- package/ios/Sources/CapacitorUpdaterPlugin/CapgoUpdater.swift +13 -0
- package/ios/Sources/CapacitorUpdaterPlugin/CryptoCipherV2.swift +37 -4
- package/package.json +1 -1
|
@@ -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
|
-
|
|
191
|
-
|
|
192
|
-
|
|
193
|
-
|
|
194
|
-
|
|
195
|
-
|
|
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
|
-
|
|
26
|
-
|
|
27
|
-
|
|
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
|
-
|
|
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
|