@capgo/capacitor-updater 6.11.1 → 6.12.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/Package.swift CHANGED
@@ -21,15 +21,15 @@ let package = Package(
21
21
  dependencies: [
22
22
  .product(name: "Capacitor", package: "capacitor-swift-pm"),
23
23
  .product(name: "Cordova", package: "capacitor-swift-pm"),
24
- .product(name: "SSZipArchive", package: "ZipArchive"),
24
+ .product(name: "ZipArchive", package: "ZipArchive"),
25
25
  .product(name: "Alamofire", package: "Alamofire"),
26
26
  .product(name: "Version", package: "Version")
27
27
  ],
28
- path: "ios/Sources/CapacitorUpdaterPlugin"),
28
+ path: "ios/Plugin"),
29
29
  .testTarget(
30
30
  name: "CapacitorUpdaterPluginTests",
31
31
  dependencies: ["CapacitorUpdaterPlugin"],
32
- path: "ios/Tests/CapacitorUpdaterPluginTests")
32
+ path: "ios/PluginTests")
33
33
  ],
34
34
  swiftLanguageVersions: [.v5]
35
35
  )
@@ -365,6 +365,7 @@ public class CapacitorUpdater {
365
365
  version,
366
366
  sessionKey,
367
367
  checksum,
368
+ this.publicKey,
368
369
  manifest != null
369
370
  );
370
371
 
@@ -373,26 +374,6 @@ public class CapacitorUpdater {
373
374
  }
374
375
  }
375
376
 
376
- private String decryptChecksum(String checksum, String version)
377
- throws IOException {
378
- if (this.publicKey.isEmpty()) {
379
- Log.e(CapacitorUpdater.TAG, "The public key is empty");
380
- return checksum;
381
- }
382
- try {
383
- byte[] checksumBytes = Base64.decode(checksum, Base64.DEFAULT);
384
- PublicKey pKey = CryptoCipherV2.stringToPublicKey(this.publicKey);
385
- byte[] decryptedChecksum = CryptoCipherV2.decryptRSA(checksumBytes, pKey);
386
- // return Base64.encodeToString(decryptedChecksum, Base64.DEFAULT);
387
- String result = Base64.encodeToString(decryptedChecksum, Base64.DEFAULT);
388
- return result.replaceAll("\\s", ""); // Remove all whitespace, including newlines
389
- } catch (GeneralSecurityException e) {
390
- Log.e(TAG, "decryptChecksum fail: " + e.getMessage());
391
- this.sendStats("decrypt_fail", version);
392
- throw new IOException("Decryption failed: " + e.getMessage());
393
- }
394
- }
395
-
396
377
  public Boolean finishDownload(
397
378
  String id,
398
379
  String dest,
@@ -412,12 +393,15 @@ public class CapacitorUpdater {
412
393
  if (!isManifest) {
413
394
  String checksumDecrypted = Objects.requireNonNullElse(checksumRes, "");
414
395
  if (!this.hasOldPrivateKeyPropertyInConfig && !sessionKey.isEmpty()) {
415
- this.decryptFileV2(downloaded, sessionKey, version);
416
- checksumDecrypted = this.decryptChecksum(checksumRes, version);
417
- checksum = this.calcChecksumV2(downloaded);
396
+ CryptoCipherV2.decryptFile(downloaded, publicKey, sessionKey);
397
+ checksumDecrypted = CryptoCipherV2.decryptChecksum(
398
+ checksumRes,
399
+ publicKey
400
+ );
401
+ checksum = CryptoCipherV2.calcChecksum(downloaded);
418
402
  } else {
419
- this.decryptFile(downloaded, sessionKey, version);
420
- checksum = this.calcChecksum(downloaded);
403
+ CryptoCipher.decryptFile(downloaded, privateKey, sessionKey, version);
404
+ checksum = CryptoCipher.calcChecksum(downloaded);
421
405
  }
422
406
  if (
423
407
  (!checksumDecrypted.isEmpty() || !this.publicKey.isEmpty()) &&
@@ -517,177 +501,6 @@ public class CapacitorUpdater {
517
501
  this.editor.commit();
518
502
  }
519
503
 
520
- private String calcChecksum(File file) {
521
- final int BUFFER_SIZE = 1024 * 1024 * 5; // 5 MB buffer size
522
- CRC32 crc = new CRC32();
523
-
524
- try (FileInputStream fis = new FileInputStream(file)) {
525
- byte[] buffer = new byte[BUFFER_SIZE];
526
- int length;
527
- while ((length = fis.read(buffer)) != -1) {
528
- crc.update(buffer, 0, length);
529
- }
530
- return String.format("%08x", crc.getValue());
531
- } catch (IOException e) {
532
- System.err.println(
533
- TAG + " Cannot calc checksum: " + file.getPath() + " " + e.getMessage()
534
- );
535
- return "";
536
- }
537
- }
538
-
539
- private String calcChecksumV2(File file) {
540
- final int BUFFER_SIZE = 1024 * 1024 * 5; // 5 MB buffer size
541
- MessageDigest digest;
542
- try {
543
- digest = MessageDigest.getInstance("SHA-256");
544
- } catch (java.security.NoSuchAlgorithmException e) {
545
- System.err.println(TAG + " SHA-256 algorithm not available");
546
- return "";
547
- }
548
-
549
- try (FileInputStream fis = new FileInputStream(file)) {
550
- byte[] buffer = new byte[BUFFER_SIZE];
551
- int length;
552
- while ((length = fis.read(buffer)) != -1) {
553
- digest.update(buffer, 0, length);
554
- }
555
- byte[] hash = digest.digest();
556
- StringBuilder hexString = new StringBuilder();
557
- for (byte b : hash) {
558
- String hex = Integer.toHexString(0xff & b);
559
- if (hex.length() == 1) hexString.append('0');
560
- hexString.append(hex);
561
- }
562
- return hexString.toString();
563
- } catch (IOException e) {
564
- System.err.println(
565
- TAG +
566
- " Cannot calc checksum v2: " +
567
- file.getPath() +
568
- " " +
569
- e.getMessage()
570
- );
571
- return "";
572
- }
573
- }
574
-
575
- private void decryptFileV2(
576
- final File file,
577
- final String ivSessionKey,
578
- final String version
579
- ) throws IOException {
580
- // (str != null && !str.isEmpty())
581
- if (
582
- this.publicKey.isEmpty() ||
583
- ivSessionKey == null ||
584
- ivSessionKey.isEmpty() ||
585
- ivSessionKey.split(":").length != 2
586
- ) {
587
- Log.i(TAG, "Cannot found public key or sessionKey");
588
- return;
589
- }
590
- if (!this.publicKey.startsWith("-----BEGIN RSA PUBLIC KEY-----")) {
591
- Log.e(
592
- CapacitorUpdater.TAG,
593
- "The public key is not a valid RSA Public key"
594
- );
595
- return;
596
- }
597
- try {
598
- String ivB64 = ivSessionKey.split(":")[0];
599
- String sessionKeyB64 = ivSessionKey.split(":")[1];
600
- byte[] iv = Base64.decode(ivB64.getBytes(), Base64.DEFAULT);
601
- byte[] sessionKey = Base64.decode(
602
- sessionKeyB64.getBytes(),
603
- Base64.DEFAULT
604
- );
605
- PublicKey pKey = CryptoCipherV2.stringToPublicKey(this.publicKey);
606
- byte[] decryptedSessionKey = CryptoCipherV2.decryptRSA(sessionKey, pKey);
607
-
608
- SecretKey sKey = CryptoCipherV2.byteToSessionKey(decryptedSessionKey);
609
- byte[] content = new byte[(int) file.length()];
610
-
611
- try (
612
- final FileInputStream fis = new FileInputStream(file);
613
- final BufferedInputStream bis = new BufferedInputStream(fis);
614
- final DataInputStream dis = new DataInputStream(bis)
615
- ) {
616
- dis.readFully(content);
617
- dis.close();
618
- byte[] decrypted = CryptoCipherV2.decryptAES(content, sKey, iv);
619
- // write the decrypted string to the file
620
- try (
621
- final FileOutputStream fos = new FileOutputStream(
622
- file.getAbsolutePath()
623
- )
624
- ) {
625
- fos.write(decrypted);
626
- }
627
- }
628
- } catch (GeneralSecurityException e) {
629
- Log.i(TAG, "decryptFile fail");
630
- this.sendStats("decrypt_fail", version);
631
- e.printStackTrace();
632
- throw new IOException("GeneralSecurityException");
633
- }
634
- }
635
-
636
- private void decryptFile(
637
- final File file,
638
- final String ivSessionKey,
639
- final String version
640
- ) throws IOException {
641
- // (str != null && !str.isEmpty())
642
- if (this.privateKey == null || this.privateKey.isEmpty()) {
643
- Log.i(TAG, "Cannot found privateKey");
644
- return;
645
- } else if (
646
- ivSessionKey == null ||
647
- ivSessionKey.isEmpty() ||
648
- ivSessionKey.split(":").length != 2
649
- ) {
650
- Log.i(TAG, "Cannot found sessionKey");
651
- return;
652
- }
653
- try {
654
- String ivB64 = ivSessionKey.split(":")[0];
655
- String sessionKeyB64 = ivSessionKey.split(":")[1];
656
- byte[] iv = Base64.decode(ivB64.getBytes(), Base64.DEFAULT);
657
- byte[] sessionKey = Base64.decode(
658
- sessionKeyB64.getBytes(),
659
- Base64.DEFAULT
660
- );
661
- PrivateKey pKey = CryptoCipher.stringToPrivateKey(this.privateKey);
662
- byte[] decryptedSessionKey = CryptoCipher.decryptRSA(sessionKey, pKey);
663
- SecretKey sKey = CryptoCipher.byteToSessionKey(decryptedSessionKey);
664
- byte[] content = new byte[(int) file.length()];
665
-
666
- try (
667
- final FileInputStream fis = new FileInputStream(file);
668
- final BufferedInputStream bis = new BufferedInputStream(fis);
669
- final DataInputStream dis = new DataInputStream(bis)
670
- ) {
671
- dis.readFully(content);
672
- dis.close();
673
- byte[] decrypted = CryptoCipher.decryptAES(content, sKey, iv);
674
- // write the decrypted string to the file
675
- try (
676
- final FileOutputStream fos = new FileOutputStream(
677
- file.getAbsolutePath()
678
- )
679
- ) {
680
- fos.write(decrypted);
681
- }
682
- }
683
- } catch (GeneralSecurityException e) {
684
- Log.i(TAG, "decryptFile fail");
685
- this.sendStats("decrypt_fail", version);
686
- e.printStackTrace();
687
- throw new IOException("GeneralSecurityException");
688
- }
689
- }
690
-
691
504
  public void downloadBackground(
692
505
  final String url,
693
506
  final String version,
@@ -60,7 +60,7 @@ public class CapacitorUpdaterPlugin extends Plugin {
60
60
  private static final String channelUrlDefault =
61
61
  "https://plugin.capgo.app/channel_self";
62
62
 
63
- private final String PLUGIN_VERSION = "6.11.1";
63
+ private final String PLUGIN_VERSION = "6.12.0";
64
64
  private static final String DELAY_CONDITION_PREFERENCES = "";
65
65
 
66
66
  private SharedPreferences.Editor editor;
@@ -13,6 +13,12 @@ package ee.forgr.capacitor_updater;
13
13
  */
14
14
  import android.util.Base64;
15
15
  import android.util.Log;
16
+ import java.io.BufferedInputStream;
17
+ import java.io.DataInputStream;
18
+ import java.io.File;
19
+ import java.io.FileInputStream;
20
+ import java.io.FileOutputStream;
21
+ import java.io.IOException;
16
22
  import java.security.GeneralSecurityException;
17
23
  import java.security.InvalidAlgorithmParameterException;
18
24
  import java.security.InvalidKeyException;
@@ -24,6 +30,7 @@ import java.security.spec.InvalidKeySpecException;
24
30
  import java.security.spec.MGF1ParameterSpec;
25
31
  import java.security.spec.PKCS8EncodedKeySpec;
26
32
  import java.security.spec.X509EncodedKeySpec;
33
+ import java.util.zip.CRC32;
27
34
  import javax.crypto.BadPaddingException;
28
35
  import javax.crypto.Cipher;
29
36
  import javax.crypto.IllegalBlockSizeException;
@@ -146,6 +153,84 @@ public class CryptoCipher {
146
153
  return readPkcs1PrivateKey(pkcs1EncodedBytes);
147
154
  }
148
155
 
156
+ public static void decryptFile(
157
+ final File file,
158
+ final String privateKey,
159
+ final String ivSessionKey,
160
+ final String version
161
+ ) throws IOException {
162
+ // (str != null && !str.isEmpty())
163
+ if (privateKey == null || privateKey.isEmpty()) {
164
+ Log.i(CapacitorUpdater.TAG, "Cannot found privateKey");
165
+ return;
166
+ } else if (
167
+ ivSessionKey == null ||
168
+ ivSessionKey.isEmpty() ||
169
+ ivSessionKey.split(":").length != 2
170
+ ) {
171
+ Log.i(CapacitorUpdater.TAG, "Cannot found sessionKey");
172
+ return;
173
+ }
174
+ try {
175
+ String ivB64 = ivSessionKey.split(":")[0];
176
+ String sessionKeyB64 = ivSessionKey.split(":")[1];
177
+ byte[] iv = Base64.decode(ivB64.getBytes(), Base64.DEFAULT);
178
+ byte[] sessionKey = Base64.decode(
179
+ sessionKeyB64.getBytes(),
180
+ Base64.DEFAULT
181
+ );
182
+ PrivateKey pKey = CryptoCipher.stringToPrivateKey(privateKey);
183
+ byte[] decryptedSessionKey = CryptoCipher.decryptRSA(sessionKey, pKey);
184
+ SecretKey sKey = CryptoCipher.byteToSessionKey(decryptedSessionKey);
185
+ byte[] content = new byte[(int) file.length()];
186
+
187
+ try (
188
+ final FileInputStream fis = new FileInputStream(file);
189
+ final BufferedInputStream bis = new BufferedInputStream(fis);
190
+ final DataInputStream dis = new DataInputStream(bis)
191
+ ) {
192
+ dis.readFully(content);
193
+ dis.close();
194
+ byte[] decrypted = CryptoCipher.decryptAES(content, sKey, iv);
195
+ // write the decrypted string to the file
196
+ try (
197
+ final FileOutputStream fos = new FileOutputStream(
198
+ file.getAbsolutePath()
199
+ )
200
+ ) {
201
+ fos.write(decrypted);
202
+ }
203
+ }
204
+ } catch (GeneralSecurityException e) {
205
+ Log.i(CapacitorUpdater.TAG, "decryptFile fail");
206
+ e.printStackTrace();
207
+ throw new IOException("GeneralSecurityException");
208
+ }
209
+ }
210
+
211
+ public static String calcChecksum(File file) {
212
+ final int BUFFER_SIZE = 1024 * 1024 * 5; // 5 MB buffer size
213
+ CRC32 crc = new CRC32();
214
+
215
+ try (FileInputStream fis = new FileInputStream(file)) {
216
+ byte[] buffer = new byte[BUFFER_SIZE];
217
+ int length;
218
+ while ((length = fis.read(buffer)) != -1) {
219
+ crc.update(buffer, 0, length);
220
+ }
221
+ return String.format("%08x", crc.getValue());
222
+ } catch (IOException e) {
223
+ System.err.println(
224
+ CapacitorUpdater.TAG +
225
+ " Cannot calc checksum: " +
226
+ file.getPath() +
227
+ " " +
228
+ e.getMessage()
229
+ );
230
+ return "";
231
+ }
232
+ }
233
+
149
234
  public static PublicKey stringToPublicKey(String publicKey) {
150
235
  byte[] encoded = Base64.decode(publicKey, Base64.DEFAULT);
151
236
 
@@ -12,10 +12,18 @@ package ee.forgr.capacitor_updater;
12
12
  * references: http://stackoverflow.com/questions/12471999/rsa-encryption-decryption-in-android
13
13
  */
14
14
  import android.util.Base64;
15
+ import android.util.Log;
16
+ import java.io.BufferedInputStream;
17
+ import java.io.DataInputStream;
18
+ import java.io.File;
19
+ import java.io.FileInputStream;
20
+ import java.io.FileOutputStream;
21
+ import java.io.IOException;
15
22
  import java.security.GeneralSecurityException;
16
23
  import java.security.InvalidAlgorithmParameterException;
17
24
  import java.security.InvalidKeyException;
18
25
  import java.security.KeyFactory;
26
+ import java.security.MessageDigest;
19
27
  import java.security.NoSuchAlgorithmException;
20
28
  import java.security.PublicKey;
21
29
  import java.security.spec.InvalidKeySpecException;
@@ -26,7 +34,6 @@ import javax.crypto.IllegalBlockSizeException;
26
34
  import javax.crypto.NoSuchPaddingException;
27
35
  import javax.crypto.SecretKey;
28
36
  import javax.crypto.spec.IvParameterSpec;
29
- import javax.crypto.spec.PSource;
30
37
  import javax.crypto.spec.SecretKeySpec;
31
38
 
32
39
  public class CryptoCipherV2 {
@@ -134,6 +141,145 @@ public class CryptoCipherV2 {
134
141
  return buf;
135
142
  }
136
143
 
144
+ public static void decryptFile(
145
+ final File file,
146
+ final String publicKey,
147
+ final String ivSessionKey
148
+ ) throws IOException {
149
+ if (
150
+ publicKey.isEmpty() ||
151
+ ivSessionKey == null ||
152
+ ivSessionKey.isEmpty() ||
153
+ ivSessionKey.split(":").length != 2
154
+ ) {
155
+ Log.i(CapacitorUpdater.TAG, "Cannot found public key or sessionKey");
156
+ return;
157
+ }
158
+ if (!publicKey.startsWith("-----BEGIN RSA PUBLIC KEY-----")) {
159
+ Log.e(
160
+ CapacitorUpdater.TAG,
161
+ "The public key is not a valid RSA Public key"
162
+ );
163
+ return;
164
+ }
165
+
166
+ try {
167
+ String ivB64 = ivSessionKey.split(":")[0];
168
+ String sessionKeyB64 = ivSessionKey.split(":")[1];
169
+ byte[] iv = Base64.decode(ivB64.getBytes(), Base64.DEFAULT);
170
+ byte[] sessionKey = Base64.decode(
171
+ sessionKeyB64.getBytes(),
172
+ Base64.DEFAULT
173
+ );
174
+ PublicKey pKey = CryptoCipherV2.stringToPublicKey(publicKey);
175
+ byte[] decryptedSessionKey = CryptoCipherV2.decryptRSA(sessionKey, pKey);
176
+
177
+ SecretKey sKey = CryptoCipherV2.byteToSessionKey(decryptedSessionKey);
178
+ byte[] content = new byte[(int) file.length()];
179
+
180
+ try (
181
+ final FileInputStream fis = new FileInputStream(file);
182
+ final BufferedInputStream bis = new BufferedInputStream(fis);
183
+ final DataInputStream dis = new DataInputStream(bis)
184
+ ) {
185
+ dis.readFully(content);
186
+ dis.close();
187
+ byte[] decrypted = CryptoCipherV2.decryptAES(content, sKey, iv);
188
+ // write the decrypted string to the file
189
+ try (
190
+ final FileOutputStream fos = new FileOutputStream(
191
+ file.getAbsolutePath()
192
+ )
193
+ ) {
194
+ fos.write(decrypted);
195
+ }
196
+ }
197
+ } catch (GeneralSecurityException e) {
198
+ Log.i(CapacitorUpdater.TAG, "decryptFile fail");
199
+ e.printStackTrace();
200
+ throw new IOException("GeneralSecurityException");
201
+ }
202
+ }
203
+
204
+ public static String decryptChecksum(String checksum, String publicKey)
205
+ throws IOException {
206
+ if (publicKey.isEmpty()) {
207
+ Log.e(CapacitorUpdater.TAG, "The public key is empty");
208
+ return checksum;
209
+ }
210
+ try {
211
+ byte[] checksumBytes = Base64.decode(checksum, Base64.DEFAULT);
212
+ PublicKey pKey = CryptoCipherV2.stringToPublicKey(publicKey);
213
+ byte[] decryptedChecksum = CryptoCipherV2.decryptRSA(checksumBytes, pKey);
214
+ // return Base64.encodeToString(decryptedChecksum, Base64.DEFAULT);
215
+ String result = Base64.encodeToString(decryptedChecksum, Base64.DEFAULT);
216
+ return result.replaceAll("\\s", ""); // Remove all whitespace, including newlines
217
+ } catch (GeneralSecurityException e) {
218
+ Log.e(CapacitorUpdater.TAG, "decryptChecksum fail: " + e.getMessage());
219
+ throw new IOException("Decryption failed: " + e.getMessage());
220
+ }
221
+ }
222
+
223
+ public static String decryptChecksum(
224
+ String checksum,
225
+ String publicKey,
226
+ String version
227
+ ) throws IOException {
228
+ if (publicKey.isEmpty()) {
229
+ Log.e(CapacitorUpdater.TAG, "The public key is empty");
230
+ return checksum;
231
+ }
232
+ try {
233
+ byte[] checksumBytes = Base64.decode(checksum, Base64.DEFAULT);
234
+ PublicKey pKey = CryptoCipherV2.stringToPublicKey(publicKey);
235
+ byte[] decryptedChecksum = CryptoCipherV2.decryptRSA(checksumBytes, pKey);
236
+ // return Base64.encodeToString(decryptedChecksum, Base64.DEFAULT);
237
+ String result = Base64.encodeToString(decryptedChecksum, Base64.DEFAULT);
238
+ return result.replaceAll("\\s", ""); // Remove all whitespace, including newlines
239
+ } catch (GeneralSecurityException e) {
240
+ Log.e(CapacitorUpdater.TAG, "decryptChecksum fail: " + e.getMessage());
241
+ throw new IOException("Decryption failed: " + e.getMessage());
242
+ }
243
+ }
244
+
245
+ public static String calcChecksum(File file) {
246
+ final int BUFFER_SIZE = 1024 * 1024 * 5; // 5 MB buffer size
247
+ MessageDigest digest;
248
+ try {
249
+ digest = MessageDigest.getInstance("SHA-256");
250
+ } catch (java.security.NoSuchAlgorithmException e) {
251
+ System.err.println(
252
+ CapacitorUpdater.TAG + " SHA-256 algorithm not available"
253
+ );
254
+ return "";
255
+ }
256
+
257
+ try (FileInputStream fis = new FileInputStream(file)) {
258
+ byte[] buffer = new byte[BUFFER_SIZE];
259
+ int length;
260
+ while ((length = fis.read(buffer)) != -1) {
261
+ digest.update(buffer, 0, length);
262
+ }
263
+ byte[] hash = digest.digest();
264
+ StringBuilder hexString = new StringBuilder();
265
+ for (byte b : hash) {
266
+ String hex = Integer.toHexString(0xff & b);
267
+ if (hex.length() == 1) hexString.append('0');
268
+ hexString.append(hex);
269
+ }
270
+ return hexString.toString();
271
+ } catch (IOException e) {
272
+ System.err.println(
273
+ CapacitorUpdater.TAG +
274
+ " Cannot calc checksum v2: " +
275
+ file.getPath() +
276
+ " " +
277
+ e.getMessage()
278
+ );
279
+ return "";
280
+ }
281
+ }
282
+
137
283
  private static byte[] createDEREncoding(int tag, byte[] value) {
138
284
  if (tag < 0 || tag >= 0xFF) {
139
285
  throw new IllegalArgumentException(
@@ -48,6 +48,7 @@ public class DownloadService extends Worker {
48
48
  public static final String VERSION = "version";
49
49
  public static final String SESSIONKEY = "sessionkey";
50
50
  public static final String CHECKSUM = "checksum";
51
+ public static final String PUBLIC_KEY = "publickey";
51
52
  public static final String IS_MANIFEST = "is_manifest";
52
53
  private static final String UPDATE_FILE = "update.dat";
53
54
 
@@ -100,6 +101,7 @@ public class DownloadService extends Worker {
100
101
  String version = getInputData().getString(VERSION);
101
102
  String sessionKey = getInputData().getString(SESSIONKEY);
102
103
  String checksum = getInputData().getString(CHECKSUM);
104
+ String publicKey = getInputData().getString(PUBLIC_KEY);
103
105
  boolean isManifest = getInputData().getBoolean(IS_MANIFEST, false);
104
106
 
105
107
  Log.d(TAG, "doWork isManifest: " + isManifest);
@@ -113,6 +115,7 @@ public class DownloadService extends Worker {
113
115
  dest,
114
116
  version,
115
117
  sessionKey,
118
+ publicKey,
116
119
  manifest.toString()
117
120
  );
118
121
  return createSuccessResult(dest, version, sessionKey, checksum, true);
@@ -154,6 +157,7 @@ public class DownloadService extends Worker {
154
157
  String dest,
155
158
  String version,
156
159
  String sessionKey,
160
+ String publicKey,
157
161
  String manifestString
158
162
  ) {
159
163
  try {
@@ -231,7 +235,8 @@ public class DownloadService extends Worker {
231
235
  targetFile,
232
236
  cacheFile,
233
237
  fileHash,
234
- id
238
+ sessionKey,
239
+ publicKey
235
240
  );
236
241
  }
237
242
 
@@ -426,7 +431,8 @@ public class DownloadService extends Worker {
426
431
  File targetFile,
427
432
  File cacheFile,
428
433
  String expectedHash,
429
- String id
434
+ String sessionKey,
435
+ String publicKey
430
436
  ) throws Exception {
431
437
  Log.d(TAG, "downloadAndVerify " + downloadUrl);
432
438
 
@@ -461,6 +467,20 @@ public class DownloadService extends Worker {
461
467
  }
462
468
  }
463
469
 
470
+ String decryptedExpectedHash = expectedHash;
471
+
472
+ if (!publicKey.isEmpty() && sessionKey != null && !sessionKey.isEmpty()) {
473
+ Log.d(
474
+ CapacitorUpdater.TAG + " DLSrv",
475
+ "Decrypting file " + targetFile.getName()
476
+ );
477
+ CryptoCipherV2.decryptFile(compressedFile, publicKey, sessionKey);
478
+ decryptedExpectedHash = CryptoCipherV2.decryptChecksum(
479
+ decryptedExpectedHash,
480
+ publicKey
481
+ );
482
+ }
483
+
464
484
  // Decompress the file
465
485
  try (
466
486
  FileInputStream fis = new FileInputStream(compressedFile);
@@ -476,10 +496,10 @@ public class DownloadService extends Worker {
476
496
 
477
497
  // Delete the compressed file
478
498
  compressedFile.delete();
499
+ String calculatedHash = CryptoCipherV2.calcChecksum(targetFile);
479
500
 
480
501
  // Verify checksum
481
- String actualHash = calculateFileHash(targetFile);
482
- if (actualHash.equals(expectedHash)) {
502
+ if (calculatedHash.equals(decryptedExpectedHash)) {
483
503
  // Only cache if checksum is correct
484
504
  copyFile(targetFile, cacheFile);
485
505
  } else {
@@ -47,6 +47,7 @@ public class DownloadWorkerManager {
47
47
  String version,
48
48
  String sessionKey,
49
49
  String checksum,
50
+ String publicKey,
50
51
  boolean isManifest
51
52
  ) {
52
53
  initializeIfNeeded(context.getApplicationContext());
@@ -68,6 +69,7 @@ public class DownloadWorkerManager {
68
69
  .putString(DownloadService.SESSIONKEY, sessionKey)
69
70
  .putString(DownloadService.CHECKSUM, checksum)
70
71
  .putBoolean(DownloadService.IS_MANIFEST, isManifest)
72
+ .putString(DownloadService.PUBLIC_KEY, publicKey)
71
73
  .build();
72
74
 
73
75
  // Create network constraints