From 015d8f9f512b5020d380aadf4af70a89a4b3dc42 Mon Sep 17 00:00:00 2001 From: cyBerta Date: Wed, 1 Jul 2020 00:15:52 +0200 Subject: inject preshipped geoip url to provider object --- .../main/java/se/leap/bitmaskclient/Provider.java | 42 +++++++++++++++------- .../java/se/leap/bitmaskclient/ProviderAPI.java | 1 + .../bitmaskclient/ProviderListBaseActivity.java | 2 +- .../se/leap/bitmaskclient/ProviderManager.java | 5 ++- 4 files changed, 36 insertions(+), 14 deletions(-) (limited to 'app/src/main') diff --git a/app/src/main/java/se/leap/bitmaskclient/Provider.java b/app/src/main/java/se/leap/bitmaskclient/Provider.java index 4dd7c76e..8db3cc97 100644 --- a/app/src/main/java/se/leap/bitmaskclient/Provider.java +++ b/app/src/main/java/se/leap/bitmaskclient/Provider.java @@ -50,6 +50,7 @@ public final class Provider implements Parcelable { private JSONObject eipServiceJson = new JSONObject(); private DefaultedURL mainUrl = new DefaultedURL(); private DefaultedURL apiUrl = new DefaultedURL(); + private DefaultedURL geoipUrl = new DefaultedURL(); private String providerIp = ""; private String providerApiIp = ""; private String certificatePin = ""; @@ -78,21 +79,35 @@ public final class Provider implements Parcelable { DOMAIN = "domain", MAIN_URL = "main_url", PROVIDER_IP = "provider_ip", - PROVIDER_API_IP = "provider_api_ip"; + PROVIDER_API_IP = "provider_api_ip", + GEOIP_URL = "geoip_url"; private static final String API_TERM_NAME = "name"; public Provider() { } public Provider(String mainUrl) { + this(mainUrl, null); + } + + public Provider(String mainUrl, String geoipUrl) { try { this.mainUrl.setUrl(new URL(mainUrl)); } catch (MalformedURLException e) { this.mainUrl = new DefaultedURL(); } + try { + this.geoipUrl.setUrl(new URL(geoipUrl)); + } catch (MalformedURLException e) { + this.geoipUrl = new DefaultedURL(); + } } public Provider(String mainUrl, String providerIp, String providerApiIp) { + this(mainUrl, null, providerIp, providerApiIp); + } + + public Provider(String mainUrl, String geoipUrl, String providerIp, String providerApiIp) { try { this.mainUrl.setUrl(new URL(mainUrl)); if (providerIp != null) { @@ -103,21 +118,18 @@ public final class Provider implements Parcelable { } } catch (MalformedURLException e) { e.printStackTrace(); + return; } - } - - public Provider(String mainUrl, String providerIp, String providerApiIp, String caCert, String definition) { try { - this.mainUrl.setUrl(new URL(mainUrl)); + this.geoipUrl.setUrl(new URL(geoipUrl)); } catch (MalformedURLException e) { - e.printStackTrace(); - } - if (this.providerIp != null) { - this.providerIp = providerIp; - } - if (this.providerApiIp != null) { - this.providerApiIp = providerApiIp; + this.geoipUrl = new DefaultedURL(); } + } + + + public Provider(String mainUrl, String geoipUrl, String providerIp, String providerApiIp, String caCert, String definition) { + this(mainUrl, geoipUrl, providerIp, providerApiIp); if (caCert != null) { this.caCert = caCert; } @@ -241,6 +253,10 @@ public final class Provider implements Parcelable { return apiUrl; } + protected DefaultedURL getGeoipUrl() { + return geoipUrl; + } + protected String getApiUrlWithVersion() { return getApiUrlString() + "/" + getApiVersion(); } @@ -321,6 +337,7 @@ public final class Provider implements Parcelable { parcel.writeString(getMainUrlString()); parcel.writeString(getProviderIp()); parcel.writeString(getProviderApiIp()); + parcel.writeString(getGeoipUrl().toString()); parcel.writeString(getDefinitionString()); parcel.writeString(getCaCert()); parcel.writeString(getEipServiceJsonString()); @@ -340,6 +357,7 @@ public final class Provider implements Parcelable { providerIp.equals(p.getProviderIp()) && providerApiIp.equals(p.getProviderApiIp()) && apiUrl.equals(p.getApiUrl()) && + geoipUrl.equals(p.getGeoipUrl()) && certificatePin.equals(p.getCertificatePin()) && certificatePinEncoding.equals(p.getCertificatePinEncoding()) && caCert.equals(p.getCaCert()) && diff --git a/app/src/main/java/se/leap/bitmaskclient/ProviderAPI.java b/app/src/main/java/se/leap/bitmaskclient/ProviderAPI.java index 9d34b38f..df67f282 100644 --- a/app/src/main/java/se/leap/bitmaskclient/ProviderAPI.java +++ b/app/src/main/java/se/leap/bitmaskclient/ProviderAPI.java @@ -53,6 +53,7 @@ public class ProviderAPI extends JobIntentService implements ProviderApiManagerB LOG_OUT = "logOut", DOWNLOAD_VPN_CERTIFICATE = "downloadUserAuthedVPNCertificate", UPDATE_INVALID_VPN_CERTIFICATE = "ProviderAPI.UPDATE_INVALID_VPN_CERTIFICATE", + GEOSERVICE = "geoService", PARAMETERS = "parameters", RECEIVER_KEY = "receiver", ERRORS = "errors", diff --git a/app/src/main/java/se/leap/bitmaskclient/ProviderListBaseActivity.java b/app/src/main/java/se/leap/bitmaskclient/ProviderListBaseActivity.java index 7c45c921..a7d0f916 100644 --- a/app/src/main/java/se/leap/bitmaskclient/ProviderListBaseActivity.java +++ b/app/src/main/java/se/leap/bitmaskclient/ProviderListBaseActivity.java @@ -106,7 +106,7 @@ public abstract class ProviderListBaseActivity extends ProviderSetupBaseActivity } public void showAndSelectProvider(String newURL) { - provider = new Provider(newURL, "", ""); + provider = new Provider(newURL, null, null); autoSelectProvider(); } diff --git a/app/src/main/java/se/leap/bitmaskclient/ProviderManager.java b/app/src/main/java/se/leap/bitmaskclient/ProviderManager.java index 6d074a7a..c23ad270 100644 --- a/app/src/main/java/se/leap/bitmaskclient/ProviderManager.java +++ b/app/src/main/java/se/leap/bitmaskclient/ProviderManager.java @@ -20,6 +20,7 @@ import java.util.Iterator; import java.util.List; import java.util.Set; +import static se.leap.bitmaskclient.Provider.GEOIP_URL; 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; @@ -90,18 +91,20 @@ public class ProviderManager implements AdapteeCollection { String providerApiIp = null; String certificate = null; String providerDefinition = null; + String geoipUrl = null; try { String provider = file.substring(0, file.length() - ".url".length()); InputStream providerFile = assetsManager.open(directory + "/" + file); mainUrl = extractKeyFromInputStream(providerFile, MAIN_URL); providerIp = extractKeyFromInputStream(providerFile, PROVIDER_IP); providerApiIp = extractKeyFromInputStream(providerFile, PROVIDER_API_IP); + geoipUrl = extractKeyFromInputStream(providerFile, GEOIP_URL); certificate = loadInputStreamAsString(assetsManager.open(provider + EXT_PEM)); providerDefinition = loadInputStreamAsString(assetsManager.open(provider + EXT_JSON)); } catch (IOException e) { e.printStackTrace(); } - providers.add(new Provider(mainUrl, providerIp, providerApiIp, certificate, providerDefinition)); + providers.add(new Provider(mainUrl, geoipUrl, providerIp, providerApiIp, certificate, providerDefinition)); } return providers; -- cgit v1.2.3 From 49b18fcdc45433d34eefb46ab236144e19022dcb Mon Sep 17 00:00:00 2001 From: cyBerta Date: Thu, 23 Jul 2020 16:56:41 +0200 Subject: implement gateway selection based on geoip service --- .../main/java/se/leap/bitmaskclient/Constants.java | 1 + .../java/se/leap/bitmaskclient/EipFragment.java | 29 ++-- .../se/leap/bitmaskclient/EipSetupObserver.java | 23 ++- .../main/java/se/leap/bitmaskclient/Provider.java | 164 ++++++++++++++------- .../java/se/leap/bitmaskclient/ProviderAPI.java | 10 +- .../se/leap/bitmaskclient/ProviderAPICommand.java | 10 +- .../leap/bitmaskclient/ProviderApiManagerBase.java | 44 +++++- .../main/java/se/leap/bitmaskclient/eip/EIP.java | 13 +- .../java/se/leap/bitmaskclient/eip/Gateway.java | 5 + .../se/leap/bitmaskclient/eip/GatewaysManager.java | 125 +++++++++------- .../leap/bitmaskclient/utils/PreferenceHelper.java | 4 + 11 files changed, 287 insertions(+), 141 deletions(-) (limited to 'app/src/main') diff --git a/app/src/main/java/se/leap/bitmaskclient/Constants.java b/app/src/main/java/se/leap/bitmaskclient/Constants.java index 6ec3076c..6462b663 100644 --- a/app/src/main/java/se/leap/bitmaskclient/Constants.java +++ b/app/src/main/java/se/leap/bitmaskclient/Constants.java @@ -142,4 +142,5 @@ public interface Constants { String LOCATION = "location"; String OPENVPN_CONFIGURATION = "openvpn_configuration"; String GATEWAYS = "gateways"; + String HOST = "host"; } diff --git a/app/src/main/java/se/leap/bitmaskclient/EipFragment.java b/app/src/main/java/se/leap/bitmaskclient/EipFragment.java index b8883f77..fceadd88 100644 --- a/app/src/main/java/se/leap/bitmaskclient/EipFragment.java +++ b/app/src/main/java/se/leap/bitmaskclient/EipFragment.java @@ -27,14 +27,6 @@ import android.graphics.ColorMatrixColorFilter; import android.os.Bundle; import android.os.IBinder; import android.os.Vibrator; -import androidx.annotation.NonNull; -import androidx.fragment.app.DialogFragment; -import androidx.fragment.app.Fragment; -import androidx.fragment.app.FragmentTransaction; -import androidx.appcompat.app.AlertDialog; -import androidx.appcompat.widget.AppCompatButton; -import androidx.appcompat.widget.AppCompatImageView; -import androidx.appcompat.widget.AppCompatTextView; import android.text.TextUtils; import android.util.Log; import android.view.Gravity; @@ -44,6 +36,15 @@ import android.view.ViewGroup; import android.widget.TextView; import android.widget.Toast; +import androidx.annotation.NonNull; +import androidx.appcompat.app.AlertDialog; +import androidx.appcompat.widget.AppCompatButton; +import androidx.appcompat.widget.AppCompatImageView; +import androidx.appcompat.widget.AppCompatTextView; +import androidx.fragment.app.DialogFragment; +import androidx.fragment.app.Fragment; +import androidx.fragment.app.FragmentTransaction; + import java.util.Observable; import java.util.Observer; @@ -62,6 +63,8 @@ import static android.view.View.GONE; import static android.view.View.VISIBLE; import static de.blinkt.openvpn.core.ConnectionStatus.LEVEL_NONETWORK; import static se.leap.bitmaskclient.Constants.ASK_TO_CANCEL_VPN; +import static se.leap.bitmaskclient.Constants.EIP_ACTION_START; +import static se.leap.bitmaskclient.Constants.EIP_EARLY_ROUTES; import static se.leap.bitmaskclient.Constants.EIP_RESTART_ON_BOOT; import static se.leap.bitmaskclient.Constants.PROVIDER_KEY; import static se.leap.bitmaskclient.Constants.REQUEST_CODE_CONFIGURE_LEAP; @@ -71,6 +74,7 @@ import static se.leap.bitmaskclient.Constants.SHARED_PREFERENCES; import static se.leap.bitmaskclient.EipSetupObserver.connectionRetry; import static se.leap.bitmaskclient.EipSetupObserver.gatewayOrder; import static se.leap.bitmaskclient.EipSetupObserver.reconnectingWithDifferentGateway; +import static se.leap.bitmaskclient.ProviderAPI.DOWNLOAD_GEOIP_JSON; import static se.leap.bitmaskclient.ProviderAPI.UPDATE_INVALID_VPN_CERTIFICATE; import static se.leap.bitmaskclient.ProviderAPI.USER_MESSAGE; import static se.leap.bitmaskclient.R.string.vpn_certificate_user_message; @@ -301,7 +305,14 @@ public class EipFragment extends Fragment implements Observer { Log.e(TAG, "context is null when trying to start VPN"); return; } - EipCommand.startVPN(context.getApplicationContext(), false); + if (!provider.getGeoipUrl().isDefault() && provider.shouldUpdateGeoIpJson()) { + Bundle bundle = new Bundle(); + bundle.putBoolean(EIP_ACTION_START, true); + bundle.putBoolean(EIP_EARLY_ROUTES, false); + ProviderAPICommand.execute(getContext().getApplicationContext(), DOWNLOAD_GEOIP_JSON, bundle, provider); + } else { + EipCommand.startVPN(context.getApplicationContext(), false); + } vpnStateImage.showProgress(); routedText.setVisibility(GONE); vpnRoute.setVisibility(GONE); diff --git a/app/src/main/java/se/leap/bitmaskclient/EipSetupObserver.java b/app/src/main/java/se/leap/bitmaskclient/EipSetupObserver.java index ee7e7ef5..7504e0c0 100644 --- a/app/src/main/java/se/leap/bitmaskclient/EipSetupObserver.java +++ b/app/src/main/java/se/leap/bitmaskclient/EipSetupObserver.java @@ -6,9 +6,10 @@ import android.content.Intent; import android.content.IntentFilter; import android.content.SharedPreferences; import android.os.Bundle; -import androidx.localbroadcastmanager.content.LocalBroadcastManager; import android.util.Log; +import androidx.localbroadcastmanager.content.LocalBroadcastManager; + import org.json.JSONObject; import java.util.Vector; @@ -39,11 +40,14 @@ import static se.leap.bitmaskclient.Constants.BROADCAST_RESULT_KEY; import static se.leap.bitmaskclient.Constants.EIP_ACTION_PREPARE_VPN; import static se.leap.bitmaskclient.Constants.EIP_ACTION_START; import static se.leap.bitmaskclient.Constants.EIP_ACTION_START_ALWAYS_ON_VPN; +import static se.leap.bitmaskclient.Constants.EIP_EARLY_ROUTES; 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.ProviderAPI.CORRECTLY_DOWNLOADED_EIP_SERVICE; +import static se.leap.bitmaskclient.ProviderAPI.CORRECTLY_DOWNLOADED_GEOIP_JSON; import static se.leap.bitmaskclient.ProviderAPI.CORRECTLY_UPDATED_INVALID_VPN_CERTIFICATE; +import static se.leap.bitmaskclient.ProviderAPI.INCORRECTLY_DOWNLOADED_GEOIP_JSON; /** * Created by cyberta on 05.12.18. @@ -151,6 +155,15 @@ class EipSetupObserver extends BroadcastReceiver implements VpnStatus.StateListe PreferenceHelper.storeProviderInPreferences(preferences, provider); EipCommand.startVPN(context.getApplicationContext(), true); break; + case CORRECTLY_DOWNLOADED_GEOIP_JSON: + provider = resultData.getParcelable(PROVIDER_KEY); + ProviderObservable.getInstance().updateProvider(provider); + PreferenceHelper.storeProviderInPreferences(preferences, provider); + maybeStartEipService(resultData); + break; + case INCORRECTLY_DOWNLOADED_GEOIP_JSON: + maybeStartEipService(resultData); + break; default: break; } @@ -160,6 +173,13 @@ class EipSetupObserver extends BroadcastReceiver implements VpnStatus.StateListe } } + private void maybeStartEipService(Bundle resultData) { + if (resultData.getBoolean(EIP_ACTION_START)) { + boolean earlyRoutes = resultData.getBoolean(EIP_EARLY_ROUTES); + EipCommand.startVPN(context.getApplicationContext(), earlyRoutes); + } + } + private void handleEipEvent(Intent intent) { int resultCode = intent.getIntExtra(BROADCAST_RESULT_CODE, RESULT_CANCELED); @@ -184,6 +204,7 @@ class EipSetupObserver extends BroadcastReceiver implements VpnStatus.StateListe finishGatewaySetup(false); EipCommand.startBlockingVPN(context.getApplicationContext()); } else { + //FIXME: finishGatewaySetup(false); EipCommand.stopVPN(context); EipStatus.refresh(); diff --git a/app/src/main/java/se/leap/bitmaskclient/Provider.java b/app/src/main/java/se/leap/bitmaskclient/Provider.java index 8db3cc97..9d1b0095 100644 --- a/app/src/main/java/se/leap/bitmaskclient/Provider.java +++ b/app/src/main/java/se/leap/bitmaskclient/Provider.java @@ -18,7 +18,6 @@ package se.leap.bitmaskclient; import android.os.Parcel; import android.os.Parcelable; -import androidx.annotation.NonNull; import com.google.gson.Gson; @@ -46,8 +45,10 @@ import static se.leap.bitmaskclient.ProviderAPI.ERRORS; public final class Provider implements Parcelable { private static long EIP_SERVICE_TIMEOUT = 1000 * 60 * 60 * 24 * 3; + private static long GEOIP_SERVICE_TIMEOUT = 1000 * 60 * 60; private JSONObject definition = new JSONObject(); // Represents our Provider's provider.json private JSONObject eipServiceJson = new JSONObject(); + private JSONObject geoIpJson = new JSONObject(); private DefaultedURL mainUrl = new DefaultedURL(); private DefaultedURL apiUrl = new DefaultedURL(); private DefaultedURL geoipUrl = new DefaultedURL(); @@ -60,6 +61,7 @@ public final class Provider implements Parcelable { private String privateKey = ""; private String vpnCertificate = ""; private long lastEipServiceUpdate = 0L; + private long lastGeoIpUpdate = 0L; private boolean allowAnonymous; private boolean allowRegistered; @@ -96,11 +98,7 @@ public final class Provider implements Parcelable { } catch (MalformedURLException e) { this.mainUrl = new DefaultedURL(); } - try { - this.geoipUrl.setUrl(new URL(geoipUrl)); - } catch (MalformedURLException e) { - this.geoipUrl = new DefaultedURL(); - } + setGeoipUrl(geoipUrl); } public Provider(String mainUrl, String providerIp, String providerApiIp) { @@ -120,11 +118,7 @@ public final class Provider implements Parcelable { e.printStackTrace(); return; } - try { - this.geoipUrl.setUrl(new URL(geoipUrl)); - } catch (MalformedURLException e) { - this.geoipUrl = new DefaultedURL(); - } + setGeoipUrl(geoipUrl); } @@ -252,11 +246,19 @@ public final class Provider implements Parcelable { protected DefaultedURL getApiUrl() { return apiUrl; } - - protected DefaultedURL getGeoipUrl() { + + public DefaultedURL getGeoipUrl() { return geoipUrl; } + public void setGeoipUrl(String url) { + try { + this.geoipUrl.setUrl(new URL(url)); + } catch (MalformedURLException e) { + this.geoipUrl = new DefaultedURL(); + } + } + protected String getApiUrlWithVersion() { return getApiUrlString() + "/" + getApiVersion(); } @@ -278,6 +280,10 @@ public final class Provider implements Parcelable { return definition != null && definition.length() > 0; } + public boolean hasGeoIpJson() { + return geoIpJson != null && geoIpJson.length() > 0; + } + public String getCaCert() { return caCert; @@ -341,19 +347,71 @@ public final class Provider implements Parcelable { parcel.writeString(getDefinitionString()); parcel.writeString(getCaCert()); parcel.writeString(getEipServiceJsonString()); + parcel.writeString(getGeoIpJsonString()); parcel.writeString(getPrivateKey()); parcel.writeString(getVpnCertificate()); parcel.writeLong(lastEipServiceUpdate); + parcel.writeLong(lastGeoIpUpdate); + } + + + //TODO: write a test for marshalling! + private Provider(Parcel in) { + try { + 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()) { + geoipUrl.setUrl(new URL(tmpString)); + } + tmpString = in.readString(); + if (!tmpString.isEmpty()) { + definition = new JSONObject((tmpString)); + parseDefinition(definition); + } + tmpString = in.readString(); + if (!tmpString.isEmpty()) { + this.caCert = tmpString; + } + tmpString = in.readString(); + if (!tmpString.isEmpty()) { + this.setEipServiceJson(new JSONObject(tmpString)); + } + tmpString = in.readString(); + if (!tmpString.isEmpty()) { + this.setGeoIpJson(new JSONObject(tmpString)); + } + tmpString = in.readString(); + if (!tmpString.isEmpty()) { + this.setPrivateKey(tmpString); + } + tmpString = in.readString(); + if (!tmpString.isEmpty()) { + this.setVpnCertificate(tmpString); + } + this.lastEipServiceUpdate = in.readLong(); + this.lastGeoIpUpdate = in.readLong(); + } catch (MalformedURLException | JSONException e) { + e.printStackTrace(); + } } + @Override public boolean equals(Object o) { if (o instanceof Provider) { Provider p = (Provider) o; return p.getDomain().equals(getDomain()) && definition.toString().equals(p.getDefinition().toString()) && - eipServiceJson.toString().equals(p.getEipServiceJson().toString())&& - mainUrl.equals(p.getMainUrl()) && + eipServiceJson.toString().equals(p.getEipServiceJsonString()) && + geoIpJson.toString().equals(p.getGeoIpJsonString()) && providerIp.equals(p.getProviderIp()) && providerApiIp.equals(p.getProviderApiIp()) && apiUrl.equals(p.getApiUrl()) && @@ -366,10 +424,12 @@ public final class Provider implements Parcelable { vpnCertificate.equals(p.getVpnCertificate()) && allowAnonymous == p.allowsAnonymous() && allowRegistered == p.allowsRegistered() && - lastEipServiceUpdate == p.getLastEipServiceUpdate(); + lastEipServiceUpdate == p.getLastEipServiceUpdate() && + lastGeoIpUpdate == p.getLastGeoIpUpdate(); } else return false; } + public JSONObject toJson() { JSONObject json = new JSONObject(); try { @@ -390,45 +450,6 @@ public final class Provider implements Parcelable { return new Gson().toJson(this); } - //TODO: write a test for marshalling! - private Provider(Parcel in) { - try { - 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); - } - tmpString = in.readString(); - if (!tmpString.isEmpty()) { - this.caCert = tmpString; - } - tmpString = in.readString(); - if (!tmpString.isEmpty()) { - this.setEipServiceJson(new JSONObject(tmpString)); - } - tmpString = in.readString(); - if (!tmpString.isEmpty()) { - this.setPrivateKey(tmpString); - } - tmpString = in.readString(); - if (!tmpString.isEmpty()) { - this.setVpnCertificate(tmpString); - } - this.lastEipServiceUpdate = in.readLong(); - } catch (MalformedURLException | JSONException e) { - e.printStackTrace(); - } - } - private boolean parseDefinition(JSONObject definition) { try { String pin = definition.getString(CA_CERT_FINGERPRINT); @@ -468,6 +489,20 @@ public final class Provider implements Parcelable { return System.currentTimeMillis() - lastEipServiceUpdate >= EIP_SERVICE_TIMEOUT; } + + public void setLastGeoIpUpdate(long timestamp) { + lastGeoIpUpdate = timestamp; + } + + public long getLastGeoIpUpdate() { + return lastGeoIpUpdate; + } + + public boolean shouldUpdateGeoIpJson() { + return System.currentTimeMillis() - lastGeoIpUpdate >= GEOIP_SERVICE_TIMEOUT; + } + + public boolean setEipServiceJson(JSONObject eipServiceJson) { if (eipServiceJson.has(ERRORS)) { return false; @@ -476,16 +511,34 @@ public final class Provider implements Parcelable { return true; } + public boolean setGeoIpJson(JSONObject geoIpJson) { + if (geoIpJson.has(ERRORS)) { + return false; + } + this.geoIpJson = geoIpJson; + return true; + } + public JSONObject getEipServiceJson() { return eipServiceJson; } + public JSONObject getGeoIpJson() { + return geoIpJson; + } + + public String getGeoIpJsonString() { + return geoIpJson.toString(); + } + public String getEipServiceJsonString() { return getEipServiceJson().toString(); } + public boolean isDefault() { return getMainUrl().isDefault() && getApiUrl().isDefault() && + getGeoipUrl().isDefault() && certificatePin.isEmpty() && certificatePinEncoding.isEmpty() && caCert.isEmpty(); @@ -533,6 +586,7 @@ public final class Provider implements Parcelable { public void reset() { definition = new JSONObject(); eipServiceJson = new JSONObject(); + geoIpJson = new JSONObject(); apiUrl = new DefaultedURL(); certificatePin = ""; certificatePinEncoding = ""; diff --git a/app/src/main/java/se/leap/bitmaskclient/ProviderAPI.java b/app/src/main/java/se/leap/bitmaskclient/ProviderAPI.java index df67f282..767e6a78 100644 --- a/app/src/main/java/se/leap/bitmaskclient/ProviderAPI.java +++ b/app/src/main/java/se/leap/bitmaskclient/ProviderAPI.java @@ -24,6 +24,7 @@ import android.content.SharedPreferences; import androidx.annotation.NonNull; import androidx.core.app.JobIntentService; import androidx.localbroadcastmanager.content.LocalBroadcastManager; + import static se.leap.bitmaskclient.Constants.SHARED_PREFERENCES; /** @@ -48,12 +49,12 @@ public class ProviderAPI extends JobIntentService implements ProviderApiManagerB TAG = ProviderAPI.class.getSimpleName(), SET_UP_PROVIDER = "setUpProvider", UPDATE_PROVIDER_DETAILS = "updateProviderDetails", + DOWNLOAD_GEOIP_JSON = "downloadGeoIpJson", SIGN_UP = "srpRegister", LOG_IN = "srpAuth", LOG_OUT = "logOut", DOWNLOAD_VPN_CERTIFICATE = "downloadUserAuthedVPNCertificate", UPDATE_INVALID_VPN_CERTIFICATE = "ProviderAPI.UPDATE_INVALID_VPN_CERTIFICATE", - GEOSERVICE = "geoService", PARAMETERS = "parameters", RECEIVER_KEY = "receiver", ERRORS = "errors", @@ -78,7 +79,9 @@ public class ProviderAPI extends JobIntentService implements ProviderApiManagerB CORRECTLY_DOWNLOADED_EIP_SERVICE = 13, INCORRECTLY_DOWNLOADED_EIP_SERVICE = 14, CORRECTLY_UPDATED_INVALID_VPN_CERTIFICATE = 15, - INCORRECTLY_UPDATED_INVALID_VPN_CERTIFICATE = 16; + INCORRECTLY_UPDATED_INVALID_VPN_CERTIFICATE = 16, + CORRECTLY_DOWNLOADED_GEOIP_JSON = 17, + INCORRECTLY_DOWNLOADED_GEOIP_JSON = 18; ProviderApiManager providerApiManager; @@ -100,11 +103,12 @@ public class ProviderAPI extends JobIntentService implements ProviderApiManagerB */ static void enqueueWork(Context context, Intent work) { try { - enqueueWork(context, ProviderAPI.class, JOB_ID, work); + ProviderAPI.enqueueWork(context, ProviderAPI.class, JOB_ID, work); } catch (IllegalStateException e) { e.printStackTrace(); } } + @Override protected void onHandleWork(@NonNull Intent command) { providerApiManager.handleIntent(command); diff --git a/app/src/main/java/se/leap/bitmaskclient/ProviderAPICommand.java b/app/src/main/java/se/leap/bitmaskclient/ProviderAPICommand.java index f3122376..9a0731cd 100644 --- a/app/src/main/java/se/leap/bitmaskclient/ProviderAPICommand.java +++ b/app/src/main/java/se/leap/bitmaskclient/ProviderAPICommand.java @@ -4,11 +4,13 @@ import android.content.Context; import android.content.Intent; import android.os.Bundle; import android.os.ResultReceiver; +import android.util.Log; import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.Nullable; public class ProviderAPICommand { + private static final String TAG = ProviderAPICommand.class.getSimpleName(); private Context context; private String action; @@ -60,22 +62,22 @@ public class ProviderAPICommand { return command; } - public static void execute(Context context, String action, Provider provider) { + public static void execute(Context context, String action, @NotNull Provider provider) { ProviderAPICommand command = new ProviderAPICommand(context, action, provider); command.execute(); } - public static void execute(Context context, String action, Bundle parameters, Provider provider) { + public static void execute(Context context, String action, Bundle parameters, @NotNull Provider provider) { ProviderAPICommand command = new ProviderAPICommand(context, action, parameters, provider); command.execute(); } - public static void execute(Context context, String action, Bundle parameters, Provider provider, ResultReceiver resultReceiver) { + public static void execute(Context context, String action, Bundle parameters, @NotNull Provider provider, ResultReceiver resultReceiver) { ProviderAPICommand command = new ProviderAPICommand(context, action, parameters, provider, resultReceiver); command.execute(); } - public static void execute(Context context, String action, Provider provider, ResultReceiver resultReceiver) { + public static void execute(Context context, String action, @NotNull Provider provider, ResultReceiver resultReceiver) { ProviderAPICommand command = new ProviderAPICommand(context, action, provider, resultReceiver); command.execute(); } diff --git a/app/src/main/java/se/leap/bitmaskclient/ProviderApiManagerBase.java b/app/src/main/java/se/leap/bitmaskclient/ProviderApiManagerBase.java index 1fb6bf48..e5ca184f 100644 --- a/app/src/main/java/se/leap/bitmaskclient/ProviderApiManagerBase.java +++ b/app/src/main/java/se/leap/bitmaskclient/ProviderApiManagerBase.java @@ -22,11 +22,12 @@ import android.content.SharedPreferences; import android.content.res.Resources; import android.os.Bundle; import android.os.ResultReceiver; -import androidx.annotation.NonNull; import android.util.Base64; import android.util.Log; import android.util.Pair; +import androidx.annotation.NonNull; + import org.json.JSONException; import org.json.JSONObject; @@ -60,17 +61,21 @@ import static se.leap.bitmaskclient.Constants.BROADCAST_RESULT_CODE; import static se.leap.bitmaskclient.Constants.BROADCAST_RESULT_KEY; import static se.leap.bitmaskclient.Constants.CREDENTIALS_PASSWORD; import static se.leap.bitmaskclient.Constants.CREDENTIALS_USERNAME; +import static se.leap.bitmaskclient.Constants.EIP_ACTION_START; 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.GEOIP_URL; 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; +import static se.leap.bitmaskclient.ProviderAPI.CORRECTLY_DOWNLOADED_GEOIP_JSON; import static se.leap.bitmaskclient.ProviderAPI.CORRECTLY_DOWNLOADED_VPN_CERTIFICATE; import static se.leap.bitmaskclient.ProviderAPI.CORRECTLY_UPDATED_INVALID_VPN_CERTIFICATE; +import static se.leap.bitmaskclient.ProviderAPI.DOWNLOAD_GEOIP_JSON; 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; @@ -78,6 +83,7 @@ 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_EIP_SERVICE; +import static se.leap.bitmaskclient.ProviderAPI.INCORRECTLY_DOWNLOADED_GEOIP_JSON; import static se.leap.bitmaskclient.ProviderAPI.INCORRECTLY_DOWNLOADED_VPN_CERTIFICATE; import static se.leap.bitmaskclient.ProviderAPI.INCORRECTLY_UPDATED_INVALID_VPN_CERTIFICATE; import static se.leap.bitmaskclient.ProviderAPI.LOGOUT_FAILED; @@ -143,7 +149,11 @@ public abstract class ProviderApiManagerBase { } public void handleIntent(Intent command) { - final ResultReceiver receiver = command.getParcelableExtra(RECEIVER_KEY); +// Log.d(TAG, "handleIntent was called!"); + ResultReceiver receiver = null; + if (command.getParcelableExtra(RECEIVER_KEY) != null) { + receiver = command.getParcelableExtra(RECEIVER_KEY); + } String action = command.getAction(); Bundle parameters = command.getBundleExtra(PARAMETERS); @@ -167,6 +177,7 @@ public abstract class ProviderApiManagerBase { Bundle task = new Bundle(); result = setUpProvider(provider, task); if (result.getBoolean(BROADCAST_RESULT_KEY)) { + getGeoIPJson(provider); sendToReceiverOrBroadcast(receiver, PROVIDER_OK, result, provider); } else { sendToReceiverOrBroadcast(receiver, PROVIDER_NOK, result, provider); @@ -177,6 +188,7 @@ public abstract class ProviderApiManagerBase { ProviderObservable.getInstance().setProviderForDns(provider); result = setUpProvider(provider, parameters); if (result.getBoolean(BROADCAST_RESULT_KEY)) { + getGeoIPJson(provider); sendToReceiverOrBroadcast(receiver, PROVIDER_OK, result, provider); } else { sendToReceiverOrBroadcast(receiver, PROVIDER_NOK, result, provider); @@ -245,6 +257,20 @@ public abstract class ProviderApiManagerBase { } } break; + + case DOWNLOAD_GEOIP_JSON: + if (!provider.getGeoipUrl().isDefault()) { + boolean startEIP = parameters.getBoolean(EIP_ACTION_START); + ProviderObservable.getInstance().setProviderForDns(provider); + result = getGeoIPJson(provider); + result.putBoolean(EIP_ACTION_START, startEIP); + if (result.getBoolean(BROADCAST_RESULT_KEY)) { + sendToReceiverOrBroadcast(receiver, CORRECTLY_DOWNLOADED_GEOIP_JSON, result, provider); + } else { + sendToReceiverOrBroadcast(receiver, INCORRECTLY_DOWNLOADED_GEOIP_JSON, result, provider); + } + ProviderObservable.getInstance().setProviderForDns(null); + } } } @@ -664,6 +690,15 @@ public abstract class ProviderApiManagerBase { protected abstract Bundle updateVpnCertificate(Provider provider); + /** + * Fetches the Geo ip Json, containing a list of gateways sorted by distance from the users current location + * + * @param provider + * @return + */ + protected abstract Bundle getGeoIPJson(Provider provider); + + protected boolean isValidJson(String jsonString) { try { new JSONObject(jsonString); @@ -708,6 +743,7 @@ public abstract class ProviderApiManagerBase { provider.setVpnCertificate(getPersistedVPNCertificate(providerDomain)); provider.setProviderApiIp(getPersistedProviderApiIp(providerDomain)); provider.setProviderIp(getPersistedProviderIp(providerDomain)); + provider.setGeoipUrl(getPersistedGeoIp(providerDomain)); } } @@ -816,6 +852,10 @@ public abstract class ProviderApiManagerBase { return getFromPersistedProvider(PROVIDER_IP, providerDomain, preferences); } + protected String getPersistedGeoIp(String providerDomain) { + return getFromPersistedProvider(GEOIP_URL, providerDomain, preferences); + } + protected boolean hasUpdatedProviderDetails(String domain) { return preferences.contains(Provider.KEY + "." + domain) && preferences.contains(CA_CERT + "." + domain); } diff --git a/app/src/main/java/se/leap/bitmaskclient/eip/EIP.java b/app/src/main/java/se/leap/bitmaskclient/eip/EIP.java index 34c88ef9..e0c96ebb 100644 --- a/app/src/main/java/se/leap/bitmaskclient/eip/EIP.java +++ b/app/src/main/java/se/leap/bitmaskclient/eip/EIP.java @@ -226,7 +226,7 @@ public final class EIP extends JobIntentService implements Observer { return; } - GatewaysManager gatewaysManager = gatewaysFromPreferences(); + GatewaysManager gatewaysManager = new GatewaysManager(getApplicationContext()); if (gatewaysManager.isEmpty()) { setErrorResult(result, warning_client_parsing_error_gateways, null); tellToReceiverOrBroadcast(this, EIP_ACTION_START, RESULT_CANCELED, result); @@ -248,7 +248,7 @@ public final class EIP extends JobIntentService implements Observer { * The {@link OnBootReceiver} will care if there is no profile. */ private void startEIPAlwaysOnVpn() { - GatewaysManager gatewaysManager = gatewaysFromPreferences(); + GatewaysManager gatewaysManager = new GatewaysManager(getApplicationContext()); Gateway gateway = gatewaysManager.select(0); if (!launchActiveGateway(gateway, 0)) { @@ -309,15 +309,6 @@ public final class EIP extends JobIntentService implements Observer { tellToReceiverOrBroadcast(this, EIP_ACTION_IS_RUNNING, resultCode); } - /** - * read eipServiceJson from preferences and parse Gateways - * - * @return GatewaysManager - */ - private GatewaysManager gatewaysFromPreferences() { - return new GatewaysManager(getApplicationContext(), preferences); - } - /** * read VPN certificate from preferences and check it * broadcast result diff --git a/app/src/main/java/se/leap/bitmaskclient/eip/Gateway.java b/app/src/main/java/se/leap/bitmaskclient/eip/Gateway.java index 66c9fe84..589fa751 100644 --- a/app/src/main/java/se/leap/bitmaskclient/eip/Gateway.java +++ b/app/src/main/java/se/leap/bitmaskclient/eip/Gateway.java @@ -34,6 +34,7 @@ import de.blinkt.openvpn.core.ConfigParser; import de.blinkt.openvpn.core.connection.Connection; import se.leap.bitmaskclient.utils.PreferenceHelper; +import static se.leap.bitmaskclient.Constants.HOST; import static se.leap.bitmaskclient.Constants.IP_ADDRESS; import static se.leap.bitmaskclient.Constants.LOCATION; import static se.leap.bitmaskclient.Constants.LOCATIONS; @@ -114,6 +115,10 @@ public class Gateway { return gateway.optString(IP_ADDRESS); } + public String getHost() { + return gateway.optString(HOST); + } + private String locationAsName(JSONObject eipDefinition) { JSONObject location = getLocationInfo(eipDefinition); return location.optString(NAME); diff --git a/app/src/main/java/se/leap/bitmaskclient/eip/GatewaysManager.java b/app/src/main/java/se/leap/bitmaskclient/eip/GatewaysManager.java index fbe1861a..e3932cb6 100644 --- a/app/src/main/java/se/leap/bitmaskclient/eip/GatewaysManager.java +++ b/app/src/main/java/se/leap/bitmaskclient/eip/GatewaysManager.java @@ -17,7 +17,6 @@ package se.leap.bitmaskclient.eip; import android.content.Context; -import android.content.SharedPreferences; import com.google.gson.Gson; import com.google.gson.reflect.TypeToken; @@ -30,6 +29,7 @@ import java.io.IOException; import java.lang.reflect.Type; import java.util.ArrayList; import java.util.LinkedHashMap; +import java.util.List; import de.blinkt.openvpn.VpnProfile; import de.blinkt.openvpn.core.ConfigParser; @@ -37,7 +37,6 @@ import de.blinkt.openvpn.core.VpnStatus; import de.blinkt.openvpn.core.connection.Connection; import se.leap.bitmaskclient.Provider; import se.leap.bitmaskclient.ProviderObservable; -import se.leap.bitmaskclient.utils.PreferenceHelper; import static de.blinkt.openvpn.core.connection.Connection.TransportType.OBFS4; import static de.blinkt.openvpn.core.connection.Connection.TransportType.OPENVPN; @@ -54,15 +53,9 @@ public class GatewaysManager { private static final String TAG = GatewaysManager.class.getSimpleName(); private Context context; - private SharedPreferences preferences; private LinkedHashMap gateways = new LinkedHashMap<>(); private Type listType = new TypeToken>() {}.getType(); - - public GatewaysManager(Context context, SharedPreferences preferences) { - this.preferences = preferences; - this.context = context; - configureFromPreferences(); - } + private ArrayList presortedList = new ArrayList<>(); public GatewaysManager(Context context) { configureFromCurrentProvider(); @@ -75,7 +68,18 @@ public class GatewaysManager { */ public Gateway select(int nClosest) { Connection.TransportType transportType = getUsePluggableTransports(context) ? OBFS4 : OPENVPN; - GatewaySelector gatewaySelector = new GatewaySelector(new ArrayList<>(gateways.values())); + + if (presortedList.size() > 0) { + return getGatewayFromPreorderedList(nClosest, transportType); + } + + return getGatewayFromTimezoneCalculation(nClosest, transportType); + } + + + private Gateway getGatewayFromTimezoneCalculation(int nClosest, Connection.TransportType transportType) { + List list = new ArrayList<>(gateways.values()); + GatewaySelector gatewaySelector = new GatewaySelector(list); Gateway gateway; while ((gateway = gatewaySelector.select(nClosest)) != null) { if (gateway.getProfile(transportType) != null) { @@ -86,6 +90,17 @@ public class GatewaysManager { return null; } + private Gateway getGatewayFromPreorderedList(int nClosest, Connection.TransportType transportType) { + while (nClosest < presortedList.size()) { + Gateway gateway = presortedList.get(nClosest); + if (gateway.getProfile(transportType) != null) { + return gateway; + } + nClosest++; + } + return null; + } + /** * Get position of the gateway from a sorted set (along the distance of the gw to your time zone) * @param profile profile belonging to a gateway @@ -126,43 +141,59 @@ public class GatewaysManager { } /** - * parse gateways from eipDefinition - * @param eipDefinition eipServiceJson + * parse gateways from Provider's eip service + * @param provider */ - private void fromEipServiceJson(JSONObject eipDefinition, JSONObject secrets) { - JSONArray gatewaysDefined = new JSONArray(); + private void parseDefaultGateways(Provider provider) { + try { + JSONObject eipDefinition = provider.getEipServiceJson(); + JSONObject secrets = secretsConfigurationFromCurrentProvider(); + + JSONArray gatewaysDefined = new JSONArray(); + try { + gatewaysDefined = eipDefinition.getJSONArray(GATEWAYS); + } catch (Exception e) { + e.printStackTrace(); + } + + for (int i = 0; i < gatewaysDefined.length(); i++) { + try { + JSONObject gw = gatewaysDefined.getJSONObject(i); + Gateway aux = new Gateway(eipDefinition, secrets, gw, this.context); + if (gateways.get(aux.getHost()) == null) { + addGateway(aux); + } + } catch (JSONException | ConfigParser.ConfigParseError | IOException e) { + e.printStackTrace(); + VpnStatus.logError("Unable to parse gateway config!"); + } + } + } catch (NullPointerException npe) { + npe.printStackTrace(); + } + } + + private void parseGatewaysFromGeoIpServiceJson(Provider provider) { + JSONObject geoIpJson = provider.getGeoIpJson(); + JSONArray gatewaylist = new JSONArray(); try { - gatewaysDefined = eipDefinition.getJSONArray(GATEWAYS); + gatewaylist = geoIpJson.getJSONArray(GATEWAYS); } catch (Exception e) { e.printStackTrace(); } - for (int i = 0; i < gatewaysDefined.length(); i++) { + for (int i = 0; i < gatewaylist.length(); i++) { try { - JSONObject gw = gatewaysDefined.getJSONObject(i); - Gateway aux = new Gateway(eipDefinition, secrets, gw, this.context); - if (gateways.get(aux.getRemoteIP()) == null) { - addGateway(aux); + String key = gatewaylist.getString(i); + if (gateways.containsKey(key)) { + presortedList.add(gateways.get(key)); } - } catch (JSONException | ConfigParser.ConfigParseError | IOException e) { + } catch (JSONException e) { e.printStackTrace(); - VpnStatus.logError("Unable to parse gateway config!"); } } } - private JSONObject secretsConfigurationFromPreferences() { - JSONObject result = new JSONObject(); - try { - result.put(Provider.CA_CERT, preferences.getString(Provider.CA_CERT, "")); - result.put(PROVIDER_PRIVATE_KEY, preferences.getString(PROVIDER_PRIVATE_KEY, "")); - result.put(PROVIDER_VPN_CERTIFICATE, preferences.getString(PROVIDER_VPN_CERTIFICATE, "")); - } catch (JSONException e) { - e.printStackTrace(); - } - return result; - } - private JSONObject secretsConfigurationFromCurrentProvider() { JSONObject result = new JSONObject(); Provider provider = ProviderObservable.getInstance().getCurrentProvider(); @@ -177,31 +208,13 @@ public class GatewaysManager { return result; } - - void clearGateways() { - gateways.clear(); - } - private void addGateway(Gateway gateway) { - gateways.put(gateway.getRemoteIP(), gateway); - } - - /** - * read EipServiceJson from preferences and set gateways - */ - private void configureFromPreferences() { - fromEipServiceJson( - PreferenceHelper.getEipDefinitionFromPreferences(preferences), secretsConfigurationFromPreferences() - ); + gateways.put(gateway.getHost(), gateway); } private void configureFromCurrentProvider() { - try { - JSONObject json = ProviderObservable.getInstance().getCurrentProvider().getEipServiceJson(); - fromEipServiceJson(json, secretsConfigurationFromCurrentProvider()); - } catch (NullPointerException npe) { - npe.printStackTrace(); - } - + Provider provider = ProviderObservable.getInstance().getCurrentProvider(); + parseDefaultGateways(provider); + parseGatewaysFromGeoIpServiceJson(provider); } } 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 669b7f8e..87bd5f93 100644 --- a/app/src/main/java/se/leap/bitmaskclient/utils/PreferenceHelper.java +++ b/app/src/main/java/se/leap/bitmaskclient/utils/PreferenceHelper.java @@ -47,6 +47,7 @@ public class PreferenceHelper { 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.setGeoipUrl(preferences.getString(Provider.GEOIP_URL, "")); provider.define(new JSONObject(preferences.getString(Provider.KEY, ""))); provider.setCaCert(preferences.getString(Provider.CA_CERT, "")); provider.setVpnCertificate(preferences.getString(PROVIDER_VPN_CERTIFICATE, "")); @@ -68,6 +69,7 @@ public class PreferenceHelper { public static void storeProviderInPreferences(SharedPreferences preferences, Provider provider) { preferences.edit().putBoolean(PROVIDER_CONFIGURED, true). putString(Provider.PROVIDER_IP, provider.getProviderIp()). + putString(Provider.GEOIP_URL, provider.getGeoipUrl().toString()). putString(Provider.PROVIDER_API_IP, provider.getProviderApiIp()). putString(Provider.MAIN_URL, provider.getMainUrlString()). putString(Provider.KEY, provider.getDefinitionString()). @@ -82,6 +84,7 @@ public class PreferenceHelper { putString(Provider.PROVIDER_IP + "." + providerDomain, provider.getProviderIp()). putString(Provider.PROVIDER_API_IP + "." + providerDomain, provider.getProviderApiIp()). putString(Provider.MAIN_URL + "." + providerDomain, provider.getMainUrlString()). + putString(Provider.GEOIP_URL + "." + providerDomain, provider.getGeoipUrl().toString()). putString(Provider.KEY + "." + providerDomain, provider.getDefinitionString()). putString(Provider.CA_CERT + "." + providerDomain, provider.getCaCert()). putString(PROVIDER_EIP_DEFINITION + "." + providerDomain, provider.getEipServiceJsonString()). @@ -114,6 +117,7 @@ public class PreferenceHelper { remove(Provider.PROVIDER_IP + "." + providerDomain). remove(Provider.PROVIDER_API_IP + "." + providerDomain). remove(Provider.MAIN_URL + "." + providerDomain). + remove(Provider.GEOIP_URL + "." + providerDomain). remove(PROVIDER_EIP_DEFINITION + "." + providerDomain). remove(PROVIDER_PRIVATE_KEY + "." + providerDomain). remove(PROVIDER_VPN_CERTIFICATE + "." + providerDomain). -- cgit v1.2.3 From 7b5ad7e802aae82b69ed8ecd916916e6545f01f2 Mon Sep 17 00:00:00 2001 From: cyBerta Date: Thu, 23 Jul 2020 17:03:15 +0200 Subject: always use provider from ProviderObservable if possible --- app/src/main/java/se/leap/bitmaskclient/StartActivity.java | 9 ++++----- .../main/java/se/leap/bitmaskclient/utils/PreferenceHelper.java | 3 --- 2 files changed, 4 insertions(+), 8 deletions(-) (limited to 'app/src/main') diff --git a/app/src/main/java/se/leap/bitmaskclient/StartActivity.java b/app/src/main/java/se/leap/bitmaskclient/StartActivity.java index b6ace6db..dd4878f3 100644 --- a/app/src/main/java/se/leap/bitmaskclient/StartActivity.java +++ b/app/src/main/java/se/leap/bitmaskclient/StartActivity.java @@ -21,9 +21,10 @@ import android.content.Intent; import android.content.SharedPreferences; import android.content.pm.PackageManager; import android.os.Bundle; +import android.util.Log; + import androidx.annotation.IntDef; import androidx.annotation.Nullable; -import android.util.Log; import java.lang.annotation.Retention; import java.lang.annotation.RetentionPolicy; @@ -40,8 +41,6 @@ import static se.leap.bitmaskclient.Constants.REQUEST_CODE_CONFIGURE_LEAP; import static se.leap.bitmaskclient.Constants.SHARED_PREFERENCES; import static se.leap.bitmaskclient.MainActivity.ACTION_SHOW_VPN_FRAGMENT; import static se.leap.bitmaskclient.utils.ConfigHelper.isDefaultBitmask; -import static se.leap.bitmaskclient.utils.PreferenceHelper.getSavedProviderFromSharedPreferences; -import static se.leap.bitmaskclient.utils.PreferenceHelper.providerInSharedPreferences; import static se.leap.bitmaskclient.utils.PreferenceHelper.storeProviderInPreferences; /** @@ -162,9 +161,9 @@ public class StartActivity extends Activity{ } private void prepareEIP() { - boolean providerExists = providerInSharedPreferences(preferences); + boolean providerExists = ProviderObservable.getInstance().getCurrentProvider() != null; if (providerExists) { - Provider provider = getSavedProviderFromSharedPreferences(preferences); + Provider provider = ProviderObservable.getInstance().getCurrentProvider(); if(!provider.isConfigured()) { configureLeapProvider(); } else { 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 87bd5f93..cb2aeb26 100644 --- a/app/src/main/java/se/leap/bitmaskclient/utils/PreferenceHelper.java +++ b/app/src/main/java/se/leap/bitmaskclient/utils/PreferenceHelper.java @@ -37,9 +37,6 @@ import static se.leap.bitmaskclient.Constants.USE_PLUGGABLE_TRANSPORTS; */ public class PreferenceHelper { - public static boolean providerInSharedPreferences(@NonNull SharedPreferences preferences) { - return preferences.getBoolean(PROVIDER_CONFIGURED, false); - } public static Provider getSavedProviderFromSharedPreferences(@NonNull SharedPreferences preferences) { Provider provider = new Provider(); -- cgit v1.2.3 From b92177a2d26f0f96671c848d26c79b08dca13f71 Mon Sep 17 00:00:00 2001 From: cyBerta Date: Thu, 23 Jul 2020 17:25:20 +0200 Subject: fix potential nullpointer exception in geoipservice json parsing --- .../se/leap/bitmaskclient/eip/GatewaysManager.java | 33 +++++++++++----------- 1 file changed, 16 insertions(+), 17 deletions(-) (limited to 'app/src/main') diff --git a/app/src/main/java/se/leap/bitmaskclient/eip/GatewaysManager.java b/app/src/main/java/se/leap/bitmaskclient/eip/GatewaysManager.java index e3932cb6..70d757d4 100644 --- a/app/src/main/java/se/leap/bitmaskclient/eip/GatewaysManager.java +++ b/app/src/main/java/se/leap/bitmaskclient/eip/GatewaysManager.java @@ -174,24 +174,23 @@ public class GatewaysManager { } private void parseGatewaysFromGeoIpServiceJson(Provider provider) { - JSONObject geoIpJson = provider.getGeoIpJson(); - JSONArray gatewaylist = new JSONArray(); - try { - gatewaylist = geoIpJson.getJSONArray(GATEWAYS); - } catch (Exception e) { - e.printStackTrace(); - } + try { + JSONObject geoIpJson = provider.getGeoIpJson(); + JSONArray gatewaylist = geoIpJson.getJSONArray(GATEWAYS); - for (int i = 0; i < gatewaylist.length(); i++) { - try { - String key = gatewaylist.getString(i); - if (gateways.containsKey(key)) { - presortedList.add(gateways.get(key)); - } - } catch (JSONException e) { - e.printStackTrace(); - } - } + for (int i = 0; i < gatewaylist.length(); i++) { + try { + String key = gatewaylist.getString(i); + if (gateways.containsKey(key)) { + presortedList.add(gateways.get(key)); + } + } catch (JSONException e) { + e.printStackTrace(); + } + } + } catch (NullPointerException | JSONException npe) { + npe.printStackTrace(); + } } private JSONObject secretsConfigurationFromCurrentProvider() { -- cgit v1.2.3 From ab6a95483e2c5f726d15216cbb32af0281334485 Mon Sep 17 00:00:00 2001 From: cyBerta Date: Fri, 24 Jul 2020 13:41:05 +0200 Subject: remove timestamps from providers equals() check and reset timestamps in reset method --- app/src/main/java/se/leap/bitmaskclient/Provider.java | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) (limited to 'app/src/main') diff --git a/app/src/main/java/se/leap/bitmaskclient/Provider.java b/app/src/main/java/se/leap/bitmaskclient/Provider.java index 9d1b0095..3aa66cc2 100644 --- a/app/src/main/java/se/leap/bitmaskclient/Provider.java +++ b/app/src/main/java/se/leap/bitmaskclient/Provider.java @@ -423,9 +423,7 @@ public final class Provider implements Parcelable { privateKey.equals(p.getPrivateKey()) && vpnCertificate.equals(p.getVpnCertificate()) && allowAnonymous == p.allowsAnonymous() && - allowRegistered == p.allowsRegistered() && - lastEipServiceUpdate == p.getLastEipServiceUpdate() && - lastGeoIpUpdate == p.getLastGeoIpUpdate(); + allowRegistered == p.allowsRegistered(); } else return false; } @@ -596,5 +594,7 @@ public final class Provider implements Parcelable { vpnCertificate = ""; allowRegistered = false; allowAnonymous = false; + lastGeoIpUpdate = 0L; + lastEipServiceUpdate = 0L; } } -- cgit v1.2.3 From 501a451b8b932e1f0e001599dbfe53810cb9ead0 Mon Sep 17 00:00:00 2001 From: cyBerta Date: Fri, 24 Jul 2020 15:41:17 +0200 Subject: adapt profile selection after perordered gateway list was introduced and use profiles mUsePluggableTransports flag instead of shared preferences to get the requested transport --- .../se/leap/bitmaskclient/eip/GatewaysManager.java | 28 +++++++++++++++++++--- 1 file changed, 25 insertions(+), 3 deletions(-) (limited to 'app/src/main') diff --git a/app/src/main/java/se/leap/bitmaskclient/eip/GatewaysManager.java b/app/src/main/java/se/leap/bitmaskclient/eip/GatewaysManager.java index 70d757d4..aa10ffae 100644 --- a/app/src/main/java/se/leap/bitmaskclient/eip/GatewaysManager.java +++ b/app/src/main/java/se/leap/bitmaskclient/eip/GatewaysManager.java @@ -70,7 +70,7 @@ public class GatewaysManager { Connection.TransportType transportType = getUsePluggableTransports(context) ? OBFS4 : OPENVPN; if (presortedList.size() > 0) { - return getGatewayFromPreorderedList(nClosest, transportType); + return getGatewayFromPresortedList(nClosest, transportType); } return getGatewayFromTimezoneCalculation(nClosest, transportType); @@ -90,7 +90,7 @@ public class GatewaysManager { return null; } - private Gateway getGatewayFromPreorderedList(int nClosest, Connection.TransportType transportType) { + private Gateway getGatewayFromPresortedList(int nClosest, Connection.TransportType transportType) { while (nClosest < presortedList.size()) { Gateway gateway = presortedList.get(nClosest); if (gateway.getProfile(transportType) != null) { @@ -107,7 +107,29 @@ public class GatewaysManager { * @return position of the gateway owning to the profile */ public int getPosition(VpnProfile profile) { - Connection.TransportType transportType = getUsePluggableTransports(context) ? OBFS4 : OPENVPN; + if (presortedList.size() > 0) { + return getPositionFromPresortedList(profile); + } + + return getPositionFromTimezoneCalculatedList(profile); + } + + private int getPositionFromPresortedList(VpnProfile profile) { + Connection.TransportType transportType = profile.mUsePluggableTransports ? OBFS4 : OPENVPN; + Gateway gateway; + int nClosest = 0; + while ((nClosest < presortedList.size())) { + gateway = presortedList.get(nClosest); + if (profile.equals(gateway.getProfile(transportType))) { + return nClosest; + } + nClosest++; + } + return -1; + } + + private int getPositionFromTimezoneCalculatedList(VpnProfile profile) { + Connection.TransportType transportType = profile.mUsePluggableTransports ? OBFS4 : OPENVPN; GatewaySelector gatewaySelector = new GatewaySelector(new ArrayList<>(gateways.values())); Gateway gateway; int nClosest = 0; -- cgit v1.2.3 From e986a294ec3e328bd48bb4c423fe835d1aa2dc69 Mon Sep 17 00:00:00 2001 From: cyBerta Date: Fri, 24 Jul 2020 16:30:02 +0200 Subject: fix bug in gateway selection - always iterate through all gateways and count those supporting the requested transport in order to get the nClosest gateway; adding more tests --- .../se/leap/bitmaskclient/eip/GatewaysManager.java | 21 ++++++++++++++------- 1 file changed, 14 insertions(+), 7 deletions(-) (limited to 'app/src/main') diff --git a/app/src/main/java/se/leap/bitmaskclient/eip/GatewaysManager.java b/app/src/main/java/se/leap/bitmaskclient/eip/GatewaysManager.java index aa10ffae..f3773758 100644 --- a/app/src/main/java/se/leap/bitmaskclient/eip/GatewaysManager.java +++ b/app/src/main/java/se/leap/bitmaskclient/eip/GatewaysManager.java @@ -81,22 +81,29 @@ public class GatewaysManager { List list = new ArrayList<>(gateways.values()); GatewaySelector gatewaySelector = new GatewaySelector(list); Gateway gateway; - while ((gateway = gatewaySelector.select(nClosest)) != null) { + int found = 0; + int i = 0; + while ((gateway = gatewaySelector.select(i)) != null) { if (gateway.getProfile(transportType) != null) { - return gateway; + if (found == nClosest) { + return gateway; + } + found++; } - nClosest++; + i++; } return null; } private Gateway getGatewayFromPresortedList(int nClosest, Connection.TransportType transportType) { - while (nClosest < presortedList.size()) { - Gateway gateway = presortedList.get(nClosest); + int found = 0; + for (Gateway gateway : presortedList) { if (gateway.getProfile(transportType) != null) { - return gateway; + if (found == nClosest) { + return gateway; + } + found++; } - nClosest++; } return null; } -- cgit v1.2.3 From d1ddaa7b10fde24b0b5f07369d1a22c221b81287 Mon Sep 17 00:00:00 2001 From: cyBerta Date: Fri, 24 Jul 2020 17:40:15 +0200 Subject: fix bug in vpn profile based gateway order detection, write additional tests for it --- .../java/se/leap/bitmaskclient/eip/Gateway.java | 4 ++++ .../se/leap/bitmaskclient/eip/GatewaysManager.java | 28 ++++++++++++---------- 2 files changed, 20 insertions(+), 12 deletions(-) (limited to 'app/src/main') diff --git a/app/src/main/java/se/leap/bitmaskclient/eip/Gateway.java b/app/src/main/java/se/leap/bitmaskclient/eip/Gateway.java index 589fa751..f3eea415 100644 --- a/app/src/main/java/se/leap/bitmaskclient/eip/Gateway.java +++ b/app/src/main/java/se/leap/bitmaskclient/eip/Gateway.java @@ -157,6 +157,10 @@ public class Gateway { return vpnProfiles.get(transportType); } + public boolean suppoortsTransport(Connection.TransportType transportType) { + return vpnProfiles.get(transportType) != null; + } + public int getTimezone() { return timezone; } diff --git a/app/src/main/java/se/leap/bitmaskclient/eip/GatewaysManager.java b/app/src/main/java/se/leap/bitmaskclient/eip/GatewaysManager.java index f3773758..0515a35e 100644 --- a/app/src/main/java/se/leap/bitmaskclient/eip/GatewaysManager.java +++ b/app/src/main/java/se/leap/bitmaskclient/eip/GatewaysManager.java @@ -84,7 +84,7 @@ public class GatewaysManager { int found = 0; int i = 0; while ((gateway = gatewaySelector.select(i)) != null) { - if (gateway.getProfile(transportType) != null) { + if (gateway.suppoortsTransport(transportType)) { if (found == nClosest) { return gateway; } @@ -98,7 +98,7 @@ public class GatewaysManager { private Gateway getGatewayFromPresortedList(int nClosest, Connection.TransportType transportType) { int found = 0; for (Gateway gateway : presortedList) { - if (gateway.getProfile(transportType) != null) { + if (gateway.suppoortsTransport(transportType)) { if (found == nClosest) { return gateway; } @@ -123,14 +123,14 @@ public class GatewaysManager { private int getPositionFromPresortedList(VpnProfile profile) { Connection.TransportType transportType = profile.mUsePluggableTransports ? OBFS4 : OPENVPN; - Gateway gateway; int nClosest = 0; - while ((nClosest < presortedList.size())) { - gateway = presortedList.get(nClosest); - if (profile.equals(gateway.getProfile(transportType))) { - return nClosest; + for (Gateway gateway : presortedList) { + if (gateway.suppoortsTransport(transportType)) { + if (profile.equals(gateway.getProfile(transportType))) { + return nClosest; + } + nClosest++; } - nClosest++; } return -1; } @@ -140,11 +140,15 @@ public class GatewaysManager { GatewaySelector gatewaySelector = new GatewaySelector(new ArrayList<>(gateways.values())); Gateway gateway; int nClosest = 0; - while ((gateway = gatewaySelector.select(nClosest)) != null) { - if (profile.equals(gateway.getProfile(transportType))) { - return nClosest; + int i = 0; + while ((gateway = gatewaySelector.select(i)) != null) { + if (gateway.suppoortsTransport(transportType)) { + if (profile.equals(gateway.getProfile(transportType))) { + return nClosest; + } + nClosest++; } - nClosest++; + i++; } return -1; } -- cgit v1.2.3 From fa0ff0970173908acc9ab2b37d4d4cc2d67c1597 Mon Sep 17 00:00:00 2001 From: cyBerta Date: Fri, 24 Jul 2020 17:48:46 +0200 Subject: remove unused methods --- app/src/main/java/se/leap/bitmaskclient/Provider.java | 8 -------- 1 file changed, 8 deletions(-) (limited to 'app/src/main') diff --git a/app/src/main/java/se/leap/bitmaskclient/Provider.java b/app/src/main/java/se/leap/bitmaskclient/Provider.java index 3aa66cc2..186ce11e 100644 --- a/app/src/main/java/se/leap/bitmaskclient/Provider.java +++ b/app/src/main/java/se/leap/bitmaskclient/Provider.java @@ -479,10 +479,6 @@ public final class Provider implements Parcelable { lastEipServiceUpdate = timestamp; } - public long getLastEipServiceUpdate() { - return lastEipServiceUpdate; - } - public boolean shouldUpdateEipServiceJson() { return System.currentTimeMillis() - lastEipServiceUpdate >= EIP_SERVICE_TIMEOUT; } @@ -492,10 +488,6 @@ public final class Provider implements Parcelable { lastGeoIpUpdate = timestamp; } - public long getLastGeoIpUpdate() { - return lastGeoIpUpdate; - } - public boolean shouldUpdateGeoIpJson() { return System.currentTimeMillis() - lastGeoIpUpdate >= GEOIP_SERVICE_TIMEOUT; } -- cgit v1.2.3