@capgo/capacitor-updater 8.41.2 → 8.41.4

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/README.md CHANGED
@@ -252,6 +252,10 @@ Capacitor Updater works by unzipping a compiled app bundle to the native device
252
252
  - Do not password encrypt the bundle zip file, or it will fail to unpack.
253
253
  - Make sure the bundle does not contain any extra hidden files or folders, or it may fail to unpack.
254
254
 
255
+ ### Downgrading to a previous version of the updater plugin
256
+
257
+ Downgrading to a previous version of the updater plugin is not supported.
258
+
255
259
  ## Updater Plugin Config
256
260
 
257
261
  <docgen-config>
@@ -85,7 +85,7 @@ public class CapacitorUpdaterPlugin extends Plugin {
85
85
  private static final String[] BREAKING_EVENT_NAMES = { "breakingAvailable", "majorAvailable" };
86
86
  private static final String LAST_FAILED_BUNDLE_PREF_KEY = "CapacitorUpdater.lastFailedBundle";
87
87
 
88
- private final String pluginVersion = "8.41.2";
88
+ private final String pluginVersion = "8.41.4";
89
89
  private static final String DELAY_CONDITION_PREFERENCES = "";
90
90
 
91
91
  private SharedPreferences.Editor editor;
@@ -210,7 +210,7 @@ public class CryptoCipher {
210
210
  detectedFormat = "base64";
211
211
  }
212
212
  logger.debug(
213
- "Received encrypted checksum format: " +
213
+ "Received checksum format: " +
214
214
  detectedFormat +
215
215
  " (length: " +
216
216
  checksum.length() +
@@ -218,6 +218,18 @@ public class CryptoCipher {
218
218
  checksumBytes.length +
219
219
  " bytes)"
220
220
  );
221
+
222
+ // RSA-2048 encrypted data must be exactly 256 bytes
223
+ // If the checksum is not 256 bytes, the bundle was not encrypted properly
224
+ if (checksumBytes.length != 256) {
225
+ logger.error(
226
+ "Checksum is not RSA encrypted (size: " +
227
+ checksumBytes.length +
228
+ " bytes, expected 256 for RSA-2048). Bundle must be uploaded with encryption when public key is configured."
229
+ );
230
+ throw new IOException("Bundle checksum is not encrypted. Upload bundle with --key flag when encryption is configured.");
231
+ }
232
+
221
233
  PublicKey pKey = CryptoCipher.stringToPublicKey(publicKey);
222
234
  byte[] decryptedChecksum = CryptoCipher.decryptRSA(checksumBytes, pKey);
223
235
  // Return as hex string to match calcChecksum output format
@@ -60,7 +60,7 @@ public class CapacitorUpdaterPlugin: CAPPlugin, CAPBridgedPlugin {
60
60
  CAPPluginMethod(name: "completeFlexibleUpdate", returnType: CAPPluginReturnPromise)
61
61
  ]
62
62
  public var implementation = CapgoUpdater()
63
- private let pluginVersion: String = "8.41.2"
63
+ private let pluginVersion: String = "8.41.4"
64
64
  static let updateUrlDefault = "https://plugin.capgo.app/updates"
65
65
  static let statsUrlDefault = "https://plugin.capgo.app/stats"
66
66
  static let channelUrlDefault = "https://plugin.capgo.app/channel_self"
@@ -382,6 +382,32 @@ public class CapacitorUpdaterPlugin: CAPPlugin, CAPBridgedPlugin {
382
382
  self.logger.info("Cleanup complete")
383
383
  }
384
384
 
385
+ // Michael (WcaleNieWolny) at 04.01.2026
386
+ // The following line of code contains a bug. After having evaluated it, I have decided not to fix it.
387
+ // The initial report: https://discord.com/channels/912707985829163099/1456985639345061969
388
+ // The bug happens in a very specific scenario. Here is the reproduction steps, followed by the lackof busniess impact
389
+ // Reproduction steps:
390
+ // 1. Install iOS app via app store. Version: 10.13.0. Version v10 of the app uses Capacitor 6 (6.3.13) - a version where the key was still "LatestVersionNative"
391
+ // 2. The plugin writes "10.13.0" to the key "LatestVersionNative"
392
+ // 3. Update the app to version 10.17.0 via Capgo.
393
+ // 4. Update the app via testflight to version 11.0.0. This version uses Capacitor 8 (8.41.3) - a version where the key was changed to "LatestNativeBuildVersion"
394
+ // 5. During the initial load of then new native version, the plugin will read "LatestNativeBuildVersion", not find it, read "LatestVersionNative", find it and revert to builtin version sucessfully.
395
+ // 6. The plugin writes "11.0.0" to the key "LatestNativeBuildVersion"
396
+ // 7. The app is now in a state where it is using the builtin version, but the key "LatestNativeBuildVersion" is still set to "11.0.0" and "LatestVersionNative" is still set to "10.13.0".
397
+ // 8. The user downgrades using app store back to version 10.13.0.
398
+ // 9. The old plugin reads "LatestVersionNative", finds "10.13.0," so it doesn't revert to builtin version. // <--- THIS IS THE FIRST PART OF THE BUG
399
+ // 10. "LatestVersionNative" is written to "10.13.0" but "LatestNativeBuildVersion" is not touched, and stays at "11.0.0"
400
+ // 11. A capgo update happesn to version 10.17.0.
401
+ // 12. The user updates again to version 11.0.0 via Testflight.
402
+ // 13. The plugin reads "LatestNativeBuildVersion", finds "11.0.0", so it doesn't revert to builtin version. It is unaware of the native update that happended.
403
+ // 14. Capgo loads the 10.13.0 version, while it should have loaded the builtin 11.0.0 version. // <--- THIS IS THE SECOND PART OF THE BUG
404
+ // The business impact:
405
+ // None - no one will ever be affected by this bug as reverting via app store should in practice never happen. You are not SUPPOSE to go from Capacitor v8 to v6.
406
+ // Downgrading isn't supported.
407
+ // Possible fixes:
408
+ // 1. Write "LatestVersionNative" - this fixes the part 1 of this bug
409
+ // 2. Compare both keys. If any is not equal to "currentBuildVersion", then revert to builtin version. This fixes the part 2 of this bug
410
+
385
411
  let previous = UserDefaults.standard.string(forKey: "LatestNativeBuildVersion") ?? UserDefaults.standard.string(forKey: "LatestVersionNative") ?? "0"
386
412
  if previous != "0" && self.currentBuildVersion != previous {
387
413
  _ = self._reset(toLastSuccessful: false)
@@ -63,13 +63,21 @@ public struct CryptoCipher {
63
63
  detectedFormat = "base64"
64
64
  }
65
65
  // swiftlint:disable:next line_length
66
- logger.debug("Received encrypted checksum format: \(detectedFormat) (length: \(checksum.count) chars, \(checksumBytes.count) bytes)")
66
+ logger.debug("Received checksum format: \(detectedFormat) (length: \(checksum.count) chars, \(checksumBytes.count) bytes)")
67
67
 
68
68
  if checksumBytes.isEmpty {
69
69
  logger.error("Decoded checksum is empty")
70
70
  throw CustomError.cannotDecode
71
71
  }
72
72
 
73
+ // RSA-2048 encrypted data must be exactly 256 bytes
74
+ // If the checksum is not 256 bytes, the bundle was not encrypted properly
75
+ if checksumBytes.count != 256 {
76
+ // swiftlint:disable:next line_length
77
+ logger.error("Checksum is not RSA encrypted (size: \(checksumBytes.count) bytes, expected 256 for RSA-2048). Bundle must be uploaded with encryption when public key is configured.")
78
+ throw CustomError.cannotDecode
79
+ }
80
+
73
81
  guard let rsaPublicKey = RSAPublicKey.load(rsaPublicKey: publicKey) else {
74
82
  logger.error("The public key is not a valid RSA Public key")
75
83
  throw CustomError.cannotDecode
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@capgo/capacitor-updater",
3
- "version": "8.41.2",
3
+ "version": "8.41.4",
4
4
  "license": "MPL-2.0",
5
5
  "description": "Live update for capacitor apps",
6
6
  "main": "dist/plugin.cjs.js",