diff options
Diffstat (limited to 'app/src')
5 files changed, 266 insertions, 8 deletions
diff --git a/app/src/main/java/se/leap/bitmaskclient/base/fragments/SettingsFragment.java b/app/src/main/java/se/leap/bitmaskclient/base/fragments/SettingsFragment.java index f4531ff8..94f737b4 100644 --- a/app/src/main/java/se/leap/bitmaskclient/base/fragments/SettingsFragment.java +++ b/app/src/main/java/se/leap/bitmaskclient/base/fragments/SettingsFragment.java @@ -9,12 +9,15 @@ import static se.leap.bitmaskclient.base.models.Constants.PREFER_UDP;  import static se.leap.bitmaskclient.base.models.Constants.SHARED_PREFERENCES;  import static se.leap.bitmaskclient.base.models.Constants.USE_BRIDGES;  import static se.leap.bitmaskclient.base.models.Constants.USE_IPv6_FIREWALL; +import static se.leap.bitmaskclient.base.utils.ConfigHelper.ObfsVpnHelper.useObfsVpn; +import static se.leap.bitmaskclient.base.utils.PreferenceHelper.allowExperimentalTransports;  import static se.leap.bitmaskclient.base.utils.PreferenceHelper.getPreferUDP;  import static se.leap.bitmaskclient.base.utils.PreferenceHelper.getShowAlwaysOnDialog;  import static se.leap.bitmaskclient.base.utils.PreferenceHelper.getUseBridges;  import static se.leap.bitmaskclient.base.utils.PreferenceHelper.getUseSnowflake;  import static se.leap.bitmaskclient.base.utils.PreferenceHelper.hasSnowflakePrefs;  import static se.leap.bitmaskclient.base.utils.PreferenceHelper.preferUDP; +import static se.leap.bitmaskclient.base.utils.PreferenceHelper.setAllowExperimentalTransports;  import static se.leap.bitmaskclient.base.utils.PreferenceHelper.useBridges;  import static se.leap.bitmaskclient.base.utils.PreferenceHelper.useSnowflake;  import static se.leap.bitmaskclient.base.utils.ViewHelper.setActionBarTitle; @@ -81,6 +84,7 @@ public class SettingsFragment extends Fragment implements SharedPreferences.OnSh          initFirewallEntry(view);          initTetheringEntry(view);          initGatewayPinningEntry(view); +        initExperimentalTransportsEntry(view);          setActionBarTitle(this, advanced_settings);          return view;      } @@ -249,6 +253,23 @@ public class SettingsFragment extends Fragment implements SharedPreferences.OnSh          });      } +    public void initExperimentalTransportsEntry(View rootView) { +        IconSwitchEntry experimentalTransports = rootView.findViewById(R.id.experimental_transports); +        if (useObfsVpn() && ProviderObservable.getInstance().getCurrentProvider().supportsExperimentalPluggableTransports()) { +            experimentalTransports.setVisibility(VISIBLE); +            experimentalTransports.setChecked(allowExperimentalTransports(this.getContext())); +            experimentalTransports.setOnCheckedChangeListener((buttonView, isChecked) -> { +                if (!buttonView.isPressed()) { +                    return; +                } +                setAllowExperimentalTransports(getContext(), isChecked); +            }); +        } else { +            experimentalTransports.setVisibility(GONE); +        } + +    } +      public void showTetheringAlert() {          try { diff --git a/app/src/main/java/se/leap/bitmaskclient/base/models/Provider.java b/app/src/main/java/se/leap/bitmaskclient/base/models/Provider.java index 02a9694a..7b8f22af 100644 --- a/app/src/main/java/se/leap/bitmaskclient/base/models/Provider.java +++ b/app/src/main/java/se/leap/bitmaskclient/base/models/Provider.java @@ -30,6 +30,7 @@ import java.net.URL;  import java.util.Locale;  import static de.blinkt.openvpn.core.connection.Connection.TransportType.OBFS4; +import static de.blinkt.openvpn.core.connection.Connection.TransportType.OBFS4_KCP;  import static se.leap.bitmaskclient.base.models.Constants.CAPABILITIES;  import static se.leap.bitmaskclient.base.models.Constants.GATEWAYS;  import static se.leap.bitmaskclient.base.models.Constants.LOCATIONS; @@ -37,8 +38,12 @@ import static se.leap.bitmaskclient.base.models.Constants.PROVIDER_ALLOWED_REGIS  import static se.leap.bitmaskclient.base.models.Constants.PROVIDER_ALLOW_ANONYMOUS;  import static se.leap.bitmaskclient.base.models.Constants.TRANSPORT;  import static se.leap.bitmaskclient.base.models.Constants.TYPE; +import static se.leap.bitmaskclient.base.utils.ConfigHelper.ObfsVpnHelper.useObfsVpn;  import static se.leap.bitmaskclient.providersetup.ProviderAPI.ERRORS; +import de.blinkt.openvpn.core.connection.Connection; +import de.blinkt.openvpn.core.connection.Connection.TransportType; +  /**   * @author Sean Leonard <meanderingcode@aetherislands.net>   * @author Parménides GV <parmegv@sdf.org> @@ -161,6 +166,17 @@ public final class Provider implements Parcelable {      }      public boolean supportsPluggableTransports() { +        if (useObfsVpn()) { +            return supportsTransports(new TransportType[]{OBFS4, OBFS4_KCP}); +        } +        return supportsTransports(new TransportType[]{OBFS4}); +    } + +    public boolean supportsExperimentalPluggableTransports() { +        return supportsTransports(new TransportType[]{OBFS4_KCP}); +    } + +    private boolean supportsTransports(TransportType[] transportTypes) {          try {              JSONArray gatewayJsons = eipServiceJson.getJSONArray(GATEWAYS);              for (int i = 0; i < gatewayJsons.length(); i++) { @@ -168,15 +184,18 @@ public final class Provider implements Parcelable {                          getJSONObject(CAPABILITIES).                          getJSONArray(TRANSPORT);                  for (int j = 0; j < transports.length(); j++) { -                    if (OBFS4.toString().equals(transports.getJSONObject(j).getString(TYPE))) { -                        return true; +                    String supportedTransportType = transports.getJSONObject(j).getString(TYPE); +                    for (TransportType transportType : transportTypes) { +                        if (transportType.toString().equals(supportedTransportType)) { +                            return true; +                        }                      }                  }              }          } catch (Exception e) { -           // ignore +            // ignore          } -       return false; +        return false;      }      public String getIpForHostname(String host) { diff --git a/app/src/main/res/layout/f_settings.xml b/app/src/main/res/layout/f_settings.xml index 7b8733cd..f89dc956 100644 --- a/app/src/main/res/layout/f_settings.xml +++ b/app/src/main/res/layout/f_settings.xml @@ -114,5 +114,14 @@              app:subtitle="Connect to a specific Gateway for debugging purposes"              /> +        <se.leap.bitmaskclient.base.views.IconSwitchEntry +            android:id="@+id/experimental_transports" +            android:layout_width="match_parent" +            android:layout_height="wrap_content" +            app:text="Experimental transports" +            app:singleLine="false" +            app:subtitle="These transports might circumvent censorship, but are still in a testing phase" +            /> +      </LinearLayout>  </ScrollView>
\ No newline at end of file diff --git a/app/src/test/java/se/leap/bitmaskclient/base/models/ProviderTest.java b/app/src/test/java/se/leap/bitmaskclient/base/models/ProviderTest.java index aaf3f255..8bff690b 100644 --- a/app/src/test/java/se/leap/bitmaskclient/base/models/ProviderTest.java +++ b/app/src/test/java/se/leap/bitmaskclient/base/models/ProviderTest.java @@ -1,21 +1,36 @@  package se.leap.bitmaskclient.base.models; +import static junit.framework.Assert.assertFalse; +import static org.junit.Assert.assertTrue; +import static org.mockito.Mockito.when; +import static org.powermock.api.mockito.PowerMockito.mockStatic; + +import org.junit.Before;  import org.junit.Test; +import org.junit.runner.RunWith; +import org.powermock.core.classloader.annotations.PrepareForTest; +import org.powermock.modules.junit4.PowerMockRunner;  import java.util.HashSet;  import java.util.Set; -import se.leap.bitmaskclient.base.models.Provider; +import se.leap.bitmaskclient.base.utils.ConfigHelper;  import se.leap.bitmaskclient.testutils.TestSetupHelper; -import static junit.framework.Assert.assertFalse; -import static org.junit.Assert.assertTrue; -  /**   * Created by cyberta on 12.02.18.   */ + +@RunWith(PowerMockRunner.class) +@PrepareForTest({ConfigHelper.ObfsVpnHelper.class})  public class ProviderTest { +    @Before +    public void setup() { +        mockStatic(ConfigHelper.ObfsVpnHelper.class); +        when(ConfigHelper.ObfsVpnHelper.useObfsVpn()).thenReturn(false); +    } +      @Test      public void testEquals_sameFields_returnsTrue() throws Exception {          Provider p1 = TestSetupHelper.getConfiguredProvider(); @@ -84,4 +99,64 @@ public class ProviderTest {          assertFalse(p1.supportsPluggableTransports());      } +    @Test +    public void testIsExperimentalPluggableTransportsSupported_Obfs4_returnsFalse() throws Exception { +        Provider p1 = TestSetupHelper.getProvider( +                "https://pt.demo.bitmask.net", +                null, +                null, +                null, +                null, +                null, +                "ptdemo.bitmask.eip-service.json", +                null); +        assertFalse(p1.supportsExperimentalPluggableTransports()); +    } + +    @Test +    public void testIsExperimentalPluggableTransportsSupported_Obfs4Kcp_returnsTrue() throws Exception { +        Provider p1 = TestSetupHelper.getProvider( +                "https://pt.demo.bitmask.net", +                null, +                null, +                null, +                null, +                null, +                "ptdemo_kcp_gateways.json", +                null); +        assertTrue(p1.supportsExperimentalPluggableTransports()); +    } + +    @Test +    public void testSupportsPluggableTransports_Obfs4Kcp_noObsvpn_returnsFalse() throws Exception { +        when(ConfigHelper.ObfsVpnHelper.useObfsVpn()).thenReturn(false); + +        Provider p1 = TestSetupHelper.getProvider( +                "https://pt.demo.bitmask.net", +                null, +                null, +                null, +                null, +                null, +                "ptdemo_only_experimental_transports_gateways.json", +                null); +        assertFalse(p1.supportsPluggableTransports()); +    } + +    @Test +    public void testSupportsPluggableTransports_Obfs4Kcp_obsvpn_returnsTrue() throws Exception { +        when(ConfigHelper.ObfsVpnHelper.useObfsVpn()).thenReturn(true); + +        Provider p1 = TestSetupHelper.getProvider( +                "https://pt.demo.bitmask.net", +                null, +                null, +                null, +                null, +                null, +                "ptdemo_only_experimental_transports_gateways.json", +                null); +        assertTrue(p1.supportsPluggableTransports()); +    } +  } diff --git a/app/src/test/resources/ptdemo_only_experimental_transports_gateways.json b/app/src/test/resources/ptdemo_only_experimental_transports_gateways.json new file mode 100644 index 00000000..31c919e7 --- /dev/null +++ b/app/src/test/resources/ptdemo_only_experimental_transports_gateways.json @@ -0,0 +1,134 @@ +{ +  "gateways":[ +    { +      "capabilities":{ +        "adblock":false, +        "filter_dns":false, +        "limited":false, +        "transport":[ +          { +            "type":"obfs4-1", +            "protocols":[ +              "tcp" +            ], +            "ports":[ +              "23050" +            ], +            "options": { +              "cert": "XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX1", +              "iatMode": "0" +            } +          }, +          { +            "type":"openvpn", +            "protocols":[ +              "tcp" +            ], +            "ports":[ +              "1195" +            ] +          } +        ], +        "user_ips":false +      }, +      "host":"pt.demo.bitmask.net", +      "ip_address":"37.218.247.60", +      "location":"Amsterdam" +    }, +    { +      "capabilities":{ +        "adblock":false, +        "filter_dns":false, +        "limited":false, +        "transport":[ +          { +            "type":"openvpn", +            "protocols":[ +              "tcp" +            ], +            "ports":[ +              "1195" +            ] +          } +        ], +        "user_ips":false +      }, +      "host":"moscow.bitmask.net", +      "ip_address":"3.21.247.89", +      "location":"moscow" +    }, +    { +      "capabilities":{ +        "adblock":false, +        "filter_dns":false, +        "limited":false, +        "transport":[ +          { +            "type":"openvpn", +            "protocols":[ +              "tcp", +              "udp" +            ], + +            "ports":[ +              "1195" +            ] +          }, +          { +            "type":"obfs4-1", +            "protocols":[ +              "tcp" +            ], +            "ports":[ +              "23050" +            ], +            "options": { +              "cert": "XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX1", +              "iatMode": "0" +            } +          } +        ], +        "user_ips":false +      }, +      "host":"manila.bitmask.net", +      "ip_address":"37.12.247.10", +      "location":"manila" +    } +  ], +  "locations":{ +    "Amsterdam":{ +      "country_code":"NL", +      "hemisphere":"N", +      "name":"Amsterdam", +      "timezone":"-1" +    }, +    "moscow": { +      "country_code": "RU", +      "hemisphere": "N", +      "name": "Moscow", +      "timezone": "+3" +    }, +    "manila": { +      "country_code": "PH", +      "hemisphere": "N", +      "name": "Manila", +      "timezone": "+8" +    } +  }, +  "openvpn_configuration":{ +    "auth":"SHA1", +    "cipher":"AES-256-CBC", +    "keepalive":"10 30", +    "tls-cipher":"DHE-RSA-AES128-SHA", +    "tun-ipv6":true, +    "dev" : "tun", +    "sndbuf" : "0", +    "rcvbuf" : "0", +    "nobind" : true, +    "persist-key" : true, +    "key-direction" : "1", +    "verb" : "3" +  }, +  "serial":2, +  "version":3 +}
\ No newline at end of file  | 
