@capgo/capacitor-updater 6.14.0 → 6.14.3
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 +11 -11
- package/android/src/main/java/ee/forgr/capacitor_updater/BundleInfo.java +134 -194
- package/android/src/main/java/ee/forgr/capacitor_updater/BundleStatus.java +23 -23
- package/android/src/main/java/ee/forgr/capacitor_updater/Callback.java +1 -1
- package/android/src/main/java/ee/forgr/capacitor_updater/CapacitorUpdater.java +960 -1165
- package/android/src/main/java/ee/forgr/capacitor_updater/CapacitorUpdaterPlugin.java +1259 -1629
- package/android/src/main/java/ee/forgr/capacitor_updater/CryptoCipher.java +161 -197
- package/android/src/main/java/ee/forgr/capacitor_updater/CryptoCipherV2.java +202 -256
- package/android/src/main/java/ee/forgr/capacitor_updater/DataManager.java +16 -16
- package/android/src/main/java/ee/forgr/capacitor_updater/DelayCondition.java +44 -48
- package/android/src/main/java/ee/forgr/capacitor_updater/DelayUntilNext.java +4 -4
- package/android/src/main/java/ee/forgr/capacitor_updater/DownloadService.java +378 -467
- package/android/src/main/java/ee/forgr/capacitor_updater/DownloadWorkerManager.java +71 -83
- package/android/src/main/java/ee/forgr/capacitor_updater/InternalUtils.java +19 -28
- package/dist/docs.json +17 -17
- package/dist/esm/definitions.d.ts +13 -13
- package/dist/esm/definitions.js.map +1 -1
- package/dist/esm/index.d.ts +2 -2
- package/dist/esm/index.js +4 -4
- package/dist/esm/index.js.map +1 -1
- package/dist/esm/web.d.ts +2 -2
- package/dist/esm/web.js +43 -43
- package/dist/esm/web.js.map +1 -1
- package/dist/plugin.cjs.js +43 -43
- package/dist/plugin.cjs.js.map +1 -1
- package/dist/plugin.js +43 -43
- package/dist/plugin.js.map +1 -1
- package/ios/Plugin/CapacitorUpdater.swift +8 -8
- package/ios/Plugin/CapacitorUpdaterPlugin.swift +1 -1
- package/package.json +5 -7
|
@@ -43,208 +43,172 @@ import javax.crypto.spec.SecretKeySpec;
|
|
|
43
43
|
|
|
44
44
|
public class CryptoCipher {
|
|
45
45
|
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
}
|
|
58
|
-
|
|
59
|
-
public static byte[] decryptAES(byte[] cipherText, SecretKey key, byte[] iv) {
|
|
60
|
-
try {
|
|
61
|
-
IvParameterSpec ivParameterSpec = new IvParameterSpec(iv);
|
|
62
|
-
Cipher cipher = Cipher.getInstance("AES/CBC/PKCS5Padding");
|
|
63
|
-
SecretKeySpec keySpec = new SecretKeySpec(key.getEncoded(), "AES");
|
|
64
|
-
cipher.init(Cipher.DECRYPT_MODE, keySpec, ivParameterSpec);
|
|
65
|
-
return cipher.doFinal(cipherText);
|
|
66
|
-
} catch (Exception e) {
|
|
67
|
-
e.printStackTrace();
|
|
46
|
+
public static byte[] decryptRSA(byte[] source, PrivateKey privateKey)
|
|
47
|
+
throws NoSuchPaddingException, NoSuchAlgorithmException, InvalidAlgorithmParameterException, InvalidKeyException, IllegalBlockSizeException, BadPaddingException {
|
|
48
|
+
Cipher cipher = Cipher.getInstance("RSA/ECB/OAEPPadding");
|
|
49
|
+
OAEPParameterSpec oaepParams = new OAEPParameterSpec(
|
|
50
|
+
"SHA-256",
|
|
51
|
+
"MGF1",
|
|
52
|
+
new MGF1ParameterSpec("SHA-256"),
|
|
53
|
+
PSource.PSpecified.DEFAULT
|
|
54
|
+
);
|
|
55
|
+
cipher.init(Cipher.DECRYPT_MODE, privateKey, oaepParams);
|
|
56
|
+
return cipher.doFinal(source);
|
|
68
57
|
}
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
58
|
+
|
|
59
|
+
public static byte[] decryptAES(byte[] cipherText, SecretKey key, byte[] iv) {
|
|
60
|
+
try {
|
|
61
|
+
IvParameterSpec ivParameterSpec = new IvParameterSpec(iv);
|
|
62
|
+
Cipher cipher = Cipher.getInstance("AES/CBC/PKCS5Padding");
|
|
63
|
+
SecretKeySpec keySpec = new SecretKeySpec(key.getEncoded(), "AES");
|
|
64
|
+
cipher.init(Cipher.DECRYPT_MODE, keySpec, ivParameterSpec);
|
|
65
|
+
return cipher.doFinal(cipherText);
|
|
66
|
+
} catch (Exception e) {
|
|
67
|
+
e.printStackTrace();
|
|
68
|
+
}
|
|
69
|
+
return null;
|
|
70
|
+
}
|
|
71
|
+
|
|
72
|
+
public static SecretKey byteToSessionKey(byte[] sessionKey) {
|
|
73
|
+
// rebuild key using SecretKeySpec
|
|
74
|
+
return new SecretKeySpec(sessionKey, 0, sessionKey.length, "AES");
|
|
75
|
+
}
|
|
76
|
+
|
|
77
|
+
private static PrivateKey readPkcs8PrivateKey(byte[] pkcs8Bytes) throws GeneralSecurityException {
|
|
78
|
+
KeyFactory keyFactory = KeyFactory.getInstance("RSA");
|
|
79
|
+
PKCS8EncodedKeySpec keySpec = new PKCS8EncodedKeySpec(pkcs8Bytes);
|
|
80
|
+
try {
|
|
81
|
+
return keyFactory.generatePrivate(keySpec);
|
|
82
|
+
} catch (InvalidKeySpecException e) {
|
|
83
|
+
throw new IllegalArgumentException("Unexpected key format!", e);
|
|
84
|
+
}
|
|
85
|
+
}
|
|
86
|
+
|
|
87
|
+
private static byte[] join(byte[] byteArray1, byte[] byteArray2) {
|
|
88
|
+
byte[] bytes = new byte[byteArray1.length + byteArray2.length];
|
|
89
|
+
System.arraycopy(byteArray1, 0, bytes, 0, byteArray1.length);
|
|
90
|
+
System.arraycopy(byteArray2, 0, bytes, byteArray1.length, byteArray2.length);
|
|
91
|
+
return bytes;
|
|
92
|
+
}
|
|
93
|
+
|
|
94
|
+
private static PrivateKey readPkcs1PrivateKey(byte[] pkcs1Bytes) throws GeneralSecurityException {
|
|
95
|
+
// We can't use Java internal APIs to parse ASN.1 structures, so we build a PKCS#8 key Java can understand
|
|
96
|
+
int pkcs1Length = pkcs1Bytes.length;
|
|
97
|
+
int totalLength = pkcs1Length + 22;
|
|
98
|
+
byte[] pkcs8Header = new byte[] {
|
|
99
|
+
0x30,
|
|
100
|
+
(byte) 0x82,
|
|
101
|
+
(byte) ((totalLength >> 8) & 0xff),
|
|
102
|
+
(byte) (totalLength & 0xff), // Sequence + total length
|
|
103
|
+
0x2,
|
|
104
|
+
0x1,
|
|
105
|
+
0x0, // Integer (0)
|
|
106
|
+
0x30,
|
|
107
|
+
0xD,
|
|
108
|
+
0x6,
|
|
109
|
+
0x9,
|
|
110
|
+
0x2A,
|
|
111
|
+
(byte) 0x86,
|
|
112
|
+
0x48,
|
|
113
|
+
(byte) 0x86,
|
|
114
|
+
(byte) 0xF7,
|
|
115
|
+
0xD,
|
|
116
|
+
0x1,
|
|
117
|
+
0x1,
|
|
118
|
+
0x1,
|
|
119
|
+
0x5,
|
|
120
|
+
0x0, // Sequence: 1.2.840.113549.1.1.1, NULL
|
|
121
|
+
0x4,
|
|
122
|
+
(byte) 0x82,
|
|
123
|
+
(byte) ((pkcs1Length >> 8) & 0xff),
|
|
124
|
+
(byte) (pkcs1Length & 0xff) // Octet string + length
|
|
125
|
+
};
|
|
126
|
+
byte[] pkcs8bytes = join(pkcs8Header, pkcs1Bytes);
|
|
127
|
+
return readPkcs8PrivateKey(pkcs8bytes);
|
|
85
128
|
}
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
}
|
|
100
|
-
|
|
101
|
-
private static PrivateKey readPkcs1PrivateKey(byte[] pkcs1Bytes)
|
|
102
|
-
throws GeneralSecurityException {
|
|
103
|
-
// We can't use Java internal APIs to parse ASN.1 structures, so we build a PKCS#8 key Java can understand
|
|
104
|
-
int pkcs1Length = pkcs1Bytes.length;
|
|
105
|
-
int totalLength = pkcs1Length + 22;
|
|
106
|
-
byte[] pkcs8Header = new byte[] {
|
|
107
|
-
0x30,
|
|
108
|
-
(byte) 0x82,
|
|
109
|
-
(byte) ((totalLength >> 8) & 0xff),
|
|
110
|
-
(byte) (totalLength & 0xff), // Sequence + total length
|
|
111
|
-
0x2,
|
|
112
|
-
0x1,
|
|
113
|
-
0x0, // Integer (0)
|
|
114
|
-
0x30,
|
|
115
|
-
0xD,
|
|
116
|
-
0x6,
|
|
117
|
-
0x9,
|
|
118
|
-
0x2A,
|
|
119
|
-
(byte) 0x86,
|
|
120
|
-
0x48,
|
|
121
|
-
(byte) 0x86,
|
|
122
|
-
(byte) 0xF7,
|
|
123
|
-
0xD,
|
|
124
|
-
0x1,
|
|
125
|
-
0x1,
|
|
126
|
-
0x1,
|
|
127
|
-
0x5,
|
|
128
|
-
0x0, // Sequence: 1.2.840.113549.1.1.1, NULL
|
|
129
|
-
0x4,
|
|
130
|
-
(byte) 0x82,
|
|
131
|
-
(byte) ((pkcs1Length >> 8) & 0xff),
|
|
132
|
-
(byte) (pkcs1Length & 0xff), // Octet string + length
|
|
133
|
-
};
|
|
134
|
-
byte[] pkcs8bytes = join(pkcs8Header, pkcs1Bytes);
|
|
135
|
-
return readPkcs8PrivateKey(pkcs8bytes);
|
|
136
|
-
}
|
|
137
|
-
|
|
138
|
-
public static PrivateKey stringToPrivateKey(String private_key)
|
|
139
|
-
throws GeneralSecurityException {
|
|
140
|
-
// Base64 decode the result
|
|
141
|
-
|
|
142
|
-
String pkcs1Pem = private_key;
|
|
143
|
-
pkcs1Pem = pkcs1Pem.replace("-----BEGIN RSA PRIVATE KEY-----", "");
|
|
144
|
-
pkcs1Pem = pkcs1Pem.replace("-----END RSA PRIVATE KEY-----", "");
|
|
145
|
-
pkcs1Pem = pkcs1Pem.replace("\\n", "");
|
|
146
|
-
pkcs1Pem = pkcs1Pem.replace(" ", "");
|
|
147
|
-
|
|
148
|
-
byte[] pkcs1EncodedBytes = Base64.decode(
|
|
149
|
-
pkcs1Pem.getBytes(),
|
|
150
|
-
Base64.DEFAULT
|
|
151
|
-
);
|
|
152
|
-
// extract the private key
|
|
153
|
-
return readPkcs1PrivateKey(pkcs1EncodedBytes);
|
|
154
|
-
}
|
|
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;
|
|
129
|
+
|
|
130
|
+
public static PrivateKey stringToPrivateKey(String private_key) throws GeneralSecurityException {
|
|
131
|
+
// Base64 decode the result
|
|
132
|
+
|
|
133
|
+
String pkcs1Pem = private_key;
|
|
134
|
+
pkcs1Pem = pkcs1Pem.replace("-----BEGIN RSA PRIVATE KEY-----", "");
|
|
135
|
+
pkcs1Pem = pkcs1Pem.replace("-----END RSA PRIVATE KEY-----", "");
|
|
136
|
+
pkcs1Pem = pkcs1Pem.replace("\\n", "");
|
|
137
|
+
pkcs1Pem = pkcs1Pem.replace(" ", "");
|
|
138
|
+
|
|
139
|
+
byte[] pkcs1EncodedBytes = Base64.decode(pkcs1Pem.getBytes(), Base64.DEFAULT);
|
|
140
|
+
// extract the private key
|
|
141
|
+
return readPkcs1PrivateKey(pkcs1EncodedBytes);
|
|
173
142
|
}
|
|
174
|
-
|
|
175
|
-
|
|
176
|
-
|
|
177
|
-
|
|
178
|
-
|
|
179
|
-
|
|
180
|
-
|
|
181
|
-
|
|
182
|
-
|
|
183
|
-
|
|
184
|
-
|
|
185
|
-
|
|
186
|
-
|
|
187
|
-
|
|
188
|
-
|
|
189
|
-
|
|
190
|
-
|
|
191
|
-
|
|
192
|
-
|
|
193
|
-
|
|
194
|
-
|
|
195
|
-
|
|
196
|
-
|
|
197
|
-
|
|
198
|
-
|
|
199
|
-
|
|
200
|
-
|
|
201
|
-
|
|
143
|
+
|
|
144
|
+
public static void decryptFile(final File file, final String privateKey, final String ivSessionKey, final String version)
|
|
145
|
+
throws IOException {
|
|
146
|
+
// (str != null && !str.isEmpty())
|
|
147
|
+
if (privateKey == null || privateKey.isEmpty()) {
|
|
148
|
+
Log.i(CapacitorUpdater.TAG, "Cannot found privateKey");
|
|
149
|
+
return;
|
|
150
|
+
} else if (ivSessionKey == null || ivSessionKey.isEmpty() || ivSessionKey.split(":").length != 2) {
|
|
151
|
+
Log.i(CapacitorUpdater.TAG, "Cannot found sessionKey");
|
|
152
|
+
return;
|
|
153
|
+
}
|
|
154
|
+
try {
|
|
155
|
+
String ivB64 = ivSessionKey.split(":")[0];
|
|
156
|
+
String sessionKeyB64 = ivSessionKey.split(":")[1];
|
|
157
|
+
byte[] iv = Base64.decode(ivB64.getBytes(), Base64.DEFAULT);
|
|
158
|
+
byte[] sessionKey = Base64.decode(sessionKeyB64.getBytes(), Base64.DEFAULT);
|
|
159
|
+
PrivateKey pKey = CryptoCipher.stringToPrivateKey(privateKey);
|
|
160
|
+
byte[] decryptedSessionKey = CryptoCipher.decryptRSA(sessionKey, pKey);
|
|
161
|
+
SecretKey sKey = CryptoCipher.byteToSessionKey(decryptedSessionKey);
|
|
162
|
+
byte[] content = new byte[(int) file.length()];
|
|
163
|
+
|
|
164
|
+
try (
|
|
165
|
+
final FileInputStream fis = new FileInputStream(file);
|
|
166
|
+
final BufferedInputStream bis = new BufferedInputStream(fis);
|
|
167
|
+
final DataInputStream dis = new DataInputStream(bis)
|
|
168
|
+
) {
|
|
169
|
+
dis.readFully(content);
|
|
170
|
+
dis.close();
|
|
171
|
+
byte[] decrypted = CryptoCipher.decryptAES(content, sKey, iv);
|
|
172
|
+
// write the decrypted string to the file
|
|
173
|
+
try (final FileOutputStream fos = new FileOutputStream(file.getAbsolutePath())) {
|
|
174
|
+
fos.write(decrypted);
|
|
175
|
+
}
|
|
176
|
+
}
|
|
177
|
+
} catch (GeneralSecurityException e) {
|
|
178
|
+
Log.i(CapacitorUpdater.TAG, "decryptFile fail");
|
|
179
|
+
e.printStackTrace();
|
|
180
|
+
throw new IOException("GeneralSecurityException");
|
|
202
181
|
}
|
|
203
|
-
}
|
|
204
|
-
} catch (GeneralSecurityException e) {
|
|
205
|
-
Log.i(CapacitorUpdater.TAG, "decryptFile fail");
|
|
206
|
-
e.printStackTrace();
|
|
207
|
-
throw new IOException("GeneralSecurityException");
|
|
208
182
|
}
|
|
209
|
-
|
|
210
|
-
|
|
211
|
-
|
|
212
|
-
|
|
213
|
-
|
|
214
|
-
|
|
215
|
-
|
|
216
|
-
|
|
217
|
-
|
|
218
|
-
|
|
219
|
-
|
|
220
|
-
|
|
221
|
-
|
|
222
|
-
|
|
223
|
-
|
|
224
|
-
|
|
225
|
-
" Cannot calc checksum: " +
|
|
226
|
-
file.getPath() +
|
|
227
|
-
" " +
|
|
228
|
-
e.getMessage()
|
|
229
|
-
);
|
|
230
|
-
return "";
|
|
183
|
+
|
|
184
|
+
public static String calcChecksum(File file) {
|
|
185
|
+
final int BUFFER_SIZE = 1024 * 1024 * 5; // 5 MB buffer size
|
|
186
|
+
CRC32 crc = new CRC32();
|
|
187
|
+
|
|
188
|
+
try (FileInputStream fis = new FileInputStream(file)) {
|
|
189
|
+
byte[] buffer = new byte[BUFFER_SIZE];
|
|
190
|
+
int length;
|
|
191
|
+
while ((length = fis.read(buffer)) != -1) {
|
|
192
|
+
crc.update(buffer, 0, length);
|
|
193
|
+
}
|
|
194
|
+
return String.format("%08x", crc.getValue());
|
|
195
|
+
} catch (IOException e) {
|
|
196
|
+
System.err.println(CapacitorUpdater.TAG + " Cannot calc checksum: " + file.getPath() + " " + e.getMessage());
|
|
197
|
+
return "";
|
|
198
|
+
}
|
|
231
199
|
}
|
|
232
|
-
|
|
233
|
-
|
|
234
|
-
|
|
235
|
-
|
|
236
|
-
|
|
237
|
-
|
|
238
|
-
|
|
239
|
-
|
|
240
|
-
|
|
241
|
-
|
|
242
|
-
|
|
243
|
-
|
|
244
|
-
|
|
245
|
-
"stringToPublicKey fail\nError:\n" + e.toString()
|
|
246
|
-
);
|
|
247
|
-
return null;
|
|
200
|
+
|
|
201
|
+
public static PublicKey stringToPublicKey(String publicKey) {
|
|
202
|
+
byte[] encoded = Base64.decode(publicKey, Base64.DEFAULT);
|
|
203
|
+
|
|
204
|
+
KeyFactory keyFactory = null;
|
|
205
|
+
try {
|
|
206
|
+
keyFactory = KeyFactory.getInstance("RSA");
|
|
207
|
+
X509EncodedKeySpec keySpec = new X509EncodedKeySpec(encoded);
|
|
208
|
+
return keyFactory.generatePublic(keySpec);
|
|
209
|
+
} catch (NoSuchAlgorithmException | InvalidKeySpecException e) {
|
|
210
|
+
Log.i("Capacitor-updater", "stringToPublicKey fail\nError:\n" + e.toString());
|
|
211
|
+
return null;
|
|
212
|
+
}
|
|
248
213
|
}
|
|
249
|
-
}
|
|
250
214
|
}
|