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