diff options
31 files changed, 845 insertions, 261 deletions
| diff --git a/app/build.gradle b/app/build.gradle index 6c236669..088be987 100644 --- a/app/build.gradle +++ b/app/build.gradle @@ -41,6 +41,7 @@ android {      buildConfigField "String", "customProviderUrl", '""'      buildConfigField "String", "customProviderIp", '""'      buildConfigField "String", "customProviderApiIp", '""' +    buildConfigField "String", "geoipUrl", '""'      testInstrumentationRunner "androidx.test.runner.AndroidJUnitRunner"      dexOptions { @@ -97,6 +98,8 @@ android {        //static ip address of the provider api, using a self signed certificate to serve provider.json, eip-service.json etc.        def customProviderApiIp = '"198.252.153.107"'        buildConfigField "String", "customProviderApiIp", customProviderApiIp +      def geoipUrl = '"https://api.black.riseup.net:9001/json"' +      buildConfigField "String", "geoipUrl", geoipUrl        //Change the versionCode as needed        //versionCode 1        //Change the versionName as needed diff --git a/app/src/insecure/java/se/leap/bitmaskclient/ProviderApiManager.java b/app/src/insecure/java/se/leap/bitmaskclient/ProviderApiManager.java index b67f6fa5..a111e907 100644 --- a/app/src/insecure/java/se/leap/bitmaskclient/ProviderApiManager.java +++ b/app/src/insecure/java/se/leap/bitmaskclient/ProviderApiManager.java @@ -136,15 +136,14 @@ public class ProviderApiManager extends ProviderApiManagerBase {      private Bundle getAndSetProviderJson(Provider provider, boolean dangerOn) {          Bundle result = new Bundle(); -        String caCert = provider.getCaCert();          JSONObject providerDefinition = provider.getDefinition();          String providerMainUrl = provider.getMainUrlString();          String providerDotJsonString; -        if(providerDefinition.length() == 0 || caCert.isEmpty()) +        if(providerDefinition.length() == 0 || provider.getCaCert().isEmpty())              providerDotJsonString = downloadWithCommercialCA(providerMainUrl + "/provider.json", dangerOn);          else -            providerDotJsonString = downloadFromApiUrlWithProviderCA("/provider.json", caCert, provider, dangerOn); +            providerDotJsonString = downloadFromApiUrlWithProviderCA("/provider.json", provider, dangerOn);          if (ConfigHelper.checkErroneousDownload(providerDotJsonString) || !isValidJson(providerDotJsonString)) {              setErrorResult(result, malformed_url, null); @@ -230,6 +229,44 @@ public class ProviderApiManager extends ProviderApiManagerBase {          return result;      } +    /** +     * Fetches the Geo ip Json, containing a list of gateways sorted by distance from the users current location +     * +     * @param provider +     * @return +     */ +    @Override +    protected Bundle getGeoIPJson(Provider provider) { +        Bundle result = new Bundle(); + +        if (!provider.shouldUpdateGeoIpJson() || provider.getGeoipUrl().isDefault()) { +            result.putBoolean(BROADCAST_RESULT_KEY, false); +            return result; +        } + + +        try { +            URL geoIpUrl = provider.getGeoipUrl().getUrl(); + +            String geoipJsonString = downloadFromUrlWithProviderCA(geoIpUrl.toString(), provider, lastDangerOn); +            JSONObject geoipJson = new JSONObject(geoipJsonString); + +            if (geoipJson.has(ERRORS)) { +                result.putBoolean(BROADCAST_RESULT_KEY, false); +            } else { +                provider.setGeoIpJson(geoipJson); +                provider.setLastEipServiceUpdate(System.currentTimeMillis()); +                result.putBoolean(BROADCAST_RESULT_KEY, true); +            } + + +        } catch (JSONException | NullPointerException e) { +            result.putBoolean(BROADCAST_RESULT_KEY, false); +            e.printStackTrace(); +        } +        return result; +    } +      private Bundle downloadCACert(Provider provider, boolean dangerOn) {          Bundle result = new Bundle(); @@ -291,16 +328,21 @@ public class ProviderApiManager extends ProviderApiManagerBase {          return responseString;      } -    private String downloadFromApiUrlWithProviderCA(String path, String caCert, Provider provider, boolean dangerOn) { +    private String downloadFromApiUrlWithProviderCA(String path, Provider provider, boolean dangerOn) { +        String baseUrl = provider.getApiUrlString(); +        String urlString = baseUrl + path; + +        return downloadFromUrlWithProviderCA(urlString, provider, dangerOn); +    } + +    private String downloadFromUrlWithProviderCA(String urlString, Provider provider, boolean dangerOn) {          String responseString;          JSONObject errorJson = new JSONObject(); -        String baseUrl = provider.getApiUrlString(); -        OkHttpClient okHttpClient = clientGenerator.initSelfSignedCAHttpClient(caCert, errorJson); +        OkHttpClient okHttpClient = clientGenerator.initSelfSignedCAHttpClient(provider.getCaCert(), errorJson);          if (okHttpClient == null) {              return errorJson.toString();          } -        String urlString = baseUrl + path;          List<Pair<String, String>> headerArgs = getAuthorizationHeader();          responseString = sendGetStringToServer(urlString, headerArgs, okHttpClient); 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 4dd7c76e..186ce11e 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,10 +45,13 @@ 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();      private String providerIp = "";      private String providerApiIp = "";      private String certificatePin = ""; @@ -59,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; @@ -78,21 +81,31 @@ 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();          } +        setGeoipUrl(geoipUrl);      }      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 +116,14 @@ public final class Provider implements Parcelable {              }          } catch (MalformedURLException e) {              e.printStackTrace(); +            return;          } +        setGeoipUrl(geoipUrl);      } -    public Provider(String mainUrl, String providerIp, String providerApiIp, String caCert, String definition) { -        try { -            this.mainUrl.setUrl(new URL(mainUrl)); -        } catch (MalformedURLException e) { -            e.printStackTrace(); -        } -        if (this.providerIp != null) { -            this.providerIp = providerIp; -        } -        if (this.providerApiIp != null) { -            this.providerApiIp = providerApiIp; -        } + +    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;          } @@ -240,6 +246,18 @@ public final class Provider implements Parcelable {      protected DefaultedURL getApiUrl() {          return apiUrl;      } +  +    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(); @@ -262,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; @@ -321,56 +343,17 @@ 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()); +        parcel.writeString(getGeoIpJsonString());          parcel.writeString(getPrivateKey());          parcel.writeString(getVpnCertificate());          parcel.writeLong(lastEipServiceUpdate); +        parcel.writeLong(lastGeoIpUpdate);      } -    @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()) && -            providerIp.equals(p.getProviderIp()) && -            providerApiIp.equals(p.getProviderApiIp()) && -            apiUrl.equals(p.getApiUrl()) && -            certificatePin.equals(p.getCertificatePin()) && -            certificatePinEncoding.equals(p.getCertificatePinEncoding()) && -            caCert.equals(p.getCaCert()) && -            apiVersion.equals(p.getApiVersion()) && -            privateKey.equals(p.getPrivateKey()) && -            vpnCertificate.equals(p.getVpnCertificate()) && -            allowAnonymous == p.allowsAnonymous() && -            allowRegistered == p.allowsRegistered() && -            lastEipServiceUpdate == p.getLastEipServiceUpdate(); -        } else return false; -    } - -    public JSONObject toJson() { -        JSONObject json = new JSONObject(); -        try { -            json.put(Provider.MAIN_URL, mainUrl); -        } catch (JSONException e) { -            e.printStackTrace(); -        } -        return json; -    } - -    @Override -    public int hashCode() { -        return getDomain().hashCode(); -    } - -    @Override -    public String toString() { -        return new Gson().toJson(this); -    }      //TODO: write a test for marshalling!      private Provider(Parcel in) { @@ -386,6 +369,10 @@ public final class Provider implements Parcelable {              }              tmpString = in.readString();              if (!tmpString.isEmpty()) { +                geoipUrl.setUrl(new URL(tmpString)); +            } +            tmpString = in.readString(); +            if (!tmpString.isEmpty()) {                  definition = new JSONObject((tmpString));                  parseDefinition(definition);              } @@ -399,6 +386,10 @@ public final class Provider implements Parcelable {              }              tmpString = in.readString();              if (!tmpString.isEmpty()) { +                this.setGeoIpJson(new JSONObject(tmpString)); +            } +            tmpString = in.readString(); +            if (!tmpString.isEmpty()) {                  this.setPrivateKey(tmpString);              }              tmpString = in.readString(); @@ -406,11 +397,57 @@ public final class Provider implements Parcelable {                  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.getEipServiceJsonString()) && +            geoIpJson.toString().equals(p.getGeoIpJsonString()) && +            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()) && +            apiVersion.equals(p.getApiVersion()) && +            privateKey.equals(p.getPrivateKey()) && +            vpnCertificate.equals(p.getVpnCertificate()) && +            allowAnonymous == p.allowsAnonymous() && +            allowRegistered == p.allowsRegistered(); +        } else return false; +    } + + +    public JSONObject toJson() { +        JSONObject json = new JSONObject(); +        try { +            json.put(Provider.MAIN_URL, mainUrl); +        } catch (JSONException e) { +            e.printStackTrace(); +        } +        return json; +    } + +    @Override +    public int hashCode() { +        return getDomain().hashCode(); +    } + +    @Override +    public String toString() { +        return new Gson().toJson(this); +    } +      private boolean parseDefinition(JSONObject definition) {          try {              String pin =  definition.getString(CA_CERT_FINGERPRINT); @@ -442,14 +479,20 @@ public final class Provider implements Parcelable {          lastEipServiceUpdate = timestamp;      } -    public long getLastEipServiceUpdate() { -        return lastEipServiceUpdate; -    } -      public boolean shouldUpdateEipServiceJson() {          return System.currentTimeMillis() - lastEipServiceUpdate >= EIP_SERVICE_TIMEOUT;      } + +    public void setLastGeoIpUpdate(long timestamp) { +        lastGeoIpUpdate = timestamp; +    } + +    public boolean shouldUpdateGeoIpJson() { +        return System.currentTimeMillis() - lastGeoIpUpdate >= GEOIP_SERVICE_TIMEOUT; +    } + +      public boolean setEipServiceJson(JSONObject eipServiceJson) {          if (eipServiceJson.has(ERRORS)) {              return false; @@ -458,16 +501,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(); @@ -515,6 +576,7 @@ public final class Provider implements Parcelable {      public void reset() {          definition = new JSONObject();          eipServiceJson = new JSONObject(); +        geoIpJson = new JSONObject();          apiUrl = new DefaultedURL();          certificatePin = "";          certificatePinEncoding = ""; @@ -524,5 +586,7 @@ public final class Provider implements Parcelable {          vpnCertificate = "";          allowRegistered = false;          allowAnonymous = false; +        lastGeoIpUpdate = 0L; +        lastEipServiceUpdate = 0L;      }  } diff --git a/app/src/main/java/se/leap/bitmaskclient/ProviderAPI.java b/app/src/main/java/se/leap/bitmaskclient/ProviderAPI.java index 9d34b38f..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,6 +49,7 @@ 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", @@ -77,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; @@ -99,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/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<Provider> {                  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; 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/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..f3eea415 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); @@ -152,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 fbe1861a..0515a35e 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,13 +68,42 @@ 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 getGatewayFromPresortedList(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) { -                return gateway; +        int found  = 0; +        int i = 0; +        while ((gateway = gatewaySelector.select(i)) != null) { +            if (gateway.suppoortsTransport(transportType)) { +                if (found == nClosest) { +                    return gateway; +                } +                found++; +            } +            i++; +        } +        return null; +    } + +    private Gateway getGatewayFromPresortedList(int nClosest, Connection.TransportType transportType) { +        int found = 0; +        for (Gateway gateway : presortedList) { +            if (gateway.suppoortsTransport(transportType)) { +                if (found == nClosest) { +                    return gateway; +                } +                found++;              } -            nClosest++;          }          return null;      } @@ -92,15 +114,41 @@ 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; +        int nClosest = 0; +        for (Gateway gateway : presortedList) { +            if (gateway.suppoortsTransport(transportType)) { +                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; -        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;      } @@ -126,41 +174,56 @@ 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(); -        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.getRemoteIP()) == null) { -                    addGateway(aux); -                } -            } catch (JSONException | ConfigParser.ConfigParseError | IOException e) { -                e.printStackTrace(); -                VpnStatus.logError("Unable to parse gateway config!"); -            } -        } +     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 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 void parseGatewaysFromGeoIpServiceJson(Provider provider) { +         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(); +                 } +             } +         } catch (NullPointerException | JSONException npe) { +             npe.printStackTrace(); +         }      }      private JSONObject secretsConfigurationFromCurrentProvider() { @@ -177,31 +240,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..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(); @@ -47,6 +44,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 +66,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 +81,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 +114,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). diff --git a/app/src/normal/assets/urls/riseup.net.url b/app/src/normal/assets/urls/riseup.net.url index a4a90f90..3c1e6b49 100644 --- a/app/src/normal/assets/urls/riseup.net.url +++ b/app/src/normal/assets/urls/riseup.net.url @@ -1,5 +1,6 @@  {  	"main_url" : "https://riseup.net",  	"provider_ip" : "198.252.153.70", -	"provider_api_ip" : "198.252.153.107" +	"provider_api_ip" : "198.252.153.107", +	"geoip_url" : "https://api.black.riseup.net:9001/json"  } diff --git a/app/src/production/java/se/leap/bitmaskclient/ProviderApiManager.java b/app/src/production/java/se/leap/bitmaskclient/ProviderApiManager.java index ceaeebc0..04ffe9e6 100644 --- a/app/src/production/java/se/leap/bitmaskclient/ProviderApiManager.java +++ b/app/src/production/java/se/leap/bitmaskclient/ProviderApiManager.java @@ -20,9 +20,10 @@ package se.leap.bitmaskclient;  import android.content.SharedPreferences;  import android.content.res.Resources;  import android.os.Bundle; -import androidx.multidex.BuildConfig;  import android.util.Pair; +import androidx.multidex.BuildConfig; +  import org.json.JSONException;  import org.json.JSONObject; @@ -58,6 +59,8 @@ import static se.leap.bitmaskclient.utils.ConfigHelper.getProviderFormattedStrin  public class ProviderApiManager extends ProviderApiManagerBase { +    private static final String TAG = ProviderApiManager.class.getSimpleName(); +      public ProviderApiManager(SharedPreferences preferences, Resources resources, OkHttpClientGenerator clientGenerator, ProviderApiServiceCallback callback) {          super(preferences, resources, clientGenerator, callback);      } @@ -120,14 +123,12 @@ public class ProviderApiManager extends ProviderApiManagerBase {      private Bundle getAndSetProviderJson(Provider provider) {          Bundle result = new Bundle(); -        String caCert = provider.getCaCert(); -          String providerDotJsonString; -        if(provider.getDefinitionString().length() == 0 || caCert.isEmpty()) { +        if(provider.getDefinitionString().length() == 0 || provider.getCaCert().isEmpty()) {              String providerJsonUrl = provider.getMainUrlString() + "/provider.json";              providerDotJsonString = downloadWithCommercialCA(providerJsonUrl, provider);          } else { -            providerDotJsonString = downloadFromApiUrlWithProviderCA("/provider.json", caCert, provider); +            providerDotJsonString = downloadFromApiUrlWithProviderCA("/provider.json", provider);          }          if (ConfigHelper.checkErroneousDownload(providerDotJsonString) || !isValidJson(providerDotJsonString)) { @@ -214,6 +215,43 @@ public class ProviderApiManager extends ProviderApiManagerBase {          return result;      } +    /** +     * Fetches the Geo ip Json, containing a list of gateways sorted by distance from the users current location +     * +     * @param provider +     * @return +     */ +    @Override +    protected Bundle getGeoIPJson(Provider provider) { +        Bundle result = new Bundle(); + +        if (!provider.shouldUpdateGeoIpJson() || provider.getGeoipUrl().isDefault()) { +            result.putBoolean(BROADCAST_RESULT_KEY, false); +            return result; +        } + +        try { +            URL geoIpUrl = provider.getGeoipUrl().getUrl(); + +            String geoipJsonString = downloadFromUrlWithProviderCA(geoIpUrl.toString(), provider); +            JSONObject geoipJson = new JSONObject(geoipJsonString); + +            if (geoipJson.has(ERRORS)) { +                result.putBoolean(BROADCAST_RESULT_KEY, false); +            } else{ +                provider.setGeoIpJson(geoipJson); +                provider.setLastGeoIpUpdate(System.currentTimeMillis()); +                result.putBoolean(BROADCAST_RESULT_KEY, true); +            } + +        } catch (JSONException | NullPointerException e) { +            result.putBoolean(BROADCAST_RESULT_KEY, false); +            e.printStackTrace(); +        } +        return result; +    } + +      private Bundle downloadCACert(Provider provider) {          Bundle result = new Bundle();          try { @@ -276,30 +314,33 @@ public class ProviderApiManager extends ProviderApiManagerBase {       *       * @return an empty string if it fails, the response body if not.       */ -    private String downloadFromApiUrlWithProviderCA(String path, String caCert, Provider provider) { +    private String downloadFromApiUrlWithProviderCA(String path, Provider provider) { +        String baseUrl = provider.getApiUrlString(); +        String urlString = baseUrl + path; +        return downloadFromUrlWithProviderCA(urlString, provider); +    } + +    private String downloadFromUrlWithProviderCA(String urlString, Provider provider) {          String responseString;          JSONObject errorJson = new JSONObject(); -        String baseUrl = provider.getApiUrlString(); -        OkHttpClient okHttpClient = clientGenerator.initSelfSignedCAHttpClient(caCert, errorJson); +        OkHttpClient okHttpClient = clientGenerator.initSelfSignedCAHttpClient(provider.getCaCert(), errorJson);          if (okHttpClient == null) {              return errorJson.toString();          } -        String urlString = baseUrl + path;          List<Pair<String, String>> headerArgs = getAuthorizationHeader();          responseString = sendGetStringToServer(urlString, headerArgs, okHttpClient);          return responseString; -      } -    /** -     * Tries to download the contents of the provided url using not commercially validated CA certificate from chosen provider. -     * -     * @param urlString as a string -     * @return an empty string if it fails, the url content if not. -     */ +        /** +         * Tries to download the contents of the provided url using not commercially validated CA certificate from chosen provider. +         * +         * @param urlString as a string +         * @return an empty string if it fails, the url content if not. +         */      private String downloadWithProviderCA(String caCert, String urlString) {          JSONObject initError = new JSONObject();          String responseString; diff --git a/app/src/sharedTest/java/se.leap.bitmaskclient/testutils/TestSetupHelper.java b/app/src/sharedTest/java/se.leap.bitmaskclient/testutils/TestSetupHelper.java index c7c85f8d..c741faf2 100644 --- a/app/src/sharedTest/java/se.leap.bitmaskclient/testutils/TestSetupHelper.java +++ b/app/src/sharedTest/java/se.leap.bitmaskclient/testutils/TestSetupHelper.java @@ -51,12 +51,14 @@ public class TestSetupHelper {      public static Provider getConfiguredProvider() throws IOException, JSONException { -        return getProvider(null,  null, null, null, null, null); +        return getProvider(null,  null, null, null, null, null, null, null);      } -    public static Provider getProvider(String domain, String providerIp, String providerApiIp, String caCertFile, String providerJson, String eipServiceJson) { +    public static Provider getProvider(String domain, String geoipUrl, String providerIp, String providerApiIp, String caCertFile, String providerJson, String eipServiceJson, String geoIpJson) {          if (domain == null)              domain = "https://riseup.net"; +        if (geoipUrl == null) +            geoipUrl = "https://api.black.riseup.net:9001/json";          if (providerIp == null) {              providerIp = "";          } @@ -70,10 +72,14 @@ public class TestSetupHelper {          if (eipServiceJson == null) {              eipServiceJson = "riseup.service.json";          } +        if (geoIpJson == null) { +            geoIpJson = "riseup.geoip.json"; +        }          try {              Provider p = new Provider(                      domain, +                    geoipUrl,                      providerIp,                      providerApiIp,                      getInputAsString(TestSetupHelper.class.getClassLoader().getResourceAsStream(caCertFile)), @@ -83,6 +89,10 @@ public class TestSetupHelper {              JSONObject eipServiceJsonObject = new JSONObject(                      getInputAsString(TestSetupHelper.class.getClassLoader().getResourceAsStream(eipServiceJson)));              p.setEipServiceJson(eipServiceJsonObject); + +            JSONObject geoIpJsonObject = new JSONObject( +                    getInputAsString(TestSetupHelper.class.getClassLoader().getResourceAsStream(geoIpJson))); +            p.setGeoIpJson(geoIpJsonObject);              return p;          } catch (IOException | JSONException e) {              e.printStackTrace(); diff --git a/app/src/test/java/se/leap/bitmaskclient/PreferenceHelperTest.java b/app/src/test/java/se/leap/bitmaskclient/PreferenceHelperTest.java index d49fa08c..edac3480 100644 --- a/app/src/test/java/se/leap/bitmaskclient/PreferenceHelperTest.java +++ b/app/src/test/java/se/leap/bitmaskclient/PreferenceHelperTest.java @@ -6,18 +6,14 @@ import org.junit.Before;  import org.junit.Test;  import se.leap.bitmaskclient.testutils.MockSharedPreferences; -import se.leap.bitmaskclient.utils.ConfigHelper; -import se.leap.bitmaskclient.utils.PreferenceHelper;  import static org.junit.Assert.assertFalse;  import static org.junit.Assert.assertTrue; -import static se.leap.bitmaskclient.Constants.PROVIDER_CONFIGURED;  import static se.leap.bitmaskclient.Constants.PROVIDER_EIP_DEFINITION;  import static se.leap.bitmaskclient.Constants.PROVIDER_PRIVATE_KEY;  import static se.leap.bitmaskclient.Constants.PROVIDER_VPN_CERTIFICATE;  import static se.leap.bitmaskclient.testutils.TestSetupHelper.getInputAsString;  import static se.leap.bitmaskclient.utils.PreferenceHelper.getSavedProviderFromSharedPreferences; -import static se.leap.bitmaskclient.utils.PreferenceHelper.providerInSharedPreferences;  /**   * Created by cyberta on 17.01.18. @@ -33,17 +29,6 @@ public class PreferenceHelperTest {      }      @Test -    public void providerInSharedPreferences_notInPreferences_returnsFalse() throws Exception { -        assertFalse(providerInSharedPreferences(mockPreferences)); -    } - -    @Test -    public void providerInSharedPreferences_inPreferences_returnsTrue() throws Exception { -        mockPreferences.edit().putBoolean(PROVIDER_CONFIGURED, true).apply(); -        assertTrue(providerInSharedPreferences(mockPreferences)); -    } - -    @Test      public void getSavedProviderFromSharedPreferences_notInPreferences_returnsDefaultProvider() throws Exception {          Provider provider = getSavedProviderFromSharedPreferences(mockPreferences);          assertFalse(provider.isConfigured()); diff --git a/app/src/test/java/se/leap/bitmaskclient/ProviderTest.java b/app/src/test/java/se/leap/bitmaskclient/ProviderTest.java index 0f9d358e..8a74e5de 100644 --- a/app/src/test/java/se/leap/bitmaskclient/ProviderTest.java +++ b/app/src/test/java/se/leap/bitmaskclient/ProviderTest.java @@ -23,13 +23,21 @@ public class ProviderTest {      }      @Test -    public void testEquals_sameFields_returnsFalse() throws Exception { +    public void testEquals_differntMainUrl_returnsFalse() throws Exception {          Provider p1 = TestSetupHelper.getConfiguredProvider();          Provider p2 = TestSetupHelper.getConfiguredProvider();          p2.setMainUrl("http://somethingsdiffer.org");          assertFalse("Providers should be same:", p1.equals(p2));      } +    @Test +    public void testEquals_differentGeoIpUrl_returnsFalse() throws Exception { +        Provider p1 = TestSetupHelper.getConfiguredProvider(); +        Provider p2 = TestSetupHelper.getConfiguredProvider(); +        p2.setGeoipUrl(null); +        assertFalse("Providers should be same:", p1.equals(p2)); +    } +      // see ProviderManagerTest testing add(...)      @Test      public void testEqualsThroughSetContains_differentFields_returnsFalse() throws Exception { @@ -55,7 +63,9 @@ public class ProviderTest {                  null,                  null,                  null, -                "ptdemo.bitmask.eip-service.json"); +                null, +                "ptdemo.bitmask.eip-service.json", +                null);          assertTrue(p1.supportsPluggableTransports());      } @@ -67,7 +77,9 @@ public class ProviderTest {                  null,                  null,                  null, -                "eip-service-two-gateways.json"); +                null, +                "eip-service-two-gateways.json", +                null);          assertFalse(p1.supportsPluggableTransports());      } diff --git a/app/src/test/java/se/leap/bitmaskclient/eip/GatewaysManagerTest.java b/app/src/test/java/se/leap/bitmaskclient/eip/GatewaysManagerTest.java index 417c4bfc..bfe96d2c 100644 --- a/app/src/test/java/se/leap/bitmaskclient/eip/GatewaysManagerTest.java +++ b/app/src/test/java/se/leap/bitmaskclient/eip/GatewaysManagerTest.java @@ -74,29 +74,6 @@ public class GatewaysManagerTest {                  .commit();      } -    @Test -    public void testFromEipServiceJson_emptyJson() throws Exception { -        GatewaysManager gatewaysManager = new GatewaysManager(mockContext, sharedPreferences); -        assertEquals(0, gatewaysManager.size()); -    } - -    @Test -    public void testFromEipServiceJson_ignoreGatewaysWithMisconfiguredTransportsWhileAddingValidOnes() throws Exception { -        updateEipServiceJson("ptdemo_misconfigured_mixed_gateways.json"); -        GatewaysManager gatewaysManager = new GatewaysManager(mockContext, sharedPreferences); -        assertEquals(1, gatewaysManager.size()); -        assertNull(gatewaysManager.select(0).getProfile(OBFS4)); -        assertNotNull(gatewaysManager.select(0).getProfile(Connection.TransportType.OPENVPN)); -    } - -    @Test -    public void testClearGatewaysAndProfiles_resetGateways() throws Exception { -        updateEipServiceJson("eip-service-two-gateways.json"); -        GatewaysManager gatewaysManager = new GatewaysManager(mockContext, sharedPreferences); -        assertEquals(2, gatewaysManager.size()); -        gatewaysManager.clearGateways(); -        assertEquals(0, gatewaysManager.size()); -    }      @Test      public void testGatewayManagerFromCurrentProvider_noProvider_noGateways() { @@ -107,7 +84,7 @@ public class GatewaysManagerTest {      @Test      public void testGatewayManagerFromCurrentProvider_misconfiguredProvider_noGateways() throws IOException, NullPointerException { -        Provider provider = getProvider(null, null, null, null, null, "ptdemo_misconfigured_gateway.json"); +        Provider provider = getProvider(null, null, null, null, null, null, "ptdemo_misconfigured_gateway.json", null);          MockHelper.mockProviderObserver(provider);          GatewaysManager gatewaysManager = new GatewaysManager(mockContext);          assertEquals(0, gatewaysManager.size()); @@ -115,7 +92,7 @@ public class GatewaysManagerTest {      @Test      public void testGatewayManagerFromCurrentProvider_threeGateways() { -        Provider provider = getProvider(null, null, null,null, null, "ptdemo_three_mixed_gateways.json"); +        Provider provider = getProvider(null, null, null, null,null, null, "ptdemo_three_mixed_gateways.json", null);          MockHelper.mockProviderObserver(provider);          GatewaysManager gatewaysManager = new GatewaysManager(mockContext);          assertEquals(3, gatewaysManager.size()); @@ -123,12 +100,10 @@ public class GatewaysManagerTest {      @Test      public void TestGetPosition_VpnProfileExtistingObfs4_returnPositionZero() throws JSONException, ConfigParser.ConfigParseError, IOException { -        Provider provider = getProvider(null, null, null, null, null, "ptdemo_three_mixed_gateways.json"); +        Provider provider = getProvider(null, null, null, null, null, null, "ptdemo_three_mixed_gateways.json", null);          JSONObject eipServiceJson = provider.getEipServiceJson();          JSONObject gateway1 = eipServiceJson.getJSONArray(GATEWAYS).getJSONObject(0);          MockHelper.mockProviderObserver(provider); -        mockStatic(PreferenceHelper.class); -        when(PreferenceHelper.getUsePluggableTransports(any(Context.class))).thenReturn(true);          GatewaysManager gatewaysManager = new GatewaysManager(mockContext);          VpnConfigGenerator configGenerator = new VpnConfigGenerator(provider.getDefinition(), secrets, gateway1, 3); @@ -140,12 +115,10 @@ public class GatewaysManagerTest {      @Test      public void TestGetPosition_VpnProfileExtistingOpenvpn_returnPositionZero() throws JSONException, ConfigParser.ConfigParseError, IOException { -        Provider provider = getProvider(null, null, null, null, null, "ptdemo_three_mixed_gateways.json"); +        Provider provider = getProvider(null, null, null, null, null, null, "ptdemo_three_mixed_gateways.json", null);          JSONObject eipServiceJson = provider.getEipServiceJson();          JSONObject gateway1 = eipServiceJson.getJSONArray(GATEWAYS).getJSONObject(0);          MockHelper.mockProviderObserver(provider); -        mockStatic(PreferenceHelper.class); -        when(PreferenceHelper.getUsePluggableTransports(any(Context.class))).thenReturn(false);          GatewaysManager gatewaysManager = new GatewaysManager(mockContext);          VpnConfigGenerator configGenerator = new VpnConfigGenerator(provider.getDefinition(), secrets, gateway1, 3); @@ -156,13 +129,41 @@ public class GatewaysManagerTest {      }      @Test +    public void TestGetPosition_VpnProfileExistingObfs4FromPresortedList_returnsPositionOne() throws JSONException, ConfigParser.ConfigParseError, IOException { +        Provider provider = getProvider(null, null, null, null, null, null, "ptdemo_three_mixed_gateways.json", "ptdemo_three_mixed_gateways.geoip.json"); +        JSONObject eipServiceJson = provider.getEipServiceJson(); +        JSONObject gateway1 = eipServiceJson.getJSONArray(GATEWAYS).getJSONObject(0); +        MockHelper.mockProviderObserver(provider); +        GatewaysManager gatewaysManager = new GatewaysManager(mockContext); + +        VpnConfigGenerator configGenerator = new VpnConfigGenerator(provider.getDefinition(), secrets, gateway1, 3); +        VpnProfile profile = configGenerator.createProfile(OBFS4); +        profile.mGatewayIp = "37.218.247.60"; + +        assertEquals(1, gatewaysManager.getPosition(profile)); +    } + +    @Test +    public void TestGetPosition_VpnProfileExistingOpenvpnFromPresortedList_returnsPositionOne() throws JSONException, ConfigParser.ConfigParseError, IOException { +        Provider provider = getProvider(null, null, null, null, null, null, "ptdemo_three_mixed_gateways.json", "ptdemo_three_mixed_gateways.geoip.json"); +        JSONObject eipServiceJson = provider.getEipServiceJson(); +        JSONObject gateway1 = eipServiceJson.getJSONArray(GATEWAYS).getJSONObject(0); +        MockHelper.mockProviderObserver(provider); +        GatewaysManager gatewaysManager = new GatewaysManager(mockContext); + +        VpnConfigGenerator configGenerator = new VpnConfigGenerator(provider.getDefinition(), secrets, gateway1, 3); +        VpnProfile profile = configGenerator.createProfile(OPENVPN); +        profile.mGatewayIp = "37.218.247.60"; + +        assertEquals(2, gatewaysManager.getPosition(profile)); +    } + +    @Test      public void TestGetPosition_VpnProfileDifferentIp_returnMinusOne() throws JSONException, ConfigParser.ConfigParseError, IOException { -        Provider provider = getProvider(null, null, null, null, null, "ptdemo_three_mixed_gateways.json"); +        Provider provider = getProvider(null, null, null, null, null, null, "ptdemo_three_mixed_gateways.json", null);          JSONObject eipServiceJson = provider.getEipServiceJson();          JSONObject gateway1 = eipServiceJson.getJSONArray(GATEWAYS).getJSONObject(0);          MockHelper.mockProviderObserver(provider); -        mockStatic(PreferenceHelper.class); -        when(PreferenceHelper.getUsePluggableTransports(any(Context.class))).thenReturn(true);          GatewaysManager gatewaysManager = new GatewaysManager(mockContext);          VpnConfigGenerator configGenerator = new VpnConfigGenerator(provider.getDefinition(), secrets, gateway1, 3); @@ -174,12 +175,10 @@ public class GatewaysManagerTest {      @Test      public void TestGetPosition_VpnProfileMoscow_returnOne() throws JSONException, ConfigParser.ConfigParseError, IOException { -        Provider provider = getProvider(null, null, null, null, null, "ptdemo_three_mixed_gateways.json"); +        Provider provider = getProvider(null, null, null, null, null, null, "ptdemo_three_mixed_gateways.json", null);          JSONObject eipServiceJson = provider.getEipServiceJson();          JSONObject gateway1 = eipServiceJson.getJSONArray(GATEWAYS).getJSONObject(1);          MockHelper.mockProviderObserver(provider); -        mockStatic(PreferenceHelper.class); -        when(PreferenceHelper.getUsePluggableTransports(any(Context.class))).thenReturn(true);          GatewaysManager gatewaysManager = new GatewaysManager(mockContext);          VpnConfigGenerator configGenerator = new VpnConfigGenerator(provider.getDefinition(), secrets, gateway1, 3); @@ -190,10 +189,8 @@ public class GatewaysManagerTest {      }      @Test -    public void TestSelectN_selectFirstObfs4Connection_returnThirdGateway() throws JSONException, ConfigParser.ConfigParseError, IOException { -        Provider provider = getProvider(null, null, null, null, null, "ptdemo_two_openvpn_one_pt_gateways.json"); -        JSONObject eipServiceJson = provider.getEipServiceJson(); -        JSONObject gateway3 = eipServiceJson.getJSONArray(GATEWAYS).getJSONObject(2); +    public void TestSelectN_selectFirstObfs4Connection_returnThirdGateway() { +        Provider provider = getProvider(null, null, null, null, null, null, "ptdemo_two_openvpn_one_pt_gateways.json", null);          MockHelper.mockProviderObserver(provider);          mockStatic(PreferenceHelper.class); @@ -203,6 +200,37 @@ public class GatewaysManagerTest {          assertEquals("37.12.247.10", gatewaysManager.select(0).getRemoteIP());      } +    @Test +    public void testSelectN_selectFromPresortedGateways_returnsGatewaysInPresortedOrder() { +        Provider provider = getProvider(null, null, null, null, null, null, "ptdemo_three_mixed_gateways.json", "ptdemo_three_mixed_gateways.geoip.json"); + +        MockHelper.mockProviderObserver(provider); +        //use openvpn, not pluggable transports +        mockStatic(PreferenceHelper.class); +        when(PreferenceHelper.getUsePluggableTransports(any(Context.class))).thenReturn(false); +        GatewaysManager gatewaysManager = new GatewaysManager(mockContext); + +        assertEquals("manila.bitmask.net", gatewaysManager.select(0).getHost()); +        assertEquals("moscow.bitmask.net", gatewaysManager.select(1).getHost()); +        assertEquals("pt.demo.bitmask.net", gatewaysManager.select(2).getHost()); +    } + +    @Test +    public void testSelectN_selectObfs4FromPresortedGateways_returnsObfs4GatewaysInPresortedOrder() { +        Provider provider = getProvider(null, null, null, null, null, null, "ptdemo_three_mixed_gateways.json", "ptdemo_three_mixed_gateways.geoip.json"); + +        MockHelper.mockProviderObserver(provider); +        //use openvpn, not pluggable transports +        mockStatic(PreferenceHelper.class); +        when(PreferenceHelper.getUsePluggableTransports(any(Context.class))).thenReturn(true); +        GatewaysManager gatewaysManager = new GatewaysManager(mockContext); + +        assertEquals("moscow.bitmask.net", gatewaysManager.select(0).getHost()); +        assertEquals("pt.demo.bitmask.net", gatewaysManager.select(1).getHost()); +        assertNull(gatewaysManager.select(2)); +    } + +      private String getJsonStringFor(String filename) throws IOException {          return TestSetupHelper.getInputAsString(getClass().getClassLoader().getResourceAsStream(filename));      } diff --git a/app/src/test/java/se/leap/bitmaskclient/eip/ProviderApiManagerTest.java b/app/src/test/java/se/leap/bitmaskclient/eip/ProviderApiManagerTest.java index 753a9474..efa6f78c 100644 --- a/app/src/test/java/se/leap/bitmaskclient/eip/ProviderApiManagerTest.java +++ b/app/src/test/java/se/leap/bitmaskclient/eip/ProviderApiManagerTest.java @@ -25,6 +25,7 @@ import android.os.Bundle;  import android.text.TextUtils;  import org.json.JSONException; +import org.json.JSONObject;  import org.junit.Before;  import org.junit.Test;  import org.junit.runner.RunWith; @@ -44,18 +45,24 @@ import se.leap.bitmaskclient.ProviderAPI;  import se.leap.bitmaskclient.ProviderApiConnector;  import se.leap.bitmaskclient.ProviderApiManager;  import se.leap.bitmaskclient.ProviderApiManagerBase; +import se.leap.bitmaskclient.testutils.BackendMockResponses.GeoIpServiceIsDownBackendResponse;  import se.leap.bitmaskclient.testutils.MockSharedPreferences;  import se.leap.bitmaskclient.utils.ConfigHelper;  import se.leap.bitmaskclient.utils.PreferenceHelper;  import static se.leap.bitmaskclient.Constants.BROADCAST_RESULT_KEY; +import static se.leap.bitmaskclient.Constants.EIP_ACTION_START;  import static se.leap.bitmaskclient.Constants.PROVIDER_KEY; +import static se.leap.bitmaskclient.ProviderAPI.CORRECTLY_DOWNLOADED_GEOIP_JSON;  import static se.leap.bitmaskclient.ProviderAPI.ERRORS; +import static se.leap.bitmaskclient.ProviderAPI.INCORRECTLY_DOWNLOADED_GEOIP_JSON; +import static se.leap.bitmaskclient.ProviderAPI.PARAMETERS;  import static se.leap.bitmaskclient.ProviderAPI.PROVIDER_NOK;  import static se.leap.bitmaskclient.ProviderAPI.PROVIDER_OK;  import static se.leap.bitmaskclient.testutils.BackendMockResponses.BackendMockProvider.TestBackendErrorCase.ERROR_CASE_FETCH_EIP_SERVICE_CERTIFICATE_INVALID;  import static se.leap.bitmaskclient.testutils.BackendMockResponses.BackendMockProvider.TestBackendErrorCase.ERROR_CASE_MICONFIGURED_PROVIDER;  import static se.leap.bitmaskclient.testutils.BackendMockResponses.BackendMockProvider.TestBackendErrorCase.ERROR_CASE_UPDATED_CERTIFICATE; +import static se.leap.bitmaskclient.testutils.BackendMockResponses.BackendMockProvider.TestBackendErrorCase.ERROR_GEOIP_SERVICE_IS_DOWN;  import static se.leap.bitmaskclient.testutils.BackendMockResponses.BackendMockProvider.TestBackendErrorCase.NO_ERROR;  import static se.leap.bitmaskclient.testutils.MockHelper.mockBundle;  import static se.leap.bitmaskclient.testutils.MockHelper.mockClientGenerator; @@ -155,7 +162,7 @@ public class ProviderApiManagerTest {      @Test      public void test_handleIntentSetupProvider_happyPath_no_preseededProviderAndCA() throws IOException, CertificateEncodingException, NoSuchAlgorithmException, JSONException { -        Provider provider = new Provider("https://riseup.net"); +        Provider provider = getConfiguredProvider();          mockFingerprintForCertificate("a5244308a1374709a9afce95e3ae47c1b44bc2398c0a70ccbf8b3a8a97f29494");          mockProviderApiConnector(NO_ERROR); @@ -269,7 +276,7 @@ public class ProviderApiManagerTest {      @Test      public void test_handleIntentSetupProvider_preseededProviderAndCA_outdatedCertificate() throws IOException, CertificateEncodingException, NoSuchAlgorithmException, JSONException { -        Provider provider = getProvider(null ,null, null, "outdated_cert.pem", null, null); +        Provider provider = getProvider(null ,null, null, null, "outdated_cert.pem", null, null, null);          mockProviderApiConnector(NO_ERROR);          providerApiManager = new ProviderApiManager(mockPreferences, mockResources, mockClientGenerator(), new TestProviderApiServiceCallback()); @@ -290,7 +297,7 @@ public class ProviderApiManagerTest {      @Test      public void test_handleIntentSetupProvider_storedProviderAndCAFromPreviousSetup_outdatedCertificate() throws IOException, CertificateEncodingException, NoSuchAlgorithmException, JSONException { -        Provider provider = new Provider("https://riseup.net"); +        Provider provider = getConfiguredProvider(); //new Provider("https://riseup.net");          mockProviderApiConnector(NO_ERROR);          mockPreferences.edit().putString(Provider.KEY + ".riseup.net", getInputAsString(getClass().getClassLoader().getResourceAsStream("riseup.net.json"))).apply();          mockPreferences.edit().putString(Provider.CA_CERT + ".riseup.net", getInputAsString(getClass().getClassLoader().getResourceAsStream("outdated_cert.pem"))).apply(); @@ -386,7 +393,7 @@ public class ProviderApiManagerTest {      @Test      public void test_handleIntentSetupProvider_outdatedPreseededProviderAndCA_successfulConfiguration() throws IOException, CertificateEncodingException, NoSuchAlgorithmException, JSONException { -        Provider provider = getProvider(null, null, null, null, "riseup_net_outdated_config.json", null); +        Provider provider = getProvider(null, null, null, null, null, "riseup_net_outdated_config.json", null, null);          mockFingerprintForCertificate(" a5244308a1374709a9afce95e3ae47c1b44bc2398c0a70ccbf8b3a8a97f29494");          mockProviderApiConnector(NO_ERROR); @@ -431,4 +438,126 @@ public class ProviderApiManagerTest {          providerApiManager.handleIntent(providerApiCommand);      } + + +    @Test +    public void test_handleIntentGetGeoip_happyPath() throws IOException, NoSuchAlgorithmException, CertificateEncodingException, JSONException { +        if ("insecure".equals(BuildConfig.FLAVOR_implementation )) { +            return; +        } + +        Provider inputProvider = getConfiguredProvider(); +        inputProvider.setGeoIpJson(new JSONObject()); +        Provider expectedProvider = getConfiguredProvider(); +        mockFingerprintForCertificate("a5244308a1374709a9afce95e3ae47c1b44bc2398c0a70ccbf8b3a8a97f29494"); +        mockProviderApiConnector(NO_ERROR); +        providerApiManager = new ProviderApiManager(mockPreferences, mockResources, mockClientGenerator(), new TestProviderApiServiceCallback()); + +        Bundle expectedResult = mockBundle(); +        expectedResult.putBoolean(EIP_ACTION_START, true); +        expectedResult.putBoolean(BROADCAST_RESULT_KEY, true); +        expectedResult.putParcelable(PROVIDER_KEY, expectedProvider); + +        Intent providerApiCommand = mockIntent(); + +        providerApiCommand.setAction(ProviderAPI.DOWNLOAD_GEOIP_JSON); +        Bundle extrasBundle = mockBundle(); +        extrasBundle.putBoolean(EIP_ACTION_START, true); +        providerApiCommand.putExtra(ProviderAPI.RECEIVER_KEY, mockResultReceiver(CORRECTLY_DOWNLOADED_GEOIP_JSON, expectedResult)); +        providerApiCommand.putExtra(PROVIDER_KEY, inputProvider); +        providerApiCommand.putExtra(PARAMETERS, extrasBundle); + +        providerApiManager.handleIntent(providerApiCommand); + +    } + + +    @Test +    public void test_handleIntentGetGeoip_serviceDown_failToDownload() throws IOException, NoSuchAlgorithmException, CertificateEncodingException, JSONException { +        if ("insecure".equals(BuildConfig.FLAVOR_implementation)) { +            return; +        } + +        Provider provider = getConfiguredProvider(); +        mockFingerprintForCertificate("a5244308a1374709a9afce95e3ae47c1b44bc2398c0a70ccbf8b3a8a97f29494"); +        mockProviderApiConnector(ERROR_GEOIP_SERVICE_IS_DOWN); +        providerApiManager = new ProviderApiManager(mockPreferences, mockResources, mockClientGenerator(), new TestProviderApiServiceCallback()); + +        Bundle expectedResult = mockBundle(); +        expectedResult.putBoolean(EIP_ACTION_START, true); +        expectedResult.putBoolean(BROADCAST_RESULT_KEY, false); +        expectedResult.putParcelable(PROVIDER_KEY, provider); + +        Intent providerApiCommand = mockIntent(); + +        providerApiCommand.setAction(ProviderAPI.DOWNLOAD_GEOIP_JSON); +        Bundle extrasBundle = mockBundle(); +        extrasBundle.putBoolean(EIP_ACTION_START, true); +        providerApiCommand.putExtra(ProviderAPI.RECEIVER_KEY, mockResultReceiver(INCORRECTLY_DOWNLOADED_GEOIP_JSON, expectedResult)); +        providerApiCommand.putExtra(PROVIDER_KEY, provider); +        providerApiCommand.putExtra(PARAMETERS, extrasBundle); + +        providerApiManager.handleIntent(providerApiCommand); + +    } + +    @Test +    public void test_handleIntentGetGeoip_didNotReachTimeoutToFetchNew_returnsFailure() throws IOException, NoSuchAlgorithmException, CertificateEncodingException, JSONException { +        if ("insecure".equals(BuildConfig.FLAVOR_implementation)) { +            return; +        } + +        Provider provider = getConfiguredProvider(); +        provider.setLastGeoIpUpdate(System.currentTimeMillis()); +        mockFingerprintForCertificate("a5244308a1374709a9afce95e3ae47c1b44bc2398c0a70ccbf8b3a8a97f29494"); +        mockProviderApiConnector(NO_ERROR); +        providerApiManager = new ProviderApiManager(mockPreferences, mockResources, mockClientGenerator(), new TestProviderApiServiceCallback()); + +        Bundle expectedResult = mockBundle(); +        expectedResult.putBoolean(EIP_ACTION_START, true); +        expectedResult.putBoolean(BROADCAST_RESULT_KEY, false); +        expectedResult.putParcelable(PROVIDER_KEY, provider); + +        Intent providerApiCommand = mockIntent(); + +        providerApiCommand.setAction(ProviderAPI.DOWNLOAD_GEOIP_JSON); +        Bundle extrasBundle = mockBundle(); +        extrasBundle.putBoolean(EIP_ACTION_START, true); +        providerApiCommand.putExtra(ProviderAPI.RECEIVER_KEY, mockResultReceiver(INCORRECTLY_DOWNLOADED_GEOIP_JSON, expectedResult)); +        providerApiCommand.putExtra(PROVIDER_KEY, provider); +        providerApiCommand.putExtra(PARAMETERS, extrasBundle); + +        providerApiManager.handleIntent(providerApiCommand); +    } + +    @Test +    public void test_handleIntentGetGeoip_noGeoipServiceURLDefined_returnsFailure() throws IOException, NoSuchAlgorithmException, CertificateEncodingException, JSONException { +        if ("insecure".equals(BuildConfig.FLAVOR_implementation)) { +            return; +        } + +        Provider provider = getConfiguredProvider(); +        provider.setGeoipUrl(null); +        provider.setGeoIpJson(new JSONObject()); +        mockFingerprintForCertificate("a5244308a1374709a9afce95e3ae47c1b44bc2398c0a70ccbf8b3a8a97f29494"); +        mockProviderApiConnector(NO_ERROR); +        providerApiManager = new ProviderApiManager(mockPreferences, mockResources, mockClientGenerator(), new TestProviderApiServiceCallback()); + +        Bundle expectedResult = mockBundle(); +        expectedResult.putBoolean(EIP_ACTION_START, true); +        expectedResult.putBoolean(BROADCAST_RESULT_KEY, false); +        expectedResult.putParcelable(PROVIDER_KEY, provider); + +        Intent providerApiCommand = mockIntent(); + +        providerApiCommand.setAction(ProviderAPI.DOWNLOAD_GEOIP_JSON); +        Bundle extrasBundle = mockBundle(); +        extrasBundle.putBoolean(EIP_ACTION_START, true); +        providerApiCommand.putExtra(ProviderAPI.RECEIVER_KEY, mockResultReceiver(INCORRECTLY_DOWNLOADED_GEOIP_JSON, expectedResult)); +        providerApiCommand.putExtra(PROVIDER_KEY, provider); +        providerApiCommand.putExtra(PARAMETERS, extrasBundle); + +        providerApiManager.handleIntent(providerApiCommand); +    } +  } diff --git a/app/src/test/java/se/leap/bitmaskclient/testutils/BackendMockResponses/BackendMockProvider.java b/app/src/test/java/se/leap/bitmaskclient/testutils/BackendMockResponses/BackendMockProvider.java index a10b1414..3e8dfd5f 100644 --- a/app/src/test/java/se/leap/bitmaskclient/testutils/BackendMockResponses/BackendMockProvider.java +++ b/app/src/test/java/se/leap/bitmaskclient/testutils/BackendMockResponses/BackendMockProvider.java @@ -32,6 +32,7 @@ public class BackendMockProvider {          ERROR_CASE_UPDATED_CERTIFICATE,          ERROR_CASE_MICONFIGURED_PROVIDER,          ERROR_CASE_FETCH_EIP_SERVICE_CERTIFICATE_INVALID, +        ERROR_GEOIP_SERVICE_IS_DOWN,          ERROR_NO_RESPONSE_BODY,         // => NullPointerException          ERROR_DNS_RESOLUTION_ERROR,     // => UnkownHostException          ERROR_SOCKET_TIMEOUT,           // => SocketTimeoutException @@ -62,6 +63,10 @@ public class BackendMockProvider {                  break;              case ERROR_CASE_FETCH_EIP_SERVICE_CERTIFICATE_INVALID:                  new EipSerivceJsonInvalidCertificateBackendResponse(); +                break; +            case ERROR_GEOIP_SERVICE_IS_DOWN: +                new GeoIpServiceIsDownBackendResponse(); +                break;              case ERROR_NO_RESPONSE_BODY:                  break;              case ERROR_DNS_RESOLUTION_ERROR: diff --git a/app/src/test/java/se/leap/bitmaskclient/testutils/BackendMockResponses/EipSerivceJsonInvalidCertificateBackendResponse.java b/app/src/test/java/se/leap/bitmaskclient/testutils/BackendMockResponses/EipSerivceJsonInvalidCertificateBackendResponse.java index b84c5508..7c2d49cc 100644 --- a/app/src/test/java/se/leap/bitmaskclient/testutils/BackendMockResponses/EipSerivceJsonInvalidCertificateBackendResponse.java +++ b/app/src/test/java/se/leap/bitmaskclient/testutils/BackendMockResponses/EipSerivceJsonInvalidCertificateBackendResponse.java @@ -52,6 +52,9 @@ public class EipSerivceJsonInvalidCertificateBackendResponse extends BaseBackend                  } else if (url.contains("config/eip-service.json")) {                      // download provider service json containing gateways, locations and openvpn settings                      throw new SSLHandshakeException("Invalid provider CA certificate"); +                } else if (url.contains(":9001/json")) { +                    // download geoip json, containing a sorted list of gateways +                    return getInputAsString(getClass().getClassLoader().getResourceAsStream("riseup.geoip.json"));                  } else if (url.contains("/users.json")) {                      //create new user                      //TODO: implement me diff --git a/app/src/test/java/se/leap/bitmaskclient/testutils/BackendMockResponses/GeoIpServiceIsDownBackendResponse.java b/app/src/test/java/se/leap/bitmaskclient/testutils/BackendMockResponses/GeoIpServiceIsDownBackendResponse.java new file mode 100644 index 00000000..3a08d8da --- /dev/null +++ b/app/src/test/java/se/leap/bitmaskclient/testutils/BackendMockResponses/GeoIpServiceIsDownBackendResponse.java @@ -0,0 +1,93 @@ +/** + * Copyright (c) 2018 LEAP Encryption Access Project and contributers + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see <http://www.gnu.org/licenses/>. + */ +package se.leap.bitmaskclient.testutils.BackendMockResponses; + +import org.mockito.invocation.InvocationOnMock; +import org.mockito.stubbing.Answer; + +import java.io.IOException; +import java.net.ConnectException; + +import static se.leap.bitmaskclient.testutils.TestSetupHelper.getInputAsString; + +/** + * Created by cyberta on 10.01.18. + */ + +public class GeoIpServiceIsDownBackendResponse extends BaseBackendResponse { +    public GeoIpServiceIsDownBackendResponse() throws IOException { +        super(); +    } + +    @Override +    public Answer<String> getAnswerForRequestStringFromServer() { +        return new Answer<String>() { +            @Override +            public String answer(InvocationOnMock invocation) throws Throwable { +                String url = (String) invocation.getArguments()[0]; +                String requestMethod = (String) invocation.getArguments()[1]; +                String jsonPayload = (String) invocation.getArguments()[2]; + +                if (url.contains("/provider.json")) { +                    //download provider json +                    return getInputAsString(getClass().getClassLoader().getResourceAsStream("riseup.net.json")); +                } else if (url.contains("/ca.crt")) { +                    //download provider ca cert +                    return getInputAsString(getClass().getClassLoader().getResourceAsStream("riseup.net.pem")); +                } else if (url.contains("config/eip-service.json")) { +                    // download provider service json containing gateways, locations and openvpn settings +                    return getInputAsString(getClass().getClassLoader().getResourceAsStream("riseup.service.json")); +                } else if (url.contains(":9001/json")) { +                    // download geoip json, containing a sorted list of gateways +                    throw new ConnectException("Failed to connect to api.black.riseup.net/198.252.153.107:9001"); +                } else if (url.contains("/users.json")) { +                    //create new user +                    //TODO: implement me +                } else if (url.contains("/sessions.json")) { +                    //srp auth: sendAToSRPServer +                    //TODO: implement me +                } else if (url.contains("/sessions/parmegvtest10.json")){ +                    //srp auth: sendM1ToSRPServer +                    //TODO: implement me +                } + +                return null; +            } +        }; +    } + +    @Override +    public Answer<Boolean> getAnswerForCanConnect() { +        return new Answer<Boolean>() { +            @Override +            public Boolean answer(InvocationOnMock invocation) throws Throwable { +                return true; +            } +        }; +    } + +    @Override +    public Answer<Boolean> getAnswerForDelete() { +        return new Answer<Boolean>() { +            @Override +            public Boolean answer(InvocationOnMock invocation) throws Throwable { +                return true; +            } +        }; +    } + +} diff --git a/app/src/test/java/se/leap/bitmaskclient/testutils/BackendMockResponses/MisconfiguredProviderBackendResponse.java b/app/src/test/java/se/leap/bitmaskclient/testutils/BackendMockResponses/MisconfiguredProviderBackendResponse.java index 4600e879..10e69bc3 100644 --- a/app/src/test/java/se/leap/bitmaskclient/testutils/BackendMockResponses/MisconfiguredProviderBackendResponse.java +++ b/app/src/test/java/se/leap/bitmaskclient/testutils/BackendMockResponses/MisconfiguredProviderBackendResponse.java @@ -50,6 +50,9 @@ public class MisconfiguredProviderBackendResponse extends BaseBackendResponse {                  } else if (url.contains("config/eip-service.json")) {                      // download provider service json containing gateways, locations and openvpn settings                      return getInputAsString(getClass().getClassLoader().getResourceAsStream("riseup.service.json")); +                } else if (url.contains(":9001/json")) { +                    // download geoip json, containing a sorted list of gateways +                    return getInputAsString(getClass().getClassLoader().getResourceAsStream("riseup.geoip.json"));                  } else if (url.contains("/users.json")) {                      //create new user                      //TODO: implement me diff --git a/app/src/test/java/se/leap/bitmaskclient/testutils/BackendMockResponses/NoErrorBackendResponse.java b/app/src/test/java/se/leap/bitmaskclient/testutils/BackendMockResponses/NoErrorBackendResponse.java index fa318e42..3c3a8ffa 100644 --- a/app/src/test/java/se/leap/bitmaskclient/testutils/BackendMockResponses/NoErrorBackendResponse.java +++ b/app/src/test/java/se/leap/bitmaskclient/testutils/BackendMockResponses/NoErrorBackendResponse.java @@ -50,6 +50,9 @@ public class NoErrorBackendResponse extends BaseBackendResponse {                  } else if (url.contains("config/eip-service.json")) {                      // download provider service json containing gateways, locations and openvpn settings                      return getInputAsString(getClass().getClassLoader().getResourceAsStream("riseup.service.json")); +                } else if (url.contains(":9001/json")) { +                    // download geoip json, containing a sorted list of gateways +                    return getInputAsString(getClass().getClassLoader().getResourceAsStream("riseup.geoip.json"));                  } else if (url.contains("/users.json")) {                      //create new user                      //TODO: implement me diff --git a/app/src/test/java/se/leap/bitmaskclient/testutils/MockHelper.java b/app/src/test/java/se/leap/bitmaskclient/testutils/MockHelper.java index 1c205c83..d3d07308 100644 --- a/app/src/test/java/se/leap/bitmaskclient/testutils/MockHelper.java +++ b/app/src/test/java/se/leap/bitmaskclient/testutils/MockHelper.java @@ -401,6 +401,8 @@ public class MockHelper {                          return providerFromPrefs.getCaCertFingerprint();                      case Provider.CA_CERT:                          return providerFromPrefs.getCaCert(); +                    case Provider.GEOIP_URL: +                        return providerFromPrefs.getGeoipUrl().toString();                  }                  return null; diff --git a/app/src/test/resources/ptdemo_three_mixed_gateways.geoip.json b/app/src/test/resources/ptdemo_three_mixed_gateways.geoip.json new file mode 100644 index 00000000..a72a85f5 --- /dev/null +++ b/app/src/test/resources/ptdemo_three_mixed_gateways.geoip.json @@ -0,0 +1,12 @@ +{ +  "ip":"51.158.144.32", +  "cc":"FR", +  "city":"Paris", +  "lat":48.8628, +  "lon":2.3292, +  "gateways":[ +    "manila.bitmask.net", +    "moscow.bitmask.net", +    "pt.demo.bitmask.net" +  ] +}
\ No newline at end of file diff --git a/app/src/test/resources/riseup.geoip.json b/app/src/test/resources/riseup.geoip.json new file mode 100644 index 00000000..b646052e --- /dev/null +++ b/app/src/test/resources/riseup.geoip.json @@ -0,0 +1,20 @@ +{ +  "ip":"51.158.144.32", +  "cc":"FR", +  "city":"Paris", +  "lat":48.8628, +  "lon":2.3292, +  "gateways":[ +    "mouette.riseup.net", +    "hoatzin.riseup.net", +    "zarapito.riseup.net", +    "redshank.riseup.net", +    "shag.riseup.net", +    "yal.riseup.net", +    "gaei.riseup.net", +    "cisne.riseup.net", +    "swan.riseup.net", +    "garza.riseup.net", +    "gaviota.riseup.net" +  ] +}
\ No newline at end of file | 
