@capgo/capacitor-updater 7.28.0 → 7.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 -1
- package/android/src/main/java/ee/forgr/capacitor_updater/CapgoUpdater.java +24 -10
- package/android/src/main/java/ee/forgr/capacitor_updater/CryptoCipher.java +28 -4
- package/ios/Sources/CapacitorUpdaterPlugin/CapacitorUpdaterPlugin.swift +1 -1
- package/ios/Sources/CapacitorUpdaterPlugin/CapgoUpdater.swift +20 -12
- package/ios/Sources/CapacitorUpdaterPlugin/CryptoCipher.swift +37 -4
- package/package.json +1 -1
|
@@ -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 = "7.
|
|
74
|
+
private final String pluginVersion = "7.30.0";
|
|
75
75
|
private static final String DELAY_CONDITION_PREFERENCES = "";
|
|
76
76
|
|
|
77
77
|
private SharedPreferences.Editor editor;
|
|
@@ -1235,18 +1235,32 @@ public class CapgoUpdater {
|
|
|
1235
1235
|
return;
|
|
1236
1236
|
}
|
|
1237
1237
|
|
|
1238
|
-
|
|
1239
|
-
|
|
1240
|
-
|
|
1241
|
-
|
|
1242
|
-
|
|
1238
|
+
JSONObject json;
|
|
1239
|
+
try {
|
|
1240
|
+
json = this.createInfoObject();
|
|
1241
|
+
} catch (JSONException e) {
|
|
1242
|
+
logger.error("Error creating info object: " + e.getMessage());
|
|
1243
|
+
final Map<String, Object> retError = new HashMap<>();
|
|
1244
|
+
retError.put("message", "Cannot get info: " + e);
|
|
1245
|
+
retError.put("error", "json_error");
|
|
1246
|
+
callback.callback(retError);
|
|
1247
|
+
return;
|
|
1248
|
+
}
|
|
1243
1249
|
|
|
1244
|
-
// Build URL with query parameters
|
|
1250
|
+
// Build URL with query parameters from JSON
|
|
1245
1251
|
HttpUrl.Builder urlBuilder = HttpUrl.parse(channelUrl).newBuilder();
|
|
1246
|
-
|
|
1247
|
-
|
|
1248
|
-
|
|
1249
|
-
|
|
1252
|
+
try {
|
|
1253
|
+
Iterator<String> keys = json.keys();
|
|
1254
|
+
while (keys.hasNext()) {
|
|
1255
|
+
String key = keys.next();
|
|
1256
|
+
Object value = json.get(key);
|
|
1257
|
+
if (value != null) {
|
|
1258
|
+
urlBuilder.addQueryParameter(key, value.toString());
|
|
1259
|
+
}
|
|
1260
|
+
}
|
|
1261
|
+
} catch (JSONException e) {
|
|
1262
|
+
logger.error("Error adding query parameters: " + e.getMessage());
|
|
1263
|
+
}
|
|
1250
1264
|
|
|
1251
1265
|
Request request = new Request.Builder().url(urlBuilder.build()).get().build();
|
|
1252
1266
|
|
|
@@ -179,18 +179,42 @@ 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
|
-
|
|
197
|
+
// Determine if input is hex or base64 encoded
|
|
198
|
+
// Hex strings only contain 0-9 and a-f, while base64 contains other characters
|
|
199
|
+
byte[] checksumBytes;
|
|
200
|
+
if (checksum.matches("^[0-9a-fA-F]+$")) {
|
|
201
|
+
// Hex encoded (new format from CLI for plugin versions >= 5.30.0, 6.30.0, 7.30.0)
|
|
202
|
+
checksumBytes = hexStringToByteArray(checksum);
|
|
203
|
+
} else {
|
|
204
|
+
// TODO: remove backwards compatibility
|
|
205
|
+
// Base64 encoded (old format for backwards compatibility)
|
|
206
|
+
checksumBytes = Base64.decode(checksum, Base64.DEFAULT);
|
|
207
|
+
}
|
|
189
208
|
PublicKey pKey = CryptoCipher.stringToPublicKey(publicKey);
|
|
190
209
|
byte[] decryptedChecksum = CryptoCipher.decryptRSA(checksumBytes, pKey);
|
|
191
|
-
//
|
|
192
|
-
|
|
193
|
-
|
|
210
|
+
// Return as hex string to match calcChecksum output format
|
|
211
|
+
StringBuilder hexString = new StringBuilder();
|
|
212
|
+
for (byte b : decryptedChecksum) {
|
|
213
|
+
String hex = Integer.toHexString(0xff & b);
|
|
214
|
+
if (hex.length() == 1) hexString.append('0');
|
|
215
|
+
hexString.append(hex);
|
|
216
|
+
}
|
|
217
|
+
return hexString.toString();
|
|
194
218
|
} catch (GeneralSecurityException e) {
|
|
195
219
|
logger.error("decryptChecksum fail: " + e.getMessage());
|
|
196
220
|
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 = "7.
|
|
57
|
+
private let pluginVersion: String = "7.30.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"
|
|
@@ -1278,20 +1278,28 @@ import UIKit
|
|
|
1278
1278
|
|
|
1279
1279
|
let semaphore: DispatchSemaphore = DispatchSemaphore(value: 0)
|
|
1280
1280
|
|
|
1281
|
-
//
|
|
1282
|
-
let
|
|
1283
|
-
let platform = "ios"
|
|
1284
|
-
let isEmulator = self.isEmulator()
|
|
1285
|
-
let isProd = self.isProd()
|
|
1281
|
+
// Create info object and convert to query parameters
|
|
1282
|
+
let infoObject = self.createInfoObject()
|
|
1286
1283
|
|
|
1287
|
-
// Create query parameters
|
|
1284
|
+
// Create query parameters from InfoObject
|
|
1288
1285
|
var urlComponents = URLComponents(string: self.channelUrl)
|
|
1289
|
-
|
|
1290
|
-
|
|
1291
|
-
|
|
1292
|
-
|
|
1293
|
-
|
|
1294
|
-
|
|
1286
|
+
var queryItems: [URLQueryItem] = []
|
|
1287
|
+
|
|
1288
|
+
// Convert InfoObject to dictionary using Mirror
|
|
1289
|
+
let mirror = Mirror(reflecting: infoObject)
|
|
1290
|
+
for child in mirror.children {
|
|
1291
|
+
if let key = child.label, let value = child.value as? CustomStringConvertible {
|
|
1292
|
+
queryItems.append(URLQueryItem(name: key, value: String(describing: value)))
|
|
1293
|
+
} else if let key = child.label {
|
|
1294
|
+
// Handle optional values
|
|
1295
|
+
let mirror = Mirror(reflecting: child.value)
|
|
1296
|
+
if let value = mirror.children.first?.value {
|
|
1297
|
+
queryItems.append(URLQueryItem(name: key, value: String(describing: value)))
|
|
1298
|
+
}
|
|
1299
|
+
}
|
|
1300
|
+
}
|
|
1301
|
+
|
|
1302
|
+
urlComponents?.queryItems = queryItems
|
|
1295
1303
|
|
|
1296
1304
|
guard let url = urlComponents?.url else {
|
|
1297
1305
|
logger.error("Invalid channel URL")
|
|
@@ -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
|
-
|
|
25
|
-
|
|
26
|
-
|
|
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
|
-
|
|
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
|