Skip to content

Commit

Permalink
Merge branch 'jawa-the-hutt/main' into development
Browse files Browse the repository at this point in the history
  • Loading branch information
riderx committed Mar 22, 2024
2 parents c953b11 + 24df89e commit cc2cda6
Show file tree
Hide file tree
Showing 9 changed files with 309 additions and 218 deletions.
11 changes: 7 additions & 4 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -165,7 +165,7 @@ CapacitorUpdater can be configured with these options:
| **`resetWhenUpdate`** | <code>boolean</code> | Automatically delete previous downloaded bundles when a newer native app bundle is installed to the device. Only available for Android and iOS. | <code>true</code> | |
| **`updateUrl`** | <code>string</code> | Configure the URL / endpoint to which update checks are sent. Only available for Android and iOS. | <code>https://api.capgo.app/auto_update</code> | |
| **`statsUrl`** | <code>string</code> | Configure the URL / endpoint to which update statistics are sent. Only available for Android and iOS. Set to "" to disable stats reporting. | <code>https://api.capgo.app/stats</code> | |
| **`privateKey`** | <code>string</code> | Configure the private key for end to end live update encryption. Only available for Android and iOS. | <code>undefined</code> | |
| **`publicKey`** | <code>string</code> | Configure the public key for end to end live update encryption. Only available for Android and iOS. | <code>undefined</code> | |
| **`version`** | <code>string</code> | Configure the current version of the app. This will be used for the first update request. If not set, the plugin will get the version from the native code. Only available for Android and iOS. | <code>undefined</code> | 4.17.48 |
| **`directUpdate`** | <code>boolean</code> | Make the plugin direct install the update when the app what just updated/installed. Only for autoUpdate mode. Only available for Android and iOS. | <code>undefined</code> | 5.1.0 |
| **`periodCheckDelay`** | <code>number</code> | Configure the delay period for period update check. the unit is in seconds. Only available for Android and iOS. Cannot be less than 600 seconds (10 minutes). | <code>600 // (10 minutes)</code> | |
Expand All @@ -176,6 +176,7 @@ CapacitorUpdater can be configured with these options:
| **`localSupaAnon`** | <code>string</code> | Configure the CLI to use a local server for testing. | <code>undefined</code> | 4.17.48 |
| **`allowModifyUrl`** | <code>boolean</code> | Allow the plugin to modify the updateUrl, statsUrl and channelUrl dynamically from the JavaScript side. | <code>false</code> | 5.4.0 |
| **`defaultChannel`** | <code>string</code> | Set the default channel for the app in the config. | <code>undefined</code> | 5.5.0 |
| **`forceEncryption`** | <code>boolean</code> | If set to true with encryption enabled, the plugin will only accept encrypted bundles. | <code>true</code> | 6.0.0 |

### Examples

Expand All @@ -193,7 +194,7 @@ In `capacitor.config.json`:
"resetWhenUpdate": false,
"updateUrl": https://example.com/api/auto_update,
"statsUrl": https://example.com/api/stats,
"privateKey": undefined,
"publicKey": undefined,
"version": undefined,
"directUpdate": undefined,
"periodCheckDelay": undefined,
Expand All @@ -203,7 +204,8 @@ In `capacitor.config.json`:
"localSupa": undefined,
"localSupaAnon": undefined,
"allowModifyUrl": undefined,
"defaultChannel": undefined
"defaultChannel": undefined,
"forceEncryption": undefined
}
}
}
Expand All @@ -227,7 +229,7 @@ const config: CapacitorConfig = {
resetWhenUpdate: false,
updateUrl: https://example.com/api/auto_update,
statsUrl: https://example.com/api/stats,
privateKey: undefined,
publicKey: undefined,
version: undefined,
directUpdate: undefined,
periodCheckDelay: undefined,
Expand All @@ -238,6 +240,7 @@ const config: CapacitorConfig = {
localSupaAnon: undefined,
allowModifyUrl: undefined,
defaultChannel: undefined,
forceEncryption: undefined,
},
},
};
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -42,6 +42,7 @@
import java.net.URLConnection;
import java.security.GeneralSecurityException;
import java.security.PrivateKey;
import java.security.PublicKey;
import java.security.SecureRandom;
import java.util.ArrayList;
import java.util.Date;
Expand Down Expand Up @@ -86,9 +87,11 @@ public class CapacitorUpdater {
public String channelUrl = "";
public String defaultChannel = "";
public String appId = "";
public String privateKey = "";
public String publicKey = "";
public Boolean hasOldPrivateKeyPropertyInConfig = false;
public String deviceID = "";
public int timeout = 20000;
public Boolean forceEncryption = false;

private final FilenameFilter filter = (f, name) -> {
// ignore directories generated by mac os x
Expand Down Expand Up @@ -338,6 +341,13 @@ public Boolean finishDownload(
) {
try {
final File downloaded = new File(this.documentsDir, dest);
if (this.hasOldPrivateKeyPropertyInConfig) {
Log.i(
CapacitorUpdater.TAG,
"There is still an privateKey property in the config"
);
}

this.decryptFile(downloaded, sessionKey, version);
final String checksum;
checksum = this.getChecksum(downloaded);
Expand Down Expand Up @@ -503,17 +513,32 @@ private void decryptFile(
final String ivSessionKey,
final String version
) throws IOException {
// (str != null && !str.isEmpty())
if (
this.privateKey == null ||
this.privateKey.isEmpty() ||
ivSessionKey == null ||
ivSessionKey.isEmpty() ||
ivSessionKey.split(":").length != 2
) {
Log.i(TAG, "Cannot found privateKey or sessionKey");
if (
this.forceEncryption &&
this.publicKey != null &&
!this.publicKey.isEmpty()
) {
Log.i(TAG, "Cannot accept non-encrypted bundle");
this.sendStats("decrypt_fail", version);
throw new IOException("GeneralSecurityException");
}
Log.i(TAG, "Cannot find public key or sessionKey");
return;
}

if (!this.publicKey.startsWith("-----BEGIN RSA PUBLIC KEY-----")) {
Log.e(
CapacitorUpdater.TAG,
"The public key is not a valid RSA Public key"
);
return;
}

try {
String ivB64 = ivSessionKey.split(":")[0];
String sessionKeyB64 = ivSessionKey.split(":")[1];
Expand All @@ -522,8 +547,10 @@ private void decryptFile(
sessionKeyB64.getBytes(),
Base64.DEFAULT
);
PrivateKey pKey = CryptoCipher.stringToPrivateKey(this.privateKey);

PublicKey pKey = CryptoCipher.stringToPublicKey(this.publicKey);
byte[] decryptedSessionKey = CryptoCipher.decryptRSA(sessionKey, pKey);

SecretKey sKey = CryptoCipher.byteToSessionKey(decryptedSessionKey);
byte[] content = new byte[(int) file.length()];

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -50,8 +50,8 @@ public class CapacitorUpdaterPlugin extends Plugin {
private static final String updateUrlDefault =
"https://api.capgo.app/updates";
private static final String statsUrlDefault = "https://api.capgo.app/stats";
private static final String defaultPrivateKey =
"-----BEGIN RSA PRIVATE KEY-----\nMIIEpQIBAAKCAQEA4pW9olT0FBXXivRCzd3xcImlWZrqkwcF2xTkX/FwXmj9eh9H\nkBLrsQmfsC+PJisRXIOGq6a0z3bsGq6jBpp3/Jr9jiaW5VuPGaKeMaZZBRvi/N5f\nIMG3hZXSOcy0IYg+E1Q7RkYO1xq5GLHseqG+PXvJsNe4R8R/Bmd/ngq0xh/cvcrH\nHpXwO0Aj9tfprlb+rHaVV79EkVRWYPidOLnK1n0EFHFJ1d/MyDIp10TEGm2xHpf/\nBrlb1an8wXEuzoC0DgYaczgTjovwR+ewSGhSHJliQdM0Qa3o1iN87DldWtydImMs\nPjJ3DUwpsjAMRe5X8Et4+udFW2ciYnQo9H0CkwIDAQABAoIBAQCtjlMV/4qBxAU4\nu0ZcWA9yywwraX0aJ3v1xrfzQYV322Wk4Ea5dbSxA5UcqCE29DA1M824t1Wxv/6z\npWbcTP9xLuresnJMtmgTE7umfiubvTONy2sENT20hgDkIwcq1CfwOEm61zjQzPhQ\nkSB5AmEsyR/BZEsUNc+ygR6AWOUFB7tj4yMc32LOTWSbE/znnF2BkmlmnQykomG1\n2oVqM3lUFP7+m8ux1O7scO6IMts+Z/eFXjWfxpbebUSvSIR83GXPQZ34S/c0ehOg\nyHdmCSOel1r3VvInMe+30j54Jr+Ml/7Ee6axiwyE2e/bd85MsK9sVdp0OtelXaqA\nOZZqWvN5AoGBAP2Hn3lSq+a8GsDH726mHJw60xM0LPbVJTYbXsmQkg1tl3NKJTMM\nQqz41+5uys+phEgLHI9gVJ0r+HaGHXnJ4zewlFjsudstb/0nfctUvTqnhEhfNo9I\ny4kufVKPRF3sMEeo7CDVJs4GNBLycEyIBy6Mbv0VcO7VaZqggRwu4no9AoGBAOTK\n6NWYs1BWlkua2wmxexGOzehNGedInp0wGr2l4FDayWjkZLqvB+nNXUQ63NdHlSs4\nWB2Z1kQXZxVaI2tPYexGUKXEo2uFob63uflbuE029ovDXIIPFTPtGNdNXwhHT5a+\nPhmy3sMc+s2BSNM5qaNmfxQxhdd6gRU6oikE+c0PAoGAMn3cKNFqIt27hkFLUgIL\nGKIuf1iYy9/PNWNmEUaVj88PpopRtkTu0nwMpROzmH/uNFriKTvKHjMvnItBO4wV\nkHW+VadvrFL0Rrqituf9d7z8/1zXBNo+juePVe3qc7oiM2NVA4Tv4YAixtM5wkQl\nCgQ15nlqsGYYTg9BJ1e/CxECgYEAjEYPzO2reuUrjr0p8F59ev1YJ0YmTJRMk0ks\nC/yIdGo/tGzbiU3JB0LfHPcN8Xu07GPGOpfYM7U5gXDbaG6qNgfCaHAQVdr/mQPi\nJQ1kCQtay8QCkscWk9iZM1//lP7LwDtxraXqSCwbZSYP9VlUNZeg8EuQqNU2EUL6\nqzWexmcCgYEA0prUGNBacraTYEknB1CsbP36UPWsqFWOvevlz+uEC5JPxPuW5ZHh\nSQN7xl6+PHyjPBM7ttwPKyhgLOVTb3K7ex/PXnudojMUK5fh7vYfChVTSlx2p6r0\nDi58PdD+node08cJH+ie0Yphp7m+D4+R9XD0v0nEvnu4BtAW6DrJasw=\n-----END RSA PRIVATE KEY-----\n";
private static final String defaultPublicKey =
"-----BEGIN RSA PUBLIC KEY-----\nMIIBCgKCAQEA4pW9olT0FBXXivRCzd3xcImlWZrqkwcF2xTkX/FwXmj9eh9HkBLr\nsQmfsC+PJisRXIOGq6a0z3bsGq6jBpp3/Jr9jiaW5VuPGaKeMaZZBRvi/N5fIMG3\nhZXSOcy0IYg+E1Q7RkYO1xq5GLHseqG+PXvJsNe4R8R/Bmd/ngq0xh/cvcrHHpXw\nO0Aj9tfprlb+rHaVV79EkVRWYPidOLnK1n0EFHFJ1d/MyDIp10TEGm2xHpf/Brlb\n1an8wXEuzoC0DgYaczgTjovwR+ewSGhSHJliQdM0Qa3o1iN87DldWtydImMsPjJ3\nDUwpsjAMRe5X8Et4+udFW2ciYnQo9H0CkwIDAQAB\n-----END RSA PUBLIC KEY-----\n";
private static final String channelUrlDefault =
"https://api.capgo.app/channel_self";

Expand Down Expand Up @@ -136,6 +136,8 @@ public void notifyListeners(final String id, final JSObject res) {
this.implementation.activity = this.getActivity();
this.implementation.versionBuild =
this.getConfig().getString("version", pInfo.versionName);
this.implementation.forceEncryption =
this.getConfig().getBoolean("forceEncryption", true);
this.implementation.PLUGIN_VERSION = this.PLUGIN_VERSION;
this.implementation.versionCode = Integer.toString(pInfo.versionCode);
this.implementation.requestQueue =
Expand Down Expand Up @@ -174,8 +176,15 @@ public void notifyListeners(final String id, final JSObject res) {
);
}
Log.i(CapacitorUpdater.TAG, "appId: " + implementation.appId);
this.implementation.privateKey =
this.getConfig().getString("privateKey", defaultPrivateKey);
this.implementation.publicKey =
getConfig().getString("publicKey", defaultPublicKey);
this.implementation.hasOldPrivateKeyPropertyInConfig = false;
if (
this.getConfig().getString("privateKey") != null &&
!this.getConfig().getString("privateKey").isEmpty()
) {
this.implementation.hasOldPrivateKeyPropertyInConfig = true;
}
this.implementation.statsUrl =
this.getConfig().getString("statsUrl", statsUrlDefault);
this.implementation.channelUrl =
Expand Down
Loading

0 comments on commit cc2cda6

Please sign in to comment.