diff options
31 files changed, 367 insertions, 359 deletions
diff --git a/app/build.gradle b/app/build.gradle index 68db8926..286ddc1c 100644 --- a/app/build.gradle +++ b/app/build.gradle @@ -37,8 +37,10 @@ android { buildConfigField 'int', 'donation_reminder_duration', '30' //skip the account creation / login screen if the provider offers anonymous vpn usage, use directly the anonymous cert instead buildConfigField 'boolean', 'priotize_anonymous_usage', 'false' - //ignore the following config, only used in custom flavor + //ignore the following configs, only used in custom flavor buildConfigField "String", "customProviderUrl", '""' + buildConfigField "String", "customProviderIp", '""' + buildConfigField "String", "customProviderApiIp", '""' testInstrumentationRunner "android.support.test.runner.AndroidJUnitRunner" dexOptions { @@ -89,6 +91,12 @@ android { //Provider base url, e.g. '"https://example.com"' def customProviderUrl = '"https://riseup.net"' buildConfigField "String", "customProviderUrl", customProviderUrl + //static ip address of provider, using a commercially validated CA certificate to serve the provider.json + def customProviderIp = '"198.252.153.70"' + buildConfigField "String", "customProviderIp", customProviderIp + //static ip address of the provider api, using a self signed certificate to serve provider.json, eip-service.json etc. + def customProviderApiIp = '"198.252.153.107"' + buildConfigField "String", "customProviderApiIp", customProviderApiIp //Change the versionCode as needed //versionCode 1 //Change the versionName as needed diff --git a/app/src/insecure/java/se/leap/bitmaskclient/AddProviderActivity.java b/app/src/insecure/java/se/leap/bitmaskclient/AddProviderActivity.java index 10608a14..102a72c3 100644 --- a/app/src/insecure/java/se/leap/bitmaskclient/AddProviderActivity.java +++ b/app/src/insecure/java/se/leap/bitmaskclient/AddProviderActivity.java @@ -9,10 +9,10 @@ import android.widget.RelativeLayout; import butterknife.InjectView; import butterknife.Optional; -import se.leap.bitmaskclient.ProviderListContent.ProviderItem; import static android.widget.RelativeLayout.BELOW; import static android.widget.RelativeLayout.LEFT_OF; +import static se.leap.bitmaskclient.Constants.DANGER_ON; public class AddProviderActivity extends AddProviderBaseActivity { @@ -36,14 +36,14 @@ public class AddProviderActivity extends AddProviderBaseActivity { checkboxDanger.setVisibility(View.VISIBLE); checkboxDanger.setText(R.string.danger_checkbox); - checkboxDanger.setChecked(preferences.getBoolean(ProviderItem.DANGER_ON, false)); + checkboxDanger.setChecked(preferences.getBoolean(DANGER_ON, false)); } @Override public void setupSaveButton() { saveButton.setOnClickListener(new View.OnClickListener() { public void onClick(View v) { - preferences.edit().putBoolean(ProviderItem.DANGER_ON, checkboxDanger.isChecked()).apply(); + preferences.edit().putBoolean(DANGER_ON, checkboxDanger.isChecked()).apply(); saveProvider(); } }); diff --git a/app/src/insecure/java/se/leap/bitmaskclient/ProviderApiManager.java b/app/src/insecure/java/se/leap/bitmaskclient/ProviderApiManager.java index fc91d7e4..e86ab8ea 100644 --- a/app/src/insecure/java/se/leap/bitmaskclient/ProviderApiManager.java +++ b/app/src/insecure/java/se/leap/bitmaskclient/ProviderApiManager.java @@ -50,6 +50,7 @@ import se.leap.bitmaskclient.utils.ConfigHelper; import static android.text.TextUtils.isEmpty; import static se.leap.bitmaskclient.Constants.BROADCAST_RESULT_KEY; +import static se.leap.bitmaskclient.Constants.DANGER_ON; import static se.leap.bitmaskclient.Constants.PROVIDER_KEY; import static se.leap.bitmaskclient.Constants.PROVIDER_VPN_CERTIFICATE; import static se.leap.bitmaskclient.ProviderAPI.ERRORS; @@ -94,7 +95,7 @@ public class ProviderApiManager extends ProviderApiManagerBase { Bundle currentDownload = new Bundle(); if (task != null) { - lastDangerOn = task.containsKey(ProviderListContent.ProviderItem.DANGER_ON) && task.getBoolean(ProviderListContent.ProviderItem.DANGER_ON); + lastDangerOn = task.containsKey(DANGER_ON) && task.getBoolean(DANGER_ON); } if (isEmpty(provider.getMainUrlString()) || provider.getMainUrl().isDefault()) { diff --git a/app/src/insecure/java/se/leap/bitmaskclient/ProviderDetailActivity.java b/app/src/insecure/java/se/leap/bitmaskclient/ProviderDetailActivity.java index cf9ee5f5..9f2fa284 100644 --- a/app/src/insecure/java/se/leap/bitmaskclient/ProviderDetailActivity.java +++ b/app/src/insecure/java/se/leap/bitmaskclient/ProviderDetailActivity.java @@ -7,7 +7,7 @@ public class ProviderDetailActivity extends AbstractProviderDetailActivity { @Override public void onBackPressed() { SharedPreferences.Editor editor = preferences.edit(); - editor.remove(ProviderListContent.ProviderItem.DANGER_ON).apply(); + editor.remove(Constants.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 9107e641..dfadaf05 100644 --- a/app/src/insecure/java/se/leap/bitmaskclient/ProviderListActivity.java +++ b/app/src/insecure/java/se/leap/bitmaskclient/ProviderListActivity.java @@ -18,14 +18,8 @@ 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; - -import java.net.MalformedURLException; -import java.net.URL; - -import se.leap.bitmaskclient.ProviderListContent.ProviderItem; +import static se.leap.bitmaskclient.Constants.DANGER_ON; import static se.leap.bitmaskclient.ProviderAPI.SET_UP_PROVIDER; import static se.leap.bitmaskclient.ProviderSetupInterface.ProviderConfigState.SETTING_UP_PROVIDER; @@ -41,14 +35,14 @@ public class ProviderListActivity extends ProviderListBaseActivity { @Override protected void onItemSelectedLogic() { - boolean danger_on = preferences.getBoolean(ProviderItem.DANGER_ON, true); + boolean danger_on = preferences.getBoolean(DANGER_ON, true); setUpProvider(danger_on); } @Override public void cancelSettingUpProvider() { super.cancelSettingUpProvider(); - preferences.edit().remove(ProviderItem.DANGER_ON).apply(); + preferences.edit().remove(DANGER_ON).apply(); } /** @@ -60,7 +54,7 @@ public class ProviderListActivity extends ProviderListBaseActivity { providerConfigState = SETTING_UP_PROVIDER; Bundle parameters = new Bundle(); - parameters.putBoolean(ProviderItem.DANGER_ON, danger_on); + parameters.putBoolean(DANGER_ON, danger_on); ProviderAPICommand.execute(this, SET_UP_PROVIDER, parameters, provider); } diff --git a/app/src/insecure/java/se/leap/bitmaskclient/ProviderListContent.java b/app/src/insecure/java/se/leap/bitmaskclient/ProviderListContent.java deleted file mode 100644 index 88e31c9a..00000000 --- a/app/src/insecure/java/se/leap/bitmaskclient/ProviderListContent.java +++ /dev/null @@ -1,82 +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 <http://www.gnu.org/licenses/>. - */ -package se.leap.bitmaskclient; - -import java.util.*; -import java.net.*; - -/** - * Models the provider list shown in the ProviderListActivity. - * - * @author parmegv - */ -public class ProviderListContent { - - public static List<ProviderItem> ITEMS = new ArrayList<ProviderItem>(); - - public static Map<String, ProviderItem> ITEM_MAP = new HashMap<String, ProviderItem>(); - - /** - * Adds a new provider item to the end of the items map, and to the items list. - * - * @param item - */ - public static void addItem(ProviderItem item) { - ITEMS.add(item); - ITEM_MAP.put(String.valueOf(ITEMS.size()), item); - } - - public static void removeItem(ProviderItem item) { - ITEMS.remove(item); - ITEM_MAP.remove(item); - } - - /** - * A provider item. - */ - public static class ProviderItem { - final public static String CUSTOM = "custom"; - final public static String DANGER_ON = "danger_on"; - private String provider_main_url; - private String name; - - /** - * @param name of the provider - * @param provider_main_url used to download provider.json file of the provider - */ - public ProviderItem(String name, String provider_main_url) { - this.name = name; - this.provider_main_url = provider_main_url; - } - - public String name() { - return name; - } - - public String providerMainUrl() { - return provider_main_url; - } - - public String domain() { - try { - return new URL(provider_main_url).getHost(); - } catch (MalformedURLException e) { - return provider_main_url.replaceFirst("http[s]?://", "").replaceFirst("/.*", ""); - } - } - } -} diff --git a/app/src/main/java/se/leap/bitmaskclient/Constants.java b/app/src/main/java/se/leap/bitmaskclient/Constants.java index 0cbf82e1..5ed28806 100644 --- a/app/src/main/java/se/leap/bitmaskclient/Constants.java +++ b/app/src/main/java/se/leap/bitmaskclient/Constants.java @@ -37,6 +37,8 @@ public interface Constants { String APP_ACTION_CONFIGURE_ALWAYS_ON_PROFILE = "configure always-on profile"; String DEFAULT_BITMASK = "normal"; String CUSTOM_BITMASK = "custom"; + String DANGER_ON = "danger_on"; + String ASK_TO_CANCEL_VPN = "ask_to_cancel_vpn"; diff --git a/app/src/main/java/se/leap/bitmaskclient/CustomProviderSetupActivity.java b/app/src/main/java/se/leap/bitmaskclient/CustomProviderSetupActivity.java index 3763f506..b3ee44ca 100644 --- a/app/src/main/java/se/leap/bitmaskclient/CustomProviderSetupActivity.java +++ b/app/src/main/java/se/leap/bitmaskclient/CustomProviderSetupActivity.java @@ -37,7 +37,7 @@ public class CustomProviderSetupActivity extends ProviderSetupBaseActivity { super.onCreate(savedInstanceState); setUpInitialUI(); restoreState(savedInstanceState); - setProvider(new Provider(BuildConfig.customProviderUrl)); + setProvider(new Provider(BuildConfig.customProviderUrl, BuildConfig.customProviderIp, BuildConfig.customProviderApiIp)); } @Override diff --git a/app/src/main/java/se/leap/bitmaskclient/DnsResolver.java b/app/src/main/java/se/leap/bitmaskclient/DnsResolver.java new file mode 100644 index 00000000..92f70492 --- /dev/null +++ b/app/src/main/java/se/leap/bitmaskclient/DnsResolver.java @@ -0,0 +1,37 @@ +package se.leap.bitmaskclient; + +import org.jetbrains.annotations.NotNull; + +import java.net.InetAddress; +import java.net.UnknownHostException; +import java.util.ArrayList; +import java.util.List; + +import okhttp3.Dns; +import se.leap.bitmaskclient.utils.IPAddress; + +class DnsResolver implements Dns { + + @Override + public List<InetAddress> lookup(@NotNull String hostname) throws UnknownHostException { + try { + return Dns.SYSTEM.lookup(hostname); + } catch (UnknownHostException e) { + ProviderObservable observable = ProviderObservable.getInstance(); + Provider currentProvider; + if (observable.getProviderForDns() != null) { + currentProvider = observable.getProviderForDns(); + } else { + currentProvider = observable.getCurrentProvider(); + } + String ip = currentProvider.getIpForHostname(hostname); + if (!ip.isEmpty()) { + ArrayList<InetAddress> addresses = new ArrayList<>(); + addresses.add(InetAddress.getByAddress(hostname, IPAddress.asBytes(ip))); + return addresses; + } else { + throw new UnknownHostException("Hostname " + hostname + " not found"); + } + } + } +} diff --git a/app/src/main/java/se/leap/bitmaskclient/EipSetupObserver.java b/app/src/main/java/se/leap/bitmaskclient/EipSetupObserver.java index eceba0db..74f132b9 100644 --- a/app/src/main/java/se/leap/bitmaskclient/EipSetupObserver.java +++ b/app/src/main/java/se/leap/bitmaskclient/EipSetupObserver.java @@ -28,7 +28,6 @@ import se.leap.bitmaskclient.eip.GatewaysManager; import se.leap.bitmaskclient.utils.PreferenceHelper; import static android.app.Activity.RESULT_CANCELED; -import static android.content.Context.MODE_PRIVATE; import static android.content.Intent.CATEGORY_DEFAULT; import static de.blinkt.openvpn.core.ConnectionStatus.LEVEL_CONNECTING_NO_SERVER_REPLY_YET; import static de.blinkt.openvpn.core.ConnectionStatus.LEVEL_NOTCONNECTED; @@ -43,11 +42,9 @@ import static se.leap.bitmaskclient.Constants.EIP_ACTION_START_ALWAYS_ON_VPN; import static se.leap.bitmaskclient.Constants.EIP_REQUEST; import static se.leap.bitmaskclient.Constants.PROVIDER_KEY; import static se.leap.bitmaskclient.Constants.PROVIDER_PROFILE; -import static se.leap.bitmaskclient.Constants.SHARED_PREFERENCES; import static se.leap.bitmaskclient.ProviderAPI.CORRECTLY_DOWNLOADED_EIP_SERVICE; import static se.leap.bitmaskclient.ProviderAPI.CORRECTLY_UPDATED_INVALID_VPN_CERTIFICATE; -import static se.leap.bitmaskclient.ProviderAPI.ERRORS; -import static se.leap.bitmaskclient.utils.PreferenceHelper.getSavedProviderFromSharedPreferences; +import static se.leap.bitmaskclient.ProviderAPI.PROVIDER_NOK; /** * Created by cyberta on 05.12.18. diff --git a/app/src/main/java/se/leap/bitmaskclient/OkHttpClientGenerator.java b/app/src/main/java/se/leap/bitmaskclient/OkHttpClientGenerator.java index 69270140..9d1168aa 100644 --- a/app/src/main/java/se/leap/bitmaskclient/OkHttpClientGenerator.java +++ b/app/src/main/java/se/leap/bitmaskclient/OkHttpClientGenerator.java @@ -88,6 +88,7 @@ public class OkHttpClientGenerator { sslCompatFactory.initSSLSocketFactory(clientBuilder); clientBuilder.cookieJar(getCookieJar()) .connectionSpecs(Collections.singletonList(spec)); + clientBuilder.dns(new DnsResolver()); return clientBuilder.build(); } catch (IllegalArgumentException e) { e.printStackTrace(); diff --git a/app/src/main/java/se/leap/bitmaskclient/Provider.java b/app/src/main/java/se/leap/bitmaskclient/Provider.java index b98c3fd3..11d685f5 100644 --- a/app/src/main/java/se/leap/bitmaskclient/Provider.java +++ b/app/src/main/java/se/leap/bitmaskclient/Provider.java @@ -18,6 +18,7 @@ package se.leap.bitmaskclient; import android.os.Parcel; import android.os.Parcelable; +import android.support.annotation.NonNull; import com.google.gson.Gson; @@ -29,6 +30,8 @@ import java.net.MalformedURLException; import java.net.URL; import java.util.Locale; +import se.leap.bitmaskclient.utils.IPAddress; + import static de.blinkt.openvpn.core.connection.Connection.TransportType.OBFS4; import static se.leap.bitmaskclient.Constants.CAPABILITIES; import static se.leap.bitmaskclient.Constants.GATEWAYS; @@ -49,6 +52,8 @@ public final class Provider implements Parcelable { private JSONObject eipServiceJson = new JSONObject(); private DefaultedURL mainUrl = new DefaultedURL(); private DefaultedURL apiUrl = new DefaultedURL(); + private String providerIp = ""; + private String providerApiIp = ""; private String certificatePin = ""; private String certificatePinEncoding = ""; private String caCert = ""; @@ -73,7 +78,9 @@ public final class Provider implements Parcelable { NAME = "name", DESCRIPTION = "description", DOMAIN = "domain", - MAIN_URL = "main_url"; + MAIN_URL = "main_url", + PROVIDER_IP = "provider_ip", + PROVIDER_API_IP = "provider_api_ip"; private static final String API_TERM_NAME = "name"; @@ -87,12 +94,32 @@ public final class Provider implements Parcelable { } } - public Provider(URL mainUrl) { - this.mainUrl.setUrl(mainUrl); + public Provider(String mainUrl, String providerIp, String providerApiIp) { + try { + this.mainUrl.setUrl(new URL(mainUrl)); + if (providerIp != null) { + this.providerIp = providerIp; + } + if (providerApiIp != null) { + this.providerApiIp = providerApiIp; + } + } catch (MalformedURLException e) { + e.printStackTrace(); + } } - public Provider(URL mainUrl, String caCert, String definition) { - this.mainUrl.setUrl(mainUrl); + public Provider(String mainUrl, String providerIp, String providerApiIp, String caCert, String definition) { + try { + this.mainUrl.setUrl(new URL(mainUrl)); + } catch (MalformedURLException e) { + e.printStackTrace(); + } + if (this.providerIp != null) { + this.providerIp = providerIp; + } + if (this.providerApiIp != null) { + this.providerApiIp = providerApiIp; + } if (caCert != null) { this.caCert = caCert; } @@ -146,6 +173,35 @@ public final class Provider implements Parcelable { return false; } + public String getIpForHostname(String host) { + if (host != null) { + if (host.equals(mainUrl.getUrl().getHost())) { + return providerIp; + } else if (host.equals(apiUrl.getUrl().getHost())) { + return providerApiIp; + } + } + return ""; + } + + public String getProviderApiIp() { + return this.providerApiIp; + } + + public void setProviderApiIp(String providerApiIp) { + if (providerApiIp == null) return; + this.providerApiIp = providerApiIp; + } + + public void setProviderIp(String providerIp) { + if (providerIp == null) return; + this.providerIp = providerIp; + } + + public String getProviderIp() { + return this.providerIp; + } + public void setMainUrl(URL url) { mainUrl.setUrl(url); } @@ -192,7 +248,7 @@ public final class Provider implements Parcelable { } - protected String getApiUrlString() { + public String getApiUrlString() { return getApiUrl().toString(); } @@ -265,6 +321,8 @@ public final class Provider implements Parcelable { @Override public void writeToParcel(Parcel parcel, int i) { parcel.writeString(getMainUrlString()); + parcel.writeString(getProviderIp()); + parcel.writeString(getProviderApiIp()); parcel.writeString(getDefinitionString()); parcel.writeString(getCaCert()); parcel.writeString(getEipServiceJsonString()); @@ -281,6 +339,8 @@ public final class Provider implements Parcelable { definition.toString().equals(p.getDefinition().toString()) && eipServiceJson.toString().equals(p.getEipServiceJson().toString())&& mainUrl.equals(p.getMainUrl()) && + providerIp.equals(p.getProviderIp()) && + providerApiIp.equals(p.getProviderApiIp()) && apiUrl.equals(p.getApiUrl()) && certificatePin.equals(p.getCertificatePin()) && certificatePinEncoding.equals(p.getCertificatePinEncoding()) && @@ -298,7 +358,6 @@ public final class Provider implements Parcelable { JSONObject json = new JSONObject(); try { json.put(Provider.MAIN_URL, mainUrl); - //TODO: add other fields here? } catch (JSONException e) { e.printStackTrace(); } @@ -321,6 +380,14 @@ public final class Provider implements Parcelable { mainUrl.setUrl(new URL(in.readString())); String tmpString = in.readString(); if (!tmpString.isEmpty()) { + providerIp = tmpString; + } + tmpString = in.readString(); + if (!tmpString.isEmpty()) { + providerApiIp = tmpString; + } + tmpString = in.readString(); + if (!tmpString.isEmpty()) { definition = new JSONObject((tmpString)); parseDefinition(definition); } @@ -445,7 +512,7 @@ public final class Provider implements Parcelable { } /** - * resets everything except the main url + * resets everything except the main url and the providerIp */ public void reset() { definition = new JSONObject(); diff --git a/app/src/main/java/se/leap/bitmaskclient/ProviderApiManagerBase.java b/app/src/main/java/se/leap/bitmaskclient/ProviderApiManagerBase.java index 0baa4e0d..7577f098 100644 --- a/app/src/main/java/se/leap/bitmaskclient/ProviderApiManagerBase.java +++ b/app/src/main/java/se/leap/bitmaskclient/ProviderApiManagerBase.java @@ -63,6 +63,9 @@ 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.Provider.CA_CERT; +import static se.leap.bitmaskclient.Provider.PROVIDER_API_IP; +import static se.leap.bitmaskclient.Provider.PROVIDER_IP; import static se.leap.bitmaskclient.ProviderAPI.BACKEND_ERROR_KEY; import static se.leap.bitmaskclient.ProviderAPI.BACKEND_ERROR_MESSAGE; import static se.leap.bitmaskclient.ProviderAPI.CORRECTLY_DOWNLOADED_EIP_SERVICE; @@ -159,6 +162,7 @@ public abstract class ProviderApiManagerBase { Bundle result = new Bundle(); switch (action) { case UPDATE_PROVIDER_DETAILS: + ProviderObservable.getInstance().setProviderForDns(provider); resetProviderDetails(provider); Bundle task = new Bundle(); result = setUpProvider(provider, task); @@ -167,14 +171,17 @@ public abstract class ProviderApiManagerBase { } else { sendToReceiverOrBroadcast(receiver, PROVIDER_NOK, result, provider); } + ProviderObservable.getInstance().setProviderForDns(null); break; case SET_UP_PROVIDER: + ProviderObservable.getInstance().setProviderForDns(provider); result = setUpProvider(provider, parameters); if (result.getBoolean(BROADCAST_RESULT_KEY)) { sendToReceiverOrBroadcast(receiver, PROVIDER_OK, result, provider); } else { sendToReceiverOrBroadcast(receiver, PROVIDER_NOK, result, provider); } + ProviderObservable.getInstance().setProviderForDns(null); break; case SIGN_UP: result = tryToRegister(provider, parameters); @@ -200,22 +207,27 @@ public abstract class ProviderApiManagerBase { } break; case DOWNLOAD_VPN_CERTIFICATE: + ProviderObservable.getInstance().setProviderForDns(provider); result = updateVpnCertificate(provider); if (result.getBoolean(BROADCAST_RESULT_KEY)) { sendToReceiverOrBroadcast(receiver, CORRECTLY_DOWNLOADED_VPN_CERTIFICATE, result, provider); } else { sendToReceiverOrBroadcast(receiver, INCORRECTLY_DOWNLOADED_VPN_CERTIFICATE, result, provider); } + ProviderObservable.getInstance().setProviderForDns(null); break; case UPDATE_INVALID_VPN_CERTIFICATE: + ProviderObservable.getInstance().setProviderForDns(provider); result = updateVpnCertificate(provider); if (result.getBoolean(BROADCAST_RESULT_KEY)) { sendToReceiverOrBroadcast(receiver, CORRECTLY_UPDATED_INVALID_VPN_CERTIFICATE, result, provider); } else { sendToReceiverOrBroadcast(receiver, INCORRECTLY_UPDATED_INVALID_VPN_CERTIFICATE, result, provider); } + ProviderObservable.getInstance().setProviderForDns(null); break; case DOWNLOAD_SERVICE_JSON: + ProviderObservable.getInstance().setProviderForDns(provider); Log.d(TAG, "update eip service json"); result = getAndSetEipServiceJson(provider); if (result.getBoolean(BROADCAST_RESULT_KEY)) { @@ -223,6 +235,7 @@ public abstract class ProviderApiManagerBase { } else { sendToReceiverOrBroadcast(receiver, INCORRECTLY_DOWNLOADED_EIP_SERVICE, result, provider); } + ProviderObservable.getInstance().getProviderForDns(); break; case PROVIDER_SET_UP: if(provider.hasEIP() && provider.hasCaCert() && provider.hasDefinition()) { @@ -596,11 +609,11 @@ public abstract class ProviderApiManagerBase { return plainResponseBody; } - private boolean canConnect(String caCert, JSONObject providerDefinition, Bundle result) { + private boolean canConnect(Provider provider, Bundle result) { JSONObject errorJson = new JSONObject(); - String providerUrl = getApiUrl(providerDefinition) + "/provider.json"; + String providerUrl = provider.getApiUrlString() + "/provider.json"; - OkHttpClient okHttpClient = clientGenerator.initSelfSignedCAHttpClient(caCert, errorJson); + OkHttpClient okHttpClient = clientGenerator.initSelfSignedCAHttpClient(provider.getCaCert(), errorJson); if (okHttpClient == null) { result.putString(ERRORS, errorJson.toString()); return false; @@ -693,6 +706,8 @@ public abstract class ProviderApiManagerBase { provider.define(getPersistedProviderDefinition(providerDomain)); provider.setPrivateKey(getPersistedPrivateKey(providerDomain)); provider.setVpnCertificate(getPersistedVPNCertificate(providerDomain)); + provider.setProviderApiIp(getPersistedProviderApiIp(providerDomain)); + provider.setProviderIp(getPersistedProviderIp(providerDomain)); } } @@ -737,7 +752,7 @@ public abstract class ProviderApiManagerBase { return setErrorResult(result, warning_corrupted_provider_cert, ERROR_CERTIFICATE_PINNING.toString()); } - if (!canConnect(caCert, provider.getDefinition(), result)) { + if (!canConnect(provider, result)) { return result; } } catch (NoSuchAlgorithmException e ) { @@ -772,15 +787,6 @@ public abstract class ProviderApiManagerBase { return result; } - protected String getApiUrl(JSONObject providerDefinition) { - try { - return providerDefinition.getString(Provider.API_URL); - } catch (JSONException e) { - e.printStackTrace(); - } - return ""; - } - protected String getPersistedPrivateKey(String providerDomain) { return getFromPersistedProvider(PROVIDER_PRIVATE_KEY, providerDomain, preferences); } @@ -799,11 +805,19 @@ public abstract class ProviderApiManagerBase { } protected String getPersistedProviderCA(String providerDomain) { - return preferences.getString(Provider.CA_CERT + "." + providerDomain, ""); + return getFromPersistedProvider(CA_CERT, providerDomain, preferences); + } + + protected String getPersistedProviderApiIp(String providerDomain) { + return getFromPersistedProvider(PROVIDER_API_IP, providerDomain, preferences); + } + + protected String getPersistedProviderIp(String providerDomain) { + return getFromPersistedProvider(PROVIDER_IP, providerDomain, preferences); } protected boolean hasUpdatedProviderDetails(String domain) { - return preferences.contains(Provider.KEY + "." + domain) && preferences.contains(Provider.CA_CERT + "." + domain); + return preferences.contains(Provider.KEY + "." + domain) && preferences.contains(CA_CERT + "." + domain); } protected String getDomainFromMainURL(String mainUrl) { diff --git a/app/src/main/java/se/leap/bitmaskclient/ProviderApiSetupBroadcastReceiver.java b/app/src/main/java/se/leap/bitmaskclient/ProviderApiSetupBroadcastReceiver.java index e8f9de36..0a2e2538 100644 --- a/app/src/main/java/se/leap/bitmaskclient/ProviderApiSetupBroadcastReceiver.java +++ b/app/src/main/java/se/leap/bitmaskclient/ProviderApiSetupBroadcastReceiver.java @@ -51,7 +51,7 @@ public class ProviderApiSetupBroadcastReceiver extends BroadcastReceiver { if (setupInterface.getConfigState() != null && setupInterface.getConfigState() == ProviderConfigState.SETTING_UP_PROVIDER) { int resultCode = intent.getIntExtra(Constants.BROADCAST_RESULT_CODE, ProviderListBaseActivity.RESULT_CANCELED); - Log.d(ProviderListBaseActivity.TAG, "Broadcast resultCode: " + Integer.toString(resultCode)); + Log.d(ProviderListBaseActivity.TAG, "Broadcast resultCode: " + resultCode); Bundle resultData = intent.getParcelableExtra(Constants.BROADCAST_RESULT_KEY); Provider handledProvider = resultData.getParcelable(Constants.PROVIDER_KEY); diff --git a/app/src/main/java/se/leap/bitmaskclient/ProviderListBaseActivity.java b/app/src/main/java/se/leap/bitmaskclient/ProviderListBaseActivity.java index c8070e18..56edd534 100644 --- a/app/src/main/java/se/leap/bitmaskclient/ProviderListBaseActivity.java +++ b/app/src/main/java/se/leap/bitmaskclient/ProviderListBaseActivity.java @@ -108,12 +108,8 @@ public abstract class ProviderListBaseActivity extends ProviderSetupBaseActivity } public void showAndSelectProvider(String newURL) { - try { - provider = new Provider(new URL((newURL))); - autoSelectProvider(); - } catch (MalformedURLException e) { - e.printStackTrace(); - } + provider = new Provider(newURL, "", ""); + autoSelectProvider(); } private void autoSelectProvider() { diff --git a/app/src/main/java/se/leap/bitmaskclient/ProviderManager.java b/app/src/main/java/se/leap/bitmaskclient/ProviderManager.java index dd9070af..ab165450 100644 --- a/app/src/main/java/se/leap/bitmaskclient/ProviderManager.java +++ b/app/src/main/java/se/leap/bitmaskclient/ProviderManager.java @@ -12,7 +12,6 @@ import java.io.File; import java.io.FileNotFoundException; import java.io.IOException; import java.io.InputStream; -import java.net.MalformedURLException; import java.net.URL; import java.util.ArrayList; import java.util.Collection; @@ -21,6 +20,9 @@ import java.util.Iterator; import java.util.List; import java.util.Set; +import static se.leap.bitmaskclient.Provider.MAIN_URL; +import static se.leap.bitmaskclient.Provider.PROVIDER_API_IP; +import static se.leap.bitmaskclient.Provider.PROVIDER_IP; import static se.leap.bitmaskclient.utils.FileHelper.createFile; import static se.leap.bitmaskclient.utils.FileHelper.persistFile; import static se.leap.bitmaskclient.utils.InputStreamHelper.getInputStreamFrom; @@ -84,22 +86,22 @@ public class ProviderManager implements AdapteeCollection<Provider> { for (String file : relativeFilePaths) { String mainUrl = null; + String providerIp = null; + String providerApiIp = null; String certificate = null; String providerDefinition = null; try { String provider = file.substring(0, file.length() - ".url".length()); - InputStream provider_file = assetsManager.open(directory + "/" + file); - mainUrl = extractMainUrlFromInputStream(provider_file); + InputStream providerFile = assetsManager.open(directory + "/" + file); + mainUrl = extractKeyFromInputStream(providerFile, MAIN_URL); + providerIp = extractKeyFromInputStream(providerFile, PROVIDER_IP); + providerApiIp = extractKeyFromInputStream(providerFile, PROVIDER_API_IP); certificate = loadInputStreamAsString(assetsManager.open(provider + EXT_PEM)); providerDefinition = loadInputStreamAsString(assetsManager.open(provider + EXT_JSON)); } catch (IOException e) { e.printStackTrace(); } - try { - providers.add(new Provider(new URL(mainUrl), certificate, providerDefinition)); - } catch (MalformedURLException e) { - e.printStackTrace(); - } + providers.add(new Provider(mainUrl, providerIp, providerApiIp, certificate, providerDefinition)); } return providers; @@ -118,23 +120,26 @@ public class ProviderManager implements AdapteeCollection<Provider> { Set<Provider> providers = new HashSet<>(); try { for (String file : files) { - String mainUrl = extractMainUrlFromInputStream(getInputStreamFrom(externalFilesDir.getAbsolutePath() + "/" + file)); - providers.add(new Provider(new URL(mainUrl))); + InputStream inputStream = getInputStreamFrom(externalFilesDir.getAbsolutePath() + "/" + file); + String mainUrl = extractKeyFromInputStream(inputStream, MAIN_URL); + String providerIp = extractKeyFromInputStream(inputStream, PROVIDER_IP); + String providerApiIp = extractKeyFromInputStream(inputStream, PROVIDER_API_IP); + providers.add(new Provider(mainUrl, providerIp, providerApiIp)); } - } catch (MalformedURLException | FileNotFoundException | NullPointerException e) { + } catch (FileNotFoundException | NullPointerException e) { e.printStackTrace(); } return providers; } - private String extractMainUrlFromInputStream(InputStream inputStream) { - String mainUrl = ""; + private String extractKeyFromInputStream(InputStream inputStream, String key) { + String value = ""; JSONObject fileContents = inputStreamToJson(inputStream); if (fileContents != null) - mainUrl = fileContents.optString(Provider.MAIN_URL); - return mainUrl; + value = fileContents.optString(key); + return value; } private JSONObject inputStreamToJson(InputStream inputStream) { diff --git a/app/src/main/java/se/leap/bitmaskclient/ProviderObservable.java b/app/src/main/java/se/leap/bitmaskclient/ProviderObservable.java index 776c0e92..50cc37d4 100644 --- a/app/src/main/java/se/leap/bitmaskclient/ProviderObservable.java +++ b/app/src/main/java/se/leap/bitmaskclient/ProviderObservable.java @@ -2,14 +2,13 @@ package se.leap.bitmaskclient; import java.util.Observable; -import se.leap.bitmaskclient.utils.PreferenceHelper; - /** * Created by cyberta on 05.12.18. */ public class ProviderObservable extends Observable { private static ProviderObservable instance; private Provider currentProvider; + private Provider providerForDns; public static ProviderObservable getInstance() { if (instance == null) { @@ -20,6 +19,7 @@ public class ProviderObservable extends Observable { public synchronized void updateProvider(Provider provider) { instance.currentProvider = provider; + instance.providerForDns = null; instance.setChanged(); instance.notifyObservers(); } @@ -28,4 +28,12 @@ public class ProviderObservable extends Observable { return instance.currentProvider; } + public void setProviderForDns(Provider provider) { + this.providerForDns = provider; + } + + public Provider getProviderForDns() { + return instance.providerForDns; + } + } diff --git a/app/src/main/java/se/leap/bitmaskclient/ProviderSetupBaseActivity.java b/app/src/main/java/se/leap/bitmaskclient/ProviderSetupBaseActivity.java index 3b8df0a8..b1bb3b07 100644 --- a/app/src/main/java/se/leap/bitmaskclient/ProviderSetupBaseActivity.java +++ b/app/src/main/java/se/leap/bitmaskclient/ProviderSetupBaseActivity.java @@ -153,6 +153,7 @@ public abstract class ProviderSetupBaseActivity extends ConfigWizardBaseActivity public void cancelSettingUpProvider() { providerConfigState = PROVIDER_NOT_SET; provider = null; + ProviderObservable.getInstance().setProviderForDns(null); hideProgressBar(); } diff --git a/app/src/main/java/se/leap/bitmaskclient/utils/IPAddress.java b/app/src/main/java/se/leap/bitmaskclient/utils/IPAddress.java new file mode 100644 index 00000000..2e3ef596 --- /dev/null +++ b/app/src/main/java/se/leap/bitmaskclient/utils/IPAddress.java @@ -0,0 +1,102 @@ +package se.leap.bitmaskclient.utils; + +/* + * Copyright (C) 2006-2008 Alfresco Software Limited. + * + * 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 2 + * 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, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + + * As a special exception to the terms and conditions of version 2.0 of + * the GPL, you may redistribute this Program in connection with Free/Libre + * and Open Source Software ("FLOSS") applications as described in Alfresco's + * FLOSS exception. You should have recieved a copy of the text describing + * the FLOSS exception, and it is also available here: + * http://www.alfresco.com/legal/licensing" + */ + +import java.util.StringTokenizer; + +/** + * TCP/IP Address Utility Class + * + * @author gkspencer + */ +public class IPAddress { + + + /** + * Convert a TCP/IP address string into a byte array + * + * @param addr String + * @return byte[] + */ + public static byte[] asBytes(String addr) { + + // Convert the TCP/IP address string to an integer value + int ipInt = parseNumericAddress(addr); + if (ipInt == 0) + return null; + + // Convert to bytes + byte[] ipByts = new byte[4]; + + ipByts[3] = (byte) (ipInt & 0xFF); + ipByts[2] = (byte) ((ipInt >> 8) & 0xFF); + ipByts[1] = (byte) ((ipInt >> 16) & 0xFF); + ipByts[0] = (byte) ((ipInt >> 24) & 0xFF); + + // Return the TCP/IP bytes + return ipByts; + } + /** + * Check if the specified address is a valid numeric TCP/IP address and return as an integer value + * + * @param ipaddr String + * @return int + */ + private static int parseNumericAddress(String ipaddr) { + + // Check if the string is valid + if (ipaddr == null || ipaddr.length() < 7 || ipaddr.length() > 15) + return 0; + + // Check the address string, should be n.n.n.n format + StringTokenizer token = new StringTokenizer(ipaddr,"."); + if (token.countTokens() != 4) + return 0; + + int ipInt = 0; + while (token.hasMoreTokens()) { + + // Get the current token and convert to an integer value + String ipNum = token.nextToken(); + + try { + // Validate the current address part + int ipVal = Integer.valueOf(ipNum).intValue(); + if (ipVal < 0 || ipVal > 255) + return 0; + + // Add to the integer address + ipInt = (ipInt << 8) + ipVal; + } + catch (NumberFormatException ex) { + return 0; + } + } + + // Return the integer address + return ipInt; + } +}
\ No newline at end of file diff --git a/app/src/main/java/se/leap/bitmaskclient/utils/PreferenceHelper.java b/app/src/main/java/se/leap/bitmaskclient/utils/PreferenceHelper.java index 40bb2eca..de2058c7 100644 --- a/app/src/main/java/se/leap/bitmaskclient/utils/PreferenceHelper.java +++ b/app/src/main/java/se/leap/bitmaskclient/utils/PreferenceHelper.java @@ -2,7 +2,6 @@ package se.leap.bitmaskclient.utils; import android.content.Context; import android.content.SharedPreferences; -import android.preference.PreferenceManager; import android.support.annotation.NonNull; import android.support.annotation.Nullable; @@ -24,6 +23,7 @@ import se.leap.bitmaskclient.Provider; import static android.content.Context.MODE_PRIVATE; import static se.leap.bitmaskclient.Constants.ALWAYS_ON_SHOW_DIALOG; import static se.leap.bitmaskclient.Constants.DEFAULT_SHARED_PREFS_BATTERY_SAVER; +import static se.leap.bitmaskclient.Constants.EXCLUDED_APPS; import static se.leap.bitmaskclient.Constants.LAST_USED_PROFILE; import static se.leap.bitmaskclient.Constants.PREFERENCES_APP_VERSION; import static se.leap.bitmaskclient.Constants.PROVIDER_CONFIGURED; @@ -33,7 +33,6 @@ import static se.leap.bitmaskclient.Constants.PROVIDER_VPN_CERTIFICATE; import static se.leap.bitmaskclient.Constants.SHARED_PREFERENCES; import static se.leap.bitmaskclient.Constants.SU_PERMISSION; import static se.leap.bitmaskclient.Constants.USE_PLUGGABLE_TRANSPORTS; -import static se.leap.bitmaskclient.Constants.EXCLUDED_APPS; /** * Created by cyberta on 18.03.18. @@ -48,6 +47,8 @@ public class PreferenceHelper { Provider provider = new Provider(); try { provider.setMainUrl(new URL(preferences.getString(Provider.MAIN_URL, ""))); + provider.setProviderIp(preferences.getString(Provider.PROVIDER_IP, "")); + provider.setProviderApiIp(preferences.getString(Provider.PROVIDER_API_IP, "")); provider.define(new JSONObject(preferences.getString(Provider.KEY, ""))); provider.setCaCert(preferences.getString(Provider.CA_CERT, "")); provider.setVpnCertificate(preferences.getString(PROVIDER_VPN_CERTIFICATE, "")); @@ -64,73 +65,12 @@ public class PreferenceHelper { return preferences.getString(toFetch + "." + providerDomain, ""); } - public static String getProviderName(String provider) { - return getProviderName(null, provider); - } - - public static String getProviderName(@Nullable SharedPreferences preferences) { - return getProviderName(preferences,null); - } - - public static String getProviderName(@Nullable SharedPreferences preferences, @Nullable String provider) { - if (provider == null && preferences != null) { - provider = preferences.getString(Provider.KEY, ""); - } - try { - JSONObject providerJson = new JSONObject(provider); - String lang = Locale.getDefault().getLanguage(); - return providerJson.getJSONObject(Provider.NAME).getString(lang); - } catch (JSONException e) { - try { - JSONObject providerJson = new JSONObject(provider); - return providerJson.getJSONObject(Provider.NAME).getString("en"); - } catch (JSONException e2) { - return null; - } - } catch (NullPointerException npe) { - return null; - } - } - - public static String getProviderDomain(SharedPreferences preferences) { - return getProviderDomain(preferences, null); - } - - public static String getProviderDomain(String provider) { - return getProviderDomain(null, provider); - } - - public static String getProviderDomain(@Nullable SharedPreferences preferences, @Nullable String provider) { - if (provider == null && preferences != null) { - provider = preferences.getString(Provider.KEY, ""); - } - try { - JSONObject providerJson = new JSONObject(provider); - return providerJson.getString(Provider.DOMAIN); - } catch (JSONException | NullPointerException e) { - return null; - } - } - - public static String getDescription(SharedPreferences preferences) { - try { - JSONObject providerJson = new JSONObject(preferences.getString(Provider.KEY, "")); - String lang = Locale.getDefault().getLanguage(); - return providerJson.getJSONObject(Provider.DESCRIPTION).getString(lang); - } catch (JSONException e) { - try { - JSONObject providerJson = new JSONObject(preferences.getString(Provider.KEY, "")); - return providerJson.getJSONObject(Provider.DESCRIPTION).getString("en"); - } catch (JSONException e1) { - return null; - } - } - } - // 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.PROVIDER_IP, provider.getProviderIp()). + putString(Provider.PROVIDER_API_IP, provider.getProviderApiIp()). putString(Provider.MAIN_URL, provider.getMainUrlString()). putString(Provider.KEY, provider.getDefinitionString()). putString(Provider.CA_CERT, provider.getCaCert()). @@ -141,6 +81,8 @@ public class PreferenceHelper { String providerDomain = provider.getDomain(); preferences.edit().putBoolean(PROVIDER_CONFIGURED, true). + putString(Provider.PROVIDER_IP + "." + providerDomain, provider.getProviderIp()). + putString(Provider.PROVIDER_API_IP + "." + providerDomain, provider.getProviderApiIp()). putString(Provider.MAIN_URL + "." + providerDomain, provider.getMainUrlString()). putString(Provider.KEY + "." + providerDomain, provider.getDefinitionString()). putString(Provider.CA_CERT + "." + providerDomain, provider.getCaCert()). @@ -167,48 +109,13 @@ public class PreferenceHelper { return VpnProfile.fromJson(lastConnectedProfileJson); } - - - - public static void clearDataOfLastProvider(SharedPreferences preferences) { - clearDataOfLastProvider(preferences, false); - } - - @Deprecated - public static void clearDataOfLastProvider(SharedPreferences preferences, boolean commit) { - Map<String, ?> allEntries = preferences.getAll(); - List<String> lastProvidersKeys = new ArrayList<>(); - for (Map.Entry<String, ?> 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(); - } - } - 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.PROVIDER_IP + "." + providerDomain). + remove(Provider.PROVIDER_API_IP + "." + 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). diff --git a/app/src/normal/assets/urls/calyx.net.url b/app/src/normal/assets/urls/calyx.net.url index 807e9e18..0b26dc25 100644 --- a/app/src/normal/assets/urls/calyx.net.url +++ b/app/src/normal/assets/urls/calyx.net.url @@ -1,3 +1,5 @@ { - "main_url" : "https://calyx.net" + "main_url" : "https://calyx.net", + "provider_ip" : "162.247.73.194", + "provider_api_ip" : "162.247.73.194" } diff --git a/app/src/normal/assets/urls/demo.bitmask.net.url b/app/src/normal/assets/urls/demo.bitmask.net.url index 0c4de648..1f8065e0 100644 --- a/app/src/normal/assets/urls/demo.bitmask.net.url +++ b/app/src/normal/assets/urls/demo.bitmask.net.url @@ -1,3 +1,5 @@ {
- "main_url" : "https://demo.bitmask.net"
-}
+ "main_url" : "https://demo.bitmask.net",
+ "provider_ip" : "198.252.153.85",
+ "provider_api_ip" : "198.252.153.85"
+}
\ No newline at end of file diff --git a/app/src/normal/assets/urls/pt.demo.bitmask.net.url b/app/src/normal/assets/urls/pt.demo.bitmask.net.url index d6e50462..a689a54d 100644 --- a/app/src/normal/assets/urls/pt.demo.bitmask.net.url +++ b/app/src/normal/assets/urls/pt.demo.bitmask.net.url @@ -1,3 +1,5 @@ { - "main_url" : "https://pt.demo.bitmask.net" + "main_url" : "https://pt.demo.bitmask.net", + "provider_ip" : "198.252.153.85", + "provider_api_ip" : "198.252.153.85" } diff --git a/app/src/normal/assets/urls/riseup.net.url b/app/src/normal/assets/urls/riseup.net.url index 42cdb979..a4a90f90 100644 --- a/app/src/normal/assets/urls/riseup.net.url +++ b/app/src/normal/assets/urls/riseup.net.url @@ -1,3 +1,5 @@ { - "main_url" : "https://riseup.net" + "main_url" : "https://riseup.net", + "provider_ip" : "198.252.153.70", + "provider_api_ip" : "198.252.153.107" } diff --git a/app/src/production/java/se/leap/bitmaskclient/ProviderApiManager.java b/app/src/production/java/se/leap/bitmaskclient/ProviderApiManager.java index 41a63ad7..6f1e3034 100644 --- a/app/src/production/java/se/leap/bitmaskclient/ProviderApiManager.java +++ b/app/src/production/java/se/leap/bitmaskclient/ProviderApiManager.java @@ -121,14 +121,13 @@ public class ProviderApiManager extends ProviderApiManagerBase { Bundle result = new Bundle(); String caCert = provider.getCaCert(); - JSONObject providerDefinition = provider.getDefinition(); String providerDotJsonString; - if(providerDefinition.length() == 0 || caCert.isEmpty()) { + if(provider.getDefinitionString().length() == 0 || caCert.isEmpty()) { String providerJsonUrl = provider.getMainUrlString() + "/provider.json"; providerDotJsonString = downloadWithCommercialCA(providerJsonUrl, provider); } else { - providerDotJsonString = downloadFromApiUrlWithProviderCA("/provider.json", caCert, providerDefinition); + providerDotJsonString = downloadFromApiUrlWithProviderCA("/provider.json", caCert, provider); } if (ConfigHelper.checkErroneousDownload(providerDotJsonString) || !isValidJson(providerDotJsonString)) { @@ -163,8 +162,7 @@ public class ProviderApiManager extends ProviderApiManagerBase { Bundle result = new Bundle(); String eipServiceJsonString = ""; try { - JSONObject providerJson = provider.getDefinition(); - String eipServiceUrl = providerJson.getString(Provider.API_URL) + "/" + providerJson.getString(Provider.API_VERSION) + "/" + EIP.SERVICE_API_PATH; + String eipServiceUrl = provider.getApiUrlWithVersion() + "/" + EIP.SERVICE_API_PATH; eipServiceJsonString = downloadWithProviderCA(provider.getCaCert(), eipServiceUrl); JSONObject eipServiceJson = new JSONObject(eipServiceJsonString); if (BuildConfig.DEBUG) { @@ -278,10 +276,10 @@ public class ProviderApiManager extends ProviderApiManagerBase { * * @return an empty string if it fails, the response body if not. */ - private String downloadFromApiUrlWithProviderCA(String path, String caCert, JSONObject providerDefinition) { + private String downloadFromApiUrlWithProviderCA(String path, String caCert, Provider provider) { String responseString; JSONObject errorJson = new JSONObject(); - String baseUrl = getApiUrl(providerDefinition); + String baseUrl = provider.getApiUrlString(); OkHttpClient okHttpClient = clientGenerator.initSelfSignedCAHttpClient(caCert, errorJson); if (okHttpClient == null) { return errorJson.toString(); diff --git a/app/src/production/java/se/leap/bitmaskclient/ProviderListContent.java b/app/src/production/java/se/leap/bitmaskclient/ProviderListContent.java deleted file mode 100644 index d9e1d1a9..00000000 --- a/app/src/production/java/se/leap/bitmaskclient/ProviderListContent.java +++ /dev/null @@ -1,81 +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 <http://www.gnu.org/licenses/>. - */ -package se.leap.bitmaskclient; - -import java.util.*; -import java.net.*; - -/** - * Models the provider list shown in the ProviderListActivity. - * - * @author parmegv - */ -public class ProviderListContent { - - public static List<ProviderItem> ITEMS = new ArrayList<ProviderItem>(); - - public static Map<String, ProviderItem> ITEM_MAP = new HashMap<String, ProviderItem>(); - - /** - * Adds a new provider item to the end of the items map, and to the items list. - * - * @param item - */ - public static void addItem(ProviderItem item) { - ITEMS.add(item); - ITEM_MAP.put(String.valueOf(ITEMS.size()), item); - } - - public static void removeItem(ProviderItem item) { - ITEMS.remove(item); - ITEM_MAP.remove(item); - } - - /** - * A provider item. - */ - public static class ProviderItem { - final public static String CUSTOM = "custom"; - private String provider_main_url; - private String name; - - /** - * @param name of the provider - * @param provider_main_url used to download provider.json file of the provider - */ - public ProviderItem(String name, String provider_main_url) { - this.name = name; - this.provider_main_url = provider_main_url; - } - - public String name() { - return name; - } - - public String providerMainUrl() { - return provider_main_url; - } - - public String domain() { - try { - return new URL(provider_main_url).getHost(); - } catch (MalformedURLException e) { - return provider_main_url.replaceFirst("http[s]?://", "").replaceFirst("/.*", ""); - } - } - } -} 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 669abc84..c7c85f8d 100644 --- a/app/src/sharedTest/java/se.leap.bitmaskclient/testutils/TestSetupHelper.java +++ b/app/src/sharedTest/java/se.leap.bitmaskclient/testutils/TestSetupHelper.java @@ -51,12 +51,18 @@ public class TestSetupHelper { public static Provider getConfiguredProvider() throws IOException, JSONException { - return getProvider(null, null, null, null); + return getProvider(null, null, null, null, null, null); } - public static Provider getProvider(String domain, String caCertFile, String providerJson, String eipServiceJson) { + public static Provider getProvider(String domain, String providerIp, String providerApiIp, String caCertFile, String providerJson, String eipServiceJson) { if (domain == null) domain = "https://riseup.net"; + if (providerIp == null) { + providerIp = ""; + } + if (providerApiIp == null) { + providerApiIp = ""; + } if (caCertFile == null) caCertFile = "riseup.net.pem"; if (providerJson == null) @@ -67,7 +73,9 @@ public class TestSetupHelper { try { Provider p = new Provider( - new URL(domain), + domain, + providerIp, + providerApiIp, getInputAsString(TestSetupHelper.class.getClassLoader().getResourceAsStream(caCertFile)), getInputAsString(TestSetupHelper.class.getClassLoader().getResourceAsStream(providerJson)) diff --git a/app/src/test/java/se/leap/bitmaskclient/ProviderTest.java b/app/src/test/java/se/leap/bitmaskclient/ProviderTest.java index c4b8f65e..0f9d358e 100644 --- a/app/src/test/java/se/leap/bitmaskclient/ProviderTest.java +++ b/app/src/test/java/se/leap/bitmaskclient/ProviderTest.java @@ -53,6 +53,8 @@ public class ProviderTest { "https://pt.demo.bitmask.net", null, null, + null, + null, "ptdemo.bitmask.eip-service.json"); assertTrue(p1.supportsPluggableTransports()); } @@ -63,6 +65,8 @@ public class ProviderTest { null, null, null, + null, + null, "eip-service-two-gateways.json"); assertFalse(p1.supportsPluggableTransports()); } diff --git a/app/src/test/java/se/leap/bitmaskclient/eip/GatewaysManagerTest.java b/app/src/test/java/se/leap/bitmaskclient/eip/GatewaysManagerTest.java index b37b3474..417c4bfc 100644 --- a/app/src/test/java/se/leap/bitmaskclient/eip/GatewaysManagerTest.java +++ b/app/src/test/java/se/leap/bitmaskclient/eip/GatewaysManagerTest.java @@ -107,7 +107,7 @@ public class GatewaysManagerTest { @Test public void testGatewayManagerFromCurrentProvider_misconfiguredProvider_noGateways() throws IOException, NullPointerException { - Provider provider = getProvider(null, null, null, "ptdemo_misconfigured_gateway.json"); + Provider provider = getProvider(null, null, null, null, null, "ptdemo_misconfigured_gateway.json"); MockHelper.mockProviderObserver(provider); GatewaysManager gatewaysManager = new GatewaysManager(mockContext); assertEquals(0, gatewaysManager.size()); @@ -115,7 +115,7 @@ public class GatewaysManagerTest { @Test public void testGatewayManagerFromCurrentProvider_threeGateways() { - Provider provider = getProvider(null, null, null, "ptdemo_three_mixed_gateways.json"); + Provider provider = getProvider(null, null, null,null, null, "ptdemo_three_mixed_gateways.json"); MockHelper.mockProviderObserver(provider); GatewaysManager gatewaysManager = new GatewaysManager(mockContext); assertEquals(3, gatewaysManager.size()); @@ -123,7 +123,7 @@ public class GatewaysManagerTest { @Test public void TestGetPosition_VpnProfileExtistingObfs4_returnPositionZero() throws JSONException, ConfigParser.ConfigParseError, IOException { - Provider provider = getProvider(null, null, null, "ptdemo_three_mixed_gateways.json"); + Provider provider = getProvider(null, null, null, null, null, "ptdemo_three_mixed_gateways.json"); JSONObject eipServiceJson = provider.getEipServiceJson(); JSONObject gateway1 = eipServiceJson.getJSONArray(GATEWAYS).getJSONObject(0); MockHelper.mockProviderObserver(provider); @@ -140,7 +140,7 @@ public class GatewaysManagerTest { @Test public void TestGetPosition_VpnProfileExtistingOpenvpn_returnPositionZero() throws JSONException, ConfigParser.ConfigParseError, IOException { - Provider provider = getProvider(null, null, null, "ptdemo_three_mixed_gateways.json"); + Provider provider = getProvider(null, null, null, null, null, "ptdemo_three_mixed_gateways.json"); JSONObject eipServiceJson = provider.getEipServiceJson(); JSONObject gateway1 = eipServiceJson.getJSONArray(GATEWAYS).getJSONObject(0); MockHelper.mockProviderObserver(provider); @@ -157,7 +157,7 @@ public class GatewaysManagerTest { @Test public void TestGetPosition_VpnProfileDifferentIp_returnMinusOne() throws JSONException, ConfigParser.ConfigParseError, IOException { - Provider provider = getProvider(null, null, null, "ptdemo_three_mixed_gateways.json"); + Provider provider = getProvider(null, null, null, null, null, "ptdemo_three_mixed_gateways.json"); JSONObject eipServiceJson = provider.getEipServiceJson(); JSONObject gateway1 = eipServiceJson.getJSONArray(GATEWAYS).getJSONObject(0); MockHelper.mockProviderObserver(provider); @@ -174,7 +174,7 @@ public class GatewaysManagerTest { @Test public void TestGetPosition_VpnProfileMoscow_returnOne() throws JSONException, ConfigParser.ConfigParseError, IOException { - Provider provider = getProvider(null, null, null, "ptdemo_three_mixed_gateways.json"); + Provider provider = getProvider(null, null, null, null, null, "ptdemo_three_mixed_gateways.json"); JSONObject eipServiceJson = provider.getEipServiceJson(); JSONObject gateway1 = eipServiceJson.getJSONArray(GATEWAYS).getJSONObject(1); MockHelper.mockProviderObserver(provider); @@ -191,7 +191,7 @@ public class GatewaysManagerTest { @Test public void TestSelectN_selectFirstObfs4Connection_returnThirdGateway() throws JSONException, ConfigParser.ConfigParseError, IOException { - Provider provider = getProvider(null, null, null, "ptdemo_two_openvpn_one_pt_gateways.json"); + Provider provider = getProvider(null, null, null, null, null, "ptdemo_two_openvpn_one_pt_gateways.json"); JSONObject eipServiceJson = provider.getEipServiceJson(); JSONObject gateway3 = eipServiceJson.getJSONArray(GATEWAYS).getJSONObject(2); 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 dde0601d..753a9474 100644 --- a/app/src/test/java/se/leap/bitmaskclient/eip/ProviderApiManagerTest.java +++ b/app/src/test/java/se/leap/bitmaskclient/eip/ProviderApiManagerTest.java @@ -269,7 +269,7 @@ public class ProviderApiManagerTest { @Test public void test_handleIntentSetupProvider_preseededProviderAndCA_outdatedCertificate() throws IOException, CertificateEncodingException, NoSuchAlgorithmException, JSONException { - Provider provider = getProvider(null ,"outdated_cert.pem", null, null); + Provider provider = getProvider(null ,null, null, "outdated_cert.pem", null, null); mockProviderApiConnector(NO_ERROR); providerApiManager = new ProviderApiManager(mockPreferences, mockResources, mockClientGenerator(), new TestProviderApiServiceCallback()); @@ -386,7 +386,7 @@ public class ProviderApiManagerTest { @Test public void test_handleIntentSetupProvider_outdatedPreseededProviderAndCA_successfulConfiguration() throws IOException, CertificateEncodingException, NoSuchAlgorithmException, JSONException { - Provider provider = getProvider(null, null, "riseup_net_outdated_config.json", null); + Provider provider = getProvider(null, null, null, null, "riseup_net_outdated_config.json", null); mockFingerprintForCertificate(" a5244308a1374709a9afce95e3ae47c1b44bc2398c0a70ccbf8b3a8a97f29494"); mockProviderApiConnector(NO_ERROR); 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 481c87cb..c0fc6531 100644 --- a/app/src/test/java/se/leap/bitmaskclient/testutils/MockHelper.java +++ b/app/src/test/java/se/leap/bitmaskclient/testutils/MockHelper.java @@ -21,6 +21,7 @@ import java.io.File; import java.io.FileNotFoundException; import java.io.IOException; import java.io.InputStream; +import java.net.UnknownHostException; import java.security.NoSuchAlgorithmException; import java.security.cert.CertificateEncodingException; import java.security.cert.X509Certificate; @@ -398,6 +399,9 @@ public class MockHelper { return providerFromPrefs.getDefinition().toString(); case Provider.CA_CERT_FINGERPRINT: return providerFromPrefs.getCaCertFingerprint(); + case Provider.CA_CERT: + return providerFromPrefs.getCaCert(); + } return null; } @@ -434,14 +438,23 @@ public class MockHelper { BackendMockProvider.provideBackendResponsesFor(errorCase); } - public static OkHttpClientGenerator mockClientGenerator() { + public static OkHttpClientGenerator mockClientGenerator(boolean resolveDNS) throws UnknownHostException { OkHttpClientGenerator mockClientGenerator = mock(OkHttpClientGenerator.class); - OkHttpClient mockedOkHttpClient = mock(OkHttpClient.class); + OkHttpClient mockedOkHttpClient = mock(OkHttpClient.class, RETURNS_DEEP_STUBS); when(mockClientGenerator.initCommercialCAHttpClient(any(JSONObject.class))).thenReturn(mockedOkHttpClient); when(mockClientGenerator.initSelfSignedCAHttpClient(anyString(), any(JSONObject.class))).thenReturn(mockedOkHttpClient); + if (resolveDNS) { + when(mockedOkHttpClient.dns().lookup(anyString())).thenReturn(new ArrayList<>()); + } else { + when(mockedOkHttpClient.dns().lookup(anyString())).thenThrow(new UnknownHostException()); + } return mockClientGenerator; } + public static OkHttpClientGenerator mockClientGenerator() throws UnknownHostException { + return mockClientGenerator(true); + } + public static Resources mockResources(InputStream inputStream) throws IOException, JSONException { Resources mockedResources = mock(Resources.class, RETURNS_DEEP_STUBS); JSONObject errorMessages = new JSONObject(TestSetupHelper.getInputAsString(inputStream)); |