From 268a7f205fa09edc145aace8bed30f75270a801f Mon Sep 17 00:00:00 2001 From: Fup Duck Date: Tue, 6 Feb 2018 17:02:00 +0100 Subject: 8827 - handle switch provider correctly * ProviderAPI no longer stores values in SharedPreferences * use EipCommand to start / stop EIP * update NavigationDrawer after changing provider * use Broadcasts for ProviderAPI * parse more properties from definition into Provider * ProviderApi no longer uses static variables * no more static Context in ProviderApiCommand --- app/build.gradle | 2 +- .../leap/bitmaskclient/test/VpnTestController.java | 1 + .../se/leap/bitmaskclient/ProviderApiManager.java | 160 +++++----- .../leap/bitmaskclient/ProviderDetailActivity.java | 5 +- .../leap/bitmaskclient/ProviderListActivity.java | 39 +-- .../AbstractProviderDetailActivity.java | 118 +++---- .../java/se/leap/bitmaskclient/ConfigHelper.java | 44 ++- .../bitmaskclient/ConfigWizardBaseActivity.java | 9 +- .../main/java/se/leap/bitmaskclient/Constants.java | 25 ++ .../main/java/se/leap/bitmaskclient/Dashboard.java | 133 ++------ .../leap/bitmaskclient/DownloadFailedDialog.java | 6 +- .../java/se/leap/bitmaskclient/EipFragment.java | 216 ++++++++----- .../java/se/leap/bitmaskclient/MainActivity.java | 67 ++-- .../leap/bitmaskclient/OkHttpClientGenerator.java | 7 +- .../main/java/se/leap/bitmaskclient/Provider.java | 109 ++++--- .../java/se/leap/bitmaskclient/ProviderAPI.java | 16 +- .../se/leap/bitmaskclient/ProviderAPICommand.java | 68 +++-- .../leap/bitmaskclient/ProviderApiManagerBase.java | 339 ++++++++++----------- .../ProviderCredentialsBaseActivity.java | 58 ++-- .../bitmaskclient/ProviderListBaseActivity.java | 99 +++--- .../java/se/leap/bitmaskclient/StartActivity.java | 1 - .../drawer/NavigationDrawerFragment.java | 43 ++- .../main/java/se/leap/bitmaskclient/eip/EIP.java | 33 +- .../bitmaskclient/userstatus/SessionDialog.java | 179 ----------- .../userstatus/UserStatusFragment.java | 31 +- .../se/leap/bitmaskclient/ProviderApiManager.java | 162 ++++------ .../leap/bitmaskclient/ProviderListActivity.java | 36 +-- .../bitmaskclient/eip/ProviderApiManagerTest.java | 35 +-- .../bitmaskclient/testutils/TestSetupHelper.java | 2 +- 29 files changed, 879 insertions(+), 1164 deletions(-) delete mode 100644 app/src/main/java/se/leap/bitmaskclient/userstatus/SessionDialog.java diff --git a/app/build.gradle b/app/build.gradle index 2e6604f2..865df811 100644 --- a/app/build.gradle +++ b/app/build.gradle @@ -5,7 +5,7 @@ apply plugin: 'com.android.application' android { compileSdkVersion 26 - buildToolsVersion '26.0.0' + buildToolsVersion '26.0.2' defaultConfig { applicationId "se.leap.bitmaskclient" diff --git a/app/src/androidTest/java/se/leap/bitmaskclient/test/VpnTestController.java b/app/src/androidTest/java/se/leap/bitmaskclient/test/VpnTestController.java index f6760161..4c6a6370 100644 --- a/app/src/androidTest/java/se/leap/bitmaskclient/test/VpnTestController.java +++ b/app/src/androidTest/java/se/leap/bitmaskclient/test/VpnTestController.java @@ -6,6 +6,7 @@ import android.widget.Button; import com.robotium.solo.Condition; import com.robotium.solo.Solo; +import de.blinkt.openvpn.activities.DisconnectVPN; import mbanje.kurt.fabbutton.ProgressRingView; import se.leap.bitmaskclient.Dashboard; import se.leap.bitmaskclient.R; diff --git a/app/src/insecure/java/se/leap/bitmaskclient/ProviderApiManager.java b/app/src/insecure/java/se/leap/bitmaskclient/ProviderApiManager.java index 8ca971e0..86250a6c 100644 --- a/app/src/insecure/java/se/leap/bitmaskclient/ProviderApiManager.java +++ b/app/src/insecure/java/se/leap/bitmaskclient/ProviderApiManager.java @@ -48,13 +48,11 @@ import okhttp3.OkHttpClient; import se.leap.bitmaskclient.eip.EIP; import static android.text.TextUtils.isEmpty; -import static se.leap.bitmaskclient.Constants.PROVIDER_ALLOWED_REGISTERED; -import static se.leap.bitmaskclient.Constants.PROVIDER_ALLOW_ANONYMOUS; +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.ProviderAPI.ERRORS; -import static se.leap.bitmaskclient.ProviderAPI.RESULT_KEY; import static se.leap.bitmaskclient.R.string.certificate_error; import static se.leap.bitmaskclient.R.string.malformed_url; import static se.leap.bitmaskclient.R.string.warning_corrupted_provider_cert; @@ -64,6 +62,9 @@ import static se.leap.bitmaskclient.R.string.warning_corrupted_provider_cert; */ public class ProviderApiManager extends ProviderApiManagerBase { + + private static final String TAG = ProviderApiManagerBase.class.getName(); + protected static boolean lastDangerOn = true; @@ -79,83 +80,58 @@ public class ProviderApiManager extends 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. - * @return a bundle with a boolean value mapped to a key named RESULT_KEY, and which is true if the update was successful. + * @return a bundle with a boolean value mapped to a key named BROADCAST_RESULT_KEY, and which is true if the update was successful. */ @Override - protected Bundle setUpProvider(Bundle task) { - int progress = 0; + protected Bundle setUpProvider(Provider provider, Bundle task) { Bundle currentDownload = new Bundle(); if (task != null) { lastDangerOn = task.containsKey(ProviderListContent.ProviderItem.DANGER_ON) && task.getBoolean(ProviderListContent.ProviderItem.DANGER_ON); - lastProviderMainUrl = task.containsKey(Provider.MAIN_URL) ? - task.getString(Provider.MAIN_URL) : - ""; - if (isEmpty(lastProviderMainUrl)) { + if (isEmpty(provider.getMainUrlString())) { setErrorResult(currentDownload, malformed_url, null); + currentDownload.putParcelable(PROVIDER_KEY, provider); return currentDownload; } - providerCaCertFingerprint = task.containsKey(Provider.CA_CERT_FINGERPRINT) ? - task.getString(Provider.CA_CERT_FINGERPRINT) : - ""; - providerCaCert = task.containsKey(Provider.CA_CERT) ? - task.getString(Provider.CA_CERT) : - ""; - - try { - providerDefinition = task.containsKey(Provider.KEY) ? - new JSONObject(task.getString(Provider.KEY)) : - new JSONObject(); - } catch (JSONException e) { - e.printStackTrace(); - providerDefinition = new JSONObject(); - } - providerApiUrl = getApiUrlWithVersion(providerDefinition); - - checkPersistedProviderUpdates(); - currentDownload = validateProviderDetails(); + getPersistedProviderUpdates(provider); + currentDownload = validateProviderDetails(provider); //provider details invalid if (currentDownload.containsKey(ERRORS)) { + currentDownload.putParcelable(PROVIDER_KEY, provider); return currentDownload; } //no provider certificate available - if (currentDownload.containsKey(RESULT_KEY) && !currentDownload.getBoolean(RESULT_KEY)) { - resetProviderDetails(); + if (currentDownload.containsKey(BROADCAST_RESULT_KEY) && !currentDownload.getBoolean(BROADCAST_RESULT_KEY)) { + resetProviderDetails(provider); } - EIP_SERVICE_JSON_DOWNLOADED = false; go_ahead = true; } - if (!PROVIDER_JSON_DOWNLOADED) - currentDownload = getAndSetProviderJson(lastProviderMainUrl, lastDangerOn, providerCaCert, providerDefinition); - if (PROVIDER_JSON_DOWNLOADED || (currentDownload.containsKey(RESULT_KEY) && currentDownload.getBoolean(RESULT_KEY))) { - broadcastProgress(progress++); - PROVIDER_JSON_DOWNLOADED = true; - - if (!CA_CERT_DOWNLOADED) - currentDownload = downloadCACert(lastDangerOn); - if (CA_CERT_DOWNLOADED || (currentDownload.containsKey(RESULT_KEY) && currentDownload.getBoolean(RESULT_KEY))) { - broadcastProgress(progress++); - CA_CERT_DOWNLOADED = true; - currentDownload = getAndSetEipServiceJson(); - if (currentDownload.containsKey(RESULT_KEY) && currentDownload.getBoolean(RESULT_KEY)) { - broadcastProgress(progress++); - EIP_SERVICE_JSON_DOWNLOADED = true; - } + if (!provider.hasDefinition()) + currentDownload = getAndSetProviderJson(provider, lastDangerOn); + if (provider.hasDefinition() || (currentDownload.containsKey(BROADCAST_RESULT_KEY) && currentDownload.getBoolean(BROADCAST_RESULT_KEY))) { + if (!provider.hasCaCert()) + currentDownload = downloadCACert(provider, lastDangerOn); + if (provider.hasCaCert() || (currentDownload.containsKey(BROADCAST_RESULT_KEY) && currentDownload.getBoolean(BROADCAST_RESULT_KEY))) { + currentDownload = getAndSetEipServiceJson(provider); } } - + currentDownload.putParcelable(PROVIDER_KEY, provider); return currentDownload; } - private Bundle getAndSetProviderJson(String providerMainUrl, boolean dangerOn, String caCert, JSONObject providerDefinition) { + private Bundle getAndSetProviderJson(Provider provider, boolean dangerOn) { Bundle result = new Bundle(); + JSONObject providerDefinition = provider.getDefinition(); + String caCert = provider.getCaCert(); + String providerMainUrl = provider.getMainUrlString(); + if (go_ahead) { String providerDotJsonString; if(providerDefinition.length() == 0 || caCert.isEmpty()) @@ -165,56 +141,57 @@ public class ProviderApiManager extends ProviderApiManagerBase { if (!isValidJson(providerDotJsonString)) { result.putString(ERRORS, resources.getString(malformed_url)); - result.putBoolean(RESULT_KEY, false); + result.putBoolean(BROADCAST_RESULT_KEY, false); return result; } try { JSONObject providerJson = new JSONObject(providerDotJsonString); - String providerDomain = getDomainFromMainURL(lastProviderMainUrl); - providerApiUrl = getApiUrlWithVersion(providerJson); - //String name = providerJson.getString(Provider.NAME); - //TODO setProviderName(name); - - 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(RESULT_KEY, true); + + 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); result.putString(ERRORS, reason_to_fail); - result.putBoolean(RESULT_KEY, false); + result.putBoolean(BROADCAST_RESULT_KEY, false); } } + result.putParcelable(PROVIDER_KEY, provider); return result; } /** * Downloads the eip-service.json from a given URL, and saves eip service capabilities including the offered gateways - * @return a bundle with a boolean value mapped to a key named RESULT_KEY, and which is true if the download was successful. + * @return a bundle with a boolean value mapped to a key named BROADCAST_RESULT_KEY, and which is true if the download was successful. */ @Override - protected Bundle getAndSetEipServiceJson() { + protected Bundle getAndSetEipServiceJson(Provider provider) { Bundle result = new Bundle(); - String eip_service_json_string = ""; + String eipServiceJsonString = ""; if (go_ahead) { try { - JSONObject provider_json = new JSONObject(preferences.getString(Provider.KEY, "")); - String eip_service_url = provider_json.getString(Provider.API_URL) + "/" + provider_json.getString(Provider.API_VERSION) + "/" + EIP.SERVICE_API_PATH; - eip_service_json_string = downloadWithProviderCA(eip_service_url, lastDangerOn); - JSONObject eip_service_json = new JSONObject(eip_service_json_string); - eip_service_json.getInt(Provider.API_RETURN_SERIAL); + JSONObject providerDefinition = provider.getDefinition(); + String eipServiceUrl = providerDefinition.getString(Provider.API_URL) + "/" + providerDefinition.getString(Provider.API_VERSION) + "/" + EIP.SERVICE_API_PATH; + eipServiceJsonString = downloadWithProviderCA(provider.getCaCert(), eipServiceUrl, lastDangerOn); + JSONObject eipServiceJson = new JSONObject(eipServiceJsonString); + eipServiceJson.getInt(Provider.API_RETURN_SERIAL); - preferences.edit().putString(PROVIDER_KEY, eip_service_json.toString()).commit(); + //preferences.edit().putString(PROVIDER_KEY, eipServiceJson.toString()).commit(); + provider.setEipServiceJson(eipServiceJson); - result.putBoolean(RESULT_KEY, true); + result.putBoolean(BROADCAST_RESULT_KEY, true); } catch (NullPointerException | JSONException e) { - String reason_to_fail = pickErrorMessage(eip_service_json_string); - result.putString(ERRORS, reason_to_fail); - result.putBoolean(RESULT_KEY, false); + String reasonToFail = pickErrorMessage(eipServiceJsonString); + result.putString(ERRORS, reasonToFail); + result.putBoolean(BROADCAST_RESULT_KEY, false); } } + result.putParcelable(PROVIDER_KEY, provider); return result; } @@ -224,19 +201,19 @@ 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() { + protected boolean updateVpnCertificate(Provider provider) { try { - JSONObject provider_json = new JSONObject(preferences.getString(Provider.KEY, "")); + JSONObject providerDefinition = provider.getDefinition(); - String provider_main_url = provider_json.getString(Provider.API_URL); - URL new_cert_string_url = new URL(provider_main_url + "/" + provider_json.getString(Provider.API_VERSION) + "/" + PROVIDER_VPN_CERTIFICATE); + String providerMainUrl = providerDefinition.getString(Provider.API_URL); + URL newCertStringUrl = new URL(providerMainUrl + "/" + providerDefinition.getString(Provider.API_VERSION) + "/" + PROVIDER_VPN_CERTIFICATE); - String cert_string = downloadWithProviderCA(new_cert_string_url.toString(), lastDangerOn); + String certString = downloadWithProviderCA(provider.getCaCert(), newCertStringUrl.toString(), lastDangerOn); - if (cert_string == null || cert_string.isEmpty() || ConfigHelper.checkErroneousDownload(cert_string)) + if (certString == null || certString.isEmpty() || ConfigHelper.checkErroneousDownload(certString)) return false; else - return loadCertificate(cert_string); + return loadCertificate(certString); } catch (IOException e) { // TODO Auto-generated catch block e.printStackTrace(); @@ -249,19 +226,18 @@ public class ProviderApiManager extends ProviderApiManagerBase { } - private Bundle downloadCACert(boolean dangerOn) { + private Bundle downloadCACert(Provider provider, boolean dangerOn) { Bundle result = new Bundle(); try { - JSONObject providerJson = new JSONObject(preferences.getString(Provider.KEY, "")); - String caCertUrl = providerJson.getString(Provider.CA_CERT_URI); - String providerDomain = providerJson.getString(Provider.DOMAIN); + String caCertUrl = provider.getDefinition().getString(Provider.CA_CERT_URI); + String providerDomain = provider.getDomain(); String certString = downloadWithCommercialCA(caCertUrl, dangerOn); - if (validCertificate(certString) && go_ahead) { - preferences.edit().putString(Provider.CA_CERT, certString).commit(); - preferences.edit().putString(Provider.CA_CERT + "." + providerDomain, certString).commit(); - result.putBoolean(RESULT_KEY, true); + 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()); } @@ -344,11 +320,11 @@ public class ProviderApiManager extends ProviderApiManagerBase { * @param dangerOn true to download CA certificate in case it has not been downloaded. * @return an empty string if it fails, the url content if not. */ - private String downloadWithProviderCA(String urlString, boolean dangerOn) { + private String downloadWithProviderCA(String caCert, String urlString, boolean dangerOn) { JSONObject initError = new JSONObject(); String responseString; - OkHttpClient okHttpClient = clientGenerator.initSelfSignedCAHttpClient(initError); + OkHttpClient okHttpClient = clientGenerator.initSelfSignedCAHttpClient(caCert, initError); if (okHttpClient == null) { return initError.toString(); } diff --git a/app/src/insecure/java/se/leap/bitmaskclient/ProviderDetailActivity.java b/app/src/insecure/java/se/leap/bitmaskclient/ProviderDetailActivity.java index 6977753f..cf9ee5f5 100644 --- a/app/src/insecure/java/se/leap/bitmaskclient/ProviderDetailActivity.java +++ b/app/src/insecure/java/se/leap/bitmaskclient/ProviderDetailActivity.java @@ -2,15 +2,12 @@ package se.leap.bitmaskclient; import android.content.SharedPreferences; -import static se.leap.bitmaskclient.Constants.PROVIDER_ALLOW_ANONYMOUS; -import static se.leap.bitmaskclient.Constants.PROVIDER_KEY; - public class ProviderDetailActivity extends AbstractProviderDetailActivity { @Override public void onBackPressed() { SharedPreferences.Editor editor = preferences.edit(); - editor.remove(Provider.KEY).remove(ProviderListContent.ProviderItem.DANGER_ON).remove(PROVIDER_ALLOW_ANONYMOUS).remove(PROVIDER_KEY).apply(); + editor.remove(ProviderListContent.ProviderItem.DANGER_ON).apply(); super.onBackPressed(); } diff --git a/app/src/insecure/java/se/leap/bitmaskclient/ProviderListActivity.java b/app/src/insecure/java/se/leap/bitmaskclient/ProviderListActivity.java index 034c9752..2fdb5b02 100644 --- a/app/src/insecure/java/se/leap/bitmaskclient/ProviderListActivity.java +++ b/app/src/insecure/java/se/leap/bitmaskclient/ProviderListActivity.java @@ -16,7 +16,6 @@ */ package se.leap.bitmaskclient; -import android.content.Intent; import android.os.Bundle; import android.support.v4.app.DialogFragment; import android.support.v4.app.FragmentTransaction; @@ -26,6 +25,8 @@ import java.net.URL; import se.leap.bitmaskclient.ProviderListContent.ProviderItem; +import static se.leap.bitmaskclient.ProviderAPI.SET_UP_PROVIDER; + /** * Activity that builds and shows the list of known available providers. *

@@ -51,12 +52,12 @@ public class ProviderListActivity extends ProviderListBaseActivity { /** * Open the new provider dialog with data */ - public void addAndSelectNewProvider(String main_url, boolean danger_on) { + public void addAndSelectNewProvider(String mainUrl, boolean danger_on) { FragmentTransaction fragment_transaction = fragmentManager.removePreviousFragment(NewProviderDialog.TAG); DialogFragment newFragment = new NewProviderDialog(); Bundle data = new Bundle(); - data.putString(Provider.MAIN_URL, main_url); + data.putString(Provider.MAIN_URL, mainUrl); data.putBoolean(ProviderItem.DANGER_ON, danger_on); newFragment.setArguments(data); newFragment.show(fragment_transaction, NewProviderDialog.TAG); @@ -87,46 +88,26 @@ public class ProviderListActivity extends ProviderListBaseActivity { */ public void setUpProvider(boolean danger_on) { mConfigState.setAction(SETTING_UP_PROVIDER); - Intent providerAPICommand = new Intent(this, ProviderAPI.class); + Bundle parameters = new Bundle(); - parameters.putString(Provider.MAIN_URL, provider.getMainUrl().toString()); parameters.putBoolean(ProviderItem.DANGER_ON, danger_on); - if (provider.hasCertificatePin()){ - parameters.putString(Provider.CA_CERT_FINGERPRINT, provider.certificatePin()); - } - if (provider.hasCaCert()) { - parameters.putString(Provider.CA_CERT, provider.getCaCert()); - } - if (provider.hasDefinition()) { - parameters.putString(Provider.KEY, provider.getDefinition().toString()); - } - - providerAPICommand.setAction(ProviderAPI.SET_UP_PROVIDER); - providerAPICommand.putExtra(ProviderAPI.PARAMETERS, parameters); - startService(providerAPICommand); + ProviderAPICommand.execute(this, SET_UP_PROVIDER, parameters, provider); } /** * Retrys setup of last used provider, allows bypassing ca certificate validation. */ @Override - public void retrySetUpProvider() { + public void retrySetUpProvider(Provider provider) { cancelSettingUpProvider(); - if (!ProviderAPI.caCertDownloaded()) { - addAndSelectNewProvider(ProviderAPI.lastProviderMainUrl(), ProviderAPI.lastDangerOn()); + if (!provider.hasCaCert()) { + addAndSelectNewProvider(provider.getMainUrlString(), ProviderAPI.lastDangerOn()); } else { showProgressBar(); adapter.hideAllBut(adapter.indexOf(provider)); - Intent providerAPICommand = new Intent(this, ProviderAPI.class); - - providerAPICommand.setAction(ProviderAPI.SET_UP_PROVIDER); - Bundle parameters = new Bundle(); - parameters.putString(Provider.MAIN_URL, provider.getMainUrl().toString()); - providerAPICommand.putExtra(ProviderAPI.PARAMETERS, parameters); - - startService(providerAPICommand); + ProviderAPICommand.execute(this, SET_UP_PROVIDER, provider); } } diff --git a/app/src/main/java/se/leap/bitmaskclient/AbstractProviderDetailActivity.java b/app/src/main/java/se/leap/bitmaskclient/AbstractProviderDetailActivity.java index fbb27b58..cdb314aa 100644 --- a/app/src/main/java/se/leap/bitmaskclient/AbstractProviderDetailActivity.java +++ b/app/src/main/java/se/leap/bitmaskclient/AbstractProviderDetailActivity.java @@ -1,7 +1,6 @@ package se.leap.bitmaskclient; import android.content.Intent; -import android.content.SharedPreferences; import android.os.Bundle; import android.support.annotation.Nullable; import android.support.v7.widget.AppCompatTextView; @@ -12,14 +11,10 @@ import android.widget.ArrayAdapter; import android.widget.ListView; import android.widget.TextView; -import org.json.JSONException; -import org.json.JSONObject; - import java.util.ArrayList; import butterknife.InjectView; -import static se.leap.bitmaskclient.Constants.PROVIDER_ALLOW_ANONYMOUS; import static se.leap.bitmaskclient.Constants.PROVIDER_KEY; import static se.leap.bitmaskclient.Constants.REQUEST_CODE_CONFIGURE_LEAP; @@ -36,56 +31,54 @@ public abstract class AbstractProviderDetailActivity extends ConfigWizardBaseAct @Override protected void onCreate(@Nullable Bundle savedInstanceState) { super.onCreate(savedInstanceState); + + provider = getIntent().getParcelableExtra(PROVIDER_KEY); setContentView(R.layout.a_provider_detail); - try { - JSONObject providerJson = new JSONObject(preferences.getString(Provider.KEY, "")); - setProviderHeaderText(ConfigHelper.getProviderName(preferences)); - description.setText(ConfigHelper.getDescription(preferences)); - // Show only the options allowed by the provider - ArrayList optionsList = new ArrayList<>(); - if (registrationAllowed(providerJson)) { - optionsList.add(getString(R.string.login_to_profile)); - optionsList.add(getString(R.string.create_profile)); - } - if (anonAllowed(providerJson)) { - optionsList.add(getString(R.string.use_anonymously_button)); - } + setProviderHeaderText(provider.getName()); + description.setText(provider.getDescription()); - options.setAdapter(new ArrayAdapter<>( - this, - android.R.layout.simple_list_item_activated_1, - android.R.id.text1, - optionsList.toArray(new String[optionsList.size()]) - )); - options.setOnItemClickListener(new AdapterView.OnItemClickListener() { - @Override - public void onItemClick(AdapterView parent, View view, int position, long id) { - String text = ((TextView) view).getText().toString(); - Intent intent; - if (text.equals(getString(R.string.login_to_profile))) { - Log.d(TAG, "login selected"); - intent = new Intent(getApplicationContext(), LoginActivity.class); - } else if (text.equals(getString(R.string.create_profile))) { - Log.d(TAG, "signup selected"); - intent = new Intent(getApplicationContext(), SignupActivity.class); - } else { - Log.d(TAG, "use anonymously selected"); - intent = new Intent(); - intent.putExtra(Provider.KEY, provider); - setResult(RESULT_OK, intent); - finish(); - return; - } - intent.putExtra(PROVIDER_KEY, provider); - intent.setFlags(Intent.FLAG_ACTIVITY_NO_ANIMATION); - startActivityForResult(intent, REQUEST_CODE_CONFIGURE_LEAP); - } - }); - } catch (JSONException e) { - // TODO show error and return + // Show only the options allowed by the provider + ArrayList optionsList = new ArrayList<>(); + if (provider.allowsRegistered()) { + optionsList.add(getString(R.string.login_to_profile)); + optionsList.add(getString(R.string.create_profile)); } + if (provider.allowsAnonymous()) { + optionsList.add(getString(R.string.use_anonymously_button)); + } + + options.setAdapter(new ArrayAdapter<>( + this, + android.R.layout.simple_list_item_activated_1, + android.R.id.text1, + optionsList.toArray(new String[optionsList.size()]) + )); + options.setOnItemClickListener(new AdapterView.OnItemClickListener() { + @Override + public void onItemClick(AdapterView parent, View view, int position, long id) { + String text = ((TextView) view).getText().toString(); + Intent intent; + if (text.equals(getString(R.string.login_to_profile))) { + Log.d(TAG, "login selected"); + intent = new Intent(getApplicationContext(), LoginActivity.class); + } else if (text.equals(getString(R.string.create_profile))) { + Log.d(TAG, "signup selected"); + intent = new Intent(getApplicationContext(), SignupActivity.class); + } else { + Log.d(TAG, "use anonymously selected"); + intent = new Intent(); + intent.putExtra(Provider.KEY, provider); + setResult(RESULT_OK, intent); + finish(); + return; + } + intent.putExtra(PROVIDER_KEY, provider); + intent.setFlags(Intent.FLAG_ACTIVITY_NO_ANIMATION); + startActivityForResult(intent, REQUEST_CODE_CONFIGURE_LEAP); + } + }); } @Override @@ -104,29 +97,4 @@ public abstract class AbstractProviderDetailActivity extends ConfigWizardBaseAct } } - private boolean anonAllowed(JSONObject providerJson) { - try { - JSONObject serviceDescription = providerJson.getJSONObject(Provider.SERVICE); - return serviceDescription.has(PROVIDER_ALLOW_ANONYMOUS) && serviceDescription.getBoolean(PROVIDER_ALLOW_ANONYMOUS); - } catch (JSONException e) { - return false; - } - } - - private boolean registrationAllowed(JSONObject providerJson) { - try { - JSONObject serviceDescription = providerJson.getJSONObject(Provider.SERVICE); - return serviceDescription.has(Provider.ALLOW_REGISTRATION) && serviceDescription.getBoolean(Provider.ALLOW_REGISTRATION); - } catch (JSONException e) { - return false; - } - } - - @Override - public void onBackPressed() { - SharedPreferences.Editor editor = preferences.edit(); - editor.remove(Provider.KEY).remove(PROVIDER_ALLOW_ANONYMOUS).remove(PROVIDER_KEY).apply(); - super.onBackPressed(); - } - } diff --git a/app/src/main/java/se/leap/bitmaskclient/ConfigHelper.java b/app/src/main/java/se/leap/bitmaskclient/ConfigHelper.java index 741a6f56..9ed7a178 100644 --- a/app/src/main/java/se/leap/bitmaskclient/ConfigHelper.java +++ b/app/src/main/java/se/leap/bitmaskclient/ConfigHelper.java @@ -21,7 +21,6 @@ import android.support.annotation.NonNull; import android.support.annotation.Nullable; import android.util.Log; -import org.jetbrains.annotations.NotNull; import org.json.JSONException; import org.json.JSONObject; import org.spongycastle.util.encoders.Base64; @@ -47,10 +46,15 @@ import java.security.cert.X509Certificate; import java.security.interfaces.RSAPrivateKey; import java.security.spec.InvalidKeySpecException; import java.security.spec.PKCS8EncodedKeySpec; +import java.util.ArrayList; +import java.util.List; import java.util.Locale; +import java.util.Map; import static android.R.attr.name; +import static se.leap.bitmaskclient.Constants.PREFERENCES_APP_VERSION; import static se.leap.bitmaskclient.Constants.PROVIDER_CONFIGURED; +import static se.leap.bitmaskclient.Constants.PROVIDER_KEY; /** * Stores constants, and implements auxiliary methods used across all Bitmask Android classes. @@ -273,7 +277,7 @@ public class ConfigHelper { try { provider.setUrl(new URL(preferences.getString(Provider.MAIN_URL, ""))); provider.define(new JSONObject(preferences.getString(Provider.KEY, ""))); - provider.setCACert(preferences.getString(Provider.CA_CERT, "")); + provider.setCaCert(preferences.getString(Provider.CA_CERT, "")); } catch (MalformedURLException | JSONException e) { e.printStackTrace(); } @@ -349,6 +353,40 @@ public class ConfigHelper { putString(Provider.MAIN_URL, provider.getMainUrlString()). putString(Provider.KEY, provider.getDefinitionString()). putString(Provider.CA_CERT, provider.getCaCert()). - apply(); + putString(PROVIDER_KEY, provider.getEipServiceJsonString()). + commit(); } + + + public static void clearDataOfLastProvider(SharedPreferences preferences) { + clearDataOfLastProvider(preferences, false); + } + + public static void clearDataOfLastProvider(SharedPreferences preferences, boolean commit) { + Map allEntries = preferences.getAll(); + List lastProvidersKeys = new ArrayList<>(); + for (Map.Entry entry : allEntries.entrySet()) { + //sort out all preferences that don't belong to the last provider + if (entry.getKey().startsWith(Provider.KEY + ".") || + entry.getKey().startsWith(Provider.CA_CERT + ".") || + entry.getKey().startsWith(Provider.CA_CERT_FINGERPRINT + "." )|| + entry.getKey().equals(PREFERENCES_APP_VERSION) + ) { + continue; + } + lastProvidersKeys.add(entry.getKey()); + } + + SharedPreferences.Editor preferenceEditor = preferences.edit(); + for (String key : lastProvidersKeys) { + preferenceEditor.remove(key); + } + if (commit) { + preferenceEditor.commit(); + } else { + preferenceEditor.apply(); + } + } + + } diff --git a/app/src/main/java/se/leap/bitmaskclient/ConfigWizardBaseActivity.java b/app/src/main/java/se/leap/bitmaskclient/ConfigWizardBaseActivity.java index 79a78fe1..7fcb5816 100644 --- a/app/src/main/java/se/leap/bitmaskclient/ConfigWizardBaseActivity.java +++ b/app/src/main/java/se/leap/bitmaskclient/ConfigWizardBaseActivity.java @@ -56,19 +56,22 @@ public abstract class ConfigWizardBaseActivity extends ButterKnifeActivity { @Override public void setContentView(View view) { super.setContentView(view); - setProviderHeaderText(ConfigHelper.getProviderName(preferences)); + if (provider != null) + setProviderHeaderText(provider.getName()); } @Override public void setContentView(int layoutResID) { super.setContentView(layoutResID); - setProviderHeaderText(ConfigHelper.getProviderName(preferences)); + if (provider != null) + setProviderHeaderText(provider.getName()); } @Override public void setContentView(View view, ViewGroup.LayoutParams params) { super.setContentView(view, params); - setProviderHeaderText(ConfigHelper.getProviderName(preferences)); + if (provider != null) + setProviderHeaderText(provider.getName()); } protected void setProviderHeaderLogo(@DrawableRes int providerHeaderLogo) { diff --git a/app/src/main/java/se/leap/bitmaskclient/Constants.java b/app/src/main/java/se/leap/bitmaskclient/Constants.java index 7ee3adab..23c5e805 100644 --- a/app/src/main/java/se/leap/bitmaskclient/Constants.java +++ b/app/src/main/java/se/leap/bitmaskclient/Constants.java @@ -17,6 +17,7 @@ public interface Constants { String REQUEST_CODE_KEY = "request_code"; int REQUEST_CODE_CONFIGURE_LEAP = 0; int REQUEST_CODE_SWITCH_PROVIDER = 1; + int REQUEST_CODE_LOG_IN = 2; ////////////////////////////////////////////// @@ -50,10 +51,34 @@ public interface Constants { ////////////////////////////////////////////// // PROVIDER CONSTANTS ///////////////////////////////////////////// + String PROVIDER_ALLOW_ANONYMOUS = "allow_anonymous"; String PROVIDER_ALLOWED_REGISTERED = "allow_registration"; String PROVIDER_VPN_CERTIFICATE = "cert"; String PROVIDER_PRIVATE_KEY = "Constants.PROVIDER_PRIVATE_KEY"; String PROVIDER_KEY = "Constants.PROVIDER_KEY"; String PROVIDER_CONFIGURED = "Constants.PROVIDER_CONFIGURED"; + + ////////////////////////////////////////////// + // CREDENTIAL CONSTANTS + ///////////////////////////////////////////// + + String CREDENTIALS_USERNAME = "username"; + String CREDENTIALS_PASSWORD = "password"; + + enum CREDENTIAL_ERRORS { + USERNAME_MISSING, + PASSWORD_INVALID_LENGTH, + RISEUP_WARNING + } + + ////////////////////////////////////////////// + // BROADCAST CONSTANTS + ///////////////////////////////////////////// + + String BROADCAST_EIP_EVENT = "BROADCAST.EIP_EVENT"; + String BROADCAST_PROVIDER_API_EVENT = "BROADCAST.PROVIDER_API_EVENT"; + String BROADCAST_RESULT_CODE = "BROADCAST.RESULT_CODE"; + String BROADCAST_RESULT_KEY = "BROADCAST.RESULT_KEY"; + } diff --git a/app/src/main/java/se/leap/bitmaskclient/Dashboard.java b/app/src/main/java/se/leap/bitmaskclient/Dashboard.java index a4db5f84..e02ce6a9 100644 --- a/app/src/main/java/se/leap/bitmaskclient/Dashboard.java +++ b/app/src/main/java/se/leap/bitmaskclient/Dashboard.java @@ -23,8 +23,6 @@ import android.content.Intent; import android.content.SharedPreferences; import android.content.pm.PackageManager.NameNotFoundException; import android.os.Bundle; -import android.os.Handler; -import android.support.v4.app.FragmentTransaction; import android.util.Log; import android.view.Menu; import android.view.MenuItem; @@ -36,14 +34,11 @@ import org.json.JSONObject; import java.net.MalformedURLException; import java.net.URL; -import java.util.ArrayList; -import java.util.List; -import java.util.Map; import butterknife.InjectView; import de.blinkt.openvpn.core.VpnStatus; +import se.leap.bitmaskclient.eip.EipCommand; import se.leap.bitmaskclient.fragments.AboutFragment; -import se.leap.bitmaskclient.userstatus.SessionDialog; import se.leap.bitmaskclient.userstatus.User; import se.leap.bitmaskclient.userstatus.UserStatusFragment; @@ -51,8 +46,6 @@ import static se.leap.bitmaskclient.Constants.APP_ACTION_CONFIGURE_ALWAYS_ON_PRO import static se.leap.bitmaskclient.Constants.APP_ACTION_QUIT; import static se.leap.bitmaskclient.Constants.EIP_IS_ALWAYS_ON; import static se.leap.bitmaskclient.Constants.EIP_RESTART_ON_BOOT; -import static se.leap.bitmaskclient.Constants.PREFERENCES_APP_VERSION; -import static se.leap.bitmaskclient.Constants.PROVIDER_ALLOW_ANONYMOUS; import static se.leap.bitmaskclient.Constants.PROVIDER_CONFIGURED; import static se.leap.bitmaskclient.Constants.PROVIDER_KEY; import static se.leap.bitmaskclient.Constants.REQUEST_CODE_CONFIGURE_LEAP; @@ -91,20 +84,15 @@ public class Dashboard extends ButterKnifeActivity { private UserStatusFragment user_status_fragment; private static Provider provider = new Provider(); - public static ProviderAPIResultReceiver providerAPI_result_receiver; - private static boolean switching_provider; private boolean handledVersion; - public static DashboardReceiver dashboardReceiver; @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); - dashboardReceiver = new DashboardReceiver(this); preferences = getSharedPreferences(SHARED_PREFERENCES, MODE_PRIVATE); fragment_manager = new FragmentManagerEnhanced(getSupportFragmentManager()); - providerAPI_result_receiver = new ProviderAPIResultReceiver(new Handler(), dashboardReceiver); if (!handledVersion) { handleVersion(); @@ -112,7 +100,6 @@ public class Dashboard extends ButterKnifeActivity { } // initialize app necessities - ProviderAPICommand.initialize(this); VpnStatus.initLogCache(getApplicationContext().getCacheDir()); User.init(getString(R.string.default_username)); @@ -159,7 +146,7 @@ public class Dashboard extends ButterKnifeActivity { try { provider.setUrl(new URL(preferences.getString(Provider.MAIN_URL, ""))); provider.define(new JSONObject(preferences.getString(Provider.KEY, ""))); - provider.setCACert(preferences.getString(Provider.CA_CERT, "")); + provider.setCaCert(preferences.getString(Provider.CA_CERT, "")); } catch (MalformedURLException | JSONException e) { e.printStackTrace(); } @@ -175,7 +162,7 @@ public class Dashboard extends ButterKnifeActivity { case 91: // 0.6.0 without Bug #5999 case 101: // 0.8.0 if (!preferences.getString(PROVIDER_KEY, "").isEmpty()) - eip_fragment.updateEipService(); + EipCommand.updateEipService(this); break; } } catch (NameNotFoundException e) { @@ -211,9 +198,9 @@ public class Dashboard extends ButterKnifeActivity { buildDashboard(false); invalidateOptionsMenuOnUiThread(); - if (data.hasExtra(SessionDialog.TAG)) { - sessionDialog(Bundle.EMPTY); - } + //if (data.hasExtra(SessionDialog.TAG)) { + // sessionDialog(Bundle.EMPTY); + //} } else if (resultCode == RESULT_CANCELED && data != null && data.hasExtra(APP_ACTION_QUIT)) { finish(); @@ -304,14 +291,14 @@ public class Dashboard extends ButterKnifeActivity { user_status_fragment.setArguments(bundle); fragment_manager.replace(R.id.user_status_fragment, user_status_fragment, UserStatusFragment.TAG); - if (provider.hasEIP()) { - fragment_manager.removePreviousFragment(EipFragment.TAG); - eip_fragment = prepareEipFragment(hideAndTurnOnEipOnBoot); - fragment_manager.replace(R.id.servicesCollection, eip_fragment, EipFragment.TAG); - if (hideAndTurnOnEipOnBoot) { - onBackPressed(); - } - } +// if (provider.hasEIP()) { +// fragment_manager.removePreviousFragment(EipFragment.TAG); +// eip_fragment = prepareEipFragment(hideAndTurnOnEipOnBoot); +// fragment_manager.replace(R.id.servicesCollection, eip_fragment, EipFragment.TAG); +// if (hideAndTurnOnEipOnBoot) { +// onBackPressed(); +// } +// } } /** @@ -367,12 +354,11 @@ public class Dashboard extends ButterKnifeActivity { showLog(); return true; case R.id.switch_provider: - switching_provider = true; if (User.loggedIn()) user_status_fragment.logOut(); else switchProvider(); return true; case R.id.signup_button: - sessionDialog(Bundle.EMPTY); + //sessionDialog(Bundle.EMPTY); return true; default: return super.onOptionsItemSelected(item); @@ -389,99 +375,14 @@ public class Dashboard extends ButterKnifeActivity { log_window_wrapper.showLog(); } - - // TODO MOVE TO VPNManager(?) - public static void downloadVpnCertificate() { - boolean is_authenticated = User.loggedIn(); - boolean allowed_anon = preferences.getBoolean(PROVIDER_ALLOW_ANONYMOUS, false); - if (allowed_anon || is_authenticated) - ProviderAPICommand.execute(Bundle.EMPTY, ProviderAPI.DOWNLOAD_CERTIFICATE, providerAPI_result_receiver); - else - sessionDialog(Bundle.EMPTY); - } - - // TODO how can we replace this - public static void sessionDialog(Bundle resultData) { - try { - FragmentTransaction transaction = fragment_manager.removePreviousFragment(SessionDialog.TAG); - SessionDialog.getInstance(provider, resultData).show(transaction, SessionDialog.TAG); - } catch (IllegalStateException e) { - e.printStackTrace(); - } - } - private void switchProvider() { - if (provider.hasEIP()) eip_fragment.stopEipIfPossible(); - - clearDataOfLastProvider(); - - switching_provider = false; - startActivityForResult(new Intent(this, ProviderListActivity.class), REQUEST_CODE_SWITCH_PROVIDER); - } +// if (provider.hasEIP()) eip_fragment.stopEipIfPossible(); - private void clearDataOfLastProvider() { - Map allEntries = preferences.getAll(); - List lastProvidersKeys = new ArrayList<>(); - for (Map.Entry entry : allEntries.entrySet()) { - //sort out all preferences that don't belong to the last provider - if (entry.getKey().startsWith(Provider.KEY + ".") || - entry.getKey().startsWith(Provider.CA_CERT + ".") || - entry.getKey().startsWith(Provider.CA_CERT_FINGERPRINT + "." )|| - entry.getKey().equals(PREFERENCES_APP_VERSION) - ) { - continue; - } - lastProvidersKeys.add(entry.getKey()); - } + ConfigHelper.clearDataOfLastProvider(preferences); - SharedPreferences.Editor preferenceEditor = preferences.edit(); - for (String key : lastProvidersKeys) { - preferenceEditor.remove(key); - } - preferenceEditor.apply(); - - switching_provider = false; startActivityForResult(new Intent(this, ProviderListActivity.class), REQUEST_CODE_SWITCH_PROVIDER); } - private static class DashboardReceiver implements ProviderAPIResultReceiver.Receiver{ - - private Dashboard dashboard; - - DashboardReceiver(Dashboard dashboard) { - this.dashboard = dashboard; - } - - @Override - public void onReceiveResult(int resultCode, Bundle resultData) { - if (resultCode == ProviderAPI.SUCCESSFUL_SIGNUP) { - String username = resultData.getString(SessionDialog.USERNAME); - String password = resultData.getString(SessionDialog.PASSWORD); - dashboard.user_status_fragment.logIn(username, password); - } else if (resultCode == ProviderAPI.FAILED_SIGNUP) { - MainActivity.sessionDialog(resultData); - } else if (resultCode == ProviderAPI.SUCCESSFUL_LOGIN) { - Dashboard.downloadVpnCertificate(); - } else if (resultCode == ProviderAPI.FAILED_LOGIN) { - MainActivity.sessionDialog(resultData); - } else if (resultCode == ProviderAPI.SUCCESSFUL_LOGOUT) { - if (switching_provider) dashboard.switchProvider(); - } else if (resultCode == ProviderAPI.LOGOUT_FAILED) { - dashboard.setResult(RESULT_CANCELED); - } else if (resultCode == ProviderAPI.CORRECTLY_DOWNLOADED_CERTIFICATE) { - dashboard.eip_fragment.updateEipService(); - dashboard.setResult(RESULT_OK); - } else if (resultCode == ProviderAPI.INCORRECTLY_DOWNLOADED_CERTIFICATE) { - dashboard.setResult(RESULT_CANCELED); - } else if (resultCode == ProviderAPI.CORRECTLY_DOWNLOADED_EIP_SERVICE) { - dashboard.eip_fragment.updateEipService(); - dashboard.setResult(RESULT_OK); - } else if (resultCode == ProviderAPI.INCORRECTLY_DOWNLOADED_EIP_SERVICE) { - dashboard.setResult(RESULT_CANCELED); - } - } - } - public static Provider getProvider() { return provider; } @Override diff --git a/app/src/main/java/se/leap/bitmaskclient/DownloadFailedDialog.java b/app/src/main/java/se/leap/bitmaskclient/DownloadFailedDialog.java index 527ce1a7..9d413a8d 100644 --- a/app/src/main/java/se/leap/bitmaskclient/DownloadFailedDialog.java +++ b/app/src/main/java/se/leap/bitmaskclient/DownloadFailedDialog.java @@ -89,7 +89,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 @@ -113,7 +113,7 @@ public class DownloadFailedDialog extends DialogFragment { builder.setPositiveButton(R.string.retry, new DialogInterface.OnClickListener() { public void onClick(DialogInterface dialog, int id) { dismiss(); - interface_with_ConfigurationWizard.retrySetUpProvider(); + interface_with_ConfigurationWizard.retrySetUpProvider(null); } }); break; @@ -124,7 +124,7 @@ public class DownloadFailedDialog extends DialogFragment { } public interface DownloadFailedDialogInterface { - void retrySetUpProvider(); + void retrySetUpProvider(Provider provider); void cancelSettingUpProvider(); diff --git a/app/src/main/java/se/leap/bitmaskclient/EipFragment.java b/app/src/main/java/se/leap/bitmaskclient/EipFragment.java index 414b1f2a..9726ebf2 100644 --- a/app/src/main/java/se/leap/bitmaskclient/EipFragment.java +++ b/app/src/main/java/se/leap/bitmaskclient/EipFragment.java @@ -18,10 +18,12 @@ 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; @@ -50,26 +52,33 @@ 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.EIP; +import se.leap.bitmaskclient.eip.EipCommand; import se.leap.bitmaskclient.eip.EipStatus; import se.leap.bitmaskclient.eip.VoidVpnService; +import se.leap.bitmaskclient.userstatus.User; +import static android.app.Activity.RESULT_OK; 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_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_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_ALLOWED_REGISTERED; import static se.leap.bitmaskclient.Constants.PROVIDER_ALLOW_ANONYMOUS; +import static se.leap.bitmaskclient.Constants.PROVIDER_KEY; import static se.leap.bitmaskclient.Constants.PROVIDER_VPN_CERTIFICATE; +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.DOWNLOAD_CERTIFICATE; public class EipFragment extends Fragment implements Observer { @@ -79,6 +88,7 @@ public class EipFragment extends Fragment implements Observer { public static final String START_EIP_ON_BOOT = "start on boot"; private SharedPreferences preferences; + private Provider provider; @InjectView(R.id.background) AppCompatImageView background; @@ -102,6 +112,9 @@ public class EipFragment extends Fragment implements Observer { private EipStatus eipStatus; private boolean wantsToConnect; + private ProviderAPIResultReceiver providerAPIResultReceiver; + private EIPBroadcastReceiver eipBroadcastReceiver; + private IOpenVPNServiceInternal mService; private ServiceConnection openVpnConnection = new ServiceConnection() { @@ -123,7 +136,18 @@ public class EipFragment extends Fragment implements Observer { public void onAttach(Context context) { super.onAttach(context); - downloadEIPServiceConfig(); + Bundle arguments = getArguments(); + if (arguments != null) { + provider = getArguments().getParcelable(PROVIDER_KEY); + if (provider == null) { + getActivity().startActivityForResult(new Intent(getActivity(), ProviderListActivity.class), REQUEST_CODE_SWITCH_PROVIDER); + } else { + Log.d(TAG, provider.getName() + " configured as provider"); + } + } else { + Log.e(TAG, "no provider given - starting ProviderListActivity"); + getActivity().startActivityForResult(new Intent(getActivity(), ProviderListActivity.class), REQUEST_CODE_SWITCH_PROVIDER); + } } @Override @@ -132,6 +156,8 @@ public class EipFragment extends Fragment implements Observer { eipStatus = EipStatus.getInstance(); eipStatus.addObserver(this); eipReceiver = new EIPReceiver(new Handler()); + eipBroadcastReceiver = new EIPBroadcastReceiver(); + providerAPIResultReceiver = new ProviderAPIResultReceiver(new Handler(), new EipFragmentReceiver()); preferences = getActivity().getSharedPreferences(SHARED_PREFERENCES, Context.MODE_PRIVATE); } @@ -152,6 +178,7 @@ 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(); } @@ -160,6 +187,8 @@ public class EipFragment extends Fragment implements Observer { public void onPause() { super.onPause(); getActivity().unbindService(openVpnConnection); + getActivity().unregisterReceiver(eipBroadcastReceiver); + Log.d(TAG, "broadcast unregistered"); } @Override @@ -199,8 +228,8 @@ public class EipFragment extends Fragment implements Observer { startEipFromScratch(); else if (canLogInToStartEIP()) { wantsToConnect = true; - Bundle bundle = new Bundle(); - MainActivity.sessionDialog(bundle); + Intent intent = new Intent(getContext(), LoginActivity.class); + getActivity().startActivityForResult(intent, REQUEST_CODE_LOG_IN); } else { Log.d(TAG, "WHAT IS GOING ON HERE?!"); // TODO: implement a fallback: check if vpncertificate was not downloaded properly or give @@ -250,7 +279,7 @@ public class EipFragment extends Fragment implements Observer { public void startEipFromScratch() { wantsToConnect = false; saveStatus(true); - eipCommand(EIP_ACTION_START); + EipCommand.startVPN(getContext(), eipReceiver); } private void stop() { @@ -282,13 +311,7 @@ public class EipFragment extends Fragment implements Observer { protected void stopEipIfPossible() { //FIXME: no need to start a service here! - eipCommand(EIP_ACTION_STOP); - } - - private void downloadEIPServiceConfig() { - ProviderAPIResultReceiver provider_api_receiver = new ProviderAPIResultReceiver(new Handler(), Dashboard.dashboardReceiver); - if(eipReceiver != null) - ProviderAPICommand.execute(Bundle.EMPTY, ProviderAPI.DOWNLOAD_EIP_SERVICE, provider_api_receiver); + EipCommand.stopVPN(getContext(), eipReceiver); } protected void askToStopEIP() { @@ -310,25 +333,6 @@ public class EipFragment extends Fragment implements Observer { .show(); } - protected void updateEipService() { - eipCommand(EIP_ACTION_UPDATE); - } - - /** - * Send a command to EIP - * - * @param action A valid String constant from EIP class representing an Intent - * filter for the EIP class - */ - private void eipCommand(String action) { - Activity activity = getActivity(); - // TODO validate "action"...how do we get the list of intent-filters for a class via Android API? - Intent vpn_intent = new Intent(activity.getApplicationContext(), EIP.class); - vpn_intent.setAction(action); - vpn_intent.putExtra(EIP_RECEIVER, eipReceiver); - activity.startService(vpn_intent); - } - @Override public void update(Observable observable, Object data) { if (observable instanceof EipStatus) { @@ -401,58 +405,81 @@ public class EipFragment extends Fragment implements Observer { protected void onReceiveResult(int resultCode, Bundle resultData) { super.onReceiveResult(resultCode, resultData); - String request = resultData.getString(EIP_REQUEST); + handleEIPEvent(resultCode, resultData); + } + } + + private class EIPBroadcastReceiver extends BroadcastReceiver { + @Override + public void onReceive(Context context, Intent intent) { + Log.d(TAG, "received Broadcast"); - if (request == null) { + String action = intent.getAction(); + if (action == null || !action.equalsIgnoreCase(BROADCAST_EIP_EVENT)) { return; } - switch (request) { - case EIP_ACTION_START: - switch (resultCode) { - case Activity.RESULT_OK: - break; - case Activity.RESULT_CANCELED: - break; - } - break; - case EIP_ACTION_STOP: - switch (resultCode) { - case Activity.RESULT_OK: - stop(); - break; - case Activity.RESULT_CANCELED: - break; - } - break; - case EIP_NOTIFICATION: - switch (resultCode) { - case Activity.RESULT_OK: - break; - case Activity.RESULT_CANCELED: - break; - } - break; - case EIP_ACTION_CHECK_CERT_VALIDITY: - switch (resultCode) { - case Activity.RESULT_OK: - break; - case Activity.RESULT_CANCELED: - Dashboard.downloadVpnCertificate(); - break; - } - break; - case EIP_ACTION_UPDATE: - switch (resultCode) { - case Activity.RESULT_OK: - if (wantsToConnect) - startEipFromScratch(); - break; - case Activity.RESULT_CANCELED: - handleNewState(); - break; - } - } + int resultCode = intent.getIntExtra(BROADCAST_RESULT_KEY, -1); + Bundle resultData = intent.getParcelableExtra(BROADCAST_RESULT_KEY); + Log.d(TAG, "Broadcast resultCode: " + Integer.toString(resultCode)); + + handleEIPEvent(resultCode, resultData); + + } + } + + 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; + } } } @@ -474,4 +501,33 @@ public class EipFragment extends Fragment implements Observer { background.setImageAlpha(255); } + private class EipFragmentReceiver implements ProviderAPIResultReceiver.Receiver{ + + @Override + public void onReceiveResult(int resultCode, Bundle resultData) { + if (resultCode == ProviderAPI.CORRECTLY_DOWNLOADED_EIP_SERVICE) { + provider = resultData.getParcelable(PROVIDER_KEY); + EipCommand.updateEipService(getContext(), eipReceiver); + } else if (resultCode == ProviderAPI.INCORRECTLY_DOWNLOADED_EIP_SERVICE) { + //dashboard.setResult(RESULT_CANCELED); + // TODO CATCH ME IF YOU CAN + } + } + } + + private void downloadVpnCertificate() { + boolean is_authenticated = User.loggedIn(); + boolean allowed_anon = preferences.getBoolean(PROVIDER_ALLOW_ANONYMOUS, false); + if (allowed_anon || is_authenticated) { + ProviderAPICommand.execute(getContext(), DOWNLOAD_CERTIFICATE, provider, providerAPIResultReceiver); + } + } + + private void setUpBroadcastReceiver() { + IntentFilter updateIntentFilter = new IntentFilter(BROADCAST_EIP_EVENT); + updateIntentFilter.addCategory(Intent.CATEGORY_DEFAULT); + getActivity().registerReceiver(eipBroadcastReceiver, updateIntentFilter); + Log.d(TAG, "broadcast registered"); + } + } diff --git a/app/src/main/java/se/leap/bitmaskclient/MainActivity.java b/app/src/main/java/se/leap/bitmaskclient/MainActivity.java index 7629f0b7..d3865559 100644 --- a/app/src/main/java/se/leap/bitmaskclient/MainActivity.java +++ b/app/src/main/java/se/leap/bitmaskclient/MainActivity.java @@ -5,15 +5,17 @@ import android.content.Intent; import android.content.SharedPreferences; import android.os.Bundle; import android.support.v4.app.Fragment; -import android.support.v4.app.FragmentTransaction; import android.support.v4.widget.DrawerLayout; import android.support.v7.app.AppCompatActivity; import android.support.v7.widget.Toolbar; import se.leap.bitmaskclient.drawer.NavigationDrawerFragment; -import se.leap.bitmaskclient.userstatus.SessionDialog; +import se.leap.bitmaskclient.eip.EipCommand; +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; @@ -23,6 +25,8 @@ public class MainActivity extends AppCompatActivity { private static FragmentManagerEnhanced fragmentManager; private SharedPreferences preferences; + private NavigationDrawerFragment navigationDrawerFragment; + public final static String ACTION_SHOW_VPN_FRAGMENT = "action_show_vpn_fragment"; /** @@ -33,13 +37,14 @@ public class MainActivity extends AppCompatActivity { protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_main); - setSupportActionBar((Toolbar) findViewById(R.id.toolbar)); - NavigationDrawerFragment navigationDrawerFragment = (NavigationDrawerFragment) + 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( @@ -49,15 +54,6 @@ public class MainActivity extends AppCompatActivity { handleIntentAction(getIntent()); } - public static void sessionDialog(Bundle resultData) { - try { - FragmentTransaction transaction = fragmentManager.removePreviousFragment(SessionDialog.TAG); - SessionDialog.getInstance(provider, resultData).show(transaction, SessionDialog.TAG); - } catch (IllegalStateException e) { - e.printStackTrace(); - } - } - @Override protected void onNewIntent(Intent intent) { super.onNewIntent(intent); @@ -70,35 +66,54 @@ public class MainActivity extends AppCompatActivity { return; } - Fragment fragment = null; - switch (intent.getAction()) { case ACTION_SHOW_VPN_FRAGMENT: - fragment = new EipFragment(); + showEipFragment(); break; default: break; } - - if (fragment != null) { - fragmentManager.beginTransaction() - .replace(R.id.container, fragment) - .commit(); - } } @Override protected void onActivityResult(int requestCode, int resultCode, Intent data) { + super.onActivityResult(requestCode, resultCode, data); if (data == null) { return; } - if (requestCode == REQUEST_CODE_CONFIGURE_LEAP) { - if (resultCode == RESULT_OK && data.hasExtra(Provider.KEY)) { - Provider provider = data.getParcelableExtra(Provider.KEY); - ConfigHelper.storeProviderInPreferences(preferences, provider); + if (resultCode == RESULT_OK && data.hasExtra(Provider.KEY)) { + provider = data.getParcelableExtra(Provider.KEY); + + if (provider == null) { + return; } + + ConfigHelper.storeProviderInPreferences(preferences, provider); + navigationDrawerFragment.refresh(); + switch (requestCode) { + case REQUEST_CODE_SWITCH_PROVIDER: + EipCommand.stopVPN(this); + break; + case REQUEST_CODE_CONFIGURE_LEAP: + break; + case REQUEST_CODE_LOG_IN: + EipCommand.startVPN(this); + break; + + } + showEipFragment(); } } + private void showEipFragment() { + Fragment fragment = new EipFragment(); + Bundle arguments = new Bundle(); + arguments.putParcelable(PROVIDER_KEY, provider); + fragment.setArguments(arguments); + fragmentManager.beginTransaction() + .replace(R.id.container, fragment) + .commit(); + } + } diff --git a/app/src/main/java/se/leap/bitmaskclient/OkHttpClientGenerator.java b/app/src/main/java/se/leap/bitmaskclient/OkHttpClientGenerator.java index 1bf679f8..6d554b0e 100644 --- a/app/src/main/java/se/leap/bitmaskclient/OkHttpClientGenerator.java +++ b/app/src/main/java/se/leap/bitmaskclient/OkHttpClientGenerator.java @@ -59,11 +59,9 @@ import static se.leap.bitmaskclient.R.string.server_unreachable_message; public class OkHttpClientGenerator { - SharedPreferences preferences; Resources resources; public OkHttpClientGenerator(SharedPreferences preferences, Resources resources) { - this.preferences = preferences; this.resources = resources; } @@ -71,9 +69,8 @@ public class OkHttpClientGenerator { return initHttpClient(initError, null); } - public OkHttpClient initSelfSignedCAHttpClient(JSONObject initError) { - String certificate = preferences.getString(Provider.CA_CERT, ""); - return initHttpClient(initError, certificate); + public OkHttpClient initSelfSignedCAHttpClient(String caCert, JSONObject initError) { + return initHttpClient(initError, caCert); } public OkHttpClient initSelfSignedCAHttpClient(JSONObject initError, String certificate) { diff --git a/app/src/main/java/se/leap/bitmaskclient/Provider.java b/app/src/main/java/se/leap/bitmaskclient/Provider.java index ae329cd1..ca28eacd 100644 --- a/app/src/main/java/se/leap/bitmaskclient/Provider.java +++ b/app/src/main/java/se/leap/bitmaskclient/Provider.java @@ -16,18 +16,22 @@ */ package se.leap.bitmaskclient; -import android.content.SharedPreferences; -import android.os.*; +import android.os.Parcel; +import android.os.Parcelable; import com.google.gson.Gson; -import org.json.*; +import org.json.JSONArray; +import org.json.JSONException; +import org.json.JSONObject; -import java.io.Serializable; -import java.net.*; -import java.util.*; +import java.net.MalformedURLException; +import java.net.URL; +import java.util.Arrays; +import java.util.Locale; -import static se.leap.bitmaskclient.Constants.PROVIDER_CONFIGURED; +import static se.leap.bitmaskclient.Constants.PROVIDER_ALLOWED_REGISTERED; +import static se.leap.bitmaskclient.Constants.PROVIDER_ALLOW_ANONYMOUS; /** * @author Sean Leonard @@ -36,11 +40,17 @@ import static se.leap.bitmaskclient.Constants.PROVIDER_CONFIGURED; public final class Provider implements Parcelable { private JSONObject definition = new JSONObject(); // Represents our Provider's provider.json + private JSONObject eipServiceJson = new JSONObject(); // Represents our Provider's provider.json private DefaultedURL mainUrl = new DefaultedURL(); private DefaultedURL apiUrl = new DefaultedURL(); private String certificatePin = ""; private String certificatePinEncoding = ""; private String caCert = ""; + private String caCertFingerprint = ""; + private String apiVerson = ""; + + private boolean allowAnonymous; + private boolean allowRegistered; final public static String API_URL = "api_uri", @@ -141,6 +151,19 @@ public final class Provider implements Parcelable { return apiUrl; } + protected String getApiUrlWithVersion() { + return getApiUrlString() + "/" + getApiVersion(); + } + + + protected String getApiUrlString() { + return getApiUrl().toString(); + } + + public String getApiVersion() { + return apiVerson; + } + protected String certificatePin() { return certificatePin; } protected boolean hasCertificatePin() { @@ -160,6 +183,10 @@ public final class Provider implements Parcelable { return caCert; } + public String getCaCertFingerprint() { + return caCertFingerprint; + } + public String getName() { // Should we pass the locale in, or query the system here? String lang = Locale.getDefault().getLanguage(); @@ -200,26 +227,7 @@ public final class Provider implements Parcelable { } protected boolean hasEIP() { - try { - JSONArray services = definition.getJSONArray(API_TERM_SERVICES); // returns ["openvpn"] - for (int i = 0; i < API_EIP_TYPES.length + 1; i++) { - try { - // Walk the EIP types array looking for matches in provider's service definitions - if (Arrays.asList(API_EIP_TYPES).contains(services.getString(i))) - return true; - } catch (NullPointerException e) { - e.printStackTrace(); - return false; - } catch (JSONException e) { - // TODO Auto-generated catch block - e.printStackTrace(); - return false; - } - } - } catch (Exception e) { - // TODO: handle exception - } - return false; + return getEipServiceJson() != null && getEipServiceJson().length() > 0; } public boolean allowsRegistration() { @@ -237,12 +245,11 @@ public final class Provider implements Parcelable { @Override public void writeToParcel(Parcel parcel, int i) { - if(mainUrl != null) - parcel.writeString(mainUrl.toString()); - if (definition != null) - parcel.writeString(definition.toString()); - if (caCert != null) - parcel.writeString(caCert); + parcel.writeString(getMainUrlString()); + parcel.writeString(getDefinitionString()); + parcel.writeString(getCaCert()); + parcel.writeString(getCaCertFingerprint()); + parcel.writeString(getEipServiceJsonString()); } @Override @@ -289,6 +296,14 @@ public final class Provider implements Parcelable { if (!caCert.isEmpty()) { this.caCert = caCert; } + String caCertFingerprint = in.readString(); + if (!caCertFingerprint.isEmpty()) { + this.caCertFingerprint = caCertFingerprint; + } + String eipServiceJson = in.readString(); + if (!eipServiceJson.isEmpty()) { + this.setEipServiceJson(new JSONObject(eipServiceJson)); + } } catch (MalformedURLException | JSONException e) { e.printStackTrace(); } @@ -300,13 +315,39 @@ public final class Provider implements Parcelable { this.certificatePin = pin.split(":")[1].trim(); this.certificatePinEncoding = pin.split(":")[0].trim(); this.apiUrl.setUrl(new URL(definition.getString(API_URL))); + this.allowAnonymous = definition.getJSONObject(Provider.SERVICE).getBoolean(PROVIDER_ALLOW_ANONYMOUS); + this.allowRegistered = definition.getJSONObject(Provider.SERVICE).getBoolean(PROVIDER_ALLOWED_REGISTERED); + this.apiVerson = getDefinition().getString(Provider.API_VERSION); } catch (JSONException | ArrayIndexOutOfBoundsException | MalformedURLException e) { e.printStackTrace(); } } - public void setCACert(String cert) { + public void setCaCert(String cert) { this.caCert = cert; } + public void setCaCertFingerprint(String certFingerprint) { + this.caCertFingerprint = certFingerprint; + } + + public boolean allowsAnonymous() { + return allowAnonymous; + } + + public boolean allowsRegistered() { + return allowRegistered; + } + + public void setEipServiceJson(JSONObject eipServiceJson) { + this.eipServiceJson = eipServiceJson; + } + + public JSONObject getEipServiceJson() { + return eipServiceJson; + } + + public String getEipServiceJsonString() { + return getEipServiceJson().toString(); + } } diff --git a/app/src/main/java/se/leap/bitmaskclient/ProviderAPI.java b/app/src/main/java/se/leap/bitmaskclient/ProviderAPI.java index ccc71a67..73f5c530 100644 --- a/app/src/main/java/se/leap/bitmaskclient/ProviderAPI.java +++ b/app/src/main/java/se/leap/bitmaskclient/ProviderAPI.java @@ -40,22 +40,18 @@ public class ProviderAPI extends IntentService implements ProviderApiManagerBase TAG = ProviderAPI.class.getSimpleName(), SET_UP_PROVIDER = "setUpProvider", UPDATE_PROVIDER_DETAILS = "updateProviderDetails", - DOWNLOAD_NEW_PROVIDER_DOTJSON = "downloadNewProviderDotJSON", SIGN_UP = "srpRegister", LOG_IN = "srpAuth", LOG_OUT = "logOut", DOWNLOAD_CERTIFICATE = "downloadUserAuthedCertificate", PARAMETERS = "parameters", - RESULT_KEY = "result", - RESULT_CODE = "RESULT CODE", RECEIVER_KEY = "receiver", ERRORS = "errors", ERRORID = "errorId", UPDATE_PROGRESSBAR = "update_progressbar", CURRENT_PROGRESS = "current_progress", DOWNLOAD_EIP_SERVICE = TAG + ".DOWNLOAD_EIP_SERVICE", - PROVIDER_SET_UP = TAG + ".PROVIDER_SET_UP", - PROVIDER_API_EVENT = "PROVIDER_API_EVENT"; + PROVIDER_SET_UP = TAG + ".PROVIDER_SET_UP"; final public static int SUCCESSFUL_LOGIN = 3, @@ -84,16 +80,6 @@ public class ProviderAPI extends IntentService implements ProviderApiManagerBase ProviderApiManager.stop(); } - //TODO: refactor me, please! - public static boolean caCertDownloaded() { - return ProviderApiManager.caCertDownloaded(); - } - - //TODO: refactor me, please! - public static String lastProviderMainUrl() { - return ProviderApiManager.lastProviderMainUrl(); - } - //TODO: refactor me, please! //used in insecure flavor only @SuppressLint("unused") diff --git a/app/src/main/java/se/leap/bitmaskclient/ProviderAPICommand.java b/app/src/main/java/se/leap/bitmaskclient/ProviderAPICommand.java index 0e4cfe8a..65d01b22 100644 --- a/app/src/main/java/se/leap/bitmaskclient/ProviderAPICommand.java +++ b/app/src/main/java/se/leap/bitmaskclient/ProviderAPICommand.java @@ -6,40 +6,74 @@ import android.os.*; import org.jetbrains.annotations.*; public class ProviderAPICommand { - private static Context context; + private Context context; - private static String action; - private static Bundle parameters; - private static ResultReceiver result_receiver; + private String action; + private Bundle parameters; + private ResultReceiver resultReceiver; + private Provider provider; - public static void initialize(Context context) { - ProviderAPICommand.context = context; + private ProviderAPICommand(@NotNull Context context, @NotNull String action, @NotNull Provider provider, ResultReceiver resultReceiver) { + this(context, action, Bundle.EMPTY, provider, resultReceiver); + } + private ProviderAPICommand(@NotNull Context context, @NotNull String action, @NotNull Provider provider) { + this(context, action, Bundle.EMPTY, provider); } - private static boolean isInitialized() { - return context != null; + private ProviderAPICommand(@NotNull Context context, @NotNull String action, @NotNull Bundle parameters, @NotNull Provider provider) { + this(context, action, parameters, provider, null); } - public static void execute(Bundle parameters, @NotNull String action, @NotNull ResultReceiver result_receiver) throws IllegalStateException { - if(!isInitialized()) throw new IllegalStateException(); + private ProviderAPICommand(@NotNull Context context, @NotNull String action, @NotNull Bundle parameters, @NotNull Provider provider, @Nullable ResultReceiver resultReceiver) { + super(); + this.context = context; + this.action = action; + this.parameters = parameters; + this.resultReceiver = resultReceiver; + this.provider = provider; + } - ProviderAPICommand.action = action; - ProviderAPICommand.parameters = parameters; - ProviderAPICommand.result_receiver = result_receiver; + private boolean isInitialized() { + return context != null; + } - Intent intent = setUpIntent(); - context.startService(intent); + private void execute() { + if (isInitialized()) { + Intent intent = setUpIntent(); + context.startService(intent); + } } - private static Intent setUpIntent() { + private Intent setUpIntent() { Intent command = new Intent(context, ProviderAPI.class); command.setAction(action); command.putExtra(ProviderAPI.PARAMETERS, parameters); - command.putExtra(ProviderAPI.RECEIVER_KEY, result_receiver); + if (resultReceiver != null) { + command.putExtra(ProviderAPI.RECEIVER_KEY, resultReceiver); + } + command.putExtra(Constants.PROVIDER_KEY, provider); return command; } + public static void execute(Context context, String action, Provider provider) { + ProviderAPICommand command = new ProviderAPICommand(context, action, provider); + command.execute(); + } + public static void execute(Context context, String action, Bundle parameters, Provider provider) { + ProviderAPICommand command = new ProviderAPICommand(context, action, parameters, provider); + command.execute(); + } + + public static void execute(Context context, String action, Bundle parameters, Provider provider, ResultReceiver resultReceiver) { + ProviderAPICommand command = new ProviderAPICommand(context, action, parameters, provider, resultReceiver); + command.execute(); + } + + public static void execute(Context context, String action, Provider provider, ResultReceiver resultReceiver) { + ProviderAPICommand command = new ProviderAPICommand(context, action, provider, resultReceiver); + command.execute(); + } } diff --git a/app/src/main/java/se/leap/bitmaskclient/ProviderApiManagerBase.java b/app/src/main/java/se/leap/bitmaskclient/ProviderApiManagerBase.java index cfc6e49d..2de16dfb 100644 --- a/app/src/main/java/se/leap/bitmaskclient/ProviderApiManagerBase.java +++ b/app/src/main/java/se/leap/bitmaskclient/ProviderApiManagerBase.java @@ -24,6 +24,7 @@ import android.os.Bundle; import android.os.ResultReceiver; import android.support.annotation.NonNull; import android.util.Base64; +import android.util.Log; import android.util.Pair; import org.json.JSONException; @@ -49,19 +50,22 @@ import java.util.List; import javax.net.ssl.SSLHandshakeException; import okhttp3.OkHttpClient; -import se.leap.bitmaskclient.userstatus.SessionDialog; -import se.leap.bitmaskclient.userstatus.User; +import se.leap.bitmaskclient.Constants.CREDENTIAL_ERRORS; import se.leap.bitmaskclient.userstatus.UserStatus; import static se.leap.bitmaskclient.ConfigHelper.getFingerprintFromCertificate; -import static se.leap.bitmaskclient.Constants.PROVIDER_ALLOWED_REGISTERED; -import static se.leap.bitmaskclient.Constants.PROVIDER_ALLOW_ANONYMOUS; +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.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.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.Provider.MAIN_URL; 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.CURRENT_PROGRESS; @@ -73,17 +77,14 @@ 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_EIP_SERVICE; -import static se.leap.bitmaskclient.ProviderAPI.PROVIDER_API_EVENT; -import static se.leap.bitmaskclient.ProviderAPI.PROVIDER_SET_UP; import static se.leap.bitmaskclient.ProviderAPI.LOGOUT_FAILED; import static se.leap.bitmaskclient.ProviderAPI.LOG_IN; import static se.leap.bitmaskclient.ProviderAPI.LOG_OUT; import static se.leap.bitmaskclient.ProviderAPI.PARAMETERS; 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; import static se.leap.bitmaskclient.ProviderAPI.RECEIVER_KEY; -import static se.leap.bitmaskclient.ProviderAPI.RESULT_CODE; -import static se.leap.bitmaskclient.ProviderAPI.RESULT_KEY; import static se.leap.bitmaskclient.ProviderAPI.SET_UP_PROVIDER; import static se.leap.bitmaskclient.ProviderAPI.SIGN_UP; import static se.leap.bitmaskclient.ProviderAPI.SUCCESSFUL_LOGIN; @@ -109,36 +110,24 @@ import static se.leap.bitmaskclient.R.string.warning_expired_provider_cert; public abstract class ProviderApiManagerBase { + private final static String TAG = ProviderApiManagerBase.class.getName(); + public interface ProviderApiServiceCallback { void broadcastEvent(Intent intent); } private ProviderApiServiceCallback serviceCallback; - protected static volatile boolean - CA_CERT_DOWNLOADED = false, - PROVIDER_JSON_DOWNLOADED = false, - EIP_SERVICE_JSON_DOWNLOADED = false; - - protected static String lastProviderMainUrl; - protected static boolean go_ahead = true; - protected static SharedPreferences preferences; - protected static String providerApiUrl; - protected static String providerCaCertFingerprint; - protected static String providerCaCert; - protected static JSONObject providerDefinition; + static boolean go_ahead = true; + protected SharedPreferences preferences; protected Resources resources; - protected OkHttpClientGenerator clientGenerator; + OkHttpClientGenerator clientGenerator; public static void stop() { go_ahead = false; } - public static String lastProviderMainUrl() { - return lastProviderMainUrl; - } - - public ProviderApiManagerBase(SharedPreferences preferences, Resources resources, OkHttpClientGenerator clientGenerator, ProviderApiServiceCallback callback) { + ProviderApiManagerBase(SharedPreferences preferences, Resources resources, OkHttpClientGenerator clientGenerator, ProviderApiServiceCallback callback) { this.preferences = preferences; this.resources = resources; this.serviceCallback = callback; @@ -150,92 +139,94 @@ public abstract class ProviderApiManagerBase { String action = command.getAction(); Bundle parameters = command.getBundleExtra(PARAMETERS); - if (providerApiUrl == null && preferences.contains(Provider.KEY)) { - try { - JSONObject provider_json = new JSONObject(preferences.getString(Provider.KEY, "")); - providerApiUrl = provider_json.getString(Provider.API_URL) + "/" + provider_json.getString(Provider.API_VERSION); - go_ahead = true; - } catch (JSONException e) { - go_ahead = false; - } + Provider provider = command.getParcelableExtra(PROVIDER_KEY); + + if (provider == null) { + Log.e(TAG, action +" called without provider!"); + return; + } + if (action == null) { + Log.e(TAG, "Intent without action sent!"); + return; } if (action.equals(UPDATE_PROVIDER_DETAILS)) { - resetProviderDetails(); + resetProviderDetails(provider); Bundle task = new Bundle(); - task.putString(MAIN_URL, lastProviderMainUrl); - Bundle result = setUpProvider(task); - if (result.getBoolean(RESULT_KEY)) { - receiver.send(PROVIDER_OK, result); + Bundle result = setUpProvider(provider, task); + if (result.getBoolean(BROADCAST_RESULT_KEY)) { + sendToReceiverOrBroadcast(receiver, PROVIDER_OK, result, provider); } else { - receiver.send(PROVIDER_NOK, result); + sendToReceiverOrBroadcast(receiver, PROVIDER_NOK, result, provider); } } else if (action.equalsIgnoreCase(SET_UP_PROVIDER)) { - Bundle result = setUpProvider(parameters); + Bundle result = setUpProvider(provider, parameters); if (go_ahead) { - if (result.getBoolean(RESULT_KEY)) { - sendToReceiverOrBroadcast(receiver, PROVIDER_OK, result); + if (result.getBoolean(BROADCAST_RESULT_KEY)) { + sendToReceiverOrBroadcast(receiver, PROVIDER_OK, result, provider); } else { - sendToReceiverOrBroadcast(receiver, PROVIDER_NOK, result); + sendToReceiverOrBroadcast(receiver, PROVIDER_NOK, result, provider); } } } else if (action.equalsIgnoreCase(SIGN_UP)) { - UserStatus.updateStatus(UserStatus.SessionStatus.SIGNING_UP, resources); Bundle result = tryToRegister(parameters); - if (result.getBoolean(RESULT_KEY)) { - sendToReceiverOrBroadcast(receiver, SUCCESSFUL_SIGNUP, result); + if (result.getBoolean(BROADCAST_RESULT_KEY)) { + sendToReceiverOrBroadcast(receiver, SUCCESSFUL_SIGNUP, result, provider); } else { - sendToReceiverOrBroadcast(receiver, FAILED_SIGNUP, result); + sendToReceiverOrBroadcast(receiver, FAILED_SIGNUP, result, provider); } } else if (action.equalsIgnoreCase(LOG_IN)) { UserStatus.updateStatus(UserStatus.SessionStatus.LOGGING_IN, resources); - Bundle result = tryToAuthenticate(parameters); - if (result.getBoolean(RESULT_KEY)) { - sendToReceiverOrBroadcast(receiver, SUCCESSFUL_LOGIN, result); + Bundle result = tryToAuthenticate(provider, parameters); + if (result.getBoolean(BROADCAST_RESULT_KEY)) { + sendToReceiverOrBroadcast(receiver, SUCCESSFUL_LOGIN, result, provider); UserStatus.updateStatus(UserStatus.SessionStatus.LOGGED_IN, resources); } else { - sendToReceiverOrBroadcast(receiver, FAILED_LOGIN, result); + sendToReceiverOrBroadcast(receiver, FAILED_LOGIN, result, provider); UserStatus.updateStatus(UserStatus.SessionStatus.NOT_LOGGED_IN, resources); } } else if (action.equalsIgnoreCase(LOG_OUT)) { UserStatus.updateStatus(UserStatus.SessionStatus.LOGGING_OUT, resources); - if (logOut()) { - sendToReceiverOrBroadcast(receiver, SUCCESSFUL_LOGOUT, Bundle.EMPTY); + if (logOut(provider)) { + sendToReceiverOrBroadcast(receiver, SUCCESSFUL_LOGOUT, Bundle.EMPTY, provider); UserStatus.updateStatus(UserStatus.SessionStatus.LOGGED_OUT, resources); } else { - sendToReceiverOrBroadcast(receiver, LOGOUT_FAILED, Bundle.EMPTY); + sendToReceiverOrBroadcast(receiver, LOGOUT_FAILED, Bundle.EMPTY, provider); UserStatus.updateStatus(UserStatus.SessionStatus.DIDNT_LOG_OUT, resources); } } else if (action.equalsIgnoreCase(DOWNLOAD_CERTIFICATE)) { - if (updateVpnCertificate()) { - sendToReceiverOrBroadcast(receiver, CORRECTLY_DOWNLOADED_CERTIFICATE, Bundle.EMPTY); + if (updateVpnCertificate(provider)) { + sendToReceiverOrBroadcast(receiver, CORRECTLY_DOWNLOADED_CERTIFICATE, Bundle.EMPTY, provider); } else { - sendToReceiverOrBroadcast(receiver, INCORRECTLY_DOWNLOADED_CERTIFICATE, Bundle.EMPTY); + sendToReceiverOrBroadcast(receiver, INCORRECTLY_DOWNLOADED_CERTIFICATE, Bundle.EMPTY, provider); } } else if (action.equalsIgnoreCase(DOWNLOAD_EIP_SERVICE)) { - Bundle result = getAndSetEipServiceJson(); - if (result.getBoolean(RESULT_KEY)) { - sendToReceiverOrBroadcast(receiver, CORRECTLY_DOWNLOADED_EIP_SERVICE, result); + Bundle result = getAndSetEipServiceJson(provider); + if (result.getBoolean(BROADCAST_RESULT_KEY)) { + sendToReceiverOrBroadcast(receiver, CORRECTLY_DOWNLOADED_EIP_SERVICE, result, provider); } else { - sendToReceiverOrBroadcast(receiver, INCORRECTLY_DOWNLOADED_EIP_SERVICE, result); + sendToReceiverOrBroadcast(receiver, INCORRECTLY_DOWNLOADED_EIP_SERVICE, result, provider); } } else if (action.equalsIgnoreCase(PROVIDER_SET_UP)) { - if(EIP_SERVICE_JSON_DOWNLOADED && CA_CERT_DOWNLOADED && PROVIDER_JSON_DOWNLOADED ) { + if(provider.hasEIP() && provider.hasCaCert() && provider.hasDefinition()) { if(receiver!= null) { - receiver.send(PROVIDER_OK, Bundle.EMPTY); + Bundle result = new Bundle(); + result.putParcelable(PROVIDER_KEY, provider); + receiver.send(PROVIDER_OK, result); } } } } - protected void resetProviderDetails() { - CA_CERT_DOWNLOADED = PROVIDER_JSON_DOWNLOADED = false; - deleteProviderDetailsFromPreferences(providerDefinition); - providerCaCert = ""; - providerDefinition = new JSONObject(); + void resetProviderDetails(Provider provider) { + provider.setCaCert(""); + provider.define(new JSONObject()); + provider.setEipServiceJson(new JSONObject()); + + deleteProviderDetailsFromPreferences(provider.getDomain()); } - protected String formatErrorMessage(final int toastStringId) { + String formatErrorMessage(final int toastStringId) { return formatErrorMessage(resources.getString(toastStringId)); } @@ -252,7 +243,7 @@ public abstract class ProviderApiManagerBase { } } - protected void addErrorMessageToJson(JSONObject jsonObject, String errorMessage) { + private void addErrorMessageToJson(JSONObject jsonObject, String errorMessage) { try { jsonObject.put(ERRORS, errorMessage); } catch (JSONException e) { @@ -260,7 +251,7 @@ public abstract class ProviderApiManagerBase { } } - protected void addErrorMessageToJson(JSONObject jsonObject, String errorMessage, String errorId) { + private void addErrorMessageToJson(JSONObject jsonObject, String errorMessage, String errorId) { try { jsonObject.put(ERRORS, errorMessage); jsonObject.put(ERRORID, errorId); @@ -274,32 +265,37 @@ public abstract class ProviderApiManagerBase { private Bundle tryToRegister(Bundle task) { Bundle result = new Bundle(); - int progress = 0; - String username = User.userName(); - String password = task.getString(SessionDialog.PASSWORD); + String username = task.getString(CREDENTIALS_USERNAME); + String password = task.getString(CREDENTIALS_PASSWORD); + Provider provider = task.getParcelable(PROVIDER_KEY); + + if(provider == null) { + result.putBoolean(BROADCAST_RESULT_KEY, false); + Log.e(TAG, "no provider when trying to register"); + return result; + } if (validUserLoginData(username, password)) { - result = register(username, password); - broadcastProgress(progress++); + result = register(provider, username, password); } else { if (!wellFormedPassword(password)) { - result.putBoolean(RESULT_KEY, false); - result.putString(SessionDialog.USERNAME, username); - result.putBoolean(SessionDialog.ERRORS.PASSWORD_INVALID_LENGTH.toString(), true); + result.putBoolean(BROADCAST_RESULT_KEY, false); + result.putString(CREDENTIALS_USERNAME, username); + result.putBoolean(CREDENTIAL_ERRORS.PASSWORD_INVALID_LENGTH.toString(), true); } if (!validUsername(username)) { - result.putBoolean(RESULT_KEY, false); - result.putBoolean(SessionDialog.ERRORS.USERNAME_MISSING.toString(), true); + result.putBoolean(BROADCAST_RESULT_KEY, false); + result.putBoolean(CREDENTIAL_ERRORS.USERNAME_MISSING.toString(), true); } } return result; } - private Bundle register(String username, String password) { + private Bundle register(Provider provider, String username, String password) { JSONObject stepResult = null; - OkHttpClient okHttpClient = clientGenerator.initSelfSignedCAHttpClient(stepResult); + OkHttpClient okHttpClient = clientGenerator.initSelfSignedCAHttpClient(provider.getCaCert(), stepResult); if (okHttpClient == null) { return authFailedNotification(stepResult, username); } @@ -309,15 +305,15 @@ public abstract class ProviderApiManagerBase { BigInteger password_verifier = client.calculateV(username, password, salt); - JSONObject api_result = sendNewUserDataToSRPServer(providerApiUrl, username, new BigInteger(1, salt).toString(16), password_verifier.toString(16), okHttpClient); + JSONObject api_result = sendNewUserDataToSRPServer(provider.getApiUrlString(), username, new BigInteger(1, salt).toString(16), password_verifier.toString(16), okHttpClient); Bundle result = new Bundle(); if (api_result.has(ERRORS)) result = authFailedNotification(api_result, username); else { - result.putString(SessionDialog.USERNAME, username); - result.putString(SessionDialog.PASSWORD, password); - result.putBoolean(RESULT_KEY, true); + result.putString(CREDENTIALS_USERNAME, username); + result.putString(CREDENTIALS_PASSWORD, password); + result.putBoolean(BROADCAST_RESULT_KEY, true); } return result; @@ -326,37 +322,39 @@ public abstract class ProviderApiManagerBase { /** * Starts the authentication process using SRP protocol. * - * @param task containing: username, password and api url. - * @return a bundle with a boolean value mapped to a key named RESULT_KEY, and which is true if authentication was successful. + * @param task containing: username, password and provider + * @return a bundle with a boolean value mapped to a key named BROADCAST_RESULT_KEY, and which is true if authentication was successful. */ - private Bundle tryToAuthenticate(Bundle task) { + private Bundle tryToAuthenticate(Provider provider, Bundle task) { Bundle result = new Bundle(); - int progress = 0; - String username = User.userName(); - String password = task.getString(SessionDialog.PASSWORD); + String username = task.getString(CREDENTIALS_USERNAME); + String password = task.getString(CREDENTIALS_PASSWORD); + if (validUserLoginData(username, password)) { - result = authenticate(username, password); - broadcastProgress(progress++); + result = authenticate(provider, username, password); } else { if (!wellFormedPassword(password)) { - result.putBoolean(RESULT_KEY, false); - result.putString(SessionDialog.USERNAME, username); - result.putBoolean(SessionDialog.ERRORS.PASSWORD_INVALID_LENGTH.toString(), true); + result.putBoolean(BROADCAST_RESULT_KEY, false); + result.putString(CREDENTIALS_USERNAME, username); + result.putBoolean(CREDENTIAL_ERRORS.PASSWORD_INVALID_LENGTH.toString(), true); } if (!validUsername(username)) { - result.putBoolean(RESULT_KEY, false); - result.putBoolean(SessionDialog.ERRORS.USERNAME_MISSING.toString(), true); + result.putBoolean(BROADCAST_RESULT_KEY, false); + result.putBoolean(CREDENTIAL_ERRORS.USERNAME_MISSING.toString(), true); } } return result; } - private Bundle authenticate(String username, String password) { + private Bundle authenticate(Provider provider, String username, String password) { Bundle result = new Bundle(); JSONObject stepResult = new JSONObject(); - OkHttpClient okHttpClient = clientGenerator.initSelfSignedCAHttpClient(stepResult); + + String providerApiUrl = provider.getApiUrlWithVersion(); + + OkHttpClient okHttpClient = clientGenerator.initSelfSignedCAHttpClient(provider.getCaCert(), stepResult); if (okHttpClient == null) { return authFailedNotification(stepResult, username); } @@ -374,13 +372,13 @@ public abstract class ProviderApiManagerBase { setTokenIfAvailable(step_result); byte[] M2 = new BigInteger(step_result.getString(LeapSRPSession.M2), 16).toByteArray(); if (client.verify(M2)) { - result.putBoolean(RESULT_KEY, true); + result.putBoolean(BROADCAST_RESULT_KEY, true); } else { authFailedNotification(step_result, username); } } else { - result.putBoolean(RESULT_KEY, false); - result.putString(SessionDialog.USERNAME, username); + result.putBoolean(BROADCAST_RESULT_KEY, false); + result.putString(CREDENTIALS_USERNAME, username); result.putString(resources.getString(R.string.user_message), resources.getString(R.string.error_srp_math_error_user_message)); } } catch (JSONException e) { @@ -424,17 +422,21 @@ public abstract class ProviderApiManagerBase { } if (!username.isEmpty()) - userNotificationBundle.putString(SessionDialog.USERNAME, username); - userNotificationBundle.putBoolean(RESULT_KEY, false); + userNotificationBundle.putString(CREDENTIALS_USERNAME, username); + userNotificationBundle.putBoolean(BROADCAST_RESULT_KEY, false); return userNotificationBundle; } - void sendToReceiverOrBroadcast(ResultReceiver receiver, int resultCode, Bundle resultData) { + void sendToReceiverOrBroadcast(ResultReceiver receiver, int resultCode, Bundle resultData, Provider provider) { + if (resultData == null || resultData == Bundle.EMPTY) { + resultData = new Bundle(); + } + resultData.putParcelable(PROVIDER_KEY, provider); if (receiver != null) { receiver.send(resultCode, resultData); } else { - broadcastEvent(PROVIDER_API_EVENT, resultCode, resultData); + broadcastEvent(resultCode, resultData); } } @@ -451,11 +453,11 @@ public abstract class ProviderApiManagerBase { serviceCallback.broadcastEvent(intentUpdate); } - void broadcastEvent(String action, int resultCode , Bundle resultData) { - Intent intentUpdate = new Intent(action); + private void broadcastEvent(int resultCode , Bundle resultData) { + Intent intentUpdate = new Intent(BROADCAST_PROVIDER_API_EVENT); intentUpdate.addCategory(Intent.CATEGORY_DEFAULT); - intentUpdate.putExtra(RESULT_CODE, resultCode); - intentUpdate.putExtra(RESULT_KEY, resultData); + intentUpdate.putExtra(BROADCAST_RESULT_CODE, resultCode); + intentUpdate.putExtra(BROADCAST_RESULT_KEY, resultData); serviceCallback.broadcastEvent(intentUpdate); } @@ -624,27 +626,23 @@ 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. - * @return a bundle with a boolean value mapped to a key named RESULT_KEY, and which is true if the update was successful. + * @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(Bundle task); + protected abstract Bundle setUpProvider(Provider provider, Bundle task); /** * Downloads the eip-service.json from a given URL, and saves eip service capabilities including the offered gateways - * @return a bundle with a boolean value mapped to a key named RESULT_KEY, and which is true if the download was successful. + * @return a bundle with a boolean value mapped to a key named BROADCAST_RESULT_KEY, and which is true if the download was successful. */ - protected abstract Bundle getAndSetEipServiceJson(); + protected abstract Bundle getAndSetEipServiceJson(Provider provider); /** * Downloads a new OpenVPN certificate, attaching authenticated cookie for authenticated certificate. * * @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(); - + protected abstract boolean updateVpnCertificate(Provider provider); - protected static boolean caCertDownloaded() { - return CA_CERT_DOWNLOADED; - } protected boolean isValidJson(String jsonString) { try { @@ -658,19 +656,19 @@ public abstract class ProviderApiManagerBase { } } - protected boolean validCertificate(String cert_string) { + protected boolean validCertificate(Provider provider, String certString) { boolean result = false; - if (!ConfigHelper.checkErroneousDownload(cert_string)) { - X509Certificate certificate = ConfigHelper.parseX509CertificateFromString(cert_string); + if (!ConfigHelper.checkErroneousDownload(certString)) { + X509Certificate certificate = ConfigHelper.parseX509CertificateFromString(certString); try { if (certificate != null) { - JSONObject provider_json = new JSONObject(preferences.getString(Provider.KEY, "")); - String fingerprint = provider_json.getString(Provider.CA_CERT_FINGERPRINT); + JSONObject providerJson = provider.getDefinition(); + String fingerprint = providerJson.getString(Provider.CA_CERT_FINGERPRINT); String encoding = fingerprint.split(":")[0]; - String expected_fingerprint = fingerprint.split(":")[1]; - String real_fingerprint = getFingerprintFromCertificate(certificate, encoding); + String expectedFingerprint = fingerprint.split(":")[1]; + String realFingerprint = getFingerprintFromCertificate(certificate, encoding); - result = real_fingerprint.trim().equalsIgnoreCase(expected_fingerprint.trim()); + result = realFingerprint.trim().equalsIgnoreCase(expectedFingerprint.trim()); } else result = false; } catch (JSONException | NoSuchAlgorithmException | CertificateEncodingException e) { @@ -681,50 +679,41 @@ public abstract class ProviderApiManagerBase { return result; } - protected void checkPersistedProviderUpdates() { - String providerDomain = getDomainFromMainURL(lastProviderMainUrl); + protected void getPersistedProviderUpdates(Provider provider) { + String providerDomain = getDomainFromMainURL(provider.getMainUrlString()); if (hasUpdatedProviderDetails(providerDomain)) { - providerCaCert = getPersistedProviderCA(providerDomain); - providerDefinition = getPersistedProviderDefinition(providerDomain); - providerCaCertFingerprint = getPersistedCaCertFingerprint(providerDomain); - providerApiUrl = getApiUrlWithVersion(providerDefinition); + provider.setCaCert(getPersistedProviderCA(providerDomain)); + provider.define(getPersistedProviderDefinition(providerDomain)); + provider.setCaCertFingerprint(getPersistedCaCertFingerprint(providerDomain)); } } - protected Bundle validateProviderDetails() { - Bundle result = validateCertificateForProvider(providerCaCert, providerDefinition, lastProviderMainUrl); + Bundle validateProviderDetails(Provider provider) { + Bundle result = validateCertificateForProvider(provider); //invalid certificate or no certificate - if (result.containsKey(ERRORS) || (result.containsKey(RESULT_KEY) && !result.getBoolean(RESULT_KEY)) ) { + if (result.containsKey(ERRORS) || (result.containsKey(BROADCAST_RESULT_KEY) && !result.getBoolean(BROADCAST_RESULT_KEY)) ) { return result; } - //valid certificate: skip download, save loaded provider CA cert and provider definition directly - try { - preferences.edit().putString(Provider.KEY, providerDefinition.toString()). - putBoolean(PROVIDER_ALLOW_ANONYMOUS, providerDefinition.getJSONObject(Provider.SERVICE).getBoolean(PROVIDER_ALLOW_ANONYMOUS)). - putBoolean(PROVIDER_ALLOWED_REGISTERED, providerDefinition.getJSONObject(Provider.SERVICE).getBoolean(PROVIDER_ALLOWED_REGISTERED)). - putString(Provider.CA_CERT, providerCaCert).commit(); - CA_CERT_DOWNLOADED = true; - PROVIDER_JSON_DOWNLOADED = true; - result.putBoolean(RESULT_KEY, true); - } catch (JSONException e) { - e.printStackTrace(); - setErrorResult(result, warning_corrupted_provider_details, ERROR_CORRUPTED_PROVIDER_JSON.toString()); - } + result.putBoolean(BROADCAST_RESULT_KEY, true); return result; } - protected Bundle validateCertificateForProvider(String cert_string, JSONObject providerDefinition, String mainUrl) { + protected Bundle validateCertificateForProvider(Provider provider) { Bundle result = new Bundle(); - result.putBoolean(RESULT_KEY, false); + result.putBoolean(BROADCAST_RESULT_KEY, false); + + String caCert = provider.getCaCert(); + JSONObject providerDefinition = provider.getDefinition(); + String mainUrl = provider.getMainUrlString(); - if (ConfigHelper.checkErroneousDownload(cert_string)) { + if (ConfigHelper.checkErroneousDownload(caCert)) { return result; } - X509Certificate certificate = ConfigHelper.parseX509CertificateFromString(cert_string); + X509Certificate certificate = ConfigHelper.parseX509CertificateFromString(caCert); if (certificate == null) { return setErrorResult(result, warning_corrupted_provider_cert, ERROR_INVALID_CERTIFICATE.toString()); } @@ -732,9 +721,9 @@ public abstract class ProviderApiManagerBase { certificate.checkValidity(); String fingerprint = getCaCertFingerprint(providerDefinition); String encoding = fingerprint.split(":")[0]; - String expected_fingerprint = fingerprint.split(":")[1]; - String real_fingerprint = getFingerprintFromCertificate(certificate, encoding); - if (!real_fingerprint.trim().equalsIgnoreCase(expected_fingerprint.trim())) { + String expectedFingerprint = fingerprint.split(":")[1]; + String realFingerprint = getFingerprintFromCertificate(certificate, encoding); + if (!realFingerprint.trim().equalsIgnoreCase(expectedFingerprint.trim())) { return setErrorResult(result, warning_corrupted_provider_cert, ERROR_CERTIFICATE_PINNING.toString()); } @@ -743,7 +732,7 @@ public abstract class ProviderApiManagerBase { return setErrorResult(result, warning_corrupted_provider_details, ERROR_CORRUPTED_PROVIDER_JSON.toString()); } - if (!canConnect(cert_string, providerDefinition, result)) { + if (!canConnect(caCert, providerDefinition, result)) { return result; } } catch (NoSuchAlgorithmException e ) { @@ -754,11 +743,11 @@ public abstract class ProviderApiManagerBase { return setErrorResult(result, warning_expired_provider_cert, ERROR_INVALID_CERTIFICATE.toString()); } - result.putBoolean(RESULT_KEY, true); + result.putBoolean(BROADCAST_RESULT_KEY, true); return result; } - protected Bundle setErrorResult(Bundle result, int errorMessageId, String errorId) { + Bundle setErrorResult(Bundle result, int errorMessageId, String errorId) { JSONObject errorJson = new JSONObject(); if (errorId != null) { addErrorMessageToJson(errorJson, resources.getString(errorMessageId), errorId); @@ -766,7 +755,7 @@ public abstract class ProviderApiManagerBase { addErrorMessageToJson(errorJson, resources.getString(errorMessageId)); } result.putString(ERRORS, errorJson.toString()); - result.putBoolean(RESULT_KEY, false); + result.putBoolean(BROADCAST_RESULT_KEY, false); return result; } @@ -807,17 +796,7 @@ public abstract class ProviderApiManagerBase { return ""; } - protected String getApiUrlWithVersion(JSONObject providerDefinition) { - try { - return providerDefinition.getString(Provider.API_URL) + "/" + providerDefinition.getString(Provider.API_VERSION); - } catch (JSONException e) { - e.printStackTrace(); - } - return ""; - } - - protected void deleteProviderDetailsFromPreferences(JSONObject providerDefinition) { - String providerDomain = getProviderDomain(providerDefinition); + protected void deleteProviderDetailsFromPreferences(String providerDomain) { if (preferences.contains(Provider.KEY + "." + providerDomain)) { preferences.edit().remove(Provider.KEY + "." + providerDomain).apply(); @@ -903,17 +882,15 @@ public abstract class ProviderApiManagerBase { return headerArgs; } - private boolean logOut() { - OkHttpClient okHttpClient = clientGenerator.initSelfSignedCAHttpClient(new JSONObject()); + private boolean logOut(Provider provider) { + OkHttpClient okHttpClient = clientGenerator.initSelfSignedCAHttpClient(provider.getCaCert(), new JSONObject()); if (okHttpClient == null) { return false; } - String deleteUrl = providerApiUrl + "/logout"; - int progress = 0; + String deleteUrl = provider.getApiUrlString() + "/logout"; if (ProviderApiConnector.delete(okHttpClient, deleteUrl)) { - broadcastProgress(progress++); LeapSRPSession.setToken(""); return true; } diff --git a/app/src/main/java/se/leap/bitmaskclient/ProviderCredentialsBaseActivity.java b/app/src/main/java/se/leap/bitmaskclient/ProviderCredentialsBaseActivity.java index 25dca4e0..a309bdf9 100644 --- a/app/src/main/java/se/leap/bitmaskclient/ProviderCredentialsBaseActivity.java +++ b/app/src/main/java/se/leap/bitmaskclient/ProviderCredentialsBaseActivity.java @@ -20,17 +20,20 @@ import android.widget.TextView; import butterknife.InjectView; import butterknife.OnClick; -import se.leap.bitmaskclient.userstatus.SessionDialog; -import se.leap.bitmaskclient.userstatus.SessionDialog.ERRORS; +import se.leap.bitmaskclient.Constants.CREDENTIAL_ERRORS; import se.leap.bitmaskclient.userstatus.User; import static android.view.View.GONE; import static android.view.View.VISIBLE; import static android.view.inputmethod.EditorInfo.IME_ACTION_DONE; -import static se.leap.bitmaskclient.ProviderAPI.PROVIDER_API_EVENT; -import static se.leap.bitmaskclient.ProviderAPI.RESULT_CODE; -import static se.leap.bitmaskclient.ProviderAPI.RESULT_KEY; -import static se.leap.bitmaskclient.userstatus.SessionDialog.USERNAME; +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.CREDENTIALS_PASSWORD; +import static se.leap.bitmaskclient.Constants.CREDENTIALS_USERNAME; +import static se.leap.bitmaskclient.ProviderAPI.DOWNLOAD_CERTIFICATE; +import static se.leap.bitmaskclient.ProviderAPI.LOG_IN; +import static se.leap.bitmaskclient.ProviderAPI.SIGN_UP; /** * Base Activity for activities concerning a provider interaction @@ -84,7 +87,7 @@ public abstract class ProviderCredentialsBaseActivity extends ConfigWizardBaseAc setContentView(R.layout.a_provider_credentials); providerAPIBroadcastReceiver = new ProviderAPIBroadcastReceiver(); - IntentFilter updateIntentFilter = new IntentFilter(PROVIDER_API_EVENT); + IntentFilter updateIntentFilter = new IntentFilter(BROADCAST_PROVIDER_API_EVENT); updateIntentFilter.addCategory(Intent.CATEGORY_DEFAULT); registerReceiver(providerAPIBroadcastReceiver, updateIntentFilter); @@ -178,34 +181,27 @@ public abstract class ProviderCredentialsBaseActivity extends ConfigWizardBaseAc void login(String username, String password) { User.setUserName(username); - Intent providerAPICommand = new Intent(this, ProviderAPI.class); - Bundle parameters = bundlePassword(password); - providerAPICommand.setAction(ProviderAPI.LOG_IN); - providerAPICommand.putExtra(ProviderAPI.PARAMETERS, parameters); - startService(providerAPICommand); + Bundle parameters = bundleUsernameAndPassword(username, password); + ProviderAPICommand.execute(this, LOG_IN, parameters, provider); } public void signUp(String username, String password) { User.setUserName(username); - Intent providerAPICommand = new Intent(this, ProviderAPI.class); - Bundle parameters = bundlePassword(password); - providerAPICommand.setAction(ProviderAPI.SIGN_UP); - providerAPICommand.putExtra(ProviderAPI.PARAMETERS, parameters); - startService(providerAPICommand); + Bundle parameters = bundleUsernameAndPassword(username, password); + ProviderAPICommand.execute(this, SIGN_UP, parameters, provider); } void downloadVpnCertificate() { - Intent providerAPICommand = new Intent(this, ProviderAPI.class); - providerAPICommand.setAction(ProviderAPI.DOWNLOAD_CERTIFICATE); - providerAPICommand.putExtra(ProviderAPI.PARAMETERS, Bundle.EMPTY); - startService(providerAPICommand); + ProviderAPICommand.execute(this, DOWNLOAD_CERTIFICATE, provider); } - protected Bundle bundlePassword(String password) { + protected Bundle bundleUsernameAndPassword(String username, String password) { Bundle parameters = new Bundle(); + if (!username.isEmpty()) + parameters.putString(CREDENTIALS_USERNAME, username); if (!password.isEmpty()) - parameters.putString(SessionDialog.PASSWORD, password); + parameters.putString(CREDENTIALS_PASSWORD, password); return parameters; } @@ -316,17 +312,17 @@ public abstract class ProviderCredentialsBaseActivity extends ConfigWizardBaseAc } private void handleReceivedErrors(Bundle arguments) { - if (arguments.containsKey(ERRORS.PASSWORD_INVALID_LENGTH.toString())) + if (arguments.containsKey(CREDENTIAL_ERRORS.PASSWORD_INVALID_LENGTH.toString())) passwordError.setError(getString(R.string.error_not_valid_password_user_message)); - else if (arguments.containsKey(ERRORS.RISEUP_WARNING.toString())) { + else if (arguments.containsKey(CREDENTIAL_ERRORS.RISEUP_WARNING.toString())) { userMessage.setVisibility(VISIBLE); userMessage.setText(R.string.login_riseup_warning); } - if (arguments.containsKey(USERNAME)) { - String username = arguments.getString(USERNAME); + if (arguments.containsKey(CREDENTIALS_USERNAME)) { + String username = arguments.getString(CREDENTIALS_USERNAME); usernameField.setText(username); } - if (arguments.containsKey(ERRORS.USERNAME_MISSING.toString())) { + if (arguments.containsKey(CREDENTIAL_ERRORS.USERNAME_MISSING.toString())) { usernameError.setError(getString(R.string.username_ask)); } if (arguments.containsKey(getString(R.string.user_message))) { @@ -356,11 +352,11 @@ public abstract class ProviderCredentialsBaseActivity extends ConfigWizardBaseAc Log.d(TAG, "received Broadcast"); String action = intent.getAction(); - if (action == null || !action.equalsIgnoreCase(PROVIDER_API_EVENT)) { + if (action == null || !action.equalsIgnoreCase(BROADCAST_PROVIDER_API_EVENT)) { return; } - int resultCode = intent.getIntExtra(RESULT_CODE, -1); + int resultCode = intent.getIntExtra(BROADCAST_RESULT_CODE, -1); switch (resultCode) { case ProviderAPI.SUCCESSFUL_SIGNUP: case ProviderAPI.SUCCESSFUL_LOGIN: @@ -368,7 +364,7 @@ public abstract class ProviderCredentialsBaseActivity extends ConfigWizardBaseAc break; case ProviderAPI.FAILED_LOGIN: case ProviderAPI.FAILED_SIGNUP: - handleReceivedErrors((Bundle) intent.getParcelableExtra(RESULT_KEY)); + handleReceivedErrors((Bundle) intent.getParcelableExtra(BROADCAST_RESULT_KEY)); break; case ProviderAPI.CORRECTLY_DOWNLOADED_CERTIFICATE: diff --git a/app/src/main/java/se/leap/bitmaskclient/ProviderListBaseActivity.java b/app/src/main/java/se/leap/bitmaskclient/ProviderListBaseActivity.java index 2b0c72db..ceb7a3c4 100644 --- a/app/src/main/java/se/leap/bitmaskclient/ProviderListBaseActivity.java +++ b/app/src/main/java/se/leap/bitmaskclient/ProviderListBaseActivity.java @@ -33,6 +33,7 @@ import android.widget.ListView; import com.pedrogomez.renderers.Renderer; import org.jetbrains.annotations.NotNull; +import org.jetbrains.annotations.Nullable; import org.json.JSONException; import org.json.JSONObject; @@ -47,18 +48,19 @@ import se.leap.bitmaskclient.fragments.AboutFragment; import static android.view.View.GONE; import static se.leap.bitmaskclient.Constants.APP_ACTION_QUIT; -import static se.leap.bitmaskclient.Constants.PROVIDER_ALLOW_ANONYMOUS; +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.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.ERRORS; import static se.leap.bitmaskclient.ProviderAPI.INCORRECTLY_DOWNLOADED_CERTIFICATE; -import static se.leap.bitmaskclient.ProviderAPI.PROVIDER_API_EVENT; 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; -import static se.leap.bitmaskclient.ProviderAPI.RESULT_CODE; -import static se.leap.bitmaskclient.ProviderAPI.RESULT_KEY; +import static se.leap.bitmaskclient.ProviderAPI.UPDATE_PROVIDER_DETAILS; /** * abstract base Activity that builds and shows the list of known available providers. @@ -101,7 +103,7 @@ public abstract class ProviderListBaseActivity extends ConfigWizardBaseActivity private boolean isActivityShowing; private String reasonToFail; - public abstract void retrySetUpProvider(); + public abstract void retrySetUpProvider(Provider provider); protected abstract void onItemSelectedLogic(); @@ -117,7 +119,7 @@ public abstract class ProviderListBaseActivity extends ConfigWizardBaseActivity @Override protected void onSaveInstanceState(@NotNull Bundle outState) { outState.putString(ACTIVITY_STATE, mConfigState.getAction()); - outState.putParcelable(Provider.KEY, provider); + outState.putParcelable(PROVIDER_KEY, provider); DialogFragment dialogFragment = (DialogFragment) fragmentManager.findFragmentByTag(DownloadFailedDialog.TAG); if (dialogFragment != null) { @@ -140,7 +142,6 @@ public abstract class ProviderListBaseActivity extends ConfigWizardBaseActivity if (savedInstanceState != null) restoreState(savedInstanceState); - setUpProviderAPIResultReceiver(); } private void restoreState(Bundle savedInstanceState) { @@ -164,6 +165,7 @@ public abstract class ProviderListBaseActivity extends ConfigWizardBaseActivity protected void onResume() { Log.d(TAG, "resuming with ConfigState: " + mConfigState.getAction()); super.onResume(); + setUpProviderAPIResultReceiver(); hideProgressBar(); isActivityShowing = true; if (SETTING_UP_PROVIDER.equals(mConfigState.getAction())) { @@ -187,13 +189,13 @@ public abstract class ProviderListBaseActivity extends ConfigWizardBaseActivity protected void onPause() { super.onPause(); isActivityShowing = false; + if (providerAPIBroadcastReceiver != null) + unregisterReceiver(providerAPIBroadcastReceiver); } @Override protected void onDestroy() { super.onDestroy(); - if (providerAPIBroadcastReceiver != null) - unregisterReceiver(providerAPIBroadcastReceiver); providerAPIResultReceiver = null; } @@ -211,25 +213,16 @@ public abstract class ProviderListBaseActivity extends ConfigWizardBaseActivity providerAPIResultReceiver = new ProviderAPIResultReceiver(new Handler(), this); providerAPIBroadcastReceiver = new ProviderAPIBroadcastReceiver(); - IntentFilter updateIntentFilter = new IntentFilter(PROVIDER_API_EVENT); + IntentFilter updateIntentFilter = new IntentFilter(BROADCAST_PROVIDER_API_EVENT); updateIntentFilter.addCategory(Intent.CATEGORY_DEFAULT); registerReceiver(providerAPIBroadcastReceiver, updateIntentFilter); } - void handleProviderSetUp() { - try { - String providerJsonString = preferences.getString(Provider.KEY, ""); - if (!providerJsonString.isEmpty()) - provider.define(new JSONObject(providerJsonString)); - String caCert = preferences.getString(Provider.CA_CERT, ""); - provider.setCACert(caCert); - } catch (JSONException e) { - e.printStackTrace(); - } + void handleProviderSetUp(Provider handledProvider) { + this.provider = handledProvider; - if (preferences.getBoolean(PROVIDER_ALLOW_ANONYMOUS, false)) { + if (provider.allowsAnonymous()) { mConfigState.putExtra(SERVICES_RETRIEVED, true); - downloadVpnCertificate(); } else { showProviderDetails(); @@ -238,7 +231,6 @@ public abstract class ProviderListBaseActivity extends ConfigWizardBaseActivity void handleProviderSetupFailed(Bundle resultData) { mConfigState.setAction(PROVIDER_NOT_SET); - preferences.edit().remove(Provider.KEY).apply(); setResult(RESULT_CANCELED, mConfigState); @@ -259,7 +251,8 @@ public abstract class ProviderListBaseActivity extends ConfigWizardBaseActivity @Override public void onReceiveResult(int resultCode, Bundle resultData) { if (resultCode == ProviderAPI.PROVIDER_OK) { - handleProviderSetUp(); + Provider provider = resultData.getParcelable(PROVIDER_KEY); + handleProviderSetUp(provider); } else if (resultCode == AboutFragment.VIEWED) { // Do nothing, right now // I need this for CW to wait for the About activity to end before going back to Dashboard. @@ -303,27 +296,20 @@ public abstract class ProviderListBaseActivity extends ConfigWizardBaseActivity hideProgressBar(); mConfigState.setAction(PROVIDER_NOT_SET); adapter.showAllProviders(); - preferences.edit().remove(Provider.KEY).remove(PROVIDER_ALLOW_ANONYMOUS).remove(PROVIDER_KEY).apply(); } @Override public void updateProviderDetails() { mConfigState.setAction(SETTING_UP_PROVIDER); - Intent providerAPICommand = new Intent(this, ProviderAPI.class); - providerAPICommand.setAction(ProviderAPI.UPDATE_PROVIDER_DETAILS); Bundle parameters = new Bundle(); parameters.putString(Provider.MAIN_URL, provider.getMainUrl().toString()); - providerAPICommand.putExtra(ProviderAPI.PARAMETERS, parameters); - startService(providerAPICommand); + ProviderAPICommand.execute(this, UPDATE_PROVIDER_DETAILS, parameters, provider); } public void checkProviderSetUp() { - Intent providerAPICommand = new Intent(this, ProviderAPI.class); - providerAPICommand.setAction(PROVIDER_SET_UP); - providerAPICommand.putExtra(ProviderAPI.RECEIVER_KEY, providerAPIResultReceiver); - startService(providerAPICommand); + ProviderAPICommand.execute(this, PROVIDER_SET_UP, provider, providerAPIResultReceiver); } private void askDashboardToQuitApp() { @@ -336,29 +322,30 @@ public abstract class ProviderListBaseActivity extends ConfigWizardBaseActivity * Asks ProviderApiService to download an anonymous (anon) VPN certificate. */ private void downloadVpnCertificate() { - Intent providerAPICommand = new Intent(this, ProviderAPI.class); - providerAPICommand.setAction(ProviderAPI.DOWNLOAD_CERTIFICATE); - startService(providerAPICommand); + ProviderAPICommand.execute(this, DOWNLOAD_CERTIFICATE, provider); } /** * Open the new provider dialog */ public void addAndSelectNewProvider() { - FragmentTransaction fragmentTransaction = fragmentManager.removePreviousFragment(NewProviderDialog.TAG); - new NewProviderDialog().show(fragmentTransaction, NewProviderDialog.TAG); + addAndSelectNewProvider(null); } /** - * Open the new provider dialog with data + * Open the new provider dialog + * @param mainUrl - the main url of the provider to add - if null add a new provider */ - public void addAndSelectNewProvider(String main_url) { + public void addAndSelectNewProvider(@Nullable String mainUrl) { FragmentTransaction fragmentTransaction = fragmentManager.removePreviousFragment(NewProviderDialog.TAG); DialogFragment newFragment = new NewProviderDialog(); - Bundle data = new Bundle(); - data.putString(Provider.MAIN_URL, main_url); - newFragment.setArguments(data); + + if (mainUrl != null) { + Bundle data = new Bundle(); + data.putString(Provider.MAIN_URL, mainUrl); + newFragment.setArguments(data); + } newFragment.show(fragmentTransaction, NewProviderDialog.TAG); } @@ -436,40 +423,26 @@ public abstract class ProviderListBaseActivity extends ConfigWizardBaseActivity Log.d(TAG, "received Broadcast"); String action = intent.getAction(); - if (action == null || !action.equalsIgnoreCase(PROVIDER_API_EVENT)) { + if (action == null || !action.equalsIgnoreCase(BROADCAST_PROVIDER_API_EVENT)) { return; } if (mConfigState.getAction() != null && mConfigState.getAction().equalsIgnoreCase(SETTING_UP_PROVIDER)) { - int resultCode = intent.getIntExtra(RESULT_CODE, -1); + int resultCode = intent.getIntExtra(BROADCAST_RESULT_CODE, -1); Log.d(TAG, "Broadcast resultCode: " + Integer.toString(resultCode)); - Bundle resultData = intent.getParcelableExtra(RESULT_KEY); - String handledProvider = resultData.getString(Provider.KEY); - - String providerName = ConfigHelper.getProviderName(handledProvider); - String providerDomain = ConfigHelper.getProviderDomain(handledProvider); + Bundle resultData = intent.getParcelableExtra(BROADCAST_RESULT_KEY); + Provider handledProvider = resultData.getParcelable(PROVIDER_KEY); - //FIXME: remove that lines as soon as Provider gets sent via broadcast - if (resultCode == PROVIDER_OK && handledProvider == null) { - providerName = ConfigHelper.getProviderName(preferences); - providerDomain = ConfigHelper.getProviderDomain(preferences); - } - - if (providerName != null && providerName.equalsIgnoreCase(provider.getName()) && - providerDomain != null && - providerDomain.equalsIgnoreCase(provider.getDomain())) { + if (handledProvider != null && handledProvider.getDomain().equalsIgnoreCase(provider.getDomain())) { switch (resultCode) { case PROVIDER_OK: - handleProviderSetUp(); + handleProviderSetUp(handledProvider); break; case PROVIDER_NOK: handleProviderSetupFailed(resultData); break; - } - } else { - switch (resultCode) { case CORRECTLY_DOWNLOADED_CERTIFICATE: handleCorrectlyDownloadedCertificate(); break; diff --git a/app/src/main/java/se/leap/bitmaskclient/StartActivity.java b/app/src/main/java/se/leap/bitmaskclient/StartActivity.java index f5991538..616264f9 100644 --- a/app/src/main/java/se/leap/bitmaskclient/StartActivity.java +++ b/app/src/main/java/se/leap/bitmaskclient/StartActivity.java @@ -69,7 +69,6 @@ public class StartActivity extends Activity { } // initialize app necessities - ProviderAPICommand.initialize(getApplicationContext()); VpnStatus.initLogCache(getApplicationContext().getCacheDir()); User.init(getString(R.string.default_username)); diff --git a/app/src/main/java/se/leap/bitmaskclient/drawer/NavigationDrawerFragment.java b/app/src/main/java/se/leap/bitmaskclient/drawer/NavigationDrawerFragment.java index 090e8d26..64d1bb72 100644 --- a/app/src/main/java/se/leap/bitmaskclient/drawer/NavigationDrawerFragment.java +++ b/app/src/main/java/se/leap/bitmaskclient/drawer/NavigationDrawerFragment.java @@ -1,7 +1,6 @@ package se.leap.bitmaskclient.drawer; -import android.content.Context; import android.content.Intent; import android.content.SharedPreferences; import android.content.res.Configuration; @@ -137,19 +136,11 @@ public class NavigationDrawerFragment extends Fragment { } }); - - accountListAdapter = new ArrayAdapter<>(actionBar.getThemedContext(), android.R.layout.simple_list_item_activated_1, android.R.id.text1); - String providerName = ConfigHelper.getProviderName(preferences); - if (providerName == null) { - //TODO: ADD A header to the ListView containing a useful message. - //TODO 2: disable switchProvider - } else { - accountListAdapter.add(providerName); - } + createListAdapterData(); mDrawerAccountsListView.setAdapter(accountListAdapter); @@ -225,16 +216,6 @@ public class NavigationDrawerFragment extends Fragment { onNavigationDrawerItemSelected(list, position); } - @Override - public void onAttach(Context context) { - super.onAttach(context); - } - - @Override - public void onDetach() { - super.onDetach(); - } - @Override public void onSaveInstanceState(Bundle outState) { super.onSaveInstanceState(outState); @@ -301,10 +282,7 @@ public class NavigationDrawerFragment extends Fragment { Log.d("Drawer", String.format("Selected position %d", position)); switch (position) { case 0: - // TODO STOP VPN - // if (provider.hasEIP()) eip_fragment.stopEipIfPossible(); - preferences.edit().clear().apply(); - startActivityForResult(new Intent(getActivity(), ProviderListActivity.class), REQUEST_CODE_SWITCH_PROVIDER); + getActivity().startActivityForResult(new Intent(getActivity(), ProviderListActivity.class), REQUEST_CODE_SWITCH_PROVIDER); break; case 1: mTitle = getString(R.string.log_fragment_title); @@ -337,4 +315,21 @@ public class NavigationDrawerFragment extends Fragment { } + public void refresh() { + createListAdapterData(); + accountListAdapter.notifyDataSetChanged(); + mDrawerAccountsListView.setAdapter(accountListAdapter); + } + + private void createListAdapterData() { + accountListAdapter.clear(); + String providerName = ConfigHelper.getProviderName(preferences); + if (providerName == null) { + //TODO: ADD A header to the ListView containing a useful message. + //TODO 2: disable switchProvider + } else { + accountListAdapter.add(providerName); + } + } + } 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 eca5b881..e53d81d9 100644 --- a/app/src/main/java/se/leap/bitmaskclient/eip/EIP.java +++ b/app/src/main/java/se/leap/bitmaskclient/eip/EIP.java @@ -30,6 +30,9 @@ import org.json.JSONObject; import de.blinkt.openvpn.LaunchVPN; import se.leap.bitmaskclient.OnBootReceiver; +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; import static se.leap.bitmaskclient.Constants.EIP_ACTION_CHECK_CERT_VALIDITY; import static se.leap.bitmaskclient.Constants.EIP_ACTION_IS_RUNNING; import static se.leap.bitmaskclient.Constants.EIP_ACTION_START; @@ -123,9 +126,9 @@ public final class EIP extends IntentService { gateway = gatewaysManager.select(); if (gateway != null && gateway.getProfile() != null) { launchActiveGateway(); - tellToReceiver(EIP_ACTION_START, Activity.RESULT_OK); + tellToReceiverOrBroadcast(EIP_ACTION_START, Activity.RESULT_OK); } else - tellToReceiver(EIP_ACTION_START, Activity.RESULT_CANCELED); + tellToReceiverOrBroadcast(EIP_ACTION_START, Activity.RESULT_CANCELED); } /** @@ -173,7 +176,7 @@ public final class EIP extends IntentService { if (eipStatus.isConnected() || eipStatus.isConnecting()) resultCode = Activity.RESULT_OK; - tellToReceiver(EIP_ACTION_STOP, resultCode); + tellToReceiverOrBroadcast(EIP_ACTION_STOP, resultCode); } /** @@ -186,7 +189,7 @@ public final class EIP extends IntentService { int resultCode = (eipStatus.isConnected()) ? Activity.RESULT_OK : Activity.RESULT_CANCELED; - tellToReceiver(EIP_ACTION_IS_RUNNING, resultCode); + tellToReceiverOrBroadcast(EIP_ACTION_IS_RUNNING, resultCode); } /** @@ -197,7 +200,7 @@ public final class EIP extends IntentService { eipDefinition = eipDefinitionFromPreferences(); if (eipDefinition.length() > 0) updateGateways(); - tellToReceiver(EIP_ACTION_UPDATE, Activity.RESULT_OK); + tellToReceiverOrBroadcast(EIP_ACTION_UPDATE, Activity.RESULT_OK); } private JSONObject eipDefinitionFromPreferences() { @@ -237,14 +240,26 @@ public final class EIP extends IntentService { int resultCode = validator.isValid() ? Activity.RESULT_OK : Activity.RESULT_CANCELED; - tellToReceiver(EIP_ACTION_CHECK_CERT_VALIDITY, resultCode); + tellToReceiverOrBroadcast(EIP_ACTION_CHECK_CERT_VALIDITY, resultCode); } - private void tellToReceiver(String action, int resultCode) { + private void tellToReceiverOrBroadcast(String action, int resultCode) { + Bundle resultData = new Bundle(); + resultData.putString(EIP_REQUEST, action); if (mReceiver != null) { - Bundle resultData = new Bundle(); - resultData.putString(EIP_REQUEST, action); mReceiver.send(resultCode, resultData); + } else { + broadcastEvent(resultCode, resultData); } } + + private void broadcastEvent(int resultCode , Bundle resultData) { + Intent intentUpdate = new Intent(BROADCAST_EIP_EVENT); + intentUpdate.addCategory(Intent.CATEGORY_DEFAULT); + intentUpdate.putExtra(BROADCAST_RESULT_CODE, resultCode); + intentUpdate.putExtra(BROADCAST_RESULT_KEY, resultData); + Log.d(TAG, "sending broadcast"); + sendBroadcast(intentUpdate); + } + } diff --git a/app/src/main/java/se/leap/bitmaskclient/userstatus/SessionDialog.java b/app/src/main/java/se/leap/bitmaskclient/userstatus/SessionDialog.java deleted file mode 100644 index 29d4f01d..00000000 --- a/app/src/main/java/se/leap/bitmaskclient/userstatus/SessionDialog.java +++ /dev/null @@ -1,179 +0,0 @@ -/** - * 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 . - */ -package se.leap.bitmaskclient.userstatus; - -import android.app.AlertDialog; -import android.content.Context; -import android.content.DialogInterface; -import android.os.Bundle; -import android.support.v4.app.DialogFragment; -import android.support.v7.app.AppCompatActivity; -import android.view.LayoutInflater; -import android.view.View; -import android.widget.EditText; -import android.widget.TextView; - -import butterknife.ButterKnife; -import butterknife.InjectView; -import se.leap.bitmaskclient.Provider; -import se.leap.bitmaskclient.R; - -import static android.view.View.VISIBLE; - -/** - * Implements the log in dialog, currently without progress dialog. - *

- * It returns to the previous fragment when finished, and sends username and password to the authenticate method. - *

- * It also notifies the user if the password is not valid. - * - * @author parmegv - */ -public class SessionDialog extends DialogFragment { - - - final public static String TAG = SessionDialog.class.getSimpleName(); - - final public static String USERNAME = "username"; - final public static String PASSWORD = "password"; - - public enum ERRORS { - USERNAME_MISSING, - PASSWORD_INVALID_LENGTH, - RISEUP_WARNING - } - - @InjectView(R.id.user_message) - TextView userMessage; - @InjectView(R.id.username_entered) - EditText usernameField; - @InjectView(R.id.password_entered) - EditText passwordField; - - public static SessionDialog getInstance(Provider provider, Bundle arguments) { - SessionDialog dialog = new SessionDialog(); - if (provider.getName().equalsIgnoreCase("riseup")) { - arguments = - arguments == Bundle.EMPTY ? - new Bundle() : arguments; - arguments.putBoolean(SessionDialog.ERRORS.RISEUP_WARNING.toString(), true); - } - if (arguments != null && !arguments.isEmpty()) { - dialog.setArguments(arguments); - } - return dialog; - } - - public AlertDialog onCreateDialog(Bundle savedInstanceState) { - - AlertDialog.Builder builder = new AlertDialog.Builder(getActivity()); - LayoutInflater inflater = getActivity().getLayoutInflater(); - View view = inflater.inflate(R.layout.session_dialog, null); - ButterKnife.inject(this, view); - - Bundle arguments = getArguments(); - if (arguments != Bundle.EMPTY && arguments != null) { - setUp(arguments); - } - - builder.setView(view) - .setPositiveButton(R.string.login_button, new DialogInterface.OnClickListener() { - public void onClick(DialogInterface dialog, int id) { - String username = getEnteredUsername(); - String password = getEnteredPassword(); - dialog.dismiss(); - interface_with_Dashboard.logIn(username, password); - } - }) - .setNegativeButton(R.string.cancel, new DialogInterface.OnClickListener() { - public void onClick(DialogInterface dialog, int id) { - dialog.cancel(); - } - }) - .setNeutralButton(R.string.signup_button, new DialogInterface.OnClickListener() { - public void onClick(DialogInterface dialog, int id) { - String username = getEnteredUsername(); - String password = getEnteredPassword(); - dialog.dismiss(); - interface_with_Dashboard.signUp(username, password); - } - }); - - return builder.create(); - } - - private void setUp(Bundle arguments) { - if (arguments.containsKey(ERRORS.PASSWORD_INVALID_LENGTH.toString())) - passwordField.setError(getString(R.string.error_not_valid_password_user_message)); - else if (arguments.containsKey(ERRORS.RISEUP_WARNING.toString())) { - userMessage.setVisibility(VISIBLE); - userMessage.setText(R.string.login_riseup_warning); - } - if (arguments.containsKey(USERNAME)) { - String username = arguments.getString(USERNAME); - usernameField.setText(username); - } - if (arguments.containsKey(ERRORS.USERNAME_MISSING.toString())) { - usernameField.setError(getString(R.string.username_ask)); - } - if (arguments.containsKey(getString(R.string.user_message))) { - userMessage.setText(arguments.getString(getString(R.string.user_message))); - userMessage.setVisibility(VISIBLE); - } else if (userMessage.getVisibility() != VISIBLE) - userMessage.setVisibility(View.GONE); - - if (!usernameField.getText().toString().isEmpty() && passwordField.isFocusable()) - passwordField.requestFocus(); - - } - - private String getEnteredUsername() { - return usernameField.getText().toString(); - } - - private String getEnteredPassword() { - return passwordField.getText().toString(); - } - - - /** - * Interface used to communicate SessionDialog with Dashboard. - * - * @author parmegv - */ - public interface SessionDialogInterface { - void logIn(String username, String password); - - void signUp(String username, String password); - - } - - SessionDialogInterface interface_with_Dashboard; - - @Override - public void onAttach(Context context) { - super.onAttach(context); - - try { - interface_with_Dashboard = (SessionDialogInterface) ((AppCompatActivity) context).getSupportFragmentManager().getFragments().get(0); - } catch (ClassCastException e) { - throw new ClassCastException(context.toString() - + " must implement LogInDialogListener"); - } - } - -} diff --git a/app/src/main/java/se/leap/bitmaskclient/userstatus/UserStatusFragment.java b/app/src/main/java/se/leap/bitmaskclient/userstatus/UserStatusFragment.java index 0f1d0cdb..70da20ac 100644 --- a/app/src/main/java/se/leap/bitmaskclient/userstatus/UserStatusFragment.java +++ b/app/src/main/java/se/leap/bitmaskclient/userstatus/UserStatusFragment.java @@ -17,18 +17,19 @@ import java.util.Observer; import butterknife.ButterKnife; import butterknife.InjectView; import butterknife.OnClick; -import se.leap.bitmaskclient.MainActivity; import se.leap.bitmaskclient.Provider; import se.leap.bitmaskclient.ProviderAPI; import se.leap.bitmaskclient.ProviderAPICommand; import se.leap.bitmaskclient.ProviderAPIResultReceiver; import se.leap.bitmaskclient.R; -public class UserStatusFragment extends Fragment implements Observer, SessionDialog.SessionDialogInterface { +public class UserStatusFragment extends Fragment implements Observer { public static String TAG = UserStatusFragment.class.getSimpleName(); private ProviderAPIResultReceiver providerAPI_result_receiver; + private Provider provider; + @InjectView(R.id.user_status_username) TextView username; @InjectView(R.id.user_status_icon) @@ -87,8 +88,8 @@ public class UserStatusFragment extends Fragment implements Observer, SessionDia android.util.Log.d(TAG, status.toString()); if(status.isLoggedIn()) logOut(); - else if(status.isLoggedOut()) - MainActivity.sessionDialog(Bundle.EMPTY); + //else if(status.isLoggedOut()) + //MainActivity.sessionDialog(Bundle.EMPTY); else if(status.inProgress()) cancelLoginOrSignup(); } @@ -143,33 +144,13 @@ public class UserStatusFragment extends Fragment implements Observer, SessionDia } - @Override - public void signUp(String username, String password) { - User.setUserName(username); - Bundle parameters = bundlePassword(password); - ProviderAPICommand.execute(parameters, ProviderAPI.SIGN_UP, providerAPI_result_receiver); - } - - @Override - public void logIn(String username, String password) { - User.setUserName(username); - Bundle parameters = bundlePassword(password); - ProviderAPICommand.execute(parameters, ProviderAPI.LOG_IN, providerAPI_result_receiver); - } - public void logOut() { android.util.Log.d(TAG, "Log out"); - ProviderAPICommand.execute(Bundle.EMPTY, ProviderAPI.LOG_OUT, providerAPI_result_receiver); + ProviderAPICommand.execute(getActivity(), ProviderAPI.LOG_OUT, provider, providerAPI_result_receiver); } public void cancelLoginOrSignup() { //EipStatus.getInstance().setConnectedOrDisconnected(); } - private Bundle bundlePassword(String password) { - Bundle parameters = new Bundle(); - if (!password.isEmpty()) - parameters.putString(SessionDialog.PASSWORD, password); - return parameters; - } } diff --git a/app/src/production/java/se/leap/bitmaskclient/ProviderApiManager.java b/app/src/production/java/se/leap/bitmaskclient/ProviderApiManager.java index a30c9615..ac58d005 100644 --- a/app/src/production/java/se/leap/bitmaskclient/ProviderApiManager.java +++ b/app/src/production/java/se/leap/bitmaskclient/ProviderApiManager.java @@ -33,13 +33,10 @@ import okhttp3.OkHttpClient; import se.leap.bitmaskclient.eip.EIP; import static android.text.TextUtils.isEmpty; -import static se.leap.bitmaskclient.Constants.PROVIDER_ALLOWED_REGISTERED; -import static se.leap.bitmaskclient.Constants.PROVIDER_ALLOW_ANONYMOUS; -import static se.leap.bitmaskclient.Constants.PROVIDER_KEY; +import static se.leap.bitmaskclient.Constants.BROADCAST_RESULT_KEY; import static se.leap.bitmaskclient.Constants.PROVIDER_VPN_CERTIFICATE; import static se.leap.bitmaskclient.DownloadFailedDialog.DOWNLOAD_ERRORS.ERROR_CERTIFICATE_PINNING; import static se.leap.bitmaskclient.ProviderAPI.ERRORS; -import static se.leap.bitmaskclient.ProviderAPI.RESULT_KEY; import static se.leap.bitmaskclient.R.string.malformed_url; import static se.leap.bitmaskclient.R.string.warning_corrupted_provider_cert; @@ -66,45 +63,23 @@ public class ProviderApiManager extends 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. - * @return a bundle with a boolean value mapped to a key named RESULT_KEY, and which is true if the update was successful. + * @return a bundle with a boolean value mapped to a key named BROADCAST_RESULT_KEY, and which is true if the update was successful. */ @Override - protected Bundle setUpProvider(Bundle task) { + protected Bundle setUpProvider(Provider provider, Bundle task) { int progress = 0; Bundle currentDownload = new Bundle(); if (task != null) { - //FIXME: this should be refactored in order to avoid static variables all over here - lastProviderMainUrl = task.containsKey(Provider.MAIN_URL) ? - task.getString(Provider.MAIN_URL) : - ""; - - if (isEmpty(lastProviderMainUrl)) { - currentDownload.putBoolean(RESULT_KEY, false); + String mainUrlString = provider.getMainUrlString(); + if (isEmpty(mainUrlString)) { + currentDownload.putBoolean(BROADCAST_RESULT_KEY, false); setErrorResult(currentDownload, malformed_url, null); return currentDownload; } - //TODO: remove that - providerCaCertFingerprint = task.containsKey(Provider.CA_CERT_FINGERPRINT) ? - task.getString(Provider.CA_CERT_FINGERPRINT) : - ""; - providerCaCert = task.containsKey(Provider.CA_CERT) ? - task.getString(Provider.CA_CERT) : - ""; - - try { - providerDefinition = task.containsKey(Provider.KEY) ? - new JSONObject(task.getString(Provider.KEY)) : - new JSONObject(); - } catch (JSONException e) { - e.printStackTrace(); - providerDefinition = new JSONObject(); - } - providerApiUrl = getApiUrlWithVersion(providerDefinition); - - checkPersistedProviderUpdates(); - currentDownload = validateProviderDetails(); + getPersistedProviderUpdates(provider); + currentDownload = validateProviderDetails(provider); //provider details invalid if (currentDownload.containsKey(ERRORS)) { @@ -112,29 +87,26 @@ public class ProviderApiManager extends ProviderApiManagerBase { } //no provider certificate available - if (currentDownload.containsKey(RESULT_KEY) && !currentDownload.getBoolean(RESULT_KEY)) { - resetProviderDetails(); + if (currentDownload.containsKey(BROADCAST_RESULT_KEY) && !currentDownload.getBoolean(BROADCAST_RESULT_KEY)) { + resetProviderDetails(provider); } - EIP_SERVICE_JSON_DOWNLOADED = false; go_ahead = true; } - if (!PROVIDER_JSON_DOWNLOADED) - currentDownload = getAndSetProviderJson(lastProviderMainUrl, providerCaCert, providerDefinition); - if (PROVIDER_JSON_DOWNLOADED || (currentDownload.containsKey(RESULT_KEY) && currentDownload.getBoolean(RESULT_KEY))) { + if (!provider.hasDefinition()) { + currentDownload = getAndSetProviderJson(provider); + } + if (provider.hasDefinition() || (currentDownload.containsKey(BROADCAST_RESULT_KEY) && currentDownload.getBoolean(BROADCAST_RESULT_KEY))) { broadcastProgress(++progress); - PROVIDER_JSON_DOWNLOADED = true; - if (!CA_CERT_DOWNLOADED) - currentDownload = downloadCACert(); - if (CA_CERT_DOWNLOADED || (currentDownload.containsKey(RESULT_KEY) && currentDownload.getBoolean(RESULT_KEY))) { + if (!provider.hasCaCert()) + currentDownload = downloadCACert(provider); + if (provider.hasCaCert() || (currentDownload.containsKey(BROADCAST_RESULT_KEY) && currentDownload.getBoolean(BROADCAST_RESULT_KEY))) { broadcastProgress(++progress); - CA_CERT_DOWNLOADED = true; - currentDownload = getAndSetEipServiceJson(); - if (currentDownload.containsKey(RESULT_KEY) && currentDownload.getBoolean(RESULT_KEY)) { + currentDownload = getAndSetEipServiceJson(provider); + if (currentDownload.containsKey(BROADCAST_RESULT_KEY) && currentDownload.getBoolean(BROADCAST_RESULT_KEY)) { broadcastProgress(++progress); - EIP_SERVICE_JSON_DOWNLOADED = true; } } } @@ -143,13 +115,16 @@ public class ProviderApiManager extends ProviderApiManagerBase { } - private Bundle getAndSetProviderJson(String providerMainUrl, String caCert, JSONObject providerDefinition) { + private Bundle getAndSetProviderJson(Provider provider) { Bundle result = new Bundle(); + String caCert = provider.getCaCert(); + JSONObject providerDefinition = provider.getDefinition(); + if (go_ahead) { String providerDotJsonString; if(providerDefinition.length() == 0 || caCert.isEmpty()) - providerDotJsonString = downloadWithCommercialCA(providerMainUrl + "/provider.json"); + providerDotJsonString = downloadWithCommercialCA(provider); else { providerDotJsonString = downloadFromApiUrlWithProviderCA("/provider.json", caCert, providerDefinition); } @@ -161,20 +136,13 @@ public class ProviderApiManager extends ProviderApiManagerBase { try { JSONObject providerJson = new JSONObject(providerDotJsonString); - String providerDomain = getDomainFromMainURL(lastProviderMainUrl); - providerApiUrl = getApiUrlWithVersion(providerJson); - //String name = providerJson.getString(Provider.NAME); - //TODO setProviderName(name); - - 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(RESULT_KEY, true); + provider.define(providerJson); + + result.putBoolean(BROADCAST_RESULT_KEY, true); } catch (JSONException e) { String reason_to_fail = pickErrorMessage(providerDotJsonString); result.putString(ERRORS, reason_to_fail); - result.putBoolean(RESULT_KEY, false); + result.putBoolean(BROADCAST_RESULT_KEY, false); } } return result; @@ -182,27 +150,27 @@ public class ProviderApiManager extends ProviderApiManagerBase { /** * Downloads the eip-service.json from a given URL, and saves eip service capabilities including the offered gateways - * @return a bundle with a boolean value mapped to a key named RESULT_KEY, and which is true if the download was successful. + * @return a bundle with a boolean value mapped to a key named BROADCAST_RESULT_KEY, and which is true if the download was successful. */ @Override - protected Bundle getAndSetEipServiceJson() { + protected Bundle getAndSetEipServiceJson(Provider provider) { Bundle result = new Bundle(); - String eip_service_json_string = ""; + String eipServiceJsonString = ""; if (go_ahead) { try { - JSONObject provider_json = new JSONObject(preferences.getString(Provider.KEY, "")); - String eip_service_url = provider_json.getString(Provider.API_URL) + "/" + provider_json.getString(Provider.API_VERSION) + "/" + EIP.SERVICE_API_PATH; - eip_service_json_string = downloadWithProviderCA(eip_service_url); - JSONObject eip_service_json = new JSONObject(eip_service_json_string); - eip_service_json.getInt(Provider.API_RETURN_SERIAL); + JSONObject provider_json = provider.getDefinition(); + String eipServiceUrl = provider_json.getString(Provider.API_URL) + "/" + provider_json.getString(Provider.API_VERSION) + "/" + EIP.SERVICE_API_PATH; + eipServiceJsonString = downloadWithProviderCA(provider.getCaCert(), eipServiceUrl); + JSONObject eipServiceJson = new JSONObject(eipServiceJsonString); + eipServiceJson.getInt(Provider.API_RETURN_SERIAL); - preferences.edit().putString(PROVIDER_KEY, eip_service_json.toString()).commit(); + provider.setEipServiceJson(eipServiceJson); - result.putBoolean(RESULT_KEY, true); + result.putBoolean(BROADCAST_RESULT_KEY, true); } catch (NullPointerException | JSONException e) { - String reason_to_fail = pickErrorMessage(eip_service_json_string); + String reason_to_fail = pickErrorMessage(eipServiceJsonString); result.putString(ERRORS, reason_to_fail); - result.putBoolean(RESULT_KEY, false); + result.putBoolean(BROADCAST_RESULT_KEY, false); } } return result; @@ -214,14 +182,13 @@ 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() { + protected boolean updateVpnCertificate(Provider provider) { try { - JSONObject provider_json = new JSONObject(preferences.getString(Provider.KEY, "")); - - String provider_main_url = provider_json.getString(Provider.API_URL); - URL new_cert_string_url = new URL(provider_main_url + "/" + provider_json.getString(Provider.API_VERSION) + "/" + PROVIDER_VPN_CERTIFICATE); + JSONObject providerJson = provider.getDefinition(); + String provider_main_url = providerJson.getString(Provider.API_URL); + URL newCertStringUrl = new URL(provider_main_url + "/" + providerJson.getString(Provider.API_VERSION) + "/" + PROVIDER_VPN_CERTIFICATE); - String cert_string = downloadWithProviderCA(new_cert_string_url.toString()); + String cert_string = downloadWithProviderCA(provider.getCaCert(), newCertStringUrl.toString()); if (ConfigHelper.checkErroneousDownload(cert_string)) return false; @@ -238,23 +205,17 @@ public class ProviderApiManager extends ProviderApiManagerBase { } } - private Bundle downloadCACert() { + private Bundle downloadCACert(Provider provider) { Bundle result = new Bundle(); - try { - JSONObject providerJson = new JSONObject(preferences.getString(Provider.KEY, "")); - String caCertUrl = providerJson.getString(Provider.CA_CERT_URI); - String providerDomain = getDomainFromMainURL(lastProviderMainUrl); - String cert_string = downloadWithCommercialCA(caCertUrl); - - if (validCertificate(cert_string) && go_ahead) { - preferences.edit().putString(Provider.CA_CERT, cert_string).commit(); - preferences.edit().putString(Provider.CA_CERT + "." + providerDomain, cert_string).commit(); - result.putBoolean(RESULT_KEY, true); - } else { - setErrorResult(result, warning_corrupted_provider_cert, ERROR_CERTIFICATE_PINNING.toString()); - } - } catch (JSONException e) { - setErrorResult(result, malformed_url, null); + 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()); } return result; @@ -263,10 +224,9 @@ public class ProviderApiManager extends ProviderApiManagerBase { /** * Tries to download the contents of the provided url using commercially validated CA certificate from chosen provider. * - * @param string_url - * @return */ - private String downloadWithCommercialCA(String string_url) { + private String downloadWithCommercialCA(Provider provider) { + String stringUrl = provider.getMainUrlString() + "/provider.json"; String responseString; JSONObject errorJson = new JSONObject(); @@ -277,14 +237,14 @@ public class ProviderApiManager extends ProviderApiManagerBase { List> 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 (responseErrorJson.getString(ERRORS).equals(resources.getString(R.string.certificate_error))) { - responseString = downloadWithProviderCA(string_url); + responseString = downloadWithProviderCA(provider.getCaCert(), stringUrl); } } catch (JSONException e) { e.printStackTrace(); @@ -324,11 +284,11 @@ public class ProviderApiManager extends ProviderApiManagerBase { * @param urlString as a string * @return an empty string if it fails, the url content if not. */ - private String downloadWithProviderCA(String urlString) { + private String downloadWithProviderCA(String caCert, String urlString) { JSONObject initError = new JSONObject(); String responseString; - OkHttpClient okHttpClient = clientGenerator.initSelfSignedCAHttpClient(initError); + OkHttpClient okHttpClient = clientGenerator.initSelfSignedCAHttpClient(caCert, initError); if (okHttpClient == null) { return initError.toString(); } diff --git a/app/src/production/java/se/leap/bitmaskclient/ProviderListActivity.java b/app/src/production/java/se/leap/bitmaskclient/ProviderListActivity.java index 8c008024..921b42e1 100644 --- a/app/src/production/java/se/leap/bitmaskclient/ProviderListActivity.java +++ b/app/src/production/java/se/leap/bitmaskclient/ProviderListActivity.java @@ -22,6 +22,8 @@ import android.os.Bundle; import java.net.MalformedURLException; import java.net.URL; +import static se.leap.bitmaskclient.ProviderAPI.SET_UP_PROVIDER; + /** * Activity that builds and shows the list of known available providers. *

@@ -61,43 +63,19 @@ public class ProviderListActivity extends ProviderListBaseActivity { */ public void setUpProvider() { mConfigState.setAction(SETTING_UP_PROVIDER); - Intent providerApiCommand = new Intent(this, ProviderAPI.class); - Bundle parameters = new Bundle(); - parameters.putString(Provider.MAIN_URL, provider.getMainUrl().toString()); - if (provider.hasCertificatePin()){ - parameters.putString(Provider.CA_CERT_FINGERPRINT, provider.certificatePin()); - } - if (provider.hasCaCert()) { - parameters.putString(Provider.CA_CERT, provider.getCaCert()); - } - if (provider.hasDefinition()) { - parameters.putString(Provider.KEY, provider.getDefinition().toString()); - } - - providerApiCommand.setAction(ProviderAPI.SET_UP_PROVIDER); - providerApiCommand.putExtra(ProviderAPI.PARAMETERS, parameters); - - startService(providerApiCommand); + ProviderAPICommand.execute(this, SET_UP_PROVIDER, provider); } @Override - public void retrySetUpProvider() { + public void retrySetUpProvider(Provider provider) { cancelSettingUpProvider(); - if (!ProviderAPI.caCertDownloaded()) { - addAndSelectNewProvider(ProviderAPI.lastProviderMainUrl()); + if (!provider.hasCaCert()) { + addAndSelectNewProvider(provider.getMainUrlString()); } else { showProgressBar(); adapter.hideAllBut(adapter.indexOf(provider)); - - Intent providerApiCommand = new Intent(this, ProviderAPI.class); - providerApiCommand.setAction(ProviderAPI.SET_UP_PROVIDER); - providerApiCommand.putExtra(ProviderAPI.RECEIVER_KEY, providerAPIResultReceiver); - Bundle parameters = new Bundle(); - parameters.putString(Provider.MAIN_URL, provider.getMainUrl().toString()); - providerApiCommand.putExtra(ProviderAPI.PARAMETERS, parameters); - - startService(providerApiCommand); + ProviderAPICommand.execute(this, SET_UP_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 f04ec0eb..a6f30393 100644 --- a/app/src/test/java/se/leap/bitmaskclient/eip/ProviderApiManagerTest.java +++ b/app/src/test/java/se/leap/bitmaskclient/eip/ProviderApiManagerTest.java @@ -38,6 +38,7 @@ 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; @@ -45,10 +46,10 @@ import se.leap.bitmaskclient.ProviderApiManager; 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.ProviderAPI.ERRORS; import static se.leap.bitmaskclient.ProviderAPI.PROVIDER_NOK; import static se.leap.bitmaskclient.ProviderAPI.PROVIDER_OK; -import static se.leap.bitmaskclient.ProviderAPI.RESULT_KEY; 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; @@ -108,18 +109,18 @@ public class ProviderApiManagerTest { public void test_handleIntentSetupProvider_noProviderMainURL() { providerApiManager = new ProviderApiManager(mockPreferences, mockResources, mockClientGenerator(), new TestProviderApiServiceCallback()); Bundle expectedResult = mockBundle(); - expectedResult.putBoolean(RESULT_KEY, false); + expectedResult.putBoolean(BROADCAST_RESULT_KEY, false); expectedResult.putString(ERRORS, "{\"errors\":\"It doesn't seem to be a Bitmask provider.\"}"); - Intent provider_API_command = mockIntent(); + Intent providerApiCommand = mockIntent(); Bundle parameters = mockBundle(); parameters.putString(Provider.MAIN_URL, ""); - 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.PARAMETERS, parameters); + providerApiCommand.putExtra(ProviderAPI.RECEIVER_KEY, mockResultReceiver(PROVIDER_NOK, expectedResult)); - providerApiManager.handleIntent(provider_API_command); + providerApiManager.handleIntent(providerApiCommand); } @Test @@ -128,7 +129,7 @@ public class ProviderApiManagerTest { mockProviderApiConnector(NO_ERROR); providerApiManager = new ProviderApiManager(mockPreferences, mockResources, mockClientGenerator(), new TestProviderApiServiceCallback()); Bundle expectedResult = mockBundle(); - expectedResult.putBoolean(RESULT_KEY, true); + expectedResult.putBoolean(BROADCAST_RESULT_KEY, true); Intent provider_API_command = mockIntent(); Bundle parameters = mockBundle(); @@ -149,7 +150,7 @@ public class ProviderApiManagerTest { mockProviderApiConnector(NO_ERROR); providerApiManager = new ProviderApiManager(mockPreferences, mockResources, mockClientGenerator(), new TestProviderApiServiceCallback()); Bundle expectedResult = mockBundle(); - expectedResult.putBoolean(RESULT_KEY, true); + expectedResult.putBoolean(BROADCAST_RESULT_KEY, true); Intent provider_API_command = mockIntent(); Bundle parameters = mockBundle(); @@ -170,7 +171,7 @@ public class ProviderApiManagerTest { 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(RESULT_KEY, true); + expectedResult.putBoolean(BROADCAST_RESULT_KEY, true); Intent provider_API_command = mockIntent(); Bundle parameters = mockBundle(); @@ -189,7 +190,7 @@ public class ProviderApiManagerTest { mockProviderApiConnector(NO_ERROR); providerApiManager = new ProviderApiManager(mockPreferences, mockResources, mockClientGenerator(), new TestProviderApiServiceCallback()); Bundle expectedResult = mockBundle(); - expectedResult.putBoolean(RESULT_KEY, false); + 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.\"}"); Intent provider_API_command = mockIntent(); @@ -211,7 +212,7 @@ public class ProviderApiManagerTest { mockProviderApiConnector(NO_ERROR); providerApiManager = new ProviderApiManager(mockPreferences, mockResources, mockClientGenerator(), new TestProviderApiServiceCallback()); Bundle expectedResult = mockBundle(); - expectedResult.putBoolean(RESULT_KEY, false); + 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.\"}"); Intent provider_API_command = mockIntent(); @@ -233,7 +234,7 @@ public class ProviderApiManagerTest { 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(RESULT_KEY, false); + 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.\"}"); Intent provider_API_command = mockIntent(); @@ -253,7 +254,7 @@ public class ProviderApiManagerTest { mockProviderApiConnector(NO_ERROR); providerApiManager = new ProviderApiManager(mockPreferences, mockResources, mockClientGenerator(), new TestProviderApiServiceCallback()); Bundle expectedResult = mockBundle(); - expectedResult.putBoolean(RESULT_KEY, false); + 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.\"}"); Intent provider_API_command = mockIntent(); @@ -276,7 +277,7 @@ public class ProviderApiManagerTest { 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(RESULT_KEY, false); + 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.\"}"); Intent provider_API_command = mockIntent(); @@ -297,7 +298,7 @@ public class ProviderApiManagerTest { providerApiManager = new ProviderApiManager(mockPreferences, mockResources, mockClientGenerator(), new TestProviderApiServiceCallback()); Bundle expectedResult = mockBundle(); - expectedResult.putBoolean(RESULT_KEY, false); + 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.\"}"); Intent provider_API_command = mockIntent(); @@ -321,7 +322,7 @@ public class ProviderApiManagerTest { 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(RESULT_KEY, false); + 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.\"}"); Intent provider_API_command = mockIntent(); diff --git a/app/src/test/java/se/leap/bitmaskclient/testutils/TestSetupHelper.java b/app/src/test/java/se/leap/bitmaskclient/testutils/TestSetupHelper.java index f8f70eaf..99febeb3 100644 --- a/app/src/test/java/se/leap/bitmaskclient/testutils/TestSetupHelper.java +++ b/app/src/test/java/se/leap/bitmaskclient/testutils/TestSetupHelper.java @@ -388,7 +388,7 @@ public class TestSetupHelper { OkHttpClientGenerator mockClientGenerator = mock(OkHttpClientGenerator.class); OkHttpClient mockedOkHttpClient = mock(OkHttpClient.class); when(mockClientGenerator.initCommercialCAHttpClient(any(JSONObject.class))).thenReturn(mockedOkHttpClient); - when(mockClientGenerator.initSelfSignedCAHttpClient(any(JSONObject.class))).thenReturn(mockedOkHttpClient); + when(mockClientGenerator.initSelfSignedCAHttpClient(anyString(), any(JSONObject.class))).thenReturn(mockedOkHttpClient); when(mockClientGenerator.initSelfSignedCAHttpClient(any(JSONObject.class), anyString())).thenReturn(mockedOkHttpClient); return mockClientGenerator; } -- cgit v1.2.3 From 8bb96b0116994897ca75ad8eb1d6c412e7d3ce40 Mon Sep 17 00:00:00 2001 From: Fup Duck Date: Tue, 6 Feb 2018 17:43:37 +0100 Subject: 8827 add EipCommand --- .../java/se/leap/bitmaskclient/eip/EipCommand.java | 66 ++++++++++++++++++++++ 1 file changed, 66 insertions(+) create mode 100644 app/src/main/java/se/leap/bitmaskclient/eip/EipCommand.java diff --git a/app/src/main/java/se/leap/bitmaskclient/eip/EipCommand.java b/app/src/main/java/se/leap/bitmaskclient/eip/EipCommand.java new file mode 100644 index 00000000..35599ab4 --- /dev/null +++ b/app/src/main/java/se/leap/bitmaskclient/eip/EipCommand.java @@ -0,0 +1,66 @@ +package se.leap.bitmaskclient.eip; + +import android.content.Context; +import android.content.Intent; +import android.os.ResultReceiver; + +import org.jetbrains.annotations.NotNull; +import org.jetbrains.annotations.Nullable; + +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; + +/** + * Use this class to send commands to EIP + */ + +public class EipCommand { + + public static void execute(@NotNull Context context, @NotNull String action) { + execute(context, action, null); + } + + /** + * Send a command to EIP + * @param context the context to start the command from + * @param action A valid String constant from EIP class representing an Intent + * filter for the EIP class + * @param resultReceiver The resultreceiver to reply to + */ + public static void execute(@NotNull Context context, @NotNull String action, @Nullable ResultReceiver resultReceiver) { + // TODO validate "action"...how do we get the list of intent-filters for a class via Android API? + Intent vpnIntent = new Intent(context.getApplicationContext(), EIP.class); + vpnIntent.setAction(action); + if (resultReceiver != null) + vpnIntent.putExtra(EIP_RECEIVER, resultReceiver); + context.startService(vpnIntent); + } + + public static void updateEipService(Context context, ResultReceiver resultReceiver) { + execute(context, EIP_ACTION_UPDATE, resultReceiver); + } + + public static void updateEipService(Context context) { + execute(context, EIP_ACTION_UPDATE); + } + + public static void startVPN(Context context) { + execute(context, EIP_ACTION_START); + } + + public static void startVPN(Context context, ResultReceiver resultReceiver) { + execute(context, EIP_ACTION_START, resultReceiver); + } + + + public static void stopVPN(Context context) { + execute(context, EIP_ACTION_STOP); + } + + public static void stopVPN(Context context, ResultReceiver resultReceiver) { + execute(context, EIP_ACTION_STOP, resultReceiver); + } + +} -- cgit v1.2.3 From 8f7f89e757f0ac8f7a2da54d2001bb2ff88269cc Mon Sep 17 00:00:00 2001 From: Fup Duck Date: Thu, 8 Feb 2018 14:34:20 +0100 Subject: 8827 - fix tests --- .../se/leap/bitmaskclient/ProviderApiManager.java | 58 +++--- .../java/se/leap/bitmaskclient/ConfigHelper.java | 8 +- .../main/java/se/leap/bitmaskclient/Dashboard.java | 2 +- .../main/java/se/leap/bitmaskclient/Provider.java | 22 +- .../leap/bitmaskclient/ProviderApiManagerBase.java | 15 +- .../se/leap/bitmaskclient/ProviderApiManager.java | 74 ++++--- .../bitmaskclient/eip/ProviderApiManagerTest.java | 229 ++++++++++++--------- 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. *

- * 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> 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); } } -- cgit v1.2.3 From 245ec90f0d61c6be3be7e74bd64146572ce37c9c Mon Sep 17 00:00:00 2001 From: Fup Duck Date: Thu, 8 Feb 2018 14:37:08 +0100 Subject: 8827 - add null check --- .../java/se/leap/bitmaskclient/AbstractProviderDetailActivity.java | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/app/src/main/java/se/leap/bitmaskclient/AbstractProviderDetailActivity.java b/app/src/main/java/se/leap/bitmaskclient/AbstractProviderDetailActivity.java index cdb314aa..9826b89b 100644 --- a/app/src/main/java/se/leap/bitmaskclient/AbstractProviderDetailActivity.java +++ b/app/src/main/java/se/leap/bitmaskclient/AbstractProviderDetailActivity.java @@ -35,6 +35,10 @@ public abstract class AbstractProviderDetailActivity extends ConfigWizardBaseAct provider = getIntent().getParcelableExtra(PROVIDER_KEY); setContentView(R.layout.a_provider_detail); + if (provider == null) { + return; + } + setProviderHeaderText(provider.getName()); description.setText(provider.getDescription()); -- cgit v1.2.3 From 9e6fe0e215e32343b38cdf20080de209a31287dd Mon Sep 17 00:00:00 2001 From: Fup Duck Date: Fri, 9 Feb 2018 12:46:06 +0100 Subject: 8827 - merge request discussions * add NullPointer checks to EipFragment * add Provider to DownloadFailedDialog * remove unused code * store certificates for pinning in SharedPreferences --- .../se/leap/bitmaskclient/ProviderApiManager.java | 6 +- .../leap/bitmaskclient/ProviderListActivity.java | 3 +- .../java/se/leap/bitmaskclient/ConfigHelper.java | 10 ++ .../leap/bitmaskclient/DownloadFailedDialog.java | 36 ++-- .../java/se/leap/bitmaskclient/EipFragment.java | 186 +++++++++++++-------- .../leap/bitmaskclient/OkHttpClientGenerator.java | 5 - .../leap/bitmaskclient/ProviderApiManagerBase.java | 4 +- .../bitmaskclient/ProviderListBaseActivity.java | 7 +- .../se/leap/bitmaskclient/ProviderApiManager.java | 3 +- .../leap/bitmaskclient/ProviderListActivity.java | 3 +- .../leap/bitmaskclient/testutils/MockHelper.java | 1 - 11 files changed, 157 insertions(+), 107 deletions(-) diff --git a/app/src/insecure/java/se/leap/bitmaskclient/ProviderApiManager.java b/app/src/insecure/java/se/leap/bitmaskclient/ProviderApiManager.java index 83a3044e..624b797b 100644 --- a/app/src/insecure/java/se/leap/bitmaskclient/ProviderApiManager.java +++ b/app/src/insecure/java/se/leap/bitmaskclient/ProviderApiManager.java @@ -174,10 +174,8 @@ public class ProviderApiManager extends ProviderApiManagerBase { JSONObject providerDefinition = provider.getDefinition(); String eipServiceUrl = providerDefinition.getString(Provider.API_URL) + "/" + providerDefinition.getString(Provider.API_VERSION) + "/" + EIP.SERVICE_API_PATH; eipServiceJsonString = downloadWithProviderCA(provider.getCaCert(), eipServiceUrl, lastDangerOn); - JSONObject eipServiceJson = new JSONObject(eipServiceJsonString); - eipServiceJson.getInt(Provider.API_RETURN_SERIAL); - //preferences.edit().putString(PROVIDER_KEY, eipServiceJson.toString()).commit(); + JSONObject eipServiceJson = new JSONObject(eipServiceJsonString); provider.setEipServiceJson(eipServiceJson); result.putBoolean(BROADCAST_RESULT_KEY, true); @@ -285,7 +283,7 @@ public class ProviderApiManager extends ProviderApiManagerBase { String responseString; JSONObject errorJson = new JSONObject(); String baseUrl = getApiUrl(providerDefinition); - OkHttpClient okHttpClient = clientGenerator.initSelfSignedCAHttpClient(errorJson, caCert); + OkHttpClient okHttpClient = clientGenerator.initSelfSignedCAHttpClient(caCert, errorJson); if (okHttpClient == null) { return errorJson.toString(); } diff --git a/app/src/insecure/java/se/leap/bitmaskclient/ProviderListActivity.java b/app/src/insecure/java/se/leap/bitmaskclient/ProviderListActivity.java index 554085b1..531c438a 100644 --- a/app/src/insecure/java/se/leap/bitmaskclient/ProviderListActivity.java +++ b/app/src/insecure/java/se/leap/bitmaskclient/ProviderListActivity.java @@ -17,6 +17,7 @@ package se.leap.bitmaskclient; import android.os.Bundle; +import android.support.annotation.NonNull; import android.support.v4.app.DialogFragment; import android.support.v4.app.FragmentTransaction; @@ -99,7 +100,7 @@ public class ProviderListActivity extends ProviderListBaseActivity { * Retrys setup of last used provider, allows bypassing ca certificate validation. */ @Override - public void retrySetUpProvider(Provider provider) { + public void retrySetUpProvider(@NonNull Provider provider) { cancelSettingUpProvider(); if (!provider.hasCaCert()) { addAndSelectNewProvider(provider.getMainUrlString(), ProviderAPI.lastDangerOn()); diff --git a/app/src/main/java/se/leap/bitmaskclient/ConfigHelper.java b/app/src/main/java/se/leap/bitmaskclient/ConfigHelper.java index 5a97624d..2e9e1897 100644 --- a/app/src/main/java/se/leap/bitmaskclient/ConfigHelper.java +++ b/app/src/main/java/se/leap/bitmaskclient/ConfigHelper.java @@ -16,6 +16,7 @@ */ package se.leap.bitmaskclient; +import android.annotation.SuppressLint; import android.content.SharedPreferences; import android.support.annotation.NonNull; import android.support.annotation.Nullable; @@ -348,6 +349,7 @@ public class ConfigHelper { } } + // TODO: replace commit with apply after refactoring EIP public static void storeProviderInPreferences(SharedPreferences preferences, Provider provider) { preferences.edit().putBoolean(PROVIDER_CONFIGURED, true). putString(Provider.MAIN_URL, provider.getMainUrlString()). @@ -355,6 +357,14 @@ public class ConfigHelper { putString(Provider.CA_CERT, provider.getCaCert()). putString(PROVIDER_KEY, provider.getEipServiceJsonString()). commit(); + + String providerDomain = provider.getDomain(); + preferences.edit().putBoolean(PROVIDER_CONFIGURED, true). + putString(Provider.MAIN_URL + "." + providerDomain, provider.getMainUrlString()). + putString(Provider.KEY + "." + providerDomain, provider.getDefinitionString()). + putString(Provider.CA_CERT + "." + providerDomain, provider.getCaCert()). + putString(PROVIDER_KEY + "." + providerDomain, provider.getEipServiceJsonString()). + apply(); } diff --git a/app/src/main/java/se/leap/bitmaskclient/DownloadFailedDialog.java b/app/src/main/java/se/leap/bitmaskclient/DownloadFailedDialog.java index 1a0c85ad..8d56cdf8 100644 --- a/app/src/main/java/se/leap/bitmaskclient/DownloadFailedDialog.java +++ b/app/src/main/java/se/leap/bitmaskclient/DownloadFailedDialog.java @@ -21,6 +21,7 @@ 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; @@ -38,8 +39,11 @@ import static se.leap.bitmaskclient.ProviderAPI.ERRORS; public class DownloadFailedDialog extends DialogFragment { public static String TAG = "downloaded_failed_dialog"; - private String reason_to_fail; + private String reasonToFail; private DOWNLOAD_ERRORS downloadError = DEFAULT; + + private Provider provider; + public enum DOWNLOAD_ERRORS { DEFAULT, ERROR_CORRUPTED_PROVIDER_JSON, @@ -50,39 +54,41 @@ public class DownloadFailedDialog extends DialogFragment { /** * @return a new instance of this DialogFragment. */ - public static DialogFragment newInstance(String reason_to_fail) { - DownloadFailedDialog dialog_fragment = new DownloadFailedDialog(); - dialog_fragment.reason_to_fail = reason_to_fail; - return dialog_fragment; + public static DialogFragment newInstance(Provider provider, String reasonToFail) { + DownloadFailedDialog dialogFragment = new DownloadFailedDialog(); + dialogFragment.reasonToFail = reasonToFail; + dialogFragment.provider = provider; + return dialogFragment; } /** * @return a new instance of this DialogFragment. */ - public static DialogFragment newInstance(JSONObject errorJson) { - DownloadFailedDialog dialog_fragment = new DownloadFailedDialog(); + public static DialogFragment newInstance(Provider provider, JSONObject errorJson) { + DownloadFailedDialog dialogFragment = new DownloadFailedDialog(); + dialogFragment.provider = provider; try { if (errorJson.has(ERRORS)) { - dialog_fragment.reason_to_fail = errorJson.getString(ERRORS); + dialogFragment.reasonToFail = errorJson.getString(ERRORS); } else { //default error msg - dialog_fragment.reason_to_fail = dialog_fragment.getString(R.string.error_io_exception_user_message); + dialogFragment.reasonToFail = dialogFragment.getString(R.string.error_io_exception_user_message); } if (errorJson.has(ERRORID)) { - dialog_fragment.downloadError = valueOf(errorJson.getString(ERRORID)); + dialogFragment.downloadError = valueOf(errorJson.getString(ERRORID)); } } catch (Exception e) { e.printStackTrace(); - dialog_fragment.reason_to_fail = dialog_fragment.getString(R.string.error_io_exception_user_message); + dialogFragment.reasonToFail = dialogFragment.getString(R.string.error_io_exception_user_message); } - return dialog_fragment; + return dialogFragment; } @Override public Dialog onCreateDialog(Bundle savedInstanceState) { AlertDialog.Builder builder = new AlertDialog.Builder(getActivity()); - builder.setMessage(reason_to_fail) + builder.setMessage(reasonToFail) .setNegativeButton(R.string.cancel, new DialogInterface.OnClickListener() { public void onClick(DialogInterface dialog, int id) { interface_with_ConfigurationWizard.cancelSettingUpProvider(); @@ -113,7 +119,7 @@ switch (downloadError) { builder.setPositiveButton(R.string.retry, new DialogInterface.OnClickListener() { public void onClick(DialogInterface dialog, int id) { dismiss(); - interface_with_ConfigurationWizard.retrySetUpProvider(null); + interface_with_ConfigurationWizard.retrySetUpProvider(provider); } }); break; @@ -124,7 +130,7 @@ switch (downloadError) { } public interface DownloadFailedDialogInterface { - void retrySetUpProvider(Provider provider); + void retrySetUpProvider(@NonNull Provider provider); void cancelSettingUpProvider(); diff --git a/app/src/main/java/se/leap/bitmaskclient/EipFragment.java b/app/src/main/java/se/leap/bitmaskclient/EipFragment.java index 2f7977dd..ceae6706 100644 --- a/app/src/main/java/se/leap/bitmaskclient/EipFragment.java +++ b/app/src/main/java/se/leap/bitmaskclient/EipFragment.java @@ -33,6 +33,7 @@ import android.os.Handler; import android.os.IBinder; import android.os.RemoteException; import android.os.ResultReceiver; +import android.support.annotation.NonNull; import android.support.v4.app.Fragment; import android.support.v7.widget.AppCompatImageView; import android.util.Log; @@ -140,16 +141,19 @@ public class EipFragment extends Fragment implements Observer { public void onAttach(Context context) { super.onAttach(context); Bundle arguments = getArguments(); - if (arguments != null) { - provider = getArguments().getParcelable(PROVIDER_KEY); - if (provider == null) { - getActivity().startActivityForResult(new Intent(getActivity(), ProviderListActivity.class), REQUEST_CODE_SWITCH_PROVIDER); + Activity activity = getActivity(); + if (activity != null) { + if (arguments != null) { + provider = arguments.getParcelable(PROVIDER_KEY); + if (provider == null) { + activity.startActivityForResult(new Intent(activity, ProviderListActivity.class), REQUEST_CODE_SWITCH_PROVIDER); + } else { + Log.d(TAG, provider.getName() + " configured as provider"); + } } else { - Log.d(TAG, provider.getName() + " configured as provider"); + Log.e(TAG, "no provider given - starting ProviderListActivity"); + activity.startActivityForResult(new Intent(activity, ProviderListActivity.class), REQUEST_CODE_SWITCH_PROVIDER); } - } else { - Log.e(TAG, "no provider given - starting ProviderListActivity"); - getActivity().startActivityForResult(new Intent(getActivity(), ProviderListActivity.class), REQUEST_CODE_SWITCH_PROVIDER); } } @@ -160,11 +164,16 @@ public class EipFragment extends Fragment implements Observer { eipReceiver = new EIPReceiver(new Handler()); eipBroadcastReceiver = new EIPBroadcastReceiver(); providerAPIResultReceiver = new ProviderAPIResultReceiver(new Handler(), new EipFragmentReceiver()); - preferences = getActivity().getSharedPreferences(SHARED_PREFERENCES, Context.MODE_PRIVATE); + Activity activity = getActivity(); + if (activity != null) { + preferences = getActivity().getSharedPreferences(SHARED_PREFERENCES, Context.MODE_PRIVATE); + } else { + Log.e(TAG, "activity is null in onCreate - no preferences set!"); + } } @Override - public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) { + public View onCreateView(@NonNull LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) { eipStatus.addObserver(this); View view = inflater.inflate(R.layout.eip_service_fragment, container, false); ButterKnife.inject(this, view); @@ -189,8 +198,12 @@ public class EipFragment extends Fragment implements Observer { @Override public void onPause() { super.onPause(); - getActivity().unbindService(openVpnConnection); - getActivity().unregisterReceiver(eipBroadcastReceiver); + + Activity activity = getActivity(); + if (activity != null) { + getActivity().unbindService(openVpnConnection); + getActivity().unregisterReceiver(eipBroadcastReceiver); + } Log.d(TAG, "broadcast unregistered"); } @@ -201,7 +214,7 @@ public class EipFragment extends Fragment implements Observer { } @Override - public void onSaveInstanceState(Bundle outState) { + public void onSaveInstanceState(@NonNull Bundle outState) { outState.putBoolean(IS_CONNECTED, eipStatus.isConnected()); super.onSaveInstanceState(outState); } @@ -238,7 +251,10 @@ public class EipFragment extends Fragment implements Observer { else if (canLogInToStartEIP()) { wantsToConnect = true; Intent intent = new Intent(getContext(), LoginActivity.class); - getActivity().startActivityForResult(intent, REQUEST_CODE_LOG_IN); + Activity activity = getActivity(); + if (activity != null) { + activity.startActivityForResult(intent, REQUEST_CODE_LOG_IN); + } } else { Log.d(TAG, "WHAT IS GOING ON HERE?!"); // TODO: implement a fallback: check if vpncertificate was not downloaded properly or give @@ -268,21 +284,25 @@ public class EipFragment extends Fragment implements Observer { private void askPendingStartCancellation() { Activity activity = getActivity(); - AlertDialog.Builder alertBuilder = new AlertDialog.Builder(getActivity()); - alertBuilder.setTitle(activity.getString(R.string.eip_cancel_connect_title)) - .setMessage(activity.getString(R.string.eip_cancel_connect_text)) - .setPositiveButton((android.R.string.yes), new DialogInterface.OnClickListener() { - @Override - public void onClick(DialogInterface dialog, int which) { - stopEipIfPossible(); - } - }) - .setNegativeButton(activity.getString(android.R.string.no), new DialogInterface.OnClickListener() { - @Override - public void onClick(DialogInterface dialog, int which) { - } - }) - .show(); + if (activity != null) { + AlertDialog.Builder alertBuilder = new AlertDialog.Builder(getActivity()); + alertBuilder.setTitle(activity.getString(R.string.eip_cancel_connect_title)) + .setMessage(activity.getString(R.string.eip_cancel_connect_text)) + .setPositiveButton((android.R.string.yes), new DialogInterface.OnClickListener() { + @Override + public void onClick(DialogInterface dialog, int which) { + stopEipIfPossible(); + } + }) + .setNegativeButton(activity.getString(android.R.string.no), new DialogInterface.OnClickListener() { + @Override + public void onClick(DialogInterface dialog, int which) { + } + }) + .show(); + } else { + Log.e(TAG, "activity is null when asking to cancel"); + } } public void startEipFromScratch() { @@ -302,9 +322,14 @@ public class EipFragment extends Fragment implements Observer { private void stopBlockingVpn() { Log.d(TAG, "stop VoidVpn!"); Activity activity = getActivity(); - Intent stopVoidVpnIntent = new Intent(activity, VoidVpnService.class); - stopVoidVpnIntent.setAction(EIP_ACTION_STOP_BLOCKING_VPN); - activity.startService(stopVoidVpnIntent); + 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() { @@ -325,21 +350,25 @@ public class EipFragment extends Fragment implements Observer { protected void askToStopEIP() { Activity activity = getActivity(); - AlertDialog.Builder alertBuilder = new AlertDialog.Builder(activity); - alertBuilder.setTitle(activity.getString(R.string.eip_cancel_connect_title)) - .setMessage(activity.getString(R.string.eip_warning_browser_inconsistency)) - .setPositiveButton((android.R.string.yes), new DialogInterface.OnClickListener() { - @Override - public void onClick(DialogInterface dialog, int which) { - stopEipIfPossible(); - } - }) - .setNegativeButton(activity.getString(android.R.string.no), new DialogInterface.OnClickListener() { - @Override - public void onClick(DialogInterface dialog, int which) { - } - }) - .show(); + if (activity != null) { + AlertDialog.Builder alertBuilder = new AlertDialog.Builder(activity); + alertBuilder.setTitle(activity.getString(R.string.eip_cancel_connect_title)) + .setMessage(activity.getString(R.string.eip_warning_browser_inconsistency)) + .setPositiveButton((android.R.string.yes), new DialogInterface.OnClickListener() { + @Override + public void onClick(DialogInterface dialog, int which) { + stopEipIfPossible(); + } + }) + .setNegativeButton(activity.getString(android.R.string.no), new DialogInterface.OnClickListener() { + @Override + public void onClick(DialogInterface dialog, int which) { + } + }) + .show(); + } else { + Log.e(TAG, "activity is null when asking to stop EIP"); + } } @Override @@ -362,25 +391,29 @@ public class EipFragment extends Fragment implements Observer { private void handleNewState() { Activity activity = getActivity(); - if (eipStatus.isConnecting()) { - mainButton.setText(activity.getString(android.R.string.cancel)); - key.setImageResource(R.drawable.vpn_connecting); - routedText.setVisibility(GONE); - vpnRoute.setVisibility(GONE); - colorBackgroundALittle(); - } else if (eipStatus.isConnected() || isOpenVpnRunningWithoutNetwork()) { - mainButton.setText(activity.getString(R.string.vpn_button_turn_off)); - key.setImageResource(R.drawable.vpn_connected); - routedText.setVisibility(VISIBLE); - vpnRoute.setVisibility(VISIBLE); - vpnRoute.setText(ConfigHelper.getProviderName(preferences)); - colorBackground(); + if (activity != null) { + if (eipStatus.isConnecting()) { + mainButton.setText(activity.getString(android.R.string.cancel)); + key.setImageResource(R.drawable.vpn_connecting); + routedText.setVisibility(GONE); + vpnRoute.setVisibility(GONE); + colorBackgroundALittle(); + } else if (eipStatus.isConnected() || isOpenVpnRunningWithoutNetwork()) { + mainButton.setText(activity.getString(R.string.vpn_button_turn_off)); + key.setImageResource(R.drawable.vpn_connected); + routedText.setVisibility(VISIBLE); + vpnRoute.setVisibility(VISIBLE); + vpnRoute.setText(ConfigHelper.getProviderName(preferences)); + colorBackground(); + } else { + mainButton.setText(activity.getString(R.string.vpn_button_turn_on)); + key.setImageResource(R.drawable.vpn_disconnected); + routedText.setVisibility(GONE); + vpnRoute.setVisibility(GONE); + greyscaleBackground(); + } } else { - mainButton.setText(activity.getString(R.string.vpn_button_turn_on)); - key.setImageResource(R.drawable.vpn_disconnected); - routedText.setVisibility(GONE); - vpnRoute.setVisibility(GONE); - greyscaleBackground(); + Log.e(TAG, "activity is null while trying to handle new state"); } } @@ -399,9 +432,13 @@ public class EipFragment extends Fragment implements Observer { private void bindOpenVpnService() { Activity activity = getActivity(); - Intent intent = new Intent(activity, OpenVPNService.class); - intent.setAction(OpenVPNService.START_SERVICE); - activity.bindService(intent, openVpnConnection, Context.BIND_AUTO_CREATE); + if (activity != null) { + Intent intent = new Intent(activity, OpenVPNService.class); + intent.setAction(OpenVPNService.START_SERVICE); + activity.bindService(intent, openVpnConnection, Context.BIND_AUTO_CREATE); + } else { + Log.e(TAG, "activity is null when binding OpenVpn"); + } } protected class EIPReceiver extends ResultReceiver { @@ -533,10 +570,15 @@ public class EipFragment extends Fragment implements Observer { } private void setUpBroadcastReceiver() { - IntentFilter updateIntentFilter = new IntentFilter(BROADCAST_EIP_EVENT); - updateIntentFilter.addCategory(Intent.CATEGORY_DEFAULT); - getActivity().registerReceiver(eipBroadcastReceiver, updateIntentFilter); - Log.d(TAG, "broadcast registered"); + Activity activity = getActivity(); + if (activity != null) { + IntentFilter updateIntentFilter = new IntentFilter(BROADCAST_EIP_EVENT); + updateIntentFilter.addCategory(Intent.CATEGORY_DEFAULT); + activity.registerReceiver(eipBroadcastReceiver, updateIntentFilter); + Log.d(TAG, "broadcast registered"); + } else { + Log.e(TAG, "activity null when setting up boradcat receiver"); + } } } diff --git a/app/src/main/java/se/leap/bitmaskclient/OkHttpClientGenerator.java b/app/src/main/java/se/leap/bitmaskclient/OkHttpClientGenerator.java index 6d554b0e..40b2ea7f 100644 --- a/app/src/main/java/se/leap/bitmaskclient/OkHttpClientGenerator.java +++ b/app/src/main/java/se/leap/bitmaskclient/OkHttpClientGenerator.java @@ -73,11 +73,6 @@ public class OkHttpClientGenerator { return initHttpClient(initError, caCert); } - public OkHttpClient initSelfSignedCAHttpClient(JSONObject initError, String certificate) { - return initHttpClient(initError, certificate); - } - - private OkHttpClient initHttpClient(JSONObject initError, String certificate) { try { TLSCompatSocketFactory sslCompatFactory; diff --git a/app/src/main/java/se/leap/bitmaskclient/ProviderApiManagerBase.java b/app/src/main/java/se/leap/bitmaskclient/ProviderApiManagerBase.java index 000dd164..6b6aa89d 100644 --- a/app/src/main/java/se/leap/bitmaskclient/ProviderApiManagerBase.java +++ b/app/src/main/java/se/leap/bitmaskclient/ProviderApiManagerBase.java @@ -66,7 +66,6 @@ import static se.leap.bitmaskclient.DownloadFailedDialog.DOWNLOAD_ERRORS.ERROR_C 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.ProviderAPI.CORRECTLY_DOWNLOADED_EIP_SERVICE; -import static se.leap.bitmaskclient.ProviderAPI.CURRENT_PROGRESS; import static se.leap.bitmaskclient.ProviderAPI.DOWNLOAD_CERTIFICATE; import static se.leap.bitmaskclient.ProviderAPI.DOWNLOAD_EIP_SERVICE; import static se.leap.bitmaskclient.ProviderAPI.ERRORID; @@ -572,7 +571,7 @@ public abstract class ProviderApiManagerBase { JSONObject errorJson = new JSONObject(); String baseUrl = getApiUrl(providerDefinition); - OkHttpClient okHttpClient = clientGenerator.initSelfSignedCAHttpClient(errorJson, caCert); + OkHttpClient okHttpClient = clientGenerator.initSelfSignedCAHttpClient(caCert, errorJson); if (okHttpClient == null) { result.putString(ERRORS, errorJson.toString()); return false; @@ -706,7 +705,6 @@ public abstract class ProviderApiManagerBase { return setErrorResult(result, warning_corrupted_provider_cert, ERROR_CERTIFICATE_PINNING.toString()); } - if (!hasApiUrlExpectedDomain(providerDefinition, mainUrl)){ return setErrorResult(result, warning_corrupted_provider_details, ERROR_CORRUPTED_PROVIDER_JSON.toString()); } diff --git a/app/src/main/java/se/leap/bitmaskclient/ProviderListBaseActivity.java b/app/src/main/java/se/leap/bitmaskclient/ProviderListBaseActivity.java index b2daff82..6a76dd55 100644 --- a/app/src/main/java/se/leap/bitmaskclient/ProviderListBaseActivity.java +++ b/app/src/main/java/se/leap/bitmaskclient/ProviderListBaseActivity.java @@ -23,6 +23,7 @@ import android.content.Intent; import android.content.IntentFilter; import android.os.Bundle; import android.os.Handler; +import android.support.annotation.NonNull; import android.support.v4.app.DialogFragment; import android.support.v4.app.FragmentTransaction; import android.util.Log; @@ -102,7 +103,7 @@ public abstract class ProviderListBaseActivity extends ConfigWizardBaseActivity private boolean isActivityShowing; private String reasonToFail; - public abstract void retrySetUpProvider(Provider provider); + public abstract void retrySetUpProvider(@NonNull Provider provider); protected abstract void onItemSelectedLogic(); @@ -360,10 +361,10 @@ public abstract class ProviderListBaseActivity extends ConfigWizardBaseActivity DialogFragment newFragment; try { JSONObject errorJson = new JSONObject(reasonToFail); - newFragment = DownloadFailedDialog.newInstance(errorJson); + newFragment = DownloadFailedDialog.newInstance(provider, errorJson); } catch (JSONException e) { e.printStackTrace(); - newFragment = DownloadFailedDialog.newInstance(reasonToFail); + newFragment = DownloadFailedDialog.newInstance(provider, reasonToFail); } newFragment.show(fragmentTransaction, DownloadFailedDialog.TAG); } catch (IllegalStateException e) { diff --git a/app/src/production/java/se/leap/bitmaskclient/ProviderApiManager.java b/app/src/production/java/se/leap/bitmaskclient/ProviderApiManager.java index a4b3e491..1783135d 100644 --- a/app/src/production/java/se/leap/bitmaskclient/ProviderApiManager.java +++ b/app/src/production/java/se/leap/bitmaskclient/ProviderApiManager.java @@ -67,7 +67,6 @@ public class ProviderApiManager extends ProviderApiManagerBase { */ @Override protected Bundle setUpProvider(Provider provider, Bundle task) { - int progress = 0; Bundle currentDownload = new Bundle(); if (isEmpty(provider.getMainUrlString()) || provider.getMainUrl().isDefault()) { @@ -260,7 +259,7 @@ public class ProviderApiManager extends ProviderApiManagerBase { String responseString; JSONObject errorJson = new JSONObject(); String baseUrl = getApiUrl(providerDefinition); - OkHttpClient okHttpClient = clientGenerator.initSelfSignedCAHttpClient(errorJson, caCert); + OkHttpClient okHttpClient = clientGenerator.initSelfSignedCAHttpClient(caCert, errorJson); if (okHttpClient == null) { return errorJson.toString(); } diff --git a/app/src/production/java/se/leap/bitmaskclient/ProviderListActivity.java b/app/src/production/java/se/leap/bitmaskclient/ProviderListActivity.java index 67c04f13..2df0ffa1 100644 --- a/app/src/production/java/se/leap/bitmaskclient/ProviderListActivity.java +++ b/app/src/production/java/se/leap/bitmaskclient/ProviderListActivity.java @@ -18,6 +18,7 @@ package se.leap.bitmaskclient; import android.content.Intent; import android.os.Bundle; +import android.support.annotation.NonNull; import java.net.MalformedURLException; import java.net.URL; @@ -67,7 +68,7 @@ public class ProviderListActivity extends ProviderListBaseActivity { } @Override - public void retrySetUpProvider(Provider provider) { + public void retrySetUpProvider(@NonNull Provider provider) { cancelSettingUpProvider(); if (!provider.hasCaCert()) { addAndSelectNewProvider(provider.getMainUrlString()); diff --git a/app/src/test/java/se/leap/bitmaskclient/testutils/MockHelper.java b/app/src/test/java/se/leap/bitmaskclient/testutils/MockHelper.java index ea7f9aae..fa5fab8c 100644 --- a/app/src/test/java/se/leap/bitmaskclient/testutils/MockHelper.java +++ b/app/src/test/java/se/leap/bitmaskclient/testutils/MockHelper.java @@ -354,7 +354,6 @@ public class MockHelper { OkHttpClient mockedOkHttpClient = mock(OkHttpClient.class); when(mockClientGenerator.initCommercialCAHttpClient(any(JSONObject.class))).thenReturn(mockedOkHttpClient); when(mockClientGenerator.initSelfSignedCAHttpClient(anyString(), any(JSONObject.class))).thenReturn(mockedOkHttpClient); - when(mockClientGenerator.initSelfSignedCAHttpClient(any(JSONObject.class), anyString())).thenReturn(mockedOkHttpClient); return mockClientGenerator; } -- cgit v1.2.3 From 9f6e74680e5cfe6507bd1e37ea217cf2887af3cc Mon Sep 17 00:00:00 2001 From: Fup Duck Date: Fri, 9 Feb 2018 14:33:20 +0100 Subject: 8827 - resolve discussions * remove stop for providerApi * enable retrySetUpProvider * renamed PROVIDER_KEY for EIP_JSON to PROVIDER_EIP_DEFINITION --- .../se/leap/bitmaskclient/ProviderApiManager.java | 66 ++++++++--------- .../leap/bitmaskclient/ProviderListActivity.java | 9 +-- .../java/se/leap/bitmaskclient/ConfigHelper.java | 6 +- .../main/java/se/leap/bitmaskclient/Constants.java | 1 + .../main/java/se/leap/bitmaskclient/Dashboard.java | 4 +- .../leap/bitmaskclient/DownloadFailedDialog.java | 15 ++-- .../se/leap/bitmaskclient/FeatureVersionCode.java | 1 + .../java/se/leap/bitmaskclient/MainActivity.java | 5 +- .../java/se/leap/bitmaskclient/ProviderAPI.java | 5 -- .../leap/bitmaskclient/ProviderApiManagerBase.java | 15 ++-- .../bitmaskclient/ProviderListBaseActivity.java | 20 +----- .../java/se/leap/bitmaskclient/StartActivity.java | 9 +++ .../main/java/se/leap/bitmaskclient/eip/EIP.java | 4 +- .../se/leap/bitmaskclient/ProviderApiManager.java | 84 ++++++++++------------ .../leap/bitmaskclient/ProviderListActivity.java | 11 +-- 15 files changed, 107 insertions(+), 148 deletions(-) diff --git a/app/src/insecure/java/se/leap/bitmaskclient/ProviderApiManager.java b/app/src/insecure/java/se/leap/bitmaskclient/ProviderApiManager.java index 624b797b..dfc98ffb 100644 --- a/app/src/insecure/java/se/leap/bitmaskclient/ProviderApiManager.java +++ b/app/src/insecure/java/se/leap/bitmaskclient/ProviderApiManager.java @@ -110,8 +110,6 @@ public class ProviderApiManager extends ProviderApiManagerBase { 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))) { @@ -132,30 +130,28 @@ public class ProviderApiManager extends ProviderApiManagerBase { String caCert = provider.getCaCert(); String providerMainUrl = provider.getMainUrlString(); - if (go_ahead) { - String providerDotJsonString; - if(providerDefinition.length() == 0 || caCert.isEmpty()) - providerDotJsonString = downloadWithCommercialCA(providerMainUrl + "/provider.json", dangerOn); - else - providerDotJsonString = downloadFromApiUrlWithProviderCA("/provider.json", caCert, providerDefinition, dangerOn); + String providerDotJsonString; + if(providerDefinition.length() == 0 || caCert.isEmpty()) + providerDotJsonString = downloadWithCommercialCA(providerMainUrl + "/provider.json", dangerOn); + else + providerDotJsonString = downloadFromApiUrlWithProviderCA("/provider.json", caCert, providerDefinition, dangerOn); - if (!isValidJson(providerDotJsonString)) { - result.putString(ERRORS, resources.getString(malformed_url)); - result.putBoolean(BROADCAST_RESULT_KEY, false); - return result; - } + if (!isValidJson(providerDotJsonString)) { + result.putString(ERRORS, resources.getString(malformed_url)); + result.putBoolean(BROADCAST_RESULT_KEY, false); + return result; + } - try { - JSONObject providerJson = new JSONObject(providerDotJsonString); + try { + JSONObject providerJson = new JSONObject(providerDotJsonString); - provider.define(providerJson); + provider.define(providerJson); - result.putBoolean(BROADCAST_RESULT_KEY, true); - } catch (JSONException e) { - String reason_to_fail = pickErrorMessage(providerDotJsonString); - result.putString(ERRORS, reason_to_fail); - result.putBoolean(BROADCAST_RESULT_KEY, false); - } + result.putBoolean(BROADCAST_RESULT_KEY, true); + } catch (JSONException e) { + String reason_to_fail = pickErrorMessage(providerDotJsonString); + result.putString(ERRORS, reason_to_fail); + result.putBoolean(BROADCAST_RESULT_KEY, false); } result.putParcelable(PROVIDER_KEY, provider); return result; @@ -169,21 +165,19 @@ public class ProviderApiManager extends ProviderApiManagerBase { protected Bundle getAndSetEipServiceJson(Provider provider) { Bundle result = new Bundle(); String eipServiceJsonString = ""; - if (go_ahead) { - try { - JSONObject providerDefinition = provider.getDefinition(); - String eipServiceUrl = providerDefinition.getString(Provider.API_URL) + "/" + providerDefinition.getString(Provider.API_VERSION) + "/" + EIP.SERVICE_API_PATH; - eipServiceJsonString = downloadWithProviderCA(provider.getCaCert(), eipServiceUrl, lastDangerOn); + try { + JSONObject providerDefinition = provider.getDefinition(); + String eipServiceUrl = providerDefinition.getString(Provider.API_URL) + "/" + providerDefinition.getString(Provider.API_VERSION) + "/" + EIP.SERVICE_API_PATH; + eipServiceJsonString = downloadWithProviderCA(provider.getCaCert(), eipServiceUrl, lastDangerOn); - JSONObject eipServiceJson = new JSONObject(eipServiceJsonString); - provider.setEipServiceJson(eipServiceJson); + JSONObject eipServiceJson = new JSONObject(eipServiceJsonString); + provider.setEipServiceJson(eipServiceJson); - result.putBoolean(BROADCAST_RESULT_KEY, true); - } catch (NullPointerException | JSONException e) { - String reasonToFail = pickErrorMessage(eipServiceJsonString); - result.putString(ERRORS, reasonToFail); - result.putBoolean(BROADCAST_RESULT_KEY, false); - } + result.putBoolean(BROADCAST_RESULT_KEY, true); + } catch (NullPointerException | JSONException e) { + String reasonToFail = pickErrorMessage(eipServiceJsonString); + result.putString(ERRORS, reasonToFail); + result.putBoolean(BROADCAST_RESULT_KEY, false); } result.putParcelable(PROVIDER_KEY, provider); return result; @@ -228,7 +222,7 @@ public class ProviderApiManager extends ProviderApiManagerBase { String certString = downloadWithCommercialCA(caCertUrl, dangerOn); - if (validCertificate(provider, certString) && go_ahead) { + if (validCertificate(provider, certString)) { provider.setCaCert(certString); preferences.edit().putString(Provider.CA_CERT + "." + providerDomain, certString).apply(); result.putBoolean(BROADCAST_RESULT_KEY, true); diff --git a/app/src/insecure/java/se/leap/bitmaskclient/ProviderListActivity.java b/app/src/insecure/java/se/leap/bitmaskclient/ProviderListActivity.java index 531c438a..5ad7ea44 100644 --- a/app/src/insecure/java/se/leap/bitmaskclient/ProviderListActivity.java +++ b/app/src/insecure/java/se/leap/bitmaskclient/ProviderListActivity.java @@ -101,14 +101,7 @@ public class ProviderListActivity extends ProviderListBaseActivity { */ @Override public void retrySetUpProvider(@NonNull Provider provider) { - cancelSettingUpProvider(); - if (!provider.hasCaCert()) { - addAndSelectNewProvider(provider.getMainUrlString(), ProviderAPI.lastDangerOn()); - } else { - showProgressBar(); - - ProviderAPICommand.execute(this, SET_UP_PROVIDER, provider); - } + ProviderAPICommand.execute(this, SET_UP_PROVIDER, provider); } } diff --git a/app/src/main/java/se/leap/bitmaskclient/ConfigHelper.java b/app/src/main/java/se/leap/bitmaskclient/ConfigHelper.java index 2e9e1897..238f0ea1 100644 --- a/app/src/main/java/se/leap/bitmaskclient/ConfigHelper.java +++ b/app/src/main/java/se/leap/bitmaskclient/ConfigHelper.java @@ -55,7 +55,7 @@ import java.util.Map; import static android.R.attr.name; import static se.leap.bitmaskclient.Constants.PREFERENCES_APP_VERSION; import static se.leap.bitmaskclient.Constants.PROVIDER_CONFIGURED; -import static se.leap.bitmaskclient.Constants.PROVIDER_KEY; +import static se.leap.bitmaskclient.Constants.PROVIDER_EIP_DEFINITION; /** * Stores constants, and implements auxiliary methods used across all Bitmask Android classes. @@ -355,7 +355,7 @@ public class ConfigHelper { putString(Provider.MAIN_URL, provider.getMainUrlString()). putString(Provider.KEY, provider.getDefinitionString()). putString(Provider.CA_CERT, provider.getCaCert()). - putString(PROVIDER_KEY, provider.getEipServiceJsonString()). + putString(PROVIDER_EIP_DEFINITION, provider.getEipServiceJsonString()). commit(); String providerDomain = provider.getDomain(); @@ -363,7 +363,7 @@ public class ConfigHelper { putString(Provider.MAIN_URL + "." + providerDomain, provider.getMainUrlString()). putString(Provider.KEY + "." + providerDomain, provider.getDefinitionString()). putString(Provider.CA_CERT + "." + providerDomain, provider.getCaCert()). - putString(PROVIDER_KEY + "." + providerDomain, provider.getEipServiceJsonString()). + putString(PROVIDER_EIP_DEFINITION + "." + providerDomain, provider.getEipServiceJsonString()). apply(); } diff --git a/app/src/main/java/se/leap/bitmaskclient/Constants.java b/app/src/main/java/se/leap/bitmaskclient/Constants.java index 6b5c6bb7..680c10bf 100644 --- a/app/src/main/java/se/leap/bitmaskclient/Constants.java +++ b/app/src/main/java/se/leap/bitmaskclient/Constants.java @@ -58,6 +58,7 @@ public interface Constants { String PROVIDER_PRIVATE_KEY = "Constants.PROVIDER_PRIVATE_KEY"; String PROVIDER_KEY = "Constants.PROVIDER_KEY"; String PROVIDER_CONFIGURED = "Constants.PROVIDER_CONFIGURED"; + String PROVIDER_EIP_DEFINITION = "Constants.EIP_DEFINITION"; ////////////////////////////////////////////// // CREDENTIAL CONSTANTS diff --git a/app/src/main/java/se/leap/bitmaskclient/Dashboard.java b/app/src/main/java/se/leap/bitmaskclient/Dashboard.java index 2f129d02..48dce1c2 100644 --- a/app/src/main/java/se/leap/bitmaskclient/Dashboard.java +++ b/app/src/main/java/se/leap/bitmaskclient/Dashboard.java @@ -47,7 +47,7 @@ import static se.leap.bitmaskclient.Constants.APP_ACTION_QUIT; import static se.leap.bitmaskclient.Constants.EIP_IS_ALWAYS_ON; import static se.leap.bitmaskclient.Constants.EIP_RESTART_ON_BOOT; import static se.leap.bitmaskclient.Constants.PROVIDER_CONFIGURED; -import static se.leap.bitmaskclient.Constants.PROVIDER_KEY; +import static se.leap.bitmaskclient.Constants.PROVIDER_EIP_DEFINITION; import static se.leap.bitmaskclient.Constants.REQUEST_CODE_CONFIGURE_LEAP; import static se.leap.bitmaskclient.Constants.REQUEST_CODE_KEY; import static se.leap.bitmaskclient.Constants.REQUEST_CODE_SWITCH_PROVIDER; @@ -161,7 +161,7 @@ public class Dashboard extends ButterKnifeActivity { switch (versionCode) { case 91: // 0.6.0 without Bug #5999 case 101: // 0.8.0 - if (!preferences.getString(PROVIDER_KEY, "").isEmpty()) + if (!preferences.getString(PROVIDER_EIP_DEFINITION, "").isEmpty()) EipCommand.updateEipService(this); break; } diff --git a/app/src/main/java/se/leap/bitmaskclient/DownloadFailedDialog.java b/app/src/main/java/se/leap/bitmaskclient/DownloadFailedDialog.java index 8d56cdf8..8a6d981d 100644 --- a/app/src/main/java/se/leap/bitmaskclient/DownloadFailedDialog.java +++ b/app/src/main/java/se/leap/bitmaskclient/DownloadFailedDialog.java @@ -86,12 +86,13 @@ public class DownloadFailedDialog extends 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) { - interface_with_ConfigurationWizard.cancelSettingUpProvider(); + interfaceWithConfigurationWizard.cancelSettingUpProvider(); dialog.dismiss(); } }); @@ -101,7 +102,7 @@ switch (downloadError) { @Override public void onClick(DialogInterface dialog, int which) { dismiss(); - interface_with_ConfigurationWizard.updateProviderDetails(); + interfaceWithConfigurationWizard.updateProviderDetails(); } }); break; @@ -111,7 +112,7 @@ switch (downloadError) { @Override public void onClick(DialogInterface dialog, int which) { dismiss(); - interface_with_ConfigurationWizard.updateProviderDetails(); + interfaceWithConfigurationWizard.updateProviderDetails(); } }); break; @@ -119,7 +120,7 @@ switch (downloadError) { builder.setPositiveButton(R.string.retry, new DialogInterface.OnClickListener() { public void onClick(DialogInterface dialog, int id) { dismiss(); - interface_with_ConfigurationWizard.retrySetUpProvider(provider); + interfaceWithConfigurationWizard.retrySetUpProvider(provider); } }); break; @@ -137,13 +138,13 @@ switch (downloadError) { void updateProviderDetails(); } - DownloadFailedDialogInterface interface_with_ConfigurationWizard; + DownloadFailedDialogInterface interfaceWithConfigurationWizard; @Override public void onAttach(Context context) { super.onAttach(context); try { - interface_with_ConfigurationWizard = (DownloadFailedDialogInterface) context; + interfaceWithConfigurationWizard = (DownloadFailedDialogInterface) context; } catch (ClassCastException e) { throw new ClassCastException(context.toString() + " must implement NoticeDialogListener"); @@ -152,7 +153,7 @@ switch (downloadError) { @Override public void onCancel(DialogInterface dialog) { - interface_with_ConfigurationWizard.cancelSettingUpProvider(); + interfaceWithConfigurationWizard.cancelSettingUpProvider(); dialog.dismiss(); } diff --git a/app/src/main/java/se/leap/bitmaskclient/FeatureVersionCode.java b/app/src/main/java/se/leap/bitmaskclient/FeatureVersionCode.java index b2a39c1a..969f006a 100644 --- a/app/src/main/java/se/leap/bitmaskclient/FeatureVersionCode.java +++ b/app/src/main/java/se/leap/bitmaskclient/FeatureVersionCode.java @@ -2,4 +2,5 @@ package se.leap.bitmaskclient; public interface FeatureVersionCode { int MULTIPLE_PROFILES = 132; + int RENAMED_EIP_IN_PREFERENCES = 132; } diff --git a/app/src/main/java/se/leap/bitmaskclient/MainActivity.java b/app/src/main/java/se/leap/bitmaskclient/MainActivity.java index 9c047bc9..06a66e43 100644 --- a/app/src/main/java/se/leap/bitmaskclient/MainActivity.java +++ b/app/src/main/java/se/leap/bitmaskclient/MainActivity.java @@ -71,11 +71,12 @@ public class MainActivity extends AppCompatActivity { switch (intent.getAction()) { case ACTION_SHOW_VPN_FRAGMENT: fragment = new EipFragment(); + Bundle bundle = new Bundle(); if (intent.hasExtra(ASK_TO_CANCEL_VPN)) { - Bundle bundle = new Bundle(); bundle.putBoolean(ASK_TO_CANCEL_VPN, true); - fragment.setArguments(bundle); } + bundle.putParcelable(PROVIDER_KEY, provider); + fragment.setArguments(bundle); break; default: break; diff --git a/app/src/main/java/se/leap/bitmaskclient/ProviderAPI.java b/app/src/main/java/se/leap/bitmaskclient/ProviderAPI.java index 73f5c530..4bffd1b2 100644 --- a/app/src/main/java/se/leap/bitmaskclient/ProviderAPI.java +++ b/app/src/main/java/se/leap/bitmaskclient/ProviderAPI.java @@ -75,11 +75,6 @@ public class ProviderAPI extends IntentService implements ProviderApiManagerBase super(TAG); } - //TODO: refactor me, please! - public static void stop() { - ProviderApiManager.stop(); - } - //TODO: refactor me, please! //used in insecure flavor only @SuppressLint("unused") diff --git a/app/src/main/java/se/leap/bitmaskclient/ProviderApiManagerBase.java b/app/src/main/java/se/leap/bitmaskclient/ProviderApiManagerBase.java index 6b6aa89d..f1c0ecef 100644 --- a/app/src/main/java/se/leap/bitmaskclient/ProviderApiManagerBase.java +++ b/app/src/main/java/se/leap/bitmaskclient/ProviderApiManagerBase.java @@ -115,15 +115,10 @@ public abstract class ProviderApiManagerBase { private ProviderApiServiceCallback serviceCallback; - static boolean go_ahead = true; protected SharedPreferences preferences; protected Resources resources; OkHttpClientGenerator clientGenerator; - public static void stop() { - go_ahead = false; - } - ProviderApiManagerBase(SharedPreferences preferences, Resources resources, OkHttpClientGenerator clientGenerator, ProviderApiServiceCallback callback) { this.preferences = preferences; this.resources = resources; @@ -158,12 +153,10 @@ public abstract class ProviderApiManagerBase { } } else if (action.equalsIgnoreCase(SET_UP_PROVIDER)) { Bundle result = setUpProvider(provider, parameters); - if (go_ahead) { - if (result.getBoolean(BROADCAST_RESULT_KEY)) { - sendToReceiverOrBroadcast(receiver, PROVIDER_OK, result, provider); - } else { - sendToReceiverOrBroadcast(receiver, PROVIDER_NOK, result, provider); - } + if (result.getBoolean(BROADCAST_RESULT_KEY)) { + sendToReceiverOrBroadcast(receiver, PROVIDER_OK, result, provider); + } else { + sendToReceiverOrBroadcast(receiver, PROVIDER_NOK, result, provider); } } else if (action.equalsIgnoreCase(SIGN_UP)) { Bundle result = tryToRegister(parameters); diff --git a/app/src/main/java/se/leap/bitmaskclient/ProviderListBaseActivity.java b/app/src/main/java/se/leap/bitmaskclient/ProviderListBaseActivity.java index 6a76dd55..6fa3b503 100644 --- a/app/src/main/java/se/leap/bitmaskclient/ProviderListBaseActivity.java +++ b/app/src/main/java/se/leap/bitmaskclient/ProviderListBaseActivity.java @@ -46,7 +46,6 @@ import butterknife.InjectView; import butterknife.OnItemClick; import se.leap.bitmaskclient.fragments.AboutFragment; -import static android.view.View.GONE; import static se.leap.bitmaskclient.Constants.APP_ACTION_QUIT; import static se.leap.bitmaskclient.Constants.BROADCAST_PROVIDER_API_EVENT; import static se.leap.bitmaskclient.Constants.BROADCAST_RESULT_CODE; @@ -229,10 +228,6 @@ public abstract class ProviderListBaseActivity extends ConfigWizardBaseActivity } void handleProviderSetupFailed(Bundle resultData) { - mConfigState.setAction(PROVIDER_NOT_SET); - - setResult(RESULT_CANCELED, mConfigState); - reasonToFail = resultData.getString(ERRORS); showDownloadFailedDialog(); } @@ -242,8 +237,7 @@ public abstract class ProviderListBaseActivity extends ConfigWizardBaseActivity } void handleIncorrectlyDownloadedCertificate() { - mConfigState.setAction(PROVIDER_NOT_SET); - hideProgressBar(); + cancelSettingUpProvider(); setResult(RESULT_CANCELED, mConfigState); } @@ -289,26 +283,18 @@ public abstract class ProviderListBaseActivity extends ConfigWizardBaseActivity } private void stopSettingUpProvider() { - ProviderAPI.stop(); - loadingScreen.setVisibility(GONE); - cancelSettingUpProvider(); } @Override public void cancelSettingUpProvider() { - hideProgressBar(); mConfigState.setAction(PROVIDER_NOT_SET); + hideProgressBar(); } @Override public void updateProviderDetails() { - mConfigState.setAction(SETTING_UP_PROVIDER); - - Bundle parameters = new Bundle(); - parameters.putString(Provider.MAIN_URL, provider.getMainUrl().toString()); - - ProviderAPICommand.execute(this, UPDATE_PROVIDER_DETAILS, parameters, provider); + ProviderAPICommand.execute(this, UPDATE_PROVIDER_DETAILS, provider); } public void checkProviderSetUp() { diff --git a/app/src/main/java/se/leap/bitmaskclient/StartActivity.java b/app/src/main/java/se/leap/bitmaskclient/StartActivity.java index a7b713c5..288b157f 100644 --- a/app/src/main/java/se/leap/bitmaskclient/StartActivity.java +++ b/app/src/main/java/se/leap/bitmaskclient/StartActivity.java @@ -20,6 +20,8 @@ import static se.leap.bitmaskclient.Constants.APP_ACTION_CONFIGURE_ALWAYS_ON_PRO import static se.leap.bitmaskclient.Constants.EIP_ACTION_START; import static se.leap.bitmaskclient.Constants.EIP_RESTART_ON_BOOT; import static se.leap.bitmaskclient.Constants.PREFERENCES_APP_VERSION; +import static se.leap.bitmaskclient.Constants.PROVIDER_EIP_DEFINITION; +import static se.leap.bitmaskclient.Constants.PROVIDER_KEY; import static se.leap.bitmaskclient.Constants.REQUEST_CODE_CONFIGURE_LEAP; import static se.leap.bitmaskclient.Constants.SHARED_PREFERENCES; import static se.leap.bitmaskclient.MainActivity.ACTION_SHOW_VPN_FRAGMENT; @@ -127,6 +129,13 @@ public class StartActivity extends Activity { if (hasNewFeature(FeatureVersionCode.MULTIPLE_PROFILES)) { // TODO prepare usage of multiple profiles } + if (hasNewFeature(FeatureVersionCode.RENAMED_EIP_IN_PREFERENCES)) { + String eipJson = preferences.getString(PROVIDER_KEY, null); + if (eipJson != null) { + preferences.edit().putString(PROVIDER_EIP_DEFINITION, eipJson). + remove(PROVIDER_KEY).apply(); + } + } // ensure all upgrades have passed before storing new information storeAppVersion(); 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 474bf045..bfecda22 100644 --- a/app/src/main/java/se/leap/bitmaskclient/eip/EIP.java +++ b/app/src/main/java/se/leap/bitmaskclient/eip/EIP.java @@ -44,7 +44,7 @@ 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_KEY; +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; @@ -214,7 +214,7 @@ public final class EIP extends IntentService { private JSONObject eipDefinitionFromPreferences() { JSONObject result = new JSONObject(); try { - String eipDefinitionString = preferences.getString(PROVIDER_KEY, ""); + String eipDefinitionString = preferences.getString(PROVIDER_EIP_DEFINITION, ""); if (!eipDefinitionString.isEmpty()) { result = new JSONObject(eipDefinitionString); } diff --git a/app/src/production/java/se/leap/bitmaskclient/ProviderApiManager.java b/app/src/production/java/se/leap/bitmaskclient/ProviderApiManager.java index 1783135d..307e8e05 100644 --- a/app/src/production/java/se/leap/bitmaskclient/ProviderApiManager.java +++ b/app/src/production/java/se/leap/bitmaskclient/ProviderApiManager.java @@ -88,8 +88,6 @@ public class ProviderApiManager extends ProviderApiManagerBase { resetProviderDetails(provider); } - go_ahead = true; - if (!provider.hasDefinition()) { currentDownload = getAndSetProviderJson(provider); } @@ -111,30 +109,28 @@ public class ProviderApiManager extends ProviderApiManagerBase { String caCert = provider.getCaCert(); JSONObject providerDefinition = provider.getDefinition(); - if (go_ahead) { - String providerDotJsonString; - if(providerDefinition.length() == 0 || caCert.isEmpty()) { - String providerJsonUrl = provider.getMainUrlString() + "/provider.json"; - providerDotJsonString = downloadWithCommercialCA(providerJsonUrl, provider); - } else { - providerDotJsonString = downloadFromApiUrlWithProviderCA("/provider.json", caCert, providerDefinition); - } + String providerDotJsonString; + if(providerDefinition.length() == 0 || caCert.isEmpty()) { + String providerJsonUrl = provider.getMainUrlString() + "/provider.json"; + providerDotJsonString = downloadWithCommercialCA(providerJsonUrl, provider); + } else { + providerDotJsonString = downloadFromApiUrlWithProviderCA("/provider.json", caCert, providerDefinition); + } - if (!isValidJson(providerDotJsonString)) { - setErrorResult(result, malformed_url, null); - return result; - } + if (!isValidJson(providerDotJsonString)) { + setErrorResult(result, malformed_url, null); + return result; + } - try { - JSONObject providerJson = new JSONObject(providerDotJsonString); - provider.define(providerJson); + try { + JSONObject providerJson = new JSONObject(providerDotJsonString); + provider.define(providerJson); - result.putBoolean(BROADCAST_RESULT_KEY, true); - } catch (JSONException e) { - String reason_to_fail = pickErrorMessage(providerDotJsonString); - result.putString(ERRORS, reason_to_fail); - result.putBoolean(BROADCAST_RESULT_KEY, false); - } + result.putBoolean(BROADCAST_RESULT_KEY, true); + } catch (JSONException e) { + String reason_to_fail = pickErrorMessage(providerDotJsonString); + result.putString(ERRORS, reason_to_fail); + result.putBoolean(BROADCAST_RESULT_KEY, false); } return result; } @@ -147,22 +143,20 @@ public class ProviderApiManager extends ProviderApiManagerBase { protected Bundle getAndSetEipServiceJson(Provider provider) { Bundle result = new Bundle(); String eipServiceJsonString = ""; - if (go_ahead) { - try { - JSONObject provider_json = provider.getDefinition(); - String eipServiceUrl = provider_json.getString(Provider.API_URL) + "/" + provider_json.getString(Provider.API_VERSION) + "/" + EIP.SERVICE_API_PATH; - eipServiceJsonString = downloadWithProviderCA(provider.getCaCert(), eipServiceUrl); - JSONObject eipServiceJson = new JSONObject(eipServiceJsonString); - eipServiceJson.getInt(Provider.API_RETURN_SERIAL); - - provider.setEipServiceJson(eipServiceJson); - - result.putBoolean(BROADCAST_RESULT_KEY, true); - } catch (NullPointerException | JSONException e) { - String reason_to_fail = pickErrorMessage(eipServiceJsonString); - result.putString(ERRORS, reason_to_fail); - result.putBoolean(BROADCAST_RESULT_KEY, false); - } + try { + JSONObject providerJson = provider.getDefinition(); + String eipServiceUrl = providerJson.getString(Provider.API_URL) + "/" + providerJson.getString(Provider.API_VERSION) + "/" + EIP.SERVICE_API_PATH; + eipServiceJsonString = downloadWithProviderCA(provider.getCaCert(), eipServiceUrl); + JSONObject eipServiceJson = new JSONObject(eipServiceJsonString); + eipServiceJson.getInt(Provider.API_RETURN_SERIAL); + + provider.setEipServiceJson(eipServiceJson); + + result.putBoolean(BROADCAST_RESULT_KEY, true); + } catch (NullPointerException | JSONException e) { + String reasonToFail = pickErrorMessage(eipServiceJsonString); + result.putString(ERRORS, reasonToFail); + result.putBoolean(BROADCAST_RESULT_KEY, false); } return result; } @@ -176,15 +170,15 @@ public class ProviderApiManager extends ProviderApiManagerBase { protected boolean updateVpnCertificate(Provider provider) { try { JSONObject providerJson = provider.getDefinition(); - String provider_main_url = providerJson.getString(Provider.API_URL); - URL newCertStringUrl = new URL(provider_main_url + "/" + providerJson.getString(Provider.API_VERSION) + "/" + PROVIDER_VPN_CERTIFICATE); + String providerMainUrl = providerJson.getString(Provider.API_URL); + URL newCertStringUrl = new URL(providerMainUrl + "/" + providerJson.getString(Provider.API_VERSION) + "/" + PROVIDER_VPN_CERTIFICATE); - String cert_string = downloadWithProviderCA(provider.getCaCert(), newCertStringUrl.toString()); + String certString = downloadWithProviderCA(provider.getCaCert(), newCertStringUrl.toString()); - if (ConfigHelper.checkErroneousDownload(cert_string)) + if (ConfigHelper.checkErroneousDownload(certString)) return false; else - return loadCertificate(cert_string); + return loadCertificate(certString); } catch (IOException e) { // TODO Auto-generated catch block e.printStackTrace(); @@ -203,7 +197,7 @@ public class ProviderApiManager extends ProviderApiManagerBase { String providerDomain = getDomainFromMainURL(provider.getMainUrlString()); String certString = downloadWithCommercialCA(caCertUrl, provider); - if (validCertificate(provider, certString) && go_ahead) { + if (validCertificate(provider, certString)) { provider.setCaCert(certString); preferences.edit().putString(Provider.CA_CERT + "." + providerDomain, certString).apply(); result.putBoolean(BROADCAST_RESULT_KEY, true); diff --git a/app/src/production/java/se/leap/bitmaskclient/ProviderListActivity.java b/app/src/production/java/se/leap/bitmaskclient/ProviderListActivity.java index 2df0ffa1..725ede3e 100644 --- a/app/src/production/java/se/leap/bitmaskclient/ProviderListActivity.java +++ b/app/src/production/java/se/leap/bitmaskclient/ProviderListActivity.java @@ -16,8 +16,6 @@ */ package se.leap.bitmaskclient; -import android.content.Intent; -import android.os.Bundle; import android.support.annotation.NonNull; import java.net.MalformedURLException; @@ -69,14 +67,7 @@ public class ProviderListActivity extends ProviderListBaseActivity { @Override public void retrySetUpProvider(@NonNull Provider provider) { - cancelSettingUpProvider(); - if (!provider.hasCaCert()) { - addAndSelectNewProvider(provider.getMainUrlString()); - } else { - showProgressBar(); - - ProviderAPICommand.execute(this, SET_UP_PROVIDER, provider); - } + ProviderAPICommand.execute(this, SET_UP_PROVIDER, provider); } } -- cgit v1.2.3 From 7f84522ce01e8bcf1b3063ff7fa19a9a7dca61ea Mon Sep 17 00:00:00 2001 From: Fup Duck Date: Fri, 9 Feb 2018 18:29:51 +0100 Subject: 8827 - resolve discussions * use LocalBroadcastManager for broadcasts * add NullPointer checks to EipFragment * store VpnCertificate & private key in Provider not preferences * EipFragment uses provider instead of reading from preferences * use switch in ProviderApiManager --- .../se/leap/bitmaskclient/ProviderApiManager.java | 12 +- .../java/se/leap/bitmaskclient/ConfigHelper.java | 9 ++ .../java/se/leap/bitmaskclient/EipFragment.java | 130 ++++++++++--------- .../main/java/se/leap/bitmaskclient/Provider.java | 65 ++++++++-- .../java/se/leap/bitmaskclient/ProviderAPI.java | 8 +- .../leap/bitmaskclient/ProviderApiManagerBase.java | 144 +++++++++++---------- .../ProviderCredentialsBaseActivity.java | 5 +- .../bitmaskclient/ProviderListBaseActivity.java | 5 +- .../main/java/se/leap/bitmaskclient/eip/EIP.java | 3 +- .../java/se/leap/bitmaskclient/eip/EipCommand.java | 23 +++- 10 files changed, 243 insertions(+), 161 deletions(-) diff --git a/app/src/insecure/java/se/leap/bitmaskclient/ProviderApiManager.java b/app/src/insecure/java/se/leap/bitmaskclient/ProviderApiManager.java index dfc98ffb..d57dfe6d 100644 --- a/app/src/insecure/java/se/leap/bitmaskclient/ProviderApiManager.java +++ b/app/src/insecure/java/se/leap/bitmaskclient/ProviderApiManager.java @@ -171,9 +171,15 @@ public class ProviderApiManager extends ProviderApiManagerBase { eipServiceJsonString = downloadWithProviderCA(provider.getCaCert(), eipServiceUrl, lastDangerOn); JSONObject eipServiceJson = new JSONObject(eipServiceJsonString); - provider.setEipServiceJson(eipServiceJson); - result.putBoolean(BROADCAST_RESULT_KEY, true); + if (eipServiceJson.has(ERRORS)) { + String reasonToFail = pickErrorMessage(eipServiceJsonString); + result.putString(ERRORS, reasonToFail); + result.putBoolean(BROADCAST_RESULT_KEY, false); + } else{ + provider.setEipServiceJson(eipServiceJson); + result.putBoolean(BROADCAST_RESULT_KEY, true); + } } catch (NullPointerException | JSONException e) { String reasonToFail = pickErrorMessage(eipServiceJsonString); result.putString(ERRORS, reasonToFail); @@ -201,7 +207,7 @@ public class ProviderApiManager extends ProviderApiManagerBase { if (certString == null || certString.isEmpty() || ConfigHelper.checkErroneousDownload(certString)) return false; else - return loadCertificate(certString); + return loadCertificate(provider, certString); } catch (IOException e) { // TODO Auto-generated catch block e.printStackTrace(); diff --git a/app/src/main/java/se/leap/bitmaskclient/ConfigHelper.java b/app/src/main/java/se/leap/bitmaskclient/ConfigHelper.java index 238f0ea1..329fd543 100644 --- a/app/src/main/java/se/leap/bitmaskclient/ConfigHelper.java +++ b/app/src/main/java/se/leap/bitmaskclient/ConfigHelper.java @@ -56,6 +56,8 @@ import static android.R.attr.name; import static se.leap.bitmaskclient.Constants.PREFERENCES_APP_VERSION; import static se.leap.bitmaskclient.Constants.PROVIDER_CONFIGURED; import static se.leap.bitmaskclient.Constants.PROVIDER_EIP_DEFINITION; +import static se.leap.bitmaskclient.Constants.PROVIDER_PRIVATE_KEY; +import static se.leap.bitmaskclient.Constants.PROVIDER_VPN_CERTIFICATE; /** * Stores constants, and implements auxiliary methods used across all Bitmask Android classes. @@ -279,6 +281,8 @@ public class ConfigHelper { provider.setMainUrl(new URL(preferences.getString(Provider.MAIN_URL, ""))); provider.define(new JSONObject(preferences.getString(Provider.KEY, ""))); provider.setCaCert(preferences.getString(Provider.CA_CERT, "")); + provider.setVpnCertificate(preferences.getString(PROVIDER_VPN_CERTIFICATE, "")); + provider.setPrivateKey(preferences.getString(PROVIDER_PRIVATE_KEY, "")); } catch (MalformedURLException | JSONException e) { e.printStackTrace(); } @@ -350,12 +354,15 @@ public class ConfigHelper { } // TODO: replace commit with apply after refactoring EIP + //FIXME: don't save private keys in shared preferences! use the keystore public static void storeProviderInPreferences(SharedPreferences preferences, Provider provider) { preferences.edit().putBoolean(PROVIDER_CONFIGURED, true). putString(Provider.MAIN_URL, provider.getMainUrlString()). putString(Provider.KEY, provider.getDefinitionString()). putString(Provider.CA_CERT, provider.getCaCert()). putString(PROVIDER_EIP_DEFINITION, provider.getEipServiceJsonString()). + putString(PROVIDER_PRIVATE_KEY, provider.getPrivateKey()). + putString(PROVIDER_VPN_CERTIFICATE, provider.getVpnCertificate()). commit(); String providerDomain = provider.getDomain(); @@ -364,6 +371,8 @@ 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/EipFragment.java b/app/src/main/java/se/leap/bitmaskclient/EipFragment.java index ceae6706..b4c7a7de 100644 --- a/app/src/main/java/se/leap/bitmaskclient/EipFragment.java +++ b/app/src/main/java/se/leap/bitmaskclient/EipFragment.java @@ -29,12 +29,11 @@ import android.content.SharedPreferences; import android.graphics.ColorMatrix; import android.graphics.ColorMatrixColorFilter; import android.os.Bundle; -import android.os.Handler; import android.os.IBinder; import android.os.RemoteException; -import android.os.ResultReceiver; 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; @@ -56,13 +55,14 @@ import de.blinkt.openvpn.core.VpnStatus; import se.leap.bitmaskclient.eip.EipCommand; import se.leap.bitmaskclient.eip.EipStatus; import se.leap.bitmaskclient.eip.VoidVpnService; -import se.leap.bitmaskclient.userstatus.User; 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_KEY; import static se.leap.bitmaskclient.Constants.EIP_ACTION_CHECK_CERT_VALIDITY; import static se.leap.bitmaskclient.Constants.EIP_ACTION_START; @@ -72,14 +72,15 @@ 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_ALLOWED_REGISTERED; -import static se.leap.bitmaskclient.Constants.PROVIDER_ALLOW_ANONYMOUS; import static se.leap.bitmaskclient.Constants.PROVIDER_KEY; -import static se.leap.bitmaskclient.Constants.PROVIDER_VPN_CERTIFICATE; 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; public class EipFragment extends Fragment implements Observer { @@ -111,12 +112,10 @@ public class EipFragment extends Fragment implements Observer { @InjectView(R.id.vpn_route) TextView vpnRoute; - private EIPReceiver eipReceiver; private EipStatus eipStatus; private boolean wantsToConnect; - private ProviderAPIResultReceiver providerAPIResultReceiver; - private EIPBroadcastReceiver eipBroadcastReceiver; + private EIPFragmentBroadcastReceiver eipFragmentBroadcastReceiver; private IOpenVPNServiceInternal mService; private ServiceConnection openVpnConnection = new ServiceConnection() { @@ -161,9 +160,7 @@ public class EipFragment extends Fragment implements Observer { public void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); eipStatus = EipStatus.getInstance(); - eipReceiver = new EIPReceiver(new Handler()); - eipBroadcastReceiver = new EIPBroadcastReceiver(); - providerAPIResultReceiver = new ProviderAPIResultReceiver(new Handler(), new EipFragmentReceiver()); + eipFragmentBroadcastReceiver = new EIPFragmentBroadcastReceiver(); Activity activity = getActivity(); if (activity != null) { preferences = getActivity().getSharedPreferences(SHARED_PREFERENCES, Context.MODE_PRIVATE); @@ -202,7 +199,7 @@ public class EipFragment extends Fragment implements Observer { Activity activity = getActivity(); if (activity != null) { getActivity().unbindService(openVpnConnection); - getActivity().unregisterReceiver(eipBroadcastReceiver); + LocalBroadcastManager.getInstance(activity).unregisterReceiver(eipFragmentBroadcastReceiver); } Log.d(TAG, "broadcast unregistered"); } @@ -246,30 +243,36 @@ public class EipFragment extends Fragment implements Observer { } private void handleSwitchOn() { - if (canStartEIP()) + Context context = getContext(); + if (context == null) { + Log.e(TAG, "context is null when switch turning on"); + return; + } + + if (canStartEIP()) { startEipFromScratch(); - else if (canLogInToStartEIP()) { + } 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); } } else { - Log.d(TAG, "WHAT IS GOING ON HERE?!"); - // TODO: implement a fallback: check if vpncertificate was not downloaded properly or give - // a user feedback. A button that does nothing on click is not a good option + // provider has no VpnCertificate but user is logged in + downloadVpnCertificate(); } } private boolean canStartEIP() { - boolean certificateExists = !preferences.getString(PROVIDER_VPN_CERTIFICATE, "").isEmpty(); - boolean isAllowedAnon = preferences.getBoolean(PROVIDER_ALLOW_ANONYMOUS, false); + boolean certificateExists = !provider.hasVpnCertificate(); + boolean isAllowedAnon = provider.allowsAnonymous(); return (isAllowedAnon || certificateExists) && !eipStatus.isConnected() && !eipStatus.isConnecting(); } private boolean canLogInToStartEIP() { - boolean isAllowedRegistered = preferences.getBoolean(PROVIDER_ALLOWED_REGISTERED, false); + boolean isAllowedRegistered = provider.allowsRegistered(); boolean isLoggedIn = !LeapSRPSession.getToken().isEmpty(); return isAllowedRegistered && !isLoggedIn && !eipStatus.isConnecting() && !eipStatus.isConnected(); } @@ -308,7 +311,12 @@ public class EipFragment extends Fragment implements Observer { public void startEipFromScratch() { wantsToConnect = false; saveStatus(true); - EipCommand.startVPN(getContext(), eipReceiver); + Context context = getContext(); + if (context != null) { + EipCommand.startVPN(context); + } else { + Log.e(TAG, "context is null when trying to start VPN"); + } } private void stop() { @@ -344,8 +352,12 @@ public class EipFragment extends Fragment implements Observer { } protected void stopEipIfPossible() { - //FIXME: no need to start a service here! - EipCommand.stopVPN(getContext(), eipReceiver); + Context context = getContext(); + if (context != null) { + EipCommand.stopVPN(getContext()); + } else { + Log.e(TAG, "context is null when trying to stop EIP"); + } } protected void askToStopEIP() { @@ -441,36 +453,26 @@ public class EipFragment extends Fragment implements Observer { } } - protected class EIPReceiver extends ResultReceiver { - - EIPReceiver(Handler handler) { - super(handler); - } - - @Override - protected void onReceiveResult(int resultCode, Bundle resultData) { - super.onReceiveResult(resultCode, resultData); - - handleEIPEvent(resultCode, resultData); - } - } - - private class EIPBroadcastReceiver extends BroadcastReceiver { + 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 || !action.equalsIgnoreCase(BROADCAST_EIP_EVENT)) { + if (action == null) { return; } int resultCode = intent.getIntExtra(BROADCAST_RESULT_KEY, -1); Bundle resultData = intent.getParcelableExtra(BROADCAST_RESULT_KEY); - Log.d(TAG, "Broadcast resultCode: " + Integer.toString(resultCode)); - - handleEIPEvent(resultCode, resultData); - + switch (action) { + case BROADCAST_EIP_EVENT: + handleEIPEvent(resultCode, resultData); + break; + case BROADCAST_PROVIDER_API_EVENT: + handleProviderApiEvent(resultCode, resultData); + break; + } } } @@ -547,37 +549,45 @@ public class EipFragment extends Fragment implements Observer { background.setImageAlpha(255); } - private class EipFragmentReceiver implements ProviderAPIResultReceiver.Receiver{ + public void handleProviderApiEvent(int resultCode, Bundle resultData) { + Context context = getContext(); + if (context == null) { + return; + } - @Override - public void onReceiveResult(int resultCode, Bundle resultData) { - if (resultCode == ProviderAPI.CORRECTLY_DOWNLOADED_EIP_SERVICE) { + // TODO call DOWNLOAD_EIP_SERVICES ore remove respective cases + switch (resultCode) { + case CORRECTLY_DOWNLOADED_EIP_SERVICE: provider = resultData.getParcelable(PROVIDER_KEY); - EipCommand.updateEipService(getContext(), eipReceiver); - } else if (resultCode == ProviderAPI.INCORRECTLY_DOWNLOADED_EIP_SERVICE) { + EipCommand.updateEipService(context); + break; + case INCORRECTLY_DOWNLOADED_EIP_SERVICE: //dashboard.setResult(RESULT_CANCELED); - // TODO CATCH ME IF YOU CAN - } + // 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() { - boolean is_authenticated = User.loggedIn(); - boolean allowed_anon = preferences.getBoolean(PROVIDER_ALLOW_ANONYMOUS, false); - if (allowed_anon || is_authenticated) { - ProviderAPICommand.execute(getContext(), DOWNLOAD_CERTIFICATE, provider, providerAPIResultReceiver); - } + ProviderAPICommand.execute(getContext(), DOWNLOAD_CERTIFICATE, provider); } private void setUpBroadcastReceiver() { Activity activity = getActivity(); if (activity != null) { IntentFilter updateIntentFilter = new IntentFilter(BROADCAST_EIP_EVENT); - updateIntentFilter.addCategory(Intent.CATEGORY_DEFAULT); - activity.registerReceiver(eipBroadcastReceiver, updateIntentFilter); + 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 boradcat receiver"); + Log.e(TAG, "activity null when setting up broadcast receiver"); } } diff --git a/app/src/main/java/se/leap/bitmaskclient/Provider.java b/app/src/main/java/se/leap/bitmaskclient/Provider.java index 9595b147..4d608222 100644 --- a/app/src/main/java/se/leap/bitmaskclient/Provider.java +++ b/app/src/main/java/se/leap/bitmaskclient/Provider.java @@ -32,6 +32,7 @@ import java.util.Locale; import static se.leap.bitmaskclient.Constants.PROVIDER_ALLOWED_REGISTERED; import static se.leap.bitmaskclient.Constants.PROVIDER_ALLOW_ANONYMOUS; +import static se.leap.bitmaskclient.ProviderAPI.ERRORS; /** * @author Sean Leonard @@ -48,6 +49,8 @@ public final class Provider implements Parcelable { private String caCert = ""; private String caCertFingerprint = ""; private String apiVerson = ""; + private String privateKey = ""; + private String vpnCertificate = ""; private boolean allowAnonymous; private boolean allowRegistered; @@ -243,7 +246,8 @@ public final class Provider implements Parcelable { } protected boolean hasEIP() { - return getEipServiceJson() != null && getEipServiceJson().length() > 0; + return getEipServiceJson() != null && getEipServiceJson().length() > 0 + && !getEipServiceJson().has(ERRORS); } public boolean allowsRegistration() { @@ -266,6 +270,8 @@ public final class Provider implements Parcelable { parcel.writeString(getCaCert()); parcel.writeString(getCaCertFingerprint()); parcel.writeString(getEipServiceJsonString()); + parcel.writeString(getPrivateKey()); + parcel.writeString(getVpnCertificate()); } @Override @@ -303,22 +309,30 @@ public final class Provider implements Parcelable { private Provider(Parcel in) { try { mainUrl.setUrl(new URL(in.readString())); - String definitionString = in.readString(); - if (!definitionString.isEmpty()) { - definition = new JSONObject((definitionString)); + String tmpString = in.readString(); + if (!tmpString.isEmpty()) { + definition = new JSONObject((tmpString)); parseDefinition(definition); } - String caCert = in.readString(); - if (!caCert.isEmpty()) { - this.caCert = caCert; + tmpString = in.readString(); + if (!tmpString.isEmpty()) { + this.caCert = tmpString; } - String caCertFingerprint = in.readString(); - if (!caCertFingerprint.isEmpty()) { - this.caCertFingerprint = caCertFingerprint; + tmpString = in.readString(); + if (!tmpString.isEmpty()) { + this.caCertFingerprint = tmpString; } - String eipServiceJson = in.readString(); - if (!eipServiceJson.isEmpty()) { - this.setEipServiceJson(new JSONObject(eipServiceJson)); + tmpString = in.readString(); + if (!tmpString.isEmpty()) { + this.setEipServiceJson(new JSONObject(tmpString)); + } + tmpString = in.readString(); + if (!tmpString.isEmpty()) { + this.setPrivateKey(tmpString); + } + tmpString = in.readString(); + if (!tmpString.isEmpty()) { + this.setVpnCertificate(tmpString); } } catch (MalformedURLException | JSONException e) { e.printStackTrace(); @@ -355,8 +369,12 @@ public final class Provider implements Parcelable { return allowRegistered; } - public void setEipServiceJson(JSONObject eipServiceJson) { + public boolean setEipServiceJson(JSONObject eipServiceJson) { + if (eipServiceJson.has(ERRORS)) { + return false; + } this.eipServiceJson = eipServiceJson; + return true; } public JSONObject getEipServiceJson() { @@ -374,4 +392,23 @@ public final class Provider implements Parcelable { caCert.isEmpty(); } + public String getPrivateKey() { + return privateKey; + } + + public void setPrivateKey(String privateKey) { + this.privateKey = privateKey; + } + + public String getVpnCertificate() { + return vpnCertificate; + } + + public void setVpnCertificate(String vpnCertificate) { + this.vpnCertificate = vpnCertificate; + } + + public boolean hasVpnCertificate() { + return getVpnCertificate() != null && getVpnCertificate().length() >0 ; + } } diff --git a/app/src/main/java/se/leap/bitmaskclient/ProviderAPI.java b/app/src/main/java/se/leap/bitmaskclient/ProviderAPI.java index 4bffd1b2..b3399416 100644 --- a/app/src/main/java/se/leap/bitmaskclient/ProviderAPI.java +++ b/app/src/main/java/se/leap/bitmaskclient/ProviderAPI.java @@ -20,6 +20,7 @@ import android.annotation.SuppressLint; import android.app.IntentService; import android.content.Intent; import android.content.SharedPreferences; +import android.support.v4.content.LocalBroadcastManager; import static se.leap.bitmaskclient.Constants.SHARED_PREFERENCES; @@ -49,9 +50,8 @@ public class ProviderAPI extends IntentService implements ProviderApiManagerBase ERRORS = "errors", ERRORID = "errorId", UPDATE_PROGRESSBAR = "update_progressbar", - CURRENT_PROGRESS = "current_progress", - DOWNLOAD_EIP_SERVICE = TAG + ".DOWNLOAD_EIP_SERVICE", - PROVIDER_SET_UP = TAG + ".PROVIDER_SET_UP"; + DOWNLOAD_EIP_SERVICE = "ProviderAPI.DOWNLOAD_EIP_SERVICE", + PROVIDER_SET_UP = "ProviderAPI.PROVIDER_SET_UP"; final public static int SUCCESSFUL_LOGIN = 3, @@ -91,7 +91,7 @@ public class ProviderAPI extends IntentService implements ProviderApiManagerBase @Override public void broadcastEvent(Intent intent) { - sendBroadcast(intent); + LocalBroadcastManager.getInstance(this).sendBroadcast(intent); } @Override diff --git a/app/src/main/java/se/leap/bitmaskclient/ProviderApiManagerBase.java b/app/src/main/java/se/leap/bitmaskclient/ProviderApiManagerBase.java index f1c0ecef..a9321a9c 100644 --- a/app/src/main/java/se/leap/bitmaskclient/ProviderApiManagerBase.java +++ b/app/src/main/java/se/leap/bitmaskclient/ProviderApiManagerBase.java @@ -142,63 +142,72 @@ public abstract class ProviderApiManagerBase { return; } - if (action.equals(UPDATE_PROVIDER_DETAILS)) { - resetProviderDetails(provider); - Bundle task = new Bundle(); - Bundle result = setUpProvider(provider, task); - if (result.getBoolean(BROADCAST_RESULT_KEY)) { - sendToReceiverOrBroadcast(receiver, PROVIDER_OK, result, provider); - } else { - sendToReceiverOrBroadcast(receiver, PROVIDER_NOK, result, provider); - } - } else if (action.equalsIgnoreCase(SET_UP_PROVIDER)) { - Bundle result = setUpProvider(provider, parameters); - if (result.getBoolean(BROADCAST_RESULT_KEY)) { - sendToReceiverOrBroadcast(receiver, PROVIDER_OK, result, provider); - } else { - sendToReceiverOrBroadcast(receiver, PROVIDER_NOK, result, provider); - } - } else if (action.equalsIgnoreCase(SIGN_UP)) { - Bundle result = tryToRegister(parameters); - if (result.getBoolean(BROADCAST_RESULT_KEY)) { - sendToReceiverOrBroadcast(receiver, SUCCESSFUL_SIGNUP, result, provider); - } else { - sendToReceiverOrBroadcast(receiver, FAILED_SIGNUP, result, provider); - } - } else if (action.equalsIgnoreCase(LOG_IN)) { - Bundle result = tryToAuthenticate(provider, parameters); - if (result.getBoolean(BROADCAST_RESULT_KEY)) { - sendToReceiverOrBroadcast(receiver, SUCCESSFUL_LOGIN, result, provider); - } else { - sendToReceiverOrBroadcast(receiver, FAILED_LOGIN, result, provider); - } - } else if (action.equalsIgnoreCase(LOG_OUT)) { - if (logOut(provider)) { - sendToReceiverOrBroadcast(receiver, SUCCESSFUL_LOGOUT, Bundle.EMPTY, provider); - } else { - sendToReceiverOrBroadcast(receiver, LOGOUT_FAILED, Bundle.EMPTY, provider); - } - } else if (action.equalsIgnoreCase(DOWNLOAD_CERTIFICATE)) { - if (updateVpnCertificate(provider)) { - sendToReceiverOrBroadcast(receiver, CORRECTLY_DOWNLOADED_CERTIFICATE, Bundle.EMPTY, provider); - } else { - sendToReceiverOrBroadcast(receiver, INCORRECTLY_DOWNLOADED_CERTIFICATE, Bundle.EMPTY, provider); - } - } else if (action.equalsIgnoreCase(DOWNLOAD_EIP_SERVICE)) { - Bundle result = getAndSetEipServiceJson(provider); - if (result.getBoolean(BROADCAST_RESULT_KEY)) { - sendToReceiverOrBroadcast(receiver, CORRECTLY_DOWNLOADED_EIP_SERVICE, result, provider); - } else { - sendToReceiverOrBroadcast(receiver, INCORRECTLY_DOWNLOADED_EIP_SERVICE, result, provider); - } - } else if (action.equalsIgnoreCase(PROVIDER_SET_UP)) { - if(provider.hasEIP() && provider.hasCaCert() && provider.hasDefinition()) { - if(receiver!= null) { - Bundle result = new Bundle(); - result.putParcelable(PROVIDER_KEY, provider); - receiver.send(PROVIDER_OK, result); + Bundle result = new Bundle(); + switch (action) { + case UPDATE_PROVIDER_DETAILS: + resetProviderDetails(provider); + Bundle task = new Bundle(); + result = setUpProvider(provider, task); + if (result.getBoolean(BROADCAST_RESULT_KEY)) { + sendToReceiverOrBroadcast(receiver, PROVIDER_OK, result, provider); + } else { + sendToReceiverOrBroadcast(receiver, PROVIDER_NOK, result, provider); } - } + break; + case SET_UP_PROVIDER: + result = setUpProvider(provider, parameters); + if (result.getBoolean(BROADCAST_RESULT_KEY)) { + sendToReceiverOrBroadcast(receiver, PROVIDER_OK, result, provider); + } else { + sendToReceiverOrBroadcast(receiver, PROVIDER_NOK, result, provider); + } + break; + case SIGN_UP: + result = tryToRegister(parameters); + if (result.getBoolean(BROADCAST_RESULT_KEY)) { + sendToReceiverOrBroadcast(receiver, SUCCESSFUL_SIGNUP, result, provider); + } else { + sendToReceiverOrBroadcast(receiver, FAILED_SIGNUP, result, provider); + } + break; + case LOG_IN: + result = tryToAuthenticate(provider, parameters); + if (result.getBoolean(BROADCAST_RESULT_KEY)) { + sendToReceiverOrBroadcast(receiver, SUCCESSFUL_LOGIN, result, provider); + } else { + sendToReceiverOrBroadcast(receiver, FAILED_LOGIN, result, provider); + } + break; + case LOG_OUT: + if (logOut(provider)) { + sendToReceiverOrBroadcast(receiver, SUCCESSFUL_LOGOUT, Bundle.EMPTY, provider); + } else { + sendToReceiverOrBroadcast(receiver, LOGOUT_FAILED, Bundle.EMPTY, provider); + } + break; + case DOWNLOAD_CERTIFICATE: + if (updateVpnCertificate(provider)) { + sendToReceiverOrBroadcast(receiver, CORRECTLY_DOWNLOADED_CERTIFICATE, Bundle.EMPTY, provider); + } else { + sendToReceiverOrBroadcast(receiver, INCORRECTLY_DOWNLOADED_CERTIFICATE, Bundle.EMPTY, provider); + } + break; + case DOWNLOAD_EIP_SERVICE: + result = getAndSetEipServiceJson(provider); + if (result.getBoolean(BROADCAST_RESULT_KEY)) { + sendToReceiverOrBroadcast(receiver, CORRECTLY_DOWNLOADED_EIP_SERVICE, result, provider); + } else { + sendToReceiverOrBroadcast(receiver, INCORRECTLY_DOWNLOADED_EIP_SERVICE, result, provider); + } + break; + case PROVIDER_SET_UP: + if(provider.hasEIP() && provider.hasCaCert() && provider.hasDefinition()) { + if(receiver!= null) { + result.putParcelable(PROVIDER_KEY, provider); + receiver.send(PROVIDER_OK, result); + } + } + break; } } @@ -824,22 +833,22 @@ public abstract class ProviderApiManagerBase { * Interprets the error message as a JSON object and extract the "errors" keyword pair. * If the error message is not a JSON object, then it is returned untouched. * - * @param string_json_error_message + * @param stringJsonErrorMessage * @return final error message */ - protected String pickErrorMessage(String string_json_error_message) { - String error_message = ""; + protected String pickErrorMessage(String stringJsonErrorMessage) { + String errorMessage = ""; try { - JSONObject json_error_message = new JSONObject(string_json_error_message); - error_message = json_error_message.getString(ERRORS); + JSONObject jsonErrorMessage = new JSONObject(stringJsonErrorMessage); + errorMessage = jsonErrorMessage.getString(ERRORS); } catch (JSONException e) { // TODO Auto-generated catch block - error_message = string_json_error_message; + errorMessage = stringJsonErrorMessage; } catch (NullPointerException e) { //do nothing } - return error_message; + return errorMessage; } @NonNull @@ -867,8 +876,7 @@ public abstract class ProviderApiManagerBase { return false; } - //FIXME: don't save private keys in shared preferences! use the keystore - protected boolean loadCertificate(String cert_string) { + protected boolean loadCertificate(Provider provider, String cert_string) { if (cert_string == null) { return false; } @@ -887,13 +895,13 @@ public abstract class ProviderApiManagerBase { RSAPrivateKey key = ConfigHelper.parseRsaKeyFromString(keyString); keyString = Base64.encodeToString(key.getEncoded(), Base64.DEFAULT); - preferences.edit().putString(PROVIDER_PRIVATE_KEY, "-----BEGIN RSA PRIVATE KEY-----\n" + keyString + "-----END RSA PRIVATE KEY-----").commit(); + provider.setPrivateKey( "-----BEGIN RSA PRIVATE KEY-----\n" + keyString + "-----END RSA PRIVATE KEY-----"); X509Certificate certificate = ConfigHelper.parseX509CertificateFromString(certificateString); certificateString = Base64.encodeToString(certificate.getEncoded(), Base64.DEFAULT); - preferences.edit().putString(PROVIDER_VPN_CERTIFICATE, "-----BEGIN CERTIFICATE-----\n" + certificateString + "-----END CERTIFICATE-----").commit(); + provider.setVpnCertificate( "-----BEGIN CERTIFICATE-----\n" + certificateString + "-----END CERTIFICATE-----"); return true; - } catch (CertificateException e) { + } catch (CertificateException | NullPointerException e) { // TODO Auto-generated catch block e.printStackTrace(); return false; diff --git a/app/src/main/java/se/leap/bitmaskclient/ProviderCredentialsBaseActivity.java b/app/src/main/java/se/leap/bitmaskclient/ProviderCredentialsBaseActivity.java index a309bdf9..88221007 100644 --- a/app/src/main/java/se/leap/bitmaskclient/ProviderCredentialsBaseActivity.java +++ b/app/src/main/java/se/leap/bitmaskclient/ProviderCredentialsBaseActivity.java @@ -9,6 +9,7 @@ import android.support.annotation.Nullable; import android.support.annotation.StringRes; import android.support.design.widget.TextInputEditText; import android.support.design.widget.TextInputLayout; +import android.support.v4.content.LocalBroadcastManager; import android.support.v7.widget.AppCompatButton; import android.support.v7.widget.AppCompatTextView; import android.text.Editable; @@ -89,7 +90,7 @@ public abstract class ProviderCredentialsBaseActivity extends ConfigWizardBaseAc IntentFilter updateIntentFilter = new IntentFilter(BROADCAST_PROVIDER_API_EVENT); updateIntentFilter.addCategory(Intent.CATEGORY_DEFAULT); - registerReceiver(providerAPIBroadcastReceiver, updateIntentFilter); + LocalBroadcastManager.getInstance(this).registerReceiver(providerAPIBroadcastReceiver, updateIntentFilter); setUpListeners(); if(savedInstanceState != null) { @@ -147,7 +148,7 @@ public abstract class ProviderCredentialsBaseActivity extends ConfigWizardBaseAc protected void onDestroy() { super.onDestroy(); if (providerAPIBroadcastReceiver != null) - unregisterReceiver(providerAPIBroadcastReceiver); + LocalBroadcastManager.getInstance(this).unregisterReceiver(providerAPIBroadcastReceiver); } @OnClick(R.id.button) diff --git a/app/src/main/java/se/leap/bitmaskclient/ProviderListBaseActivity.java b/app/src/main/java/se/leap/bitmaskclient/ProviderListBaseActivity.java index 6fa3b503..1fb54884 100644 --- a/app/src/main/java/se/leap/bitmaskclient/ProviderListBaseActivity.java +++ b/app/src/main/java/se/leap/bitmaskclient/ProviderListBaseActivity.java @@ -26,6 +26,7 @@ import android.os.Handler; import android.support.annotation.NonNull; import android.support.v4.app.DialogFragment; import android.support.v4.app.FragmentTransaction; +import android.support.v4.content.LocalBroadcastManager; import android.util.Log; import android.view.Menu; import android.widget.ListView; @@ -188,7 +189,7 @@ public abstract class ProviderListBaseActivity extends ConfigWizardBaseActivity super.onPause(); isActivityShowing = false; if (providerAPIBroadcastReceiver != null) - unregisterReceiver(providerAPIBroadcastReceiver); + LocalBroadcastManager.getInstance(this).unregisterReceiver(providerAPIBroadcastReceiver); } @Override @@ -213,7 +214,7 @@ public abstract class ProviderListBaseActivity extends ConfigWizardBaseActivity IntentFilter updateIntentFilter = new IntentFilter(BROADCAST_PROVIDER_API_EVENT); updateIntentFilter.addCategory(Intent.CATEGORY_DEFAULT); - registerReceiver(providerAPIBroadcastReceiver, updateIntentFilter); + LocalBroadcastManager.getInstance(this).registerReceiver(providerAPIBroadcastReceiver, updateIntentFilter); } void handleProviderSetUp(Provider handledProvider) { 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 bfecda22..46528b85 100644 --- a/app/src/main/java/se/leap/bitmaskclient/eip/EIP.java +++ b/app/src/main/java/se/leap/bitmaskclient/eip/EIP.java @@ -22,6 +22,7 @@ import android.content.Intent; import android.content.SharedPreferences; import android.os.Bundle; import android.os.ResultReceiver; +import android.support.v4.content.LocalBroadcastManager; import android.util.Log; import org.json.JSONException; @@ -267,7 +268,7 @@ public final class EIP extends IntentService { intentUpdate.putExtra(BROADCAST_RESULT_CODE, resultCode); intentUpdate.putExtra(BROADCAST_RESULT_KEY, resultData); Log.d(TAG, "sending broadcast"); - sendBroadcast(intentUpdate); + LocalBroadcastManager.getInstance(this).sendBroadcast(intentUpdate); } } 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 35599ab4..1c778ec7 100644 --- a/app/src/main/java/se/leap/bitmaskclient/eip/EipCommand.java +++ b/app/src/main/java/se/leap/bitmaskclient/eip/EipCommand.java @@ -3,10 +3,12 @@ package se.leap.bitmaskclient.eip; import android.content.Context; import android.content.Intent; import android.os.ResultReceiver; +import android.support.annotation.NonNull; import org.jetbrains.annotations.NotNull; 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; @@ -38,29 +40,36 @@ public class EipCommand { context.startService(vpnIntent); } - public static void updateEipService(Context context, ResultReceiver resultReceiver) { + public static void updateEipService(@NonNull Context context, ResultReceiver resultReceiver) { execute(context, EIP_ACTION_UPDATE, resultReceiver); } - public static void updateEipService(Context context) { + public static void updateEipService(@NonNull Context context) { execute(context, EIP_ACTION_UPDATE); } - public static void startVPN(Context context) { + public static void startVPN(@NonNull Context context) { execute(context, EIP_ACTION_START); } - public static void startVPN(Context context, ResultReceiver resultReceiver) { + public static void startVPN(@NonNull Context context, ResultReceiver resultReceiver) { execute(context, EIP_ACTION_START, resultReceiver); } - - public static void stopVPN(Context context) { + public static void stopVPN(@NonNull Context context) { execute(context, EIP_ACTION_STOP); } - public static void stopVPN(Context context, ResultReceiver resultReceiver) { + public static void stopVPN(@NonNull Context context, ResultReceiver resultReceiver) { execute(context, EIP_ACTION_STOP, resultReceiver); } + public static void checkVpnCertificate(@NonNull Context context) { + execute(context, EIP_ACTION_CHECK_CERT_VALIDITY); + } + + public static void checkVpnCertificate(@NonNull Context context, ResultReceiver resultReceiver) { + execute(context, EIP_ACTION_CHECK_CERT_VALIDITY, resultReceiver); + } + } -- cgit v1.2.3 From a5ee219936bfe89b30b073fc73501d891a25c1d7 Mon Sep 17 00:00:00 2001 From: Fup Duck Date: Fri, 9 Feb 2018 20:44:56 +0100 Subject: 8827 - save privatekey and vpncert --- .../bitmaskclient/ProviderListBaseActivity.java | 5 +++-- .../java/se/leap/bitmaskclient/eip/Gateway.java | 24 ++++++++++++---------- .../se/leap/bitmaskclient/eip/GatewaysManager.java | 6 +++--- 3 files changed, 19 insertions(+), 16 deletions(-) diff --git a/app/src/main/java/se/leap/bitmaskclient/ProviderListBaseActivity.java b/app/src/main/java/se/leap/bitmaskclient/ProviderListBaseActivity.java index 1fb54884..41d2d849 100644 --- a/app/src/main/java/se/leap/bitmaskclient/ProviderListBaseActivity.java +++ b/app/src/main/java/se/leap/bitmaskclient/ProviderListBaseActivity.java @@ -233,7 +233,8 @@ public abstract class ProviderListBaseActivity extends ConfigWizardBaseActivity showDownloadFailedDialog(); } - void handleCorrectlyDownloadedCertificate() { + void handleCorrectlyDownloadedCertificate(Provider handledProvider) { + this.provider = handledProvider; showProviderDetails(); } @@ -419,7 +420,7 @@ public abstract class ProviderListBaseActivity extends ConfigWizardBaseActivity handleProviderSetupFailed(resultData); break; case CORRECTLY_DOWNLOADED_CERTIFICATE: - handleCorrectlyDownloadedCertificate(); + handleCorrectlyDownloadedCertificate(handledProvider); break; case INCORRECTLY_DOWNLOADED_CERTIFICATE: handleIncorrectlyDownloadedCertificate(); diff --git a/app/src/main/java/se/leap/bitmaskclient/eip/Gateway.java b/app/src/main/java/se/leap/bitmaskclient/eip/Gateway.java index ff7d011e..6cccdcd2 100644 --- a/app/src/main/java/se/leap/bitmaskclient/eip/Gateway.java +++ b/app/src/main/java/se/leap/bitmaskclient/eip/Gateway.java @@ -16,14 +16,16 @@ */ package se.leap.bitmaskclient.eip; -import com.google.gson.*; +import com.google.gson.Gson; -import org.json.*; +import org.json.JSONException; +import org.json.JSONObject; -import java.io.*; +import java.io.IOException; +import java.io.StringReader; -import de.blinkt.openvpn.*; -import de.blinkt.openvpn.core.*; +import de.blinkt.openvpn.VpnProfile; +import de.blinkt.openvpn.core.ConfigParser; /** * Gateway provides objects defining gateways and their metadata. @@ -37,7 +39,7 @@ public class Gateway { public final static String TAG = Gateway.class.getSimpleName(); - private JSONObject general_configuration; + private JSONObject generalConfiguration; private JSONObject secrets; private JSONObject gateway; @@ -54,7 +56,7 @@ public class Gateway { this.gateway = gateway; this.secrets = secrets; - general_configuration = getGeneralConfiguration(eip_definition); + generalConfiguration = getGeneralConfiguration(eip_definition); timezone = getTimezone(eip_definition); mName = locationAsName(eip_definition); @@ -80,9 +82,9 @@ public class Gateway { return location.optString("name"); } - private JSONObject getLocationInfo(JSONObject eip_definition) { + private JSONObject getLocationInfo(JSONObject eipDefinition) { try { - JSONObject locations = eip_definition.getJSONObject("locations"); + JSONObject locations = eipDefinition.getJSONObject("locations"); return locations.getJSONObject(gateway.getString("location")); } catch (JSONException e) { @@ -97,8 +99,8 @@ public class Gateway { try { ConfigParser cp = new ConfigParser(); - VpnConfigGenerator vpn_configuration_generator = new VpnConfigGenerator(general_configuration, secrets, gateway); - String configuration = vpn_configuration_generator.generate(); + VpnConfigGenerator vpnConfigurationGenerator = new VpnConfigGenerator(generalConfiguration, secrets, gateway); + String configuration = vpnConfigurationGenerator.generate(); cp.parseConfig(new StringReader(configuration)); return cp.convertProfile(); diff --git a/app/src/main/java/se/leap/bitmaskclient/eip/GatewaysManager.java b/app/src/main/java/se/leap/bitmaskclient/eip/GatewaysManager.java index 0b330ed9..1bdb53ab 100644 --- a/app/src/main/java/se/leap/bitmaskclient/eip/GatewaysManager.java +++ b/app/src/main/java/se/leap/bitmaskclient/eip/GatewaysManager.java @@ -94,14 +94,14 @@ public class GatewaysManager { return new Gson().toJson(gateways, list_type); } - public void fromEipServiceJson(JSONObject eip_definition) { + public void fromEipServiceJson(JSONObject eipDefinition) { try { - JSONArray gatewaysDefined = eip_definition.getJSONArray("gateways"); + JSONArray gatewaysDefined = eipDefinition.getJSONArray("gateways"); for (int i = 0; i < gatewaysDefined.length(); i++) { JSONObject gw = gatewaysDefined.getJSONObject(i); if (isOpenVpnGateway(gw)) { JSONObject secrets = secretsConfiguration(); - Gateway aux = new Gateway(eip_definition, secrets, gw); + Gateway aux = new Gateway(eipDefinition, secrets, gw); if (!containsProfileWithSecrets(aux.getProfile())) { addGateway(aux); } -- cgit v1.2.3 From 02738271daa9457e5f4e97508301bb11a612fb24 Mon Sep 17 00:00:00 2001 From: Fup Duck Date: Fri, 9 Feb 2018 20:56:14 +0100 Subject: 8827 - bugfix --- app/src/production/java/se/leap/bitmaskclient/ProviderApiManager.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/app/src/production/java/se/leap/bitmaskclient/ProviderApiManager.java b/app/src/production/java/se/leap/bitmaskclient/ProviderApiManager.java index 307e8e05..839c5a5d 100644 --- a/app/src/production/java/se/leap/bitmaskclient/ProviderApiManager.java +++ b/app/src/production/java/se/leap/bitmaskclient/ProviderApiManager.java @@ -178,7 +178,7 @@ public class ProviderApiManager extends ProviderApiManagerBase { if (ConfigHelper.checkErroneousDownload(certString)) return false; else - return loadCertificate(certString); + return loadCertificate(provider, certString); } catch (IOException e) { // TODO Auto-generated catch block e.printStackTrace(); -- cgit v1.2.3 From f728bbb6eb24268d7223ac4347ad2cd5f004e85c Mon Sep 17 00:00:00 2001 From: cyBerta Date: Sat, 10 Feb 2018 23:19:00 +0100 Subject: #8837 new handling of connection state LEVEL_VPNPAUSED - don't throw an illegal state exception --- app/src/main/java/se/leap/bitmaskclient/eip/EipStatus.java | 9 ++++++++- 1 file changed, 8 insertions(+), 1 deletion(-) diff --git a/app/src/main/java/se/leap/bitmaskclient/eip/EipStatus.java b/app/src/main/java/se/leap/bitmaskclient/eip/EipStatus.java index 0da74872..855bfc64 100644 --- a/app/src/main/java/se/leap/bitmaskclient/eip/EipStatus.java +++ b/app/src/main/java/se/leap/bitmaskclient/eip/EipStatus.java @@ -24,6 +24,7 @@ import java.util.Observable; import de.blinkt.openvpn.core.ConnectionStatus; import de.blinkt.openvpn.core.LogItem; +import de.blinkt.openvpn.core.ProfileManager; import de.blinkt.openvpn.core.VpnStatus; /** @@ -92,7 +93,13 @@ public class EipStatus extends Observable implements VpnStatus.StateListener { currentEipLevel = EipLevel.CONNECTED; break; case LEVEL_VPNPAUSED: - throw new IllegalStateException("Ics-Openvpn's VPNPAUSED state is not supported by Bitmask"); + if (ProfileManager.getLastConnectedVpn().mPersistTun) { + //if persistTun is enabled, treat EipLevel as connecting as it *shouldn't* allow passing traffic in the clear... + currentEipLevel = EipLevel.CONNECTING; + } else { + //... if persistTun is not enabled, background network traffic will pass in the clear + currentEipLevel = EipLevel.DISCONNECTED; + } case LEVEL_CONNECTING_SERVER_REPLIED: case LEVEL_CONNECTING_NO_SERVER_REPLY_YET: case LEVEL_WAITING_FOR_USER_INPUT: -- cgit v1.2.3 From ca82cdf77ee4d30b820a1f936315c6c5be78359d Mon Sep 17 00:00:00 2001 From: Fup Duck Date: Sun, 11 Feb 2018 13:25:24 +0100 Subject: 8827 - discussion * validate urls before changing anything in Provider.define() * save private key and vpn cert after login/signup --- .../se/leap/bitmaskclient/ProviderApiManager.java | 8 +++++- .../java/se/leap/bitmaskclient/ConfigHelper.java | 5 ++++ .../java/se/leap/bitmaskclient/EipFragment.java | 5 ++-- .../main/java/se/leap/bitmaskclient/Provider.java | 24 +++++++++++++++--- .../leap/bitmaskclient/ProviderApiManagerBase.java | 29 ++++++++++++++++++---- .../ProviderCredentialsBaseActivity.java | 14 ++++++++--- .../se/leap/bitmaskclient/ProviderApiManager.java | 9 +++++-- 7 files changed, 77 insertions(+), 17 deletions(-) diff --git a/app/src/insecure/java/se/leap/bitmaskclient/ProviderApiManager.java b/app/src/insecure/java/se/leap/bitmaskclient/ProviderApiManager.java index d57dfe6d..1c5247c0 100644 --- a/app/src/insecure/java/se/leap/bitmaskclient/ProviderApiManager.java +++ b/app/src/insecure/java/se/leap/bitmaskclient/ProviderApiManager.java @@ -52,10 +52,12 @@ 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.ProviderAPI.ERRORS; import static se.leap.bitmaskclient.R.string.certificate_error; 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; /** * Created by cyberta on 04.01.18. @@ -145,7 +147,11 @@ public class ProviderApiManager extends ProviderApiManagerBase { try { JSONObject providerJson = new JSONObject(providerDotJsonString); - provider.define(providerJson); + if (provider.define(providerJson)) { + result.putBoolean(BROADCAST_RESULT_KEY, true); + } else { + return setErrorResult(result, warning_corrupted_provider_details, ERROR_CORRUPTED_PROVIDER_JSON.toString()); + } result.putBoolean(BROADCAST_RESULT_KEY, true); } catch (JSONException e) { diff --git a/app/src/main/java/se/leap/bitmaskclient/ConfigHelper.java b/app/src/main/java/se/leap/bitmaskclient/ConfigHelper.java index 329fd543..f8204b20 100644 --- a/app/src/main/java/se/leap/bitmaskclient/ConfigHelper.java +++ b/app/src/main/java/se/leap/bitmaskclient/ConfigHelper.java @@ -281,6 +281,7 @@ public class ConfigHelper { provider.setMainUrl(new URL(preferences.getString(Provider.MAIN_URL, ""))); provider.define(new JSONObject(preferences.getString(Provider.KEY, ""))); provider.setCaCert(preferences.getString(Provider.CA_CERT, "")); + provider.setCaCertFingerprint(preferences.getString(Provider.CA_CERT_FINGERPRINT, "")); provider.setVpnCertificate(preferences.getString(PROVIDER_VPN_CERTIFICATE, "")); provider.setPrivateKey(preferences.getString(PROVIDER_PRIVATE_KEY, "")); } catch (MalformedURLException | JSONException e) { @@ -290,6 +291,10 @@ public class ConfigHelper { return provider; } + public String getFromPersistedProvider(String toFetch, String providerDomain, SharedPreferences preferences) { + return preferences.getString(toFetch + "." + providerDomain, ""); + } + public static String getProviderName(String provider) { return getProviderName(null, provider); } diff --git a/app/src/main/java/se/leap/bitmaskclient/EipFragment.java b/app/src/main/java/se/leap/bitmaskclient/EipFragment.java index b4c7a7de..41d9ff04 100644 --- a/app/src/main/java/se/leap/bitmaskclient/EipFragment.java +++ b/app/src/main/java/se/leap/bitmaskclient/EipFragment.java @@ -63,6 +63,7 @@ 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; @@ -266,7 +267,7 @@ public class EipFragment extends Fragment implements Observer { } private boolean canStartEIP() { - boolean certificateExists = !provider.hasVpnCertificate(); + boolean certificateExists = provider.hasVpnCertificate(); boolean isAllowedAnon = provider.allowsAnonymous(); return (isAllowedAnon || certificateExists) && !eipStatus.isConnected() && !eipStatus.isConnecting(); } @@ -463,7 +464,7 @@ public class EipFragment extends Fragment implements Observer { return; } - int resultCode = intent.getIntExtra(BROADCAST_RESULT_KEY, -1); + int resultCode = intent.getIntExtra(BROADCAST_RESULT_CODE, -1); Bundle resultData = intent.getParcelableExtra(BROADCAST_RESULT_KEY); switch (action) { case BROADCAST_EIP_EVENT: diff --git a/app/src/main/java/se/leap/bitmaskclient/Provider.java b/app/src/main/java/se/leap/bitmaskclient/Provider.java index 4d608222..e53dd4fb 100644 --- a/app/src/main/java/se/leap/bitmaskclient/Provider.java +++ b/app/src/main/java/se/leap/bitmaskclient/Provider.java @@ -141,9 +141,27 @@ public final class Provider implements Parcelable { } } - public void define(JSONObject providerJson) { - definition = providerJson; - parseDefinition(definition); + public boolean define(JSONObject providerJson) { + /* + * fix against "api_uri": "https://calyx.net.malicious.url.net:4430", + * This method aims to prevent attacks where the provider.json file got manipulated by a third party. + * The main url should not change. + */ + + try { + String providerApiUrl = providerJson.getString(Provider.API_URL); + String providerDomain = providerJson.getString(Provider.DOMAIN); + if (getMainUrlString().contains(providerDomain) && providerApiUrl.contains(providerDomain + ":")) { + definition = providerJson; + parseDefinition(definition); + return true; + } else { + return false; + } + } catch (JSONException e) { + e.printStackTrace(); + return false; + } } protected JSONObject getDefinition() { diff --git a/app/src/main/java/se/leap/bitmaskclient/ProviderApiManagerBase.java b/app/src/main/java/se/leap/bitmaskclient/ProviderApiManagerBase.java index a9321a9c..5fe6ed05 100644 --- a/app/src/main/java/se/leap/bitmaskclient/ProviderApiManagerBase.java +++ b/app/src/main/java/se/leap/bitmaskclient/ProviderApiManagerBase.java @@ -87,7 +87,6 @@ import static se.leap.bitmaskclient.ProviderAPI.SIGN_UP; import static se.leap.bitmaskclient.ProviderAPI.SUCCESSFUL_LOGIN; import static se.leap.bitmaskclient.ProviderAPI.SUCCESSFUL_LOGOUT; import static se.leap.bitmaskclient.ProviderAPI.SUCCESSFUL_SIGNUP; -import static se.leap.bitmaskclient.ProviderAPI.UPDATE_PROGRESSBAR; 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.error_io_exception_user_message; @@ -665,6 +664,8 @@ public abstract class ProviderApiManagerBase { provider.setCaCert(getPersistedProviderCA(providerDomain)); provider.define(getPersistedProviderDefinition(providerDomain)); provider.setCaCertFingerprint(getPersistedCaCertFingerprint(providerDomain)); + provider.setPrivateKey(getPersistedPrivateKey(providerDomain)); + provider.setVpnCertificate(getPersistedVPNCertificate(providerDomain)); } } @@ -707,10 +708,6 @@ public abstract class ProviderApiManagerBase { return setErrorResult(result, warning_corrupted_provider_cert, ERROR_CERTIFICATE_PINNING.toString()); } - if (!hasApiUrlExpectedDomain(providerDefinition, mainUrl)){ - return setErrorResult(result, warning_corrupted_provider_details, ERROR_CORRUPTED_PROVIDER_JSON.toString()); - } - if (!canConnect(caCert, providerDefinition, result)) { return result; } @@ -797,6 +794,24 @@ public abstract class ProviderApiManagerBase { return ""; } + protected String getPersistedPrivateKey(String providerDomain) { + try { + return getPersistedProviderDefinition(providerDomain).getString(PROVIDER_PRIVATE_KEY); + } catch (JSONException e) { + e.printStackTrace(); + } + return ""; + } + + protected String getPersistedVPNCertificate(String providerDomain) { + try { + return getPersistedProviderDefinition(providerDomain).getString(PROVIDER_VPN_CERTIFICATE); + } catch (JSONException e) { + e.printStackTrace(); + } + return ""; + } + protected JSONObject getPersistedProviderDefinition(String providerDomain) { try { return new JSONObject(preferences.getString(Provider.KEY + "." + providerDomain, "")); @@ -806,6 +821,10 @@ public abstract class ProviderApiManagerBase { } } + protected String getFromPersistedProvider(String toFetch, String providerDomain) { + return preferences.getString(toFetch + "." + providerDomain, ""); + } + protected String getPersistedProviderCA(String providerDomain) { return preferences.getString(Provider.CA_CERT + "." + providerDomain, ""); } diff --git a/app/src/main/java/se/leap/bitmaskclient/ProviderCredentialsBaseActivity.java b/app/src/main/java/se/leap/bitmaskclient/ProviderCredentialsBaseActivity.java index 47a45a74..7714e979 100644 --- a/app/src/main/java/se/leap/bitmaskclient/ProviderCredentialsBaseActivity.java +++ b/app/src/main/java/se/leap/bitmaskclient/ProviderCredentialsBaseActivity.java @@ -40,6 +40,7 @@ import static se.leap.bitmaskclient.Constants.BROADCAST_RESULT_CODE; 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.LOG_IN; import static se.leap.bitmaskclient.ProviderAPI.SIGN_UP; @@ -201,7 +202,8 @@ public abstract class ProviderCredentialsBaseActivity extends ConfigWizardBaseAc ProviderAPICommand.execute(this, SIGN_UP, parameters, provider); } - void downloadVpnCertificate() { + void downloadVpnCertificate(Provider handledProvider) { + provider = handledProvider; ProviderAPICommand.execute(this, DOWNLOAD_CERTIFICATE, provider); } @@ -361,7 +363,8 @@ public abstract class ProviderCredentialsBaseActivity extends ConfigWizardBaseAc hideProgressBar(); } - private void successfullyFinished() { + private void successfullyFinished(Provider handledProvider) { + provider = handledProvider; Intent resultData = new Intent(); resultData.putExtra(Provider.KEY, provider); setResult(RESULT_OK, resultData); @@ -379,10 +382,13 @@ public abstract class ProviderCredentialsBaseActivity extends ConfigWizardBaseAc } int resultCode = intent.getIntExtra(BROADCAST_RESULT_CODE, -1); + Bundle resultData = intent.getParcelableExtra(BROADCAST_RESULT_KEY); + Provider handledProvider = resultData.getParcelable(PROVIDER_KEY); + switch (resultCode) { case ProviderAPI.SUCCESSFUL_SIGNUP: case ProviderAPI.SUCCESSFUL_LOGIN: - downloadVpnCertificate(); + downloadVpnCertificate(handledProvider); break; case ProviderAPI.FAILED_LOGIN: case ProviderAPI.FAILED_SIGNUP: @@ -390,7 +396,7 @@ public abstract class ProviderCredentialsBaseActivity extends ConfigWizardBaseAc break; case ProviderAPI.CORRECTLY_DOWNLOADED_CERTIFICATE: - successfullyFinished(); + successfullyFinished(handledProvider); //activity.eip_fragment.updateEipService(); break; case ProviderAPI.INCORRECTLY_DOWNLOADED_CERTIFICATE: diff --git a/app/src/production/java/se/leap/bitmaskclient/ProviderApiManager.java b/app/src/production/java/se/leap/bitmaskclient/ProviderApiManager.java index 839c5a5d..5317118b 100644 --- a/app/src/production/java/se/leap/bitmaskclient/ProviderApiManager.java +++ b/app/src/production/java/se/leap/bitmaskclient/ProviderApiManager.java @@ -36,9 +36,11 @@ import static android.text.TextUtils.isEmpty; import static se.leap.bitmaskclient.Constants.BROADCAST_RESULT_KEY; import static se.leap.bitmaskclient.Constants.PROVIDER_VPN_CERTIFICATE; import static se.leap.bitmaskclient.DownloadFailedDialog.DOWNLOAD_ERRORS.ERROR_CERTIFICATE_PINNING; +import static se.leap.bitmaskclient.DownloadFailedDialog.DOWNLOAD_ERRORS.ERROR_CORRUPTED_PROVIDER_JSON; import static se.leap.bitmaskclient.ProviderAPI.ERRORS; import static se.leap.bitmaskclient.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; /** * Implements the logic of the provider api http requests. The methods of this class need to be called from @@ -124,9 +126,12 @@ public class ProviderApiManager extends ProviderApiManagerBase { try { JSONObject providerJson = new JSONObject(providerDotJsonString); - provider.define(providerJson); + if (provider.define(providerJson)) { + result.putBoolean(BROADCAST_RESULT_KEY, true); + } else { + return setErrorResult(result, warning_corrupted_provider_details, ERROR_CORRUPTED_PROVIDER_JSON.toString()); + } - result.putBoolean(BROADCAST_RESULT_KEY, true); } catch (JSONException e) { String reason_to_fail = pickErrorMessage(providerDotJsonString); result.putString(ERRORS, reason_to_fail); -- cgit v1.2.3 From 1b97d5dfc596763c03d584d089a1e00edd1eecbc Mon Sep 17 00:00:00 2001 From: Fup Duck Date: Sun, 11 Feb 2018 14:39:27 +0100 Subject: 8827 - merge request discussions * add deleteProviderDetailsFromPreferences to ConfigHelper * validate every field in Provider.equals * add reset() method to Provider --- .../java/se/leap/bitmaskclient/ConfigHelper.java | 15 ++++- .../main/java/se/leap/bitmaskclient/Provider.java | 64 ++++++++++++++++------ .../leap/bitmaskclient/ProviderApiManagerBase.java | 20 +------ 3 files changed, 63 insertions(+), 36 deletions(-) diff --git a/app/src/main/java/se/leap/bitmaskclient/ConfigHelper.java b/app/src/main/java/se/leap/bitmaskclient/ConfigHelper.java index f8204b20..086ba216 100644 --- a/app/src/main/java/se/leap/bitmaskclient/ConfigHelper.java +++ b/app/src/main/java/se/leap/bitmaskclient/ConfigHelper.java @@ -16,7 +16,6 @@ */ package se.leap.bitmaskclient; -import android.annotation.SuppressLint; import android.content.SharedPreferences; import android.support.annotation.NonNull; import android.support.annotation.Nullable; @@ -412,5 +411,19 @@ public class ConfigHelper { } } + public static void deleteProviderDetailsFromPreferences(@NonNull SharedPreferences preferences, String providerDomain) { + preferences.edit(). + remove(Provider.KEY + "." + providerDomain). + remove(Provider.CA_CERT + "." + providerDomain). + remove(Provider.CA_CERT_FINGERPRINT + "." + providerDomain). + remove(Provider.MAIN_URL + "." + providerDomain). + remove(Provider.KEY + "." + providerDomain). + remove(Provider.CA_CERT + "." + providerDomain). + remove(PROVIDER_EIP_DEFINITION + "." + providerDomain). + remove(PROVIDER_PRIVATE_KEY + "." + providerDomain). + remove(PROVIDER_VPN_CERTIFICATE + "." + providerDomain). + apply(); + } + } diff --git a/app/src/main/java/se/leap/bitmaskclient/Provider.java b/app/src/main/java/se/leap/bitmaskclient/Provider.java index e53dd4fb..4937ed58 100644 --- a/app/src/main/java/se/leap/bitmaskclient/Provider.java +++ b/app/src/main/java/se/leap/bitmaskclient/Provider.java @@ -21,13 +21,11 @@ import android.os.Parcelable; import com.google.gson.Gson; -import org.json.JSONArray; import org.json.JSONException; import org.json.JSONObject; import java.net.MalformedURLException; import java.net.URL; -import java.util.Arrays; import java.util.Locale; import static se.leap.bitmaskclient.Constants.PROVIDER_ALLOWED_REGISTERED; @@ -41,14 +39,14 @@ import static se.leap.bitmaskclient.ProviderAPI.ERRORS; public final class Provider implements Parcelable { private JSONObject definition = new JSONObject(); // Represents our Provider's provider.json - private JSONObject eipServiceJson = new JSONObject(); // Represents our Provider's provider.json + private JSONObject eipServiceJson = new JSONObject(); private DefaultedURL mainUrl = new DefaultedURL(); private DefaultedURL apiUrl = new DefaultedURL(); private String certificatePin = ""; private String certificatePinEncoding = ""; private String caCert = ""; private String caCertFingerprint = ""; - private String apiVerson = ""; + private String apiVersion = ""; private String privateKey = ""; private String vpnCertificate = ""; @@ -68,17 +66,9 @@ public final class Provider implements Parcelable { NAME = "name", DESCRIPTION = "description", DOMAIN = "domain", - MAIN_URL = "main_url", - DOT_JSON_URL = "provider_json_url"; + MAIN_URL = "main_url"; - // Array of what API versions we understand - protected static final String[] API_VERSIONS = {"1"}; // I assume we might encounter arbitrary version "numbers" - // Some API pieces we want to know about - private static final String API_TERM_SERVICES = "services"; private static final String API_TERM_NAME = "name"; - private static final String API_TERM_DOMAIN = "domain"; - private static final String API_TERM_DEFAULT_LANGUAGE = "default_language"; - protected static final String[] API_EIP_TYPES = {"openvpn"}; public Provider() { } @@ -164,7 +154,7 @@ public final class Provider implements Parcelable { } } - protected JSONObject getDefinition() { + public JSONObject getDefinition() { return definition; } @@ -198,7 +188,7 @@ public final class Provider implements Parcelable { } public String getApiVersion() { - return apiVerson; + return apiVersion; } protected String certificatePin() { return certificatePin; } @@ -296,7 +286,20 @@ public final class Provider implements Parcelable { public boolean equals(Object o) { if (o instanceof Provider) { Provider p = (Provider) o; - return p.getDomain().equals(getDomain()); + return p.getDomain().equals(getDomain()) && + definition.equals(p.getDefinition()) && + eipServiceJson.equals(p.getEipServiceJson())&& + mainUrl.equals(p.getMainUrl()) && + apiUrl.equals(p.getApiUrl()) && + certificatePin.equals(p.getCertificatePin()) && + certificatePinEncoding.equals(p.getCertificatePinEncoding()) && + caCert.equals(p.getCaCert()) && + caCertFingerprint.equals(p.getCaCertFingerprint()) && + apiVersion.equals(p.getApiVersion()) && + privateKey.equals(p.getPrivateKey()) && + vpnCertificate.equals(p.getVpnCertificate()) && + allowAnonymous == p.allowsAnonymous() && + allowRegistered == p.allowsRegistered(); } else return false; } @@ -365,7 +368,7 @@ public final class Provider implements Parcelable { this.apiUrl.setUrl(new URL(definition.getString(API_URL))); this.allowAnonymous = definition.getJSONObject(Provider.SERVICE).getBoolean(PROVIDER_ALLOW_ANONYMOUS); this.allowRegistered = definition.getJSONObject(Provider.SERVICE).getBoolean(PROVIDER_ALLOWED_REGISTERED); - this.apiVerson = getDefinition().getString(Provider.API_VERSION); + this.apiVersion = getDefinition().getString(Provider.API_VERSION); } catch (JSONException | ArrayIndexOutOfBoundsException | MalformedURLException e) { e.printStackTrace(); } @@ -429,4 +432,31 @@ public final class Provider implements Parcelable { public boolean hasVpnCertificate() { return getVpnCertificate() != null && getVpnCertificate().length() >0 ; } + + public String getCertificatePin() { + return certificatePin; + } + + public String getCertificatePinEncoding() { + return certificatePinEncoding; + } + + /** + * resets everything except the main url + */ + public void reset() { + definition = new JSONObject(); + eipServiceJson = new JSONObject(); + apiUrl = new DefaultedURL(); + certificatePin = ""; + certificatePinEncoding = ""; + caCert = ""; + caCertFingerprint = ""; + apiVersion = ""; + privateKey = ""; + vpnCertificate = ""; + allowRegistered = false; + allowAnonymous = false; + } + } diff --git a/app/src/main/java/se/leap/bitmaskclient/ProviderApiManagerBase.java b/app/src/main/java/se/leap/bitmaskclient/ProviderApiManagerBase.java index 5fe6ed05..1284ca64 100644 --- a/app/src/main/java/se/leap/bitmaskclient/ProviderApiManagerBase.java +++ b/app/src/main/java/se/leap/bitmaskclient/ProviderApiManagerBase.java @@ -211,11 +211,8 @@ public abstract class ProviderApiManagerBase { } void resetProviderDetails(Provider provider) { - provider.setCaCert(""); - provider.define(new JSONObject()); - provider.setEipServiceJson(new JSONObject()); - - deleteProviderDetailsFromPreferences(provider.getDomain()); + provider.reset(); + ConfigHelper.deleteProviderDetailsFromPreferences(preferences, provider.getDomain()); } String formatErrorMessage(final int toastStringId) { @@ -772,19 +769,6 @@ public abstract class ProviderApiManagerBase { return ""; } - protected void deleteProviderDetailsFromPreferences(String providerDomain) { - - if (preferences.contains(Provider.KEY + "." + providerDomain)) { - preferences.edit().remove(Provider.KEY + "." + providerDomain).apply(); - } - if (preferences.contains(Provider.CA_CERT + "." + providerDomain)) { - preferences.edit().remove(Provider.CA_CERT + "." + providerDomain).apply(); - } - if (preferences.contains(Provider.CA_CERT_FINGERPRINT + "." + providerDomain)) { - preferences.edit().remove(Provider.CA_CERT_FINGERPRINT + "." + providerDomain).apply(); - } - } - protected String getPersistedCaCertFingerprint(String providerDomain) { try { return getPersistedProviderDefinition(providerDomain).getString(Provider.CA_CERT_FINGERPRINT); -- cgit v1.2.3 From fde2fbd9de3b014bd77a517b2cb7faf7beb4a560 Mon Sep 17 00:00:00 2001 From: Fup Duck Date: Sun, 11 Feb 2018 15:11:32 +0100 Subject: 8827 - refactoring * remove unused functions * refactor reading stored credentials from preferences --- .../java/se/leap/bitmaskclient/ConfigHelper.java | 2 +- .../leap/bitmaskclient/ProviderApiManagerBase.java | 57 ++-------------------- 2 files changed, 5 insertions(+), 54 deletions(-) diff --git a/app/src/main/java/se/leap/bitmaskclient/ConfigHelper.java b/app/src/main/java/se/leap/bitmaskclient/ConfigHelper.java index 086ba216..ba078701 100644 --- a/app/src/main/java/se/leap/bitmaskclient/ConfigHelper.java +++ b/app/src/main/java/se/leap/bitmaskclient/ConfigHelper.java @@ -290,7 +290,7 @@ public class ConfigHelper { return provider; } - public String getFromPersistedProvider(String toFetch, String providerDomain, SharedPreferences preferences) { + public static String getFromPersistedProvider(String toFetch, String providerDomain, SharedPreferences preferences) { return preferences.getString(toFetch + "." + providerDomain, ""); } diff --git a/app/src/main/java/se/leap/bitmaskclient/ProviderApiManagerBase.java b/app/src/main/java/se/leap/bitmaskclient/ProviderApiManagerBase.java index 1284ca64..09e0faa8 100644 --- a/app/src/main/java/se/leap/bitmaskclient/ProviderApiManagerBase.java +++ b/app/src/main/java/se/leap/bitmaskclient/ProviderApiManagerBase.java @@ -685,7 +685,6 @@ public abstract class ProviderApiManagerBase { String caCert = provider.getCaCert(); JSONObject providerDefinition = provider.getDefinition(); - String mainUrl = provider.getMainUrlString(); if (ConfigHelper.checkErroneousDownload(caCert)) { return result; @@ -732,25 +731,6 @@ public abstract class ProviderApiManagerBase { return result; } - /** - * This method aims to prevent attacks where the provider.json file got manipulated by a third party. - * The main url is visible to the provider when setting up a new provider. - * The user is responsible to check that this is the provider main url he intends to connect to. - * - * @param providerDefinition - * @param mainUrlString - * @return - */ - private boolean hasApiUrlExpectedDomain(JSONObject providerDefinition, String mainUrlString) { - // fix against "api_uri": "https://calyx.net.malicious.url.net:4430", - String apiUrlString = getApiUrl(providerDefinition); - String providerDomain = getProviderDomain(providerDefinition); - if (mainUrlString.contains(providerDomain) && apiUrlString.contains(providerDomain + ":")) { - return true; - } - return false; - } - protected String getCaCertFingerprint(JSONObject providerDefinition) { try { return providerDefinition.getString(Provider.CA_CERT_FINGERPRINT); @@ -770,59 +750,30 @@ public abstract class ProviderApiManagerBase { } protected String getPersistedCaCertFingerprint(String providerDomain) { - try { - return getPersistedProviderDefinition(providerDomain).getString(Provider.CA_CERT_FINGERPRINT); - } catch (JSONException e) { - e.printStackTrace(); - } - return ""; + return ConfigHelper.getFromPersistedProvider(Provider.CA_CERT_FINGERPRINT, providerDomain, preferences); } protected String getPersistedPrivateKey(String providerDomain) { - try { - return getPersistedProviderDefinition(providerDomain).getString(PROVIDER_PRIVATE_KEY); - } catch (JSONException e) { - e.printStackTrace(); - } - return ""; + return ConfigHelper.getFromPersistedProvider(PROVIDER_PRIVATE_KEY, providerDomain, preferences); } protected String getPersistedVPNCertificate(String providerDomain) { - try { - return getPersistedProviderDefinition(providerDomain).getString(PROVIDER_VPN_CERTIFICATE); - } catch (JSONException e) { - e.printStackTrace(); - } - return ""; + return ConfigHelper.getFromPersistedProvider(PROVIDER_VPN_CERTIFICATE, providerDomain, preferences); } protected JSONObject getPersistedProviderDefinition(String providerDomain) { try { - return new JSONObject(preferences.getString(Provider.KEY + "." + providerDomain, "")); + return new JSONObject(ConfigHelper.getFromPersistedProvider(Provider.KEY, providerDomain, preferences)); } catch (JSONException e) { e.printStackTrace(); return new JSONObject(); } } - protected String getFromPersistedProvider(String toFetch, String providerDomain) { - return preferences.getString(toFetch + "." + providerDomain, ""); - } - protected String getPersistedProviderCA(String providerDomain) { return preferences.getString(Provider.CA_CERT + "." + providerDomain, ""); } - protected String getProviderDomain(JSONObject providerDefinition) { - try { - return providerDefinition.getString(Provider.DOMAIN); - } catch (JSONException e) { - e.printStackTrace(); - } - - return ""; - } - protected boolean hasUpdatedProviderDetails(String domain) { return preferences.contains(Provider.KEY + "." + domain) && preferences.contains(Provider.CA_CERT + "." + domain); } -- cgit v1.2.3 From 757293ca946f1b8c25d7bf13fc9f70bf70b4d8c5 Mon Sep 17 00:00:00 2001 From: cyBerta Date: Mon, 12 Feb 2018 13:08:24 +0100 Subject: #8837 update tests and fix VPN_Paused implementation for EipStatus --- .../java/se/leap/bitmaskclient/eip/EipStatus.java | 3 +- .../se/leap/bitmaskclient/eip/EipStatusTest.java | 35 ++++++++++++++++++---- 2 files changed, 32 insertions(+), 6 deletions(-) diff --git a/app/src/main/java/se/leap/bitmaskclient/eip/EipStatus.java b/app/src/main/java/se/leap/bitmaskclient/eip/EipStatus.java index 855bfc64..df252500 100644 --- a/app/src/main/java/se/leap/bitmaskclient/eip/EipStatus.java +++ b/app/src/main/java/se/leap/bitmaskclient/eip/EipStatus.java @@ -93,13 +93,14 @@ public class EipStatus extends Observable implements VpnStatus.StateListener { currentEipLevel = EipLevel.CONNECTED; break; case LEVEL_VPNPAUSED: - if (ProfileManager.getLastConnectedVpn().mPersistTun) { + if (ProfileManager.getLastConnectedVpn() != null && ProfileManager.getLastConnectedVpn().mPersistTun) { //if persistTun is enabled, treat EipLevel as connecting as it *shouldn't* allow passing traffic in the clear... currentEipLevel = EipLevel.CONNECTING; } else { //... if persistTun is not enabled, background network traffic will pass in the clear currentEipLevel = EipLevel.DISCONNECTED; } + break; case LEVEL_CONNECTING_SERVER_REPLIED: case LEVEL_CONNECTING_NO_SERVER_REPLY_YET: case LEVEL_WAITING_FOR_USER_INPUT: diff --git a/app/src/test/java/se/leap/bitmaskclient/eip/EipStatusTest.java b/app/src/test/java/se/leap/bitmaskclient/eip/EipStatusTest.java index 15085b46..f332b094 100644 --- a/app/src/test/java/se/leap/bitmaskclient/eip/EipStatusTest.java +++ b/app/src/test/java/se/leap/bitmaskclient/eip/EipStatusTest.java @@ -3,9 +3,12 @@ package se.leap.bitmaskclient.eip; import org.junit.Before; import org.junit.Test; import org.junit.runner.RunWith; -import org.mockito.junit.MockitoJUnitRunner; +import org.powermock.core.classloader.annotations.PrepareForTest; +import org.powermock.modules.junit4.PowerMockRunner; +import de.blinkt.openvpn.VpnProfile; import de.blinkt.openvpn.core.ConnectionStatus; +import de.blinkt.openvpn.core.ProfileManager; import de.blinkt.openvpn.core.VpnStatus; import se.leap.bitmaskclient.R; @@ -18,6 +21,8 @@ import static de.blinkt.openvpn.core.ConnectionStatus.LEVEL_VPNPAUSED; import static de.blinkt.openvpn.core.ConnectionStatus.LEVEL_WAITING_FOR_USER_INPUT; import static de.blinkt.openvpn.core.ConnectionStatus.UNKNOWN_LEVEL; import static junit.framework.Assert.assertTrue; +import static org.powermock.api.mockito.PowerMockito.mockStatic; +import static org.powermock.api.mockito.PowerMockito.when; import static se.leap.bitmaskclient.eip.EipStatus.EipLevel.CONNECTING; import static se.leap.bitmaskclient.eip.EipStatus.EipLevel.DISCONNECTED; import static se.leap.bitmaskclient.eip.EipStatus.EipLevel.UNKNOWN; @@ -26,7 +31,8 @@ import static se.leap.bitmaskclient.eip.EipStatus.EipLevel.UNKNOWN; * Created by cyberta on 06.12.17. * TODO: Mock AsyncTask */ -@RunWith(MockitoJUnitRunner.class) +@RunWith(PowerMockRunner.class) +@PrepareForTest({ProfileManager.class}) public class EipStatusTest { EipStatus eipStatus; @@ -46,9 +52,28 @@ public class EipStatusTest { assertTrue("LEVEL_CONNECTED state", eipStatus.getState().equals("CONNECTED")); } - @Test(expected= IllegalStateException.class) - public void testUpdateState_LEVEL_VPNPAUSED() throws Exception { - VpnStatus.updateStateString("USERPAUSE", "", R.string.state_userpause, LEVEL_VPNPAUSED); + @Test + public void testUpdateState_LEVEL_VPNPAUSED_hasPersistentTun() throws Exception { + + mockStatic(ProfileManager.class); + VpnProfile mockVpnProfile = new VpnProfile("mockProfile"); + mockVpnProfile.mPersistTun = true; + when(ProfileManager.getLastConnectedVpn()).thenReturn(mockVpnProfile); + VpnStatus.updateStateString("SCREENOFF", "", R.string.state_screenoff, LEVEL_VPNPAUSED); + assertTrue("LEVEL_VPN_PAUSED eipLevel", eipStatus.getEipLevel() == CONNECTING); + assertTrue("LEVEL_VPN_PAUSED level", eipStatus.getLevel() == LEVEL_VPNPAUSED); + } + + @Test + public void testUpdateState_LEVEL_VPNPAUSED_hasNotPersistentTun() throws Exception { + + mockStatic(ProfileManager.class); + VpnProfile mockVpnProfile = new VpnProfile("mockProfile"); + mockVpnProfile.mPersistTun = false; + when(ProfileManager.getLastConnectedVpn()).thenReturn(mockVpnProfile); + VpnStatus.updateStateString("SCREENOFF", "", R.string.state_screenoff, LEVEL_VPNPAUSED); + assertTrue("LEVEL_VPN_PAUSED eipLevel", eipStatus.getEipLevel() == DISCONNECTED); + assertTrue("LEVEL_VPN_PAUSED level", eipStatus.getLevel() == LEVEL_VPNPAUSED); } @Test -- cgit v1.2.3 From e9d3260f6439c4b00c6708658d6edd61a246ea67 Mon Sep 17 00:00:00 2001 From: Fup Duck Date: Mon, 12 Feb 2018 13:31:13 +0100 Subject: 8827 - fix equals for Provider --- app/src/main/java/se/leap/bitmaskclient/DefaultedURL.java | 9 +++++++++ app/src/main/java/se/leap/bitmaskclient/Provider.java | 4 ++-- .../main/java/se/leap/bitmaskclient/ProviderApiManagerBase.java | 1 - 3 files changed, 11 insertions(+), 3 deletions(-) diff --git a/app/src/main/java/se/leap/bitmaskclient/DefaultedURL.java b/app/src/main/java/se/leap/bitmaskclient/DefaultedURL.java index 57ff1fd8..0cbb0d72 100644 --- a/app/src/main/java/se/leap/bitmaskclient/DefaultedURL.java +++ b/app/src/main/java/se/leap/bitmaskclient/DefaultedURL.java @@ -36,4 +36,13 @@ public class DefaultedURL { public String toString() { return url.toString(); } + + @Override + public boolean equals(Object o) { + if (o instanceof DefaultedURL) { + return url.equals(((DefaultedURL) o).getUrl()); + } + return false; + } + } diff --git a/app/src/main/java/se/leap/bitmaskclient/Provider.java b/app/src/main/java/se/leap/bitmaskclient/Provider.java index 4937ed58..7aa2f398 100644 --- a/app/src/main/java/se/leap/bitmaskclient/Provider.java +++ b/app/src/main/java/se/leap/bitmaskclient/Provider.java @@ -287,8 +287,8 @@ public final class Provider implements Parcelable { if (o instanceof Provider) { Provider p = (Provider) o; return p.getDomain().equals(getDomain()) && - definition.equals(p.getDefinition()) && - eipServiceJson.equals(p.getEipServiceJson())&& + definition.toString().equals(p.getDefinition().toString()) && + eipServiceJson.toString().equals(p.getEipServiceJson().toString())&& mainUrl.equals(p.getMainUrl()) && apiUrl.equals(p.getApiUrl()) && certificatePin.equals(p.getCertificatePin()) && diff --git a/app/src/main/java/se/leap/bitmaskclient/ProviderApiManagerBase.java b/app/src/main/java/se/leap/bitmaskclient/ProviderApiManagerBase.java index 09e0faa8..f4fee635 100644 --- a/app/src/main/java/se/leap/bitmaskclient/ProviderApiManagerBase.java +++ b/app/src/main/java/se/leap/bitmaskclient/ProviderApiManagerBase.java @@ -660,7 +660,6 @@ public abstract class ProviderApiManagerBase { if (hasUpdatedProviderDetails(providerDomain)) { provider.setCaCert(getPersistedProviderCA(providerDomain)); provider.define(getPersistedProviderDefinition(providerDomain)); - provider.setCaCertFingerprint(getPersistedCaCertFingerprint(providerDomain)); provider.setPrivateKey(getPersistedPrivateKey(providerDomain)); provider.setVpnCertificate(getPersistedVPNCertificate(providerDomain)); } -- cgit v1.2.3 From 24788afa45ff46616b41626e7607d4461ab77387 Mon Sep 17 00:00:00 2001 From: Fup Duck Date: Mon, 12 Feb 2018 13:35:16 +0100 Subject: 8827 - remove caCertificate from Provider It's already represented by CertificatePin & CertificatePinEncoding --- .../java/se/leap/bitmaskclient/ConfigHelper.java | 1 - .../main/java/se/leap/bitmaskclient/Provider.java | 22 ---------------------- .../leap/bitmaskclient/ProviderApiManagerBase.java | 22 ++++------------------ 3 files changed, 4 insertions(+), 41 deletions(-) diff --git a/app/src/main/java/se/leap/bitmaskclient/ConfigHelper.java b/app/src/main/java/se/leap/bitmaskclient/ConfigHelper.java index ba078701..7b2accd6 100644 --- a/app/src/main/java/se/leap/bitmaskclient/ConfigHelper.java +++ b/app/src/main/java/se/leap/bitmaskclient/ConfigHelper.java @@ -280,7 +280,6 @@ public class ConfigHelper { provider.setMainUrl(new URL(preferences.getString(Provider.MAIN_URL, ""))); provider.define(new JSONObject(preferences.getString(Provider.KEY, ""))); provider.setCaCert(preferences.getString(Provider.CA_CERT, "")); - provider.setCaCertFingerprint(preferences.getString(Provider.CA_CERT_FINGERPRINT, "")); provider.setVpnCertificate(preferences.getString(PROVIDER_VPN_CERTIFICATE, "")); provider.setPrivateKey(preferences.getString(PROVIDER_PRIVATE_KEY, "")); } 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 7aa2f398..a2f50dd9 100644 --- a/app/src/main/java/se/leap/bitmaskclient/Provider.java +++ b/app/src/main/java/se/leap/bitmaskclient/Provider.java @@ -45,7 +45,6 @@ public final class Provider implements Parcelable { private String certificatePin = ""; private String certificatePinEncoding = ""; private String caCert = ""; - private String caCertFingerprint = ""; private String apiVersion = ""; private String privateKey = ""; private String vpnCertificate = ""; @@ -191,12 +190,6 @@ public final class Provider implements Parcelable { return apiVersion; } - protected String certificatePin() { return certificatePin; } - - protected boolean hasCertificatePin() { - return certificatePin != null && !certificatePin.isEmpty(); - } - boolean hasCaCert() { return caCert != null && !caCert.isEmpty(); } @@ -210,10 +203,6 @@ public final class Provider implements Parcelable { return caCert; } - public String getCaCertFingerprint() { - return caCertFingerprint; - } - public String getName() { // Should we pass the locale in, or query the system here? String lang = Locale.getDefault().getLanguage(); @@ -276,7 +265,6 @@ public final class Provider implements Parcelable { parcel.writeString(getMainUrlString()); parcel.writeString(getDefinitionString()); parcel.writeString(getCaCert()); - parcel.writeString(getCaCertFingerprint()); parcel.writeString(getEipServiceJsonString()); parcel.writeString(getPrivateKey()); parcel.writeString(getVpnCertificate()); @@ -294,7 +282,6 @@ public final class Provider implements Parcelable { certificatePin.equals(p.getCertificatePin()) && certificatePinEncoding.equals(p.getCertificatePinEncoding()) && caCert.equals(p.getCaCert()) && - caCertFingerprint.equals(p.getCaCertFingerprint()) && apiVersion.equals(p.getApiVersion()) && privateKey.equals(p.getPrivateKey()) && vpnCertificate.equals(p.getVpnCertificate()) && @@ -340,10 +327,6 @@ public final class Provider implements Parcelable { this.caCert = tmpString; } tmpString = in.readString(); - if (!tmpString.isEmpty()) { - this.caCertFingerprint = tmpString; - } - tmpString = in.readString(); if (!tmpString.isEmpty()) { this.setEipServiceJson(new JSONObject(tmpString)); } @@ -378,10 +361,6 @@ public final class Provider implements Parcelable { this.caCert = cert; } - public void setCaCertFingerprint(String certFingerprint) { - this.caCertFingerprint = certFingerprint; - } - public boolean allowsAnonymous() { return allowAnonymous; } @@ -451,7 +430,6 @@ public final class Provider implements Parcelable { certificatePin = ""; certificatePinEncoding = ""; caCert = ""; - caCertFingerprint = ""; apiVersion = ""; privateKey = ""; vpnCertificate = ""; diff --git a/app/src/main/java/se/leap/bitmaskclient/ProviderApiManagerBase.java b/app/src/main/java/se/leap/bitmaskclient/ProviderApiManagerBase.java index f4fee635..505ee55b 100644 --- a/app/src/main/java/se/leap/bitmaskclient/ProviderApiManagerBase.java +++ b/app/src/main/java/se/leap/bitmaskclient/ProviderApiManagerBase.java @@ -683,7 +683,6 @@ public abstract class ProviderApiManagerBase { result.putBoolean(BROADCAST_RESULT_KEY, false); String caCert = provider.getCaCert(); - JSONObject providerDefinition = provider.getDefinition(); if (ConfigHelper.checkErroneousDownload(caCert)) { return result; @@ -695,15 +694,15 @@ public abstract class ProviderApiManagerBase { } try { certificate.checkValidity(); - String fingerprint = getCaCertFingerprint(providerDefinition); - String encoding = fingerprint.split(":")[0]; - String expectedFingerprint = fingerprint.split(":")[1]; + String encoding = provider.getCertificatePinEncoding(); + String expectedFingerprint = provider.getCertificatePin(); + String realFingerprint = getFingerprintFromCertificate(certificate, encoding); if (!realFingerprint.trim().equalsIgnoreCase(expectedFingerprint.trim())) { return setErrorResult(result, warning_corrupted_provider_cert, ERROR_CERTIFICATE_PINNING.toString()); } - if (!canConnect(caCert, providerDefinition, result)) { + if (!canConnect(caCert, provider.getDefinition(), result)) { return result; } } catch (NoSuchAlgorithmException e ) { @@ -730,15 +729,6 @@ public abstract class ProviderApiManagerBase { return result; } - protected String getCaCertFingerprint(JSONObject providerDefinition) { - try { - return providerDefinition.getString(Provider.CA_CERT_FINGERPRINT); - } catch (JSONException e) { - e.printStackTrace(); - } - return ""; - } - protected String getApiUrl(JSONObject providerDefinition) { try { return providerDefinition.getString(Provider.API_URL); @@ -748,10 +738,6 @@ public abstract class ProviderApiManagerBase { return ""; } - protected String getPersistedCaCertFingerprint(String providerDomain) { - return ConfigHelper.getFromPersistedProvider(Provider.CA_CERT_FINGERPRINT, providerDomain, preferences); - } - protected String getPersistedPrivateKey(String providerDomain) { return ConfigHelper.getFromPersistedProvider(PROVIDER_PRIVATE_KEY, providerDomain, preferences); } -- cgit v1.2.3 From 710fdd182dc1a470c949f50701d3aace4d67134c Mon Sep 17 00:00:00 2001 From: Fup Duck Date: Tue, 13 Feb 2018 11:05:01 +0100 Subject: 8827 - add mockConfigHelpper --- .../main/java/se/leap/bitmaskclient/Provider.java | 4 ++++ .../bitmaskclient/eip/ProviderApiManagerTest.java | 12 ++++++---- .../leap/bitmaskclient/testutils/MockHelper.java | 28 ++++++++++++++++++++++ 3 files changed, 39 insertions(+), 5 deletions(-) diff --git a/app/src/main/java/se/leap/bitmaskclient/Provider.java b/app/src/main/java/se/leap/bitmaskclient/Provider.java index a2f50dd9..b3362409 100644 --- a/app/src/main/java/se/leap/bitmaskclient/Provider.java +++ b/app/src/main/java/se/leap/bitmaskclient/Provider.java @@ -420,6 +420,10 @@ public final class Provider implements Parcelable { return certificatePinEncoding; } + public String getCaCertFingerprint() { + return getCertificatePinEncoding() + ":" + getCertificatePin(); + } + /** * resets everything except the main url */ 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 3ebf6201..b0953493 100644 --- a/app/src/test/java/se/leap/bitmaskclient/eip/ProviderApiManagerTest.java +++ b/app/src/test/java/se/leap/bitmaskclient/eip/ProviderApiManagerTest.java @@ -57,6 +57,7 @@ import static se.leap.bitmaskclient.testutils.BackendMockResponses.BackendMockPr import static se.leap.bitmaskclient.testutils.BackendMockResponses.BackendMockProvider.TestBackendErrorCase.NO_ERROR; import static se.leap.bitmaskclient.testutils.MockHelper.mockBundle; import static se.leap.bitmaskclient.testutils.MockHelper.mockClientGenerator; +import static se.leap.bitmaskclient.testutils.MockHelper.mockConfigHelper; import static se.leap.bitmaskclient.testutils.MockHelper.mockFingerprintForCertificate; import static se.leap.bitmaskclient.testutils.MockHelper.mockIntent; import static se.leap.bitmaskclient.testutils.MockHelper.mockProviderApiConnector; @@ -197,7 +198,8 @@ public class ProviderApiManagerTest { @Test public void test_handleIntentSetupProvider_happyPath_storedProviderAndCAFromPreviousSetup() throws IOException, CertificateEncodingException, NoSuchAlgorithmException, JSONException { Provider provider = new Provider("https://riseup.net"); - mockFingerprintForCertificate("a5244308a1374709a9afce95e3ae47c1b44bc2398c0a70ccbf8b3a8a97f29494"); + mockConfigHelper("a5244308a1374709a9afce95e3ae47c1b44bc2398c0a70ccbf8b3a8a97f29494", getConfiguredProvider()); + 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(); @@ -260,10 +262,10 @@ public class ProviderApiManagerTest { } @Test - public void test_handleIntentSetupProvider_storedProviderAndCAFromPreviousSetup_failedPinning() throws IOException, CertificateEncodingException, NoSuchAlgorithmException { + public void test_handleIntentSetupProvider_storedProviderAndCAFromPreviousSetup_failedPinning() throws IOException, CertificateEncodingException, NoSuchAlgorithmException, JSONException { Provider provider = new Provider("https://riseup.net"); + mockConfigHelper("a5244308a1374709a9afce95e3ae47c1b44bc2398c0a70ccbf8b3a8a97f29495", getConfiguredProvider()); - 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(); @@ -333,7 +335,7 @@ public class ProviderApiManagerTest { public void test_handleIntentSetupProvider_preseededProviderAndCA_ValidCertificateButUpdatedCertificateOnServerSide() throws IOException, CertificateEncodingException, NoSuchAlgorithmException, JSONException { Provider provider = getConfiguredProvider(); - mockFingerprintForCertificate(" a5244308a1374709a9afce95e3ae47c1b44bc2398c0a70ccbf8b3a8a97f29494"); + mockConfigHelper("a5244308a1374709a9afce95e3ae47c1b44bc2398c0a70ccbf8b3a8a97f29494", getConfiguredProvider()); mockProviderApiConnector(ERROR_CASE_UPDATED_CERTIFICATE); providerApiManager = new ProviderApiManager(mockPreferences, mockResources, mockClientGenerator(), new TestProviderApiServiceCallback()); @@ -356,7 +358,7 @@ public class ProviderApiManagerTest { public void test_handleIntentSetupProvider_storedProviderAndCAFromPreviousSetup_ValidCertificateButUpdatedCertificateOnServerSide() throws IOException, CertificateEncodingException, NoSuchAlgorithmException, JSONException { Provider provider = new Provider("https://riseup.net"); - mockFingerprintForCertificate("a5244308a1374709a9afce95e3ae47c1b44bc2398c0a70ccbf8b3a8a97f29494"); + mockConfigHelper("a5244308a1374709a9afce95e3ae47c1b44bc2398c0a70ccbf8b3a8a97f29494", getConfiguredProvider()); 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(); diff --git a/app/src/test/java/se/leap/bitmaskclient/testutils/MockHelper.java b/app/src/test/java/se/leap/bitmaskclient/testutils/MockHelper.java index fa5fab8c..3e66a07d 100644 --- a/app/src/test/java/se/leap/bitmaskclient/testutils/MockHelper.java +++ b/app/src/test/java/se/leap/bitmaskclient/testutils/MockHelper.java @@ -1,6 +1,7 @@ package se.leap.bitmaskclient.testutils; import android.content.Intent; +import android.content.SharedPreferences; import android.content.res.Resources; import android.os.Bundle; import android.os.Parcelable; @@ -28,7 +29,9 @@ import java.util.Set; import okhttp3.OkHttpClient; import se.leap.bitmaskclient.ConfigHelper; +import se.leap.bitmaskclient.Constants; import se.leap.bitmaskclient.OkHttpClientGenerator; +import se.leap.bitmaskclient.Provider; import se.leap.bitmaskclient.R; import se.leap.bitmaskclient.testutils.BackendMockResponses.BackendMockProvider; import se.leap.bitmaskclient.testutils.matchers.BundleMatcher; @@ -44,6 +47,8 @@ import static org.mockito.Mockito.doAnswer; import static org.mockito.Mockito.mock; import static org.mockito.Mockito.when; import static org.powermock.api.mockito.PowerMockito.mockStatic; +import static se.leap.bitmaskclient.Constants.PROVIDER_PRIVATE_KEY; +import static se.leap.bitmaskclient.Constants.PROVIDER_VPN_CERTIFICATE; /** * Created by cyberta on 29.01.18. @@ -338,6 +343,29 @@ public class MockHelper { return resultReceiver; } + public static void mockConfigHelper(String mockedFingerprint, final Provider providerFromPrefs) throws CertificateEncodingException, NoSuchAlgorithmException { + mockStatic(ConfigHelper.class); + when(ConfigHelper.getFromPersistedProvider(anyString(), anyString(), any(SharedPreferences.class))).thenAnswer(new Answer() { + @Override + public String answer(InvocationOnMock invocation) throws Throwable { + String key = (String) invocation.getArguments()[0]; + switch (key) { + case PROVIDER_PRIVATE_KEY: + return providerFromPrefs.getPrivateKey(); + case PROVIDER_VPN_CERTIFICATE: + return providerFromPrefs.getVpnCertificate(); + case Provider.KEY: + return providerFromPrefs.getDefinition().toString(); + case Provider.CA_CERT_FINGERPRINT: + return providerFromPrefs.getCaCertFingerprint(); + } + return null; + } + }); + when(ConfigHelper.getFingerprintFromCertificate(any(X509Certificate.class), anyString())).thenReturn(mockedFingerprint); + when(ConfigHelper.checkErroneousDownload(anyString())).thenCallRealMethod(); + when(ConfigHelper.parseX509CertificateFromString(anyString())).thenCallRealMethod(); + } public static void mockFingerprintForCertificate(String mockedFingerprint) throws CertificateEncodingException, NoSuchAlgorithmException { mockStatic(ConfigHelper.class); when(ConfigHelper.getFingerprintFromCertificate(any(X509Certificate.class), anyString())).thenReturn(mockedFingerprint); -- cgit v1.2.3 From 3cc60ff642134e7442500e309c6b1248c819c0e8 Mon Sep 17 00:00:00 2001 From: Fup Duck Date: Tue, 13 Feb 2018 11:31:18 +0100 Subject: 8827 - add ProviderTest & DefaultedURLTest --- .../testutils/TestSetupHelper.java | 33 ++++++++++++++++++++++ .../se/leap/bitmaskclient/DefaultedURLTest.java | 31 ++++++++++++++++++++ .../java/se/leap/bitmaskclient/ProviderTest.java | 21 ++++++++++++++ .../bitmaskclient/eip/ProviderApiManagerTest.java | 30 ++------------------ .../leap/bitmaskclient/testutils/MockHelper.java | 1 + 5 files changed, 88 insertions(+), 28 deletions(-) create mode 100644 app/src/test/java/se/leap/bitmaskclient/DefaultedURLTest.java create mode 100644 app/src/test/java/se/leap/bitmaskclient/ProviderTest.java diff --git a/app/src/sharedTest/java/se.leap.bitmaskclient/testutils/TestSetupHelper.java b/app/src/sharedTest/java/se.leap.bitmaskclient/testutils/TestSetupHelper.java index 725924e6..a9584238 100644 --- a/app/src/sharedTest/java/se.leap.bitmaskclient/testutils/TestSetupHelper.java +++ b/app/src/sharedTest/java/se.leap.bitmaskclient/testutils/TestSetupHelper.java @@ -17,10 +17,17 @@ package se.leap.bitmaskclient.testutils; +import junit.framework.Test; + +import org.json.JSONException; + import java.io.BufferedReader; import java.io.IOException; import java.io.InputStream; import java.io.InputStreamReader; +import java.net.URL; + +import se.leap.bitmaskclient.Provider; /** * Created by cyberta on 08.10.17. @@ -40,4 +47,30 @@ public class TestSetupHelper { return sb.toString(); } + + public static Provider getConfiguredProvider() throws IOException, JSONException { + return getProvider(null, null, null); + } + + public static 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(TestSetupHelper.class.getClassLoader().getResourceAsStream(caCertFile)), + getInputAsString(TestSetupHelper.class.getClassLoader().getResourceAsStream(jsonFile)) + + ); + } catch (IOException e) { + e.printStackTrace(); + } + return null; + } + } diff --git a/app/src/test/java/se/leap/bitmaskclient/DefaultedURLTest.java b/app/src/test/java/se/leap/bitmaskclient/DefaultedURLTest.java new file mode 100644 index 00000000..cbf47621 --- /dev/null +++ b/app/src/test/java/se/leap/bitmaskclient/DefaultedURLTest.java @@ -0,0 +1,31 @@ +package se.leap.bitmaskclient; + +import org.junit.Test; + +import java.net.MalformedURLException; +import java.net.URL; + +import static org.junit.Assert.*; + +/** + * Created by cyberta on 11.02.18. + */ +public class DefaultedURLTest { + + @Test + public void testEquals_false() throws MalformedURLException { + DefaultedURL defaultedURL = new DefaultedURL(); + DefaultedURL customURL = new DefaultedURL(); + customURL.setUrl(new URL("https://customurl.com")); + + assertFalse(defaultedURL.equals(customURL)); + } + + @Test + public void testEquals_true() throws MalformedURLException { + DefaultedURL defaultedURL = new DefaultedURL(); + DefaultedURL customURL = new DefaultedURL(); + assertTrue(defaultedURL.equals(customURL)); + } + +} diff --git a/app/src/test/java/se/leap/bitmaskclient/ProviderTest.java b/app/src/test/java/se/leap/bitmaskclient/ProviderTest.java new file mode 100644 index 00000000..794c3087 --- /dev/null +++ b/app/src/test/java/se/leap/bitmaskclient/ProviderTest.java @@ -0,0 +1,21 @@ +package se.leap.bitmaskclient; + +import org.junit.Test; + +import se.leap.bitmaskclient.testutils.TestSetupHelper; + +import static org.junit.Assert.assertTrue; + +/** + * Created by cyberta on 12.02.18. + */ +public class ProviderTest { + + @Test + public void testEquals_sameFields_returnsTrue() throws Exception { + Provider p1 = TestSetupHelper.getConfiguredProvider(); + Provider p2 = TestSetupHelper.getConfiguredProvider(); + assertTrue("Providers should be same:", p1.equals(p2)); + } + +} 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 b0953493..4842d170 100644 --- a/app/src/test/java/se/leap/bitmaskclient/eip/ProviderApiManagerTest.java +++ b/app/src/test/java/se/leap/bitmaskclient/eip/ProviderApiManagerTest.java @@ -25,7 +25,6 @@ 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; @@ -36,7 +35,6 @@ 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; @@ -64,7 +62,9 @@ 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.getConfiguredProvider; import static se.leap.bitmaskclient.testutils.TestSetupHelper.getInputAsString; +import static se.leap.bitmaskclient.testutils.TestSetupHelper.getProvider; /** @@ -108,32 +108,6 @@ 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() throws IOException, JSONException { Provider provider = new Provider(""); diff --git a/app/src/test/java/se/leap/bitmaskclient/testutils/MockHelper.java b/app/src/test/java/se/leap/bitmaskclient/testutils/MockHelper.java index 3e66a07d..c2362c7b 100644 --- a/app/src/test/java/se/leap/bitmaskclient/testutils/MockHelper.java +++ b/app/src/test/java/se/leap/bitmaskclient/testutils/MockHelper.java @@ -344,6 +344,7 @@ public class MockHelper { } public static void mockConfigHelper(String mockedFingerprint, final Provider providerFromPrefs) throws CertificateEncodingException, NoSuchAlgorithmException { + // FIXME use MockSharedPreferences instead of provider mockStatic(ConfigHelper.class); when(ConfigHelper.getFromPersistedProvider(anyString(), anyString(), any(SharedPreferences.class))).thenAnswer(new Answer() { @Override -- cgit v1.2.3 From b5483d9a799d89c99dc2389379c7cceb1e148110 Mon Sep 17 00:00:00 2001 From: Fup Duck Date: Tue, 13 Feb 2018 11:53:25 +0100 Subject: update targetSdk --- app/src/main/AndroidManifest.xml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/app/src/main/AndroidManifest.xml b/app/src/main/AndroidManifest.xml index 029e9fdb..f60a2db6 100644 --- a/app/src/main/AndroidManifest.xml +++ b/app/src/main/AndroidManifest.xml @@ -21,7 +21,7 @@ + android:targetSdkVersion="27" /> -- cgit v1.2.3