diff options
29 files changed, 388 insertions, 121 deletions
diff --git a/app/assets/urls/calyx.net.url b/app/assets/urls/calyx.net.url index 8de04fe9..807e9e18 100644 --- a/app/assets/urls/calyx.net.url +++ b/app/assets/urls/calyx.net.url @@ -1,3 +1,3 @@ { - "main_url" : "https://calyx.net/" + "main_url" : "https://calyx.net" } diff --git a/app/assets/urls/demo.bitmask.net.url b/app/assets/urls/demo.bitmask.net.url index 1a412055..0c4de648 100644 --- a/app/assets/urls/demo.bitmask.net.url +++ b/app/assets/urls/demo.bitmask.net.url @@ -1,3 +1,3 @@ {
- "main_url" : "https://demo.bitmask.net/"
+ "main_url" : "https://demo.bitmask.net"
}
diff --git a/app/assets/urls/riseup.net.url b/app/assets/urls/riseup.net.url index 4548b433..42cdb979 100644 --- a/app/assets/urls/riseup.net.url +++ b/app/assets/urls/riseup.net.url @@ -1,3 +1,3 @@ { - "main_url" : "https://riseup.net/" + "main_url" : "https://riseup.net" } diff --git a/app/src/insecure/java/se/leap/bitmaskclient/ProviderApiManager.java b/app/src/insecure/java/se/leap/bitmaskclient/ProviderApiManager.java index 42bd576a..798b6433 100644 --- a/app/src/insecure/java/se/leap/bitmaskclient/ProviderApiManager.java +++ b/app/src/insecure/java/se/leap/bitmaskclient/ProviderApiManager.java @@ -140,7 +140,7 @@ public class ProviderApiManager extends ProviderApiManagerBase { else providerDotJsonString = downloadFromApiUrlWithProviderCA("/provider.json", caCert, providerDefinition, dangerOn); - if (!isValidJson(providerDotJsonString)) { + if (ConfigHelper.checkErroneousDownload(providerDotJsonString) || !isValidJson(providerDotJsonString)) { result.putString(ERRORS, resources.getString(malformed_url)); result.putBoolean(BROADCAST_RESULT_KEY, false); return result; @@ -206,9 +206,7 @@ public class ProviderApiManager extends ProviderApiManagerBase { protected Bundle updateVpnCertificate(Provider provider) { Bundle result = new Bundle(); try { - JSONObject providerJson = provider.getDefinition(); - String providerMainUrl = providerJson.getString(Provider.API_URL); - URL newCertStringUrl = new URL(providerMainUrl + "/" + providerJson.getString(Provider.API_VERSION) + "/" + PROVIDER_VPN_CERTIFICATE); + URL newCertStringUrl = new URL(provider.getApiUrlWithVersion() + "/" + PROVIDER_VPN_CERTIFICATE); String certString = downloadWithProviderCA(provider.getCaCert(), newCertStringUrl.toString(), lastDangerOn); if (ConfigHelper.checkErroneousDownload(certString)) { @@ -223,8 +221,7 @@ public class ProviderApiManager extends ProviderApiManagerBase { } } result = loadCertificate(provider, certString); - } catch (IOException | JSONException e) { - // TODO try to get Provider Json + } catch (IOException e) { setErrorResult(result, downloading_vpn_certificate_failed, null); e.printStackTrace(); } diff --git a/app/src/main/java/de/blinkt/openvpn/core/OpenVPNService.java b/app/src/main/java/de/blinkt/openvpn/core/OpenVPNService.java index 6c312c87..f701b7aa 100644 --- a/app/src/main/java/de/blinkt/openvpn/core/OpenVPNService.java +++ b/app/src/main/java/de/blinkt/openvpn/core/OpenVPNService.java @@ -913,7 +913,7 @@ public class OpenVPNService extends VpnService implements StateListener, Callbac // CONNECTED // Does not work :( notificationManager.buildOpenVpnNotification( - mProfile.mName, + mProfile != null ? mProfile.mName : "", VpnStatus.getLastCleanLogMessage(this), VpnStatus.getLastCleanLogMessage(this), level, @@ -944,7 +944,7 @@ public class OpenVPNService extends VpnService implements StateListener, Callbac humanReadableByteCount(out, false, getResources()), humanReadableByteCount(diffOut / OpenVPNManagement.mBytecountInterval, true, getResources())); notificationManager.buildOpenVpnNotification( - mProfile.mName, + mProfile != null ? mProfile.mName : "", netstat, null, LEVEL_CONNECTED, @@ -987,7 +987,7 @@ public class OpenVPNService extends VpnService implements StateListener, Callbac public void requestInputFromUser(int resid, String needed) { VpnStatus.updateStateString("NEED", "need " + needed, resid, LEVEL_WAITING_FOR_USER_INPUT); notificationManager.buildOpenVpnNotification( - mProfile.mName, + mProfile != null ? mProfile.mName : "", getString(resid), getString(resid), LEVEL_WAITING_FOR_USER_INPUT, diff --git a/app/src/main/java/se/leap/bitmaskclient/ConfigHelper.java b/app/src/main/java/se/leap/bitmaskclient/ConfigHelper.java index a52df460..a21a9601 100644 --- a/app/src/main/java/se/leap/bitmaskclient/ConfigHelper.java +++ b/app/src/main/java/se/leap/bitmaskclient/ConfigHelper.java @@ -27,6 +27,8 @@ import org.spongycastle.util.encoders.Base64; import java.io.BufferedReader; import java.io.ByteArrayInputStream; +import java.io.FileInputStream; +import java.io.FileNotFoundException; import java.io.IOException; import java.io.InputStream; import java.io.InputStreamReader; @@ -47,9 +49,11 @@ import java.security.interfaces.RSAPrivateKey; import java.security.spec.InvalidKeySpecException; import java.security.spec.PKCS8EncodedKeySpec; import java.util.ArrayList; +import java.util.HashSet; import java.util.List; import java.util.Locale; import java.util.Map; +import java.util.Set; import static android.R.attr.name; import static se.leap.bitmaskclient.Constants.PREFERENCES_APP_VERSION; @@ -74,7 +78,7 @@ public class ConfigHelper { public static boolean checkErroneousDownload(String downloadedString) { try { - if (downloadedString == null || downloadedString.isEmpty() || new JSONObject(downloadedString).has(ProviderAPI.ERRORS)) { + if (downloadedString == null || downloadedString.isEmpty() || new JSONObject(downloadedString).has(ProviderAPI.ERRORS) || new JSONObject(downloadedString).has(ProviderAPI.BACKEND_ERROR_KEY)) { return true; } else { return false; @@ -125,36 +129,14 @@ public class ConfigHelper { return (X509Certificate) certificate; } + public static String loadInputStreamAsString(java.io.InputStream is) { + java.util.Scanner s = new java.util.Scanner(is).useDelimiter("\\A"); + return s.hasNext() ? s.next() : ""; + } - public static String loadInputStreamAsString(InputStream inputStream) { - BufferedReader in = null; - try { - StringBuilder buf = new StringBuilder(); - in = new BufferedReader(new InputStreamReader(inputStream)); - - String str; - boolean isFirst = true; - while ( (str = in.readLine()) != null ) { - if (isFirst) - isFirst = false; - else - buf.append('\n'); - buf.append(str); - } - return buf.toString(); - } catch (IOException e) { - Log.e(TAG, "Error opening asset " + name); - } finally { - if (in != null) { - try { - in.close(); - } catch (IOException e) { - Log.e(TAG, "Error closing asset " + name); - } - } - } - - return null; + //allows us to mock FileInputStream + public static InputStream getInputStreamFrom(String filePath) throws FileNotFoundException { + return new FileInputStream(filePath); } protected static RSAPrivateKey parseRsaKeyFromString(String rsaKeyString) { diff --git a/app/src/main/java/se/leap/bitmaskclient/EipFragment.java b/app/src/main/java/se/leap/bitmaskclient/EipFragment.java index fb57aea8..8d1fa03a 100644 --- a/app/src/main/java/se/leap/bitmaskclient/EipFragment.java +++ b/app/src/main/java/se/leap/bitmaskclient/EipFragment.java @@ -60,7 +60,7 @@ 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_VPN_CERTIFICATE; -import static se.leap.bitmaskclient.ProviderCredentialsBaseActivity.USER_MESSAGE; +import static se.leap.bitmaskclient.ProviderAPI.USER_MESSAGE; import static se.leap.bitmaskclient.R.string.vpn_certificate_user_message; public class EipFragment extends Fragment implements Observer { diff --git a/app/src/main/java/se/leap/bitmaskclient/MainActivity.java b/app/src/main/java/se/leap/bitmaskclient/MainActivity.java index 6e778309..b4be55a4 100644 --- a/app/src/main/java/se/leap/bitmaskclient/MainActivity.java +++ b/app/src/main/java/se/leap/bitmaskclient/MainActivity.java @@ -20,7 +20,6 @@ import android.support.v7.app.AppCompatActivity; import android.support.v7.widget.Toolbar; import android.util.Log; -import org.jetbrains.annotations.NotNull; import org.json.JSONException; import org.json.JSONObject; @@ -58,7 +57,7 @@ import static se.leap.bitmaskclient.ProviderAPI.CORRECTLY_DOWNLOADED_VPN_CERTIFI import static se.leap.bitmaskclient.ProviderAPI.ERRORS; import static se.leap.bitmaskclient.ProviderAPI.INCORRECTLY_DOWNLOADED_EIP_SERVICE; import static se.leap.bitmaskclient.ProviderAPI.INCORRECTLY_DOWNLOADED_VPN_CERTIFICATE; -import static se.leap.bitmaskclient.ProviderCredentialsBaseActivity.USER_MESSAGE; +import static se.leap.bitmaskclient.ProviderAPI.USER_MESSAGE; import static se.leap.bitmaskclient.R.string.downloading_vpn_certificate_failed; import static se.leap.bitmaskclient.R.string.vpn_certificate_user_message; @@ -67,12 +66,7 @@ public class MainActivity extends AppCompatActivity implements Observer { public final static String TAG = MainActivity.class.getSimpleName(); - private static final String KEY_ACTIVITY_STATE = "key state of activity"; - private static final String DEFAULT_UI_STATE = "default state"; - private static final String SHOW_DIALOG_STATE = "show dialog"; - private static final String REASON_TO_FAIL = "reason to fail"; - - private static Provider provider = new Provider(); + private Provider provider = new Provider(); private SharedPreferences preferences; private EipStatus eipStatus; private NavigationDrawerFragment navigationDrawerFragment; @@ -198,7 +192,7 @@ public class MainActivity extends AppCompatActivity implements Observer { break; } } - + //TODO: Why do we want this --v? legacy and redundant? Fragment fragment = new EipFragment(); Bundle arguments = new Bundle(); arguments.putParcelable(PROVIDER_KEY, provider); diff --git a/app/src/main/java/se/leap/bitmaskclient/Provider.java b/app/src/main/java/se/leap/bitmaskclient/Provider.java index 7104143c..fd067bf9 100644 --- a/app/src/main/java/se/leap/bitmaskclient/Provider.java +++ b/app/src/main/java/se/leap/bitmaskclient/Provider.java @@ -90,9 +90,8 @@ public final class Provider implements Parcelable { } if (definition != null) { try { - this.definition = new JSONObject(definition); - parseDefinition(this.definition); - } catch (JSONException | NullPointerException e) { + define(new JSONObject(definition)); + } catch (JSONException e) { e.printStackTrace(); } } @@ -133,26 +132,8 @@ public final class Provider implements Parcelable { } 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; - } + definition = providerJson; + return parseDefinition(definition); } public JSONObject getDefinition() { @@ -297,8 +278,6 @@ public final class Provider implements Parcelable { try { json.put(Provider.MAIN_URL, mainUrl); //TODO: add other fields here? - //this is used to save custom providers as json. I guess this doesn't work correctly - //TODO 2: verify that } catch (JSONException e) { e.printStackTrace(); } @@ -345,7 +324,7 @@ public final class Provider implements Parcelable { } } - private void parseDefinition(JSONObject definition) { + private boolean parseDefinition(JSONObject definition) { try { String pin = definition.getString(CA_CERT_FINGERPRINT); this.certificatePin = pin.split(":")[1].trim(); @@ -354,8 +333,9 @@ public final class Provider implements Parcelable { this.allowAnonymous = definition.getJSONObject(Provider.SERVICE).getBoolean(PROVIDER_ALLOW_ANONYMOUS); this.allowRegistered = definition.getJSONObject(Provider.SERVICE).getBoolean(PROVIDER_ALLOWED_REGISTERED); this.apiVersion = getDefinition().getString(Provider.API_VERSION); + return true; } catch (JSONException | ArrayIndexOutOfBoundsException | MalformedURLException e) { - e.printStackTrace(); + return false; } } @@ -446,5 +426,4 @@ public final class Provider implements Parcelable { allowRegistered = false; allowAnonymous = false; } - } diff --git a/app/src/main/java/se/leap/bitmaskclient/ProviderAPI.java b/app/src/main/java/se/leap/bitmaskclient/ProviderAPI.java index f5efde05..f1f474d7 100644 --- a/app/src/main/java/se/leap/bitmaskclient/ProviderAPI.java +++ b/app/src/main/java/se/leap/bitmaskclient/ProviderAPI.java @@ -51,6 +51,7 @@ public class ProviderAPI extends IntentService implements ProviderApiManagerBase ERRORID = "errorId", BACKEND_ERROR_KEY = "error", BACKEND_ERROR_MESSAGE = "message", + USER_MESSAGE = "userMessage", DOWNLOAD_SERVICE_JSON = "ProviderAPI.DOWNLOAD_SERVICE_JSON", PROVIDER_SET_UP = "ProviderAPI.PROVIDER_SET_UP"; diff --git a/app/src/main/java/se/leap/bitmaskclient/ProviderApiManagerBase.java b/app/src/main/java/se/leap/bitmaskclient/ProviderApiManagerBase.java index b93abaeb..2cde431e 100644 --- a/app/src/main/java/se/leap/bitmaskclient/ProviderApiManagerBase.java +++ b/app/src/main/java/se/leap/bitmaskclient/ProviderApiManagerBase.java @@ -46,6 +46,7 @@ import java.security.cert.X509Certificate; import java.security.interfaces.RSAPrivateKey; import java.util.ArrayList; import java.util.List; +import java.util.NoSuchElementException; import javax.net.ssl.SSLHandshakeException; @@ -63,19 +64,16 @@ import static se.leap.bitmaskclient.Constants.PROVIDER_PRIVATE_KEY; import static se.leap.bitmaskclient.Constants.PROVIDER_VPN_CERTIFICATE; import static se.leap.bitmaskclient.ProviderAPI.BACKEND_ERROR_KEY; import static se.leap.bitmaskclient.ProviderAPI.BACKEND_ERROR_MESSAGE; -import static se.leap.bitmaskclient.ProviderSetupFailedDialog.DOWNLOAD_ERRORS.ERROR_CERTIFICATE_PINNING; -import static se.leap.bitmaskclient.ProviderSetupFailedDialog.DOWNLOAD_ERRORS.ERROR_CORRUPTED_PROVIDER_JSON; -import static se.leap.bitmaskclient.ProviderSetupFailedDialog.DOWNLOAD_ERRORS.ERROR_INVALID_CERTIFICATE; -import static se.leap.bitmaskclient.ProviderAPI.CORRECTLY_DOWNLOADED_VPN_CERTIFICATE; import static se.leap.bitmaskclient.ProviderAPI.CORRECTLY_DOWNLOADED_EIP_SERVICE; -import static se.leap.bitmaskclient.ProviderAPI.DOWNLOAD_VPN_CERTIFICATE; +import static se.leap.bitmaskclient.ProviderAPI.CORRECTLY_DOWNLOADED_VPN_CERTIFICATE; import static se.leap.bitmaskclient.ProviderAPI.DOWNLOAD_SERVICE_JSON; +import static se.leap.bitmaskclient.ProviderAPI.DOWNLOAD_VPN_CERTIFICATE; import static se.leap.bitmaskclient.ProviderAPI.ERRORID; import static se.leap.bitmaskclient.ProviderAPI.ERRORS; import static se.leap.bitmaskclient.ProviderAPI.FAILED_LOGIN; import static se.leap.bitmaskclient.ProviderAPI.FAILED_SIGNUP; -import static se.leap.bitmaskclient.ProviderAPI.INCORRECTLY_DOWNLOADED_VPN_CERTIFICATE; import static se.leap.bitmaskclient.ProviderAPI.INCORRECTLY_DOWNLOADED_EIP_SERVICE; +import static se.leap.bitmaskclient.ProviderAPI.INCORRECTLY_DOWNLOADED_VPN_CERTIFICATE; import static se.leap.bitmaskclient.ProviderAPI.LOGOUT_FAILED; import static se.leap.bitmaskclient.ProviderAPI.LOG_IN; import static se.leap.bitmaskclient.ProviderAPI.LOG_OUT; @@ -90,15 +88,18 @@ 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_PROVIDER_DETAILS; +import static se.leap.bitmaskclient.ProviderAPI.USER_MESSAGE; +import static se.leap.bitmaskclient.ProviderSetupFailedDialog.DOWNLOAD_ERRORS.ERROR_CERTIFICATE_PINNING; +import static se.leap.bitmaskclient.ProviderSetupFailedDialog.DOWNLOAD_ERRORS.ERROR_CORRUPTED_PROVIDER_JSON; +import static se.leap.bitmaskclient.ProviderSetupFailedDialog.DOWNLOAD_ERRORS.ERROR_INVALID_CERTIFICATE; import static se.leap.bitmaskclient.R.string.certificate_error; -import static se.leap.bitmaskclient.R.string.switch_provider_menu_option; -import static se.leap.bitmaskclient.R.string.vpn_certificate_is_invalid; import static se.leap.bitmaskclient.R.string.error_io_exception_user_message; import static se.leap.bitmaskclient.R.string.error_json_exception_user_message; import static se.leap.bitmaskclient.R.string.error_no_such_algorithm_exception_user_message; import static se.leap.bitmaskclient.R.string.malformed_url; import static se.leap.bitmaskclient.R.string.server_unreachable_message; import static se.leap.bitmaskclient.R.string.service_is_down_error; +import static se.leap.bitmaskclient.R.string.vpn_certificate_is_invalid; import static se.leap.bitmaskclient.R.string.warning_corrupted_provider_cert; import static se.leap.bitmaskclient.R.string.warning_corrupted_provider_details; import static se.leap.bitmaskclient.R.string.warning_expired_provider_cert; @@ -290,7 +291,7 @@ public abstract class ProviderApiManagerBase { JSONObject stepResult = null; OkHttpClient okHttpClient = clientGenerator.initSelfSignedCAHttpClient(provider.getCaCert(), stepResult); if (okHttpClient == null) { - return authFailedNotification(stepResult, username); + return backendErrorNotification(stepResult, username); } LeapSRPSession client = new LeapSRPSession(username, password); @@ -302,7 +303,7 @@ public abstract class ProviderApiManagerBase { Bundle result = new Bundle(); if (api_result.has(ERRORS) || api_result.has(BACKEND_ERROR_KEY)) - result = authFailedNotification(api_result, username); + result = backendErrorNotification(api_result, username); else { result.putString(CREDENTIALS_USERNAME, username); result.putString(CREDENTIALS_PASSWORD, password); @@ -349,7 +350,7 @@ public abstract class ProviderApiManagerBase { OkHttpClient okHttpClient = clientGenerator.initSelfSignedCAHttpClient(provider.getCaCert(), stepResult); if (okHttpClient == null) { - return authFailedNotification(stepResult, username); + return backendErrorNotification(stepResult, username); } LeapSRPSession client = new LeapSRPSession(username, password); @@ -367,15 +368,15 @@ public abstract class ProviderApiManagerBase { if (client.verify(M2)) { result.putBoolean(BROADCAST_RESULT_KEY, true); } else { - authFailedNotification(step_result, username); + backendErrorNotification(step_result, username); } } else { 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)); + result.putString(USER_MESSAGE, resources.getString(R.string.error_srp_math_error_user_message)); } } catch (JSONException e) { - result = authFailedNotification(step_result, username); + result = backendErrorNotification(step_result, username); e.printStackTrace(); } @@ -391,7 +392,7 @@ public abstract class ProviderApiManagerBase { return true; } - private Bundle authFailedNotification(JSONObject result, String username) { + private Bundle backendErrorNotification(JSONObject result, String username) { Bundle userNotificationBundle = new Bundle(); if (result.has(ERRORS)) { Object baseErrorMessage = result.opt(ERRORS); @@ -400,14 +401,14 @@ public abstract class ProviderApiManagerBase { JSONObject errorMessage = result.getJSONObject(ERRORS); String errorType = errorMessage.keys().next().toString(); String message = errorMessage.get(errorType).toString(); - userNotificationBundle.putString(resources.getString(R.string.user_message), message); - } catch (JSONException e) { + userNotificationBundle.putString(USER_MESSAGE, message); + } catch (JSONException | NoSuchElementException | NullPointerException e) { e.printStackTrace(); } } else if (baseErrorMessage instanceof String) { try { String errorMessage = result.getString(ERRORS); - userNotificationBundle.putString(resources.getString(R.string.user_message), errorMessage); + userNotificationBundle.putString(USER_MESSAGE, errorMessage); } catch (JSONException e) { e.printStackTrace(); } @@ -418,7 +419,7 @@ public abstract class ProviderApiManagerBase { if (result.has(BACKEND_ERROR_MESSAGE)) { backendErrorMessage = resources.getString(R.string.error) + result.getString(BACKEND_ERROR_MESSAGE); } - userNotificationBundle.putString(resources.getString(R.string.user_message), backendErrorMessage); + userNotificationBundle.putString(USER_MESSAGE, backendErrorMessage); } catch (JSONException e) { e.printStackTrace(); } @@ -431,7 +432,7 @@ public abstract class ProviderApiManagerBase { return userNotificationBundle; } - void sendToReceiverOrBroadcast(ResultReceiver receiver, int resultCode, Bundle resultData, Provider provider) { + private void sendToReceiverOrBroadcast(ResultReceiver receiver, int resultCode, Bundle resultData, Provider provider) { if (resultData == null || resultData == Bundle.EMPTY) { resultData = new Bundle(); } diff --git a/app/src/main/java/se/leap/bitmaskclient/ProviderCredentialsBaseActivity.java b/app/src/main/java/se/leap/bitmaskclient/ProviderCredentialsBaseActivity.java index d41be512..e6877756 100644 --- a/app/src/main/java/se/leap/bitmaskclient/ProviderCredentialsBaseActivity.java +++ b/app/src/main/java/se/leap/bitmaskclient/ProviderCredentialsBaseActivity.java @@ -30,6 +30,7 @@ import org.json.JSONException; import butterknife.InjectView; import butterknife.OnClick; import se.leap.bitmaskclient.Constants.CREDENTIAL_ERRORS; +import se.leap.bitmaskclient.eip.EipCommand; import se.leap.bitmaskclient.userstatus.User; import static android.view.View.GONE; @@ -41,9 +42,12 @@ 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.BACKEND_ERROR_KEY; import static se.leap.bitmaskclient.ProviderAPI.DOWNLOAD_VPN_CERTIFICATE; +import static se.leap.bitmaskclient.ProviderAPI.ERRORS; import static se.leap.bitmaskclient.ProviderAPI.LOG_IN; import static se.leap.bitmaskclient.ProviderAPI.SIGN_UP; +import static se.leap.bitmaskclient.ProviderAPI.USER_MESSAGE; /** * Base Activity for activities concerning a provider interaction @@ -59,7 +63,6 @@ public abstract class ProviderCredentialsBaseActivity extends ConfigWizardBaseAc final private static String SHOWING_FORM = "SHOWING_FORM"; final private static String PERFORMING_ACTION = "PERFORMING_ACTION"; - final public static String USER_MESSAGE = "USER_MESSAGE"; final private static String USERNAME_ERROR = "USERNAME_ERROR"; final private static String PASSWORD_ERROR = "PASSWORD_ERROR"; final private static String PASSWORD_VERIFICATION_ERROR = "PASSWORD_VERIFICATION_ERROR"; @@ -344,8 +347,8 @@ public abstract class ProviderCredentialsBaseActivity extends ConfigWizardBaseAc if (arguments.containsKey(CREDENTIAL_ERRORS.USERNAME_MISSING.toString())) { usernameError.setError(getString(R.string.username_ask)); } - if (arguments.containsKey(getString(R.string.user_message))) { - String userMessageString = arguments.getString(getString(R.string.user_message)); + if (arguments.containsKey(USER_MESSAGE)) { + String userMessageString = arguments.getString(USER_MESSAGE); try { userMessageString = new JSONArray(userMessageString).getString(0); } catch (JSONException e) { @@ -395,6 +398,10 @@ public abstract class ProviderCredentialsBaseActivity extends ConfigWizardBaseAc switch (resultCode) { case ProviderAPI.SUCCESSFUL_SIGNUP: + String password = resultData.getString(CREDENTIALS_PASSWORD); + String username = resultData.getString(CREDENTIALS_USERNAME); + login(username, password); + break; case ProviderAPI.SUCCESSFUL_LOGIN: downloadVpnCertificate(handledProvider); break; @@ -403,12 +410,11 @@ public abstract class ProviderCredentialsBaseActivity extends ConfigWizardBaseAc handleReceivedErrors((Bundle) intent.getParcelableExtra(BROADCAST_RESULT_KEY)); break; + case ProviderAPI.INCORRECTLY_DOWNLOADED_VPN_CERTIFICATE: + // error handling takes place in MainActivity case ProviderAPI.CORRECTLY_DOWNLOADED_VPN_CERTIFICATE: successfullyFinished(handledProvider); break; - case ProviderAPI.INCORRECTLY_DOWNLOADED_VPN_CERTIFICATE: - // TODO activity.setResult(RESULT_CANCELED); - break; } } } diff --git a/app/src/main/java/se/leap/bitmaskclient/ProviderListBaseActivity.java b/app/src/main/java/se/leap/bitmaskclient/ProviderListBaseActivity.java index e961b0a2..3bf51a8c 100644 --- a/app/src/main/java/se/leap/bitmaskclient/ProviderListBaseActivity.java +++ b/app/src/main/java/se/leap/bitmaskclient/ProviderListBaseActivity.java @@ -207,7 +207,8 @@ public abstract class ProviderListBaseActivity extends ConfigWizardBaseActivity void handleProviderSetUp(Provider handledProvider) { this.provider = handledProvider; - + adapter.add(provider); + adapter.saveProviders(); if (provider.allowsAnonymous()) { mConfigState.putExtra(SERVICES_RETRIEVED, true); downloadVpnCertificate(); diff --git a/app/src/main/java/se/leap/bitmaskclient/ProviderManager.java b/app/src/main/java/se/leap/bitmaskclient/ProviderManager.java index ed41be67..97ba3b98 100644 --- a/app/src/main/java/se/leap/bitmaskclient/ProviderManager.java +++ b/app/src/main/java/se/leap/bitmaskclient/ProviderManager.java @@ -31,6 +31,8 @@ public class ProviderManager implements AdapteeCollection<Provider> { private File externalFilesDir; private Set<Provider> defaultProviders; private Set<Provider> customProviders; + private Set<URL> defaultProviderURLs; + private Set<URL> customProviderURLs; private static ProviderManager instance; @@ -52,11 +54,20 @@ public class ProviderManager implements AdapteeCollection<Provider> { private void addDefaultProviders(AssetManager assets_manager) { try { defaultProviders = providersFromAssets(URLS, assets_manager.list(URLS)); + defaultProviderURLs = getProviderUrlSetFromProviderSet(defaultProviders); } catch (IOException e) { e.printStackTrace(); } } + private Set<URL> getProviderUrlSetFromProviderSet(Set<Provider> providers) { + HashSet<URL> providerUrls = new HashSet<>(); + for (Provider provider : providers) { + providerUrls.add(provider.getMainUrl().getUrl()); + } + return providerUrls; + } + private Set<Provider> providersFromAssets(String directory, String[] relativeFilePaths) { Set<Provider> providers = new HashSet<>(); @@ -89,13 +100,14 @@ public class ProviderManager implements AdapteeCollection<Provider> { customProviders = externalFilesDir != null && externalFilesDir.isDirectory() ? providersFromFiles(externalFilesDir.list()) : new HashSet<Provider>(); + customProviderURLs = getProviderUrlSetFromProviderSet(customProviders); } private Set<Provider> providersFromFiles(String[] files) { Set<Provider> providers = new HashSet<>(); try { for (String file : files) { - String mainUrl = extractMainUrlFromInputStream(new FileInputStream(externalFilesDir.getAbsolutePath() + "/" + file)); + String mainUrl = extractMainUrlFromInputStream(ConfigHelper.getInputStreamFrom(externalFilesDir.getAbsolutePath() + "/" + file)); providers.add(new Provider(new URL(mainUrl))); } } catch (MalformedURLException | FileNotFoundException e) { @@ -132,6 +144,8 @@ public class ProviderManager implements AdapteeCollection<Provider> { allProviders.addAll(defaultProviders); if(customProviders != null) allProviders.addAll(customProviders); + //add an option to add a custom provider + //TODO: refactor me? allProviders.add(new Provider()); return allProviders; } @@ -153,32 +167,59 @@ public class ProviderManager implements AdapteeCollection<Provider> { @Override public boolean add(Provider element) { - return !defaultProviders.contains(element) || customProviders.add(element); + return element != null && + !defaultProviderURLs.contains(element.getMainUrl().getUrl()) && + customProviders.add(element) && + customProviderURLs.add(element.getMainUrl().getUrl()); } @Override public boolean remove(Object element) { - return customProviders.remove(element); + return element instanceof Provider && + customProviders.remove(element) && + customProviderURLs.remove(((Provider) element).getMainUrl().getUrl()); } @Override public boolean addAll(Collection<? extends Provider> elements) { - return customProviders.addAll(elements); + Iterator iterator = elements.iterator(); + boolean addedAll = true; + while (iterator.hasNext()) { + Provider p = (Provider) iterator.next(); + addedAll = customProviders.add(p) && + customProviderURLs.add(p.getMainUrl().getUrl()) && + addedAll; + } + return addedAll; } @Override public boolean removeAll(Collection<?> elements) { - if(!elements.getClass().equals(Provider.class)) + Iterator iterator = elements.iterator(); + boolean removedAll = true; + try { + while (iterator.hasNext()) { + Provider p = (Provider) iterator.next(); + removedAll = ((defaultProviders.remove(p) && defaultProviderURLs.remove(p.getMainUrl().getUrl())) || + (customProviders.remove(p) && customProviderURLs.remove(p.getMainUrl().getUrl()))) && + removedAll; + } + } catch (ClassCastException e) { return false; - return defaultProviders.removeAll(elements) || customProviders.removeAll(elements); + } + + return removedAll; } @Override public void clear() { defaultProviders.clear(); customProviders.clear(); + customProviderURLs.clear(); + defaultProviderURLs.clear(); } + //FIXME: removed custom providers should be deleted here as well void saveCustomProvidersToFile() { try { for (Provider provider : customProviders) { diff --git a/app/src/production/java/se/leap/bitmaskclient/ProviderApiManager.java b/app/src/production/java/se/leap/bitmaskclient/ProviderApiManager.java index e5ee6c49..885d69db 100644 --- a/app/src/production/java/se/leap/bitmaskclient/ProviderApiManager.java +++ b/app/src/production/java/se/leap/bitmaskclient/ProviderApiManager.java @@ -34,6 +34,7 @@ import se.leap.bitmaskclient.eip.EIP; import static android.text.TextUtils.isEmpty; import static se.leap.bitmaskclient.Constants.BROADCAST_RESULT_KEY; +import static se.leap.bitmaskclient.Constants.PROVIDER_KEY; import static se.leap.bitmaskclient.Constants.PROVIDER_VPN_CERTIFICATE; import static se.leap.bitmaskclient.ProviderAPI.ERRORS; import static se.leap.bitmaskclient.ProviderSetupFailedDialog.DOWNLOAD_ERRORS.ERROR_CERTIFICATE_PINNING; @@ -84,6 +85,7 @@ public class ProviderApiManager extends ProviderApiManagerBase { //provider details invalid if (currentDownload.containsKey(ERRORS)) { + currentDownload.putParcelable(PROVIDER_KEY, provider); return currentDownload; } @@ -121,7 +123,7 @@ public class ProviderApiManager extends ProviderApiManagerBase { providerDotJsonString = downloadFromApiUrlWithProviderCA("/provider.json", caCert, providerDefinition); } - if (!isValidJson(providerDotJsonString)) { + if (ConfigHelper.checkErroneousDownload(providerDotJsonString) || !isValidJson(providerDotJsonString)) { setErrorResult(result, malformed_url, null); return result; } @@ -177,9 +179,7 @@ public class ProviderApiManager extends ProviderApiManagerBase { protected Bundle updateVpnCertificate(Provider provider) { Bundle result = new Bundle(); try { - JSONObject providerJson = provider.getDefinition(); - String providerMainUrl = providerJson.getString(Provider.API_URL); - URL newCertStringUrl = new URL(providerMainUrl + "/" + providerJson.getString(Provider.API_VERSION) + "/" + PROVIDER_VPN_CERTIFICATE); + URL newCertStringUrl = new URL(provider.getApiUrlWithVersion() + "/" + PROVIDER_VPN_CERTIFICATE); String certString = downloadWithProviderCA(provider.getCaCert(), newCertStringUrl.toString()); if (ConfigHelper.checkErroneousDownload(certString)) { @@ -194,7 +194,7 @@ public class ProviderApiManager extends ProviderApiManagerBase { } } return loadCertificate(provider, certString); - } catch (IOException | JSONException e) { + } catch (IOException e) { // TODO try to get Provider Json setErrorResult(result, downloading_vpn_certificate_failed, null); e.printStackTrace(); diff --git a/app/src/production/java/se/leap/bitmaskclient/ProviderListActivity.java b/app/src/production/java/se/leap/bitmaskclient/ProviderListActivity.java index b6e67331..cf1d1aa6 100644 --- a/app/src/production/java/se/leap/bitmaskclient/ProviderListActivity.java +++ b/app/src/production/java/se/leap/bitmaskclient/ProviderListActivity.java @@ -39,11 +39,10 @@ public class ProviderListActivity extends ProviderListBaseActivity { setUpProvider(); } + @Override public void showAndSelectProvider(String provider_main_url) { try { provider = new Provider(new URL((provider_main_url))); - adapter.add(provider); - adapter.saveProviders(); autoSelectProvider(provider); } catch (MalformedURLException e) { e.printStackTrace(); diff --git a/app/src/test/java/se/leap/bitmaskclient/ProviderTest.java b/app/src/test/java/se/leap/bitmaskclient/ProviderTest.java index 794c3087..495d5b3f 100644 --- a/app/src/test/java/se/leap/bitmaskclient/ProviderTest.java +++ b/app/src/test/java/se/leap/bitmaskclient/ProviderTest.java @@ -1,9 +1,15 @@ package se.leap.bitmaskclient; +import org.json.JSONException; import org.junit.Test; +import java.io.IOException; +import java.util.HashSet; +import java.util.Set; + import se.leap.bitmaskclient.testutils.TestSetupHelper; +import static junit.framework.Assert.assertFalse; import static org.junit.Assert.assertTrue; /** @@ -18,4 +24,28 @@ public class ProviderTest { assertTrue("Providers should be same:", p1.equals(p2)); } + @Test + public void testEquals_sameFields_returnsFalse() throws Exception { + Provider p1 = TestSetupHelper.getConfiguredProvider(); + Provider p2 = TestSetupHelper.getConfiguredProvider(); + p2.setMainUrl("http://somethingsdiffer.org"); + assertFalse("Providers should be same:", p1.equals(p2)); + } + + // see ProviderManagerTest testing add(...) + @Test + public void testEqualsThroughSetContains_differentFields_returnsFalse() throws Exception { + Provider p1 = TestSetupHelper.getConfiguredProvider(); + Provider p2 = TestSetupHelper.getConfiguredProvider(); + p2.setMainUrl("http://somethingsdiffer.org"); + Provider p3 = new Provider("https://anotherprovider.net"); + + Set<Provider> defaultProviders = new HashSet<>(); + defaultProviders.add(p1); + defaultProviders.add(p2); + + assertTrue(defaultProviders.contains(p1)); + assertTrue(defaultProviders.contains(p2)); + assertFalse(defaultProviders.contains(p3)); + } } 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 c2362c7b..d85b050f 100644 --- a/app/src/test/java/se/leap/bitmaskclient/testutils/MockHelper.java +++ b/app/src/test/java/se/leap/bitmaskclient/testutils/MockHelper.java @@ -14,6 +14,7 @@ import org.json.JSONObject; import org.mockito.invocation.InvocationOnMock; import org.mockito.stubbing.Answer; +import java.io.FileNotFoundException; import java.io.IOException; import java.io.InputStream; import java.security.NoSuchAlgorithmException; @@ -29,7 +30,6 @@ 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; @@ -343,6 +343,18 @@ public class MockHelper { return resultReceiver; } + public static void mockConfigHelperForFileInputStream() throws FileNotFoundException { + mockStatic(ConfigHelper.class); + when(ConfigHelper.loadInputStreamAsString(any(InputStream.class))).thenCallRealMethod(); + when(ConfigHelper.getInputStreamFrom(anyString())).thenAnswer(new Answer<InputStream>() { + @Override + public InputStream answer(InvocationOnMock invocation) throws Throwable { + String filename = (String) invocation.getArguments()[0]; + return getClass().getClassLoader().getResourceAsStream(filename); + } + }); + } + public static void mockConfigHelper(String mockedFingerprint, final Provider providerFromPrefs) throws CertificateEncodingException, NoSuchAlgorithmException { // FIXME use MockSharedPreferences instead of provider mockStatic(ConfigHelper.class); @@ -366,6 +378,7 @@ public class MockHelper { when(ConfigHelper.getFingerprintFromCertificate(any(X509Certificate.class), anyString())).thenReturn(mockedFingerprint); when(ConfigHelper.checkErroneousDownload(anyString())).thenCallRealMethod(); when(ConfigHelper.parseX509CertificateFromString(anyString())).thenCallRealMethod(); + when(ConfigHelper.loadInputStreamAsString(any(InputStream.class))).thenCallRealMethod(); } public static void mockFingerprintForCertificate(String mockedFingerprint) throws CertificateEncodingException, NoSuchAlgorithmException { mockStatic(ConfigHelper.class); diff --git a/app/src/test/resources/externalDir/leapcolombia.json b/app/src/test/resources/externalDir/leapcolombia.json new file mode 100644 index 00000000..6820988c --- /dev/null +++ b/app/src/test/resources/externalDir/leapcolombia.json @@ -0,0 +1,3 @@ +{ + "main_url" : "https://leapcolombia.org" +}
\ No newline at end of file diff --git a/app/src/test/resources/preconfigured/calyx.net.json b/app/src/test/resources/preconfigured/calyx.net.json new file mode 100644 index 00000000..30ab43c5 --- /dev/null +++ b/app/src/test/resources/preconfigured/calyx.net.json @@ -0,0 +1,37 @@ +{ + "api_uri": "https://calyx.net:4430", + "api_version": "1", + "ca_cert_fingerprint": "SHA256: 43683c9ba3862c5384a8c1885072fcac40b5d2d4dd67331443f13a3077fa2e69", + "ca_cert_uri": "https://calyx.net/ca.crt", + "default_language": "en", + "description": { + "en": "Calyx Institute privacy focused ISP testbed" + }, + "domain": "calyx.net", + "enrollment_policy": "open", + "languages": [ + "en" + ], + "name": { + "en": "calyx" + }, + "service": { + "allow_anonymous": false, + "allow_free": true, + "allow_limited_bandwidth": false, + "allow_paid": false, + "allow_registration": true, + "allow_unlimited_bandwidth": true, + "bandwidth_limit": 102400, + "default_service_level": 1, + "levels": { + "1": { + "description": "Please donate.", + "name": "free" + } + } + }, + "services": [ + "openvpn" + ] +}
\ No newline at end of file diff --git a/app/src/test/resources/preconfigured/calyx.net.pem b/app/src/test/resources/preconfigured/calyx.net.pem new file mode 100644 index 00000000..cedb2e38 --- /dev/null +++ b/app/src/test/resources/preconfigured/calyx.net.pem @@ -0,0 +1,31 @@ +-----BEGIN CERTIFICATE----- +MIIFYzCCA0ugAwIBAgIBATANBgkqhkiG9w0BAQ0FADBEMQ4wDAYDVQQKDAVjYWx5 +eDEaMBgGA1UECwwRaHR0cHM6Ly9jYWx5eC5uZXQxFjAUBgNVBAMMDWNhbHl4IFJv +b3QgQ0EwHhcNMTMwNzAyMDAwMDAwWhcNMjMwNzAyMDAwMDAwWjBEMQ4wDAYDVQQK +DAVjYWx5eDEaMBgGA1UECwwRaHR0cHM6Ly9jYWx5eC5uZXQxFjAUBgNVBAMMDWNh +bHl4IFJvb3QgQ0EwggIiMA0GCSqGSIb3DQEBAQUAA4ICDwAwggIKAoICAQDupdnx +Bgat537XOqrZOulE/RvjoXB1S07sy9/MMtksXFoQuWJZRCSTp1Jaqg3H/e9o1nct +LQO91+izfJe07TUyajFl7CfllYgMeyKTYcT85dFwNX4pcIHZr8UpmO0MpGBoR4W1 +8cPa3vxAG0CsyUmrASJVyhRouk4qazRosM5RwBxTdMzCK7L3SwqPQoxlY9YmRJlD +XYZlK5VMJd0dj9XxhMeFs5n43R0bsDENryrExSbuxoNfnUoQg3wffKk+Z0gW7YgW +ivPsbObqOgXUuBEU0xr9xMNBpU33ffLIsccrHq1EKp8zGfCOcww6v7+zEadUkVLo +6j/rRhYYgRw9lijZG1rMuV/mTGnUqbjHsdoz5mzkFFWeTSqo44lvhveUyCcwRNmi +2sjS77l0fCTzfreufffFoOEcRVMRfsnJdu/xPeARoXILEx8nQ421mSn6spOZlDQr +Tt0T0BAWt+VNc+m0IGSW3SwS7r5MUyQ/M5GrbQBGi5W2SzPriKZ79YTOwPVmXKLZ +vJoEuKRDkEPJLBAhcD5oSQljOm/Wp/hjmRH4HnI1y4XMshWlDsyRDB1Au5yrsfwN +noFVSskEcbXlZfNgml4lktLBqz+qwsw+voq6Ak7ROKbc0ii5s8+iNMbAtIK7GcFF +kuKKIyRmmGlDim/SDhlNdWo7Ah4Akde7zfWufwIDAQABo2AwXjAdBgNVHQ4EFgQU +AY8+K4ZupAQ+L9ttFJG3vaLBq5gwDgYDVR0PAQH/BAQDAgIEMAwGA1UdEwQFMAMB +Af8wHwYDVR0jBBgwFoAUAY8+K4ZupAQ+L9ttFJG3vaLBq5gwDQYJKoZIhvcNAQEN +BQADggIBAOpXi5o3g/2o2rPa53iG7Zgcy8RpePGgZk6xknGYWeLamEqSh+XWQZ2w +2kQP54bf8HfPj3ugJBWsVtYAs/ltJwzeBfYDrwEJd1N8tw2IRuGlQOWiTAVVLBj4 +Zs+dikSuMoA399f/7BlUIEpVLUiV/emTtbkjFnDeKEV9zql6ypR0BtR8Knf8ALvL +YfMsWLvTe4rXeypzxIaE2pn8ttcXLYAX0ml2MofTi5xcDhMn1vznKIvs82xhncQx +I1MJMWqPHNHgJUJpA+y1IFh5LPbpag9PKQ0yQ9sM+/dyGumF2jElsMw71flh/Txr +2dEv8+FNV1pPK26XJZBK24rNWFs30eAFfH9EQCwVla174I4PDoWqsIR7vtQMObDt +Bq34R3TjjJJIt2sCSlYLooWwiK7Q+d/SgYqA+MSDmmwhzm86ToK6cwbCsvuw1AxR +X6VIs4U8wOotgljzX/CSpKqlxcqZjhnAuelZ1+KiN8RHKPj7AzSLYOv/YwTjLTIq +EOxquoNR58uDa5pBG22a7xWbSaKosn/mEl8SrUr6klzzc8Vh09IMoxrw74uLdAg2 +1jnrhm7qg91Ttb0aXiqbV+Kg/qQzojdewnnoBFnv4jaQ3y8zDCfMhsBtWlWz4Knb +Zqga1WyRm3Gj1j6IV0oOincYMrw5YA7bgXpwop/Lo/mmliMA14ps +-----END CERTIFICATE-----
\ No newline at end of file diff --git a/app/src/test/resources/preconfigured/demo.bitmask.net.json b/app/src/test/resources/preconfigured/demo.bitmask.net.json new file mode 100644 index 00000000..e7fe6099 --- /dev/null +++ b/app/src/test/resources/preconfigured/demo.bitmask.net.json @@ -0,0 +1,42 @@ +{ + "api_uri": "https://api.demo.bitmask.net:4430", + "api_version": "1", + "ca_cert_fingerprint": "SHA256: 0f17c033115f6b76ff67871872303ff65034efe7dd1b910062ca323eb4da5c7e", + "ca_cert_uri": "https://demo.bitmask.net/ca.crt", + "default_language": "en", + "description": { + "el": "demo.bitmask.net allows you to test the Bitmask application. User accounts may be periodically deleted.", + "en": "demo.bitmask.net allows you to test the Bitmask application. User accounts may be periodically deleted.", + "es": "demo.bitmask.net allows you to test the Bitmask application. User accounts may be periodically deleted." + }, + "domain": "demo.bitmask.net", + "enrollment_policy": "open", + "languages": [ + "de", + "en", + "es", + "pt" + ], + "name": { + "en": "Bitmask" + }, + "service": { + "allow_anonymous": true, + "allow_free": true, + "allow_limited_bandwidth": false, + "allow_paid": false, + "allow_registration": true, + "allow_unlimited_bandwidth": true, + "bandwidth_limit": 102400, + "default_service_level": 1, + "levels": { + "1": { + "description": "Please donate.", + "name": "free" + } + } + }, + "services": [ + "openvpn" + ] +}
\ No newline at end of file diff --git a/app/src/test/resources/preconfigured/demo.bitmask.net.pem b/app/src/test/resources/preconfigured/demo.bitmask.net.pem new file mode 100644 index 00000000..9a422161 --- /dev/null +++ b/app/src/test/resources/preconfigured/demo.bitmask.net.pem @@ -0,0 +1,32 @@ +-----BEGIN CERTIFICATE----- +MIIFbzCCA1egAwIBAgIBATANBgkqhkiG9w0BAQ0FADBKMRgwFgYDVQQDDA9CaXRt +YXNrIFJvb3QgQ0ExEDAOBgNVBAoMB0JpdG1hc2sxHDAaBgNVBAsME2h0dHBzOi8v +Yml0bWFzay5uZXQwHhcNMTIxMTA2MDAwMDAwWhcNMjIxMTA2MDAwMDAwWjBKMRgw +FgYDVQQDDA9CaXRtYXNrIFJvb3QgQ0ExEDAOBgNVBAoMB0JpdG1hc2sxHDAaBgNV +BAsME2h0dHBzOi8vYml0bWFzay5uZXQwggIiMA0GCSqGSIb3DQEBAQUAA4ICDwAw +ggIKAoICAQC1eV4YvayaU+maJbWrD4OHo3d7S1BtDlcvkIRS1Fw3iYDjsyDkZxai +dHp4EUasfNQ+EVtXUvtk6170EmLco6Elg8SJBQ27trE6nielPRPCfX3fQzETRfvB +7tNvGw4Jn2YKiYoMD79kkjgyZjkJ2r/bEHUSevmR09BRp86syHZerdNGpXYhcQ84 +CA1+V+603GFIHnrP+uQDdssW93rgDNYu+exT+Wj6STfnUkugyjmPRPjL7wh0tzy+ +znCeLl4xiV3g9sjPnc7r2EQKd5uaTe3j71sDPF92KRk0SSUndREz+B1+Dbe/RGk4 +MEqGFuOzrtsgEhPIX0hplhb0Tgz/rtug+yTT7oJjBa3u20AAOQ38/M99EfdeJvc4 +lPFF1XBBLh6X9UKF72an2NuANiX6XPySnJgZ7nZ09RiYZqVwu/qt3DfvLfhboq+0 +bQvLUPXrVDr70onv5UDjpmEA/cLmaIqqrduuTkFZOym65/PfAPvpGnt7crQj/Ibl +DEDYZQmP7AS+6zBjoOzNjUGE5r40zWAR1RSi7zliXTu+yfsjXUIhUAWmYR6J3KxB +lfsiHBQ+8dn9kC3YrUexWoOqBiqJOAJzZh5Y1tqgzfh+2nmHSB2dsQRs7rDRRlyy +YMbkpzL9ZsOUO2eTP1mmar6YjCN+rggYjRrX71K2SpBG6b1zZxOG+wIDAQABo2Aw +XjAdBgNVHQ4EFgQUuYGDLL2sswnYpHHvProt1JU+D48wDgYDVR0PAQH/BAQDAgIE +MAwGA1UdEwQFMAMBAf8wHwYDVR0jBBgwFoAUuYGDLL2sswnYpHHvProt1JU+D48w +DQYJKoZIhvcNAQENBQADggIBADeG67vaFcbITGpi51264kHPYPEWaXUa5XYbtmBl +cXYyB6hY5hv/YNuVGJ1gWsDmdeXEyj0j2icGQjYdHRfwhrbEri+h1EZOm1cSBDuY +k/P5+ctHyOXx8IE79DBsZ6IL61UKIaKhqZBfLGYcWu17DVV6+LT+AKtHhOrv3TSj +RnAcKnCbKqXLhUPXpK0eTjPYS2zQGQGIhIy9sQXVXJJJsGrPgMxna1Xw2JikBOCG +htD/JKwt6xBmNwktH0GI/LVtVgSp82Clbn9C4eZN9E5YbVYjLkIEDhpByeC71QhX +EIQ0ZR56bFuJA/CwValBqV/G9gscTPQqd+iETp8yrFpAVHOW+YzSFbxjTEkBte1J +aF0vmbqdMAWLk+LEFPQRptZh0B88igtx6tV5oVd+p5IVRM49poLhuPNJGPvMj99l +mlZ4+AeRUnbOOeAEuvpLJbel4rhwFzmUiGoeTVoPZyMevWcVFq6BMkS+jRR2w0jK +G6b0v5XDHlcFYPOgUrtsOBFJVwbutLvxdk6q37kIFnWCd8L3kmES5q4wjyFK47Co +Ja8zlx64jmMZPg/t3wWqkZgXZ14qnbyG5/lGsj5CwVtfDljrhN0oCWK1FZaUmW3d +69db12/g4f6phldhxiWuGC/W6fCW5kre7nmhshcltqAJJuU47iX+DarBFiIj816e +yV8e +-----END CERTIFICATE-----
\ No newline at end of file diff --git a/app/src/test/resources/preconfigured/riseup.net.json b/app/src/test/resources/preconfigured/riseup.net.json new file mode 100644 index 00000000..9a5ec79e --- /dev/null +++ b/app/src/test/resources/preconfigured/riseup.net.json @@ -0,0 +1,37 @@ +{ + "api_uri": "https://api.black.riseup.net:443", + "api_version": "1", + "ca_cert_fingerprint": "SHA256: a5244308a1374709a9afce95e3ae47c1b44bc2398c0a70ccbf8b3a8a97f29494", + "ca_cert_uri": "https://black.riseup.net/ca.crt", + "default_language": "en", + "description": { + "en": "Riseup is a non-profit collective in Seattle that provides online communication tools for people and groups working toward liberatory social change." + }, + "domain": "riseup.net", + "enrollment_policy": "open", + "languages": [ + "en" + ], + "name": { + "en": "Riseup Networks" + }, + "service": { + "allow_anonymous": false, + "allow_free": true, + "allow_limited_bandwidth": false, + "allow_paid": false, + "allow_registration": true, + "allow_unlimited_bandwidth": true, + "bandwidth_limit": 102400, + "default_service_level": 1, + "levels": { + "1": { + "description": "Please donate.", + "name": "free" + } + } + }, + "services": [ + "openvpn" + ] +}
\ No newline at end of file diff --git a/app/src/test/resources/preconfigured/riseup.net.pem b/app/src/test/resources/preconfigured/riseup.net.pem new file mode 100644 index 00000000..c890aff4 --- /dev/null +++ b/app/src/test/resources/preconfigured/riseup.net.pem @@ -0,0 +1,32 @@ +-----BEGIN CERTIFICATE----- +MIIFjTCCA3WgAwIBAgIBATANBgkqhkiG9w0BAQ0FADBZMRgwFgYDVQQKDA9SaXNl +dXAgTmV0d29ya3MxGzAZBgNVBAsMEmh0dHBzOi8vcmlzZXVwLm5ldDEgMB4GA1UE +AwwXUmlzZXVwIE5ldHdvcmtzIFJvb3QgQ0EwHhcNMTQwNDI4MDAwMDAwWhcNMjQw +NDI4MDAwMDAwWjBZMRgwFgYDVQQKDA9SaXNldXAgTmV0d29ya3MxGzAZBgNVBAsM +Emh0dHBzOi8vcmlzZXVwLm5ldDEgMB4GA1UEAwwXUmlzZXVwIE5ldHdvcmtzIFJv +b3QgQ0EwggIiMA0GCSqGSIb3DQEBAQUAA4ICDwAwggIKAoICAQC76J4ciMJ8Sg0m +TP7DF2DT9zNe0Csk4myoMFC57rfJeqsAlJCv1XMzBmXrw8wq/9z7XHv6n/0sWU7a +7cF2hLR33ktjwODlx7vorU39/lXLndo492ZBhXQtG1INMShyv+nlmzO6GT7ESfNE +LliFitEzwIegpMqxCIHXFuobGSCWF4N0qLHkq/SYUMoOJ96O3hmPSl1kFDRMtWXY +iw1SEKjUvpyDJpVs3NGxeLCaA7bAWhDY5s5Yb2fA1o8ICAqhowurowJpW7n5ZuLK +5VNTlNy6nZpkjt1QycYvNycffyPOFm/Q/RKDlvnorJIrihPkyniV3YY5cGgP+Qkx +HUOT0uLA6LHtzfiyaOqkXwc4b0ZcQD5Vbf6Prd20Ppt6ei0zazkUPwxld3hgyw58 +m/4UIjG3PInWTNf293GngK2Bnz8Qx9e/6TueMSAn/3JBLem56E0WtmbLVjvko+LF +PM5xA+m0BmuSJtrD1MUCXMhqYTtiOvgLBlUm5zkNxALzG+cXB28k6XikXt6MRG7q +hzIPG38zwkooM55yy5i1YfcIi5NjMH6A+t4IJxxwb67MSb6UFOwg5kFokdONZcwj +shczHdG9gLKSBIvrKa03Nd3W2dF9hMbRu//STcQxOailDBQCnXXfAATj9pYzdY4k +ha8VCAREGAKTDAex9oXf1yRuktES4QIDAQABo2AwXjAdBgNVHQ4EFgQUC4tdmLVu +f9hwfK4AGliaet5KkcgwDgYDVR0PAQH/BAQDAgIEMAwGA1UdEwQFMAMBAf8wHwYD +VR0jBBgwFoAUC4tdmLVuf9hwfK4AGliaet5KkcgwDQYJKoZIhvcNAQENBQADggIB +AGzL+GRnYu99zFoy0bXJKOGCF5XUXP/3gIXPRDqQf5g7Cu/jYMID9dB3No4Zmf7v +qHjiSXiS8jx1j/6/Luk6PpFbT7QYm4QLs1f4BlfZOti2KE8r7KRDPIecUsUXW6P/ +3GJAVYH/+7OjA39za9AieM7+H5BELGccGrM5wfl7JeEz8in+V2ZWDzHQO4hMkiTQ +4ZckuaL201F68YpiItBNnJ9N5nHr1MRiGyApHmLXY/wvlrOpclh95qn+lG6/2jk7 +3AmihLOKYMlPwPakJg4PYczm3icFLgTpjV5sq2md9bRyAg3oPGfAuWHmKj2Ikqch +Td5CHKGxEEWbGUWEMP0s1A/JHWiCbDigc4Cfxhy56CWG4q0tYtnc2GMw8OAUO6Wf +Xu5pYKNkzKSEtT/MrNJt44tTZWbKV/Pi/N2Fx36my7TgTUj7g3xcE9eF4JV2H/sg +tsK3pwE0FEqGnT4qMFbixQmc8bGyuakr23wjMvfO7eZUxBuWYR2SkcP26sozF9PF +tGhbZHQVGZUTVPyvwahMUEhbPGVerOW0IYpxkm0x/eaWdTc4vPpf/rIlgbAjarnJ +UN9SaWRlWKSdP4haujnzCoJbM7dU9bjvlGZNyXEekgeT0W2qFeGGp+yyUWw8tNsp +0BuC1b7uW/bBn/xKm319wXVDvBgZgcktMolak39V7DVO +-----END CERTIFICATE-----
\ No newline at end of file diff --git a/app/src/test/resources/preconfigured/urls/calyx.net.url b/app/src/test/resources/preconfigured/urls/calyx.net.url new file mode 100644 index 00000000..807e9e18 --- /dev/null +++ b/app/src/test/resources/preconfigured/urls/calyx.net.url @@ -0,0 +1,3 @@ +{ + "main_url" : "https://calyx.net" +} diff --git a/app/src/test/resources/preconfigured/urls/demo.bitmask.net.url b/app/src/test/resources/preconfigured/urls/demo.bitmask.net.url new file mode 100644 index 00000000..0c4de648 --- /dev/null +++ b/app/src/test/resources/preconfigured/urls/demo.bitmask.net.url @@ -0,0 +1,3 @@ +{
+ "main_url" : "https://demo.bitmask.net"
+}
diff --git a/app/src/test/resources/preconfigured/urls/riseup.net.url b/app/src/test/resources/preconfigured/urls/riseup.net.url new file mode 100644 index 00000000..42cdb979 --- /dev/null +++ b/app/src/test/resources/preconfigured/urls/riseup.net.url @@ -0,0 +1,3 @@ +{ + "main_url" : "https://riseup.net" +} diff --git a/ics-openvpn b/ics-openvpn -Subproject 984e58fea146fff53d2348d869ca4e1076cb9c9 +Subproject a727180b24969f7320c562925dabf27afd57c40 |