diff options
6 files changed, 106 insertions, 19 deletions
@@ -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 |