summaryrefslogtreecommitdiff
path: root/app
diff options
context:
space:
mode:
Diffstat (limited to 'app')
-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/ConfigWizardBaseActivity.java15
-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.java302
-rw-r--r--app/src/main/java/se/leap/bitmaskclient/MainActivity.java269
-rw-r--r--app/src/main/java/se/leap/bitmaskclient/MainActivityErrorDialog.java142
-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.java27
-rw-r--r--app/src/main/java/se/leap/bitmaskclient/ProviderListBaseActivity.java99
-rw-r--r--app/src/main/java/se/leap/bitmaskclient/ProviderSetupFailedDialog.java (renamed from app/src/main/java/se/leap/bitmaskclient/DownloadFailedDialog.java)48
-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.java37
-rw-r--r--app/src/production/java/se/leap/bitmaskclient/ProviderListActivity.java1
-rw-r--r--app/src/test/java/se/leap/bitmaskclient/ConfigHelperTest.java6
-rw-r--r--app/src/test/resources/private_rsa_key.pem24
-rw-r--r--app/src/test/resources/riseup.net.vpn_cert.pem23
24 files changed, 832 insertions, 455 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/ConfigWizardBaseActivity.java b/app/src/main/java/se/leap/bitmaskclient/ConfigWizardBaseActivity.java
index 7fcb5816..ea328216 100644
--- a/app/src/main/java/se/leap/bitmaskclient/ConfigWizardBaseActivity.java
+++ b/app/src/main/java/se/leap/bitmaskclient/ConfigWizardBaseActivity.java
@@ -2,6 +2,7 @@ package se.leap.bitmaskclient;
import android.content.SharedPreferences;
import android.os.Bundle;
+import android.os.PersistableBundle;
import android.support.annotation.DrawableRes;
import android.support.annotation.Nullable;
import android.support.annotation.StringRes;
@@ -74,6 +75,20 @@ public abstract class ConfigWizardBaseActivity extends ButterKnifeActivity {
setProviderHeaderText(provider.getName());
}
+ @Override
+ public void onSaveInstanceState(Bundle outState) {
+ super.onSaveInstanceState(outState);
+ if (provider != null) {
+ outState.putParcelable(PROVIDER_KEY, provider);
+ }
+ }
+
+ protected void restoreState(Bundle savedInstanceState) {
+ if (savedInstanceState != null && savedInstanceState.containsKey(PROVIDER_KEY)) {
+ provider = savedInstanceState.getParcelable(PROVIDER_KEY);
+ }
+ }
+
protected void setProviderHeaderLogo(@DrawableRes int providerHeaderLogo) {
this.providerHeaderLogo.setImageResource(providerHeaderLogo);
}
diff --git a/app/src/main/java/se/leap/bitmaskclient/Constants.java b/app/src/main/java/se/leap/bitmaskclient/Constants.java
index fb2655e3..2b7a8113 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 4bacfff8..fb57aea8 100644
--- a/app/src/main/java/se/leap/bitmaskclient/EipFragment.java
+++ b/app/src/main/java/se/leap/bitmaskclient/EipFragment.java
@@ -17,23 +17,19 @@
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.app.AlertDialog;
import android.support.v7.widget.AppCompatImageView;
import android.util.Log;
import android.view.LayoutInflater;
@@ -50,45 +46,27 @@ 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 se.leap.bitmaskclient.views.VpnStateImage;
-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 {
public final static String TAG = EipFragment.class.getSimpleName();
- protected static final String IS_CONNECTED = TAG + ".is_connected";
public static final String START_EIP_ON_BOOT = "start on boot";
public static final String ASK_TO_CANCEL_VPN = "ask_to_cancel_vpn";
@@ -112,9 +90,14 @@ public class EipFragment extends Fragment implements Observer {
TextView vpnRoute;
private EipStatus eipStatus;
- private boolean wantsToConnect;
- private EIPFragmentBroadcastReceiver eipFragmentBroadcastReceiver;
+ //---saved Instance -------
+ private final static String KEY_SHOW_PENDING_START_CANCELLATION = "KEY_SHOW_PENDING_START_CANCELLATION";
+ private final static String KEY_SHOW_ASK_TO_STOP_EIP = "KEY_SHOW_ASK_TO_STOP_EIP";
+ private boolean showPendingStartCancellation = false;
+ private boolean showAskToStopEip = false;
+ //------------------------
+ AlertDialog alertDialog;
private IOpenVPNServiceInternal mService;
private ServiceConnection openVpnConnection = new ServiceConnection() {
@@ -159,7 +142,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);
@@ -176,8 +158,11 @@ public class EipFragment extends Fragment implements Observer {
Bundle arguments = getArguments();
if (arguments != null && arguments.containsKey(ASK_TO_CANCEL_VPN) && arguments.getBoolean(ASK_TO_CANCEL_VPN)) {
+ arguments.remove(ASK_TO_CANCEL_VPN);
+ setArguments(arguments);
askToStopEIP();
}
+ restoreFromSavedInstance(savedInstanceState);
return view;
}
@@ -186,7 +171,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();
}
@@ -198,21 +182,37 @@ 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");
}
@Override
- public void onDestroyView() {
- super.onDestroyView();
- eipStatus.deleteObserver(this);
+ public void onSaveInstanceState(@NonNull Bundle outState) {
+ super.onSaveInstanceState(outState);
+ if (showAskToStopEip) {
+ outState.putBoolean(KEY_SHOW_ASK_TO_STOP_EIP, true);
+ alertDialog.dismiss();
+ } else if (showPendingStartCancellation) {
+ outState.putBoolean(KEY_SHOW_PENDING_START_CANCELLATION, true);
+ alertDialog.dismiss();
+
+ }
+ }
+
+ private void restoreFromSavedInstance(Bundle savedInstanceState) {
+ if (savedInstanceState != null && savedInstanceState.containsKey(KEY_SHOW_PENDING_START_CANCELLATION)) {
+ showPendingStartCancellation = true;
+ askPendingStartCancellation();
+ } else if (savedInstanceState != null && savedInstanceState.containsKey(KEY_SHOW_ASK_TO_STOP_EIP)) {
+ showAskToStopEip = true;
+ askToStopEIP();
+ }
}
@Override
- public void onSaveInstanceState(@NonNull Bundle outState) {
- outState.putBoolean(IS_CONNECTED, eipStatus.isConnected());
- super.onSaveInstanceState(outState);
+ public void onDestroyView() {
+ super.onDestroyView();
+ eipStatus.deleteObserver(this);
}
private void saveStatus(boolean restartOnBoot) {
@@ -246,13 +246,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();
@@ -267,7 +261,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();
}
@@ -279,38 +273,13 @@ public class EipFragment extends Fragment implements Observer {
}
}
- private void askPendingStartCancellation() {
- Activity activity = getActivity();
- if (activity == null) {
- Log.e(TAG, "activity is null when asking to cancel");
- return;
- }
- AlertDialog.Builder alertBuilder = new AlertDialog.Builder(getActivity());
- alertBuilder.setTitle(activity.getString(R.string.eip_cancel_connect_title))
- .setMessage(activity.getString(R.string.eip_cancel_connect_text))
- .setPositiveButton((android.R.string.yes), new DialogInterface.OnClickListener() {
- @Override
- public void onClick(DialogInterface dialog, int which) {
- stopEipIfPossible();
- }
- })
- .setNegativeButton(activity.getString(android.R.string.no), new DialogInterface.OnClickListener() {
- @Override
- public void onClick(DialogInterface dialog, int which) {
- }
- })
- .show();
-
- }
-
public void startEipFromScratch() {
+ saveStatus(true);
Context context = getContext();
if (context == null) {
Log.e(TAG, "context is null when trying to start VPN");
return;
}
- wantsToConnect = false;
- saveStatus(true);
EipCommand.startVPN(context, false);
vpnStateImage.showProgress();
routedText.setVisibility(GONE);
@@ -318,54 +287,54 @@ public class EipFragment extends Fragment implements Observer {
colorBackgroundALittle();
}
- private void stop() {
- saveStatus(false);
- if (eipStatus.isBlockingVpnEstablished()) {
- stopBlockingVpn();
+ protected void stopEipIfPossible() {
+ Context context = getContext();
+ if (context != null) {
+ EipCommand.stopVPN(getContext());
+ } else {
+ Log.e(TAG, "context is null when trying to stop EIP");
}
- disconnect();
}
- private void stopBlockingVpn() {
- Log.d(TAG, "stop VoidVpn!");
+ private void askPendingStartCancellation() {
Activity activity = getActivity();
if (activity == null) {
- // TODO what to do if not stopping void vpn?
- Log.e(TAG, "activity is null when trying to stop blocking vpn");
+ Log.e(TAG, "activity is null when asking to cancel");
return;
}
- Intent stopVoidVpnIntent = new Intent(activity, VoidVpnService.class);
- stopVoidVpnIntent.setAction(EIP_ACTION_STOP_BLOCKING_VPN);
- activity.startService(stopVoidVpnIntent);
- }
- private void disconnect() {
- ProfileManager.setConntectedVpnProfileDisconnected(getActivity());
- if (mService != null) {
- try {
- mService.stopVPN(false);
- } catch (RemoteException e) {
- VpnStatus.logException(e);
+ AlertDialog.Builder alertBuilder = new AlertDialog.Builder(getActivity());
+ showPendingStartCancellation = true;
+ alertDialog = alertBuilder.setTitle(activity.getString(R.string.eip_cancel_connect_title))
+ .setMessage(activity.getString(R.string.eip_cancel_connect_text))
+ .setPositiveButton((android.R.string.yes), new DialogInterface.OnClickListener() {
+ @Override
+ public void onClick(DialogInterface dialog, int which) {
+ stopEipIfPossible();
+ }
+ })
+ .setNegativeButton(activity.getString(android.R.string.no), new DialogInterface.OnClickListener() {
+ @Override
+ public void onClick(DialogInterface dialog, int which) {
+ }
+ }).setOnDismissListener(new DialogInterface.OnDismissListener() {
+ @Override
+ public void onDismiss(DialogInterface dialog) {
+ showPendingStartCancellation = false;
}
- }
- }
+ }).show();
- protected void stopEipIfPossible() {
- Context context = getContext();
- if (context == null) {
- Log.e(TAG, "context is null when trying to stop EIP");
- return;
- }
- EipCommand.stopVPN(getContext());
}
protected void askToStopEIP() {
Activity activity = getActivity();
if (activity == null) {
Log.e(TAG, "activity is null when asking to stop EIP");
+ return;
}
AlertDialog.Builder alertBuilder = new AlertDialog.Builder(activity);
- alertBuilder.setTitle(activity.getString(R.string.eip_cancel_connect_title))
+ showAskToStopEip = true;
+ alertDialog = alertBuilder.setTitle(activity.getString(R.string.eip_cancel_connect_title))
.setMessage(activity.getString(R.string.eip_warning_browser_inconsistency))
.setPositiveButton((android.R.string.yes), new DialogInterface.OnClickListener() {
@Override
@@ -377,8 +346,12 @@ public class EipFragment extends Fragment implements Observer {
@Override
public void onClick(DialogInterface dialog, int which) {
}
- })
- .show();
+ }).setOnDismissListener(new DialogInterface.OnDismissListener() {
+ @Override
+ public void onDismiss(DialogInterface dialog) {
+ showAskToStopEip = false;
+ }
+ }).show();
}
@Override
@@ -457,84 +430,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);
@@ -553,46 +448,21 @@ public class EipFragment extends Fragment implements Observer {
background.setImageAlpha(210);
}
- 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 83ab4144..6e778309 100644
--- a/app/src/main/java/se/leap/bitmaskclient/MainActivity.java
+++ b/app/src/main/java/se/leap/bitmaskclient/MainActivity.java
@@ -1,33 +1,97 @@
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 {
-public class MainActivity extends AppCompatActivity {
+ public final static String TAG = MainActivity.class.getSimpleName();
+
+ private static final String KEY_ACTIVITY_STATE = "key state of activity";
+ private static final String DEFAULT_UI_STATE = "default state";
+ private static final String SHOW_DIALOG_STATE = "show dialog";
+ private static final String REASON_TO_FAIL = "reason to fail";
private static Provider provider = new Provider();
- private static FragmentManagerEnhanced fragmentManager;
private SharedPreferences preferences;
-
+ 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,22 +106,31 @@ 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());
}
@Override
+ protected void onResume() {
+ super.onResume();
+ bindOpenVpnService();
+ }
+
+ @Override
protected void onNewIntent(Intent intent) {
super.onNewIntent(intent);
setIntent(intent);
@@ -86,6 +159,9 @@ public class MainActivity extends AppCompatActivity {
default:
break;
}
+ // on layout change / recreation of the activity, we don't want create new Fragments
+ // instead the fragments themselves care about recreation and state restoration
+ intent.setAction(null);
if (fragment != null) {
new FragmentManagerEnhanced(getSupportFragmentManager()).beginTransaction()
@@ -127,8 +203,191 @@ 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();
+ }
+
+
+ @Override
+ public void update(Observable observable, Object data) {
+ if (observable instanceof EipStatus) {
+ eipStatus = (EipStatus) observable;
+ }
+ }
+
+ 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");
+ }
+
+ 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()) {
+ showMainActivityErrorDialog(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, true);
+ 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, true);
+ break;
+ case INCORRECTLY_DOWNLOADED_VPN_CERTIFICATE:
+ if (LeapSRPSession.loggedIn() || provider.allowsAnonymous()) {
+ showMainActivityErrorDialog(getString(downloading_vpn_certificate_failed));
+ } else {
+ askUserToLogIn(getString(vpn_certificate_user_message));
+ }
+ break;
+ }
+ }
+
+ /**
+ * Shows an error dialog
+ */
+ public void showMainActivityErrorDialog(String reasonToFail) {
+ 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();
+ Log.w(TAG, "error dialog leaked!");
+ }
+
+ }
+
+
+ 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..23bc8427
--- /dev/null
+++ b/app/src/main/java/se/leap/bitmaskclient/MainActivityErrorDialog.java
@@ -0,0 +1,142 @@
+/**
+ * Copyright (c) 2018 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.Dialog;
+import android.content.DialogInterface;
+import android.os.Bundle;
+import android.support.annotation.NonNull;
+import android.support.annotation.Nullable;
+import android.support.v4.app.DialogFragment;
+import android.support.v7.app.AlertDialog;
+
+import org.json.JSONObject;
+
+import static se.leap.bitmaskclient.MainActivityErrorDialog.DOWNLOAD_ERRORS.DEFAULT;
+import static se.leap.bitmaskclient.MainActivityErrorDialog.DOWNLOAD_ERRORS.valueOf;
+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 an error dialog for the main activity.
+ *
+ * @author fupduck
+ * @author cyberta
+ */
+public class MainActivityErrorDialog extends DialogFragment {
+
+ final public static String TAG = "downloaded_failed_dialog";
+ final private static String KEY_REASON_TO_FAIL = "key reason to fail";
+ final private static String KEY_PROVIDER = "key provider";
+ private String reasonToFail;
+ private DOWNLOAD_ERRORS downloadError = DEFAULT;
+
+ 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
+ public void onCreate(@Nullable Bundle savedInstanceState) {
+ super.onCreate(savedInstanceState);
+ restoreFromSavedInstance(savedInstanceState);
+ }
+
+ @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) {
+ }
+ });
+ switch (downloadError) {
+ case ERROR_INVALID_VPN_CERTIFICATE:
+ builder.setPositiveButton(R.string.update_certificate, new DialogInterface.OnClickListener() {
+ @Override
+ public void onClick(DialogInterface dialog, int which) {
+ ProviderAPICommand.execute(getContext(), DOWNLOAD_VPN_CERTIFICATE, provider);
+ }
+ });
+ break;
+ default:
+ break;
+ }
+
+ // Create the AlertDialog object and return it
+ return builder.create();
+ }
+
+
+ @Override
+ public void onSaveInstanceState(Bundle outState) {
+ super.onSaveInstanceState(outState);
+ outState.putString(KEY_REASON_TO_FAIL, reasonToFail);
+ outState.putParcelable(KEY_PROVIDER, provider);
+ }
+
+ private void restoreFromSavedInstance(Bundle savedInstanceState) {
+ if (savedInstanceState == null) {
+ return;
+ }
+ if (savedInstanceState.containsKey(KEY_PROVIDER)) {
+ this.provider = savedInstanceState.getParcelable(KEY_PROVIDER);
+ }
+ if (savedInstanceState.containsKey(KEY_REASON_TO_FAIL)) {
+ this.reasonToFail = savedInstanceState.getString(KEY_REASON_TO_FAIL);
+ }
+ }
+
+}
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..6faf8bb8 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";
@@ -102,8 +102,12 @@ public abstract class ProviderCredentialsBaseActivity extends ConfigWizardBaseAc
LocalBroadcastManager.getInstance(this).registerReceiver(providerAPIBroadcastReceiver, updateIntentFilter);
setUpListeners();
- if(savedInstanceState != null) {
- restoreState(savedInstanceState);
+ restoreState(savedInstanceState);
+
+ String userMessageString = getIntent().getStringExtra(USER_MESSAGE);
+ if (userMessageString != null) {
+ userMessage.setText(userMessageString);
+ userMessage.setVisibility(VISIBLE);
}
}
@@ -121,7 +125,11 @@ public abstract class ProviderCredentialsBaseActivity extends ConfigWizardBaseAc
}
}
- private void restoreState(Bundle savedInstance) {
+ protected void restoreState(Bundle savedInstance) {
+ super.restoreState(savedInstance);
+ if (savedInstance == null) {
+ return;
+ }
if (savedInstance.getString(USER_MESSAGE) != null) {
userMessage.setText(savedInstance.getString(USER_MESSAGE));
userMessage.setVisibility(VISIBLE);
@@ -204,7 +212,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 +389,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 +403,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..e961b0a2 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;
@@ -91,7 +91,8 @@ public abstract class ProviderListBaseActivity extends ConfigWizardBaseActivity
final protected static String PROVIDER_NOT_SET = "PROVIDER NOT SET";
final protected static String SETTING_UP_PROVIDER = "PROVIDER GETS SET";
final private static String SHOWING_PROVIDER_DETAILS = "SHOWING PROVIDER DETAILS";
- final private static String PENDING_SHOW_FAILED_DIALOG = "SHOW FAILED DIALOG";
+ final private static String PENDING_SHOW_FAILED_DIALOG = "SHOW FAILED DIALOG PENDING";
+ final private static String SHOW_FAILED_DIALOG = "SHOW FAILED DIALOG";
final private static String REASON_TO_FAIL = "REASON TO FAIL";
final protected static String SERVICES_RETRIEVED = "SERVICES RETRIEVED";
@@ -117,19 +118,24 @@ public abstract class ProviderListBaseActivity extends ConfigWizardBaseActivity
}
@Override
- protected void onSaveInstanceState(@NotNull Bundle outState) {
+ public void onSaveInstanceState(@NotNull Bundle outState) {
outState.putString(ACTIVITY_STATE, mConfigState.getAction());
- outState.putParcelable(PROVIDER_KEY, provider);
-
- DialogFragment dialogFragment = (DialogFragment) fragmentManager.findFragmentByTag(DownloadFailedDialog.TAG);
- if (dialogFragment != null) {
- outState.putString(REASON_TO_FAIL, reasonToFail);
- dialogFragment.dismiss();
- }
+ outState.putString(REASON_TO_FAIL, reasonToFail);
super.onSaveInstanceState(outState);
}
+ protected void restoreState(Bundle savedInstanceState) {
+ super.restoreState(savedInstanceState);
+ if (savedInstanceState == null) {
+ return;
+ }
+ mConfigState.setAction(savedInstanceState.getString(ACTIVITY_STATE, PROVIDER_NOT_SET));
+ if (savedInstanceState.containsKey(REASON_TO_FAIL)) {
+ reasonToFail = savedInstanceState.getString(REASON_TO_FAIL);
+ }
+ }
+
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
@@ -137,28 +143,8 @@ public abstract class ProviderListBaseActivity extends ConfigWizardBaseActivity
providerManager = ProviderManager.getInstance(getAssets(), getExternalFilesDir(null));
setUpInitialUI();
-
initProviderList();
-
- if (savedInstanceState != null)
- restoreState(savedInstanceState);
- }
-
- private void restoreState(Bundle savedInstanceState) {
-
- provider = savedInstanceState.getParcelable(Provider.KEY);
- mConfigState.setAction(savedInstanceState.getString(ACTIVITY_STATE, PROVIDER_NOT_SET));
-
- reasonToFail = savedInstanceState.getString(REASON_TO_FAIL);
- if(reasonToFail != null) {
- showDownloadFailedDialog();
- }
-
- if (SETTING_UP_PROVIDER.equals(mConfigState.getAction()) ||
- PENDING_SHOW_FAILED_DIALOG.equals(mConfigState.getAction())
- ) {
- showProgressBar();
- }
+ restoreState(savedInstanceState);
}
@Override
@@ -166,15 +152,17 @@ public abstract class ProviderListBaseActivity extends ConfigWizardBaseActivity
Log.d(TAG, "resuming with ConfigState: " + mConfigState.getAction());
super.onResume();
setUpProviderAPIResultReceiver();
- hideProgressBar();
isActivityShowing = true;
if (SETTING_UP_PROVIDER.equals(mConfigState.getAction())) {
showProgressBar();
checkProviderSetUp();
} else if (PENDING_SHOW_FAILED_DIALOG.equals(mConfigState.getAction())) {
+ showProgressBar();
showDownloadFailedDialog();
+ } else if (SHOW_FAILED_DIALOG.equals(mConfigState.getAction())) {
+ showProgressBar();
} else if (SHOWING_PROVIDER_DETAILS.equals(mConfigState.getAction())) {
- cancelAndShowAllProviders();
+ cancelSettingUpProvider();
}
}
@@ -257,7 +245,7 @@ public abstract class ProviderListBaseActivity extends ConfigWizardBaseActivity
@OnItemClick(R.id.provider_list)
void onItemSelected(int position) {
if (SETTING_UP_PROVIDER.equals(mConfigState.getAction()) ||
- PENDING_SHOW_FAILED_DIALOG.equals(mConfigState.getAction())) {
+ SHOW_FAILED_DIALOG.equals(mConfigState.getAction())) {
return;
}
@@ -276,10 +264,9 @@ public abstract class ProviderListBaseActivity extends ConfigWizardBaseActivity
@Override
public void onBackPressed() {
if (SETTING_UP_PROVIDER.equals(mConfigState.getAction()) ||
- PENDING_SHOW_FAILED_DIALOG.equals(mConfigState.getAction())) {
+ SHOW_FAILED_DIALOG.equals(mConfigState.getAction())) {
stopSettingUpProvider();
} else {
- askDashboardToQuitApp();
super.onBackPressed();
}
}
@@ -291,11 +278,13 @@ public abstract class ProviderListBaseActivity extends ConfigWizardBaseActivity
@Override
public void cancelSettingUpProvider() {
mConfigState.setAction(PROVIDER_NOT_SET);
+ provider = null;
hideProgressBar();
}
@Override
public void updateProviderDetails() {
+ mConfigState.setAction(SETTING_UP_PROVIDER);
ProviderAPICommand.execute(this, UPDATE_PROVIDER_DETAILS, provider);
}
@@ -303,17 +292,11 @@ public abstract class ProviderListBaseActivity extends ConfigWizardBaseActivity
ProviderAPICommand.execute(this, PROVIDER_SET_UP, provider, providerAPIResultReceiver);
}
- private void askDashboardToQuitApp() {
- Intent askQuit = new Intent();
- askQuit.putExtra(APP_ACTION_QUIT, APP_ACTION_QUIT);
- setResult(RESULT_CANCELED, askQuit);
- }
-
/**
* 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,20 +328,23 @@ public abstract class ProviderListBaseActivity extends ConfigWizardBaseActivity
*/
public void showDownloadFailedDialog() {
try {
- FragmentTransaction fragmentTransaction = fragmentManager.removePreviousFragment(DownloadFailedDialog.TAG);
+ mConfigState.setAction(SHOW_FAILED_DIALOG);
+ 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);
+ } catch (NullPointerException e) {
+ //reasonToFail was null
+ return;
}
- newFragment.show(fragmentTransaction, DownloadFailedDialog.TAG);
+ newFragment.show(fragmentTransaction, ProviderSetupFailedDialog.TAG);
} catch (IllegalStateException e) {
e.printStackTrace();
mConfigState.setAction(PENDING_SHOW_FAILED_DIALOG);
- mConfigState.putExtra(REASON_TO_FAIL, reasonToFail);
}
}
@@ -388,11 +374,6 @@ public abstract class ProviderListBaseActivity extends ConfigWizardBaseActivity
return true;
}
- public void cancelAndShowAllProviders() {
- mConfigState.setAction(PROVIDER_NOT_SET);
- provider = null;
- }
-
public class ProviderAPIBroadcastReceiver extends BroadcastReceiver {
@Override
public void onReceive(Context context, Intent intent) {
@@ -405,7 +386,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 +400,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..5bd9575e 100644
--- a/app/src/main/java/se/leap/bitmaskclient/DownloadFailedDialog.java
+++ b/app/src/main/java/se/leap/bitmaskclient/ProviderSetupFailedDialog.java
@@ -22,12 +22,13 @@ import android.content.Context;
import android.content.DialogInterface;
import android.os.Bundle;
import android.support.annotation.NonNull;
+import android.support.annotation.Nullable;
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,9 +37,12 @@ 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 final static String KEY_PROVIDER = "key provider";
+ private final static String KEY_REASON_TO_FAIL = "key reason to fail";
+ private final static String KEY_DOWNLOAD_ERROR = "key download error";
private String reasonToFail;
private DOWNLOAD_ERRORS downloadError = DEFAULT;
@@ -55,7 +59,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 +69,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)) {
@@ -86,6 +90,12 @@ public class DownloadFailedDialog extends DialogFragment {
}
@Override
+ public void onCreate(@Nullable Bundle savedInstanceState) {
+ super.onCreate(savedInstanceState);
+ restoreFromSavedInstance(savedInstanceState);
+ }
+
+ @Override
@NonNull
public Dialog onCreateDialog(Bundle savedInstanceState) {
AlertDialog.Builder builder = new AlertDialog.Builder(getActivity());
@@ -93,15 +103,13 @@ public class DownloadFailedDialog extends DialogFragment {
.setNegativeButton(R.string.cancel, new DialogInterface.OnClickListener() {
public void onClick(DialogInterface dialog, int id) {
interfaceWithConfigurationWizard.cancelSettingUpProvider();
- dialog.dismiss();
}
});
-switch (downloadError) {
+ switch (downloadError) {
case ERROR_CORRUPTED_PROVIDER_JSON:
builder.setPositiveButton(R.string.update_provider_details, new DialogInterface.OnClickListener() {
@Override
public void onClick(DialogInterface dialog, int which) {
- dismiss();
interfaceWithConfigurationWizard.updateProviderDetails();
}
});
@@ -111,7 +119,6 @@ switch (downloadError) {
builder.setPositiveButton(R.string.update_certificate, new DialogInterface.OnClickListener() {
@Override
public void onClick(DialogInterface dialog, int which) {
- dismiss();
interfaceWithConfigurationWizard.updateProviderDetails();
}
});
@@ -119,7 +126,6 @@ switch (downloadError) {
default:
builder.setPositiveButton(R.string.retry, new DialogInterface.OnClickListener() {
public void onClick(DialogInterface dialog, int id) {
- dismiss();
interfaceWithConfigurationWizard.retrySetUpProvider(provider);
}
});
@@ -157,4 +163,26 @@ switch (downloadError) {
dialog.dismiss();
}
+ @Override
+ public void onSaveInstanceState(Bundle outState) {
+ super.onSaveInstanceState(outState);
+ outState.putParcelable(KEY_PROVIDER, provider);
+ outState.putString(KEY_REASON_TO_FAIL, reasonToFail);
+ outState.putString(KEY_DOWNLOAD_ERROR, downloadError.toString());
+ }
+
+ private void restoreFromSavedInstance(Bundle savedInstanceState) {
+ if (savedInstanceState == null) {
+ return;
+ }
+ if (savedInstanceState.containsKey(KEY_PROVIDER)) {
+ this.provider = savedInstanceState.getParcelable(KEY_PROVIDER);
+ }
+ if (savedInstanceState.containsKey(KEY_REASON_TO_FAIL)) {
+ this.reasonToFail = savedInstanceState.getString(KEY_REASON_TO_FAIL);
+ }
+ if (savedInstanceState.containsKey(KEY_DOWNLOAD_ERROR)) {
+ this.downloadError = valueOf(savedInstanceState.getString(KEY_DOWNLOAD_ERROR));
+ }
+ }
}
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 9c7f6d1a..cbce1a81 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,7 +43,6 @@ 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_EARLY_ROUTES;
import static se.leap.bitmaskclient.Constants.EIP_RECEIVER;
import static se.leap.bitmaskclient.Constants.EIP_REQUEST;
@@ -49,6 +50,8 @@ 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
@@ -62,16 +65,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);
}
@@ -80,9 +81,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
@@ -110,11 +108,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;
}
}
@@ -125,21 +120,29 @@ public final class EIP extends IntentService {
* It also sets up early routes.
*/
private void startEIP(boolean earlyRoutes) {
+ if (!EipStatus.getInstance().isBlockingVpnEstablished() && earlyRoutes) {
+ 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) {
- 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);
}
/**
@@ -149,14 +152,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!");
}
@@ -172,7 +173,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);
@@ -182,10 +183,11 @@ public final class EIP extends IntentService {
}
private void stopEIP() {
+ // TODO 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);
}
@@ -198,22 +200,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 {
@@ -228,34 +219,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);
@@ -264,13 +246,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 1c2ae5da..d2c8b4fc 100644
--- a/app/src/main/java/se/leap/bitmaskclient/eip/EipCommand.java
+++ b/app/src/main/java/se/leap/bitmaskclient/eip/EipCommand.java
@@ -12,7 +12,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_EARLY_ROUTES;
import static se.leap.bitmaskclient.Constants.EIP_RECEIVER;
@@ -45,14 +44,6 @@ public class EipCommand {
context.startService(vpnIntent);
}
- public static void updateEipService(@NonNull Context context, ResultReceiver resultReceiver) {
- execute(context, EIP_ACTION_UPDATE, resultReceiver, null);
- }
-
- public static void updateEipService(@NonNull Context context) {
- execute(context, EIP_ACTION_UPDATE, null, null);
- }
-
public static void startVPN(@NonNull Context context, boolean earlyRoutes) {
Intent baseIntent = new Intent();
baseIntent.putExtra(EIP_EARLY_ROUTES, earlyRoutes);
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..e5ee6c49 100644
--- a/app/src/production/java/se/leap/bitmaskclient/ProviderApiManager.java
+++ b/app/src/production/java/se/leap/bitmaskclient/ProviderApiManager.java
@@ -35,9 +35,11 @@ import se.leap.bitmaskclient.eip.EIP;
import static android.text.TextUtils.isEmpty;
import static se.leap.bitmaskclient.Constants.BROADCAST_RESULT_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.ProviderAPI.ERRORS;
+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.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/production/java/se/leap/bitmaskclient/ProviderListActivity.java b/app/src/production/java/se/leap/bitmaskclient/ProviderListActivity.java
index 725ede3e..b6e67331 100644
--- a/app/src/production/java/se/leap/bitmaskclient/ProviderListActivity.java
+++ b/app/src/production/java/se/leap/bitmaskclient/ProviderListActivity.java
@@ -67,6 +67,7 @@ public class ProviderListActivity extends ProviderListBaseActivity {
@Override
public void retrySetUpProvider(@NonNull Provider provider) {
+ mConfigState.setAction(SETTING_UP_PROVIDER);
ProviderAPICommand.execute(this, SET_UP_PROVIDER, provider);
}
diff --git a/app/src/test/java/se/leap/bitmaskclient/ConfigHelperTest.java b/app/src/test/java/se/leap/bitmaskclient/ConfigHelperTest.java
index 84f38086..2c7848bc 100644
--- a/app/src/test/java/se/leap/bitmaskclient/ConfigHelperTest.java
+++ b/app/src/test/java/se/leap/bitmaskclient/ConfigHelperTest.java
@@ -10,6 +10,9 @@ import se.leap.bitmaskclient.testutils.MockSharedPreferences;
import static org.junit.Assert.assertFalse;
import static org.junit.Assert.assertTrue;
import static se.leap.bitmaskclient.Constants.PROVIDER_CONFIGURED;
+import static se.leap.bitmaskclient.Constants.PROVIDER_EIP_DEFINITION;
+import static se.leap.bitmaskclient.Constants.PROVIDER_PRIVATE_KEY;
+import static se.leap.bitmaskclient.Constants.PROVIDER_VPN_CERTIFICATE;
import static se.leap.bitmaskclient.testutils.TestSetupHelper.getInputAsString;
/**
@@ -48,6 +51,9 @@ public class ConfigHelperTest {
.putString(Provider.KEY, getInputAsString(getClass().getClassLoader().getResourceAsStream("riseup.net.json")))
.putString(Provider.MAIN_URL, "https://riseup.net")
.putString(Provider.CA_CERT, getInputAsString(getClass().getClassLoader().getResourceAsStream("riseup.net.pem")))
+ .putString(PROVIDER_EIP_DEFINITION, getInputAsString(getClass().getClassLoader().getResourceAsStream("eip-service-two-gateways.json")))
+ .putString(PROVIDER_VPN_CERTIFICATE, getInputAsString(getClass().getClassLoader().getResourceAsStream("riseup.net.vpn_cert.pem")))
+ .putString(PROVIDER_PRIVATE_KEY, getInputAsString(getClass().getClassLoader().getResourceAsStream("private_rsa_key.pem")))
.apply();
Provider provider = ConfigHelper.getSavedProviderFromSharedPreferences(mockPreferences);
assertTrue(provider.isConfigured());
diff --git a/app/src/test/resources/private_rsa_key.pem b/app/src/test/resources/private_rsa_key.pem
new file mode 100644
index 00000000..dd60e663
--- /dev/null
+++ b/app/src/test/resources/private_rsa_key.pem
@@ -0,0 +1,24 @@
+-----BEGIN RSA PRIVATE KEY-----
+MIIEvAIBADANBgkqhkiG9w0BAQEFAASCBKYwggSiAgEAAoIBAQDKIkAutGIS7YIMdOGlSmjme7Zi
+PX/Py+MVSe6rnl36gh2d5yXuzA0+8LYD/GdYboVc8clriP0Y1EQZ+KkIGjWRvWOFIyPSQzIKaz10
+93mw3FUrgSubysRaqscs3T81YCHO+7ffJK97eqOP9HKW3Q4oDlcuWPG9HgP1Vq6qhXS1AHNryp+a
+LoLmjiUyhBoDYOAyy3x2vMMMGXJ2XzWwbFwC15mgGf2L0+nCVyy0OymQay7b9x1KEn0eKSwLNlwP
+aVxanDS5lKfdyDBqUmcGmnVSZTlYcy0l1rMJswa9l0+tkyJZ4G6vtsTcvJaZGyK1uGoJsrVsajXN
+sOgfPv7dXBALAgMBAAECggEAYQjCMOmNLzLvPFWbwQKQixyWeGC3i6R/9cdRGPfke46c8yF0t0cj
+kLRzXER9xBkCUpULsWDIx3OW4bTaSDZ0wurc7Jvq5VQ2oIPMs+rdc0bCaCkRKy/SxQe4p9PqNRBa
+CogSQ7/Tsf40qLWbkMq7sgT4Wxp9qeDP26XqIZgBZ6XeVNvVetEKliFwmaaaDpnN5drTww3uxigG
+me+hwgy/ZxCWWq+Hs+B8lNttvMsVtGckEBYJE3lspeLHcKaiNYUHQtkCG5kuczZPKAF9ieeBG2F6
+sGl5UEJAUmkvRcCBgL6kqARGEqHfhTHEKo/GjEpC88Qn9ZFDP6QVcnHq2EFxuQKBgQDm6cJEkQDR
+nwzQtjeln90IqbQslvXvg7zXTnYWRQKW5B5FUk1q5h1xmNHCsA98dkTY5pIOTfk9dKiyF9wJ5s2x
+uiIHbpUZ7fFCbVcvSvaVt6JvY2nTJQaYbbJg17QrhJQdnekcI/h8zfUwrUof6hBAj2OfR+Ua3bPj
+3ZO2IlWRHwKBgQDgGBINXtdYzb32IKIPEpOqGdfrV3vBVE+D+UZ3JdZSpCnk20VdQ9B0llRurVEt
+A0LvCgmlP2eAdHoxIOlfHqV5NBCl1JXes73AJkvJU35ad4fiWEZXT94zY7TMBUgnEjgnVfXjvHXW
+BCyJ8PWkn/RMawbS0aJRml4VN83S1NFHlQKBgF5U/qTuK8x20lBtMDx8G1sPoOhaX2wSgFHg3sLo
+PE+SL3+YSMIz8bFXgdGsBReOZT/Kqb4oQnrFrqjasGxnGn7RkFdC6KxoFRhS/Lv4PtYY58Xjcfbs
++E3K+oUveY4RokSbHwD8/OVXaiQRlueEwlDtgwAt6b1Y9sVO3qoYSqZ3AoGATrvmS9BQtSDEZ1+b
+0NPkEdW2qTc5gfmPXn0MpvwiSzLmjUQFIPmcmfnffGtko/4LXFUYgni+csF51R0NIaBw3x7N4pXI
+elCIkKRj6D5vnHV2xq3hOPgUx9V2RmBss12RYTCwje0/MYyR4X1JsSeJ+/d2lEeXUjh8adQLetHP
+HekCgYBsGFUmm2G3CdXArGRk2vJimqmUdYOBezaYoQrAb8iw7trpQ+s2tIzAeeSmT6tGo7mmFdAe
+Sa96iH5R4cEMXKAJy7ik8Dj/vl5G77xcBiPOcz2K61jf5PySeXp2TsK8DEzjmRKuNKv/Fw1bZ6JF
+tvMXYGoy6YumMdJykQ1pwq00cw==
+-----END RSA PRIVATE KEY----- \ No newline at end of file
diff --git a/app/src/test/resources/riseup.net.vpn_cert.pem b/app/src/test/resources/riseup.net.vpn_cert.pem
new file mode 100644
index 00000000..e3040033
--- /dev/null
+++ b/app/src/test/resources/riseup.net.vpn_cert.pem
@@ -0,0 +1,23 @@
+-----BEGIN CERTIFICATE-----
+MIIEmzCCAoOgAwIBAgIQUX5qjwlLDM2OyZ7TduhvrDANBgkqhkiG9w0BAQsFADB1MRgwFgYDVQQK
+DA9SaXNldXAgTmV0d29ya3MxGzAZBgNVBAsMEmh0dHBzOi8vcmlzZXVwLm5ldDE8MDoGA1UEAwwz
+UmlzZXVwIE5ldHdvcmtzIFJvb3QgQ0EgKGNsaWVudCBjZXJ0aWZpY2F0ZXMgb25seSEpMB4XDTE4
+MDExODAwMDAwMFoXDTE4MDQxODAwMDAwMFowLTErMCkGA1UEAwwiVU5MSU1JVEVENjh4amVsMGZx
+MnRzbmk0MGlxanQyZTYwbjCCASIwDQYJKoZIhvcNAQEBBQADggEPADCCAQoCggEBAMoiQC60YhLt
+ggx04aVKaOZ7tmI9f8/L4xVJ7queXfqCHZ3nJe7MDT7wtgP8Z1huhVzxyWuI/RjURBn4qQgaNZG9
+Y4UjI9JDMgprPXT3ebDcVSuBK5vKxFqqxyzdPzVgIc77t98kr3t6o4/0cpbdDigOVy5Y8b0eA/VW
+rqqFdLUAc2vKn5ouguaOJTKEGgNg4DLLfHa8wwwZcnZfNbBsXALXmaAZ/YvT6cJXLLQ7KZBrLtv3
+HUoSfR4pLAs2XA9pXFqcNLmUp93IMGpSZwaadVJlOVhzLSXWswmzBr2XT62TIlngbq+2xNy8lpkb
+IrW4agmytWxqNc2w6B8+/t1cEAsCAwEAAaNvMG0wHQYDVR0OBBYEFOBLKoWXxcC2gmWZFwcgtk9b
+gH8qMAsGA1UdDwQEAwIHgDATBgNVHSUEDDAKBggrBgEFBQcDAjAJBgNVHRMEAjAAMB8GA1UdIwQY
+MBaAFBf0G9XlKgEBTWuiXTYKKQmWZYBGMA0GCSqGSIb3DQEBCwUAA4ICAQCDZBLGPg5XjIMbOOiE
+mlo45Es0ch0ojDrTQC/FOQQQjeHoyRrFF0qrDb5te/QAJQ5a+gxZkXpgBhwz/l6I4rUoWw5KNCoC
+bfb1wqpVkgHbZyBaUcxq/sxr8LkqLN95wbICXoRSQyJefMMhHn0k0UaFT6Sd5QRQG5dmWC6K296X
+/FnOwJOWESHYDYr7t6Clnk8eIQH3xc0YEVjDYB7aenc6NuYB5haCXTzoS67xC3RqOIujy2aYkQbn
+V7PB+g257WmTvhCoVXW8dks0uhQrot6MCqdlWTd1nwUGB15Lpdgtpt2PUOET9hUtUN86LBw/BZNO
+JV95z5LNr/uV72P46Lh6iWTQiCBjFPd3XVMANlFlXQaJi+zjX1xmJBg12RoCGlAtL/8YuxlZqdU6
+Vw9ceuZpQJ2nqaRwi9kAeTW57PfvaMpBQHi2OrwIwWIehzkbpbHqQzCubF5S5ENf+uaYbaR3m+nF
+Xq4UDxRgLhZfGIvHubwz5A9nzjpvJ0xw7LT/zaMKy85e9/l6rRlMIE8aA50+KYZK7s93xv6AKyYW
+qhyHJVIoYyB/vB639MudvhnN7n36mZhg3W0Zd4thQBx4rLrNK0ZD0Pfk6J+Lzd6KYgIKB0Xp0YYx
+mDwpp4uhUA1hmxisiFjf5121jdSDyP7/abZK+3udOalShfdWE41zfbThhw==
+-----END CERTIFICATE----- \ No newline at end of file