summaryrefslogtreecommitdiff
path: root/app/src/main/java/se/leap
diff options
context:
space:
mode:
Diffstat (limited to 'app/src/main/java/se/leap')
-rw-r--r--app/src/main/java/se/leap/bitmaskclient/base/fragments/SettingsFragment.java80
-rw-r--r--app/src/main/java/se/leap/bitmaskclient/base/models/Constants.java1
-rw-r--r--app/src/main/java/se/leap/bitmaskclient/base/utils/ConfigHelper.java33
-rw-r--r--app/src/main/java/se/leap/bitmaskclient/base/utils/PreferenceHelper.java9
-rw-r--r--app/src/main/java/se/leap/bitmaskclient/eip/GatewaysManager.java20
-rw-r--r--app/src/main/java/se/leap/bitmaskclient/eip/VpnNotificationManager.java3
6 files changed, 111 insertions, 35 deletions
diff --git a/app/src/main/java/se/leap/bitmaskclient/base/fragments/SettingsFragment.java b/app/src/main/java/se/leap/bitmaskclient/base/fragments/SettingsFragment.java
index be2fe4f4..f4531ff8 100644
--- a/app/src/main/java/se/leap/bitmaskclient/base/fragments/SettingsFragment.java
+++ b/app/src/main/java/se/leap/bitmaskclient/base/fragments/SettingsFragment.java
@@ -1,12 +1,35 @@
package se.leap.bitmaskclient.base.fragments;
+import static android.content.Context.MODE_PRIVATE;
+import static android.view.View.GONE;
+import static android.view.View.VISIBLE;
+import static se.leap.bitmaskclient.R.string.advanced_settings;
+import static se.leap.bitmaskclient.base.models.Constants.GATEWAY_PINNING;
+import static se.leap.bitmaskclient.base.models.Constants.PREFER_UDP;
+import static se.leap.bitmaskclient.base.models.Constants.SHARED_PREFERENCES;
+import static se.leap.bitmaskclient.base.models.Constants.USE_BRIDGES;
+import static se.leap.bitmaskclient.base.models.Constants.USE_IPv6_FIREWALL;
+import static se.leap.bitmaskclient.base.utils.PreferenceHelper.getPreferUDP;
+import static se.leap.bitmaskclient.base.utils.PreferenceHelper.getShowAlwaysOnDialog;
+import static se.leap.bitmaskclient.base.utils.PreferenceHelper.getUseBridges;
+import static se.leap.bitmaskclient.base.utils.PreferenceHelper.getUseSnowflake;
+import static se.leap.bitmaskclient.base.utils.PreferenceHelper.hasSnowflakePrefs;
+import static se.leap.bitmaskclient.base.utils.PreferenceHelper.preferUDP;
+import static se.leap.bitmaskclient.base.utils.PreferenceHelper.useBridges;
+import static se.leap.bitmaskclient.base.utils.PreferenceHelper.useSnowflake;
+import static se.leap.bitmaskclient.base.utils.ViewHelper.setActionBarTitle;
+
+import android.app.AlertDialog;
+import android.content.Context;
import android.content.Intent;
import android.content.SharedPreferences;
import android.os.Build;
import android.os.Bundle;
+import android.text.TextUtils;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
+import android.widget.EditText;
import android.widget.Toast;
import androidx.annotation.NonNull;
@@ -18,6 +41,7 @@ import androidx.fragment.app.FragmentTransaction;
import java.util.Set;
import de.blinkt.openvpn.core.VpnStatus;
+import se.leap.bitmaskclient.BuildConfig;
import se.leap.bitmaskclient.R;
import se.leap.bitmaskclient.base.FragmentManagerEnhanced;
import se.leap.bitmaskclient.base.MainActivity;
@@ -28,24 +52,6 @@ import se.leap.bitmaskclient.base.views.IconTextEntry;
import se.leap.bitmaskclient.eip.EipCommand;
import se.leap.bitmaskclient.firewall.FirewallManager;
-import static android.content.Context.MODE_PRIVATE;
-import static android.view.View.GONE;
-import static android.view.View.VISIBLE;
-import static se.leap.bitmaskclient.R.string.advanced_settings;
-import static se.leap.bitmaskclient.base.models.Constants.PREFER_UDP;
-import static se.leap.bitmaskclient.base.models.Constants.SHARED_PREFERENCES;
-import static se.leap.bitmaskclient.base.models.Constants.USE_BRIDGES;
-import static se.leap.bitmaskclient.base.models.Constants.USE_IPv6_FIREWALL;
-import static se.leap.bitmaskclient.base.utils.PreferenceHelper.getPreferUDP;
-import static se.leap.bitmaskclient.base.utils.PreferenceHelper.getShowAlwaysOnDialog;
-import static se.leap.bitmaskclient.base.utils.PreferenceHelper.getUseBridges;
-import static se.leap.bitmaskclient.base.utils.PreferenceHelper.getUseSnowflake;
-import static se.leap.bitmaskclient.base.utils.PreferenceHelper.hasSnowflakePrefs;
-import static se.leap.bitmaskclient.base.utils.PreferenceHelper.preferUDP;
-import static se.leap.bitmaskclient.base.utils.PreferenceHelper.useBridges;
-import static se.leap.bitmaskclient.base.utils.PreferenceHelper.useSnowflake;
-import static se.leap.bitmaskclient.base.utils.ViewHelper.setActionBarTitle;
-
public class SettingsFragment extends Fragment implements SharedPreferences.OnSharedPreferenceChangeListener {
private FirewallManager firewallManager;
@@ -74,6 +80,7 @@ public class SettingsFragment extends Fragment implements SharedPreferences.OnSh
initUseSnowflakeEntry(view);
initFirewallEntry(view);
initTetheringEntry(view);
+ initGatewayPinningEntry(view);
setActionBarTitle(this, advanced_settings);
return view;
}
@@ -207,6 +214,41 @@ public class SettingsFragment extends Fragment implements SharedPreferences.OnSh
});
}
+ private void initGatewayPinningEntry(View rootView) {
+ if (!BuildConfig.BUILD_TYPE.equals("debug")) {
+ return;
+ }
+ Context context = this.getContext();
+ if (context == null) {
+ return;
+ }
+ IconTextEntry gatewayPinning = rootView.findViewById(R.id.gateway_pinning);
+ String pinnedGateway = PreferenceHelper.getPinnedGateway(rootView.getContext());
+ gatewayPinning.setSubtitle(pinnedGateway != null ? pinnedGateway : "Connect to a specific Gateway for debugging purposes");
+
+ gatewayPinning.setOnClickListener(v -> {
+ EditText gatewayPinningEditText = new EditText(rootView.getContext());
+ gatewayPinningEditText.setText(pinnedGateway);
+ new AlertDialog.Builder(context)
+ .setTitle("Gateway Pinning")
+ .setMessage("Enter the domain name of the gateway")
+ .setView(gatewayPinningEditText)
+ .setPositiveButton(android.R.string.ok, (dialogInterface, i) -> {
+ if (gatewayPinningEditText.getText() != null) {
+ String editTextInput = gatewayPinningEditText.getText().toString();
+ if (!TextUtils.isEmpty(editTextInput)) {
+ PreferenceHelper.setPreferredCity(context, null);
+ PreferenceHelper.pinGateway(context, editTextInput);
+ } else {
+ PreferenceHelper.pinGateway(context, null);
+ }
+ }
+ })
+ .setNegativeButton(android.R.string.cancel, null)
+ .create().show();
+ });
+ }
+
public void showTetheringAlert() {
try {
@@ -245,6 +287,8 @@ public class SettingsFragment extends Fragment implements SharedPreferences.OnSh
initPreferUDPEntry(rootView);
} else if (key.equals(USE_IPv6_FIREWALL)) {
initFirewallEntry(getView());
+ } if (key.equals(GATEWAY_PINNING)) {
+ initGatewayPinningEntry(rootView);
}
}
diff --git a/app/src/main/java/se/leap/bitmaskclient/base/models/Constants.java b/app/src/main/java/se/leap/bitmaskclient/base/models/Constants.java
index 86b438f8..bde909ba 100644
--- a/app/src/main/java/se/leap/bitmaskclient/base/models/Constants.java
+++ b/app/src/main/java/se/leap/bitmaskclient/base/models/Constants.java
@@ -43,6 +43,7 @@ public interface Constants {
String PREFERRED_CITY = "preferred_city";
String USE_SNOWFLAKE = "use_snowflake";
String PREFER_UDP = "prefer_UDP";
+ String GATEWAY_PINNING = "gateway_pinning";
//////////////////////////////////////////////
diff --git a/app/src/main/java/se/leap/bitmaskclient/base/utils/ConfigHelper.java b/app/src/main/java/se/leap/bitmaskclient/base/utils/ConfigHelper.java
index 27943022..ca1261a8 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,6 +16,8 @@
*/
package se.leap.bitmaskclient.base.utils;
+import static se.leap.bitmaskclient.base.models.Constants.DEFAULT_BITMASK;
+
import android.content.Context;
import android.content.res.Resources;
import android.os.Build;
@@ -37,7 +39,6 @@ import java.security.KeyFactory;
import java.security.MessageDigest;
import java.security.NoSuchAlgorithmException;
import java.security.NoSuchProviderException;
-import java.security.cert.Certificate;
import java.security.cert.CertificateEncodingException;
import java.security.cert.CertificateException;
import java.security.cert.CertificateFactory;
@@ -47,7 +48,6 @@ import java.security.spec.InvalidKeySpecException;
import java.security.spec.PKCS8EncodedKeySpec;
import java.util.ArrayList;
import java.util.Calendar;
-import java.util.Collection;
import java.util.regex.Matcher;
import java.util.regex.Pattern;
@@ -55,20 +55,20 @@ import se.leap.bitmaskclient.BuildConfig;
import se.leap.bitmaskclient.R;
import se.leap.bitmaskclient.providersetup.ProviderAPI;
-import static se.leap.bitmaskclient.base.models.Constants.DEFAULT_BITMASK;
-
/**
* Stores constants, and implements auxiliary methods used across all Bitmask Android classes.
* Wraps BuildConfigFields for to support easier unit testing
*
* @author parmegv
* @author MeanderingCode
+ * @author cyberta
*/
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 {
@@ -103,23 +103,26 @@ public class ConfigHelper {
}
public static ArrayList<X509Certificate> parseX509CertificatesFromString(String certificateString) {
- Collection<? extends Certificate> certificates;
+ ArrayList<X509Certificate> certificates = new ArrayList<>();
CertificateFactory cf;
try {
cf = CertificateFactory.getInstance("X.509");
- certificateString = certificateString.replaceAll("-----BEGIN CERTIFICATE-----", "").trim().replaceAll("-----END CERTIFICATE-----", "").trim();
- byte[] certBytes = Base64.decode(certificateString);
- try (InputStream caInput = new ByteArrayInputStream(certBytes)) {
- certificates = cf.generateCertificates(caInput);
- if (certificates != null) {
- for (Certificate cert : certificates) {
- System.out.println("ca=" + ((X509Certificate) cert).getSubjectDN());
- }
- return (ArrayList<X509Certificate>) certificates;
+ Matcher matcher = PEM_CERTIFICATE_PATTERN.matcher(certificateString);
+ while (matcher.find()) {
+ String certificate = matcher.group(3);
+ if (certificate == null) continue;
+ byte[] certBytes = Base64.decode(certificate.trim());
+ try (InputStream caInput = new ByteArrayInputStream(certBytes)) {
+ X509Certificate x509certificate = (X509Certificate) cf.generateCertificate(caInput);
+ certificates.add(x509certificate);
+ System.out.println("ca=" + x509certificate.getSubjectDN() + ", SAN= " + x509certificate.getSubjectAlternativeNames());
+ } catch (IOException | CertificateException | NullPointerException | IllegalArgumentException | ClassCastException e) {
+ e.printStackTrace();
}
}
- } catch (NullPointerException | CertificateException | IOException | IllegalArgumentException | ClassCastException e) {
+ return certificates;
+ } catch (CertificateException e) {
e.printStackTrace();
}
diff --git a/app/src/main/java/se/leap/bitmaskclient/base/utils/PreferenceHelper.java b/app/src/main/java/se/leap/bitmaskclient/base/utils/PreferenceHelper.java
index fe9100cb..08bfbdc3 100644
--- a/app/src/main/java/se/leap/bitmaskclient/base/utils/PreferenceHelper.java
+++ b/app/src/main/java/se/leap/bitmaskclient/base/utils/PreferenceHelper.java
@@ -26,6 +26,7 @@ import static se.leap.bitmaskclient.base.models.Constants.ALLOW_TETHERING_WIFI;
import static se.leap.bitmaskclient.base.models.Constants.ALWAYS_ON_SHOW_DIALOG;
import static se.leap.bitmaskclient.base.models.Constants.DEFAULT_SHARED_PREFS_BATTERY_SAVER;
import static se.leap.bitmaskclient.base.models.Constants.EXCLUDED_APPS;
+import static se.leap.bitmaskclient.base.models.Constants.GATEWAY_PINNING;
import static se.leap.bitmaskclient.base.models.Constants.LAST_UPDATE_CHECK;
import static se.leap.bitmaskclient.base.models.Constants.LAST_USED_PROFILE;
import static se.leap.bitmaskclient.base.models.Constants.PREFERRED_CITY;
@@ -154,6 +155,14 @@ public class PreferenceHelper {
putBoolean(context, PREFER_UDP, prefer);
}
+ public static String getPinnedGateway(Context context) {
+ return getString(context, GATEWAY_PINNING, null);
+ }
+
+ public static void pinGateway(Context context, String value) {
+ putString(context, GATEWAY_PINNING, value);
+ }
+
public static boolean getUseBridges(SharedPreferences preferences) {
return preferences.getBoolean(USE_BRIDGES, false);
}
diff --git a/app/src/main/java/se/leap/bitmaskclient/eip/GatewaysManager.java b/app/src/main/java/se/leap/bitmaskclient/eip/GatewaysManager.java
index 76ec9650..a11c7e34 100644
--- a/app/src/main/java/se/leap/bitmaskclient/eip/GatewaysManager.java
+++ b/app/src/main/java/se/leap/bitmaskclient/eip/GatewaysManager.java
@@ -41,6 +41,7 @@ import de.blinkt.openvpn.core.ConfigParser;
import de.blinkt.openvpn.core.VpnStatus;
import de.blinkt.openvpn.core.connection.Connection;
import de.blinkt.openvpn.core.connection.Connection.TransportType;
+import se.leap.bitmaskclient.BuildConfig;
import se.leap.bitmaskclient.base.models.Location;
import se.leap.bitmaskclient.base.models.Provider;
import se.leap.bitmaskclient.base.models.ProviderObservable;
@@ -338,9 +339,11 @@ public class GatewaysManager {
if (gateways.get(aux.getHost()) == null) {
addGateway(aux);
}
- } catch (JSONException | ConfigParser.ConfigParseError | IOException e) {
+ } catch (JSONException | IOException e) {
e.printStackTrace();
VpnStatus.logError("Unable to parse gateway config!");
+ } catch (ConfigParser.ConfigParseError e) {
+ VpnStatus.logError("Unable to parse gateway config: " + e.getLocalizedMessage());
}
}
} catch (NullPointerException npe) {
@@ -419,6 +422,9 @@ public class GatewaysManager {
private void configureFromCurrentProvider() {
Provider provider = ProviderObservable.getInstance().getCurrentProvider();
parseDefaultGateways(provider);
+ if (BuildConfig.BUILD_TYPE.equals("debug") && handleGatewayPinning()) {
+ return;
+ }
if (hasSortedGatewaysWithLoad(provider)) {
parseGatewaysWithLoad(provider);
} else {
@@ -427,5 +433,17 @@ public class GatewaysManager {
}
+ private boolean handleGatewayPinning() {
+ String host = PreferenceHelper.getPinnedGateway(this.context);
+ if (host == null) {
+ return false;
+ }
+ Gateway gateway = gateways.get(host);
+ gateways.clear();
+ if (gateway != null) {
+ gateways.put(host, gateway);
+ }
+ return true;
+ }
}
diff --git a/app/src/main/java/se/leap/bitmaskclient/eip/VpnNotificationManager.java b/app/src/main/java/se/leap/bitmaskclient/eip/VpnNotificationManager.java
index d2603533..a869210e 100644
--- a/app/src/main/java/se/leap/bitmaskclient/eip/VpnNotificationManager.java
+++ b/app/src/main/java/se/leap/bitmaskclient/eip/VpnNotificationManager.java
@@ -196,7 +196,8 @@ public class VpnNotificationManager {
}
public void cancelAll() {
- compatNotificationManager.cancelAll();
+ compatNotificationManager.cancel(OpenVPNService.NOTIFICATION_CHANNEL_NEWSTATUS_ID.hashCode());
+ compatNotificationManager.cancel(VoidVpnService.NOTIFICATION_CHANNEL_NEWSTATUS_ID.hashCode());
}