summaryrefslogtreecommitdiff
path: root/app/src/main/java
diff options
context:
space:
mode:
authorcyBerta <cyberta@riseup.net>2020-07-23 16:56:41 +0200
committercyBerta <cyberta@riseup.net>2020-07-23 16:56:41 +0200
commit49b18fcdc45433d34eefb46ab236144e19022dcb (patch)
tree891521f590ce55c54371c0f5261c764d2478244a /app/src/main/java
parent015d8f9f512b5020d380aadf4af70a89a4b3dc42 (diff)
implement gateway selection based on geoip service
Diffstat (limited to 'app/src/main/java')
-rw-r--r--app/src/main/java/se/leap/bitmaskclient/Constants.java1
-rw-r--r--app/src/main/java/se/leap/bitmaskclient/EipFragment.java29
-rw-r--r--app/src/main/java/se/leap/bitmaskclient/EipSetupObserver.java23
-rw-r--r--app/src/main/java/se/leap/bitmaskclient/Provider.java164
-rw-r--r--app/src/main/java/se/leap/bitmaskclient/ProviderAPI.java10
-rw-r--r--app/src/main/java/se/leap/bitmaskclient/ProviderAPICommand.java10
-rw-r--r--app/src/main/java/se/leap/bitmaskclient/ProviderApiManagerBase.java44
-rw-r--r--app/src/main/java/se/leap/bitmaskclient/eip/EIP.java13
-rw-r--r--app/src/main/java/se/leap/bitmaskclient/eip/Gateway.java5
-rw-r--r--app/src/main/java/se/leap/bitmaskclient/eip/GatewaysManager.java125
-rw-r--r--app/src/main/java/se/leap/bitmaskclient/utils/PreferenceHelper.java4
11 files changed, 287 insertions, 141 deletions
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)) {
@@ -310,15 +310,6 @@ public final class EIP extends JobIntentService implements Observer {
}
/**
- * 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<String, Gateway> gateways = new LinkedHashMap<>();
private Type listType = new TypeToken<ArrayList<Gateway>>() {}.getType();
-
- public GatewaysManager(Context context, SharedPreferences preferences) {
- this.preferences = preferences;
- this.context = context;
- configureFromPreferences();
- }
+ private ArrayList<Gateway> 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<Gateway> 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).