diff options
7 files changed, 222 insertions, 186 deletions
diff --git a/app/src/insecure/java/se/leap/bitmaskclient/ProviderApiManager.java b/app/src/insecure/java/se/leap/bitmaskclient/ProviderApiManager.java index 86250a6c..83a3044e 100644 --- a/app/src/insecure/java/se/leap/bitmaskclient/ProviderApiManager.java +++ b/app/src/insecure/java/se/leap/bitmaskclient/ProviderApiManager.java @@ -88,30 +88,30 @@ public class ProviderApiManager extends ProviderApiManagerBase {          if (task != null) {              lastDangerOn = task.containsKey(ProviderListContent.ProviderItem.DANGER_ON) && task.getBoolean(ProviderListContent.ProviderItem.DANGER_ON); +        } -            if (isEmpty(provider.getMainUrlString())) { -                setErrorResult(currentDownload, malformed_url, null); -                currentDownload.putParcelable(PROVIDER_KEY, provider); -                return currentDownload; -            } - -            getPersistedProviderUpdates(provider); -            currentDownload = validateProviderDetails(provider); +        if (isEmpty(provider.getMainUrlString()) || provider.getMainUrl().isDefault()) { +            setErrorResult(currentDownload, malformed_url, null); +            currentDownload.putParcelable(PROVIDER_KEY, provider); +            return currentDownload; +        } -            //provider details invalid -            if (currentDownload.containsKey(ERRORS)) { -                currentDownload.putParcelable(PROVIDER_KEY, provider); -                return currentDownload; -            } +        getPersistedProviderUpdates(provider); +        currentDownload = validateProviderDetails(provider); -            //no provider certificate available -            if (currentDownload.containsKey(BROADCAST_RESULT_KEY) && !currentDownload.getBoolean(BROADCAST_RESULT_KEY)) { -                resetProviderDetails(provider); -            } +        //provider details invalid +        if (currentDownload.containsKey(ERRORS)) { +            currentDownload.putParcelable(PROVIDER_KEY, provider); +            return currentDownload; +        } -            go_ahead = true; +        //no provider certificate available +        if (currentDownload.containsKey(BROADCAST_RESULT_KEY) && !currentDownload.getBoolean(BROADCAST_RESULT_KEY)) { +            resetProviderDetails(provider);          } +        go_ahead = true; +          if (!provider.hasDefinition())              currentDownload = getAndSetProviderJson(provider, lastDangerOn);          if (provider.hasDefinition() || (currentDownload.containsKey(BROADCAST_RESULT_KEY) && currentDownload.getBoolean(BROADCAST_RESULT_KEY))) { @@ -150,10 +150,6 @@ public class ProviderApiManager extends ProviderApiManagerBase {                  provider.define(providerJson); -//                preferences.edit().putString(Provider.KEY, providerJson.toString()). -//                        putBoolean(PROVIDER_ALLOW_ANONYMOUS, providerJson.getJSONObject(Provider.SERVICE).getBoolean(PROVIDER_ALLOW_ANONYMOUS)). -//                        putBoolean(PROVIDER_ALLOWED_REGISTERED, providerJson.getJSONObject(Provider.SERVICE).getBoolean(PROVIDER_ALLOWED_REGISTERED)). -//                        putString(Provider.KEY + "." + providerDomain, providerJson.toString()).commit();                  result.putBoolean(BROADCAST_RESULT_KEY, true);              } catch (JSONException e) {                  String reason_to_fail = pickErrorMessage(providerDotJsonString); @@ -251,13 +247,13 @@ public class ProviderApiManager extends ProviderApiManagerBase {      /**       * Tries to download the contents of the provided url using commercially validated CA certificate from chosen provider.       * <p/> -     * If danger_on flag is true, SSL exceptions will be managed by futher methods that will try to use some bypass methods. +     * If dangerOn flag is true, SSL exceptions will be managed by futher methods that will try to use some bypass methods.       * -     * @param string_url -     * @param danger_on  if the user completely trusts this provider +     * @param stringUrl +     * @param dangerOn  if the user completely trusts this provider       * @return       */ -    private String downloadWithCommercialCA(String string_url, boolean danger_on) { +    private String downloadWithCommercialCA(String stringUrl, boolean dangerOn) {          String responseString;          JSONObject errorJson = new JSONObject(); @@ -268,14 +264,14 @@ public class ProviderApiManager extends ProviderApiManagerBase {          List<Pair<String, String>> headerArgs = getAuthorizationHeader(); -        responseString = sendGetStringToServer(string_url, headerArgs, okHttpClient); +        responseString = sendGetStringToServer(stringUrl, headerArgs, okHttpClient);          if (responseString != null && responseString.contains(ERRORS)) {              try {                  // try to download with provider CA on certificate error                  JSONObject responseErrorJson = new JSONObject(responseString); -                if (danger_on && responseErrorJson.getString(ERRORS).equals(resources.getString(R.string.certificate_error))) { -                    responseString = downloadWithoutCA(string_url); +                if (dangerOn && responseErrorJson.getString(ERRORS).equals(resources.getString(R.string.certificate_error))) { +                    responseString = downloadWithoutCA(stringUrl);                  }              } catch (JSONException e) {                  e.printStackTrace(); @@ -352,7 +348,7 @@ public class ProviderApiManager extends ProviderApiManagerBase {       * Downloads the string that's in the url with any certificate.       */      // This method is totally insecure anyways. So no need to refactor that in order to use okHttpClient, force modern TLS etc.. DO NOT USE IN PRODUCTION! -    private String downloadWithoutCA(String url_string) { +    private String downloadWithoutCA(String urlString) {          String string = "";          try { @@ -382,7 +378,7 @@ public class ProviderApiManager extends ProviderApiManagerBase {              SSLContext context = SSLContext.getInstance("TLS");              context.init(new KeyManager[0], new TrustManager[]{new DefaultTrustManager()}, new SecureRandom()); -            URL url = new URL(url_string); +            URL url = new URL(urlString);              HttpsURLConnection urlConnection = (HttpsURLConnection) url.openConnection();              urlConnection.setSSLSocketFactory(context.getSocketFactory());              urlConnection.setHostnameVerifier(hostnameVerifier); diff --git a/app/src/main/java/se/leap/bitmaskclient/ConfigHelper.java b/app/src/main/java/se/leap/bitmaskclient/ConfigHelper.java index 9ed7a178..5a97624d 100644 --- a/app/src/main/java/se/leap/bitmaskclient/ConfigHelper.java +++ b/app/src/main/java/se/leap/bitmaskclient/ConfigHelper.java @@ -102,14 +102,14 @@ public class ConfigHelper {          return ret;      } -    public static X509Certificate parseX509CertificateFromString(String certificate_string) { +    public static X509Certificate parseX509CertificateFromString(String certificateString) {          java.security.cert.Certificate certificate = null;          CertificateFactory cf;          try {              cf = CertificateFactory.getInstance("X.509"); -            certificate_string = certificate_string.replaceFirst("-----BEGIN CERTIFICATE-----", "").replaceFirst("-----END CERTIFICATE-----", "").trim(); -            byte[] cert_bytes = Base64.decode(certificate_string); +            certificateString = certificateString.replaceFirst("-----BEGIN CERTIFICATE-----", "").replaceFirst("-----END CERTIFICATE-----", "").trim(); +            byte[] cert_bytes = Base64.decode(certificateString);              InputStream caInput = new ByteArrayInputStream(cert_bytes);              try {                  certificate = cf.generateCertificate(caInput); @@ -275,7 +275,7 @@ public class ConfigHelper {      public static Provider getSavedProviderFromSharedPreferences(@NonNull SharedPreferences preferences) {          Provider provider = new Provider();          try { -            provider.setUrl(new URL(preferences.getString(Provider.MAIN_URL, ""))); +            provider.setMainUrl(new URL(preferences.getString(Provider.MAIN_URL, "")));              provider.define(new JSONObject(preferences.getString(Provider.KEY, "")));              provider.setCaCert(preferences.getString(Provider.CA_CERT, ""));          } catch (MalformedURLException | JSONException e) { diff --git a/app/src/main/java/se/leap/bitmaskclient/Dashboard.java b/app/src/main/java/se/leap/bitmaskclient/Dashboard.java index e02ce6a9..2f129d02 100644 --- a/app/src/main/java/se/leap/bitmaskclient/Dashboard.java +++ b/app/src/main/java/se/leap/bitmaskclient/Dashboard.java @@ -144,7 +144,7 @@ public class Dashboard extends ButterKnifeActivity {      private Provider getSavedProviderFromSharedPreferences() {          Provider provider = new Provider();          try { -            provider.setUrl(new URL(preferences.getString(Provider.MAIN_URL, ""))); +            provider.setMainUrl(new URL(preferences.getString(Provider.MAIN_URL, "")));              provider.define(new JSONObject(preferences.getString(Provider.KEY, "")));              provider.setCaCert(preferences.getString(Provider.CA_CERT, ""));          } catch (MalformedURLException | JSONException e) { diff --git a/app/src/main/java/se/leap/bitmaskclient/Provider.java b/app/src/main/java/se/leap/bitmaskclient/Provider.java index ca28eacd..711d0573 100644 --- a/app/src/main/java/se/leap/bitmaskclient/Provider.java +++ b/app/src/main/java/se/leap/bitmaskclient/Provider.java @@ -79,6 +79,14 @@ public final class Provider implements Parcelable {      public Provider() { } +    public Provider(String mainUrl) { +        try { +            this.mainUrl.setUrl(new URL(mainUrl)); +        } catch (MalformedURLException e) { +            this.mainUrl = new DefaultedURL(); +        } +    } +      public Provider(URL mainUrl) {          this.mainUrl.setUrl(mainUrl);      } @@ -118,12 +126,20 @@ public final class Provider implements Parcelable {                  !caCert.isEmpty();      } -    protected void setUrl(URL url) { +    public void setMainUrl(URL url) {          mainUrl.setUrl(url);      } -    protected void define(JSONObject provider_json) { -        definition = provider_json; +    public void setMainUrl(String url) { +        try { +            mainUrl.setUrl(new URL(url)); +        } catch (MalformedURLException e) { +            e.printStackTrace(); +        } +    } + +    public void define(JSONObject providerJson) { +        definition = providerJson;          parseDefinition(definition);      } diff --git a/app/src/main/java/se/leap/bitmaskclient/ProviderApiManagerBase.java b/app/src/main/java/se/leap/bitmaskclient/ProviderApiManagerBase.java index 7e4acf44..000dd164 100644 --- a/app/src/main/java/se/leap/bitmaskclient/ProviderApiManagerBase.java +++ b/app/src/main/java/se/leap/bitmaskclient/ProviderApiManagerBase.java @@ -432,19 +432,6 @@ public abstract class ProviderApiManagerBase {          }      } -    /** -     * Sets up an intent with the progress value passed as a parameter -     * and sends it as a broadcast. -     * -     * @param progress -     */ -    void broadcastProgress(int progress) { -        Intent intentUpdate = new Intent(UPDATE_PROGRESSBAR); -        intentUpdate.addCategory(Intent.CATEGORY_DEFAULT); -        intentUpdate.putExtra(CURRENT_PROGRESS, progress); -        serviceCallback.broadcastEvent(intentUpdate); -    } -      private void broadcastEvent(int resultCode , Bundle resultData) {          Intent intentUpdate = new Intent(BROADCAST_PROVIDER_API_EVENT);          intentUpdate.addCategory(Intent.CATEGORY_DEFAULT); @@ -617,7 +604,7 @@ public abstract class ProviderApiManagerBase {      /**       * Downloads a provider.json from a given URL, adding a new provider using the given name.       * -     * @param task containing a boolean meaning if the provider is custom or not, another boolean meaning if the user completely trusts this provider, the provider name and its provider.json url. +     * @param task containing a boolean meaning if the provider is custom or not, another boolean meaning if the user completely trusts this provider       * @return a bundle with a boolean value mapped to a key named BROADCAST_RESULT_KEY, and which is true if the update was successful.       */      protected abstract Bundle setUpProvider(Provider provider, Bundle task); diff --git a/app/src/production/java/se/leap/bitmaskclient/ProviderApiManager.java b/app/src/production/java/se/leap/bitmaskclient/ProviderApiManager.java index ac58d005..a4b3e491 100644 --- a/app/src/production/java/se/leap/bitmaskclient/ProviderApiManager.java +++ b/app/src/production/java/se/leap/bitmaskclient/ProviderApiManager.java @@ -70,44 +70,35 @@ public class ProviderApiManager extends ProviderApiManagerBase {          int progress = 0;          Bundle currentDownload = new Bundle(); -        if (task != null) { -            String mainUrlString = provider.getMainUrlString(); -            if (isEmpty(mainUrlString)) { -                currentDownload.putBoolean(BROADCAST_RESULT_KEY, false); -                setErrorResult(currentDownload, malformed_url, null); -                return currentDownload; -            } - -            getPersistedProviderUpdates(provider); -            currentDownload = validateProviderDetails(provider); +        if (isEmpty(provider.getMainUrlString()) || provider.getMainUrl().isDefault()) { +            currentDownload.putBoolean(BROADCAST_RESULT_KEY, false); +            setErrorResult(currentDownload, malformed_url, null); +            return currentDownload; +        } -            //provider details invalid -            if (currentDownload.containsKey(ERRORS)) { -                return currentDownload; -            } +        getPersistedProviderUpdates(provider); +        currentDownload = validateProviderDetails(provider); -            //no provider certificate available -            if (currentDownload.containsKey(BROADCAST_RESULT_KEY) && !currentDownload.getBoolean(BROADCAST_RESULT_KEY)) { -                resetProviderDetails(provider); -            } +        //provider details invalid +        if (currentDownload.containsKey(ERRORS)) { +            return currentDownload; +        } -            go_ahead = true; +        //no provider certificate available +        if (currentDownload.containsKey(BROADCAST_RESULT_KEY) && !currentDownload.getBoolean(BROADCAST_RESULT_KEY)) { +            resetProviderDetails(provider);          } +        go_ahead = true; +          if (!provider.hasDefinition()) {              currentDownload = getAndSetProviderJson(provider);          }          if (provider.hasDefinition() || (currentDownload.containsKey(BROADCAST_RESULT_KEY) && currentDownload.getBoolean(BROADCAST_RESULT_KEY))) { -            broadcastProgress(++progress); -              if (!provider.hasCaCert())                  currentDownload = downloadCACert(provider);              if (provider.hasCaCert() || (currentDownload.containsKey(BROADCAST_RESULT_KEY) && currentDownload.getBoolean(BROADCAST_RESULT_KEY))) { -                broadcastProgress(++progress);                  currentDownload = getAndSetEipServiceJson(provider); -                if (currentDownload.containsKey(BROADCAST_RESULT_KEY) && currentDownload.getBoolean(BROADCAST_RESULT_KEY)) { -                    broadcastProgress(++progress); -                }              }          } @@ -123,9 +114,10 @@ public class ProviderApiManager extends ProviderApiManagerBase {          if (go_ahead) {              String providerDotJsonString; -            if(providerDefinition.length() == 0 || caCert.isEmpty()) -                providerDotJsonString = downloadWithCommercialCA(provider); -            else { +            if(providerDefinition.length() == 0 || caCert.isEmpty()) { +                String providerJsonUrl = provider.getMainUrlString() + "/provider.json"; +                providerDotJsonString = downloadWithCommercialCA(providerJsonUrl, provider); +            } else {                  providerDotJsonString = downloadFromApiUrlWithProviderCA("/provider.json", caCert, providerDefinition);              } @@ -207,15 +199,20 @@ public class ProviderApiManager extends ProviderApiManagerBase {      private Bundle downloadCACert(Provider provider) {          Bundle result = new Bundle(); -        String providerDomain = getDomainFromMainURL(provider.getMainUrlString()); -        String certString = downloadWithCommercialCA(provider); - -        if (validCertificate(provider, certString) && go_ahead) { -            provider.setCaCert(certString); -            preferences.edit().putString(Provider.CA_CERT + "." + providerDomain, certString).apply(); -            result.putBoolean(BROADCAST_RESULT_KEY, true); -        } else { -            setErrorResult(result, warning_corrupted_provider_cert, ERROR_CERTIFICATE_PINNING.toString()); +        try { +            String caCertUrl = provider.getDefinition().getString(Provider.CA_CERT_URI); +            String providerDomain = getDomainFromMainURL(provider.getMainUrlString()); +            String certString = downloadWithCommercialCA(caCertUrl, provider); + +            if (validCertificate(provider, certString) && go_ahead) { +                provider.setCaCert(certString); +                preferences.edit().putString(Provider.CA_CERT + "." + providerDomain, certString).apply(); +                result.putBoolean(BROADCAST_RESULT_KEY, true); +            } else { +                setErrorResult(result, warning_corrupted_provider_cert, ERROR_CERTIFICATE_PINNING.toString()); +            } +        } catch (JSONException e) { +            e.printStackTrace();          }          return result; @@ -225,8 +222,7 @@ public class ProviderApiManager extends ProviderApiManagerBase {       * Tries to download the contents of the provided url using commercially validated CA certificate from chosen provider.       *       */ -    private String downloadWithCommercialCA(Provider provider) { -        String stringUrl = provider.getMainUrlString() + "/provider.json"; +    private String downloadWithCommercialCA(String stringUrl, Provider provider) {          String responseString;          JSONObject errorJson = new JSONObject(); 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 aeb7e8c1..3ebf6201 100644 --- a/app/src/test/java/se/leap/bitmaskclient/eip/ProviderApiManagerTest.java +++ b/app/src/test/java/se/leap/bitmaskclient/eip/ProviderApiManagerTest.java @@ -24,6 +24,8 @@ import android.content.res.Resources;  import android.os.Bundle;  import android.text.TextUtils; +import org.json.JSONException; +import org.json.JSONObject;  import org.junit.Before;  import org.junit.Test;  import org.junit.runner.RunWith; @@ -34,11 +36,11 @@ import org.powermock.core.classloader.annotations.PrepareForTest;  import org.powermock.modules.junit4.PowerMockRunner;  import java.io.IOException; +import java.net.URL;  import java.security.NoSuchAlgorithmException;  import java.security.cert.CertificateEncodingException;  import se.leap.bitmaskclient.ConfigHelper; -import se.leap.bitmaskclient.Constants;  import se.leap.bitmaskclient.Provider;  import se.leap.bitmaskclient.ProviderAPI;  import se.leap.bitmaskclient.ProviderApiConnector; @@ -47,12 +49,12 @@ import se.leap.bitmaskclient.ProviderApiManagerBase;  import se.leap.bitmaskclient.testutils.MockSharedPreferences;  import static se.leap.bitmaskclient.Constants.BROADCAST_RESULT_KEY; +import static se.leap.bitmaskclient.Constants.PROVIDER_KEY;  import static se.leap.bitmaskclient.ProviderAPI.ERRORS;  import static se.leap.bitmaskclient.ProviderAPI.PROVIDER_NOK;  import static se.leap.bitmaskclient.ProviderAPI.PROVIDER_OK;  import static se.leap.bitmaskclient.testutils.BackendMockResponses.BackendMockProvider.TestBackendErrorCase.ERROR_CASE_UPDATED_CERTIFICATE;  import static se.leap.bitmaskclient.testutils.BackendMockResponses.BackendMockProvider.TestBackendErrorCase.NO_ERROR; -import static se.leap.bitmaskclient.testutils.TestSetupHelper.getInputAsString;  import static se.leap.bitmaskclient.testutils.MockHelper.mockBundle;  import static se.leap.bitmaskclient.testutils.MockHelper.mockClientGenerator;  import static se.leap.bitmaskclient.testutils.MockHelper.mockFingerprintForCertificate; @@ -61,6 +63,7 @@ import static se.leap.bitmaskclient.testutils.MockHelper.mockProviderApiConnecto  import static se.leap.bitmaskclient.testutils.MockHelper.mockResources;  import static se.leap.bitmaskclient.testutils.MockHelper.mockResultReceiver;  import static se.leap.bitmaskclient.testutils.MockHelper.mockTextUtils; +import static se.leap.bitmaskclient.testutils.TestSetupHelper.getInputAsString;  /** @@ -104,195 +107,232 @@ public class ProviderApiManagerTest {          mockResources = mockResources(getClass().getClassLoader().getResourceAsStream("error_messages.json"));      } +    private Provider getConfiguredProvider() throws IOException, JSONException { +        return getProvider(null, null, null); +    } + +    private Provider getProvider(String domain, String caCertFile, String jsonFile) { +        if (domain == null) +            domain = "https://riseup.net"; +        if (caCertFile == null) +            caCertFile = "riseup.net.pem"; +        if (jsonFile == null) +            jsonFile = "riseup.net.json"; + +        try { +            return new Provider( +                    new URL(domain), +                    getInputAsString(getClass().getClassLoader().getResourceAsStream(caCertFile)), +                    getInputAsString(getClass().getClassLoader().getResourceAsStream(jsonFile)) + +            ); +        } catch (IOException e) { +            e.printStackTrace(); +        } +        return null; +    } +      @Test -    public void test_handleIntentSetupProvider_noProviderMainURL() { +    public void test_handleIntentSetupProvider_noProviderMainURL() throws IOException, JSONException { +        Provider provider = new Provider(""); +          providerApiManager = new ProviderApiManager(mockPreferences, mockResources, mockClientGenerator(), new TestProviderApiServiceCallback());          Bundle expectedResult = mockBundle(); +          expectedResult.putBoolean(BROADCAST_RESULT_KEY, false);          expectedResult.putString(ERRORS, "{\"errors\":\"It doesn't seem to be a Bitmask provider.\"}"); +        expectedResult.putParcelable(PROVIDER_KEY, provider);          Intent providerApiCommand = mockIntent(); -        Bundle parameters = mockBundle(); -        parameters.putString(Provider.MAIN_URL, ""); -          providerApiCommand.setAction(ProviderAPI.SET_UP_PROVIDER); -        providerApiCommand.putExtra(ProviderAPI.PARAMETERS, parameters);          providerApiCommand.putExtra(ProviderAPI.RECEIVER_KEY, mockResultReceiver(PROVIDER_NOK, expectedResult)); +        providerApiCommand.putExtra(PROVIDER_KEY, provider);          providerApiManager.handleIntent(providerApiCommand);      }      @Test -    public void test_handleIntentSetupProvider_happyPath_preseededProviderAndCA() throws IOException, CertificateEncodingException, NoSuchAlgorithmException { +    public void test_handleIntentSetupProvider_happyPath_preseededProviderAndCA() throws IOException, CertificateEncodingException, NoSuchAlgorithmException, JSONException { +        Provider provider = getConfiguredProvider(); +          mockFingerprintForCertificate(" a5244308a1374709a9afce95e3ae47c1b44bc2398c0a70ccbf8b3a8a97f29494");          mockProviderApiConnector(NO_ERROR);          providerApiManager = new ProviderApiManager(mockPreferences, mockResources, mockClientGenerator(), new TestProviderApiServiceCallback());          Bundle expectedResult = mockBundle(); +          expectedResult.putBoolean(BROADCAST_RESULT_KEY, true); +        expectedResult.putParcelable(PROVIDER_KEY, provider); -        Intent provider_API_command = mockIntent(); -        Bundle parameters = mockBundle(); -        parameters.putString(Provider.MAIN_URL, "https://riseup.net"); -        parameters.putString(Provider.CA_CERT, getInputAsString(getClass().getClassLoader().getResourceAsStream("riseup.net.pem"))); -        parameters.putString(Provider.KEY, getInputAsString(getClass().getClassLoader().getResourceAsStream("riseup.net.json"))); +        Intent providerApiCommand = mockIntent(); -        provider_API_command.setAction(ProviderAPI.SET_UP_PROVIDER); -        provider_API_command.putExtra(ProviderAPI.PARAMETERS, parameters); -        provider_API_command.putExtra(ProviderAPI.RECEIVER_KEY, mockResultReceiver(PROVIDER_OK, expectedResult)); +        providerApiCommand.putExtra(PROVIDER_KEY, provider); +        providerApiCommand.setAction(ProviderAPI.SET_UP_PROVIDER); +        providerApiCommand.putExtra(ProviderAPI.RECEIVER_KEY, mockResultReceiver(PROVIDER_OK, expectedResult)); -        providerApiManager.handleIntent(provider_API_command); +        providerApiManager.handleIntent(providerApiCommand);      }      @Test -    public void test_handleIntentSetupProvider_happyPath_no_preseededProviderAndCA() throws IOException, CertificateEncodingException, NoSuchAlgorithmException { +    public void test_handleIntentSetupProvider_happyPath_no_preseededProviderAndCA() throws IOException, CertificateEncodingException, NoSuchAlgorithmException, JSONException { +        Provider provider = new Provider("https://riseup.net"); +          mockFingerprintForCertificate("a5244308a1374709a9afce95e3ae47c1b44bc2398c0a70ccbf8b3a8a97f29494");          mockProviderApiConnector(NO_ERROR);          providerApiManager = new ProviderApiManager(mockPreferences, mockResources, mockClientGenerator(), new TestProviderApiServiceCallback());          Bundle expectedResult = mockBundle(); +          expectedResult.putBoolean(BROADCAST_RESULT_KEY, true); +        expectedResult.putParcelable(PROVIDER_KEY, provider); -        Intent provider_API_command = mockIntent(); -        Bundle parameters = mockBundle(); -        parameters.putString(Provider.MAIN_URL, "https://riseup.net"); +        Intent providerApiCommand = mockIntent(); -        provider_API_command.setAction(ProviderAPI.SET_UP_PROVIDER); -        provider_API_command.putExtra(ProviderAPI.PARAMETERS, parameters); -        provider_API_command.putExtra(ProviderAPI.RECEIVER_KEY, mockResultReceiver(PROVIDER_OK, expectedResult)); +        providerApiCommand.setAction(ProviderAPI.SET_UP_PROVIDER); +        providerApiCommand.putExtra(ProviderAPI.RECEIVER_KEY, mockResultReceiver(PROVIDER_OK, expectedResult)); +        providerApiCommand.putExtra(PROVIDER_KEY, provider); -        providerApiManager.handleIntent(provider_API_command); +        providerApiManager.handleIntent(providerApiCommand);      }      @Test -    public void test_handleIntentSetupProvider_happyPath_storedProviderAndCAFromPreviousSetup() throws IOException, CertificateEncodingException, NoSuchAlgorithmException { +    public void test_handleIntentSetupProvider_happyPath_storedProviderAndCAFromPreviousSetup() throws IOException, CertificateEncodingException, NoSuchAlgorithmException, JSONException { +        Provider provider = new Provider("https://riseup.net");          mockFingerprintForCertificate("a5244308a1374709a9afce95e3ae47c1b44bc2398c0a70ccbf8b3a8a97f29494");          mockProviderApiConnector(NO_ERROR);          mockPreferences.edit().putString(Provider.KEY + ".riseup.net", getInputAsString(getClass().getClassLoader().getResourceAsStream("riseup.net.json"))).apply();          mockPreferences.edit().putString(Provider.CA_CERT + ".riseup.net", getInputAsString(getClass().getClassLoader().getResourceAsStream("riseup.net.pem"))).apply();          providerApiManager = new ProviderApiManager(mockPreferences, mockResources, mockClientGenerator(), new TestProviderApiServiceCallback()); +          Bundle expectedResult = mockBundle();          expectedResult.putBoolean(BROADCAST_RESULT_KEY, true); +        expectedResult.putParcelable(PROVIDER_KEY, provider); -        Intent provider_API_command = mockIntent(); -        Bundle parameters = mockBundle(); -        parameters.putString(Provider.MAIN_URL, "https://riseup.net"); +        Intent providerApiCommand = mockIntent(); +        providerApiCommand.setAction(ProviderAPI.SET_UP_PROVIDER); +        providerApiCommand.putExtra(ProviderAPI.RECEIVER_KEY, mockResultReceiver(PROVIDER_OK, expectedResult)); -        provider_API_command.setAction(ProviderAPI.SET_UP_PROVIDER); -        provider_API_command.putExtra(ProviderAPI.PARAMETERS, parameters); -        provider_API_command.putExtra(ProviderAPI.RECEIVER_KEY, mockResultReceiver(PROVIDER_OK, expectedResult)); +        providerApiCommand.putExtra(PROVIDER_KEY, provider); -        providerApiManager.handleIntent(provider_API_command); +        providerApiManager.handleIntent(providerApiCommand);      }      @Test -    public void test_handleIntentSetupProvider_preseededProviderAndCA_failedCAPinning() throws IOException, CertificateEncodingException, NoSuchAlgorithmException { +    public void test_handleIntentSetupProvider_preseededProviderAndCA_failedCAPinning() throws IOException, CertificateEncodingException, NoSuchAlgorithmException, JSONException { +        Provider provider = getConfiguredProvider();          mockFingerprintForCertificate(" a5244308a1374709a9afce95e3ae47c1b44bc2398c0a70ccbf8b3a8a97f29495");          mockProviderApiConnector(NO_ERROR);          providerApiManager = new ProviderApiManager(mockPreferences, mockResources, mockClientGenerator(), new TestProviderApiServiceCallback());          Bundle expectedResult = mockBundle();          expectedResult.putBoolean(BROADCAST_RESULT_KEY, false);          expectedResult.putString(ERRORS, "{\"errorId\":\"ERROR_CERTIFICATE_PINNING\",\"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 provider_API_command = mockIntent(); -        Bundle parameters = mockBundle(); -        parameters.putString(Provider.MAIN_URL, "https://riseup.net"); -        parameters.putString(Provider.CA_CERT, getInputAsString(getClass().getClassLoader().getResourceAsStream("riseup.net.pem"))); -        parameters.putString(Provider.KEY, getInputAsString(getClass().getClassLoader().getResourceAsStream("riseup.net.json"))); +        Intent providerApiCommand = mockIntent(); -        provider_API_command.setAction(ProviderAPI.SET_UP_PROVIDER); -        provider_API_command.putExtra(ProviderAPI.PARAMETERS, parameters); -        provider_API_command.putExtra(ProviderAPI.RECEIVER_KEY, mockResultReceiver(PROVIDER_NOK, expectedResult)); +        providerApiCommand.setAction(ProviderAPI.SET_UP_PROVIDER); +        providerApiCommand.putExtra(ProviderAPI.RECEIVER_KEY, mockResultReceiver(PROVIDER_NOK, expectedResult)); + +        providerApiCommand.putExtra(PROVIDER_KEY, provider); -        providerApiManager.handleIntent(provider_API_command); +        providerApiManager.handleIntent(providerApiCommand);      }      @Test -    public void test_handleIntentSetupProvider_no_preseededProviderAndCA_failedPinning() throws IOException, CertificateEncodingException, NoSuchAlgorithmException { +    public void test_handleIntentSetupProvider_no_preseededProviderAndCA_failedPinning() throws IOException, CertificateEncodingException, NoSuchAlgorithmException, JSONException { +        Provider provider = new Provider("https://riseup.net");          mockFingerprintForCertificate("a5244308a1374709a9afce95e3ae47c1b44bc2398c0a70ccbf8b3a8a97f29495");          mockProviderApiConnector(NO_ERROR);          providerApiManager = new ProviderApiManager(mockPreferences, mockResources, mockClientGenerator(), new TestProviderApiServiceCallback()); +          Bundle expectedResult = mockBundle();          expectedResult.putBoolean(BROADCAST_RESULT_KEY, false);          expectedResult.putString(ERRORS, "{\"errorId\":\"ERROR_CERTIFICATE_PINNING\",\"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 provider_API_command = mockIntent(); -        Bundle parameters = mockBundle(); -        parameters.putString(Provider.MAIN_URL, "https://riseup.net"); +        Intent providerApiCommand = mockIntent(); + +        providerApiCommand.setAction(ProviderAPI.SET_UP_PROVIDER); +        providerApiCommand.putExtra(ProviderAPI.RECEIVER_KEY, mockResultReceiver(PROVIDER_NOK, expectedResult)); -        provider_API_command.setAction(ProviderAPI.SET_UP_PROVIDER); -        provider_API_command.putExtra(ProviderAPI.PARAMETERS, parameters); -        provider_API_command.putExtra(ProviderAPI.RECEIVER_KEY, mockResultReceiver(PROVIDER_NOK, expectedResult)); +        providerApiCommand.putExtra(PROVIDER_KEY, provider); -        providerApiManager.handleIntent(provider_API_command); +        providerApiManager.handleIntent(providerApiCommand);      }      @Test      public void test_handleIntentSetupProvider_storedProviderAndCAFromPreviousSetup_failedPinning() throws IOException, CertificateEncodingException, NoSuchAlgorithmException { +        Provider provider = new Provider("https://riseup.net"); +          mockFingerprintForCertificate("a5244308a1374709a9afce95e3ae47c1b44bc2398c0a70ccbf8b3a8a97f29495");          mockProviderApiConnector(NO_ERROR);          mockPreferences.edit().putString(Provider.KEY + ".riseup.net", getInputAsString(getClass().getClassLoader().getResourceAsStream("riseup.net.json"))).apply();          mockPreferences.edit().putString(Provider.CA_CERT + ".riseup.net", getInputAsString(getClass().getClassLoader().getResourceAsStream("riseup.net.pem"))).apply();          providerApiManager = new ProviderApiManager(mockPreferences, mockResources, mockClientGenerator(), new TestProviderApiServiceCallback()); +          Bundle expectedResult = mockBundle();          expectedResult.putBoolean(BROADCAST_RESULT_KEY, false);          expectedResult.putString(ERRORS, "{\"errorId\":\"ERROR_CERTIFICATE_PINNING\",\"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 provider_API_command = mockIntent(); -        Bundle parameters = mockBundle(); -        parameters.putString(Provider.MAIN_URL, "https://riseup.net"); +        Intent providerApiCommand = mockIntent(); -        provider_API_command.setAction(ProviderAPI.SET_UP_PROVIDER); -        provider_API_command.putExtra(ProviderAPI.PARAMETERS, parameters); -        provider_API_command.putExtra(ProviderAPI.RECEIVER_KEY, mockResultReceiver(PROVIDER_NOK, expectedResult)); +        providerApiCommand.setAction(ProviderAPI.SET_UP_PROVIDER); +        providerApiCommand.putExtra(ProviderAPI.RECEIVER_KEY, mockResultReceiver(PROVIDER_NOK, expectedResult)); + +        providerApiCommand.putExtra(PROVIDER_KEY, provider); -        providerApiManager.handleIntent(provider_API_command); +        providerApiManager.handleIntent(providerApiCommand);      }      @Test -    public void test_handleIntentSetupProvider_preseededProviderAndCA_outdatedCertificate() throws IOException, CertificateEncodingException, NoSuchAlgorithmException { +    public void test_handleIntentSetupProvider_preseededProviderAndCA_outdatedCertificate() throws IOException, CertificateEncodingException, NoSuchAlgorithmException, JSONException { +        Provider provider = getProvider(null ,"outdated_cert.pem", null);          mockProviderApiConnector(NO_ERROR);          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 expired. You can either update Bitmask (recommended) or update the provider certificate using a commercial CA certificate.\"}"); +        expectedResult.putParcelable(PROVIDER_KEY, provider); -        Intent provider_API_command = mockIntent(); -        Bundle parameters = mockBundle(); -        parameters.putString(Provider.MAIN_URL, "https://riseup.net"); -        parameters.putString(Provider.CA_CERT, getInputAsString(getClass().getClassLoader().getResourceAsStream("outdated_cert.pem"))); -        parameters.putString(Provider.KEY, getInputAsString(getClass().getClassLoader().getResourceAsStream("riseup.net.json"))); +        Intent providerApiCommand = mockIntent(); + +        providerApiCommand.setAction(ProviderAPI.SET_UP_PROVIDER); +        providerApiCommand.putExtra(ProviderAPI.RECEIVER_KEY, mockResultReceiver(PROVIDER_NOK, expectedResult)); -        provider_API_command.setAction(ProviderAPI.SET_UP_PROVIDER); -        provider_API_command.putExtra(ProviderAPI.PARAMETERS, parameters); -        provider_API_command.putExtra(ProviderAPI.RECEIVER_KEY, mockResultReceiver(PROVIDER_NOK, expectedResult)); +        providerApiCommand.putExtra(PROVIDER_KEY, provider); -        providerApiManager.handleIntent(provider_API_command); +        providerApiManager.handleIntent(providerApiCommand);      }      @Test -    public void test_handleIntentSetupProvider_storedProviderAndCAFromPreviousSetup_outdatedCertificate() throws IOException, CertificateEncodingException, NoSuchAlgorithmException { +    public void test_handleIntentSetupProvider_storedProviderAndCAFromPreviousSetup_outdatedCertificate() throws IOException, CertificateEncodingException, NoSuchAlgorithmException, JSONException { +        Provider provider = new Provider("https://riseup.net");          mockProviderApiConnector(NO_ERROR);          mockPreferences.edit().putString(Provider.KEY + ".riseup.net", getInputAsString(getClass().getClassLoader().getResourceAsStream("riseup.net.json"))).apply();          mockPreferences.edit().putString(Provider.CA_CERT + ".riseup.net", getInputAsString(getClass().getClassLoader().getResourceAsStream("outdated_cert.pem"))).apply();          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 expired. You can either update Bitmask (recommended) or update the provider certificate using a commercial CA certificate.\"}"); +        expectedResult.putParcelable(PROVIDER_KEY, provider); -        Intent provider_API_command = mockIntent(); -        Bundle parameters = mockBundle(); -        parameters.putString(Provider.MAIN_URL, "https://riseup.net"); +        Intent providerApiCommand = mockIntent(); -        provider_API_command.setAction(ProviderAPI.SET_UP_PROVIDER); -        provider_API_command.putExtra(ProviderAPI.PARAMETERS, parameters); -        provider_API_command.putExtra(ProviderAPI.RECEIVER_KEY, mockResultReceiver(PROVIDER_NOK, expectedResult)); +        providerApiCommand.setAction(ProviderAPI.SET_UP_PROVIDER); +        providerApiCommand.putExtra(ProviderAPI.RECEIVER_KEY, mockResultReceiver(PROVIDER_NOK, expectedResult)); + +        providerApiCommand.putExtra(PROVIDER_KEY, provider); -        providerApiManager.handleIntent(provider_API_command); +        providerApiManager.handleIntent(providerApiCommand);      }      @Test -    public void test_handleIntentSetupProvider_preseededProviderAndCA_ValidCertificateButUpdatedCertificateOnServerSide() throws IOException, CertificateEncodingException, NoSuchAlgorithmException { +    public void test_handleIntentSetupProvider_preseededProviderAndCA_ValidCertificateButUpdatedCertificateOnServerSide() throws IOException, CertificateEncodingException, NoSuchAlgorithmException, JSONException { +        Provider provider = getConfiguredProvider(); +          mockFingerprintForCertificate(" a5244308a1374709a9afce95e3ae47c1b44bc2398c0a70ccbf8b3a8a97f29494");          mockProviderApiConnector(ERROR_CASE_UPDATED_CERTIFICATE); @@ -300,39 +340,40 @@ 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.putParcelable(PROVIDER_KEY, provider); -        Intent provider_API_command = mockIntent(); -        Bundle parameters = mockBundle(); -        parameters.putString(Provider.MAIN_URL, "https://riseup.net"); -        parameters.putString(Provider.CA_CERT, getInputAsString(getClass().getClassLoader().getResourceAsStream("riseup.net.pem"))); -        parameters.putString(Provider.KEY, getInputAsString(getClass().getClassLoader().getResourceAsStream("riseup.net.json"))); +        Intent providerApiCommand = mockIntent(); + +        providerApiCommand.setAction(ProviderAPI.SET_UP_PROVIDER); +        providerApiCommand.putExtra(ProviderAPI.RECEIVER_KEY, mockResultReceiver(PROVIDER_NOK, expectedResult)); -        provider_API_command.setAction(ProviderAPI.SET_UP_PROVIDER); -        provider_API_command.putExtra(ProviderAPI.PARAMETERS, parameters); -        provider_API_command.putExtra(ProviderAPI.RECEIVER_KEY, mockResultReceiver(PROVIDER_NOK, expectedResult)); +        providerApiCommand.putExtra(PROVIDER_KEY, provider); -        providerApiManager.handleIntent(provider_API_command); +        providerApiManager.handleIntent(providerApiCommand);      }      @Test -    public void test_handleIntentSetupProvider_storedProviderAndCAFromPreviousSetup_ValidCertificateButUpdatedCertificateOnServerSide() throws IOException, CertificateEncodingException, NoSuchAlgorithmException { +    public void test_handleIntentSetupProvider_storedProviderAndCAFromPreviousSetup_ValidCertificateButUpdatedCertificateOnServerSide() throws IOException, CertificateEncodingException, NoSuchAlgorithmException, JSONException { +        Provider provider = new Provider("https://riseup.net"); +          mockFingerprintForCertificate("a5244308a1374709a9afce95e3ae47c1b44bc2398c0a70ccbf8b3a8a97f29494");          mockProviderApiConnector(ERROR_CASE_UPDATED_CERTIFICATE);          mockPreferences.edit().putString(Provider.KEY + ".riseup.net", getInputAsString(getClass().getClassLoader().getResourceAsStream("riseup.net.json"))).apply();          mockPreferences.edit().putString(Provider.CA_CERT + ".riseup.net", getInputAsString(getClass().getClassLoader().getResourceAsStream("riseup.net.pem"))).apply();          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.putParcelable(PROVIDER_KEY, provider); + +        Intent providerApiCommand = mockIntent(); -        Intent provider_API_command = mockIntent(); -        Bundle parameters = mockBundle(); -        parameters.putString(Provider.MAIN_URL, "https://riseup.net"); +        providerApiCommand.setAction(ProviderAPI.SET_UP_PROVIDER); +        providerApiCommand.putExtra(ProviderAPI.RECEIVER_KEY, mockResultReceiver(PROVIDER_NOK, expectedResult)); -        provider_API_command.setAction(ProviderAPI.SET_UP_PROVIDER); -        provider_API_command.putExtra(ProviderAPI.PARAMETERS, parameters); -        provider_API_command.putExtra(ProviderAPI.RECEIVER_KEY, mockResultReceiver(PROVIDER_NOK, expectedResult)); +        providerApiCommand.putExtra(PROVIDER_KEY, provider); -        providerApiManager.handleIntent(provider_API_command); +        providerApiManager.handleIntent(providerApiCommand);      }  }  | 
