From a7725722c35136c42c9acc242a50588e1fac8bb0 Mon Sep 17 00:00:00 2001 From: cyBerta Date: Wed, 17 Jan 2024 15:16:30 +0100 Subject: replace deprectated Observer and Observables by PropertyChangeListener and PropertyChangeSupport --- .../bitmaskclient/base/BitmaskTileService.java | 13 ++++---- .../se/leap/bitmaskclient/base/MainActivity.java | 12 ++++---- .../bitmaskclient/base/fragments/EipFragment.java | 36 ++++++++++++++-------- .../base/fragments/GatewaySelectionFragment.java | 10 +++--- .../base/fragments/NavigationDrawerFragment.java | 10 +++--- .../base/fragments/TetheringDialog.java | 13 ++++---- .../base/models/ProviderObservable.java | 24 ++++++++++++--- 7 files changed, 73 insertions(+), 45 deletions(-) (limited to 'app/src/main/java/se/leap/bitmaskclient/base') diff --git a/app/src/main/java/se/leap/bitmaskclient/base/BitmaskTileService.java b/app/src/main/java/se/leap/bitmaskclient/base/BitmaskTileService.java index 370a7af6..d85e0a75 100644 --- a/app/src/main/java/se/leap/bitmaskclient/base/BitmaskTileService.java +++ b/app/src/main/java/se/leap/bitmaskclient/base/BitmaskTileService.java @@ -8,6 +8,8 @@ import android.os.Build; import android.service.quicksettings.Tile; import android.service.quicksettings.TileService; +import java.beans.PropertyChangeEvent; +import java.beans.PropertyChangeListener; import java.util.Observable; import java.util.Observer; @@ -19,7 +21,7 @@ import se.leap.bitmaskclient.base.models.ProviderObservable; @TargetApi(Build.VERSION_CODES.N) -public class BitmaskTileService extends TileService implements Observer { +public class BitmaskTileService extends TileService implements PropertyChangeListener { @SuppressLint("Override") @TargetApi(Build.VERSION_CODES.N) @@ -59,7 +61,7 @@ public class BitmaskTileService extends TileService implements Observer { public void onStartListening() { super.onStartListening(); EipStatus.getInstance().addObserver(this); - update(EipStatus.getInstance(), null); + propertyChange(new PropertyChangeEvent(EipStatus.getInstance(), EipStatus.PROPERTY_CHANGE, null, EipStatus.getInstance())); } @Override @@ -69,16 +71,15 @@ public class BitmaskTileService extends TileService implements Observer { } @Override - public void update(Observable o, Object arg) { + public void propertyChange(PropertyChangeEvent evt) { Tile t = getQsTile(); // Tile t should never be null according to https://developer.android.com/reference/kotlin/android/service/quicksettings/TileService. // Hovever we've got crash reports. if (t == null) { return; } - - if (o instanceof EipStatus) { - EipStatus status = (EipStatus) o; + if (EipStatus.PROPERTY_CHANGE.equals(evt.getPropertyName())) { + EipStatus status = (EipStatus) evt.getNewValue(); Icon icon; String title; if (status.isConnecting() || status.isReconnecting()) { diff --git a/app/src/main/java/se/leap/bitmaskclient/base/MainActivity.java b/app/src/main/java/se/leap/bitmaskclient/base/MainActivity.java index 5da238d4..3f541d8d 100644 --- a/app/src/main/java/se/leap/bitmaskclient/base/MainActivity.java +++ b/app/src/main/java/se/leap/bitmaskclient/base/MainActivity.java @@ -59,8 +59,8 @@ import androidx.fragment.app.FragmentTransaction; import org.json.JSONException; import org.json.JSONObject; -import java.util.Observable; -import java.util.Observer; +import java.beans.PropertyChangeEvent; +import java.beans.PropertyChangeListener; import se.leap.bitmaskclient.BuildConfig; import se.leap.bitmaskclient.R; @@ -80,7 +80,7 @@ import se.leap.bitmaskclient.eip.EipSetupListener; import se.leap.bitmaskclient.eip.EipSetupObserver; import se.leap.bitmaskclient.providersetup.ProviderAPI; -public class MainActivity extends AppCompatActivity implements EipSetupListener, Observer { +public class MainActivity extends AppCompatActivity implements EipSetupListener, PropertyChangeListener { public final static String TAG = MainActivity.class.getSimpleName(); @@ -354,9 +354,9 @@ public class MainActivity extends AppCompatActivity implements EipSetupListener, } @Override - public void update(Observable o, Object arg) { - if (o instanceof ProviderObservable) { - this.provider = ((ProviderObservable) o).getCurrentProvider(); + public void propertyChange(PropertyChangeEvent evt) { + if (ProviderObservable.PROPERTY_CHANGE.equals(evt.getPropertyName())) { + this.provider = (Provider) evt.getNewValue(); } } diff --git a/app/src/main/java/se/leap/bitmaskclient/base/fragments/EipFragment.java b/app/src/main/java/se/leap/bitmaskclient/base/fragments/EipFragment.java index f4e09e62..fb93796e 100644 --- a/app/src/main/java/se/leap/bitmaskclient/base/fragments/EipFragment.java +++ b/app/src/main/java/se/leap/bitmaskclient/base/fragments/EipFragment.java @@ -56,8 +56,8 @@ import androidx.fragment.app.FragmentTransaction; import androidx.vectordrawable.graphics.drawable.Animatable2Compat.AnimationCallback; import androidx.vectordrawable.graphics.drawable.AnimatedVectorDrawableCompat; -import java.util.Observable; -import java.util.Observer; +import java.beans.PropertyChangeEvent; +import java.beans.PropertyChangeListener; import de.blinkt.openvpn.core.ConnectionStatus; import de.blinkt.openvpn.core.VpnStatus; @@ -80,7 +80,7 @@ import se.leap.bitmaskclient.providersetup.activities.SetupActivity; import se.leap.bitmaskclient.tor.TorServiceCommand; import se.leap.bitmaskclient.tor.TorStatusObservable; -public class EipFragment extends Fragment implements Observer { +public class EipFragment extends Fragment implements PropertyChangeListener { public final static String TAG = EipFragment.class.getSimpleName(); @@ -375,17 +375,27 @@ public class EipFragment extends Fragment implements Observer { } + @Override - public void update(Observable observable, Object data) { - if (observable instanceof EipStatus) { - previousEipLevel = eipStatus.getEipLevel(); - eipStatus = (EipStatus) observable; - handleNewStateOnMain(); - - } else if (observable instanceof ProviderObservable) { - provider = ((ProviderObservable) observable).getCurrentProvider(); - } else if (observable instanceof TorStatusObservable && EipStatus.getInstance().isUpdatingVpnCert()) { - handleNewStateOnMain(); + public void propertyChange(PropertyChangeEvent evt) { + switch (evt.getPropertyName()) { + case ProviderObservable.PROPERTY_CHANGE: { + provider = ((Provider) evt.getNewValue()); + break; + } + case TorStatusObservable.PROPERTY_CHANGE: { + if (EipStatus.getInstance().isUpdatingVpnCert()) { + handleNewStateOnMain(); + } + break; + } + case EipStatus.PROPERTY_CHANGE: { + previousEipLevel = eipStatus.getEipLevel(); + eipStatus = (EipStatus) evt.getNewValue(); + handleNewStateOnMain(); + break; + } + default: {} } } diff --git a/app/src/main/java/se/leap/bitmaskclient/base/fragments/GatewaySelectionFragment.java b/app/src/main/java/se/leap/bitmaskclient/base/fragments/GatewaySelectionFragment.java index 99b1ac39..bb5a06c4 100644 --- a/app/src/main/java/se/leap/bitmaskclient/base/fragments/GatewaySelectionFragment.java +++ b/app/src/main/java/se/leap/bitmaskclient/base/fragments/GatewaySelectionFragment.java @@ -44,6 +44,8 @@ import androidx.fragment.app.Fragment; import androidx.recyclerview.widget.LinearLayoutManager; import androidx.recyclerview.widget.RecyclerView; +import java.beans.PropertyChangeEvent; +import java.beans.PropertyChangeListener; import java.lang.ref.WeakReference; import java.util.List; import java.util.Observable; @@ -64,7 +66,7 @@ interface LocationListSelectionListener { void onLocationManuallySelected(Location location); } -public class GatewaySelectionFragment extends Fragment implements Observer, LocationListSelectionListener, SharedPreferences.OnSharedPreferenceChangeListener { +public class GatewaySelectionFragment extends Fragment implements PropertyChangeListener, LocationListSelectionListener, SharedPreferences.OnSharedPreferenceChangeListener { private static final String TAG = GatewaySelectionFragment.class.getSimpleName(); @@ -197,9 +199,9 @@ public class GatewaySelectionFragment extends Fragment implements Observer, Loca } @Override - public void update(Observable o, Object arg) { - if (o instanceof EipStatus) { - eipStatus = (EipStatus) o; + public void propertyChange(PropertyChangeEvent evt) { + if (EipStatus.PROPERTY_CHANGE.equals(evt.getPropertyName())) { + eipStatus = (EipStatus) evt.getNewValue(); Activity activity = getActivity(); if (activity != null) { activity.runOnUiThread(this::updateRecommendedLocation); diff --git a/app/src/main/java/se/leap/bitmaskclient/base/fragments/NavigationDrawerFragment.java b/app/src/main/java/se/leap/bitmaskclient/base/fragments/NavigationDrawerFragment.java index 60c21c40..e74d70a2 100644 --- a/app/src/main/java/se/leap/bitmaskclient/base/fragments/NavigationDrawerFragment.java +++ b/app/src/main/java/se/leap/bitmaskclient/base/fragments/NavigationDrawerFragment.java @@ -53,8 +53,8 @@ import androidx.core.view.GravityCompat; import androidx.drawerlayout.widget.DrawerLayout; import androidx.fragment.app.Fragment; -import java.util.Observable; -import java.util.Observer; +import java.beans.PropertyChangeEvent; +import java.beans.PropertyChangeListener; import se.leap.bitmaskclient.BuildConfig; import se.leap.bitmaskclient.R; @@ -74,7 +74,7 @@ import se.leap.bitmaskclient.tethering.TetheringObservable; * See the * design guidelines for a complete explanation of the behaviors implemented here. */ -public class NavigationDrawerFragment extends Fragment implements SharedPreferences.OnSharedPreferenceChangeListener, Observer { +public class NavigationDrawerFragment extends Fragment implements SharedPreferences.OnSharedPreferenceChangeListener, PropertyChangeListener { /** * Per the design guidelines, you should show the drawer on launch until the user manually @@ -444,8 +444,8 @@ public class NavigationDrawerFragment extends Fragment implements SharedPreferen } @Override - public void update(Observable o, Object arg) { - if (o instanceof TetheringObservable || o instanceof EipStatus) { + public void propertyChange(PropertyChangeEvent evt) { + if (EipStatus.PROPERTY_CHANGE.equals(evt.getPropertyName()) || TetheringObservable.PROPERTY_CHANGE.equals(evt.getPropertyName())) { try { getActivity().runOnUiThread(() -> enableSaveBatteryEntry(!TetheringObservable.getInstance().getTetheringState().isVpnTetheringRunning())); diff --git a/app/src/main/java/se/leap/bitmaskclient/base/fragments/TetheringDialog.java b/app/src/main/java/se/leap/bitmaskclient/base/fragments/TetheringDialog.java index 588daa3f..05744bc9 100644 --- a/app/src/main/java/se/leap/bitmaskclient/base/fragments/TetheringDialog.java +++ b/app/src/main/java/se/leap/bitmaskclient/base/fragments/TetheringDialog.java @@ -22,8 +22,8 @@ import androidx.appcompat.app.AppCompatDialogFragment; import androidx.recyclerview.widget.LinearLayoutManager; import androidx.recyclerview.widget.RecyclerView; -import java.util.Observable; -import java.util.Observer; +import java.beans.PropertyChangeEvent; +import java.beans.PropertyChangeListener; import java.util.regex.Matcher; import java.util.regex.Pattern; @@ -52,7 +52,7 @@ import se.leap.bitmaskclient.tethering.TetheringObservable; * along with this program. If not, see . */ -public class TetheringDialog extends AppCompatDialogFragment implements Observer { +public class TetheringDialog extends AppCompatDialogFragment implements PropertyChangeListener { public final static String TAG = TetheringDialog.class.getName(); @@ -241,9 +241,9 @@ public class TetheringDialog extends AppCompatDialogFragment implements Observer } @Override - public void update(Observable o, Object arg) { - if (o instanceof TetheringObservable) { - TetheringObservable observable = (TetheringObservable) o; + public void propertyChange(PropertyChangeEvent evt) { + if (TetheringObservable.PROPERTY_CHANGE.equals(evt.getPropertyName())) { + TetheringObservable observable = (TetheringObservable) evt.getNewValue(); Log.d(TAG, "TetheringObservable is updated"); dataset[0].enabled = observable.isWifiTetheringEnabled(); dataset[1].enabled = observable.isUsbTetheringEnabled(); @@ -251,5 +251,4 @@ public class TetheringDialog extends AppCompatDialogFragment implements Observer adapter.notifyDataSetChanged(); } } - } diff --git a/app/src/main/java/se/leap/bitmaskclient/base/models/ProviderObservable.java b/app/src/main/java/se/leap/bitmaskclient/base/models/ProviderObservable.java index 3e1e1fcc..6e28ac3e 100644 --- a/app/src/main/java/se/leap/bitmaskclient/base/models/ProviderObservable.java +++ b/app/src/main/java/se/leap/bitmaskclient/base/models/ProviderObservable.java @@ -2,13 +2,17 @@ package se.leap.bitmaskclient.base.models; import androidx.annotation.NonNull; -import java.util.Observable; +import java.beans.PropertyChangeListener; +import java.beans.PropertyChangeSupport; /** * Created by cyberta on 05.12.18. */ -public class ProviderObservable extends Observable { +public class ProviderObservable { private static ProviderObservable instance; + private final PropertyChangeSupport changeSupport; + public static final String PROPERTY_CHANGE = "ProviderObservable"; + private Provider currentProvider; private Provider providerForDns; @@ -19,11 +23,23 @@ public class ProviderObservable extends Observable { return instance; } + private ProviderObservable() { + changeSupport = new PropertyChangeSupport(this); + currentProvider = new Provider(); + } + + public void addObserver(PropertyChangeListener propertyChangeListener) { + changeSupport.addPropertyChangeListener(propertyChangeListener); + } + + public void deleteObserver(PropertyChangeListener propertyChangeListener) { + changeSupport.removePropertyChangeListener(propertyChangeListener); + } + public synchronized void updateProvider(@NonNull Provider provider) { instance.currentProvider = provider; instance.providerForDns = null; - instance.setChanged(); - instance.notifyObservers(); + instance.changeSupport.firePropertyChange(PROPERTY_CHANGE, null, provider); } public Provider getCurrentProvider() { -- cgit v1.2.3 From 5db48094b7cbc4bab12e2fe8476ff1404971e49c Mon Sep 17 00:00:00 2001 From: cyBerta Date: Wed, 24 Jan 2024 21:59:27 +0100 Subject: fix GatewaySelectorTest, introduce TimezoneHelper --- .../bitmaskclient/base/utils/ConfigHelper.java | 18 ++-------- .../bitmaskclient/base/utils/TimezoneHelper.java | 42 ++++++++++++++++++++++ 2 files changed, 44 insertions(+), 16 deletions(-) create mode 100644 app/src/main/java/se/leap/bitmaskclient/base/utils/TimezoneHelper.java (limited to 'app/src/main/java/se/leap/bitmaskclient/base') diff --git a/app/src/main/java/se/leap/bitmaskclient/base/utils/ConfigHelper.java b/app/src/main/java/se/leap/bitmaskclient/base/utils/ConfigHelper.java index 9289738a..d416a1ab 100644 --- a/app/src/main/java/se/leap/bitmaskclient/base/utils/ConfigHelper.java +++ b/app/src/main/java/se/leap/bitmaskclient/base/utils/ConfigHelper.java @@ -48,7 +48,6 @@ import java.security.interfaces.RSAPrivateKey; import java.security.spec.InvalidKeySpecException; import java.security.spec.PKCS8EncodedKeySpec; import java.util.ArrayList; -import java.util.Calendar; import java.util.regex.Matcher; import java.util.regex.Pattern; @@ -206,27 +205,14 @@ public class ConfigHelper { return BuildConfig.priotize_anonymous_usage; } - public static int getCurrentTimezone() { - return Calendar.getInstance().get(Calendar.ZONE_OFFSET) / 3600000; - } - - public static int timezoneDistance(int local_timezone, int remoteTimezone) { - // Distance along the numberline of Prime Meridian centric, assumes UTC-11 through UTC+12 - int dist = Math.abs(local_timezone - remoteTimezone); - // Farther than 12 timezones and it's shorter around the "back" - if (dist > 12) - dist = 12 - (dist - 12); // Well i'll be. Absolute values make equations do funny things. - return dist; - } - /** * * @param remoteTimezone * @return a value between 0.1 and 1.0 */ public static double getConnectionQualityFromTimezoneDistance(int remoteTimezone) { - int localTimeZone = ConfigHelper.getCurrentTimezone(); - int distance = ConfigHelper.timezoneDistance(localTimeZone, remoteTimezone); + int localTimeZone = TimezoneHelper.getCurrentTimezone(); + int distance = TimezoneHelper.timezoneDistance(localTimeZone, remoteTimezone); return Math.max(distance / 12.0, 0.1); } diff --git a/app/src/main/java/se/leap/bitmaskclient/base/utils/TimezoneHelper.java b/app/src/main/java/se/leap/bitmaskclient/base/utils/TimezoneHelper.java new file mode 100644 index 00000000..c543368d --- /dev/null +++ b/app/src/main/java/se/leap/bitmaskclient/base/utils/TimezoneHelper.java @@ -0,0 +1,42 @@ +package se.leap.bitmaskclient.base.utils; + +import androidx.annotation.VisibleForTesting; + +import java.util.Calendar; + +public class TimezoneHelper { + + public interface TimezoneInterface { + int getCurrentTimezone(); + } + + private static TimezoneInterface instance = new DefaultTimezoneHelper(); + + @VisibleForTesting + public TimezoneHelper(TimezoneInterface timezoneInterface) { + instance = timezoneInterface; + } + + public static TimezoneInterface get() { + return instance; + } + + public static int timezoneDistance(int localTimezone, int remoteTimezone) { // Distance along the numberline of Prime Meridian centric, assumes UTC-11 through UTC+12 + int dist = Math.abs(localTimezone - remoteTimezone); + // Farther than 12 timezones and it's shorter around the "back" + if (dist > 12) + dist = 12 - (dist - 12); // Well i'll be. Absolute values make equations do funny things. + return dist; + } + + public static int getCurrentTimezone() { + return get().getCurrentTimezone(); + } + + public static class DefaultTimezoneHelper implements TimezoneInterface { + @Override + public int getCurrentTimezone() { + return Calendar.getInstance().get(Calendar.ZONE_OFFSET) / 3600000; + } + } +} -- cgit v1.2.3 From ed8a28962675b540389fc9280ab1122613230fa8 Mon Sep 17 00:00:00 2001 From: cyBerta Date: Thu, 25 Jan 2024 01:26:05 +0100 Subject: fix ProviderManagerTest, adapt InputStreamHelper and Filehelper to be mockable by injection --- .../leap/bitmaskclient/base/utils/FileHelper.java | 41 +++++++++++++++++++--- .../base/utils/InputStreamHelper.java | 24 ++++++++++++- 2 files changed, 60 insertions(+), 5 deletions(-) (limited to 'app/src/main/java/se/leap/bitmaskclient/base') diff --git a/app/src/main/java/se/leap/bitmaskclient/base/utils/FileHelper.java b/app/src/main/java/se/leap/bitmaskclient/base/utils/FileHelper.java index eb1c255c..f1d86876 100644 --- a/app/src/main/java/se/leap/bitmaskclient/base/utils/FileHelper.java +++ b/app/src/main/java/se/leap/bitmaskclient/base/utils/FileHelper.java @@ -2,6 +2,8 @@ package se.leap.bitmaskclient.base.utils; import android.content.Context; +import androidx.annotation.VisibleForTesting; + import java.io.BufferedReader; import java.io.File; import java.io.FileWriter; @@ -9,19 +11,50 @@ import java.io.IOException; import java.io.InputStream; import java.io.InputStreamReader; +import de.blinkt.openvpn.core.NativeUtils; + /** * Created by cyberta on 18.03.18. */ public class FileHelper { + + public interface FileHelperInterface { + File createFile(File dir, String fileName); + void persistFile(File file, String content) throws IOException; + } + + public static class DefaultFileHelper implements FileHelperInterface { + @Override + public File createFile(File dir, String fileName) { + return new File(dir, fileName); + } + + @Override + public void persistFile(File file, String content) throws IOException { + FileWriter writer = new FileWriter(file); + writer.write(content); + writer.close(); + } + } + + private static FileHelperInterface instance = new DefaultFileHelper(); + + @VisibleForTesting + public FileHelper(FileHelperInterface helperInterface) { + if (!NativeUtils.isUnitTest()) { + throw new IllegalStateException("FileHelper injected with FileHelperInterface outside of an unit test"); + } + + instance = helperInterface; + } + public static File createFile(File dir, String fileName) { - return new File(dir, fileName); + return instance.createFile(dir, fileName); } public static void persistFile(File file, String content) throws IOException { - FileWriter writer = new FileWriter(file); - writer.write(content); - writer.close(); + instance.persistFile(file, content); } public static String readPublicKey(Context context) { diff --git a/app/src/main/java/se/leap/bitmaskclient/base/utils/InputStreamHelper.java b/app/src/main/java/se/leap/bitmaskclient/base/utils/InputStreamHelper.java index 8e6273a7..6dfe0861 100644 --- a/app/src/main/java/se/leap/bitmaskclient/base/utils/InputStreamHelper.java +++ b/app/src/main/java/se/leap/bitmaskclient/base/utils/InputStreamHelper.java @@ -8,14 +8,36 @@ import java.io.FileNotFoundException; import java.io.IOException; import java.io.InputStream; +import de.blinkt.openvpn.core.NativeUtils; + /** * Created by cyberta on 18.03.18. */ public class InputStreamHelper { + public interface InputStreamHelperInterface { + InputStream getInputStreamFrom(String filePath) throws FileNotFoundException; + + } + + private static InputStreamHelperInterface instance = new DefaultInputStreamHelper(); + + private static class DefaultInputStreamHelper implements InputStreamHelperInterface { + @Override + public InputStream getInputStreamFrom(String filePath) throws FileNotFoundException { + return new FileInputStream(filePath); + } + } + + public InputStreamHelper(InputStreamHelperInterface helperInterface) { + if (!NativeUtils.isUnitTest()) { + throw new IllegalStateException("InputStreamHelper injected with InputStreamHelperInterface outside of an unit test"); + } + instance = helperInterface; + } //allows us to mock FileInputStream public static InputStream getInputStreamFrom(String filePath) throws FileNotFoundException { - return new FileInputStream(filePath); + return instance.getInputStreamFrom(filePath); } public static String loadInputStreamAsString(InputStream is) { -- cgit v1.2.3 From 23278cefe308043228c9da9b4937d27888146206 Mon Sep 17 00:00:00 2001 From: cyBerta Date: Thu, 25 Jan 2024 02:32:55 +0100 Subject: fix VpnConfigGenerator Test, move RSAHelper and ObfsVpnHelper out of ConfigHelper, use injection pattern for these helpers --- .../base/fragments/ObfuscationProxyDialog.java | 2 +- .../base/fragments/SettingsFragment.java | 2 +- .../leap/bitmaskclient/base/models/Constants.java | 1 + .../leap/bitmaskclient/base/models/Provider.java | 4 +- .../bitmaskclient/base/utils/ConfigHelper.java | 67 ----------------- .../bitmaskclient/base/utils/ObfsVpnHelper.java | 86 ++++++++++++++++++++++ .../bitmaskclient/base/utils/PreferenceHelper.java | 7 +- .../leap/bitmaskclient/base/utils/RSAHelper.java | 72 ++++++++++++++++++ 8 files changed, 169 insertions(+), 72 deletions(-) create mode 100644 app/src/main/java/se/leap/bitmaskclient/base/utils/ObfsVpnHelper.java create mode 100644 app/src/main/java/se/leap/bitmaskclient/base/utils/RSAHelper.java (limited to 'app/src/main/java/se/leap/bitmaskclient/base') diff --git a/app/src/main/java/se/leap/bitmaskclient/base/fragments/ObfuscationProxyDialog.java b/app/src/main/java/se/leap/bitmaskclient/base/fragments/ObfuscationProxyDialog.java index 948d764f..635af701 100644 --- a/app/src/main/java/se/leap/bitmaskclient/base/fragments/ObfuscationProxyDialog.java +++ b/app/src/main/java/se/leap/bitmaskclient/base/fragments/ObfuscationProxyDialog.java @@ -15,7 +15,7 @@ import androidx.appcompat.app.AppCompatDialogFragment; import androidx.appcompat.widget.AppCompatButton; import androidx.appcompat.widget.AppCompatEditText; -import se.leap.bitmaskclient.base.utils.ConfigHelper.ObfsVpnHelper; +import se.leap.bitmaskclient.base.utils.ObfsVpnHelper; import se.leap.bitmaskclient.base.utils.PreferenceHelper; import se.leap.bitmaskclient.base.views.IconSwitchEntry; import se.leap.bitmaskclient.databinding.DObfuscationProxyBinding; 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 c8c994a5..77becc80 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 @@ -8,7 +8,7 @@ import static se.leap.bitmaskclient.base.models.Constants.PREFER_UDP; 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.models.Constants.USE_OBFUSCATION_PINNING; -import static se.leap.bitmaskclient.base.utils.ConfigHelper.ObfsVpnHelper.useObfsVpn; +import static se.leap.bitmaskclient.base.utils.ObfsVpnHelper.useObfsVpn; import static se.leap.bitmaskclient.base.utils.ConfigHelper.isCalyxOSWithTetheringSupport; import static se.leap.bitmaskclient.base.utils.PreferenceHelper.allowExperimentalTransports; import static se.leap.bitmaskclient.base.utils.PreferenceHelper.getExcludedApps; 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 70bf3943..18590f0b 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 @@ -52,6 +52,7 @@ public interface Constants { String OBFUSCATION_PINNING_CERT = "obfuscation_pinning_cert"; String OBFUSCATION_PINNING_KCP = "obfuscation_pinning_udp"; String OBFUSCATION_PINNING_LOCATION = "obfuscation_pinning_location"; + String USE_SYSTEM_PROXY = "usesystemproxy"; ////////////////////////////////////////////// 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 14c78cc3..af9122de 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 @@ -28,8 +28,8 @@ 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.base.utils.ConfigHelper.RSAHelper.parseRsaKeyFromString; +import static se.leap.bitmaskclient.base.utils.ObfsVpnHelper.useObfsVpn; +import static se.leap.bitmaskclient.base.utils.RSAHelper.parseRsaKeyFromString; import static se.leap.bitmaskclient.providersetup.ProviderAPI.ERRORS; import android.os.Parcel; diff --git a/app/src/main/java/se/leap/bitmaskclient/base/utils/ConfigHelper.java b/app/src/main/java/se/leap/bitmaskclient/base/utils/ConfigHelper.java index d416a1ab..a06d85be 100644 --- a/app/src/main/java/se/leap/bitmaskclient/base/utils/ConfigHelper.java +++ b/app/src/main/java/se/leap/bitmaskclient/base/utils/ConfigHelper.java @@ -36,17 +36,12 @@ import java.io.ByteArrayInputStream; import java.io.IOException; import java.io.InputStream; import java.math.BigInteger; -import java.security.KeyFactory; import java.security.MessageDigest; import java.security.NoSuchAlgorithmException; -import java.security.NoSuchProviderException; import java.security.cert.CertificateEncodingException; import java.security.cert.CertificateException; import java.security.cert.CertificateFactory; import java.security.cert.X509Certificate; -import java.security.interfaces.RSAPrivateKey; -import java.security.spec.InvalidKeySpecException; -import java.security.spec.PKCS8EncodedKeySpec; import java.util.ArrayList; import java.util.regex.Matcher; import java.util.regex.Pattern; @@ -130,39 +125,6 @@ public class ConfigHelper { return null; } - public static class RSAHelper { - public static RSAPrivateKey parseRsaKeyFromString(String rsaKeyString) { - RSAPrivateKey key; - try { - KeyFactory kf; - if (Build.VERSION.SDK_INT < Build.VERSION_CODES.P) { - kf = KeyFactory.getInstance("RSA", "BC"); - } else { - kf = KeyFactory.getInstance("RSA"); - } - rsaKeyString = rsaKeyString.replaceFirst("-----BEGIN RSA PRIVATE KEY-----", "").replaceFirst("-----END RSA PRIVATE KEY-----", ""); - PKCS8EncodedKeySpec keySpec = new PKCS8EncodedKeySpec(Base64.decode(rsaKeyString)); - key = (RSAPrivateKey) kf.generatePrivate(keySpec); - } catch (InvalidKeySpecException e) { - // TODO Auto-generated catch block - e.printStackTrace(); - return null; - } catch (NoSuchAlgorithmException e) { - // TODO Auto-generated catch block - e.printStackTrace(); - return null; - } catch (NullPointerException e) { - e.printStackTrace(); - return null; - } catch (NoSuchProviderException e) { - e.printStackTrace(); - return null; - } - - return key; - } - } - private static String byteArrayToHex(byte[] input) { int readBytes = input.length; StringBuffer hexData = new StringBuffer(); @@ -273,35 +235,6 @@ public class ConfigHelper { Build.VERSION.SDK_INT >= Build.VERSION_CODES.R; } - // ObfsVpnHelper class allows us to mock BuildConfig.use_obfsvpn while - // not mocking the whole ConfigHelper class - public static class ObfsVpnHelper { - public static boolean useObfsVpn() { - return BuildConfig.use_obfsvpn; - } - - public static boolean hasObfuscationPinningDefaults() { - return BuildConfig.obfsvpn_ip != null && - BuildConfig.obfsvpn_port != null && - BuildConfig.obfsvpn_cert != null && - !BuildConfig.obfsvpn_ip.isEmpty() && - !BuildConfig.obfsvpn_port.isEmpty() && - !BuildConfig.obfsvpn_cert.isEmpty(); - } - public static String obfsvpnIP() { - return BuildConfig.obfsvpn_ip; - } - public static String obfsvpnPort() { - return BuildConfig.obfsvpn_port; - } - public static String obfsvpnCert() { - return BuildConfig.obfsvpn_cert; - } - public static boolean useKcp() { - return BuildConfig.obfsvpn_use_kcp; - } - } - public static int getPendingIntentFlags() { int flags = PendingIntent.FLAG_CANCEL_CURRENT; if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.S) { diff --git a/app/src/main/java/se/leap/bitmaskclient/base/utils/ObfsVpnHelper.java b/app/src/main/java/se/leap/bitmaskclient/base/utils/ObfsVpnHelper.java new file mode 100644 index 00000000..054c85b3 --- /dev/null +++ b/app/src/main/java/se/leap/bitmaskclient/base/utils/ObfsVpnHelper.java @@ -0,0 +1,86 @@ +package se.leap.bitmaskclient.base.utils; + +import androidx.annotation.VisibleForTesting; + +import de.blinkt.openvpn.core.NativeUtils; +import se.leap.bitmaskclient.BuildConfig; + +// ObfsVpnHelper class allows us to mock BuildConfig fields related to the pre-shipped circumvention settings +public class ObfsVpnHelper { + + public interface ObfsVpnHelperInterface { + boolean useObfsVpn(); + boolean hasObfuscationPinningDefaults(); + String obfsvpnIP(); + String obfsvpnPort(); + String obfsvpnCert(); + boolean useKcp(); + } + + public static class DefaultObfsVpnHelper implements ObfsVpnHelperInterface { + @Override + public boolean useObfsVpn() { + return BuildConfig.use_obfsvpn; + } + + @Override + public boolean hasObfuscationPinningDefaults() { + return BuildConfig.obfsvpn_ip != null && + BuildConfig.obfsvpn_port != null && + BuildConfig.obfsvpn_cert != null && + !BuildConfig.obfsvpn_ip.isEmpty() && + !BuildConfig.obfsvpn_port.isEmpty() && + !BuildConfig.obfsvpn_cert.isEmpty(); + } + + @Override + public String obfsvpnIP() { + return BuildConfig.obfsvpn_ip; + } + + @Override + public String obfsvpnPort() { + return BuildConfig.obfsvpn_port; + } + + @Override + public String obfsvpnCert() { + return BuildConfig.obfsvpn_cert; + } + + @Override + public boolean useKcp() { + return BuildConfig.obfsvpn_use_kcp; + } + } + + private static ObfsVpnHelperInterface instance = new DefaultObfsVpnHelper(); + + @VisibleForTesting + public ObfsVpnHelper(ObfsVpnHelperInterface helperInterface) { + if (!NativeUtils.isUnitTest()) { + throw new IllegalStateException("ObfsVpnHelper injected with ObfsVpnHelperInterface outside of an unit test"); + } + instance = helperInterface; + } + + public static boolean useObfsVpn() { + return instance.useObfsVpn(); + } + + public static boolean hasObfuscationPinningDefaults() { + return instance.hasObfuscationPinningDefaults(); + } + public static String obfsvpnIP() { + return instance.obfsvpnIP(); + } + public static String obfsvpnPort() { + return instance.obfsvpnPort(); + } + public static String obfsvpnCert() { + return instance.obfsvpnCert(); + } + public static boolean useKcp() { + return instance.useKcp(); + } +} 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 b35a04cd..a04c3686 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 @@ -40,6 +40,7 @@ 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.models.Constants.USE_OBFUSCATION_PINNING; import static se.leap.bitmaskclient.base.models.Constants.USE_SNOWFLAKE; +import static se.leap.bitmaskclient.base.models.Constants.USE_SYSTEM_PROXY; import android.content.Context; import android.content.SharedPreferences; @@ -460,12 +461,16 @@ public class PreferenceHelper { return getBoolean(ALLOW_EXPERIMENTAL_TRANSPORTS, false); } + public static boolean useSystemProxy() { + return getBoolean(USE_SYSTEM_PROXY, true); + } + public static void setUseObfuscationPinning(Boolean pinning) { putBoolean(USE_OBFUSCATION_PINNING, pinning); } public static boolean useObfuscationPinning() { - return ConfigHelper.ObfsVpnHelper.useObfsVpn() && + return ObfsVpnHelper.useObfsVpn() && getUseBridges() && getBoolean(USE_OBFUSCATION_PINNING, false) && !TextUtils.isEmpty(getObfuscationPinningIP()) && diff --git a/app/src/main/java/se/leap/bitmaskclient/base/utils/RSAHelper.java b/app/src/main/java/se/leap/bitmaskclient/base/utils/RSAHelper.java new file mode 100644 index 00000000..2872139a --- /dev/null +++ b/app/src/main/java/se/leap/bitmaskclient/base/utils/RSAHelper.java @@ -0,0 +1,72 @@ +package se.leap.bitmaskclient.base.utils; + +import android.os.Build; + +import androidx.annotation.VisibleForTesting; + +import org.spongycastle.util.encoders.Base64; + +import java.security.KeyFactory; +import java.security.NoSuchAlgorithmException; +import java.security.NoSuchProviderException; +import java.security.interfaces.RSAPrivateKey; +import java.security.spec.InvalidKeySpecException; +import java.security.spec.PKCS8EncodedKeySpec; + +import de.blinkt.openvpn.core.NativeUtils; + +public class RSAHelper { + + public interface RSAHelperInterface { + RSAPrivateKey parseRsaKeyFromString(String rsaKeyString); + } + + public static class DefaultRSAHelper implements RSAHelperInterface { + + @Override + public RSAPrivateKey parseRsaKeyFromString(String rsaKeyString) { + RSAPrivateKey key; + try { + KeyFactory kf; + if (Build.VERSION.SDK_INT < Build.VERSION_CODES.P) { + kf = KeyFactory.getInstance("RSA", "BC"); + } else { + kf = KeyFactory.getInstance("RSA"); + } + rsaKeyString = rsaKeyString.replaceFirst("-----BEGIN RSA PRIVATE KEY-----", "").replaceFirst("-----END RSA PRIVATE KEY-----", ""); + PKCS8EncodedKeySpec keySpec = new PKCS8EncodedKeySpec(Base64.decode(rsaKeyString)); + key = (RSAPrivateKey) kf.generatePrivate(keySpec); + } catch (InvalidKeySpecException e) { + // TODO Auto-generated catch block + e.printStackTrace(); + return null; + } catch (NoSuchAlgorithmException e) { + // TODO Auto-generated catch block + e.printStackTrace(); + return null; + } catch (NullPointerException e) { + e.printStackTrace(); + return null; + } catch (NoSuchProviderException e) { + e.printStackTrace(); + return null; + } + + return key; + } + } + + private static RSAHelperInterface instance = new DefaultRSAHelper(); + + @VisibleForTesting + public RSAHelper(RSAHelperInterface helperInterface) { + if (!NativeUtils.isUnitTest()) { + throw new IllegalStateException("RSAHelper injected with RSAHelperInterface outside of an unit test"); + } + instance = helperInterface; + } + + public static RSAPrivateKey parseRsaKeyFromString(String rsaKeyString) { + return instance.parseRsaKeyFromString(rsaKeyString); + } +} -- cgit v1.2.3 From b85dc1b2ea68ab7ca7e11ab545bb88f4dbb59bdb Mon Sep 17 00:00:00 2001 From: cyBerta Date: Thu, 25 Jan 2024 03:01:21 +0100 Subject: fix VpnCertificateValidatorTest, extract CertificateHelper (returns a fingerprint for a x509 cert) from ConfigHelper --- .../base/utils/CertificateHelper.java | 64 ++++++++++++++++++++++ 1 file changed, 64 insertions(+) create mode 100644 app/src/main/java/se/leap/bitmaskclient/base/utils/CertificateHelper.java (limited to 'app/src/main/java/se/leap/bitmaskclient/base') diff --git a/app/src/main/java/se/leap/bitmaskclient/base/utils/CertificateHelper.java b/app/src/main/java/se/leap/bitmaskclient/base/utils/CertificateHelper.java new file mode 100644 index 00000000..11202734 --- /dev/null +++ b/app/src/main/java/se/leap/bitmaskclient/base/utils/CertificateHelper.java @@ -0,0 +1,64 @@ +package se.leap.bitmaskclient.base.utils; + +import androidx.annotation.NonNull; +import androidx.annotation.VisibleForTesting; + +import java.security.MessageDigest; +import java.security.NoSuchAlgorithmException; +import java.security.cert.CertificateEncodingException; +import java.security.cert.X509Certificate; + +import de.blinkt.openvpn.core.NativeUtils; + +public class CertificateHelper { + + public interface CertificateHelperInterface { + String getFingerprintFromCertificate(X509Certificate certificate, String encoding) throws NoSuchAlgorithmException, CertificateEncodingException; + + } + + public static class DefaultCertificateHelper implements CertificateHelperInterface { + + public String byteArrayToHex(byte[] input) { + int readBytes = input.length; + StringBuffer hexData = new StringBuffer(); + int onebyte; + for (int i = 0; i < readBytes; i++) { + onebyte = ((0x000000ff & input[i]) | 0xffffff00); + hexData.append(Integer.toHexString(onebyte).substring(6)); + } + return hexData.toString(); + } + + /** + * Calculates the hexadecimal representation of a sha256/sha1 fingerprint of a certificate + * + * @param certificate + * @param encoding + * @return + * @throws NoSuchAlgorithmException + * @throws CertificateEncodingException + */ + @Override + public String getFingerprintFromCertificate(X509Certificate certificate, String encoding) throws NoSuchAlgorithmException, CertificateEncodingException { + byte[] byteArray = MessageDigest.getInstance(encoding).digest(certificate.getEncoded()); + return byteArrayToHex(byteArray); + } + } + + private static CertificateHelperInterface instance = new DefaultCertificateHelper(); + + @VisibleForTesting + public CertificateHelper(CertificateHelperInterface helperInterface) { + if (!NativeUtils.isUnitTest()) { + throw new IllegalStateException("CertificateHelper injected with CertificateHelperInterface outside of an unit test"); + } + instance = helperInterface; + } + + @NonNull + public static String getFingerprintFromCertificate(X509Certificate certificate, String encoding) throws NoSuchAlgorithmException, CertificateEncodingException { + return instance.getFingerprintFromCertificate(certificate, encoding); + } + +} -- cgit v1.2.3 From b6c2c7c8ffbcf87110c33e179f1506285dffd949 Mon Sep 17 00:00:00 2001 From: cyBerta Date: Thu, 25 Jan 2024 23:17:16 +0100 Subject: rename ObfsvpnHelper to BuildConfigHelper, adding other BuildConfig properties there --- .../base/fragments/NavigationDrawerFragment.java | 2 +- .../base/fragments/ObfuscationProxyDialog.java | 12 +-- .../base/fragments/SettingsFragment.java | 2 +- .../leap/bitmaskclient/base/models/Provider.java | 2 +- .../base/utils/BuildConfigHelper.java | 98 ++++++++++++++++++++++ .../bitmaskclient/base/utils/ConfigHelper.java | 6 -- .../bitmaskclient/base/utils/ObfsVpnHelper.java | 86 ------------------- .../bitmaskclient/base/utils/PreferenceHelper.java | 2 +- 8 files changed, 108 insertions(+), 102 deletions(-) create mode 100644 app/src/main/java/se/leap/bitmaskclient/base/utils/BuildConfigHelper.java delete mode 100644 app/src/main/java/se/leap/bitmaskclient/base/utils/ObfsVpnHelper.java (limited to 'app/src/main/java/se/leap/bitmaskclient/base') diff --git a/app/src/main/java/se/leap/bitmaskclient/base/fragments/NavigationDrawerFragment.java b/app/src/main/java/se/leap/bitmaskclient/base/fragments/NavigationDrawerFragment.java index e74d70a2..16aea065 100644 --- a/app/src/main/java/se/leap/bitmaskclient/base/fragments/NavigationDrawerFragment.java +++ b/app/src/main/java/se/leap/bitmaskclient/base/fragments/NavigationDrawerFragment.java @@ -24,7 +24,7 @@ import static se.leap.bitmaskclient.base.models.Constants.ENABLE_DONATION; import static se.leap.bitmaskclient.base.models.Constants.PREFERRED_CITY; import static se.leap.bitmaskclient.base.models.Constants.PROVIDER_KEY; import static se.leap.bitmaskclient.base.models.Constants.REQUEST_CODE_SWITCH_PROVIDER; -import static se.leap.bitmaskclient.base.utils.ConfigHelper.isDefaultBitmask; +import static se.leap.bitmaskclient.base.utils.BuildConfigHelper.isDefaultBitmask; import static se.leap.bitmaskclient.base.utils.PreferenceHelper.getPreferredCity; import static se.leap.bitmaskclient.base.utils.PreferenceHelper.getSaveBattery; import static se.leap.bitmaskclient.base.utils.PreferenceHelper.saveBattery; diff --git a/app/src/main/java/se/leap/bitmaskclient/base/fragments/ObfuscationProxyDialog.java b/app/src/main/java/se/leap/bitmaskclient/base/fragments/ObfuscationProxyDialog.java index 635af701..7d12ca70 100644 --- a/app/src/main/java/se/leap/bitmaskclient/base/fragments/ObfuscationProxyDialog.java +++ b/app/src/main/java/se/leap/bitmaskclient/base/fragments/ObfuscationProxyDialog.java @@ -15,7 +15,7 @@ import androidx.appcompat.app.AppCompatDialogFragment; import androidx.appcompat.widget.AppCompatButton; import androidx.appcompat.widget.AppCompatEditText; -import se.leap.bitmaskclient.base.utils.ObfsVpnHelper; +import se.leap.bitmaskclient.base.utils.BuildConfigHelper; import se.leap.bitmaskclient.base.utils.PreferenceHelper; import se.leap.bitmaskclient.base.views.IconSwitchEntry; import se.leap.bitmaskclient.databinding.DObfuscationProxyBinding; @@ -68,12 +68,12 @@ public class ObfuscationProxyDialog extends AppCompatDialogFragment { dismiss(); }); - useDefaultsButton.setVisibility(ObfsVpnHelper.hasObfuscationPinningDefaults() ? VISIBLE : GONE); + useDefaultsButton.setVisibility(BuildConfigHelper.hasObfuscationPinningDefaults() ? VISIBLE : GONE); useDefaultsButton.setOnClickListener(v -> { - ipField.setText(ObfsVpnHelper.obfsvpnIP()); - portField.setText(ObfsVpnHelper.obfsvpnPort()); - certificateField.setText(ObfsVpnHelper.obfsvpnCert()); - kcpSwitch.setChecked(ObfsVpnHelper.useKcp()); + ipField.setText(BuildConfigHelper.obfsvpnIP()); + portField.setText(BuildConfigHelper.obfsvpnPort()); + certificateField.setText(BuildConfigHelper.obfsvpnCert()); + kcpSwitch.setChecked(BuildConfigHelper.useKcp()); }); cancelButton.setOnClickListener(v -> { 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 77becc80..d7b62de2 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 @@ -8,7 +8,7 @@ import static se.leap.bitmaskclient.base.models.Constants.PREFER_UDP; 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.models.Constants.USE_OBFUSCATION_PINNING; -import static se.leap.bitmaskclient.base.utils.ObfsVpnHelper.useObfsVpn; +import static se.leap.bitmaskclient.base.utils.BuildConfigHelper.useObfsVpn; import static se.leap.bitmaskclient.base.utils.ConfigHelper.isCalyxOSWithTetheringSupport; import static se.leap.bitmaskclient.base.utils.PreferenceHelper.allowExperimentalTransports; import static se.leap.bitmaskclient.base.utils.PreferenceHelper.getExcludedApps; 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 af9122de..cb9bd520 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 @@ -28,7 +28,7 @@ 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.ObfsVpnHelper.useObfsVpn; +import static se.leap.bitmaskclient.base.utils.BuildConfigHelper.useObfsVpn; import static se.leap.bitmaskclient.base.utils.RSAHelper.parseRsaKeyFromString; import static se.leap.bitmaskclient.providersetup.ProviderAPI.ERRORS; diff --git a/app/src/main/java/se/leap/bitmaskclient/base/utils/BuildConfigHelper.java b/app/src/main/java/se/leap/bitmaskclient/base/utils/BuildConfigHelper.java new file mode 100644 index 00000000..e1f65b5e --- /dev/null +++ b/app/src/main/java/se/leap/bitmaskclient/base/utils/BuildConfigHelper.java @@ -0,0 +1,98 @@ +package se.leap.bitmaskclient.base.utils; + +import static se.leap.bitmaskclient.base.models.Constants.DEFAULT_BITMASK; + +import androidx.annotation.VisibleForTesting; + +import de.blinkt.openvpn.core.NativeUtils; +import se.leap.bitmaskclient.BuildConfig; + +// ObfsVpnHelper class allows us to mock BuildConfig fields related to the pre-shipped circumvention settings +public class BuildConfigHelper { + + public interface BuildConfigHelperInterface { + boolean useObfsVpn(); + boolean hasObfuscationPinningDefaults(); + String obfsvpnIP(); + String obfsvpnPort(); + String obfsvpnCert(); + boolean useKcp(); + boolean isDefaultBitmask(); + } + + public static class DefaultBuildConfigHelper implements BuildConfigHelperInterface { + @Override + public boolean useObfsVpn() { + return BuildConfig.use_obfsvpn; + } + + @Override + public boolean hasObfuscationPinningDefaults() { + return BuildConfig.obfsvpn_ip != null && + BuildConfig.obfsvpn_port != null && + BuildConfig.obfsvpn_cert != null && + !BuildConfig.obfsvpn_ip.isEmpty() && + !BuildConfig.obfsvpn_port.isEmpty() && + !BuildConfig.obfsvpn_cert.isEmpty(); + } + + @Override + public String obfsvpnIP() { + return BuildConfig.obfsvpn_ip; + } + + @Override + public String obfsvpnPort() { + return BuildConfig.obfsvpn_port; + } + + @Override + public String obfsvpnCert() { + return BuildConfig.obfsvpn_cert; + } + + @Override + public boolean useKcp() { + return BuildConfig.obfsvpn_use_kcp; + } + + @Override + public boolean isDefaultBitmask() { + return BuildConfig.FLAVOR_branding.equals(DEFAULT_BITMASK); + } + } + + private static BuildConfigHelperInterface instance = new DefaultBuildConfigHelper(); + + @VisibleForTesting + public BuildConfigHelper(BuildConfigHelperInterface helperInterface) { + if (!NativeUtils.isUnitTest()) { + throw new IllegalStateException("ObfsVpnHelper injected with ObfsVpnHelperInterface outside of an unit test"); + } + instance = helperInterface; + } + + public static boolean useObfsVpn() { + return instance.useObfsVpn(); + } + + public static boolean hasObfuscationPinningDefaults() { + return instance.hasObfuscationPinningDefaults(); + } + public static String obfsvpnIP() { + return instance.obfsvpnIP(); + } + public static String obfsvpnPort() { + return instance.obfsvpnPort(); + } + public static String obfsvpnCert() { + return instance.obfsvpnCert(); + } + public static boolean useKcp() { + return instance.useKcp(); + } + + public static boolean isDefaultBitmask() { + return instance.isDefaultBitmask(); + } +} diff --git a/app/src/main/java/se/leap/bitmaskclient/base/utils/ConfigHelper.java b/app/src/main/java/se/leap/bitmaskclient/base/utils/ConfigHelper.java index a06d85be..a7916399 100644 --- a/app/src/main/java/se/leap/bitmaskclient/base/utils/ConfigHelper.java +++ b/app/src/main/java/se/leap/bitmaskclient/base/utils/ConfigHelper.java @@ -16,8 +16,6 @@ */ package se.leap.bitmaskclient.base.utils; -import static se.leap.bitmaskclient.base.models.Constants.DEFAULT_BITMASK; - import android.app.PendingIntent; import android.content.Context; import android.content.res.Resources; @@ -159,10 +157,6 @@ public class ConfigHelper { } } - public static boolean isDefaultBitmask() { - return BuildConfig.FLAVOR_branding.equals(DEFAULT_BITMASK); - } - public static boolean preferAnonymousUsage() { return BuildConfig.priotize_anonymous_usage; } diff --git a/app/src/main/java/se/leap/bitmaskclient/base/utils/ObfsVpnHelper.java b/app/src/main/java/se/leap/bitmaskclient/base/utils/ObfsVpnHelper.java deleted file mode 100644 index 054c85b3..00000000 --- a/app/src/main/java/se/leap/bitmaskclient/base/utils/ObfsVpnHelper.java +++ /dev/null @@ -1,86 +0,0 @@ -package se.leap.bitmaskclient.base.utils; - -import androidx.annotation.VisibleForTesting; - -import de.blinkt.openvpn.core.NativeUtils; -import se.leap.bitmaskclient.BuildConfig; - -// ObfsVpnHelper class allows us to mock BuildConfig fields related to the pre-shipped circumvention settings -public class ObfsVpnHelper { - - public interface ObfsVpnHelperInterface { - boolean useObfsVpn(); - boolean hasObfuscationPinningDefaults(); - String obfsvpnIP(); - String obfsvpnPort(); - String obfsvpnCert(); - boolean useKcp(); - } - - public static class DefaultObfsVpnHelper implements ObfsVpnHelperInterface { - @Override - public boolean useObfsVpn() { - return BuildConfig.use_obfsvpn; - } - - @Override - public boolean hasObfuscationPinningDefaults() { - return BuildConfig.obfsvpn_ip != null && - BuildConfig.obfsvpn_port != null && - BuildConfig.obfsvpn_cert != null && - !BuildConfig.obfsvpn_ip.isEmpty() && - !BuildConfig.obfsvpn_port.isEmpty() && - !BuildConfig.obfsvpn_cert.isEmpty(); - } - - @Override - public String obfsvpnIP() { - return BuildConfig.obfsvpn_ip; - } - - @Override - public String obfsvpnPort() { - return BuildConfig.obfsvpn_port; - } - - @Override - public String obfsvpnCert() { - return BuildConfig.obfsvpn_cert; - } - - @Override - public boolean useKcp() { - return BuildConfig.obfsvpn_use_kcp; - } - } - - private static ObfsVpnHelperInterface instance = new DefaultObfsVpnHelper(); - - @VisibleForTesting - public ObfsVpnHelper(ObfsVpnHelperInterface helperInterface) { - if (!NativeUtils.isUnitTest()) { - throw new IllegalStateException("ObfsVpnHelper injected with ObfsVpnHelperInterface outside of an unit test"); - } - instance = helperInterface; - } - - public static boolean useObfsVpn() { - return instance.useObfsVpn(); - } - - public static boolean hasObfuscationPinningDefaults() { - return instance.hasObfuscationPinningDefaults(); - } - public static String obfsvpnIP() { - return instance.obfsvpnIP(); - } - public static String obfsvpnPort() { - return instance.obfsvpnPort(); - } - public static String obfsvpnCert() { - return instance.obfsvpnCert(); - } - public static boolean useKcp() { - return instance.useKcp(); - } -} 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 a04c3686..2420a797 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 @@ -470,7 +470,7 @@ public class PreferenceHelper { } public static boolean useObfuscationPinning() { - return ObfsVpnHelper.useObfsVpn() && + return BuildConfigHelper.useObfsVpn() && getUseBridges() && getBoolean(USE_OBFUSCATION_PINNING, false) && !TextUtils.isEmpty(getObfuscationPinningIP()) && -- cgit v1.2.3 From 2bcbfb1d537fe8f616adc252fac7c3e8673ebaa7 Mon Sep 17 00:00:00 2001 From: cyBerta Date: Thu, 25 Jan 2024 23:20:35 +0100 Subject: improve TimezoneHelper, don't allow to set the TimezoneInterface outside of UnitTests --- .../main/java/se/leap/bitmaskclient/base/utils/TimezoneHelper.java | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) (limited to 'app/src/main/java/se/leap/bitmaskclient/base') diff --git a/app/src/main/java/se/leap/bitmaskclient/base/utils/TimezoneHelper.java b/app/src/main/java/se/leap/bitmaskclient/base/utils/TimezoneHelper.java index c543368d..63b12fd3 100644 --- a/app/src/main/java/se/leap/bitmaskclient/base/utils/TimezoneHelper.java +++ b/app/src/main/java/se/leap/bitmaskclient/base/utils/TimezoneHelper.java @@ -4,6 +4,8 @@ import androidx.annotation.VisibleForTesting; import java.util.Calendar; +import de.blinkt.openvpn.core.NativeUtils; + public class TimezoneHelper { public interface TimezoneInterface { @@ -14,6 +16,9 @@ public class TimezoneHelper { @VisibleForTesting public TimezoneHelper(TimezoneInterface timezoneInterface) { + if (!NativeUtils.isUnitTest()) { + throw new IllegalStateException("TimezoneHelper injected with timezoneInterface outside of an unit test"); + } instance = timezoneInterface; } @@ -33,7 +38,7 @@ public class TimezoneHelper { return get().getCurrentTimezone(); } - public static class DefaultTimezoneHelper implements TimezoneInterface { + private static class DefaultTimezoneHelper implements TimezoneInterface { @Override public int getCurrentTimezone() { return Calendar.getInstance().get(Calendar.ZONE_OFFSET) / 3600000; -- cgit v1.2.3 From a8cbf6ea3c794e6cad818979a9c2d4ac95fb7a0f Mon Sep 17 00:00:00 2001 From: cyBerta Date: Thu, 25 Jan 2024 23:24:23 +0100 Subject: remove methods from ConfigHelper after moving functionality to CertificateHelper --- .../bitmaskclient/base/utils/ConfigHelper.java | 29 ---------------------- 1 file changed, 29 deletions(-) (limited to 'app/src/main/java/se/leap/bitmaskclient/base') diff --git a/app/src/main/java/se/leap/bitmaskclient/base/utils/ConfigHelper.java b/app/src/main/java/se/leap/bitmaskclient/base/utils/ConfigHelper.java index a7916399..bb9d1196 100644 --- a/app/src/main/java/se/leap/bitmaskclient/base/utils/ConfigHelper.java +++ b/app/src/main/java/se/leap/bitmaskclient/base/utils/ConfigHelper.java @@ -34,9 +34,6 @@ import java.io.ByteArrayInputStream; import java.io.IOException; import java.io.InputStream; import java.math.BigInteger; -import java.security.MessageDigest; -import java.security.NoSuchAlgorithmException; -import java.security.cert.CertificateEncodingException; import java.security.cert.CertificateException; import java.security.cert.CertificateFactory; import java.security.cert.X509Certificate; @@ -123,32 +120,6 @@ public class ConfigHelper { return null; } - private static String byteArrayToHex(byte[] input) { - int readBytes = input.length; - StringBuffer hexData = new StringBuffer(); - int onebyte; - for (int i = 0; i < readBytes; i++) { - onebyte = ((0x000000ff & input[i]) | 0xffffff00); - hexData.append(Integer.toHexString(onebyte).substring(6)); - } - return hexData.toString(); - } - - /** - * Calculates the hexadecimal representation of a sha256/sha1 fingerprint of a certificate - * - * @param certificate - * @param encoding - * @return - * @throws NoSuchAlgorithmException - * @throws CertificateEncodingException - */ - @NonNull - public static String getFingerprintFromCertificate(X509Certificate certificate, String encoding) throws NoSuchAlgorithmException, CertificateEncodingException /*, UnsupportedEncodingException*/ { - byte[] byteArray = MessageDigest.getInstance(encoding).digest(certificate.getEncoded()); - return byteArrayToHex(byteArray); - } - public static void ensureNotOnMainThread(@NonNull Context context) throws IllegalStateException{ Looper looper = Looper.myLooper(); if (looper != null && looper == context.getMainLooper()) { -- cgit v1.2.3 From 6f7b3bbf255b0be4d5ff1bd994aad0d61b8cca8d Mon Sep 17 00:00:00 2001 From: cyBerta Date: Thu, 25 Jan 2024 23:55:52 +0100 Subject: fix ProviderApiManagerTest, sneaking in some missing changes from previous commits as well --- .../bitmaskclient/base/utils/ConfigHelper.java | 8 +++++ .../bitmaskclient/base/utils/HandlerProvider.java | 38 ++++++++++++++++++++++ 2 files changed, 46 insertions(+) create mode 100644 app/src/main/java/se/leap/bitmaskclient/base/utils/HandlerProvider.java (limited to 'app/src/main/java/se/leap/bitmaskclient/base') diff --git a/app/src/main/java/se/leap/bitmaskclient/base/utils/ConfigHelper.java b/app/src/main/java/se/leap/bitmaskclient/base/utils/ConfigHelper.java index bb9d1196..71fe8eba 100644 --- a/app/src/main/java/se/leap/bitmaskclient/base/utils/ConfigHelper.java +++ b/app/src/main/java/se/leap/bitmaskclient/base/utils/ConfigHelper.java @@ -41,6 +41,7 @@ import java.util.ArrayList; import java.util.regex.Matcher; import java.util.regex.Pattern; +import de.blinkt.openvpn.core.NativeUtils; import okhttp3.internal.publicsuffix.PublicSuffixDatabase; import se.leap.bitmaskclient.BuildConfig; import se.leap.bitmaskclient.R; @@ -207,4 +208,11 @@ public class ConfigHelper { } return flags; } + + public static int getTorTimeout() { + if (NativeUtils.isUnitTest()) { + return 1; + } + return 180; + } } diff --git a/app/src/main/java/se/leap/bitmaskclient/base/utils/HandlerProvider.java b/app/src/main/java/se/leap/bitmaskclient/base/utils/HandlerProvider.java new file mode 100644 index 00000000..d9198ab7 --- /dev/null +++ b/app/src/main/java/se/leap/bitmaskclient/base/utils/HandlerProvider.java @@ -0,0 +1,38 @@ +package se.leap.bitmaskclient.base.utils; + +import android.os.Handler; +import android.os.Looper; + +public class HandlerProvider { + + + public interface HandlerInterface { + void postDelayed(Runnable r, long delay); + } + + + private static HandlerInterface instance; + + public HandlerProvider(HandlerInterface handlerInterface) { + instance = handlerInterface; + } + public static HandlerInterface get() { + if (instance == null) { + instance = new DefaultHandler(); + } + return instance; + } + + public static class DefaultHandler implements HandlerInterface { + Handler handler; + + public DefaultHandler() { + this.handler = new Handler(Looper.getMainLooper()); + } + @Override + public void postDelayed(Runnable r, long delay) { + this.handler.postDelayed(r, delay); + } + } +} + -- cgit v1.2.3 From 6c3efd90f70a93c6a668c7cb954ab4a353c73d66 Mon Sep 17 00:00:00 2001 From: cyBerta Date: Fri, 26 Jan 2024 00:01:46 +0100 Subject: move reqex pattern for IPv4 and PEM into functions for now --- .../main/java/se/leap/bitmaskclient/base/utils/ConfigHelper.java | 8 +++----- 1 file changed, 3 insertions(+), 5 deletions(-) (limited to 'app/src/main/java/se/leap/bitmaskclient/base') diff --git a/app/src/main/java/se/leap/bitmaskclient/base/utils/ConfigHelper.java b/app/src/main/java/se/leap/bitmaskclient/base/utils/ConfigHelper.java index 71fe8eba..cd5d1fca 100644 --- a/app/src/main/java/se/leap/bitmaskclient/base/utils/ConfigHelper.java +++ b/app/src/main/java/se/leap/bitmaskclient/base/utils/ConfigHelper.java @@ -59,8 +59,6 @@ public class ConfigHelper { final public static String NG_1024 = "eeaf0ab9adb38dd69c33f80afa8fc5e86072618775ff3c0b9ea2314c9c256576d674df7496ea81d3383b4813d692c6e0e0d5d8e250b98be48e495c1d6089dad15dc7d7b46154d6b6ce8ef4ad69b15d4982559b297bcf1885c529f566660e57ec68edbc3c05726cc02fd4cbf4976eaa9afd5138fe8376435b9fc61d2fc0eb06e3"; final public static BigInteger G = new BigInteger("2"); - final public static Pattern IPv4_PATTERN = Pattern.compile("^(?:(?:25[0-5]|2[0-4][0-9]|1[0-9][0-9]|[1-9][0-9]|[0-9])\\.){3}(?:25[0-5]|2[0-4][0-9]|1[0-9][0-9]|[1-9][0-9]|[0-9])$"); - final public static Pattern PEM_CERTIFICATE_PATTERN = Pattern.compile("((-----BEGIN CERTIFICATE-----)([A-Za-z0-9+/=\\n]+)(-----END CERTIFICATE-----)+)"); public static boolean checkErroneousDownload(String downloadedString) { try { @@ -99,8 +97,8 @@ public class ConfigHelper { CertificateFactory cf; try { cf = CertificateFactory.getInstance("X.509"); - - Matcher matcher = PEM_CERTIFICATE_PATTERN.matcher(certificateString); + Pattern pattern = Pattern.compile("((-----BEGIN CERTIFICATE-----)([A-Za-z0-9+/=\\n]+)(-----END CERTIFICATE-----)+)"); + Matcher matcher = pattern.matcher(certificateString); while (matcher.find()) { String certificate = matcher.group(3); if (certificate == null) continue; @@ -188,7 +186,7 @@ public class ConfigHelper { if (ipv4 == null) { return false; } - Matcher matcher = IPv4_PATTERN.matcher(ipv4); + Matcher matcher = Pattern.compile("^(?:(?:25[0-5]|2[0-4][0-9]|1[0-9][0-9]|[1-9][0-9]|[0-9])\\.){3}(?:25[0-5]|2[0-4][0-9]|1[0-9][0-9]|[1-9][0-9]|[0-9])$").matcher(ipv4); return matcher.matches(); } -- cgit v1.2.3