summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--README.md10
-rw-r--r--app/src/main/java/se/leap/bitmaskclient/base/fragments/SettingsFragment.java80
-rw-r--r--app/src/main/java/se/leap/bitmaskclient/base/models/Constants.java1
-rw-r--r--app/src/main/java/se/leap/bitmaskclient/base/utils/PreferenceHelper.java9
-rw-r--r--app/src/main/java/se/leap/bitmaskclient/eip/GatewaysManager.java16
-rw-r--r--app/src/main/res/layout/f_settings.xml9
6 files changed, 106 insertions, 19 deletions
diff --git a/README.md b/README.md
index 2794acc1..fbf172cc 100644
--- a/README.md
+++ b/README.md
@@ -183,6 +183,16 @@ If you want to build and sign apks and aab bundles for the current commit, run:
Please check `./prepareFordistribution.sh -h` for all options!
+### Running unit tests
+
+Unit tests should always run against release builds, it is expected that some tests fail in debug builds.
+
+You can execute all unit tests from the command line with:
+
+```bash
+ ./gradlew testCustomProductionFatReleaseUnitTest testNormalProductionFatReleaseUnitTest
+```
+
## Supported Versions <a name="supported-versions"></a>
Currently API 16 (Android 4.1) - API 30 (Android 11) are officially supported. Keep backwards compatibility in mind if you plan to contribute new features.
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 be2fe4f4..f4531ff8 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
@@ -1,12 +1,35 @@
package se.leap.bitmaskclient.base.fragments;
+import static android.content.Context.MODE_PRIVATE;
+import static android.view.View.GONE;
+import static android.view.View.VISIBLE;
+import static se.leap.bitmaskclient.R.string.advanced_settings;
+import static se.leap.bitmaskclient.base.models.Constants.GATEWAY_PINNING;
+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.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.useBridges;
+import static se.leap.bitmaskclient.base.utils.PreferenceHelper.useSnowflake;
+import static se.leap.bitmaskclient.base.utils.ViewHelper.setActionBarTitle;
+
+import android.app.AlertDialog;
+import android.content.Context;
import android.content.Intent;
import android.content.SharedPreferences;
import android.os.Build;
import android.os.Bundle;
+import android.text.TextUtils;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
+import android.widget.EditText;
import android.widget.Toast;
import androidx.annotation.NonNull;
@@ -18,6 +41,7 @@ import androidx.fragment.app.FragmentTransaction;
import java.util.Set;
import de.blinkt.openvpn.core.VpnStatus;
+import se.leap.bitmaskclient.BuildConfig;
import se.leap.bitmaskclient.R;
import se.leap.bitmaskclient.base.FragmentManagerEnhanced;
import se.leap.bitmaskclient.base.MainActivity;
@@ -28,24 +52,6 @@ import se.leap.bitmaskclient.base.views.IconTextEntry;
import se.leap.bitmaskclient.eip.EipCommand;
import se.leap.bitmaskclient.firewall.FirewallManager;
-import static android.content.Context.MODE_PRIVATE;
-import static android.view.View.GONE;
-import static android.view.View.VISIBLE;
-import static se.leap.bitmaskclient.R.string.advanced_settings;
-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.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.useBridges;
-import static se.leap.bitmaskclient.base.utils.PreferenceHelper.useSnowflake;
-import static se.leap.bitmaskclient.base.utils.ViewHelper.setActionBarTitle;
-
public class SettingsFragment extends Fragment implements SharedPreferences.OnSharedPreferenceChangeListener {
private FirewallManager firewallManager;
@@ -74,6 +80,7 @@ public class SettingsFragment extends Fragment implements SharedPreferences.OnSh
initUseSnowflakeEntry(view);
initFirewallEntry(view);
initTetheringEntry(view);
+ initGatewayPinningEntry(view);
setActionBarTitle(this, advanced_settings);
return view;
}
@@ -207,6 +214,41 @@ public class SettingsFragment extends Fragment implements SharedPreferences.OnSh
});
}
+ private void initGatewayPinningEntry(View rootView) {
+ if (!BuildConfig.BUILD_TYPE.equals("debug")) {
+ return;
+ }
+ Context context = this.getContext();
+ if (context == null) {
+ return;
+ }
+ IconTextEntry gatewayPinning = rootView.findViewById(R.id.gateway_pinning);
+ String pinnedGateway = PreferenceHelper.getPinnedGateway(rootView.getContext());
+ gatewayPinning.setSubtitle(pinnedGateway != null ? pinnedGateway : "Connect to a specific Gateway for debugging purposes");
+
+ gatewayPinning.setOnClickListener(v -> {
+ EditText gatewayPinningEditText = new EditText(rootView.getContext());
+ gatewayPinningEditText.setText(pinnedGateway);
+ new AlertDialog.Builder(context)
+ .setTitle("Gateway Pinning")
+ .setMessage("Enter the domain name of the gateway")
+ .setView(gatewayPinningEditText)
+ .setPositiveButton(android.R.string.ok, (dialogInterface, i) -> {
+ if (gatewayPinningEditText.getText() != null) {
+ String editTextInput = gatewayPinningEditText.getText().toString();
+ if (!TextUtils.isEmpty(editTextInput)) {
+ PreferenceHelper.setPreferredCity(context, null);
+ PreferenceHelper.pinGateway(context, editTextInput);
+ } else {
+ PreferenceHelper.pinGateway(context, null);
+ }
+ }
+ })
+ .setNegativeButton(android.R.string.cancel, null)
+ .create().show();
+ });
+ }
+
public void showTetheringAlert() {
try {
@@ -245,6 +287,8 @@ public class SettingsFragment extends Fragment implements SharedPreferences.OnSh
initPreferUDPEntry(rootView);
} else if (key.equals(USE_IPv6_FIREWALL)) {
initFirewallEntry(getView());
+ } if (key.equals(GATEWAY_PINNING)) {
+ initGatewayPinningEntry(rootView);
}
}
diff --git a/app/src/main/java/se/leap/bitmaskclient/base/models/Constants.java b/app/src/main/java/se/leap/bitmaskclient/base/models/Constants.java
index 86b438f8..bde909ba 100644
--- a/app/src/main/java/se/leap/bitmaskclient/base/models/Constants.java
+++ b/app/src/main/java/se/leap/bitmaskclient/base/models/Constants.java
@@ -43,6 +43,7 @@ public interface Constants {
String PREFERRED_CITY = "preferred_city";
String USE_SNOWFLAKE = "use_snowflake";
String PREFER_UDP = "prefer_UDP";
+ String GATEWAY_PINNING = "gateway_pinning";
//////////////////////////////////////////////
diff --git a/app/src/main/java/se/leap/bitmaskclient/base/utils/PreferenceHelper.java b/app/src/main/java/se/leap/bitmaskclient/base/utils/PreferenceHelper.java
index fe9100cb..08bfbdc3 100644
--- a/app/src/main/java/se/leap/bitmaskclient/base/utils/PreferenceHelper.java
+++ b/app/src/main/java/se/leap/bitmaskclient/base/utils/PreferenceHelper.java
@@ -26,6 +26,7 @@ import static se.leap.bitmaskclient.base.models.Constants.ALLOW_TETHERING_WIFI;
import static se.leap.bitmaskclient.base.models.Constants.ALWAYS_ON_SHOW_DIALOG;
import static se.leap.bitmaskclient.base.models.Constants.DEFAULT_SHARED_PREFS_BATTERY_SAVER;
import static se.leap.bitmaskclient.base.models.Constants.EXCLUDED_APPS;
+import static se.leap.bitmaskclient.base.models.Constants.GATEWAY_PINNING;
import static se.leap.bitmaskclient.base.models.Constants.LAST_UPDATE_CHECK;
import static se.leap.bitmaskclient.base.models.Constants.LAST_USED_PROFILE;
import static se.leap.bitmaskclient.base.models.Constants.PREFERRED_CITY;
@@ -154,6 +155,14 @@ public class PreferenceHelper {
putBoolean(context, PREFER_UDP, prefer);
}
+ public static String getPinnedGateway(Context context) {
+ return getString(context, GATEWAY_PINNING, null);
+ }
+
+ public static void pinGateway(Context context, String value) {
+ putString(context, GATEWAY_PINNING, value);
+ }
+
public static boolean getUseBridges(SharedPreferences preferences) {
return preferences.getBoolean(USE_BRIDGES, false);
}
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 76ec9650..7fc810cc 100644
--- a/app/src/main/java/se/leap/bitmaskclient/eip/GatewaysManager.java
+++ b/app/src/main/java/se/leap/bitmaskclient/eip/GatewaysManager.java
@@ -41,6 +41,7 @@ import de.blinkt.openvpn.core.ConfigParser;
import de.blinkt.openvpn.core.VpnStatus;
import de.blinkt.openvpn.core.connection.Connection;
import de.blinkt.openvpn.core.connection.Connection.TransportType;
+import se.leap.bitmaskclient.BuildConfig;
import se.leap.bitmaskclient.base.models.Location;
import se.leap.bitmaskclient.base.models.Provider;
import se.leap.bitmaskclient.base.models.ProviderObservable;
@@ -419,7 +420,9 @@ public class GatewaysManager {
private void configureFromCurrentProvider() {
Provider provider = ProviderObservable.getInstance().getCurrentProvider();
parseDefaultGateways(provider);
- if (hasSortedGatewaysWithLoad(provider)) {
+ if (BuildConfig.BUILD_TYPE.equals("debug")) {
+ keepOnlyPinnedGateway();
+ } else if (hasSortedGatewaysWithLoad(provider)) {
parseGatewaysWithLoad(provider);
} else {
parseSimpleGatewayList(provider);
@@ -427,5 +430,16 @@ public class GatewaysManager {
}
+ private void keepOnlyPinnedGateway() {
+ String host = PreferenceHelper.getPinnedGateway(this.context);
+ if (host == null) {
+ return;
+ }
+ Gateway gateway = gateways.get(host);
+ gateways.clear();
+ if (gateway != null) {
+ gateways.put(host, gateway);
+ }
+ }
}
diff --git a/app/src/main/res/layout/f_settings.xml b/app/src/main/res/layout/f_settings.xml
index 398d2c86..7b8733cd 100644
--- a/app/src/main/res/layout/f_settings.xml
+++ b/app/src/main/res/layout/f_settings.xml
@@ -105,5 +105,14 @@
app:icon="@drawable/ic_access_point_36"
/>
+ <se.leap.bitmaskclient.base.views.IconTextEntry
+ android:id="@+id/gateway_pinning"
+ android:layout_width="match_parent"
+ android:layout_height="wrap_content"
+ app:text="Gateway pinning"
+ app:singleLine="false"
+ app:subtitle="Connect to a specific Gateway for debugging purposes"
+ />
+
</LinearLayout>
</ScrollView> \ No newline at end of file