From 080c18229a5eb17beb0b65ee0546566c93a56c11 Mon Sep 17 00:00:00 2001 From: cyBerta Date: Sat, 11 Nov 2023 01:17:10 +0100 Subject: remove unused layout file of deprecated provider setup UI --- .../main/res/layout-xlarge/v_provider_header.xml | 29 ---------------------- 1 file changed, 29 deletions(-) delete mode 100644 app/src/main/res/layout-xlarge/v_provider_header.xml (limited to 'app/src/main') diff --git a/app/src/main/res/layout-xlarge/v_provider_header.xml b/app/src/main/res/layout-xlarge/v_provider_header.xml deleted file mode 100644 index 28bcaa6c..00000000 --- a/app/src/main/res/layout-xlarge/v_provider_header.xml +++ /dev/null @@ -1,29 +0,0 @@ - - - - - - - - \ No newline at end of file -- cgit v1.2.3 From f5cf60421e58637e87324047c4a22edea2e1968f Mon Sep 17 00:00:00 2001 From: cyBerta Date: Sat, 11 Nov 2023 01:18:41 +0100 Subject: add null-check before delayed calling of the activity callback in ConfigureOrivuderFragment, fixes an NPE --- .../providersetup/fragments/ConfigureProviderFragment.java | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) (limited to 'app/src/main') diff --git a/app/src/main/java/se/leap/bitmaskclient/providersetup/fragments/ConfigureProviderFragment.java b/app/src/main/java/se/leap/bitmaskclient/providersetup/fragments/ConfigureProviderFragment.java index ec646cac..e041b19b 100644 --- a/app/src/main/java/se/leap/bitmaskclient/providersetup/fragments/ConfigureProviderFragment.java +++ b/app/src/main/java/se/leap/bitmaskclient/providersetup/fragments/ConfigureProviderFragment.java @@ -222,7 +222,9 @@ public class ConfigureProviderFragment extends BaseSetupFragment implements Obse setupActivityCallback.onProviderSelected(provider); handler.postDelayed(() -> { if (!ProviderSetupObservable.isCanceled()) { - setupActivityCallback.onConfigurationSuccess(); + if (setupActivityCallback != null) { + setupActivityCallback.onConfigurationSuccess(); + } } }, 750); break; -- cgit v1.2.3 From 7cbb783b7d7df1c52ffcc6f4ee5c3b526b8f0375 Mon Sep 17 00:00:00 2001 From: cyBerta Date: Thu, 16 Nov 2023 09:29:40 +0100 Subject: replace direct call on private static currentStatus field with getInstance() in global observable EipStatus in order to avoid possible NPEs --- .../java/se/leap/bitmaskclient/eip/EipStatus.java | 31 +++++++++++----------- 1 file changed, 15 insertions(+), 16 deletions(-) (limited to 'app/src/main') diff --git a/app/src/main/java/se/leap/bitmaskclient/eip/EipStatus.java b/app/src/main/java/se/leap/bitmaskclient/eip/EipStatus.java index 9244f531..8182cab9 100644 --- a/app/src/main/java/se/leap/bitmaskclient/eip/EipStatus.java +++ b/app/src/main/java/se/leap/bitmaskclient/eip/EipStatus.java @@ -73,14 +73,13 @@ public class EipStatus extends Observable implements VpnStatus.StateListener { @Override public void updateState(final String state, final String logmessage, final int localizedResId, final ConnectionStatus level) { - ConnectionStatus tmp = currentStatus.getLevel(); - currentStatus = getInstance(); - currentStatus.setState(state); - currentStatus.setLogMessage(logmessage); - currentStatus.setLocalizedResId(localizedResId); - currentStatus.setLevel(level); - currentStatus.setEipLevel(level); - if (tmp != currentStatus.getLevel() || "RECONNECTING".equals(state) || "UI_CONNECTING".equals(state)) { + ConnectionStatus tmp = getInstance().getLevel(); + getInstance().setState(state); + getInstance().setLogMessage(logmessage); + getInstance().setLocalizedResId(localizedResId); + getInstance().setLevel(level); + getInstance().setEipLevel(level); + if (tmp != getInstance().getLevel() || "RECONNECTING".equals(state) || "UI_CONNECTING".equals(state)) { refresh(); } } @@ -90,13 +89,13 @@ public class EipStatus extends Observable implements VpnStatus.StateListener { } public boolean isReconnecting() { - Log.d(TAG, "eip currentVPNStatus : " + currentStatus.getState() ); - return "RECONNECTING".equals(currentStatus.getState()); + Log.d(TAG, "eip currentVPNStatus : " + getInstance().getState() ); + return "RECONNECTING".equals(getInstance().getState()); } public boolean isVPNRunningWithoutNetwork() { - return currentStatus.getLevel() == LEVEL_NONETWORK && - !"NO_PROCESS".equals(currentStatus.getState()); + return getInstance().getLevel() == LEVEL_NONETWORK && + !"NO_PROCESS".equals(getInstance().getState()); } private void setEipLevel(ConnectionStatus level) { @@ -147,7 +146,7 @@ public class EipStatus extends Observable implements VpnStatus.StateListener { * @param futureLevel */ private void setEipLevelWithDelay(ConnectionStatus futureLevel) { - new DelayTask(currentStatus.getLevel(), futureLevel).execute(); + new DelayTask(getInstance().getLevel(), futureLevel).execute(); } private static class DelayTask extends AsyncTask { @@ -169,7 +168,7 @@ public class EipStatus extends Observable implements VpnStatus.StateListener { } protected void onPostExecute(Void result) { - if (currentLevel == currentStatus.getLevel()) { + if (currentLevel == getInstance().getLevel()) { switch (futureLevel) { case LEVEL_NONETWORK: currentEipLevel = EipLevel.DISCONNECTED; @@ -301,8 +300,8 @@ public class EipStatus extends Observable implements VpnStatus.StateListener { } public static void refresh() { - currentStatus.setChanged(); - currentStatus.notifyObservers(); + getInstance().setChanged(); + getInstance().notifyObservers(); } } -- cgit v1.2.3 From 767585d54d8f347744ebcf5f22da3324d980749a Mon Sep 17 00:00:00 2001 From: cyBerta Date: Fri, 17 Nov 2023 00:13:38 +0100 Subject: use application context to create VPN permission request intent --- .../se/leap/bitmaskclient/providersetup/activities/SetupActivity.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'app/src/main') diff --git a/app/src/main/java/se/leap/bitmaskclient/providersetup/activities/SetupActivity.java b/app/src/main/java/se/leap/bitmaskclient/providersetup/activities/SetupActivity.java index b258a100..dd735f84 100644 --- a/app/src/main/java/se/leap/bitmaskclient/providersetup/activities/SetupActivity.java +++ b/app/src/main/java/se/leap/bitmaskclient/providersetup/activities/SetupActivity.java @@ -100,7 +100,7 @@ public class SetupActivity extends AppCompatActivity implements SetupActivityCal // indicator views for VPN permission - Intent requestVpnPermission = VpnService.prepare(this); + Intent requestVpnPermission = VpnService.prepare(this.getApplicationContext()); if (requestVpnPermission != null) { addIndicatorView(indicatorViews); addIndicatorView(indicatorViews); -- cgit v1.2.3 From a142bf89106ce7c0ab1938df29e75423c047642b Mon Sep 17 00:00:00 2001 From: cyBerta Date: Tue, 21 Nov 2023 14:54:10 +0100 Subject: remove deprecated layout files --- .../main/res/layout-xlarge/v_loading_screen.xml | 214 --------------------- app/src/main/res/layout/v_loading_screen.xml | 213 -------------------- 2 files changed, 427 deletions(-) delete mode 100644 app/src/main/res/layout-xlarge/v_loading_screen.xml delete mode 100644 app/src/main/res/layout/v_loading_screen.xml (limited to 'app/src/main') diff --git a/app/src/main/res/layout-xlarge/v_loading_screen.xml b/app/src/main/res/layout-xlarge/v_loading_screen.xml deleted file mode 100644 index 22b72f29..00000000 --- a/app/src/main/res/layout-xlarge/v_loading_screen.xml +++ /dev/null @@ -1,214 +0,0 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - \ No newline at end of file diff --git a/app/src/main/res/layout/v_loading_screen.xml b/app/src/main/res/layout/v_loading_screen.xml deleted file mode 100644 index dd83aa38..00000000 --- a/app/src/main/res/layout/v_loading_screen.xml +++ /dev/null @@ -1,213 +0,0 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - \ No newline at end of file -- cgit v1.2.3 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 ++++++++++--- .../main/java/se/leap/bitmaskclient/eip/EIP.java | 10 +++--- .../java/se/leap/bitmaskclient/eip/EipStatus.java | 20 ++++++++--- .../se/leap/bitmaskclient/eip/VoidVpnService.java | 11 +++--- .../bitmaskclient/firewall/FirewallManager.java | 14 ++++---- .../pluggableTransports/ObfsVpnClient.java | 10 +++--- .../pluggableTransports/ShapeshifterClient.java | 13 +++---- .../tethering/TetheringObservable.java | 26 +++++++++----- .../bitmaskclient/tor/ClientTransportPlugin.java | 10 +++--- .../bitmaskclient/tor/TorStatusObservable.java | 40 ++++++++++++++-------- 16 files changed, 170 insertions(+), 102 deletions(-) (limited to 'app/src/main') 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() { diff --git a/app/src/main/java/se/leap/bitmaskclient/eip/EIP.java b/app/src/main/java/se/leap/bitmaskclient/eip/EIP.java index d8905bca..ed61ca13 100644 --- a/app/src/main/java/se/leap/bitmaskclient/eip/EIP.java +++ b/app/src/main/java/se/leap/bitmaskclient/eip/EIP.java @@ -67,6 +67,8 @@ import androidx.localbroadcastmanager.content.LocalBroadcastManager; import org.json.JSONException; import org.json.JSONObject; +import java.beans.PropertyChangeEvent; +import java.beans.PropertyChangeListener; import java.io.Closeable; import java.lang.ref.WeakReference; import java.util.Observable; @@ -97,7 +99,7 @@ import se.leap.bitmaskclient.eip.GatewaysManager.GatewayOptions; * @author Sean Leonard * @author Parménides GV */ -public final class EIP extends JobIntentService implements Observer { +public final class EIP extends JobIntentService implements PropertyChangeListener { public final static String TAG = EIP.class.getSimpleName(), @@ -160,9 +162,9 @@ public final class EIP extends JobIntentService implements Observer { * update eipStatus whenever it changes */ @Override - public void update(Observable observable, Object data) { - if (observable instanceof EipStatus) { - eipStatus = (EipStatus) observable; + public void propertyChange(PropertyChangeEvent evt) { + if (EipStatus.PROPERTY_CHANGE.equals(evt.getPropertyName())) { + eipStatus = (EipStatus) evt.getNewValue(); } } diff --git a/app/src/main/java/se/leap/bitmaskclient/eip/EipStatus.java b/app/src/main/java/se/leap/bitmaskclient/eip/EipStatus.java index 8182cab9..c2ba8af3 100644 --- a/app/src/main/java/se/leap/bitmaskclient/eip/EipStatus.java +++ b/app/src/main/java/se/leap/bitmaskclient/eip/EipStatus.java @@ -20,10 +20,10 @@ import static de.blinkt.openvpn.core.ConnectionStatus.LEVEL_NONETWORK; import android.content.Context; import android.os.AsyncTask; -import androidx.annotation.VisibleForTesting; import android.util.Log; -import java.util.Observable; +import java.beans.PropertyChangeListener; +import java.beans.PropertyChangeSupport; import de.blinkt.openvpn.core.ConnectionStatus; import de.blinkt.openvpn.core.LogItem; @@ -34,7 +34,7 @@ import de.blinkt.openvpn.core.VpnStatus; * EipStatus changes it's state (EipLevel) when ConnectionStatus gets updated by OpenVpnService or * by VoidVpnService. */ -public class EipStatus extends Observable implements VpnStatus.StateListener { +public class EipStatus implements VpnStatus.StateListener { public static String TAG = EipStatus.class.getSimpleName(); private static EipStatus currentStatus; @@ -60,6 +60,9 @@ public class EipStatus extends Observable implements VpnStatus.StateListener { private int localizedResId; private boolean isUpdatingVPNCertificate; + private final PropertyChangeSupport propertyChange; + public static final String PROPERTY_CHANGE = "EipStatus"; + public static EipStatus getInstance() { if (currentStatus == null) { currentStatus = new EipStatus(); @@ -69,6 +72,7 @@ public class EipStatus extends Observable implements VpnStatus.StateListener { } private EipStatus() { + propertyChange = new PropertyChangeSupport(this); } @Override @@ -300,8 +304,14 @@ public class EipStatus extends Observable implements VpnStatus.StateListener { } public static void refresh() { - getInstance().setChanged(); - getInstance().notifyObservers(); + currentStatus.propertyChange.firePropertyChange(PROPERTY_CHANGE, null, currentStatus); + } + + public void addObserver(PropertyChangeListener propertyChangeListener) { + propertyChange.addPropertyChangeListener(propertyChangeListener); } + public void deleteObserver(PropertyChangeListener propertyChangeListener) { + propertyChange.removePropertyChangeListener(propertyChangeListener); + } } diff --git a/app/src/main/java/se/leap/bitmaskclient/eip/VoidVpnService.java b/app/src/main/java/se/leap/bitmaskclient/eip/VoidVpnService.java index b32671ae..f08371c6 100644 --- a/app/src/main/java/se/leap/bitmaskclient/eip/VoidVpnService.java +++ b/app/src/main/java/se/leap/bitmaskclient/eip/VoidVpnService.java @@ -33,6 +33,8 @@ import android.os.ParcelFileDescriptor; import android.system.OsConstants; import android.util.Log; +import java.beans.PropertyChangeEvent; +import java.beans.PropertyChangeListener; import java.io.IOException; import java.util.Observable; import java.util.Observer; @@ -43,7 +45,7 @@ import se.leap.bitmaskclient.R; import se.leap.bitmaskclient.base.utils.PreferenceHelper; -public class VoidVpnService extends VpnService implements Observer, VpnNotificationManager.VpnServiceCallback { +public class VoidVpnService extends VpnService implements PropertyChangeListener, VpnNotificationManager.VpnServiceCallback { static final String TAG = VoidVpnService.class.getSimpleName(); private ParcelFileDescriptor fd; @@ -183,10 +185,11 @@ public class VoidVpnService extends VpnService implements Observer, VpnNotificat getApplicationContext().startService(startEIP); } + @Override - public void update(Observable observable, Object arg) { - if (observable instanceof EipStatus) { - eipStatus = (EipStatus) observable; + public void propertyChange(PropertyChangeEvent evt) { + if (EipStatus.PROPERTY_CHANGE.equals(evt.getPropertyName())) { + eipStatus = (EipStatus) evt.getNewValue(); } if (handlerThread.isInterrupted() || !handlerThread.isAlive()) { return; diff --git a/app/src/main/java/se/leap/bitmaskclient/firewall/FirewallManager.java b/app/src/main/java/se/leap/bitmaskclient/firewall/FirewallManager.java index 8df1638c..c7a7040f 100644 --- a/app/src/main/java/se/leap/bitmaskclient/firewall/FirewallManager.java +++ b/app/src/main/java/se/leap/bitmaskclient/firewall/FirewallManager.java @@ -21,16 +21,16 @@ import android.os.Handler; import android.os.Looper; import android.widget.Toast; -import java.util.Observable; -import java.util.Observer; +import java.beans.PropertyChangeEvent; +import java.beans.PropertyChangeListener; import de.blinkt.openvpn.core.VpnStatus; import se.leap.bitmaskclient.R; +import se.leap.bitmaskclient.base.utils.PreferenceHelper; import se.leap.bitmaskclient.tethering.TetheringObservable; import se.leap.bitmaskclient.tethering.TetheringState; -import se.leap.bitmaskclient.base.utils.PreferenceHelper; -public class FirewallManager implements FirewallCallback, Observer { +public class FirewallManager implements FirewallCallback, PropertyChangeListener { public static String BITMASK_CHAIN = "bitmask_fw"; public static String BITMASK_FORWARD = "bitmask_forward"; public static String BITMASK_POSTROUTING = "bitmask_postrouting"; @@ -150,9 +150,9 @@ public class FirewallManager implements FirewallCallback, 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(); TetheringState state = observable.getTetheringState(); if (state.hasAnyVpnTetheringAllowed() && state.hasAnyDeviceTetheringEnabled()) { startTethering(); diff --git a/app/src/main/java/se/leap/bitmaskclient/pluggableTransports/ObfsVpnClient.java b/app/src/main/java/se/leap/bitmaskclient/pluggableTransports/ObfsVpnClient.java index 9d5ddcf9..685349ed 100644 --- a/app/src/main/java/se/leap/bitmaskclient/pluggableTransports/ObfsVpnClient.java +++ b/app/src/main/java/se/leap/bitmaskclient/pluggableTransports/ObfsVpnClient.java @@ -4,6 +4,8 @@ import static se.leap.bitmaskclient.base.models.Constants.KCP; import android.util.Log; +import java.beans.PropertyChangeEvent; +import java.beans.PropertyChangeListener; import java.util.Observable; import java.util.Observer; import java.util.concurrent.atomic.AtomicBoolean; @@ -14,7 +16,7 @@ import de.blinkt.openvpn.core.ConnectionStatus; import de.blinkt.openvpn.core.VpnStatus; import se.leap.bitmaskclient.eip.EipStatus; -public class ObfsVpnClient implements Observer, PtClientInterface { +public class ObfsVpnClient implements PropertyChangeListener, PtClientInterface { public static final AtomicInteger SOCKS_PORT = new AtomicInteger(4430); public static final String SOCKS_IP = "127.0.0.1"; @@ -114,9 +116,9 @@ public class ObfsVpnClient implements Observer, PtClientInterface { // TODO: register observer! @Override - public void update(Observable observable, Object arg) { - if (observable instanceof EipStatus) { - EipStatus status = (EipStatus) observable; + public void propertyChange(PropertyChangeEvent evt) { + if (EipStatus.PROPERTY_CHANGE.equals(evt.getPropertyName())) { + EipStatus status = (EipStatus) evt.getNewValue(); if (status.getLevel() == ConnectionStatus.LEVEL_NONETWORK) { noNetwork = true; } else { diff --git a/app/src/main/java/se/leap/bitmaskclient/pluggableTransports/ShapeshifterClient.java b/app/src/main/java/se/leap/bitmaskclient/pluggableTransports/ShapeshifterClient.java index 102dcf35..e57401f8 100644 --- a/app/src/main/java/se/leap/bitmaskclient/pluggableTransports/ShapeshifterClient.java +++ b/app/src/main/java/se/leap/bitmaskclient/pluggableTransports/ShapeshifterClient.java @@ -21,14 +21,14 @@ import android.os.Handler; import android.os.Looper; import android.util.Log; -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; import se.leap.bitmaskclient.eip.EipStatus; -public class ShapeshifterClient implements Observer { +public class ShapeshifterClient implements PropertyChangeListener { public static final String DISPATCHER_PORT = "4430"; public static final String DISPATCHER_IP = "127.0.0.1"; @@ -123,10 +123,11 @@ public class ShapeshifterClient implements Observer { return false; } + @Override - public void update(Observable observable, Object arg) { - if (observable instanceof EipStatus) { - EipStatus status = (EipStatus) observable; + public void propertyChange(PropertyChangeEvent evt) { + if (EipStatus.PROPERTY_CHANGE.equals(evt.getPropertyName())) { + EipStatus status = (EipStatus) evt.getNewValue(); if (status.getLevel() == ConnectionStatus.LEVEL_NONETWORK) { noNetwork = true; } else { diff --git a/app/src/main/java/se/leap/bitmaskclient/tethering/TetheringObservable.java b/app/src/main/java/se/leap/bitmaskclient/tethering/TetheringObservable.java index a25f8c85..5d62b081 100644 --- a/app/src/main/java/se/leap/bitmaskclient/tethering/TetheringObservable.java +++ b/app/src/main/java/se/leap/bitmaskclient/tethering/TetheringObservable.java @@ -18,15 +18,19 @@ package se.leap.bitmaskclient.tethering; import androidx.annotation.NonNull; -import java.util.Observable; +import java.beans.PropertyChangeListener; +import java.beans.PropertyChangeSupport; -public class TetheringObservable extends Observable { +public class TetheringObservable { private static TetheringObservable instance; private TetheringState tetheringState; + private final PropertyChangeSupport changeSupport; + public static final String PROPERTY_CHANGE = "TetheringObservable"; private TetheringObservable() { tetheringState = new TetheringState(); + changeSupport = new PropertyChangeSupport(this); } public static TetheringObservable getInstance() { @@ -36,10 +40,17 @@ public class TetheringObservable extends Observable { return instance; } + public void addObserver(PropertyChangeListener propertyChangeListener) { + changeSupport.addPropertyChangeListener(propertyChangeListener); + } + + public void deleteObserver(PropertyChangeListener propertyChangeListener) { + changeSupport.removePropertyChangeListener(propertyChangeListener); + } + public static void allowVpnWifiTethering(boolean enabled) { if (getInstance().tetheringState.isVpnWifiTetheringAllowed != enabled) { getInstance().tetheringState.isVpnWifiTetheringAllowed = enabled; - getInstance().setChanged(); getInstance().notifyObservers(); } } @@ -47,7 +58,6 @@ public class TetheringObservable extends Observable { public static void allowVpnUsbTethering(boolean enabled) { if (getInstance().tetheringState.isVpnUsbTetheringAllowed != enabled) { getInstance().tetheringState.isVpnUsbTetheringAllowed = enabled; - getInstance().setChanged(); getInstance().notifyObservers(); } } @@ -55,7 +65,6 @@ public class TetheringObservable extends Observable { public static void allowVpnBluetoothTethering(boolean enabled) { if (getInstance().tetheringState.isVpnBluetoothTetheringAllowed != enabled) { getInstance().tetheringState.isVpnBluetoothTetheringAllowed = enabled; - getInstance().setChanged(); getInstance().notifyObservers(); } } @@ -70,7 +79,6 @@ public class TetheringObservable extends Observable { state.wifiAddress = address; state.lastSeenWifiAddress = address.isEmpty() ? state.lastSeenWifiAddress : address; state.lastSeenWifiInterface = interfaceName.isEmpty() ? state.lastSeenWifiInterface : interfaceName; - getInstance().setChanged(); getInstance().notifyObservers(); } @@ -86,7 +94,6 @@ public class TetheringObservable extends Observable { state.usbInterface = interfaceName; state.lastSeenUsbAddress = address.isEmpty() ? state.lastSeenUsbAddress : address; state.lastSeenUsbInterface = interfaceName.isEmpty() ? state.lastSeenUsbInterface : interfaceName; - getInstance().setChanged(); getInstance().notifyObservers(); } } @@ -101,7 +108,6 @@ public class TetheringObservable extends Observable { state.bluetoothInterface = interfaceName; state.lastSeenBluetoothAddress = address.isEmpty() ? state.lastSeenBluetoothAddress : address; state.lastSeenBluetoothInterface = interfaceName.isEmpty() ? state.lastSeenBluetoothInterface : interfaceName; - getInstance().setChanged(); getInstance().notifyObservers(); } } @@ -121,4 +127,8 @@ public class TetheringObservable extends Observable { public TetheringState getTetheringState() { return tetheringState; } + + private void notifyObservers() { + changeSupport.firePropertyChange(PROPERTY_CHANGE, null, getInstance()); + } } diff --git a/app/src/main/java/se/leap/bitmaskclient/tor/ClientTransportPlugin.java b/app/src/main/java/se/leap/bitmaskclient/tor/ClientTransportPlugin.java index b1c4ca83..f13eb70e 100644 --- a/app/src/main/java/se/leap/bitmaskclient/tor/ClientTransportPlugin.java +++ b/app/src/main/java/se/leap/bitmaskclient/tor/ClientTransportPlugin.java @@ -30,6 +30,8 @@ import androidx.annotation.Nullable; import org.torproject.jni.ClientTransportPluginInterface; +import java.beans.PropertyChangeEvent; +import java.beans.PropertyChangeListener; import java.io.BufferedReader; import java.io.File; import java.io.FileNotFoundException; @@ -38,8 +40,6 @@ import java.io.InputStreamReader; import java.lang.ref.WeakReference; import java.util.Collection; import java.util.HashMap; -import java.util.Observable; -import java.util.Observer; import java.util.Random; import java.util.Scanner; import java.util.Vector; @@ -49,7 +49,7 @@ import java.util.regex.Pattern; import IPtProxy.IPtProxy; -public class ClientTransportPlugin implements ClientTransportPluginInterface, Observer { +public class ClientTransportPlugin implements ClientTransportPluginInterface, PropertyChangeListener { public static String TAG = ClientTransportPlugin.class.getSimpleName(); private HashMap mFronts; @@ -221,8 +221,8 @@ public class ClientTransportPlugin implements ClientTransportPluginInterface, Ob } @Override - public void update(Observable o, Object arg) { - if (o instanceof TorStatusObservable) { + public void propertyChange(PropertyChangeEvent evt) { + if(TorStatusObservable.PROPERTY_CHANGE.equals(evt.getPropertyName())) { TorStatusObservable.SnowflakeStatus snowflakeStatus = TorStatusObservable.getSnowflakeStatus(); if (snowflakeStatus == this.snowflakeStatus) { return; diff --git a/app/src/main/java/se/leap/bitmaskclient/tor/TorStatusObservable.java b/app/src/main/java/se/leap/bitmaskclient/tor/TorStatusObservable.java index 8bb41dd2..b1ad6084 100644 --- a/app/src/main/java/se/leap/bitmaskclient/tor/TorStatusObservable.java +++ b/app/src/main/java/se/leap/bitmaskclient/tor/TorStatusObservable.java @@ -29,8 +29,8 @@ import android.util.Log; import androidx.annotation.Nullable; -import java.util.Observable; -import java.util.Observer; +import java.beans.PropertyChangeListener; +import java.beans.PropertyChangeSupport; import java.util.Vector; import java.util.concurrent.CountDownLatch; import java.util.concurrent.TimeUnit; @@ -39,10 +39,13 @@ import java.util.concurrent.atomic.AtomicBoolean; import se.leap.bitmaskclient.R; -public class TorStatusObservable extends Observable { +public class TorStatusObservable { private static final String TAG = TorStatusObservable.class.getSimpleName(); + private final PropertyChangeSupport propertyChange; + public static final String PROPERTY_CHANGE = "TorStatusObservable"; + public interface StatusCondition { boolean met(); } @@ -98,6 +101,7 @@ public class TorStatusObservable extends Observable { private TorStatusObservable() { torNotificationManager = new TorNotificationManager(); + propertyChange = new PropertyChangeSupport(this); } public static TorStatusObservable getInstance() { @@ -126,11 +130,11 @@ public class TorStatusObservable extends Observable { public static boolean waitUntil(StatusCondition condition, int timeout) throws InterruptedException, TimeoutException { CountDownLatch countDownLatch = new CountDownLatch(1); final AtomicBoolean conditionMet = new AtomicBoolean(false); - Observer observer = (o, arg) -> { - if (condition.met()) { - countDownLatch.countDown(); - conditionMet.set(true); - } + PropertyChangeListener observer = evt -> { + if (condition.met()) { + countDownLatch.countDown(); + conditionMet.set(true); + } }; if (condition.met()) { // no need to wait @@ -145,6 +149,14 @@ public class TorStatusObservable extends Observable { return true; } + public void addObserver(PropertyChangeListener propertyChangeListener) { + propertyChange.addPropertyChangeListener(propertyChangeListener); + } + + public void deleteObserver(PropertyChangeListener propertyChangeListener) { + propertyChange.removePropertyChangeListener(propertyChangeListener); + } + public static void logSnowflakeMessage(Context context, String message) { addLog(message); if (getInstance().status != TorStatus.OFF) { @@ -191,7 +203,6 @@ public class TorStatusObservable extends Observable { getInstance().lastSnowflakeLog = context.getString(R.string.snowflake_sending_data); } Log.d(TAG, "snowflake status " + getInstance().snowflakeStatus); - instance.setChanged(); instance.notifyObservers(); } @@ -230,7 +241,7 @@ public class TorStatusObservable extends Observable { public static void updateState(Context context, String status, int bootstrapPercent, @Nullable String logKey) { try { - Log.d(TAG, "update tor state: " + status + " " + bootstrapPercent + " "+ logKey); + // Log.d(TAG, "update tor state: " + status + " " + bootstrapPercent + " "+ logKey); getInstance().status = TorStatus.valueOf(status); if (bootstrapPercent != -1) { getInstance().bootstrapPercent = bootstrapPercent; @@ -247,7 +258,7 @@ public class TorStatusObservable extends Observable { getInstance().torNotificationManager.buildTorNotification(context, getStringForCurrentStatus(context), getNotificationLog(), getBootstrapProgress()); } - instance.setChanged(); + instance.notifyObservers(); } catch (IllegalStateException e) { @@ -255,6 +266,10 @@ public class TorStatusObservable extends Observable { } } + private void notifyObservers() { + instance.propertyChange.firePropertyChange(PROPERTY_CHANGE, null, instance); + } + private static String getStringFor(Context context, String key) { switch (key) { case "conn_pt": @@ -294,13 +309,11 @@ public class TorStatusObservable extends Observable { public static void setLastError(String error) { getInstance().lastError = error; - instance.setChanged(); instance.notifyObservers(); } public static void setProxyPort(int port) { getInstance().port = port; - instance.setChanged(); instance.notifyObservers(); } @@ -345,7 +358,6 @@ public class TorStatusObservable extends Observable { if (!getInstance().cancelled) { getInstance().cancelled = true; getInstance().port = -1; - getInstance().setChanged(); getInstance().notifyObservers(); } } -- cgit v1.2.3 From a43be4240f48bca2985a4cc3ddee124ff80bfb1a Mon Sep 17 00:00:00 2001 From: cyBerta Date: Mon, 22 Jan 2024 17:23:47 +0100 Subject: fix check if provider setup result matches the intended last selected provider --- .../providersetup/fragments/ConfigureProviderFragment.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'app/src/main') diff --git a/app/src/main/java/se/leap/bitmaskclient/providersetup/fragments/ConfigureProviderFragment.java b/app/src/main/java/se/leap/bitmaskclient/providersetup/fragments/ConfigureProviderFragment.java index e041b19b..9e8589ae 100644 --- a/app/src/main/java/se/leap/bitmaskclient/providersetup/fragments/ConfigureProviderFragment.java +++ b/app/src/main/java/se/leap/bitmaskclient/providersetup/fragments/ConfigureProviderFragment.java @@ -206,7 +206,7 @@ public class ConfigureProviderFragment extends BaseSetupFragment implements Obse if (ignoreProviderAPIUpdates || provider == null || (setupActivityCallback.getSelectedProvider() != null && - !setupActivityCallback.getSelectedProvider().getDomain().equals(provider.getDomain()))) { + !setupActivityCallback.getSelectedProvider().getMainUrlString().equals(provider.getMainUrlString()))) { return; } -- 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 ++++++++++++++++++++++ .../se/leap/bitmaskclient/eip/GatewaySelector.java | 6 ++-- 3 files changed, 47 insertions(+), 19 deletions(-) create mode 100644 app/src/main/java/se/leap/bitmaskclient/base/utils/TimezoneHelper.java (limited to 'app/src/main') 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; + } + } +} diff --git a/app/src/main/java/se/leap/bitmaskclient/eip/GatewaySelector.java b/app/src/main/java/se/leap/bitmaskclient/eip/GatewaySelector.java index ad95c823..6a0b4b08 100644 --- a/app/src/main/java/se/leap/bitmaskclient/eip/GatewaySelector.java +++ b/app/src/main/java/se/leap/bitmaskclient/eip/GatewaySelector.java @@ -1,5 +1,8 @@ package se.leap.bitmaskclient.eip; +import static se.leap.bitmaskclient.base.utils.TimezoneHelper.timezoneDistance; +import static se.leap.bitmaskclient.base.utils.TimezoneHelper.getCurrentTimezone; + import android.util.Log; import java.util.ArrayList; @@ -10,9 +13,6 @@ import java.util.Map; import java.util.Set; import java.util.TreeMap; -import static se.leap.bitmaskclient.base.utils.ConfigHelper.getCurrentTimezone; -import static se.leap.bitmaskclient.base.utils.ConfigHelper.timezoneDistance; - public class GatewaySelector { private final static String TAG = GatewaySelector.class.getSimpleName(); List gateways; -- 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') 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 --- .../main/java/de/blinkt/openvpn/VpnProfile.java | 5 +- .../de/blinkt/openvpn/core/OpenVPNService.java | 2 +- .../openvpn/core/connection/Obfs4Connection.java | 2 +- .../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 ++++++++++++++++++ .../leap/bitmaskclient/eip/VpnConfigGenerator.java | 2 +- .../providersetup/ProviderApiManagerBase.java | 2 +- 13 files changed, 175 insertions(+), 79 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') diff --git a/app/src/main/java/de/blinkt/openvpn/VpnProfile.java b/app/src/main/java/de/blinkt/openvpn/VpnProfile.java index 780ac9d8..9da1e452 100644 --- a/app/src/main/java/de/blinkt/openvpn/VpnProfile.java +++ b/app/src/main/java/de/blinkt/openvpn/VpnProfile.java @@ -16,7 +16,6 @@ import android.content.pm.PackageInfo; import android.content.pm.PackageManager; import android.os.Build; import android.os.Bundle; -import android.preference.PreferenceManager; import android.security.KeyChain; import android.security.KeyChainException; import android.text.TextUtils; @@ -77,6 +76,7 @@ import de.blinkt.openvpn.core.connection.ConnectionAdapter; import se.leap.bitmaskclient.BuildConfig; import se.leap.bitmaskclient.R; import se.leap.bitmaskclient.base.models.ProviderObservable; +import se.leap.bitmaskclient.base.utils.PreferenceHelper; public class VpnProfile implements Serializable, Cloneable { // Note that this class cannot be moved to core where it belongs since @@ -651,8 +651,7 @@ public class VpnProfile implements Serializable, Cloneable { if (mPushPeerInfo) cfg.append("push-peer-info\n"); - SharedPreferences prefs = PreferenceManager.getDefaultSharedPreferences(context); - boolean usesystemproxy = prefs.getBoolean("usesystemproxy", true); + boolean usesystemproxy = PreferenceHelper.useSystemProxy(); if (usesystemproxy && !mIsOpenVPN22 && !configForOvpn3 && !usesExtraProxyOptions()) { cfg.append("# Use system proxy setting\n"); cfg.append("management-query-proxy\n"); diff --git a/app/src/main/java/de/blinkt/openvpn/core/OpenVPNService.java b/app/src/main/java/de/blinkt/openvpn/core/OpenVPNService.java index b38eeb14..e311158c 100644 --- a/app/src/main/java/de/blinkt/openvpn/core/OpenVPNService.java +++ b/app/src/main/java/de/blinkt/openvpn/core/OpenVPNService.java @@ -9,7 +9,7 @@ import static de.blinkt.openvpn.core.ConnectionStatus.LEVEL_CONNECTED; import static de.blinkt.openvpn.core.ConnectionStatus.LEVEL_WAITING_FOR_USER_INPUT; import static de.blinkt.openvpn.core.NetworkSpace.IpAddress; import static se.leap.bitmaskclient.base.models.Constants.PROVIDER_PROFILE; -import static se.leap.bitmaskclient.base.utils.ConfigHelper.ObfsVpnHelper.useObfsVpn; +import static se.leap.bitmaskclient.base.utils.ObfsVpnHelper.useObfsVpn; import android.Manifest.permission; import android.app.Notification; diff --git a/app/src/main/java/de/blinkt/openvpn/core/connection/Obfs4Connection.java b/app/src/main/java/de/blinkt/openvpn/core/connection/Obfs4Connection.java index d152031a..0abb5822 100644 --- a/app/src/main/java/de/blinkt/openvpn/core/connection/Obfs4Connection.java +++ b/app/src/main/java/de/blinkt/openvpn/core/connection/Obfs4Connection.java @@ -1,6 +1,6 @@ package de.blinkt.openvpn.core.connection; -import static se.leap.bitmaskclient.base.utils.ConfigHelper.ObfsVpnHelper.useObfsVpn; +import static se.leap.bitmaskclient.base.utils.ObfsVpnHelper.useObfsVpn; import static se.leap.bitmaskclient.pluggableTransports.ShapeshifterClient.DISPATCHER_IP; import static se.leap.bitmaskclient.pluggableTransports.ShapeshifterClient.DISPATCHER_PORT; 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); + } +} diff --git a/app/src/main/java/se/leap/bitmaskclient/eip/VpnConfigGenerator.java b/app/src/main/java/se/leap/bitmaskclient/eip/VpnConfigGenerator.java index 6d5a406e..d21b6078 100644 --- a/app/src/main/java/se/leap/bitmaskclient/eip/VpnConfigGenerator.java +++ b/app/src/main/java/se/leap/bitmaskclient/eip/VpnConfigGenerator.java @@ -30,7 +30,7 @@ import static se.leap.bitmaskclient.base.models.Constants.REMOTE; import static se.leap.bitmaskclient.base.models.Constants.TCP; import static se.leap.bitmaskclient.base.models.Constants.TRANSPORT; import static se.leap.bitmaskclient.base.models.Constants.UDP; -import static se.leap.bitmaskclient.base.utils.ConfigHelper.ObfsVpnHelper.useObfsVpn; +import static se.leap.bitmaskclient.base.utils.ObfsVpnHelper.useObfsVpn; import static se.leap.bitmaskclient.pluggableTransports.ShapeshifterClient.DISPATCHER_IP; import static se.leap.bitmaskclient.pluggableTransports.ShapeshifterClient.DISPATCHER_PORT; diff --git a/app/src/main/java/se/leap/bitmaskclient/providersetup/ProviderApiManagerBase.java b/app/src/main/java/se/leap/bitmaskclient/providersetup/ProviderApiManagerBase.java index 93648bb0..08067d38 100644 --- a/app/src/main/java/se/leap/bitmaskclient/providersetup/ProviderApiManagerBase.java +++ b/app/src/main/java/se/leap/bitmaskclient/providersetup/ProviderApiManagerBase.java @@ -45,7 +45,7 @@ import static se.leap.bitmaskclient.base.models.Provider.CA_CERT; import static se.leap.bitmaskclient.base.models.Provider.GEOIP_URL; import static se.leap.bitmaskclient.base.models.Provider.PROVIDER_API_IP; import static se.leap.bitmaskclient.base.models.Provider.PROVIDER_IP; -import static se.leap.bitmaskclient.base.utils.ConfigHelper.RSAHelper.parseRsaKeyFromString; +import static se.leap.bitmaskclient.base.utils.RSAHelper.parseRsaKeyFromString; import static se.leap.bitmaskclient.base.utils.ConfigHelper.getDomainFromMainURL; import static se.leap.bitmaskclient.base.utils.ConfigHelper.getFingerprintFromCertificate; import static se.leap.bitmaskclient.base.utils.ConfigHelper.getProviderFormattedString; -- 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 ++++++++++++++++++++++ .../providersetup/ProviderApiManagerBase.java | 2 +- 2 files changed, 65 insertions(+), 1 deletion(-) create mode 100644 app/src/main/java/se/leap/bitmaskclient/base/utils/CertificateHelper.java (limited to 'app/src/main') 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); + } + +} diff --git a/app/src/main/java/se/leap/bitmaskclient/providersetup/ProviderApiManagerBase.java b/app/src/main/java/se/leap/bitmaskclient/providersetup/ProviderApiManagerBase.java index 08067d38..05c5448a 100644 --- a/app/src/main/java/se/leap/bitmaskclient/providersetup/ProviderApiManagerBase.java +++ b/app/src/main/java/se/leap/bitmaskclient/providersetup/ProviderApiManagerBase.java @@ -47,7 +47,7 @@ import static se.leap.bitmaskclient.base.models.Provider.PROVIDER_API_IP; import static se.leap.bitmaskclient.base.models.Provider.PROVIDER_IP; import static se.leap.bitmaskclient.base.utils.RSAHelper.parseRsaKeyFromString; import static se.leap.bitmaskclient.base.utils.ConfigHelper.getDomainFromMainURL; -import static se.leap.bitmaskclient.base.utils.ConfigHelper.getFingerprintFromCertificate; +import static se.leap.bitmaskclient.base.utils.CertificateHelper.getFingerprintFromCertificate; import static se.leap.bitmaskclient.base.utils.ConfigHelper.getProviderFormattedString; import static se.leap.bitmaskclient.base.utils.PreferenceHelper.deleteProviderDetailsFromPreferences; import static se.leap.bitmaskclient.base.utils.PreferenceHelper.getFromPersistedProvider; -- 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 --- .../de/blinkt/openvpn/core/OpenVPNService.java | 2 +- .../openvpn/core/connection/Obfs4Connection.java | 2 +- .../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 +- .../leap/bitmaskclient/eip/VpnConfigGenerator.java | 2 +- .../providersetup/SetupViewPagerAdapter.java | 2 +- .../providersetup/activities/SetupActivity.java | 2 +- .../fragments/CircumventionSetupFragment.java | 4 +- .../fragments/ConfigureProviderFragment.java | 2 +- 15 files changed, 115 insertions(+), 111 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') diff --git a/app/src/main/java/de/blinkt/openvpn/core/OpenVPNService.java b/app/src/main/java/de/blinkt/openvpn/core/OpenVPNService.java index e311158c..5a618f10 100644 --- a/app/src/main/java/de/blinkt/openvpn/core/OpenVPNService.java +++ b/app/src/main/java/de/blinkt/openvpn/core/OpenVPNService.java @@ -9,7 +9,7 @@ import static de.blinkt.openvpn.core.ConnectionStatus.LEVEL_CONNECTED; import static de.blinkt.openvpn.core.ConnectionStatus.LEVEL_WAITING_FOR_USER_INPUT; import static de.blinkt.openvpn.core.NetworkSpace.IpAddress; import static se.leap.bitmaskclient.base.models.Constants.PROVIDER_PROFILE; -import static se.leap.bitmaskclient.base.utils.ObfsVpnHelper.useObfsVpn; +import static se.leap.bitmaskclient.base.utils.BuildConfigHelper.useObfsVpn; import android.Manifest.permission; import android.app.Notification; diff --git a/app/src/main/java/de/blinkt/openvpn/core/connection/Obfs4Connection.java b/app/src/main/java/de/blinkt/openvpn/core/connection/Obfs4Connection.java index 0abb5822..19ea180d 100644 --- a/app/src/main/java/de/blinkt/openvpn/core/connection/Obfs4Connection.java +++ b/app/src/main/java/de/blinkt/openvpn/core/connection/Obfs4Connection.java @@ -1,6 +1,6 @@ package de.blinkt.openvpn.core.connection; -import static se.leap.bitmaskclient.base.utils.ObfsVpnHelper.useObfsVpn; +import static se.leap.bitmaskclient.base.utils.BuildConfigHelper.useObfsVpn; import static se.leap.bitmaskclient.pluggableTransports.ShapeshifterClient.DISPATCHER_IP; import static se.leap.bitmaskclient.pluggableTransports.ShapeshifterClient.DISPATCHER_PORT; 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()) && diff --git a/app/src/main/java/se/leap/bitmaskclient/eip/VpnConfigGenerator.java b/app/src/main/java/se/leap/bitmaskclient/eip/VpnConfigGenerator.java index d21b6078..4c8fa797 100644 --- a/app/src/main/java/se/leap/bitmaskclient/eip/VpnConfigGenerator.java +++ b/app/src/main/java/se/leap/bitmaskclient/eip/VpnConfigGenerator.java @@ -30,7 +30,7 @@ import static se.leap.bitmaskclient.base.models.Constants.REMOTE; import static se.leap.bitmaskclient.base.models.Constants.TCP; import static se.leap.bitmaskclient.base.models.Constants.TRANSPORT; import static se.leap.bitmaskclient.base.models.Constants.UDP; -import static se.leap.bitmaskclient.base.utils.ObfsVpnHelper.useObfsVpn; +import static se.leap.bitmaskclient.base.utils.BuildConfigHelper.useObfsVpn; import static se.leap.bitmaskclient.pluggableTransports.ShapeshifterClient.DISPATCHER_IP; import static se.leap.bitmaskclient.pluggableTransports.ShapeshifterClient.DISPATCHER_PORT; diff --git a/app/src/main/java/se/leap/bitmaskclient/providersetup/SetupViewPagerAdapter.java b/app/src/main/java/se/leap/bitmaskclient/providersetup/SetupViewPagerAdapter.java index 00630f39..fb190dc2 100644 --- a/app/src/main/java/se/leap/bitmaskclient/providersetup/SetupViewPagerAdapter.java +++ b/app/src/main/java/se/leap/bitmaskclient/providersetup/SetupViewPagerAdapter.java @@ -1,6 +1,6 @@ package se.leap.bitmaskclient.providersetup; -import static se.leap.bitmaskclient.base.utils.ConfigHelper.isDefaultBitmask; +import static se.leap.bitmaskclient.base.utils.BuildConfigHelper.isDefaultBitmask; import static se.leap.bitmaskclient.providersetup.fragments.SetupFragmentFactory.CIRCUMVENTION_SETUP_FRAGMENT; import static se.leap.bitmaskclient.providersetup.fragments.SetupFragmentFactory.CONFIGURE_PROVIDER_FRAGMENT; import static se.leap.bitmaskclient.providersetup.fragments.SetupFragmentFactory.NOTIFICATION_PERMISSON_EDUCATIONAL_FRAGMENT; diff --git a/app/src/main/java/se/leap/bitmaskclient/providersetup/activities/SetupActivity.java b/app/src/main/java/se/leap/bitmaskclient/providersetup/activities/SetupActivity.java index dd735f84..9235daad 100644 --- a/app/src/main/java/se/leap/bitmaskclient/providersetup/activities/SetupActivity.java +++ b/app/src/main/java/se/leap/bitmaskclient/providersetup/activities/SetupActivity.java @@ -3,7 +3,7 @@ package se.leap.bitmaskclient.providersetup.activities; import static android.view.View.GONE; import static android.view.View.VISIBLE; import static androidx.appcompat.app.ActionBar.DISPLAY_SHOW_CUSTOM; -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.deleteProviderDetailsFromPreferences; import static se.leap.bitmaskclient.providersetup.fragments.SetupFragmentFactory.CONFIGURE_PROVIDER_FRAGMENT; import static se.leap.bitmaskclient.tor.TorStatusObservable.TorStatus.OFF; diff --git a/app/src/main/java/se/leap/bitmaskclient/providersetup/fragments/CircumventionSetupFragment.java b/app/src/main/java/se/leap/bitmaskclient/providersetup/fragments/CircumventionSetupFragment.java index 34a93319..cdb8bd78 100644 --- a/app/src/main/java/se/leap/bitmaskclient/providersetup/fragments/CircumventionSetupFragment.java +++ b/app/src/main/java/se/leap/bitmaskclient/providersetup/fragments/CircumventionSetupFragment.java @@ -1,8 +1,7 @@ package se.leap.bitmaskclient.providersetup.fragments; -import static se.leap.bitmaskclient.base.utils.ConfigHelper.isDefaultBitmask; +import static se.leap.bitmaskclient.base.utils.BuildConfigHelper.isDefaultBitmask; -import android.content.Context; import android.graphics.Typeface; import android.os.Bundle; import android.view.LayoutInflater; @@ -17,7 +16,6 @@ import se.leap.bitmaskclient.base.utils.PreferenceHelper; import se.leap.bitmaskclient.databinding.FCircumventionSetupBinding; import se.leap.bitmaskclient.providersetup.ProviderManager; import se.leap.bitmaskclient.providersetup.activities.CancelCallback; -import se.leap.bitmaskclient.providersetup.activities.SetupActivityCallback; public class CircumventionSetupFragment extends BaseSetupFragment implements CancelCallback { diff --git a/app/src/main/java/se/leap/bitmaskclient/providersetup/fragments/ConfigureProviderFragment.java b/app/src/main/java/se/leap/bitmaskclient/providersetup/fragments/ConfigureProviderFragment.java index 9e8589ae..877628fb 100644 --- a/app/src/main/java/se/leap/bitmaskclient/providersetup/fragments/ConfigureProviderFragment.java +++ b/app/src/main/java/se/leap/bitmaskclient/providersetup/fragments/ConfigureProviderFragment.java @@ -9,7 +9,7 @@ import static se.leap.bitmaskclient.R.string.description_configure_provider_circ import static se.leap.bitmaskclient.base.models.Constants.BROADCAST_RESULT_CODE; import static se.leap.bitmaskclient.base.models.Constants.BROADCAST_RESULT_KEY; import static se.leap.bitmaskclient.base.models.Constants.PROVIDER_KEY; -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.getUseSnowflake; import static se.leap.bitmaskclient.base.utils.ViewHelper.animateContainerVisibility; import static se.leap.bitmaskclient.providersetup.ProviderAPI.CORRECTLY_DOWNLOADED_VPN_CERTIFICATE; -- 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') 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') 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 be8535ff9ab0968187acd008b8c01e1b8d9c336e Mon Sep 17 00:00:00 2001 From: cyBerta Date: Thu, 25 Jan 2024 23:27:59 +0100 Subject: ProviderSetupObservable: replace deprecated Observer class with PropertyChangeListener --- .../providersetup/ProviderSetupObservable.java | 46 ++++++++++++++++------ .../fragments/ConfigureProviderFragment.java | 10 ++--- 2 files changed, 39 insertions(+), 17 deletions(-) (limited to 'app/src/main') diff --git a/app/src/main/java/se/leap/bitmaskclient/providersetup/ProviderSetupObservable.java b/app/src/main/java/se/leap/bitmaskclient/providersetup/ProviderSetupObservable.java index 90a32fea..c882b0bb 100644 --- a/app/src/main/java/se/leap/bitmaskclient/providersetup/ProviderSetupObservable.java +++ b/app/src/main/java/se/leap/bitmaskclient/providersetup/ProviderSetupObservable.java @@ -16,14 +16,19 @@ package se.leap.bitmaskclient.providersetup; * along with this program. If not, see . */ -import android.os.Handler; -import android.os.Looper; - -import java.util.Observable; +import java.beans.PropertyChangeListener; +import java.beans.PropertyChangeSupport; +import se.leap.bitmaskclient.base.utils.HandlerProvider; +import se.leap.bitmaskclient.base.utils.HandlerProvider.HandlerInterface; import se.leap.bitmaskclient.tor.TorStatusObservable; -public class ProviderSetupObservable extends Observable { +/** + * This Observable tracks the progress of a started provider bootstrapping attempt. + * Each required API call us taken into account as well as the state of tor's bootstrapping in case + * it is used for censorship circumvention. + */ +public class ProviderSetupObservable { private static final String TAG = ProviderSetupObservable.class.getSimpleName(); @@ -36,9 +41,28 @@ public class ProviderSetupObservable extends Observable { public static final int DOWNLOADED_VPN_CERTIFICATE = 100; private static ProviderSetupObservable instance; - private final Handler handler = new Handler(Looper.getMainLooper()); + private final PropertyChangeSupport changeSupport; + public static final String PROPERTY_CHANGE = "ProviderSetupObservable"; + private final HandlerInterface handler; private long lastUpdate = 0; + + + private ProviderSetupObservable() { + handler = HandlerProvider.get(); + changeSupport = new PropertyChangeSupport(this); + + } + + public void addObserver(PropertyChangeListener propertyChangeListener) { + changeSupport.addPropertyChangeListener(propertyChangeListener); + } + + public void deleteObserver(PropertyChangeListener propertyChangeListener) { + changeSupport.removePropertyChangeListener(propertyChangeListener); + } + + public static ProviderSetupObservable getInstance() { if (instance == null) { instance = new ProviderSetupObservable(); @@ -58,8 +82,8 @@ public class ProviderSetupObservable extends Observable { getInstance().progress = progress; } - getInstance().setChanged(); - getInstance().notifyObservers(); + getInstance().changeSupport.firePropertyChange(PROPERTY_CHANGE, null, getInstance()); + }, now - getInstance().lastUpdate < 500L ? 500L : 0L); getInstance().lastUpdate = System.currentTimeMillis() + 500; } @@ -72,8 +96,7 @@ public class ProviderSetupObservable extends Observable { getInstance().handler.postDelayed(() -> { getInstance().progress = (TorStatusObservable.getBootstrapProgress()) / 2; - getInstance().setChanged(); - getInstance().notifyObservers(); + getInstance().changeSupport.firePropertyChange(PROPERTY_CHANGE, null, getInstance()); }, now - getInstance().lastUpdate < 500L ? 500L : 0); getInstance().lastUpdate = System.currentTimeMillis() + 500; } @@ -84,8 +107,7 @@ public class ProviderSetupObservable extends Observable { public static void reset() { getInstance().progress = 0; - getInstance().setChanged(); - getInstance().notifyObservers(); + getInstance().changeSupport.firePropertyChange(PROPERTY_CHANGE, null, getInstance()); } public static void cancel() { diff --git a/app/src/main/java/se/leap/bitmaskclient/providersetup/fragments/ConfigureProviderFragment.java b/app/src/main/java/se/leap/bitmaskclient/providersetup/fragments/ConfigureProviderFragment.java index 877628fb..8477c302 100644 --- a/app/src/main/java/se/leap/bitmaskclient/providersetup/fragments/ConfigureProviderFragment.java +++ b/app/src/main/java/se/leap/bitmaskclient/providersetup/fragments/ConfigureProviderFragment.java @@ -42,9 +42,9 @@ import androidx.core.content.res.ResourcesCompat; import androidx.recyclerview.widget.LinearLayoutManager; import androidx.recyclerview.widget.RecyclerView; +import java.beans.PropertyChangeEvent; +import java.beans.PropertyChangeListener; import java.util.List; -import java.util.Observable; -import java.util.Observer; import se.leap.bitmaskclient.R; import se.leap.bitmaskclient.base.models.Provider; @@ -57,7 +57,7 @@ import se.leap.bitmaskclient.providersetup.TorLogAdapter; import se.leap.bitmaskclient.providersetup.activities.CancelCallback; import se.leap.bitmaskclient.tor.TorStatusObservable; -public class ConfigureProviderFragment extends BaseSetupFragment implements Observer, CancelCallback, EipSetupListener { +public class ConfigureProviderFragment extends BaseSetupFragment implements PropertyChangeListener, CancelCallback, EipSetupListener { private static final String TAG = ConfigureProviderFragment.class.getSimpleName(); @@ -158,8 +158,8 @@ public class ConfigureProviderFragment extends BaseSetupFragment implements Obse } @Override - public void update(Observable o, Object arg) { - if (o instanceof ProviderSetupObservable) { + public void propertyChange(PropertyChangeEvent evt) { + if (ProviderSetupObservable.PROPERTY_CHANGE.equals(evt.getPropertyName())) { Activity activity = getActivity(); if (activity == null || binding == null) { return; -- cgit v1.2.3 From 9bba7b29a416b2617af033a778ef13a512024502 Mon Sep 17 00:00:00 2001 From: cyBerta Date: Thu, 25 Jan 2024 23:37:53 +0100 Subject: refactor ProviderApiConnector, allow to inject dummy implementations for unit tests --- .../providersetup/ProviderApiConnector.java | 134 +++++++++++++-------- .../providersetup/ProviderApiManagerBase.java | 13 +- 2 files changed, 94 insertions(+), 53 deletions(-) (limited to 'app/src/main') diff --git a/app/src/main/java/se/leap/bitmaskclient/providersetup/ProviderApiConnector.java b/app/src/main/java/se/leap/bitmaskclient/providersetup/ProviderApiConnector.java index 35ad9cd2..cc875c79 100644 --- a/app/src/main/java/se/leap/bitmaskclient/providersetup/ProviderApiConnector.java +++ b/app/src/main/java/se/leap/bitmaskclient/providersetup/ProviderApiConnector.java @@ -18,6 +18,8 @@ package se.leap.bitmaskclient.providersetup; import androidx.annotation.NonNull; +import androidx.annotation.VisibleForTesting; + import android.util.Pair; import java.io.IOException; @@ -26,6 +28,9 @@ import java.util.List; import java.util.Locale; import java.util.Scanner; +import javax.net.ssl.SSLHandshakeException; + +import de.blinkt.openvpn.core.NativeUtils; import de.blinkt.openvpn.core.VpnStatus; import okhttp3.MediaType; import okhttp3.OkHttpClient; @@ -39,72 +44,103 @@ import okhttp3.Response; public class ProviderApiConnector { - private static final MediaType JSON - = MediaType.parse("application/json; charset=utf-8"); + public interface ProviderApiConnectorInterface { + boolean delete(OkHttpClient okHttpClient, String deleteUrl) throws RuntimeException, IOException; + boolean canConnect(@NonNull OkHttpClient okHttpClient, String url) throws RuntimeException, IOException; + String requestStringFromServer(@NonNull String url, @NonNull String requestMethod, String jsonString, @NonNull List> headerArgs, @NonNull OkHttpClient okHttpClient) throws RuntimeException, IOException; + + } + public static class DefaultProviderApiCpnnector implements ProviderApiConnectorInterface { + + @Override + public boolean delete(OkHttpClient okHttpClient, String deleteUrl) { + try { + Request.Builder requestBuilder = new Request.Builder() + .url(deleteUrl) + .delete(); + Request request = requestBuilder.build(); + + Response response = okHttpClient.newCall(request).execute(); + //response code 401: already logged out + if (response.isSuccessful() || response.code() == 401) { + return true; + } + } catch (IOException | RuntimeException e) { + return false; + } + + return false; + } - public static boolean delete(OkHttpClient okHttpClient, String deleteUrl) { - try { + @Override + public boolean canConnect(@NonNull OkHttpClient okHttpClient, String url) throws RuntimeException, IOException { Request.Builder requestBuilder = new Request.Builder() - .url(deleteUrl) - .delete(); + .url(url) + .method("GET", null); Request request = requestBuilder.build(); Response response = okHttpClient.newCall(request).execute(); - //response code 401: already logged out - if (response.isSuccessful() || response.code() == 401) { - return true; + if (!response.isSuccessful()) { + VpnStatus.logWarning("[API] API request failed canConnect(): " + url); } - } catch (IOException | RuntimeException e) { - return false; + return response.isSuccessful(); } - return false; - } + @Override + public String requestStringFromServer(@NonNull String url, @NonNull String requestMethod, String jsonString, @NonNull List> headerArgs, @NonNull OkHttpClient okHttpClient) throws RuntimeException, IOException { + RequestBody jsonBody = jsonString != null ? RequestBody.create(JSON, jsonString) : null; + Request.Builder requestBuilder = new Request.Builder() + .url(url) + .method(requestMethod, jsonBody); + for (Pair keyValPair : headerArgs) { + requestBuilder.addHeader(keyValPair.first, keyValPair.second); + } - public static boolean canConnect(@NonNull OkHttpClient okHttpClient, String url) throws RuntimeException, IOException { - Request.Builder requestBuilder = new Request.Builder() - .url(url) - .method("GET", null); - Request request = requestBuilder.build(); - - Response response = okHttpClient.newCall(request).execute(); - if (!response.isSuccessful()) { - VpnStatus.logWarning("[API] API request failed canConnect(): " + url); + //TODO: move to getHeaderArgs()? + String locale = Locale.getDefault().getLanguage() + Locale.getDefault().getCountry(); + requestBuilder.addHeader("Accept-Language", locale); + Request request = requestBuilder.build(); + + Response response = okHttpClient.newCall(request).execute(); + if (!response.isSuccessful()) { + VpnStatus.logWarning("[API] API request failed: " + url); + } + + if (response.body() != null) { + InputStream inputStream = response.body().byteStream(); + Scanner scanner = new Scanner(inputStream).useDelimiter("\\A"); + if (scanner.hasNext()) { + String result = scanner.next(); + response.body().close(); + return result; + } + } + return null; } - return response.isSuccessful(); + } + private static final MediaType JSON = MediaType.parse("application/json; charset=utf-8"); + private static ProviderApiConnectorInterface instance = new DefaultProviderApiCpnnector(); + @VisibleForTesting + public ProviderApiConnector(ProviderApiConnectorInterface connectorInterface) { + if (!NativeUtils.isUnitTest()) { + throw new IllegalStateException("ProviderApiConnector injected with ProviderApiConnectorInterface outside of an unit test"); + } + instance = connectorInterface; } - public static String requestStringFromServer(@NonNull String url, @NonNull String request_method, String jsonString, @NonNull List> headerArgs, @NonNull OkHttpClient okHttpClient) throws RuntimeException, IOException { - RequestBody jsonBody = jsonString != null ? RequestBody.create(JSON, jsonString) : null; - Request.Builder requestBuilder = new Request.Builder() - .url(url) - .method(request_method, jsonBody); - for (Pair keyValPair : headerArgs) { - requestBuilder.addHeader(keyValPair.first, keyValPair.second); - } + public static boolean delete(OkHttpClient okHttpClient, String deleteUrl) throws RuntimeException, IOException { + return instance.delete(okHttpClient, deleteUrl); + } - //TODO: move to getHeaderArgs()? - String locale = Locale.getDefault().getLanguage() + Locale.getDefault().getCountry(); - requestBuilder.addHeader("Accept-Language", locale); - Request request = requestBuilder.build(); + public static boolean canConnect(@NonNull OkHttpClient okHttpClient, String url) throws RuntimeException, IOException { + return instance.canConnect(okHttpClient, url); - Response response = okHttpClient.newCall(request).execute(); - if (!response.isSuccessful()) { - VpnStatus.logWarning("[API] API request failed: " + url); - } + } - if (response.body() != null) { - InputStream inputStream = response.body().byteStream(); - Scanner scanner = new Scanner(inputStream).useDelimiter("\\A"); - if (scanner.hasNext()) { - String result = scanner.next(); - response.body().close(); - return result; - } - } - return null; + public static String requestStringFromServer(@NonNull String url, @NonNull String requestMethod, String jsonString, @NonNull List> headerArgs, @NonNull OkHttpClient okHttpClient) throws RuntimeException, IOException { + return instance.requestStringFromServer(url, requestMethod, jsonString, headerArgs, okHttpClient); } } diff --git a/app/src/main/java/se/leap/bitmaskclient/providersetup/ProviderApiManagerBase.java b/app/src/main/java/se/leap/bitmaskclient/providersetup/ProviderApiManagerBase.java index 05c5448a..1f737b0c 100644 --- a/app/src/main/java/se/leap/bitmaskclient/providersetup/ProviderApiManagerBase.java +++ b/app/src/main/java/se/leap/bitmaskclient/providersetup/ProviderApiManagerBase.java @@ -45,6 +45,7 @@ import static se.leap.bitmaskclient.base.models.Provider.CA_CERT; import static se.leap.bitmaskclient.base.models.Provider.GEOIP_URL; import static se.leap.bitmaskclient.base.models.Provider.PROVIDER_API_IP; import static se.leap.bitmaskclient.base.models.Provider.PROVIDER_IP; +import static se.leap.bitmaskclient.base.utils.ConfigHelper.getTorTimeout; import static se.leap.bitmaskclient.base.utils.RSAHelper.parseRsaKeyFromString; import static se.leap.bitmaskclient.base.utils.ConfigHelper.getDomainFromMainURL; import static se.leap.bitmaskclient.base.utils.CertificateHelper.getFingerprintFromCertificate; @@ -380,7 +381,7 @@ public abstract class ProviderApiManagerBase { if (TorStatusObservable.getStatus() == ON) { return; } - TorStatusObservable.waitUntil(this::isTorOnOrCancelled, 180); + TorStatusObservable.waitUntil(this::isTorOnOrCancelled, getTorTimeout()); } private boolean isTorOnOrCancelled() { @@ -1138,9 +1139,13 @@ public abstract class ProviderApiManagerBase { String deleteUrl = provider.getApiUrlWithVersion() + "/logout"; - if (ProviderApiConnector.delete(okHttpClient, deleteUrl)) { - LeapSRPSession.setToken(""); - return true; + try { + if (ProviderApiConnector.delete(okHttpClient, deleteUrl)) { + LeapSRPSession.setToken(""); + return true; + } + } catch (IOException e) { + // eat me } return false; } -- 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') 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') 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