@capgo/capacitor-updater 7.39.0 → 7.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 -199
- 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 -668
- package/dist/esm/definitions.d.ts +23 -342
- 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
|
@@ -179,7 +179,8 @@ public class CapgoUpdater {
|
|
|
179
179
|
ZipEntry entry;
|
|
180
180
|
while ((entry = zis.getNextEntry()) != null) {
|
|
181
181
|
if (entry.getName().contains("\\")) {
|
|
182
|
-
logger.error("
|
|
182
|
+
logger.error("Unzip failed: Windows path not supported");
|
|
183
|
+
logger.debug("Invalid path: " + entry.getName());
|
|
183
184
|
this.sendStats("windows_path_fail");
|
|
184
185
|
}
|
|
185
186
|
final File file = new File(targetDirectory, entry.getName());
|
|
@@ -275,7 +276,8 @@ public class CapgoUpdater {
|
|
|
275
276
|
boolean success = finishDownload(id, dest, version, sessionKey, checksum, true, isManifest);
|
|
276
277
|
BundleInfo resultBundle;
|
|
277
278
|
if (!success) {
|
|
278
|
-
logger.error("Finish download failed
|
|
279
|
+
logger.error("Finish download failed");
|
|
280
|
+
logger.debug("Version: " + version);
|
|
279
281
|
resultBundle = new BundleInfo(
|
|
280
282
|
id,
|
|
281
283
|
version,
|
|
@@ -307,7 +309,8 @@ public class CapgoUpdater {
|
|
|
307
309
|
case FAILED:
|
|
308
310
|
Data failedData = workInfo.getOutputData();
|
|
309
311
|
String error = failedData.getString(DownloadService.ERROR);
|
|
310
|
-
logger.error("Download failed
|
|
312
|
+
logger.error("Download failed");
|
|
313
|
+
logger.debug("Error: " + error + ", State: " + workInfo.getState());
|
|
311
314
|
String failedVersion = failedData.getString(DownloadService.VERSION);
|
|
312
315
|
|
|
313
316
|
io.execute(() -> {
|
|
@@ -423,7 +426,8 @@ public class CapgoUpdater {
|
|
|
423
426
|
CryptoCipher.logChecksumInfo("Calculated checksum", checksum);
|
|
424
427
|
CryptoCipher.logChecksumInfo("Expected checksum", checksumDecrypted);
|
|
425
428
|
if ((!checksumDecrypted.isEmpty() || !this.publicKey.isEmpty()) && !checksumDecrypted.equals(checksum)) {
|
|
426
|
-
logger.error("
|
|
429
|
+
logger.error("Checksum mismatch");
|
|
430
|
+
logger.debug("Expected: " + checksumDecrypted + ", Got: " + checksum);
|
|
427
431
|
this.sendStats("checksum_fail");
|
|
428
432
|
throw new IOException("Checksum failed: " + id);
|
|
429
433
|
}
|
|
@@ -435,7 +439,8 @@ public class CapgoUpdater {
|
|
|
435
439
|
}
|
|
436
440
|
final Boolean res = this.delete(id);
|
|
437
441
|
if (!res) {
|
|
438
|
-
logger.info("
|
|
442
|
+
logger.info("Failed to cleanup after error");
|
|
443
|
+
logger.debug("Version: " + version);
|
|
439
444
|
}
|
|
440
445
|
|
|
441
446
|
final Map<String, Object> ret = new HashMap<>();
|
|
@@ -536,7 +541,8 @@ public class CapgoUpdater {
|
|
|
536
541
|
this.deleteDirectory(cacheFolder, threadToCheck);
|
|
537
542
|
logger.info("Cleaned up delta cache folder");
|
|
538
543
|
} catch (IOException e) {
|
|
539
|
-
logger.error("Failed to cleanup delta cache
|
|
544
|
+
logger.error("Failed to cleanup delta cache");
|
|
545
|
+
logger.debug("Error: " + e.getMessage());
|
|
540
546
|
}
|
|
541
547
|
}
|
|
542
548
|
|
|
@@ -577,9 +583,11 @@ public class CapgoUpdater {
|
|
|
577
583
|
try {
|
|
578
584
|
this.deleteDirectory(entry, threadToCheck);
|
|
579
585
|
this.removeBundleInfo(id);
|
|
580
|
-
logger.info("Deleted orphan bundle directory
|
|
586
|
+
logger.info("Deleted orphan bundle directory");
|
|
587
|
+
logger.debug("Bundle ID: " + id);
|
|
581
588
|
} catch (IOException e) {
|
|
582
|
-
logger.error("Failed to delete orphan bundle directory
|
|
589
|
+
logger.error("Failed to delete orphan bundle directory");
|
|
590
|
+
logger.debug("Bundle ID: " + id + ", Error: " + e.getMessage());
|
|
583
591
|
}
|
|
584
592
|
}
|
|
585
593
|
}
|
|
@@ -616,9 +624,11 @@ public class CapgoUpdater {
|
|
|
616
624
|
|
|
617
625
|
try {
|
|
618
626
|
this.deleteDirectory(entry, threadToCheck);
|
|
619
|
-
logger.info("Deleted orphaned temp unzip folder
|
|
627
|
+
logger.info("Deleted orphaned temp unzip folder");
|
|
628
|
+
logger.debug("Folder: " + folderName);
|
|
620
629
|
} catch (IOException e) {
|
|
621
|
-
logger.error("Failed to delete orphaned temp folder
|
|
630
|
+
logger.error("Failed to delete orphaned temp folder");
|
|
631
|
+
logger.debug("Folder: " + folderName + ", Error: " + e.getMessage());
|
|
622
632
|
}
|
|
623
633
|
}
|
|
624
634
|
}
|
|
@@ -705,7 +715,8 @@ public class CapgoUpdater {
|
|
|
705
715
|
} catch (Exception e) {
|
|
706
716
|
// Clean up on failure
|
|
707
717
|
downloadFutures.remove(id);
|
|
708
|
-
logger.error("Error waiting for download
|
|
718
|
+
logger.error("Error waiting for download");
|
|
719
|
+
logger.debug("Error: " + e.getMessage());
|
|
709
720
|
BundleInfo errorBundle = new BundleInfo(id, version, BundleStatus.ERROR, new Date(System.currentTimeMillis()), "");
|
|
710
721
|
saveBundleInfo(id, errorBundle);
|
|
711
722
|
if (e instanceof IOException) {
|
|
@@ -745,12 +756,14 @@ public class CapgoUpdater {
|
|
|
745
756
|
public Boolean delete(final String id, final Boolean removeInfo) throws IOException {
|
|
746
757
|
final BundleInfo deleted = this.getBundleInfo(id);
|
|
747
758
|
if (deleted.isBuiltin() || this.getCurrentBundleId().equals(id)) {
|
|
748
|
-
logger.error("Cannot delete
|
|
759
|
+
logger.error("Cannot delete current or builtin bundle");
|
|
760
|
+
logger.debug("Bundle ID: " + id);
|
|
749
761
|
return false;
|
|
750
762
|
}
|
|
751
763
|
final BundleInfo next = this.getNextBundle();
|
|
752
764
|
if (next != null && !next.isDeleted() && !next.isErrorStatus() && next.getId().equals(id)) {
|
|
753
|
-
logger.error("Cannot delete the next bundle"
|
|
765
|
+
logger.error("Cannot delete the next bundle");
|
|
766
|
+
logger.debug("Bundle ID: " + id);
|
|
754
767
|
return false;
|
|
755
768
|
}
|
|
756
769
|
// Cancel download for this version if active
|
|
@@ -767,7 +780,8 @@ public class CapgoUpdater {
|
|
|
767
780
|
}
|
|
768
781
|
return true;
|
|
769
782
|
}
|
|
770
|
-
logger.
|
|
783
|
+
logger.info("Bundle not found on disk");
|
|
784
|
+
logger.debug("Version: " + deleted.getVersionName());
|
|
771
785
|
// perhaps we did not find the bundle in the files, but if the user requested a delete, we delete
|
|
772
786
|
if (removeInfo) {
|
|
773
787
|
this.removeBundleInfo(id);
|
|
@@ -938,11 +952,13 @@ public class CapgoUpdater {
|
|
|
938
952
|
if (response.isSuccessful()) {
|
|
939
953
|
logger.info("Rate limit statistic sent");
|
|
940
954
|
} else {
|
|
941
|
-
logger.error("Error sending rate limit statistic
|
|
955
|
+
logger.error("Error sending rate limit statistic");
|
|
956
|
+
logger.debug("Response code: " + response.code());
|
|
942
957
|
}
|
|
943
958
|
}
|
|
944
959
|
} catch (final Exception e) {
|
|
945
|
-
logger.error("Failed to send rate limit statistic
|
|
960
|
+
logger.error("Failed to send rate limit statistic");
|
|
961
|
+
logger.debug("Error: " + e.getMessage());
|
|
946
962
|
}
|
|
947
963
|
}
|
|
948
964
|
|
|
@@ -1039,7 +1055,8 @@ public class CapgoUpdater {
|
|
|
1039
1055
|
json.put("defaultChannel", channel);
|
|
1040
1056
|
}
|
|
1041
1057
|
} catch (JSONException e) {
|
|
1042
|
-
logger.error("Error
|
|
1058
|
+
logger.error("Error getting latest version");
|
|
1059
|
+
logger.debug("JSONException: " + e.getMessage());
|
|
1043
1060
|
final Map<String, Object> retError = new HashMap<>();
|
|
1044
1061
|
retError.put("message", "Cannot get info: " + e);
|
|
1045
1062
|
retError.put("error", "json_error");
|
|
@@ -1111,7 +1128,8 @@ public class CapgoUpdater {
|
|
|
1111
1128
|
json = this.createInfoObject();
|
|
1112
1129
|
json.put("channel", channel);
|
|
1113
1130
|
} catch (JSONException e) {
|
|
1114
|
-
logger.error("Error
|
|
1131
|
+
logger.error("Error setting channel");
|
|
1132
|
+
logger.debug("JSONException: " + e.getMessage());
|
|
1115
1133
|
final Map<String, Object> retError = new HashMap<>();
|
|
1116
1134
|
retError.put("message", "Cannot get info: " + e);
|
|
1117
1135
|
retError.put("error", "json_error");
|
|
@@ -1157,7 +1175,8 @@ public class CapgoUpdater {
|
|
|
1157
1175
|
try {
|
|
1158
1176
|
json = this.createInfoObject();
|
|
1159
1177
|
} catch (JSONException e) {
|
|
1160
|
-
logger.error("Error
|
|
1178
|
+
logger.error("Error getting channel");
|
|
1179
|
+
logger.debug("JSONException: " + e.getMessage());
|
|
1161
1180
|
final Map<String, Object> retError = new HashMap<>();
|
|
1162
1181
|
retError.put("message", "Cannot get info: " + e);
|
|
1163
1182
|
retError.put("error", "json_error");
|
|
@@ -1279,7 +1298,8 @@ public class CapgoUpdater {
|
|
|
1279
1298
|
try {
|
|
1280
1299
|
json = this.createInfoObject();
|
|
1281
1300
|
} catch (JSONException e) {
|
|
1282
|
-
logger.error("Error creating info object
|
|
1301
|
+
logger.error("Error creating info object");
|
|
1302
|
+
logger.debug("JSONException: " + e.getMessage());
|
|
1283
1303
|
final Map<String, Object> retError = new HashMap<>();
|
|
1284
1304
|
retError.put("message", "Cannot get info: " + e);
|
|
1285
1305
|
retError.put("error", "json_error");
|
|
@@ -1299,7 +1319,8 @@ public class CapgoUpdater {
|
|
|
1299
1319
|
}
|
|
1300
1320
|
}
|
|
1301
1321
|
} catch (JSONException e) {
|
|
1302
|
-
logger.error("Error adding query parameters
|
|
1322
|
+
logger.error("Error adding query parameters");
|
|
1323
|
+
logger.debug("JSONException: " + e.getMessage());
|
|
1303
1324
|
}
|
|
1304
1325
|
|
|
1305
1326
|
Request request = new Request.Builder().url(urlBuilder.build()).get().build();
|
|
@@ -1420,7 +1441,8 @@ public class CapgoUpdater {
|
|
|
1420
1441
|
json.put("old_version_name", oldVersionName);
|
|
1421
1442
|
json.put("action", action);
|
|
1422
1443
|
} catch (JSONException e) {
|
|
1423
|
-
logger.error("Error
|
|
1444
|
+
logger.error("Error preparing stats");
|
|
1445
|
+
logger.debug("JSONException: " + e.getMessage());
|
|
1424
1446
|
return;
|
|
1425
1447
|
}
|
|
1426
1448
|
|
|
@@ -1435,7 +1457,8 @@ public class CapgoUpdater {
|
|
|
1435
1457
|
new okhttp3.Callback() {
|
|
1436
1458
|
@Override
|
|
1437
1459
|
public void onFailure(@NonNull Call call, @NonNull IOException e) {
|
|
1438
|
-
logger.error("Failed to send stats
|
|
1460
|
+
logger.error("Failed to send stats");
|
|
1461
|
+
logger.debug("Error: " + e.getMessage());
|
|
1439
1462
|
}
|
|
1440
1463
|
|
|
1441
1464
|
@Override
|
|
@@ -1447,9 +1470,11 @@ public class CapgoUpdater {
|
|
|
1447
1470
|
}
|
|
1448
1471
|
|
|
1449
1472
|
if (response.isSuccessful()) {
|
|
1450
|
-
logger.info("Stats
|
|
1473
|
+
logger.info("Stats sent successfully");
|
|
1474
|
+
logger.debug("Action: " + action + ", Version: " + versionName);
|
|
1451
1475
|
} else {
|
|
1452
|
-
logger.error("Error sending stats
|
|
1476
|
+
logger.error("Error sending stats");
|
|
1477
|
+
logger.debug("Response code: " + response.code());
|
|
1453
1478
|
}
|
|
1454
1479
|
}
|
|
1455
1480
|
}
|
|
@@ -1476,14 +1501,8 @@ public class CapgoUpdater {
|
|
|
1476
1501
|
result = BundleInfo.fromJSON(stored);
|
|
1477
1502
|
}
|
|
1478
1503
|
} catch (JSONException e) {
|
|
1479
|
-
logger.error(
|
|
1480
|
-
|
|
1481
|
-
trueId +
|
|
1482
|
-
"] stored value: '" +
|
|
1483
|
-
this.prefs.getString(trueId + INFO_SUFFIX, "") +
|
|
1484
|
-
"' error: " +
|
|
1485
|
-
e.getMessage()
|
|
1486
|
-
);
|
|
1504
|
+
logger.error("Failed to parse bundle info");
|
|
1505
|
+
logger.debug("Bundle ID: " + trueId + ", Error: " + e.getMessage());
|
|
1487
1506
|
// Clear corrupted data
|
|
1488
1507
|
this.editor.remove(trueId + INFO_SUFFIX);
|
|
1489
1508
|
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);
|