@capgo/capacitor-updater 6.39.0 → 6.40.2
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/CapgoCapacitorUpdater.podspec +1 -1
- package/Package.swift +2 -2
- package/README.md +70 -202
- package/android/src/main/java/ee/forgr/capacitor_updater/CapacitorUpdaterPlugin.java +54 -56
- package/android/src/main/java/ee/forgr/capacitor_updater/CapgoUpdater.java +52 -33
- package/android/src/main/java/ee/forgr/capacitor_updater/CryptoCipher.java +10 -14
- package/android/src/main/java/ee/forgr/capacitor_updater/DeviceIdHelper.java +0 -6
- package/dist/docs.json +112 -684
- package/dist/esm/definitions.d.ts +23 -352
- package/dist/esm/definitions.js.map +1 -1
- package/dist/esm/history.js +2 -2
- package/dist/esm/history.js.map +1 -1
- package/dist/esm/index.d.ts +1 -0
- package/dist/esm/index.js +1 -0
- package/dist/esm/index.js.map +1 -1
- package/dist/esm/web.js.map +1 -1
- package/dist/plugin.cjs.js +3 -2
- package/dist/plugin.cjs.js.map +1 -1
- package/dist/plugin.js +4 -4
- package/dist/plugin.js.map +1 -1
- package/ios/Sources/CapacitorUpdaterPlugin/CapacitorUpdaterPlugin.swift +2 -2
- package/ios/Sources/CapacitorUpdaterPlugin/CapgoUpdater.swift +151 -107
- package/ios/Sources/CapacitorUpdaterPlugin/CryptoCipher.swift +34 -23
- package/package.json +6 -5
|
@@ -181,7 +181,8 @@ public class CapgoUpdater {
|
|
|
181
181
|
ZipEntry entry;
|
|
182
182
|
while ((entry = zis.getNextEntry()) != null) {
|
|
183
183
|
if (entry.getName().contains("\\")) {
|
|
184
|
-
logger.error("
|
|
184
|
+
logger.error("Unzip failed: Windows path not supported");
|
|
185
|
+
logger.debug("Invalid path: " + entry.getName());
|
|
185
186
|
this.sendStats("windows_path_fail");
|
|
186
187
|
}
|
|
187
188
|
final File file = new File(targetDirectory, entry.getName());
|
|
@@ -277,7 +278,8 @@ public class CapgoUpdater {
|
|
|
277
278
|
boolean success = finishDownload(id, dest, version, sessionKey, checksum, true, isManifest);
|
|
278
279
|
BundleInfo resultBundle;
|
|
279
280
|
if (!success) {
|
|
280
|
-
logger.error("Finish download failed
|
|
281
|
+
logger.error("Finish download failed");
|
|
282
|
+
logger.debug("Version: " + version);
|
|
281
283
|
resultBundle = new BundleInfo(
|
|
282
284
|
id,
|
|
283
285
|
version,
|
|
@@ -309,7 +311,8 @@ public class CapgoUpdater {
|
|
|
309
311
|
case FAILED:
|
|
310
312
|
Data failedData = workInfo.getOutputData();
|
|
311
313
|
String error = failedData.getString(DownloadService.ERROR);
|
|
312
|
-
logger.error("Download failed
|
|
314
|
+
logger.error("Download failed");
|
|
315
|
+
logger.debug("Error: " + error + ", State: " + workInfo.getState());
|
|
313
316
|
String failedVersion = failedData.getString(DownloadService.VERSION);
|
|
314
317
|
|
|
315
318
|
io.execute(() -> {
|
|
@@ -428,7 +431,8 @@ public class CapgoUpdater {
|
|
|
428
431
|
CryptoCipher.logChecksumInfo("Calculated checksum", checksum);
|
|
429
432
|
CryptoCipher.logChecksumInfo("Expected checksum", checksumDecrypted);
|
|
430
433
|
if ((!checksumDecrypted.isEmpty() || !this.publicKey.isEmpty()) && !checksumDecrypted.equals(checksum)) {
|
|
431
|
-
logger.error("
|
|
434
|
+
logger.error("Checksum mismatch");
|
|
435
|
+
logger.debug("Expected: " + checksumDecrypted + ", Got: " + checksum);
|
|
432
436
|
this.sendStats("checksum_fail");
|
|
433
437
|
throw new IOException("Checksum failed: " + id);
|
|
434
438
|
}
|
|
@@ -440,7 +444,8 @@ public class CapgoUpdater {
|
|
|
440
444
|
}
|
|
441
445
|
final Boolean res = this.delete(id);
|
|
442
446
|
if (!res) {
|
|
443
|
-
logger.info("
|
|
447
|
+
logger.info("Failed to cleanup after error");
|
|
448
|
+
logger.debug("Version: " + version);
|
|
444
449
|
}
|
|
445
450
|
|
|
446
451
|
final Map<String, Object> ret = new HashMap<>();
|
|
@@ -541,7 +546,8 @@ public class CapgoUpdater {
|
|
|
541
546
|
this.deleteDirectory(cacheFolder, threadToCheck);
|
|
542
547
|
logger.info("Cleaned up delta cache folder");
|
|
543
548
|
} catch (IOException e) {
|
|
544
|
-
logger.error("Failed to cleanup delta cache
|
|
549
|
+
logger.error("Failed to cleanup delta cache");
|
|
550
|
+
logger.debug("Error: " + e.getMessage());
|
|
545
551
|
}
|
|
546
552
|
}
|
|
547
553
|
|
|
@@ -582,9 +588,11 @@ public class CapgoUpdater {
|
|
|
582
588
|
try {
|
|
583
589
|
this.deleteDirectory(entry, threadToCheck);
|
|
584
590
|
this.removeBundleInfo(id);
|
|
585
|
-
logger.info("Deleted orphan bundle directory
|
|
591
|
+
logger.info("Deleted orphan bundle directory");
|
|
592
|
+
logger.debug("Bundle ID: " + id);
|
|
586
593
|
} catch (IOException e) {
|
|
587
|
-
logger.error("Failed to delete orphan bundle directory
|
|
594
|
+
logger.error("Failed to delete orphan bundle directory");
|
|
595
|
+
logger.debug("Bundle ID: " + id + ", Error: " + e.getMessage());
|
|
588
596
|
}
|
|
589
597
|
}
|
|
590
598
|
}
|
|
@@ -621,9 +629,11 @@ public class CapgoUpdater {
|
|
|
621
629
|
|
|
622
630
|
try {
|
|
623
631
|
this.deleteDirectory(entry, threadToCheck);
|
|
624
|
-
logger.info("Deleted orphaned temp unzip folder
|
|
632
|
+
logger.info("Deleted orphaned temp unzip folder");
|
|
633
|
+
logger.debug("Folder: " + folderName);
|
|
625
634
|
} catch (IOException e) {
|
|
626
|
-
logger.error("Failed to delete orphaned temp folder
|
|
635
|
+
logger.error("Failed to delete orphaned temp folder");
|
|
636
|
+
logger.debug("Folder: " + folderName + ", Error: " + e.getMessage());
|
|
627
637
|
}
|
|
628
638
|
}
|
|
629
639
|
}
|
|
@@ -710,7 +720,8 @@ public class CapgoUpdater {
|
|
|
710
720
|
} catch (Exception e) {
|
|
711
721
|
// Clean up on failure
|
|
712
722
|
downloadFutures.remove(id);
|
|
713
|
-
logger.error("Error waiting for download
|
|
723
|
+
logger.error("Error waiting for download");
|
|
724
|
+
logger.debug("Error: " + e.getMessage());
|
|
714
725
|
BundleInfo errorBundle = new BundleInfo(id, version, BundleStatus.ERROR, new Date(System.currentTimeMillis()), "");
|
|
715
726
|
saveBundleInfo(id, errorBundle);
|
|
716
727
|
if (e instanceof IOException) {
|
|
@@ -750,12 +761,14 @@ public class CapgoUpdater {
|
|
|
750
761
|
public Boolean delete(final String id, final Boolean removeInfo) throws IOException {
|
|
751
762
|
final BundleInfo deleted = this.getBundleInfo(id);
|
|
752
763
|
if (deleted.isBuiltin() || this.getCurrentBundleId().equals(id)) {
|
|
753
|
-
logger.error("Cannot delete
|
|
764
|
+
logger.error("Cannot delete current or builtin bundle");
|
|
765
|
+
logger.debug("Bundle ID: " + id);
|
|
754
766
|
return false;
|
|
755
767
|
}
|
|
756
768
|
final BundleInfo next = this.getNextBundle();
|
|
757
769
|
if (next != null && !next.isDeleted() && !next.isErrorStatus() && next.getId().equals(id)) {
|
|
758
|
-
logger.error("Cannot delete the next bundle"
|
|
770
|
+
logger.error("Cannot delete the next bundle");
|
|
771
|
+
logger.debug("Bundle ID: " + id);
|
|
759
772
|
return false;
|
|
760
773
|
}
|
|
761
774
|
// Cancel download for this version if active
|
|
@@ -772,7 +785,8 @@ public class CapgoUpdater {
|
|
|
772
785
|
}
|
|
773
786
|
return true;
|
|
774
787
|
}
|
|
775
|
-
logger.
|
|
788
|
+
logger.info("Bundle not found on disk");
|
|
789
|
+
logger.debug("Version: " + deleted.getVersionName());
|
|
776
790
|
// perhaps we did not find the bundle in the files, but if the user requested a delete, we delete
|
|
777
791
|
if (removeInfo) {
|
|
778
792
|
this.removeBundleInfo(id);
|
|
@@ -943,11 +957,13 @@ public class CapgoUpdater {
|
|
|
943
957
|
if (response.isSuccessful()) {
|
|
944
958
|
logger.info("Rate limit statistic sent");
|
|
945
959
|
} else {
|
|
946
|
-
logger.error("Error sending rate limit statistic
|
|
960
|
+
logger.error("Error sending rate limit statistic");
|
|
961
|
+
logger.debug("Response code: " + response.code());
|
|
947
962
|
}
|
|
948
963
|
}
|
|
949
964
|
} catch (final Exception e) {
|
|
950
|
-
logger.error("Failed to send rate limit statistic
|
|
965
|
+
logger.error("Failed to send rate limit statistic");
|
|
966
|
+
logger.debug("Error: " + e.getMessage());
|
|
951
967
|
}
|
|
952
968
|
}
|
|
953
969
|
|
|
@@ -1044,7 +1060,8 @@ public class CapgoUpdater {
|
|
|
1044
1060
|
json.put("defaultChannel", channel);
|
|
1045
1061
|
}
|
|
1046
1062
|
} catch (JSONException e) {
|
|
1047
|
-
logger.error("Error
|
|
1063
|
+
logger.error("Error getting latest version");
|
|
1064
|
+
logger.debug("JSONException: " + e.getMessage());
|
|
1048
1065
|
final Map<String, Object> retError = new HashMap<>();
|
|
1049
1066
|
retError.put("message", "Cannot get info: " + e);
|
|
1050
1067
|
retError.put("error", "json_error");
|
|
@@ -1116,7 +1133,8 @@ public class CapgoUpdater {
|
|
|
1116
1133
|
json = this.createInfoObject();
|
|
1117
1134
|
json.put("channel", channel);
|
|
1118
1135
|
} catch (JSONException e) {
|
|
1119
|
-
logger.error("Error
|
|
1136
|
+
logger.error("Error setting channel");
|
|
1137
|
+
logger.debug("JSONException: " + e.getMessage());
|
|
1120
1138
|
final Map<String, Object> retError = new HashMap<>();
|
|
1121
1139
|
retError.put("message", "Cannot get info: " + e);
|
|
1122
1140
|
retError.put("error", "json_error");
|
|
@@ -1162,7 +1180,8 @@ public class CapgoUpdater {
|
|
|
1162
1180
|
try {
|
|
1163
1181
|
json = this.createInfoObject();
|
|
1164
1182
|
} catch (JSONException e) {
|
|
1165
|
-
logger.error("Error
|
|
1183
|
+
logger.error("Error getting channel");
|
|
1184
|
+
logger.debug("JSONException: " + e.getMessage());
|
|
1166
1185
|
final Map<String, Object> retError = new HashMap<>();
|
|
1167
1186
|
retError.put("message", "Cannot get info: " + e);
|
|
1168
1187
|
retError.put("error", "json_error");
|
|
@@ -1284,7 +1303,8 @@ public class CapgoUpdater {
|
|
|
1284
1303
|
try {
|
|
1285
1304
|
json = this.createInfoObject();
|
|
1286
1305
|
} catch (JSONException e) {
|
|
1287
|
-
logger.error("Error creating info object
|
|
1306
|
+
logger.error("Error creating info object");
|
|
1307
|
+
logger.debug("JSONException: " + e.getMessage());
|
|
1288
1308
|
final Map<String, Object> retError = new HashMap<>();
|
|
1289
1309
|
retError.put("message", "Cannot get info: " + e);
|
|
1290
1310
|
retError.put("error", "json_error");
|
|
@@ -1304,7 +1324,8 @@ public class CapgoUpdater {
|
|
|
1304
1324
|
}
|
|
1305
1325
|
}
|
|
1306
1326
|
} catch (JSONException e) {
|
|
1307
|
-
logger.error("Error adding query parameters
|
|
1327
|
+
logger.error("Error adding query parameters");
|
|
1328
|
+
logger.debug("JSONException: " + e.getMessage());
|
|
1308
1329
|
}
|
|
1309
1330
|
|
|
1310
1331
|
Request request = new Request.Builder().url(urlBuilder.build()).get().build();
|
|
@@ -1425,7 +1446,8 @@ public class CapgoUpdater {
|
|
|
1425
1446
|
json.put("old_version_name", oldVersionName);
|
|
1426
1447
|
json.put("action", action);
|
|
1427
1448
|
} catch (JSONException e) {
|
|
1428
|
-
logger.error("Error
|
|
1449
|
+
logger.error("Error preparing stats");
|
|
1450
|
+
logger.debug("JSONException: " + e.getMessage());
|
|
1429
1451
|
return;
|
|
1430
1452
|
}
|
|
1431
1453
|
|
|
@@ -1440,7 +1462,8 @@ public class CapgoUpdater {
|
|
|
1440
1462
|
new okhttp3.Callback() {
|
|
1441
1463
|
@Override
|
|
1442
1464
|
public void onFailure(@NonNull Call call, @NonNull IOException e) {
|
|
1443
|
-
logger.error("Failed to send stats
|
|
1465
|
+
logger.error("Failed to send stats");
|
|
1466
|
+
logger.debug("Error: " + e.getMessage());
|
|
1444
1467
|
}
|
|
1445
1468
|
|
|
1446
1469
|
@Override
|
|
@@ -1452,9 +1475,11 @@ public class CapgoUpdater {
|
|
|
1452
1475
|
}
|
|
1453
1476
|
|
|
1454
1477
|
if (response.isSuccessful()) {
|
|
1455
|
-
logger.info("Stats
|
|
1478
|
+
logger.info("Stats sent successfully");
|
|
1479
|
+
logger.debug("Action: " + action + ", Version: " + versionName);
|
|
1456
1480
|
} else {
|
|
1457
|
-
logger.error("Error sending stats
|
|
1481
|
+
logger.error("Error sending stats");
|
|
1482
|
+
logger.debug("Response code: " + response.code());
|
|
1458
1483
|
}
|
|
1459
1484
|
}
|
|
1460
1485
|
}
|
|
@@ -1481,14 +1506,8 @@ public class CapgoUpdater {
|
|
|
1481
1506
|
result = BundleInfo.fromJSON(stored);
|
|
1482
1507
|
}
|
|
1483
1508
|
} catch (JSONException e) {
|
|
1484
|
-
logger.error(
|
|
1485
|
-
|
|
1486
|
-
trueId +
|
|
1487
|
-
"] stored value: '" +
|
|
1488
|
-
this.prefs.getString(trueId + INFO_SUFFIX, "") +
|
|
1489
|
-
"' error: " +
|
|
1490
|
-
e.getMessage()
|
|
1491
|
-
);
|
|
1509
|
+
logger.error("Failed to parse bundle info");
|
|
1510
|
+
logger.debug("Bundle ID: " + trueId + ", Error: " + e.getMessage());
|
|
1492
1511
|
// Clear corrupted data
|
|
1493
1512
|
this.editor.remove(trueId + INFO_SUFFIX);
|
|
1494
1513
|
this.editor.commit();
|
|
@@ -235,14 +235,11 @@ public class CryptoCipher {
|
|
|
235
235
|
detectedAlgorithm = "SHA-256";
|
|
236
236
|
} else if (decryptedChecksum.length == 4) {
|
|
237
237
|
detectedAlgorithm = "CRC32 (deprecated)";
|
|
238
|
-
logger.error(
|
|
239
|
-
"CRC32 checksum detected. This algorithm is deprecated and no longer supported. Please update your CLI to use SHA-256 checksums."
|
|
240
|
-
);
|
|
238
|
+
logger.error("CRC32 checksum detected - deprecated algorithm");
|
|
241
239
|
} else {
|
|
242
240
|
detectedAlgorithm = "unknown (" + decryptedChecksum.length + " bytes)";
|
|
243
|
-
logger.error(
|
|
244
|
-
|
|
245
|
-
);
|
|
241
|
+
logger.error("Unknown checksum algorithm detected");
|
|
242
|
+
logger.debug("Byte count: " + decryptedChecksum.length + ", Expected: 32 (SHA-256)");
|
|
246
243
|
}
|
|
247
244
|
logger.debug(
|
|
248
245
|
"Decrypted checksum: " +
|
|
@@ -255,7 +252,8 @@ public class CryptoCipher {
|
|
|
255
252
|
);
|
|
256
253
|
return result;
|
|
257
254
|
} catch (GeneralSecurityException e) {
|
|
258
|
-
logger.error("
|
|
255
|
+
logger.error("Checksum decryption failed");
|
|
256
|
+
logger.debug("Error: " + e.getMessage());
|
|
259
257
|
throw new IOException("Decryption failed: " + e.getMessage());
|
|
260
258
|
}
|
|
261
259
|
}
|
|
@@ -286,13 +284,10 @@ public class CryptoCipher {
|
|
|
286
284
|
String algorithm = detectChecksumAlgorithm(hexChecksum);
|
|
287
285
|
logger.debug(label + ": " + algorithm + " hex format (length: " + hexChecksum.length() + " chars)");
|
|
288
286
|
if (algorithm.contains("CRC32")) {
|
|
289
|
-
logger.error(
|
|
290
|
-
"CRC32 checksum detected. This algorithm is deprecated and no longer supported. Please update your CLI to use SHA-256 checksums."
|
|
291
|
-
);
|
|
287
|
+
logger.error("CRC32 checksum detected - deprecated algorithm");
|
|
292
288
|
} else if (algorithm.contains("unknown")) {
|
|
293
|
-
logger.error(
|
|
294
|
-
|
|
295
|
-
);
|
|
289
|
+
logger.error("Unknown checksum algorithm detected");
|
|
290
|
+
logger.debug("Char count: " + hexChecksum.length() + ", Expected: 64 (SHA-256)");
|
|
296
291
|
}
|
|
297
292
|
}
|
|
298
293
|
|
|
@@ -321,7 +316,8 @@ public class CryptoCipher {
|
|
|
321
316
|
}
|
|
322
317
|
return hexString.toString();
|
|
323
318
|
} catch (IOException e) {
|
|
324
|
-
logger.error("Cannot
|
|
319
|
+
logger.error("Cannot calculate checksum");
|
|
320
|
+
logger.debug("Path: " + file.getPath() + ", Error: " + e.getMessage());
|
|
325
321
|
return "";
|
|
326
322
|
}
|
|
327
323
|
}
|
|
@@ -8,7 +8,6 @@ package ee.forgr.capacitor_updater;
|
|
|
8
8
|
|
|
9
9
|
import android.content.Context;
|
|
10
10
|
import android.content.SharedPreferences;
|
|
11
|
-
import android.os.Build;
|
|
12
11
|
import android.security.keystore.KeyGenParameterSpec;
|
|
13
12
|
import android.security.keystore.KeyProperties;
|
|
14
13
|
import java.io.IOException;
|
|
@@ -56,11 +55,6 @@ public class DeviceIdHelper {
|
|
|
56
55
|
* @return Device ID as a lowercase UUID string
|
|
57
56
|
*/
|
|
58
57
|
public static String getOrCreateDeviceId(Context context, SharedPreferences legacyPrefs) {
|
|
59
|
-
// API 23+ required for Android Keystore
|
|
60
|
-
if (Build.VERSION.SDK_INT < Build.VERSION_CODES.M) {
|
|
61
|
-
return getFallbackDeviceId(legacyPrefs);
|
|
62
|
-
}
|
|
63
|
-
|
|
64
58
|
try {
|
|
65
59
|
// Try to get device ID from Keystore storage
|
|
66
60
|
String deviceId = getDeviceIdFromKeystore(context);
|