summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorcyBerta <cyberta@riseup.net>2022-07-15 22:08:57 +0200
committercyBerta <cyberta@riseup.net>2022-07-19 00:06:12 +0200
commit472a3fdb9c9036f5666e65b5dfd9bd91a51563f8 (patch)
tree42d36b0adf658f41add285e48204ecd5b1ee5206
parent93c7fd8c592a85341e8dff594ba1ec535aa103c2 (diff)
add UI to enable experimental kcp transport if the client uses obfsvpn instead of shapeshifter and the provider supports the kcp variant
-rw-r--r--app/src/main/java/se/leap/bitmaskclient/base/fragments/SettingsFragment.java21
-rw-r--r--app/src/main/java/se/leap/bitmaskclient/base/models/Provider.java27
-rw-r--r--app/src/main/res/layout/f_settings.xml9
-rw-r--r--app/src/test/java/se/leap/bitmaskclient/base/models/ProviderTest.java83
-rw-r--r--app/src/test/resources/ptdemo_only_experimental_transports_gateways.json134
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