summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--app/src/insecure/java/se/leap/bitmaskclient/ProviderApiManager.java45
-rw-r--r--app/src/main/java/se/leap/bitmaskclient/ConfigHelper.java9
-rw-r--r--app/src/main/java/se/leap/bitmaskclient/Constants.java2
-rw-r--r--app/src/main/java/se/leap/bitmaskclient/Dashboard.java0
-rw-r--r--app/src/main/java/se/leap/bitmaskclient/EipFragment.java200
-rw-r--r--app/src/main/java/se/leap/bitmaskclient/MainActivity.java307
-rw-r--r--app/src/main/java/se/leap/bitmaskclient/MainActivityErrorDialog.java148
-rw-r--r--app/src/main/java/se/leap/bitmaskclient/OkHttpClientGenerator.java5
-rw-r--r--app/src/main/java/se/leap/bitmaskclient/Provider.java16
-rw-r--r--app/src/main/java/se/leap/bitmaskclient/ProviderAPI.java13
-rw-r--r--app/src/main/java/se/leap/bitmaskclient/ProviderApiManagerBase.java47
-rw-r--r--app/src/main/java/se/leap/bitmaskclient/ProviderCredentialsBaseActivity.java19
-rw-r--r--app/src/main/java/se/leap/bitmaskclient/ProviderListBaseActivity.java26
-rw-r--r--app/src/main/java/se/leap/bitmaskclient/ProviderSetupFailedDialog.java (renamed from app/src/main/java/se/leap/bitmaskclient/DownloadFailedDialog.java)12
-rw-r--r--app/src/main/java/se/leap/bitmaskclient/eip/EIP.java134
-rw-r--r--app/src/main/java/se/leap/bitmaskclient/eip/EipCommand.java9
-rw-r--r--app/src/main/java/se/leap/bitmaskclient/eip/VpnCertificateValidator.java8
-rw-r--r--app/src/main/res/values/strings.xml6
-rw-r--r--app/src/production/java/se/leap/bitmaskclient/ProviderApiManager.java33
-rw-r--r--app/src/test/java/se/leap/bitmaskclient/eip/ProviderApiManagerTest.java8
20 files changed, 675 insertions, 372 deletions
diff --git a/app/src/insecure/java/se/leap/bitmaskclient/ProviderApiManager.java b/app/src/insecure/java/se/leap/bitmaskclient/ProviderApiManager.java
index 1c5247c0..42bd576a 100644
--- a/app/src/insecure/java/se/leap/bitmaskclient/ProviderApiManager.java
+++ b/app/src/insecure/java/se/leap/bitmaskclient/ProviderApiManager.java
@@ -51,10 +51,12 @@ import static android.text.TextUtils.isEmpty;
import static se.leap.bitmaskclient.Constants.BROADCAST_RESULT_KEY;
import static se.leap.bitmaskclient.Constants.PROVIDER_KEY;
import static se.leap.bitmaskclient.Constants.PROVIDER_VPN_CERTIFICATE;
-import static se.leap.bitmaskclient.DownloadFailedDialog.DOWNLOAD_ERRORS.ERROR_CERTIFICATE_PINNING;
-import static se.leap.bitmaskclient.DownloadFailedDialog.DOWNLOAD_ERRORS.ERROR_CORRUPTED_PROVIDER_JSON;
+import static se.leap.bitmaskclient.ProviderSetupFailedDialog.DOWNLOAD_ERRORS.ERROR_CERTIFICATE_PINNING;
+import static se.leap.bitmaskclient.ProviderSetupFailedDialog.DOWNLOAD_ERRORS.ERROR_CORRUPTED_PROVIDER_JSON;
import static se.leap.bitmaskclient.ProviderAPI.ERRORS;
import static se.leap.bitmaskclient.R.string.certificate_error;
+import static se.leap.bitmaskclient.R.string.downloading_vpn_certificate_failed;
+import static se.leap.bitmaskclient.R.string.error_io_exception_user_message;
import static se.leap.bitmaskclient.R.string.malformed_url;
import static se.leap.bitmaskclient.R.string.warning_corrupted_provider_cert;
import static se.leap.bitmaskclient.R.string.warning_corrupted_provider_details;
@@ -201,28 +203,33 @@ public class ProviderApiManager extends ProviderApiManagerBase {
* @return true if certificate was downloaded correctly, false if provider.json is not present in SharedPreferences, or if the certificate url could not be parsed as a URI, or if there was an SSL error.
*/
@Override
- protected boolean updateVpnCertificate(Provider provider) {
+ protected Bundle updateVpnCertificate(Provider provider) {
+ Bundle result = new Bundle();
try {
- JSONObject providerDefinition = provider.getDefinition();
-
- String providerMainUrl = providerDefinition.getString(Provider.API_URL);
- URL newCertStringUrl = new URL(providerMainUrl + "/" + providerDefinition.getString(Provider.API_VERSION) + "/" + PROVIDER_VPN_CERTIFICATE);
+ JSONObject providerJson = provider.getDefinition();
+ String providerMainUrl = providerJson.getString(Provider.API_URL);
+ URL newCertStringUrl = new URL(providerMainUrl + "/" + providerJson.getString(Provider.API_VERSION) + "/" + PROVIDER_VPN_CERTIFICATE);
String certString = downloadWithProviderCA(provider.getCaCert(), newCertStringUrl.toString(), lastDangerOn);
-
- if (certString == null || certString.isEmpty() || ConfigHelper.checkErroneousDownload(certString))
- return false;
- else
- return loadCertificate(provider, certString);
- } catch (IOException e) {
- // TODO Auto-generated catch block
- e.printStackTrace();
- return false;
- } catch (JSONException e) {
- // TODO Auto-generated catch block
+ if (ConfigHelper.checkErroneousDownload(certString)) {
+ if (certString == null || certString.isEmpty()) {
+ // probably 204
+ setErrorResult(result, error_io_exception_user_message, null);
+ } else {
+ String reasonToFail = pickErrorMessage(certString);
+ result.putString(ERRORS, reasonToFail);
+ result.putBoolean(BROADCAST_RESULT_KEY, false);
+ return result;
+ }
+ }
+ result = loadCertificate(provider, certString);
+ } catch (IOException | JSONException e) {
+ // TODO try to get Provider Json
+ setErrorResult(result, downloading_vpn_certificate_failed, null);
e.printStackTrace();
- return false;
}
+ result.putParcelable(PROVIDER_KEY, provider);
+ return result;
}
diff --git a/app/src/main/java/se/leap/bitmaskclient/ConfigHelper.java b/app/src/main/java/se/leap/bitmaskclient/ConfigHelper.java
index 7b2accd6..a52df460 100644
--- a/app/src/main/java/se/leap/bitmaskclient/ConfigHelper.java
+++ b/app/src/main/java/se/leap/bitmaskclient/ConfigHelper.java
@@ -72,9 +72,9 @@ public class ConfigHelper {
"eeaf0ab9adb38dd69c33f80afa8fc5e86072618775ff3c0b9ea2314c9c256576d674df7496ea81d3383b4813d692c6e0e0d5d8e250b98be48e495c1d6089dad15dc7d7b46154d6b6ce8ef4ad69b15d4982559b297bcf1885c529f566660e57ec68edbc3c05726cc02fd4cbf4976eaa9afd5138fe8376435b9fc61d2fc0eb06e3";
final public static BigInteger G = new BigInteger("2");
- public static boolean checkErroneousDownload(String downloaded_string) {
+ public static boolean checkErroneousDownload(String downloadedString) {
try {
- if (downloaded_string == null || downloaded_string.isEmpty() || new JSONObject(downloaded_string).has(ProviderAPI.ERRORS)) {
+ if (downloadedString == null || downloadedString.isEmpty() || new JSONObject(downloadedString).has(ProviderAPI.ERRORS)) {
return true;
} else {
return false;
@@ -158,7 +158,7 @@ public class ConfigHelper {
}
protected static RSAPrivateKey parseRsaKeyFromString(String rsaKeyString) {
- RSAPrivateKey key = null;
+ RSAPrivateKey key;
try {
KeyFactory kf = KeyFactory.getInstance("RSA", "BC");
rsaKeyString = rsaKeyString.replaceFirst("-----BEGIN RSA PRIVATE KEY-----", "").replaceFirst("-----END RSA PRIVATE KEY-----", "");
@@ -282,6 +282,7 @@ public class ConfigHelper {
provider.setCaCert(preferences.getString(Provider.CA_CERT, ""));
provider.setVpnCertificate(preferences.getString(PROVIDER_VPN_CERTIFICATE, ""));
provider.setPrivateKey(preferences.getString(PROVIDER_PRIVATE_KEY, ""));
+ provider.setEipServiceJson(new JSONObject(preferences.getString(PROVIDER_EIP_DEFINITION, "")));
} catch (MalformedURLException | JSONException e) {
e.printStackTrace();
}
@@ -374,8 +375,6 @@ public class ConfigHelper {
putString(Provider.KEY + "." + providerDomain, provider.getDefinitionString()).
putString(Provider.CA_CERT + "." + providerDomain, provider.getCaCert()).
putString(PROVIDER_EIP_DEFINITION + "." + providerDomain, provider.getEipServiceJsonString()).
- putString(PROVIDER_PRIVATE_KEY + "." + providerDomain, provider.getPrivateKey()).
- putString(PROVIDER_VPN_CERTIFICATE + "." + providerDomain, provider.getVpnCertificate()).
apply();
}
diff --git a/app/src/main/java/se/leap/bitmaskclient/Constants.java b/app/src/main/java/se/leap/bitmaskclient/Constants.java
index 680c10bf..12b56b93 100644
--- a/app/src/main/java/se/leap/bitmaskclient/Constants.java
+++ b/app/src/main/java/se/leap/bitmaskclient/Constants.java
@@ -35,13 +35,11 @@ public interface Constants {
String EIP_ACTION_CHECK_CERT_VALIDITY = "EIP.CHECK_CERT_VALIDITY";
String EIP_ACTION_START = "se.leap.bitmaskclient.EIP.START";
String EIP_ACTION_STOP = "se.leap.bitmaskclient.EIP.STOP";
- String EIP_ACTION_UPDATE = "se.leap.bitmaskclient.EIP.UPDATE";
String EIP_ACTION_IS_RUNNING = "se.leap.bitmaskclient.EIP.IS_RUNNING";
String EIP_ACTION_START_ALWAYS_ON_VPN = "se.leap.bitmaskclient.START_ALWAYS_ON_VPN";
String EIP_ACTION_START_BLOCKING_VPN = "se.leap.bitmaskclient.EIP_ACTION_START_BLOCKING_VPN";
String EIP_ACTION_STOP_BLOCKING_VPN = "se.leap.bitmaskclient.EIP_ACTION_STOP_BLOCKING_VPN";
- String EIP_NOTIFICATION = "EIP.NOTIFICATION";
String EIP_RECEIVER = "EIP.RECEIVER";
String EIP_REQUEST = "EIP.REQUEST";
String EIP_RESTART_ON_BOOT = "EIP.RESTART_ON_BOOT";
diff --git a/app/src/main/java/se/leap/bitmaskclient/Dashboard.java b/app/src/main/java/se/leap/bitmaskclient/Dashboard.java
new file mode 100644
index 00000000..e69de29b
--- /dev/null
+++ b/app/src/main/java/se/leap/bitmaskclient/Dashboard.java
diff --git a/app/src/main/java/se/leap/bitmaskclient/EipFragment.java b/app/src/main/java/se/leap/bitmaskclient/EipFragment.java
index 41d9ff04..e1c61801 100644
--- a/app/src/main/java/se/leap/bitmaskclient/EipFragment.java
+++ b/app/src/main/java/se/leap/bitmaskclient/EipFragment.java
@@ -18,22 +18,18 @@ package se.leap.bitmaskclient;
import android.app.Activity;
import android.app.AlertDialog;
-import android.content.BroadcastReceiver;
import android.content.ComponentName;
import android.content.Context;
import android.content.DialogInterface;
import android.content.Intent;
-import android.content.IntentFilter;
import android.content.ServiceConnection;
import android.content.SharedPreferences;
import android.graphics.ColorMatrix;
import android.graphics.ColorMatrixColorFilter;
import android.os.Bundle;
import android.os.IBinder;
-import android.os.RemoteException;
import android.support.annotation.NonNull;
import android.support.v4.app.Fragment;
-import android.support.v4.content.LocalBroadcastManager;
import android.support.v7.widget.AppCompatImageView;
import android.util.Log;
import android.view.LayoutInflater;
@@ -50,38 +46,20 @@ import butterknife.InjectView;
import butterknife.OnClick;
import de.blinkt.openvpn.core.IOpenVPNServiceInternal;
import de.blinkt.openvpn.core.OpenVPNService;
-import de.blinkt.openvpn.core.ProfileManager;
-import de.blinkt.openvpn.core.VpnStatus;
import se.leap.bitmaskclient.eip.EipCommand;
import se.leap.bitmaskclient.eip.EipStatus;
-import se.leap.bitmaskclient.eip.VoidVpnService;
-import static android.app.Activity.RESULT_OK;
-import static android.content.Intent.CATEGORY_DEFAULT;
import static android.view.View.GONE;
import static android.view.View.VISIBLE;
import static de.blinkt.openvpn.core.ConnectionStatus.LEVEL_NONETWORK;
-import static se.leap.bitmaskclient.Constants.BROADCAST_EIP_EVENT;
-import static se.leap.bitmaskclient.Constants.BROADCAST_PROVIDER_API_EVENT;
-import static se.leap.bitmaskclient.Constants.BROADCAST_RESULT_CODE;
-import static se.leap.bitmaskclient.Constants.BROADCAST_RESULT_KEY;
-import static se.leap.bitmaskclient.Constants.EIP_ACTION_CHECK_CERT_VALIDITY;
-import static se.leap.bitmaskclient.Constants.EIP_ACTION_START;
-import static se.leap.bitmaskclient.Constants.EIP_ACTION_STOP;
-import static se.leap.bitmaskclient.Constants.EIP_ACTION_STOP_BLOCKING_VPN;
-import static se.leap.bitmaskclient.Constants.EIP_ACTION_UPDATE;
-import static se.leap.bitmaskclient.Constants.EIP_NOTIFICATION;
-import static se.leap.bitmaskclient.Constants.EIP_REQUEST;
import static se.leap.bitmaskclient.Constants.EIP_RESTART_ON_BOOT;
import static se.leap.bitmaskclient.Constants.PROVIDER_KEY;
import static se.leap.bitmaskclient.Constants.REQUEST_CODE_LOG_IN;
import static se.leap.bitmaskclient.Constants.REQUEST_CODE_SWITCH_PROVIDER;
import static se.leap.bitmaskclient.Constants.SHARED_PREFERENCES;
-import static se.leap.bitmaskclient.ProviderAPI.CORRECTLY_DOWNLOADED_CERTIFICATE;
-import static se.leap.bitmaskclient.ProviderAPI.CORRECTLY_DOWNLOADED_EIP_SERVICE;
-import static se.leap.bitmaskclient.ProviderAPI.DOWNLOAD_CERTIFICATE;
-import static se.leap.bitmaskclient.ProviderAPI.INCORRECTLY_DOWNLOADED_CERTIFICATE;
-import static se.leap.bitmaskclient.ProviderAPI.INCORRECTLY_DOWNLOADED_EIP_SERVICE;
+import static se.leap.bitmaskclient.ProviderAPI.DOWNLOAD_VPN_CERTIFICATE;
+import static se.leap.bitmaskclient.ProviderCredentialsBaseActivity.USER_MESSAGE;
+import static se.leap.bitmaskclient.R.string.vpn_certificate_user_message;
public class EipFragment extends Fragment implements Observer {
@@ -114,9 +92,6 @@ public class EipFragment extends Fragment implements Observer {
TextView vpnRoute;
private EipStatus eipStatus;
- private boolean wantsToConnect;
-
- private EIPFragmentBroadcastReceiver eipFragmentBroadcastReceiver;
private IOpenVPNServiceInternal mService;
private ServiceConnection openVpnConnection = new ServiceConnection() {
@@ -161,7 +136,6 @@ public class EipFragment extends Fragment implements Observer {
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
eipStatus = EipStatus.getInstance();
- eipFragmentBroadcastReceiver = new EIPFragmentBroadcastReceiver();
Activity activity = getActivity();
if (activity != null) {
preferences = getActivity().getSharedPreferences(SHARED_PREFERENCES, Context.MODE_PRIVATE);
@@ -188,7 +162,6 @@ public class EipFragment extends Fragment implements Observer {
super.onResume();
//FIXME: avoid race conditions while checking certificate an logging in at about the same time
//eipCommand(Constants.EIP_ACTION_CHECK_CERT_VALIDITY);
- setUpBroadcastReceiver();
handleNewState();
bindOpenVpnService();
}
@@ -200,7 +173,6 @@ public class EipFragment extends Fragment implements Observer {
Activity activity = getActivity();
if (activity != null) {
getActivity().unbindService(openVpnConnection);
- LocalBroadcastManager.getInstance(activity).unregisterReceiver(eipFragmentBroadcastReceiver);
}
Log.d(TAG, "broadcast unregistered");
}
@@ -253,13 +225,7 @@ public class EipFragment extends Fragment implements Observer {
if (canStartEIP()) {
startEipFromScratch();
} else if (canLogInToStartEIP()) {
- wantsToConnect = true;
- Intent intent = new Intent(getContext(), LoginActivity.class);
- intent.putExtra(PROVIDER_KEY, provider);
- Activity activity = getActivity();
- if (activity != null) {
- activity.startActivityForResult(intent, REQUEST_CODE_LOG_IN);
- }
+ askUserToLogIn(getString(vpn_certificate_user_message));
} else {
// provider has no VpnCertificate but user is logged in
downloadVpnCertificate();
@@ -274,7 +240,7 @@ public class EipFragment extends Fragment implements Observer {
private boolean canLogInToStartEIP() {
boolean isAllowedRegistered = provider.allowsRegistered();
- boolean isLoggedIn = !LeapSRPSession.getToken().isEmpty();
+ boolean isLoggedIn = LeapSRPSession.loggedIn();
return isAllowedRegistered && !isLoggedIn && !eipStatus.isConnecting() && !eipStatus.isConnected();
}
@@ -310,7 +276,6 @@ public class EipFragment extends Fragment implements Observer {
}
public void startEipFromScratch() {
- wantsToConnect = false;
saveStatus(true);
Context context = getContext();
if (context != null) {
@@ -320,38 +285,6 @@ public class EipFragment extends Fragment implements Observer {
}
}
- private void stop() {
- saveStatus(false);
- if (eipStatus.isBlockingVpnEstablished()) {
- stopBlockingVpn();
- }
- disconnect();
- }
-
- private void stopBlockingVpn() {
- Log.d(TAG, "stop VoidVpn!");
- Activity activity = getActivity();
- if (activity != null) {
- Intent stopVoidVpnIntent = new Intent(activity, VoidVpnService.class);
- stopVoidVpnIntent.setAction(EIP_ACTION_STOP_BLOCKING_VPN);
- activity.startService(stopVoidVpnIntent);
- } else {
- Log.e(TAG, "activity is null when trying to stop blocking vpn");
- // TODO what to do if not stopping void vpn?
- }
- }
-
- private void disconnect() {
- ProfileManager.setConntectedVpnProfileDisconnected(getActivity());
- if (mService != null) {
- try {
- mService.stopVPN(false);
- } catch (RemoteException e) {
- VpnStatus.logException(e);
- }
- }
- }
-
protected void stopEipIfPossible() {
Context context = getContext();
if (context != null) {
@@ -454,84 +387,6 @@ public class EipFragment extends Fragment implements Observer {
}
}
- private class EIPFragmentBroadcastReceiver extends BroadcastReceiver {
- @Override
- public void onReceive(Context context, Intent intent) {
- Log.d(TAG, "received Broadcast");
-
- String action = intent.getAction();
- if (action == null) {
- return;
- }
-
- int resultCode = intent.getIntExtra(BROADCAST_RESULT_CODE, -1);
- Bundle resultData = intent.getParcelableExtra(BROADCAST_RESULT_KEY);
- switch (action) {
- case BROADCAST_EIP_EVENT:
- handleEIPEvent(resultCode, resultData);
- break;
- case BROADCAST_PROVIDER_API_EVENT:
- handleProviderApiEvent(resultCode, resultData);
- break;
- }
- }
- }
-
- private void handleEIPEvent(int resultCode, Bundle resultData) {
- String request = resultData.getString(EIP_REQUEST);
-
- if (request == null) {
- return;
- }
-
- switch (request) {
- case EIP_ACTION_START:
- switch (resultCode) {
- case RESULT_OK:
- break;
- case Activity.RESULT_CANCELED:
- break;
- }
- break;
- case EIP_ACTION_STOP:
- switch (resultCode) {
- case RESULT_OK:
- stop();
- break;
- case Activity.RESULT_CANCELED:
- break;
- }
- break;
- case EIP_NOTIFICATION:
- switch (resultCode) {
- case RESULT_OK:
- break;
- case Activity.RESULT_CANCELED:
- break;
- }
- break;
- case EIP_ACTION_CHECK_CERT_VALIDITY:
- switch (resultCode) {
- case RESULT_OK:
- break;
- case Activity.RESULT_CANCELED:
- downloadVpnCertificate();
- break;
- }
- break;
- case EIP_ACTION_UPDATE:
- switch (resultCode) {
- case RESULT_OK:
- if (wantsToConnect)
- startEipFromScratch();
- break;
- case Activity.RESULT_CANCELED:
- handleNewState();
- break;
- }
- }
- }
-
private void greyscaleBackground() {
ColorMatrix matrix = new ColorMatrix();
matrix.setSaturation(0);
@@ -550,46 +405,21 @@ public class EipFragment extends Fragment implements Observer {
background.setImageAlpha(255);
}
- public void handleProviderApiEvent(int resultCode, Bundle resultData) {
- Context context = getContext();
- if (context == null) {
- return;
- }
-
- // TODO call DOWNLOAD_EIP_SERVICES ore remove respective cases
- switch (resultCode) {
- case CORRECTLY_DOWNLOADED_EIP_SERVICE:
- provider = resultData.getParcelable(PROVIDER_KEY);
- EipCommand.updateEipService(context);
- break;
- case INCORRECTLY_DOWNLOADED_EIP_SERVICE:
- //dashboard.setResult(RESULT_CANCELED);
- // TODO CATCH ME IF YOU CAN - WHAT DO WE WANT TO DO?
- break;
- case CORRECTLY_DOWNLOADED_CERTIFICATE:
- startEipFromScratch();
- break;
- case INCORRECTLY_DOWNLOADED_CERTIFICATE:
- // TODO CATCH ME IF YOU CAN - LOGIN?
- break;
- }
- }
-
private void downloadVpnCertificate() {
- ProviderAPICommand.execute(getContext(), DOWNLOAD_CERTIFICATE, provider);
+ ProviderAPICommand.execute(getContext(), DOWNLOAD_VPN_CERTIFICATE, provider);
}
- private void setUpBroadcastReceiver() {
+ private void askUserToLogIn(String userMessage) {
+ Intent intent = new Intent(getContext(), LoginActivity.class);
+ intent.putExtra(PROVIDER_KEY, provider);
+
+ if(userMessage != null) {
+ intent.putExtra(USER_MESSAGE, userMessage);
+ }
+
Activity activity = getActivity();
if (activity != null) {
- IntentFilter updateIntentFilter = new IntentFilter(BROADCAST_EIP_EVENT);
- updateIntentFilter.addAction(BROADCAST_PROVIDER_API_EVENT);
- updateIntentFilter.addCategory(CATEGORY_DEFAULT);
- LocalBroadcastManager.getInstance(activity).registerReceiver(eipFragmentBroadcastReceiver, updateIntentFilter);
- Log.d(TAG, "broadcast registered");
- } else {
- Log.e(TAG, "activity null when setting up broadcast receiver");
+ activity.startActivityForResult(intent, REQUEST_CODE_LOG_IN);
}
}
-
}
diff --git a/app/src/main/java/se/leap/bitmaskclient/MainActivity.java b/app/src/main/java/se/leap/bitmaskclient/MainActivity.java
index 69002355..2a2a68a7 100644
--- a/app/src/main/java/se/leap/bitmaskclient/MainActivity.java
+++ b/app/src/main/java/se/leap/bitmaskclient/MainActivity.java
@@ -1,33 +1,101 @@
package se.leap.bitmaskclient;
+import android.content.BroadcastReceiver;
+import android.content.ComponentName;
+import android.content.Context;
import android.content.Intent;
+import android.content.IntentFilter;
+import android.content.ServiceConnection;
import android.content.SharedPreferences;
import android.os.Bundle;
+import android.os.IBinder;
+import android.os.RemoteException;
+import android.support.v4.app.DialogFragment;
import android.support.v4.app.Fragment;
+import android.support.v4.app.FragmentTransaction;
+import android.support.v4.content.LocalBroadcastManager;
import android.support.v4.widget.DrawerLayout;
import android.support.v7.app.AppCompatActivity;
import android.support.v7.widget.Toolbar;
+import android.util.Log;
+import org.jetbrains.annotations.NotNull;
+import org.json.JSONException;
+import org.json.JSONObject;
+
+import java.util.Observable;
+import java.util.Observer;
+
+import de.blinkt.openvpn.core.IOpenVPNServiceInternal;
+import de.blinkt.openvpn.core.OpenVPNService;
+import de.blinkt.openvpn.core.ProfileManager;
+import de.blinkt.openvpn.core.VpnStatus;
import se.leap.bitmaskclient.drawer.NavigationDrawerFragment;
import se.leap.bitmaskclient.eip.EipCommand;
+import se.leap.bitmaskclient.eip.EipStatus;
+import se.leap.bitmaskclient.eip.VoidVpnService;
import se.leap.bitmaskclient.fragments.LogFragment;
+import static android.content.Intent.CATEGORY_DEFAULT;
+import static se.leap.bitmaskclient.Constants.BROADCAST_EIP_EVENT;
+import static se.leap.bitmaskclient.Constants.BROADCAST_PROVIDER_API_EVENT;
+import static se.leap.bitmaskclient.Constants.BROADCAST_RESULT_CODE;
+import static se.leap.bitmaskclient.Constants.BROADCAST_RESULT_KEY;
+import static se.leap.bitmaskclient.Constants.EIP_ACTION_START;
+import static se.leap.bitmaskclient.Constants.EIP_ACTION_STOP;
+import static se.leap.bitmaskclient.Constants.EIP_ACTION_STOP_BLOCKING_VPN;
+import static se.leap.bitmaskclient.Constants.EIP_REQUEST;
+import static se.leap.bitmaskclient.Constants.EIP_RESTART_ON_BOOT;
import static se.leap.bitmaskclient.Constants.PROVIDER_KEY;
import static se.leap.bitmaskclient.Constants.REQUEST_CODE_CONFIGURE_LEAP;
import static se.leap.bitmaskclient.Constants.REQUEST_CODE_LOG_IN;
import static se.leap.bitmaskclient.Constants.REQUEST_CODE_SWITCH_PROVIDER;
import static se.leap.bitmaskclient.Constants.SHARED_PREFERENCES;
import static se.leap.bitmaskclient.EipFragment.ASK_TO_CANCEL_VPN;
+import static se.leap.bitmaskclient.ProviderAPI.CORRECTLY_DOWNLOADED_EIP_SERVICE;
+import static se.leap.bitmaskclient.ProviderAPI.CORRECTLY_DOWNLOADED_VPN_CERTIFICATE;
+import static se.leap.bitmaskclient.ProviderAPI.ERRORS;
+import static se.leap.bitmaskclient.ProviderAPI.INCORRECTLY_DOWNLOADED_EIP_SERVICE;
+import static se.leap.bitmaskclient.ProviderAPI.INCORRECTLY_DOWNLOADED_VPN_CERTIFICATE;
+import static se.leap.bitmaskclient.ProviderCredentialsBaseActivity.USER_MESSAGE;
+import static se.leap.bitmaskclient.R.string.downloading_vpn_certificate_failed;
+import static se.leap.bitmaskclient.R.string.vpn_certificate_user_message;
+
+
+public class MainActivity extends AppCompatActivity implements Observer, MainActivityErrorDialog.MainActivityErrorDialogInterface{
+ public final static String TAG = MainActivity.class.getSimpleName();
-public class MainActivity extends AppCompatActivity {
+ private final String ACTIVITY_STATE = "state of activity";
+ private final String DEFAULT_UI_STATE = "default state";
+ private final String SHOW_DIALOG_STATE = "show dialog";
+ private final String REASON_TO_FAIL = "reason to fail";
+ protected Intent mConfigState = new Intent(DEFAULT_UI_STATE);
private static Provider provider = new Provider();
- private static FragmentManagerEnhanced fragmentManager;
private SharedPreferences preferences;
+ private String reasonToFail;
+
+ private EipStatus eipStatus;
private NavigationDrawerFragment navigationDrawerFragment;
+ private MainActivityBroadcastReceiver mainActivityBroadcastReceiver;
+
+ private IOpenVPNServiceInternal mService;
+ private ServiceConnection openVpnConnection = new ServiceConnection() {
+ @Override
+ public void onServiceConnected(ComponentName className,
+ IBinder service) {
+ mService = IOpenVPNServiceInternal.Stub.asInterface(service);
+ }
+
+ @Override
+ public void onServiceDisconnected(ComponentName arg0) {
+ mService = null;
+ }
+
+ };
public final static String ACTION_SHOW_VPN_FRAGMENT = "action_show_vpn_fragment";
public final static String ACTION_SHOW_LOG_FRAGMENT = "action_show_log_fragment";
@@ -42,19 +110,62 @@ public class MainActivity extends AppCompatActivity {
setContentView(R.layout.activity_main);
setSupportActionBar((Toolbar) findViewById(R.id.toolbar));
+ mainActivityBroadcastReceiver = new MainActivityBroadcastReceiver();
+ setUpBroadcastReceiver();
+
navigationDrawerFragment = (NavigationDrawerFragment)
getSupportFragmentManager().findFragmentById(R.id.navigation_drawer);
preferences = getSharedPreferences(SHARED_PREFERENCES, MODE_PRIVATE);
provider = ConfigHelper.getSavedProviderFromSharedPreferences(preferences);
- fragmentManager = new FragmentManagerEnhanced(getSupportFragmentManager());
// Set up the drawer.
navigationDrawerFragment.setUp(
R.id.navigation_drawer,
(DrawerLayout) findViewById(R.id.drawer_layout));
+ eipStatus = EipStatus.getInstance();
+
handleIntentAction(getIntent());
+ if(savedInstanceState != null) {
+ restoreState(savedInstanceState);
+ }
+
+ }
+
+ @Override
+ protected void onSaveInstanceState(@NotNull Bundle outState) {
+ outState.putString(ACTIVITY_STATE, mConfigState.getAction());
+ outState.putParcelable(PROVIDER_KEY, provider);
+
+ DialogFragment dialogFragment = (DialogFragment) new FragmentManagerEnhanced(getSupportFragmentManager()).findFragmentByTag(MainActivityErrorDialog.TAG);
+ outState.putString(REASON_TO_FAIL, reasonToFail);
+ if (dialogFragment != null) {
+ dialogFragment.dismiss();
+ }
+
+ super.onSaveInstanceState(outState);
+ }
+
+ private void restoreState(Bundle savedInstance) {
+ String activityState = savedInstance.getString(ACTIVITY_STATE, "");
+ if (activityState.equals(SHOW_DIALOG_STATE)) {
+ reasonToFail = savedInstance.getString(REASON_TO_FAIL);
+ if (reasonToFail != null) {
+ showDownloadFailedDialog(reasonToFail);
+ }
+ }
+ }
+
+ @Override
+ protected void onResume() {
+ super.onResume();
+ bindOpenVpnService();
+
+ String action = mConfigState.getAction();
+ if(action.equalsIgnoreCase(SHOW_DIALOG_STATE)) {
+ showDownloadFailedDialog(reasonToFail);
+ }
}
@Override
@@ -127,8 +238,196 @@ public class MainActivity extends AppCompatActivity {
Bundle arguments = new Bundle();
arguments.putParcelable(PROVIDER_KEY, provider);
fragment.setArguments(arguments);
- fragmentManager.beginTransaction()
+ new FragmentManagerEnhanced(getSupportFragmentManager()).beginTransaction()
.replace(R.id.container, fragment)
.commit();
}
+
+ @Override
+ protected void onPause() {
+ super.onPause();
+ unbindService(openVpnConnection);
+ }
+
+ @Override
+ protected void onDestroy() {
+ LocalBroadcastManager.getInstance(this).unregisterReceiver(mainActivityBroadcastReceiver);
+ mainActivityBroadcastReceiver = null;
+ super.onDestroy();
+ }
+
+ private void setUpBroadcastReceiver() {
+ IntentFilter updateIntentFilter = new IntentFilter(BROADCAST_EIP_EVENT);
+ updateIntentFilter.addAction(BROADCAST_PROVIDER_API_EVENT);
+ updateIntentFilter.addCategory(CATEGORY_DEFAULT);
+ LocalBroadcastManager.getInstance(this).registerReceiver(mainActivityBroadcastReceiver, updateIntentFilter);
+ Log.d(TAG, "broadcast registered");
+ }
+
+ @Override
+ public void onDialogDismissed() {
+ mConfigState.setAction(DEFAULT_UI_STATE);
+ reasonToFail = null;
+ }
+
+ private class MainActivityBroadcastReceiver extends BroadcastReceiver {
+ @Override
+ public void onReceive(Context context, Intent intent) {
+ Log.d(TAG, "received Broadcast");
+
+ String action = intent.getAction();
+ if (action == null) {
+ return;
+ }
+
+ int resultCode = intent.getIntExtra(BROADCAST_RESULT_CODE, RESULT_CANCELED);
+ Bundle resultData = intent.getParcelableExtra(BROADCAST_RESULT_KEY);
+ if (resultData == null) {
+ resultData = Bundle.EMPTY;
+ }
+
+ switch (action) {
+ case BROADCAST_EIP_EVENT:
+ handleEIPEvent(resultCode, resultData);
+ break;
+ case BROADCAST_PROVIDER_API_EVENT:
+ handleProviderApiEvent(resultCode, resultData);
+ break;
+ }
+ }
+ }
+
+ private void handleEIPEvent(int resultCode, Bundle resultData) {
+ String request = resultData.getString(EIP_REQUEST);
+
+ if (request == null) {
+ return;
+ }
+
+ switch (request) {
+ case EIP_ACTION_START:
+ switch (resultCode) {
+ case RESULT_OK:
+ break;
+ case RESULT_CANCELED:
+ String error = resultData.getString(ERRORS);
+ if (LeapSRPSession.loggedIn() || provider.allowsAnonymous()) {
+ showDownloadFailedDialog(error);
+ } else {
+ askUserToLogIn(getString(vpn_certificate_user_message));
+ }
+ break;
+ }
+ break;
+ case EIP_ACTION_STOP:
+ switch (resultCode) {
+ case RESULT_OK:
+ stop();
+ break;
+ case RESULT_CANCELED:
+ break;
+ }
+ break;
+ }
+ }
+
+ public void handleProviderApiEvent(int resultCode, Bundle resultData) {
+ // TODO call DOWNLOAD_EIP_SERVICES ore remove respective cases
+ switch (resultCode) {
+ case CORRECTLY_DOWNLOADED_EIP_SERVICE:
+ provider = resultData.getParcelable(PROVIDER_KEY);
+ EipCommand.startVPN(this);
+ break;
+ case INCORRECTLY_DOWNLOADED_EIP_SERVICE:
+ // TODO CATCH ME IF YOU CAN - WHAT DO WE WANT TO DO?
+ break;
+
+ case CORRECTLY_DOWNLOADED_VPN_CERTIFICATE:
+ provider = resultData.getParcelable(PROVIDER_KEY);
+ ConfigHelper.storeProviderInPreferences(preferences, provider);
+ EipCommand.startVPN(this);
+ break;
+ case INCORRECTLY_DOWNLOADED_VPN_CERTIFICATE:
+ if (LeapSRPSession.loggedIn() || provider.allowsAnonymous()) {
+ showDownloadFailedDialog(getString(downloading_vpn_certificate_failed));
+ } else {
+ askUserToLogIn(getString(vpn_certificate_user_message));
+ }
+ break;
+ }
+ }
+
+ /**
+ * Shows an error dialog
+ */
+ public void showDownloadFailedDialog(String reasonToFail) {
+ this.reasonToFail = reasonToFail;
+ mConfigState.setAction(SHOW_DIALOG_STATE);
+ try {
+
+ FragmentTransaction fragmentTransaction = new FragmentManagerEnhanced(
+ this.getSupportFragmentManager()).removePreviousFragment(
+ MainActivityErrorDialog.TAG);
+ DialogFragment newFragment;
+ try {
+ JSONObject errorJson = new JSONObject(reasonToFail);
+ newFragment = MainActivityErrorDialog.newInstance(provider, errorJson);
+ } catch (JSONException e) {
+ e.printStackTrace();
+ newFragment = MainActivityErrorDialog.newInstance(provider, reasonToFail);
+ }
+ newFragment.show(fragmentTransaction, MainActivityErrorDialog.TAG);
+ } catch (IllegalStateException | NullPointerException e) {
+ e.printStackTrace();
+ }
+
+ }
+
+ @Override
+ public void update(Observable observable, Object data) {
+ if (observable instanceof EipStatus) {
+ eipStatus = (EipStatus) observable;
+ }
+ }
+
+ private void stop() {
+ preferences.edit().putBoolean(EIP_RESTART_ON_BOOT, false).apply();
+ if (eipStatus.isBlockingVpnEstablished()) {
+ stopBlockingVpn();
+ }
+ disconnect();
+ }
+
+ private void stopBlockingVpn() {
+ Log.d(TAG, "stop VoidVpn!");
+ Intent stopVoidVpnIntent = new Intent(this, VoidVpnService.class);
+ stopVoidVpnIntent.setAction(EIP_ACTION_STOP_BLOCKING_VPN);
+ startService(stopVoidVpnIntent);
+ }
+
+ private void disconnect() {
+ ProfileManager.setConntectedVpnProfileDisconnected(this);
+ if (mService != null) {
+ try {
+ mService.stopVPN(false);
+ } catch (RemoteException e) {
+ VpnStatus.logException(e);
+ }
+ }
+ }
+
+ private void bindOpenVpnService() {
+ Intent intent = new Intent(this, OpenVPNService.class);
+ intent.setAction(OpenVPNService.START_SERVICE);
+ bindService(intent, openVpnConnection, Context.BIND_AUTO_CREATE);
+ }
+
+ private void askUserToLogIn(String userMessage) {
+ Intent intent = new Intent(this, LoginActivity.class);
+ intent.putExtra(PROVIDER_KEY, provider);
+ if (userMessage != null) {
+ intent.putExtra(USER_MESSAGE, userMessage);
+ }
+ startActivityForResult(intent, REQUEST_CODE_LOG_IN);
+ }
}
diff --git a/app/src/main/java/se/leap/bitmaskclient/MainActivityErrorDialog.java b/app/src/main/java/se/leap/bitmaskclient/MainActivityErrorDialog.java
new file mode 100644
index 00000000..374c48fa
--- /dev/null
+++ b/app/src/main/java/se/leap/bitmaskclient/MainActivityErrorDialog.java
@@ -0,0 +1,148 @@
+/**
+ * Copyright (c) 2013 LEAP Encryption Access Project and contributers
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
+ */
+package se.leap.bitmaskclient;
+
+import android.app.AlertDialog;
+import android.app.Dialog;
+import android.content.Context;
+import android.content.DialogInterface;
+import android.os.Bundle;
+import android.support.annotation.NonNull;
+import android.support.v4.app.DialogFragment;
+
+import org.json.JSONObject;
+
+import static se.leap.bitmaskclient.MainActivityErrorDialog.DOWNLOAD_ERRORS.*;
+import static se.leap.bitmaskclient.ProviderAPI.DOWNLOAD_VPN_CERTIFICATE;
+import static se.leap.bitmaskclient.eip.EIP.ERRORS;
+import static se.leap.bitmaskclient.eip.EIP.ERROR_ID;
+
+/**
+ * Implements a dialog to show why a download failed.
+ *
+ * @author parmegv
+ */
+public class MainActivityErrorDialog extends DialogFragment {
+
+ public static String TAG = "downloaded_failed_dialog";
+ private String reasonToFail;
+ private DOWNLOAD_ERRORS downloadError = DEFAULT;
+
+ private MainActivityErrorDialogInterface callbackInterface;
+ private Provider provider;
+
+ public enum DOWNLOAD_ERRORS {
+ DEFAULT,
+ ERROR_INVALID_VPN_CERTIFICATE,
+ }
+
+ /**
+ * @return a new instance of this DialogFragment.
+ */
+ public static DialogFragment newInstance(Provider provider, String reasonToFail) {
+ MainActivityErrorDialog dialogFragment = new MainActivityErrorDialog();
+ dialogFragment.reasonToFail = reasonToFail;
+ dialogFragment.provider = provider;
+ return dialogFragment;
+ }
+
+ /**
+ * @return a new instance of this DialogFragment.
+ */
+ public static DialogFragment newInstance(Provider provider, JSONObject errorJson) {
+ MainActivityErrorDialog dialogFragment = new MainActivityErrorDialog();
+ dialogFragment.provider = provider;
+ try {
+ if (errorJson.has(ERRORS)) {
+ dialogFragment.reasonToFail = errorJson.getString(ERRORS);
+ } else {
+ //default error msg
+ dialogFragment.reasonToFail = dialogFragment.getString(R.string.error_io_exception_user_message);
+ }
+
+ if (errorJson.has(ERROR_ID)) {
+ dialogFragment.downloadError = valueOf(errorJson.getString(ERROR_ID));
+ }
+ } catch (Exception e) {
+ e.printStackTrace();
+ dialogFragment.reasonToFail = dialogFragment.getString(R.string.error_io_exception_user_message);
+ }
+ return dialogFragment;
+ }
+
+ @Override
+ @NonNull
+ public Dialog onCreateDialog(Bundle savedInstanceState) {
+ AlertDialog.Builder builder = new AlertDialog.Builder(getActivity());
+ builder.setMessage(reasonToFail)
+ .setNegativeButton(R.string.cancel, new DialogInterface.OnClickListener() {
+ public void onClick(DialogInterface dialog, int id) {
+ dialog.dismiss();
+ callbackInterface.onDialogDismissed();
+ }
+ });
+ switch (downloadError) {
+ case ERROR_INVALID_VPN_CERTIFICATE:
+ builder.setPositiveButton(R.string.update_certificate, new DialogInterface.OnClickListener() {
+ @Override
+ public void onClick(DialogInterface dialog, int which) {
+ dismiss();
+ ProviderAPICommand.execute(getContext(), DOWNLOAD_VPN_CERTIFICATE, provider);
+ callbackInterface.onDialogDismissed();
+ }
+ });
+ break;
+ default:
+ builder.setPositiveButton(R.string.retry, new DialogInterface.OnClickListener() {
+ public void onClick(DialogInterface dialog, int id) {
+ dismiss();
+ callbackInterface.onDialogDismissed();
+ }
+ });
+ break;
+ }
+
+ // Create the AlertDialog object and return it
+ return builder.create();
+ }
+
+ @Override
+ public void dismiss() {
+ super.dismiss();
+ }
+
+ public interface MainActivityErrorDialogInterface {
+ void onDialogDismissed();
+ }
+
+ @Override
+ public void onAttach(Context context) {
+ super.onAttach(context);
+ try {
+ callbackInterface = (MainActivityErrorDialogInterface) context;
+ } catch (ClassCastException e) {
+ throw new ClassCastException(context.toString()
+ + " must implement NoticeDialogListener");
+ }
+ }
+
+ @Override
+ public void onCancel(DialogInterface dialog) {
+ super.onCancel(dialog);
+ callbackInterface.onDialogDismissed();
+ }
+}
diff --git a/app/src/main/java/se/leap/bitmaskclient/OkHttpClientGenerator.java b/app/src/main/java/se/leap/bitmaskclient/OkHttpClientGenerator.java
index 40b2ea7f..7d1054f1 100644
--- a/app/src/main/java/se/leap/bitmaskclient/OkHttpClientGenerator.java
+++ b/app/src/main/java/se/leap/bitmaskclient/OkHttpClientGenerator.java
@@ -52,6 +52,7 @@ import static se.leap.bitmaskclient.R.string.error_io_exception_user_message;
import static se.leap.bitmaskclient.R.string.error_no_such_algorithm_exception_user_message;
import static se.leap.bitmaskclient.R.string.keyChainAccessError;
import static se.leap.bitmaskclient.R.string.server_unreachable_message;
+import static se.leap.bitmaskclient.R.string.warning_corrupted_provider_cert;
/**
* Created by cyberta on 08.01.18.
@@ -90,7 +91,8 @@ public class OkHttpClientGenerator {
return clientBuilder.build();
} catch (IllegalArgumentException e) {
e.printStackTrace();
- addErrorMessageToJson(initError, resources.getString(R.string.certificate_error));
+ // TODO ca cert is invalid - show better error ?!
+ addErrorMessageToJson(initError, resources.getString(certificate_error));
} catch (IllegalStateException | KeyManagementException | KeyStoreException e) {
e.printStackTrace();
addErrorMessageToJson(initError, String.format(resources.getString(keyChainAccessError), e.getLocalizedMessage()));
@@ -99,6 +101,7 @@ public class OkHttpClientGenerator {
addErrorMessageToJson(initError, resources.getString(error_no_such_algorithm_exception_user_message));
} catch (CertificateException e) {
e.printStackTrace();
+ // TODO ca cert is invalid - show better error ?!
addErrorMessageToJson(initError, resources.getString(certificate_error));
} catch (UnknownHostException e) {
e.printStackTrace();
diff --git a/app/src/main/java/se/leap/bitmaskclient/Provider.java b/app/src/main/java/se/leap/bitmaskclient/Provider.java
index b3362409..7104143c 100644
--- a/app/src/main/java/se/leap/bitmaskclient/Provider.java
+++ b/app/src/main/java/se/leap/bitmaskclient/Provider.java
@@ -112,10 +112,12 @@ public final class Provider implements Parcelable {
public boolean isConfigured() {
return !mainUrl.isDefault() &&
- definition.length() > 0 &&
!apiUrl.isDefault() &&
- caCert != null &&
- !caCert.isEmpty();
+ hasCaCert() &&
+ hasDefinition() &&
+ hasVpnCertificate() &&
+ hasEIP() &&
+ hasPrivateKey();
}
public void setMainUrl(URL url) {
@@ -161,7 +163,7 @@ public final class Provider implements Parcelable {
return getDefinition().toString();
}
- protected String getDomain() {
+ public String getDomain() {
return mainUrl.getDomain();
}
@@ -169,7 +171,7 @@ public final class Provider implements Parcelable {
return getMainUrl().toString();
}
- protected DefaultedURL getMainUrl() {
+ public DefaultedURL getMainUrl() {
return mainUrl;
}
@@ -400,6 +402,10 @@ public final class Provider implements Parcelable {
this.privateKey = privateKey;
}
+ public boolean hasPrivateKey() {
+ return privateKey != null && privateKey.length() > 0;
+ }
+
public String getVpnCertificate() {
return vpnCertificate;
}
diff --git a/app/src/main/java/se/leap/bitmaskclient/ProviderAPI.java b/app/src/main/java/se/leap/bitmaskclient/ProviderAPI.java
index b3399416..2e153c7a 100644
--- a/app/src/main/java/se/leap/bitmaskclient/ProviderAPI.java
+++ b/app/src/main/java/se/leap/bitmaskclient/ProviderAPI.java
@@ -44,13 +44,12 @@ public class ProviderAPI extends IntentService implements ProviderApiManagerBase
SIGN_UP = "srpRegister",
LOG_IN = "srpAuth",
LOG_OUT = "logOut",
- DOWNLOAD_CERTIFICATE = "downloadUserAuthedCertificate",
+ DOWNLOAD_VPN_CERTIFICATE = "downloadUserAuthedVPNCertificate",
PARAMETERS = "parameters",
RECEIVER_KEY = "receiver",
ERRORS = "errors",
ERRORID = "errorId",
- UPDATE_PROGRESSBAR = "update_progressbar",
- DOWNLOAD_EIP_SERVICE = "ProviderAPI.DOWNLOAD_EIP_SERVICE",
+ DOWNLOAD_SERVICE_JSON = "ProviderAPI.DOWNLOAD_SERVICE_JSON",
PROVIDER_SET_UP = "ProviderAPI.PROVIDER_SET_UP";
final public static int
@@ -60,8 +59,8 @@ public class ProviderAPI extends IntentService implements ProviderApiManagerBase
FAILED_SIGNUP = 6,
SUCCESSFUL_LOGOUT = 7,
LOGOUT_FAILED = 8,
- CORRECTLY_DOWNLOADED_CERTIFICATE = 9,
- INCORRECTLY_DOWNLOADED_CERTIFICATE = 10,
+ CORRECTLY_DOWNLOADED_VPN_CERTIFICATE = 9,
+ INCORRECTLY_DOWNLOADED_VPN_CERTIFICATE = 10,
PROVIDER_OK = 11,
PROVIDER_NOK = 12,
CORRECTLY_DOWNLOADED_EIP_SERVICE = 13,
@@ -69,8 +68,6 @@ public class ProviderAPI extends IntentService implements ProviderApiManagerBase
ProviderApiManager providerApiManager;
-
-
public ProviderAPI() {
super(TAG);
}
@@ -82,7 +79,6 @@ public class ProviderAPI extends IntentService implements ProviderApiManagerBase
return ProviderApiManager.lastDangerOn();
}
-
@Override
public void onCreate() {
super.onCreate();
@@ -99,7 +95,6 @@ public class ProviderAPI extends IntentService implements ProviderApiManagerBase
providerApiManager.handleIntent(command);
}
-
private ProviderApiManager initApiManager() {
SharedPreferences preferences = getSharedPreferences(SHARED_PREFERENCES, MODE_PRIVATE);
OkHttpClientGenerator clientGenerator = new OkHttpClientGenerator(preferences, getResources());
diff --git a/app/src/main/java/se/leap/bitmaskclient/ProviderApiManagerBase.java b/app/src/main/java/se/leap/bitmaskclient/ProviderApiManagerBase.java
index 505ee55b..5aff1af1 100644
--- a/app/src/main/java/se/leap/bitmaskclient/ProviderApiManagerBase.java
+++ b/app/src/main/java/se/leap/bitmaskclient/ProviderApiManagerBase.java
@@ -61,18 +61,18 @@ import static se.leap.bitmaskclient.Constants.CREDENTIALS_USERNAME;
import static se.leap.bitmaskclient.Constants.PROVIDER_KEY;
import static se.leap.bitmaskclient.Constants.PROVIDER_PRIVATE_KEY;
import static se.leap.bitmaskclient.Constants.PROVIDER_VPN_CERTIFICATE;
-import static se.leap.bitmaskclient.DownloadFailedDialog.DOWNLOAD_ERRORS.ERROR_CERTIFICATE_PINNING;
-import static se.leap.bitmaskclient.DownloadFailedDialog.DOWNLOAD_ERRORS.ERROR_CORRUPTED_PROVIDER_JSON;
-import static se.leap.bitmaskclient.DownloadFailedDialog.DOWNLOAD_ERRORS.ERROR_INVALID_CERTIFICATE;
-import static se.leap.bitmaskclient.ProviderAPI.CORRECTLY_DOWNLOADED_CERTIFICATE;
+import static se.leap.bitmaskclient.ProviderSetupFailedDialog.DOWNLOAD_ERRORS.ERROR_CERTIFICATE_PINNING;
+import static se.leap.bitmaskclient.ProviderSetupFailedDialog.DOWNLOAD_ERRORS.ERROR_CORRUPTED_PROVIDER_JSON;
+import static se.leap.bitmaskclient.ProviderSetupFailedDialog.DOWNLOAD_ERRORS.ERROR_INVALID_CERTIFICATE;
+import static se.leap.bitmaskclient.ProviderAPI.CORRECTLY_DOWNLOADED_VPN_CERTIFICATE;
import static se.leap.bitmaskclient.ProviderAPI.CORRECTLY_DOWNLOADED_EIP_SERVICE;
-import static se.leap.bitmaskclient.ProviderAPI.DOWNLOAD_CERTIFICATE;
-import static se.leap.bitmaskclient.ProviderAPI.DOWNLOAD_EIP_SERVICE;
+import static se.leap.bitmaskclient.ProviderAPI.DOWNLOAD_VPN_CERTIFICATE;
+import static se.leap.bitmaskclient.ProviderAPI.DOWNLOAD_SERVICE_JSON;
import static se.leap.bitmaskclient.ProviderAPI.ERRORID;
import static se.leap.bitmaskclient.ProviderAPI.ERRORS;
import static se.leap.bitmaskclient.ProviderAPI.FAILED_LOGIN;
import static se.leap.bitmaskclient.ProviderAPI.FAILED_SIGNUP;
-import static se.leap.bitmaskclient.ProviderAPI.INCORRECTLY_DOWNLOADED_CERTIFICATE;
+import static se.leap.bitmaskclient.ProviderAPI.INCORRECTLY_DOWNLOADED_VPN_CERTIFICATE;
import static se.leap.bitmaskclient.ProviderAPI.INCORRECTLY_DOWNLOADED_EIP_SERVICE;
import static se.leap.bitmaskclient.ProviderAPI.LOGOUT_FAILED;
import static se.leap.bitmaskclient.ProviderAPI.LOG_IN;
@@ -89,6 +89,7 @@ import static se.leap.bitmaskclient.ProviderAPI.SUCCESSFUL_LOGOUT;
import static se.leap.bitmaskclient.ProviderAPI.SUCCESSFUL_SIGNUP;
import static se.leap.bitmaskclient.ProviderAPI.UPDATE_PROVIDER_DETAILS;
import static se.leap.bitmaskclient.R.string.certificate_error;
+import static se.leap.bitmaskclient.R.string.vpn_certificate_is_invalid;
import static se.leap.bitmaskclient.R.string.error_io_exception_user_message;
import static se.leap.bitmaskclient.R.string.error_json_exception_user_message;
import static se.leap.bitmaskclient.R.string.error_no_such_algorithm_exception_user_message;
@@ -184,14 +185,15 @@ public abstract class ProviderApiManagerBase {
sendToReceiverOrBroadcast(receiver, LOGOUT_FAILED, Bundle.EMPTY, provider);
}
break;
- case DOWNLOAD_CERTIFICATE:
- if (updateVpnCertificate(provider)) {
- sendToReceiverOrBroadcast(receiver, CORRECTLY_DOWNLOADED_CERTIFICATE, Bundle.EMPTY, provider);
+ case DOWNLOAD_VPN_CERTIFICATE:
+ result = updateVpnCertificate(provider);
+ if (result.getBoolean(BROADCAST_RESULT_KEY)) {
+ sendToReceiverOrBroadcast(receiver, CORRECTLY_DOWNLOADED_VPN_CERTIFICATE, result, provider);
} else {
- sendToReceiverOrBroadcast(receiver, INCORRECTLY_DOWNLOADED_CERTIFICATE, Bundle.EMPTY, provider);
+ sendToReceiverOrBroadcast(receiver, INCORRECTLY_DOWNLOADED_VPN_CERTIFICATE, result, provider);
}
break;
- case DOWNLOAD_EIP_SERVICE:
+ case DOWNLOAD_SERVICE_JSON:
result = getAndSetEipServiceJson(provider);
if (result.getBoolean(BROADCAST_RESULT_KEY)) {
sendToReceiverOrBroadcast(receiver, CORRECTLY_DOWNLOADED_EIP_SERVICE, result, provider);
@@ -537,7 +539,7 @@ public abstract class ProviderApiManagerBase {
}
private String requestStringFromServer(@NonNull String url, @NonNull String request_method, String jsonString, @NonNull List<Pair<String, String>> headerArgs, @NonNull OkHttpClient okHttpClient) {
- String plainResponseBody = null;
+ String plainResponseBody;
try {
@@ -617,7 +619,7 @@ public abstract class ProviderApiManagerBase {
*
* @return true if certificate was downloaded correctly, false if provider.json is not present in SharedPreferences, or if the certificate url could not be parsed as a URI, or if there was an SSL error.
*/
- protected abstract boolean updateVpnCertificate(Provider provider);
+ protected abstract Bundle updateVpnCertificate(Provider provider);
protected boolean isValidJson(String jsonString) {
@@ -815,15 +817,17 @@ public abstract class ProviderApiManagerBase {
return false;
}
- protected boolean loadCertificate(Provider provider, String cert_string) {
- if (cert_string == null) {
- return false;
+ protected Bundle loadCertificate(Provider provider, String certString) {
+ Bundle result = new Bundle();
+ if (certString == null) {
+ setErrorResult(result, vpn_certificate_is_invalid, null);
+ return result;
}
try {
// API returns concatenated cert & key. Split them for OpenVPN options
String certificateString = null, keyString = null;
- String[] certAndKey = cert_string.split("(?<=-\n)");
+ String[] certAndKey = certString.split("(?<=-\n)");
for (int i = 0; i < certAndKey.length - 1; i++) {
if (certAndKey[i].contains("KEY")) {
keyString = certAndKey[i++] + certAndKey[i];
@@ -837,13 +841,14 @@ public abstract class ProviderApiManagerBase {
provider.setPrivateKey( "-----BEGIN RSA PRIVATE KEY-----\n" + keyString + "-----END RSA PRIVATE KEY-----");
X509Certificate certificate = ConfigHelper.parseX509CertificateFromString(certificateString);
+ certificate.checkValidity();
certificateString = Base64.encodeToString(certificate.getEncoded(), Base64.DEFAULT);
provider.setVpnCertificate( "-----BEGIN CERTIFICATE-----\n" + certificateString + "-----END CERTIFICATE-----");
- return true;
+ result.putBoolean(BROADCAST_RESULT_KEY, true);
} catch (CertificateException | NullPointerException e) {
- // TODO Auto-generated catch block
e.printStackTrace();
- return false;
+ setErrorResult(result, vpn_certificate_is_invalid, null);
}
+ return result;
}
}
diff --git a/app/src/main/java/se/leap/bitmaskclient/ProviderCredentialsBaseActivity.java b/app/src/main/java/se/leap/bitmaskclient/ProviderCredentialsBaseActivity.java
index 7714e979..ba10ae24 100644
--- a/app/src/main/java/se/leap/bitmaskclient/ProviderCredentialsBaseActivity.java
+++ b/app/src/main/java/se/leap/bitmaskclient/ProviderCredentialsBaseActivity.java
@@ -41,7 +41,7 @@ import static se.leap.bitmaskclient.Constants.BROADCAST_RESULT_KEY;
import static se.leap.bitmaskclient.Constants.CREDENTIALS_PASSWORD;
import static se.leap.bitmaskclient.Constants.CREDENTIALS_USERNAME;
import static se.leap.bitmaskclient.Constants.PROVIDER_KEY;
-import static se.leap.bitmaskclient.ProviderAPI.DOWNLOAD_CERTIFICATE;
+import static se.leap.bitmaskclient.ProviderAPI.DOWNLOAD_VPN_CERTIFICATE;
import static se.leap.bitmaskclient.ProviderAPI.LOG_IN;
import static se.leap.bitmaskclient.ProviderAPI.SIGN_UP;
@@ -59,7 +59,7 @@ public abstract class ProviderCredentialsBaseActivity extends ConfigWizardBaseAc
final private static String SHOWING_FORM = "SHOWING_FORM";
final private static String PERFORMING_ACTION = "PERFORMING_ACTION";
- final private static String USER_MESSAGE = "USER_MESSAGE";
+ final public static String USER_MESSAGE = "USER_MESSAGE";
final private static String USERNAME_ERROR = "USERNAME_ERROR";
final private static String PASSWORD_ERROR = "PASSWORD_ERROR";
final private static String PASSWORD_VERIFICATION_ERROR = "PASSWORD_VERIFICATION_ERROR";
@@ -105,6 +105,12 @@ public abstract class ProviderCredentialsBaseActivity extends ConfigWizardBaseAc
if(savedInstanceState != null) {
restoreState(savedInstanceState);
}
+
+ String userMessageString = getIntent().getStringExtra(USER_MESSAGE);
+ if (userMessageString != null) {
+ userMessage.setText(userMessageString);
+ userMessage.setVisibility(VISIBLE);
+ }
}
@Override
@@ -204,7 +210,7 @@ public abstract class ProviderCredentialsBaseActivity extends ConfigWizardBaseAc
void downloadVpnCertificate(Provider handledProvider) {
provider = handledProvider;
- ProviderAPICommand.execute(this, DOWNLOAD_CERTIFICATE, provider);
+ ProviderAPICommand.execute(this, DOWNLOAD_VPN_CERTIFICATE, provider);
}
protected Bundle bundleUsernameAndPassword(String username, String password) {
@@ -381,7 +387,7 @@ public abstract class ProviderCredentialsBaseActivity extends ConfigWizardBaseAc
return;
}
- int resultCode = intent.getIntExtra(BROADCAST_RESULT_CODE, -1);
+ int resultCode = intent.getIntExtra(BROADCAST_RESULT_CODE, RESULT_CANCELED);
Bundle resultData = intent.getParcelableExtra(BROADCAST_RESULT_KEY);
Provider handledProvider = resultData.getParcelable(PROVIDER_KEY);
@@ -395,11 +401,10 @@ public abstract class ProviderCredentialsBaseActivity extends ConfigWizardBaseAc
handleReceivedErrors((Bundle) intent.getParcelableExtra(BROADCAST_RESULT_KEY));
break;
- case ProviderAPI.CORRECTLY_DOWNLOADED_CERTIFICATE:
+ case ProviderAPI.CORRECTLY_DOWNLOADED_VPN_CERTIFICATE:
successfullyFinished(handledProvider);
- //activity.eip_fragment.updateEipService();
break;
- case ProviderAPI.INCORRECTLY_DOWNLOADED_CERTIFICATE:
+ case ProviderAPI.INCORRECTLY_DOWNLOADED_VPN_CERTIFICATE:
// TODO activity.setResult(RESULT_CANCELED);
break;
}
diff --git a/app/src/main/java/se/leap/bitmaskclient/ProviderListBaseActivity.java b/app/src/main/java/se/leap/bitmaskclient/ProviderListBaseActivity.java
index 41d2d849..3b855601 100644
--- a/app/src/main/java/se/leap/bitmaskclient/ProviderListBaseActivity.java
+++ b/app/src/main/java/se/leap/bitmaskclient/ProviderListBaseActivity.java
@@ -53,10 +53,10 @@ import static se.leap.bitmaskclient.Constants.BROADCAST_RESULT_CODE;
import static se.leap.bitmaskclient.Constants.BROADCAST_RESULT_KEY;
import static se.leap.bitmaskclient.Constants.PROVIDER_KEY;
import static se.leap.bitmaskclient.Constants.REQUEST_CODE_CONFIGURE_LEAP;
-import static se.leap.bitmaskclient.ProviderAPI.CORRECTLY_DOWNLOADED_CERTIFICATE;
-import static se.leap.bitmaskclient.ProviderAPI.DOWNLOAD_CERTIFICATE;
+import static se.leap.bitmaskclient.ProviderAPI.CORRECTLY_DOWNLOADED_VPN_CERTIFICATE;
+import static se.leap.bitmaskclient.ProviderAPI.DOWNLOAD_VPN_CERTIFICATE;
import static se.leap.bitmaskclient.ProviderAPI.ERRORS;
-import static se.leap.bitmaskclient.ProviderAPI.INCORRECTLY_DOWNLOADED_CERTIFICATE;
+import static se.leap.bitmaskclient.ProviderAPI.INCORRECTLY_DOWNLOADED_VPN_CERTIFICATE;
import static se.leap.bitmaskclient.ProviderAPI.PROVIDER_NOK;
import static se.leap.bitmaskclient.ProviderAPI.PROVIDER_OK;
import static se.leap.bitmaskclient.ProviderAPI.PROVIDER_SET_UP;
@@ -74,7 +74,7 @@ import static se.leap.bitmaskclient.ProviderAPI.UPDATE_PROVIDER_DETAILS;
*/
public abstract class ProviderListBaseActivity extends ConfigWizardBaseActivity
- implements NewProviderDialog.NewProviderDialogInterface, DownloadFailedDialog.DownloadFailedDialogInterface, ProviderAPIResultReceiver.Receiver {
+ implements NewProviderDialog.NewProviderDialogInterface, ProviderSetupFailedDialog.DownloadFailedDialogInterface, ProviderAPIResultReceiver.Receiver {
@InjectView(R.id.provider_list)
protected ListView providerListView;
@@ -121,7 +121,7 @@ public abstract class ProviderListBaseActivity extends ConfigWizardBaseActivity
outState.putString(ACTIVITY_STATE, mConfigState.getAction());
outState.putParcelable(PROVIDER_KEY, provider);
- DialogFragment dialogFragment = (DialogFragment) fragmentManager.findFragmentByTag(DownloadFailedDialog.TAG);
+ DialogFragment dialogFragment = (DialogFragment) fragmentManager.findFragmentByTag(ProviderSetupFailedDialog.TAG);
if (dialogFragment != null) {
outState.putString(REASON_TO_FAIL, reasonToFail);
dialogFragment.dismiss();
@@ -313,7 +313,7 @@ public abstract class ProviderListBaseActivity extends ConfigWizardBaseActivity
* Asks ProviderApiService to download an anonymous (anon) VPN certificate.
*/
private void downloadVpnCertificate() {
- ProviderAPICommand.execute(this, DOWNLOAD_CERTIFICATE, provider);
+ ProviderAPICommand.execute(this, DOWNLOAD_VPN_CERTIFICATE, provider);
}
/**
@@ -345,16 +345,16 @@ public abstract class ProviderListBaseActivity extends ConfigWizardBaseActivity
*/
public void showDownloadFailedDialog() {
try {
- FragmentTransaction fragmentTransaction = fragmentManager.removePreviousFragment(DownloadFailedDialog.TAG);
+ FragmentTransaction fragmentTransaction = fragmentManager.removePreviousFragment(ProviderSetupFailedDialog.TAG);
DialogFragment newFragment;
try {
JSONObject errorJson = new JSONObject(reasonToFail);
- newFragment = DownloadFailedDialog.newInstance(provider, errorJson);
+ newFragment = ProviderSetupFailedDialog.newInstance(provider, errorJson);
} catch (JSONException e) {
e.printStackTrace();
- newFragment = DownloadFailedDialog.newInstance(provider, reasonToFail);
+ newFragment = ProviderSetupFailedDialog.newInstance(provider, reasonToFail);
}
- newFragment.show(fragmentTransaction, DownloadFailedDialog.TAG);
+ newFragment.show(fragmentTransaction, ProviderSetupFailedDialog.TAG);
} catch (IllegalStateException e) {
e.printStackTrace();
mConfigState.setAction(PENDING_SHOW_FAILED_DIALOG);
@@ -405,7 +405,7 @@ public abstract class ProviderListBaseActivity extends ConfigWizardBaseActivity
if (mConfigState.getAction() != null &&
mConfigState.getAction().equalsIgnoreCase(SETTING_UP_PROVIDER)) {
- int resultCode = intent.getIntExtra(BROADCAST_RESULT_CODE, -1);
+ int resultCode = intent.getIntExtra(BROADCAST_RESULT_CODE, RESULT_CANCELED);
Log.d(TAG, "Broadcast resultCode: " + Integer.toString(resultCode));
Bundle resultData = intent.getParcelableExtra(BROADCAST_RESULT_KEY);
@@ -419,10 +419,10 @@ public abstract class ProviderListBaseActivity extends ConfigWizardBaseActivity
case PROVIDER_NOK:
handleProviderSetupFailed(resultData);
break;
- case CORRECTLY_DOWNLOADED_CERTIFICATE:
+ case CORRECTLY_DOWNLOADED_VPN_CERTIFICATE:
handleCorrectlyDownloadedCertificate(handledProvider);
break;
- case INCORRECTLY_DOWNLOADED_CERTIFICATE:
+ case INCORRECTLY_DOWNLOADED_VPN_CERTIFICATE:
handleIncorrectlyDownloadedCertificate();
break;
}
diff --git a/app/src/main/java/se/leap/bitmaskclient/DownloadFailedDialog.java b/app/src/main/java/se/leap/bitmaskclient/ProviderSetupFailedDialog.java
index 8a6d981d..9e77452c 100644
--- a/app/src/main/java/se/leap/bitmaskclient/DownloadFailedDialog.java
+++ b/app/src/main/java/se/leap/bitmaskclient/ProviderSetupFailedDialog.java
@@ -26,8 +26,8 @@ import android.support.v4.app.DialogFragment;
import org.json.JSONObject;
-import static se.leap.bitmaskclient.DownloadFailedDialog.DOWNLOAD_ERRORS.DEFAULT;
-import static se.leap.bitmaskclient.DownloadFailedDialog.DOWNLOAD_ERRORS.valueOf;
+import static se.leap.bitmaskclient.ProviderSetupFailedDialog.DOWNLOAD_ERRORS.DEFAULT;
+import static se.leap.bitmaskclient.ProviderSetupFailedDialog.DOWNLOAD_ERRORS.valueOf;
import static se.leap.bitmaskclient.ProviderAPI.ERRORID;
import static se.leap.bitmaskclient.ProviderAPI.ERRORS;
@@ -36,7 +36,7 @@ import static se.leap.bitmaskclient.ProviderAPI.ERRORS;
*
* @author parmegv
*/
-public class DownloadFailedDialog extends DialogFragment {
+public class ProviderSetupFailedDialog extends DialogFragment {
public static String TAG = "downloaded_failed_dialog";
private String reasonToFail;
@@ -55,7 +55,7 @@ public class DownloadFailedDialog extends DialogFragment {
* @return a new instance of this DialogFragment.
*/
public static DialogFragment newInstance(Provider provider, String reasonToFail) {
- DownloadFailedDialog dialogFragment = new DownloadFailedDialog();
+ ProviderSetupFailedDialog dialogFragment = new ProviderSetupFailedDialog();
dialogFragment.reasonToFail = reasonToFail;
dialogFragment.provider = provider;
return dialogFragment;
@@ -65,7 +65,7 @@ public class DownloadFailedDialog extends DialogFragment {
* @return a new instance of this DialogFragment.
*/
public static DialogFragment newInstance(Provider provider, JSONObject errorJson) {
- DownloadFailedDialog dialogFragment = new DownloadFailedDialog();
+ ProviderSetupFailedDialog dialogFragment = new ProviderSetupFailedDialog();
dialogFragment.provider = provider;
try {
if (errorJson.has(ERRORS)) {
@@ -96,7 +96,7 @@ public class DownloadFailedDialog extends DialogFragment {
dialog.dismiss();
}
});
-switch (downloadError) {
+ switch (downloadError) {
case ERROR_CORRUPTED_PROVIDER_JSON:
builder.setPositiveButton(R.string.update_provider_details, new DialogInterface.OnClickListener() {
@Override
diff --git a/app/src/main/java/se/leap/bitmaskclient/eip/EIP.java b/app/src/main/java/se/leap/bitmaskclient/eip/EIP.java
index 46528b85..88047f55 100644
--- a/app/src/main/java/se/leap/bitmaskclient/eip/EIP.java
+++ b/app/src/main/java/se/leap/bitmaskclient/eip/EIP.java
@@ -16,7 +16,6 @@
*/
package se.leap.bitmaskclient.eip;
-import android.app.Activity;
import android.app.IntentService;
import android.content.Intent;
import android.content.SharedPreferences;
@@ -33,6 +32,9 @@ import java.lang.ref.WeakReference;
import de.blinkt.openvpn.LaunchVPN;
import se.leap.bitmaskclient.OnBootReceiver;
+import static android.app.Activity.RESULT_CANCELED;
+import static android.app.Activity.RESULT_OK;
+import static android.content.Intent.CATEGORY_DEFAULT;
import static se.leap.bitmaskclient.Constants.BROADCAST_EIP_EVENT;
import static se.leap.bitmaskclient.Constants.BROADCAST_RESULT_CODE;
import static se.leap.bitmaskclient.Constants.BROADCAST_RESULT_KEY;
@@ -41,13 +43,14 @@ import static se.leap.bitmaskclient.Constants.EIP_ACTION_IS_RUNNING;
import static se.leap.bitmaskclient.Constants.EIP_ACTION_START;
import static se.leap.bitmaskclient.Constants.EIP_ACTION_START_ALWAYS_ON_VPN;
import static se.leap.bitmaskclient.Constants.EIP_ACTION_STOP;
-import static se.leap.bitmaskclient.Constants.EIP_ACTION_UPDATE;
import static se.leap.bitmaskclient.Constants.EIP_RECEIVER;
import static se.leap.bitmaskclient.Constants.EIP_REQUEST;
import static se.leap.bitmaskclient.Constants.EIP_RESTART_ON_BOOT;
import static se.leap.bitmaskclient.Constants.PROVIDER_EIP_DEFINITION;
import static se.leap.bitmaskclient.Constants.PROVIDER_VPN_CERTIFICATE;
import static se.leap.bitmaskclient.Constants.SHARED_PREFERENCES;
+import static se.leap.bitmaskclient.MainActivityErrorDialog.DOWNLOAD_ERRORS.ERROR_INVALID_VPN_CERTIFICATE;
+import static se.leap.bitmaskclient.R.string.vpn_certificate_is_invalid;
/**
* EIP is the abstract base class for interacting with and managing the Encrypted
@@ -61,16 +64,14 @@ import static se.leap.bitmaskclient.Constants.SHARED_PREFERENCES;
*/
public final class EIP extends IntentService {
- public final static String TAG = EIP.class.getSimpleName();
- public final static String SERVICE_API_PATH = "config/eip-service.json";
+ public final static String TAG = EIP.class.getSimpleName(),
+ SERVICE_API_PATH = "config/eip-service.json",
+ ERRORS = "errors",
+ ERROR_ID = "errorID";
private WeakReference<ResultReceiver> mReceiverRef = new WeakReference<>(null);
private SharedPreferences preferences;
- private JSONObject eipDefinition;
- private GatewaysManager gatewaysManager = new GatewaysManager();
- private Gateway gateway;
-
public EIP() {
super(TAG);
}
@@ -79,9 +80,6 @@ public final class EIP extends IntentService {
public void onCreate() {
super.onCreate();
preferences = getSharedPreferences(SHARED_PREFERENCES, MODE_PRIVATE);
- eipDefinition = eipDefinitionFromPreferences();
- if (gatewaysManager.isEmpty())
- gatewaysFromPreferences();
}
@Override
@@ -108,11 +106,8 @@ public final class EIP extends IntentService {
case EIP_ACTION_IS_RUNNING:
isRunning();
break;
- case EIP_ACTION_UPDATE:
- updateEIPService();
- break;
case EIP_ACTION_CHECK_CERT_VALIDITY:
- checkCertValidity();
+ checkVPNCertificateValidity();
break;
}
}
@@ -123,21 +118,29 @@ public final class EIP extends IntentService {
* It also sets up early routes.
*/
private void startEIP() {
+ if (!EipStatus.getInstance().isBlockingVpnEstablished()) {
+ earlyRoutes();
+ }
+
+ Bundle result = new Bundle();
+
if (!preferences.getBoolean(EIP_RESTART_ON_BOOT, false)){
preferences.edit().putBoolean(EIP_RESTART_ON_BOOT, true).commit();
}
- if (gatewaysManager.isEmpty())
- updateEIPService();
- if (!EipStatus.getInstance().isBlockingVpnEstablished()) {
- earlyRoutes();
+
+ GatewaysManager gatewaysManager = gatewaysFromPreferences();
+ if (!isVPNCertificateValid()){
+ setErrorResult(result, vpn_certificate_is_invalid, ERROR_INVALID_VPN_CERTIFICATE.toString());
+ tellToReceiverOrBroadcast(EIP_ACTION_START, RESULT_CANCELED, result);
+ return;
}
- gateway = gatewaysManager.select();
+ Gateway gateway = gatewaysManager.select();
if (gateway != null && gateway.getProfile() != null) {
- launchActiveGateway();
- tellToReceiverOrBroadcast(EIP_ACTION_START, Activity.RESULT_OK);
+ launchActiveGateway(gateway);
+ tellToReceiverOrBroadcast(EIP_ACTION_START, RESULT_OK);
} else
- tellToReceiverOrBroadcast(EIP_ACTION_START, Activity.RESULT_CANCELED);
+ tellToReceiverOrBroadcast(EIP_ACTION_START, RESULT_CANCELED);
}
/**
@@ -147,14 +150,12 @@ public final class EIP extends IntentService {
private void startEIPAlwaysOnVpn() {
Log.d(TAG, "startEIPAlwaysOnVpn vpn");
- if (gatewaysManager.isEmpty())
- updateEIPService();
-
- gateway = gatewaysManager.select();
+ GatewaysManager gatewaysManager = gatewaysFromPreferences();
+ Gateway gateway = gatewaysManager.select();
if (gateway != null && gateway.getProfile() != null) {
Log.d(TAG, "startEIPAlwaysOnVpn eip launch avtive gateway vpn");
- launchActiveGateway();
+ launchActiveGateway(gateway);
} else {
Log.d(TAG, "startEIPAlwaysOnVpn no active profile available!");
}
@@ -170,7 +171,7 @@ public final class EIP extends IntentService {
startActivity(voidVpnLauncher);
}
- private void launchActiveGateway() {
+ private void launchActiveGateway(Gateway gateway) {
Intent intent = new Intent(this, LaunchVPN.class);
intent.setAction(Intent.ACTION_MAIN);
intent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
@@ -180,10 +181,11 @@ public final class EIP extends IntentService {
}
private void stopEIP() {
+ // TODO try to do anything! stop eip from here if possible...
EipStatus eipStatus = EipStatus.getInstance();
- int resultCode = Activity.RESULT_CANCELED;
+ int resultCode = RESULT_CANCELED;
if (eipStatus.isConnected() || eipStatus.isConnecting())
- resultCode = Activity.RESULT_OK;
+ resultCode = RESULT_OK;
tellToReceiverOrBroadcast(EIP_ACTION_STOP, resultCode);
}
@@ -196,22 +198,11 @@ public final class EIP extends IntentService {
private void isRunning() {
EipStatus eipStatus = EipStatus.getInstance();
int resultCode = (eipStatus.isConnected()) ?
- Activity.RESULT_OK :
- Activity.RESULT_CANCELED;
+ RESULT_OK :
+ RESULT_CANCELED;
tellToReceiverOrBroadcast(EIP_ACTION_IS_RUNNING, resultCode);
}
- /**
- * Loads eip-service.json from SharedPreferences, delete previous vpn profiles and add new gateways.
- * TODO Implement API call to refresh eip-service.json from the provider
- */
- private void updateEIPService() {
- eipDefinition = eipDefinitionFromPreferences();
- if (eipDefinition.length() > 0)
- updateGateways();
- tellToReceiverOrBroadcast(EIP_ACTION_UPDATE, Activity.RESULT_OK);
- }
-
private JSONObject eipDefinitionFromPreferences() {
JSONObject result = new JSONObject();
try {
@@ -226,34 +217,25 @@ public final class EIP extends IntentService {
return result;
}
- private void updateGateways() {
- gatewaysManager.clearGatewaysAndProfiles();
- gatewaysManager.fromEipServiceJson(eipDefinition);
- gatewaysToPreferences();
+ private GatewaysManager gatewaysFromPreferences() {
+ GatewaysManager gatewaysManager = new GatewaysManager(this, preferences);
+ gatewaysManager.fromEipServiceJson(eipDefinitionFromPreferences());
+ return gatewaysManager;
}
- private void gatewaysFromPreferences() {
- String gatewaysString = preferences.getString(Gateway.TAG, "");
- gatewaysManager = new GatewaysManager(this, preferences);
- gatewaysManager.addFromString(gatewaysString);
- preferences.edit().remove(Gateway.TAG).apply();
- }
-
- private void gatewaysToPreferences() {
- String gateways_string = gatewaysManager.toString();
- preferences.edit().putString(Gateway.TAG, gateways_string).commit();
+ private void checkVPNCertificateValidity() {
+ int resultCode = isVPNCertificateValid() ?
+ RESULT_OK :
+ RESULT_CANCELED;
+ tellToReceiverOrBroadcast(EIP_ACTION_CHECK_CERT_VALIDITY, resultCode);
}
- private void checkCertValidity() {
+ private boolean isVPNCertificateValid() {
VpnCertificateValidator validator = new VpnCertificateValidator(preferences.getString(PROVIDER_VPN_CERTIFICATE, ""));
- int resultCode = validator.isValid() ?
- Activity.RESULT_OK :
- Activity.RESULT_CANCELED;
- tellToReceiverOrBroadcast(EIP_ACTION_CHECK_CERT_VALIDITY, resultCode);
+ return validator.isValid();
}
- private void tellToReceiverOrBroadcast(String action, int resultCode) {
- Bundle resultData = new Bundle();
+ private void tellToReceiverOrBroadcast(String action, int resultCode, Bundle resultData) {
resultData.putString(EIP_REQUEST, action);
if (mReceiverRef.get() != null) {
mReceiverRef.get().send(resultCode, resultData);
@@ -262,13 +244,33 @@ public final class EIP extends IntentService {
}
}
+ private void tellToReceiverOrBroadcast(String action, int resultCode) {
+ tellToReceiverOrBroadcast(action, resultCode, new Bundle());
+ }
+
private void broadcastEvent(int resultCode , Bundle resultData) {
Intent intentUpdate = new Intent(BROADCAST_EIP_EVENT);
- intentUpdate.addCategory(Intent.CATEGORY_DEFAULT);
+ intentUpdate.addCategory(CATEGORY_DEFAULT);
intentUpdate.putExtra(BROADCAST_RESULT_CODE, resultCode);
intentUpdate.putExtra(BROADCAST_RESULT_KEY, resultData);
Log.d(TAG, "sending broadcast");
LocalBroadcastManager.getInstance(this).sendBroadcast(intentUpdate);
}
+ Bundle setErrorResult(Bundle result, int errorMessageId, String errorId) {
+ JSONObject errorJson = new JSONObject();
+ addErrorMessageToJson(errorJson, getResources().getString(errorMessageId), errorId);
+ result.putString(ERRORS, errorJson.toString());
+ result.putBoolean(BROADCAST_RESULT_KEY, false);
+ return result;
+ }
+
+ private void addErrorMessageToJson(JSONObject jsonObject, String errorMessage, String errorId) {
+ try {
+ jsonObject.put(ERRORS, errorMessage);
+ jsonObject.put(ERROR_ID, errorId);
+ } catch (JSONException e) {
+ e.printStackTrace();
+ }
+ }
}
diff --git a/app/src/main/java/se/leap/bitmaskclient/eip/EipCommand.java b/app/src/main/java/se/leap/bitmaskclient/eip/EipCommand.java
index 1c778ec7..aa06b462 100644
--- a/app/src/main/java/se/leap/bitmaskclient/eip/EipCommand.java
+++ b/app/src/main/java/se/leap/bitmaskclient/eip/EipCommand.java
@@ -11,7 +11,6 @@ import org.jetbrains.annotations.Nullable;
import static se.leap.bitmaskclient.Constants.EIP_ACTION_CHECK_CERT_VALIDITY;
import static se.leap.bitmaskclient.Constants.EIP_ACTION_START;
import static se.leap.bitmaskclient.Constants.EIP_ACTION_STOP;
-import static se.leap.bitmaskclient.Constants.EIP_ACTION_UPDATE;
import static se.leap.bitmaskclient.Constants.EIP_RECEIVER;
/**
@@ -40,14 +39,6 @@ public class EipCommand {
context.startService(vpnIntent);
}
- public static void updateEipService(@NonNull Context context, ResultReceiver resultReceiver) {
- execute(context, EIP_ACTION_UPDATE, resultReceiver);
- }
-
- public static void updateEipService(@NonNull Context context) {
- execute(context, EIP_ACTION_UPDATE);
- }
-
public static void startVPN(@NonNull Context context) {
execute(context, EIP_ACTION_START);
}
diff --git a/app/src/main/java/se/leap/bitmaskclient/eip/VpnCertificateValidator.java b/app/src/main/java/se/leap/bitmaskclient/eip/VpnCertificateValidator.java
index 197a080b..03dd9d05 100644
--- a/app/src/main/java/se/leap/bitmaskclient/eip/VpnCertificateValidator.java
+++ b/app/src/main/java/se/leap/bitmaskclient/eip/VpnCertificateValidator.java
@@ -48,12 +48,16 @@ public class VpnCertificateValidator {
return false;
}
- X509Certificate certificate_x509 = ConfigHelper.parseX509CertificateFromString(certificate);
- return isValid(certificate_x509);
+ X509Certificate x509Certificate = ConfigHelper.parseX509CertificateFromString(certificate);
+ return isValid(x509Certificate);
}
private boolean isValid(X509Certificate certificate) {
+ if (certificate == null) {
+ return false;
+ }
+
Calendar offsetDate = calculateOffsetCertificateValidity(certificate);
try {
certificate.checkValidity(offsetDate.getTime());
diff --git a/app/src/main/res/values/strings.xml b/app/src/main/res/values/strings.xml
index 515e1f37..c3e91617 100644
--- a/app/src/main/res/values/strings.xml
+++ b/app/src/main/res/values/strings.xml
@@ -100,8 +100,12 @@
<string name="void_vpn_title">Blocking traffic</string>
<string name="update_provider_details">Update provider details</string>
<string name="update_certificate">Update certificate</string>
+ <string name="warning_eip_json_corrupted">Updating provider configuration failed.</string>
+ <string name="eip_json_corrupted_user_message">Updating provider configuration failed. Please log in to try again.</string>
<string name="warning_corrupted_provider_details">Stored provider details are corrupted. You can either update Bitmask (recommended) or update the provider details using a commercial CA certificate.</string>
<string name="warning_corrupted_provider_cert">Stored provider certificate is invalid. You can either update Bitmask (recommended) or update the provider certificate using a commercial CA certificate.</string>
<string name="warning_expired_provider_cert">Stored provider certificate is expired. You can either update Bitmask (recommended) or update the provider certificate using a commercial CA certificate.</string>
-
+ <string name="downloading_vpn_certificate_failed">Downloading the VPN certificate failed. Try again or choose another provider.</string>
+ <string name="vpn_certificate_is_invalid">VPN certificate is invalid. Try to download a new one.</string>
+ <string name="vpn_certificate_user_message">The VPN certificate is invalid. Please log in to do download a new one.</string>
</resources>
diff --git a/app/src/production/java/se/leap/bitmaskclient/ProviderApiManager.java b/app/src/production/java/se/leap/bitmaskclient/ProviderApiManager.java
index 5317118b..a6f0436d 100644
--- a/app/src/production/java/se/leap/bitmaskclient/ProviderApiManager.java
+++ b/app/src/production/java/se/leap/bitmaskclient/ProviderApiManager.java
@@ -38,6 +38,8 @@ import static se.leap.bitmaskclient.Constants.PROVIDER_VPN_CERTIFICATE;
import static se.leap.bitmaskclient.DownloadFailedDialog.DOWNLOAD_ERRORS.ERROR_CERTIFICATE_PINNING;
import static se.leap.bitmaskclient.DownloadFailedDialog.DOWNLOAD_ERRORS.ERROR_CORRUPTED_PROVIDER_JSON;
import static se.leap.bitmaskclient.ProviderAPI.ERRORS;
+import static se.leap.bitmaskclient.R.string.downloading_vpn_certificate_failed;
+import static se.leap.bitmaskclient.R.string.error_io_exception_user_message;
import static se.leap.bitmaskclient.R.string.malformed_url;
import static se.leap.bitmaskclient.R.string.warning_corrupted_provider_cert;
import static se.leap.bitmaskclient.R.string.warning_corrupted_provider_details;
@@ -172,27 +174,32 @@ public class ProviderApiManager extends ProviderApiManagerBase {
* @return true if certificate was downloaded correctly, false if provider.json is not present in SharedPreferences, or if the certificate url could not be parsed as a URI, or if there was an SSL error.
*/
@Override
- protected boolean updateVpnCertificate(Provider provider) {
+ protected Bundle updateVpnCertificate(Provider provider) {
+ Bundle result = new Bundle();
try {
JSONObject providerJson = provider.getDefinition();
String providerMainUrl = providerJson.getString(Provider.API_URL);
URL newCertStringUrl = new URL(providerMainUrl + "/" + providerJson.getString(Provider.API_VERSION) + "/" + PROVIDER_VPN_CERTIFICATE);
String certString = downloadWithProviderCA(provider.getCaCert(), newCertStringUrl.toString());
-
- if (ConfigHelper.checkErroneousDownload(certString))
- return false;
- else
- return loadCertificate(provider, certString);
- } catch (IOException e) {
- // TODO Auto-generated catch block
- e.printStackTrace();
- return false;
- } catch (JSONException e) {
- // TODO Auto-generated catch block
+ if (ConfigHelper.checkErroneousDownload(certString)) {
+ if (certString == null || certString.isEmpty()) {
+ // probably 204
+ setErrorResult(result, error_io_exception_user_message, null);
+ } else {
+ String reasonToFail = pickErrorMessage(certString);
+ result.putString(ERRORS, reasonToFail);
+ result.putBoolean(BROADCAST_RESULT_KEY, false);
+ return result;
+ }
+ }
+ return loadCertificate(provider, certString);
+ } catch (IOException | JSONException e) {
+ // TODO try to get Provider Json
+ setErrorResult(result, downloading_vpn_certificate_failed, null);
e.printStackTrace();
- return false;
}
+ return result;
}
private Bundle downloadCACert(Provider provider) {
diff --git a/app/src/test/java/se/leap/bitmaskclient/eip/ProviderApiManagerTest.java b/app/src/test/java/se/leap/bitmaskclient/eip/ProviderApiManagerTest.java
index 4842d170..0121f7aa 100644
--- a/app/src/test/java/se/leap/bitmaskclient/eip/ProviderApiManagerTest.java
+++ b/app/src/test/java/se/leap/bitmaskclient/eip/ProviderApiManagerTest.java
@@ -269,7 +269,7 @@ public class ProviderApiManagerTest {
Bundle expectedResult = mockBundle();
expectedResult.putBoolean(BROADCAST_RESULT_KEY, false);
- expectedResult.putString(ERRORS, "{\"errorId\":\"ERROR_INVALID_CERTIFICATE\",\"errors\":\"Stored provider certificate is expired. You can either update Bitmask (recommended) or update the provider certificate using a commercial CA certificate.\"}");
+ expectedResult.putString(ERRORS, "{\"errorId\":\"ERROR_INVALID_VPN_CERTIFICATE\",\"errors\":\"Stored provider certificate is expired. You can either update Bitmask (recommended) or update the provider certificate using a commercial CA certificate.\"}");
expectedResult.putParcelable(PROVIDER_KEY, provider);
Intent providerApiCommand = mockIntent();
@@ -292,7 +292,7 @@ public class ProviderApiManagerTest {
Bundle expectedResult = mockBundle();
expectedResult.putBoolean(BROADCAST_RESULT_KEY, false);
- expectedResult.putString(ERRORS, "{\"errorId\":\"ERROR_INVALID_CERTIFICATE\",\"errors\":\"Stored provider certificate is expired. You can either update Bitmask (recommended) or update the provider certificate using a commercial CA certificate.\"}");
+ expectedResult.putString(ERRORS, "{\"errorId\":\"ERROR_INVALID_VPN_CERTIFICATE\",\"errors\":\"Stored provider certificate is expired. You can either update Bitmask (recommended) or update the provider certificate using a commercial CA certificate.\"}");
expectedResult.putParcelable(PROVIDER_KEY, provider);
Intent providerApiCommand = mockIntent();
@@ -315,7 +315,7 @@ public class ProviderApiManagerTest {
providerApiManager = new ProviderApiManager(mockPreferences, mockResources, mockClientGenerator(), new TestProviderApiServiceCallback());
Bundle expectedResult = mockBundle();
expectedResult.putBoolean(BROADCAST_RESULT_KEY, false);
- expectedResult.putString(ERRORS, "{\"errorId\":\"ERROR_INVALID_CERTIFICATE\",\"errors\":\"Stored provider certificate is invalid. You can either update Bitmask (recommended) or update the provider certificate using a commercial CA certificate.\"}");
+ expectedResult.putString(ERRORS, "{\"errorId\":\"ERROR_INVALID_VPN_CERTIFICATE\",\"errors\":\"Stored provider certificate is invalid. You can either update Bitmask (recommended) or update the provider certificate using a commercial CA certificate.\"}");
expectedResult.putParcelable(PROVIDER_KEY, provider);
Intent providerApiCommand = mockIntent();
@@ -340,7 +340,7 @@ public class ProviderApiManagerTest {
Bundle expectedResult = mockBundle();
expectedResult.putBoolean(BROADCAST_RESULT_KEY, false);
- expectedResult.putString(ERRORS, "{\"errorId\":\"ERROR_INVALID_CERTIFICATE\",\"errors\":\"Stored provider certificate is invalid. You can either update Bitmask (recommended) or update the provider certificate using a commercial CA certificate.\"}");
+ expectedResult.putString(ERRORS, "{\"errorId\":\"ERROR_INVALID_VPN_CERTIFICATE\",\"errors\":\"Stored provider certificate is invalid. You can either update Bitmask (recommended) or update the provider certificate using a commercial CA certificate.\"}");
expectedResult.putParcelable(PROVIDER_KEY, provider);
Intent providerApiCommand = mockIntent();