diff --git a/app/src/custom/assets/riseup.net.json b/app/src/custom/assets/riseup.net.json index 5e14abc38413e5dc23b368e9b25c339a6fbc82a7..407e2e22dd404d0541e6f8601afc7904cb739867 100644 --- a/app/src/custom/assets/riseup.net.json +++ b/app/src/custom/assets/riseup.net.json @@ -1,37 +1,37 @@ { - "api_uri":"https://api.black.riseup.net:4430", - "api_version":"3", - "ca_cert_fingerprint":"SHA256: dd919b7513b4a1368faa20e38cd3314156805677f48b787cdd9b4a92dec64eb0", - "ca_cert_uri":"https://black.riseup.net/ca.crt", - "default_language":"en", - "description":{ - "en": "Riseup is a non-profit collective in Seattle that provides online communication tools for people and groups working toward liberatory social change." + "api_uri": "https://api.black.riseup.net:4430", + "api_version": "3", + "ca_cert_fingerprint": "SHA256: dd919b7513b4a1368faa20e38cd3314156805677f48b787cdd9b4a92dec64eb0", + "ca_cert_uri": "https://black.riseup.net/ca.crt", + "default_language": "en", + "description": { + "en": "Riseup Networks" }, - "domain":"riseup.net", - "enrollment_policy":"open", - "languages":[ + "domain": "riseup.net", + "enrollment_policy": "open", + "languages": [ "en" ], - "name":{ - "en":"Riseup Networks" + "name": { + "en": "Riseup Networks" }, - "service":{ - "allow_anonymous":true, - "allow_free":true, - "allow_limited_bandwidth":false, - "allow_paid":false, - "allow_registration":false, - "allow_unlimited_bandwidth":true, - "bandwidth_limit":102400, - "default_service_level":1, - "levels":{ - "1":{ - "description":"Please donate.", - "name":"free" + "service": { + "allow_anonymous": true, + "allow_free": true, + "allow_limited_bandwidth": false, + "allow_paid": false, + "allow_registration": false, + "allow_unlimited_bandwidth": true, + "bandwidth_limit": 102400, + "default_service_level": 1, + "levels": { + "1": { + "description": "Please donate.", + "name": "free" } } }, - "services":[ + "services": [ "openvpn" ] } \ No newline at end of file diff --git a/app/src/main/java/se/leap/bitmaskclient/base/fragments/CensorshipCircumventionFragment.java b/app/src/main/java/se/leap/bitmaskclient/base/fragments/CensorshipCircumventionFragment.java index 37f9eb18eac1517c4ef1b3c3c5c473c9c9f9a2df..e8789b32c7cda0526a3f4b60db700b037015138b 100644 --- a/app/src/main/java/se/leap/bitmaskclient/base/fragments/CensorshipCircumventionFragment.java +++ b/app/src/main/java/se/leap/bitmaskclient/base/fragments/CensorshipCircumventionFragment.java @@ -5,6 +5,7 @@ import static se.leap.bitmaskclient.base.utils.PreferenceHelper.getUseObfs4Kcp; import static se.leap.bitmaskclient.base.utils.PreferenceHelper.getUsePortHopping; 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.resetSnowflakeSettings; import static se.leap.bitmaskclient.base.utils.PreferenceHelper.setUsePortHopping; import static se.leap.bitmaskclient.base.utils.PreferenceHelper.setUseTunnel; import static se.leap.bitmaskclient.base.utils.PreferenceHelper.useBridges; @@ -29,11 +30,11 @@ import se.leap.bitmaskclient.databinding.FCensorshipCircumventionBinding; import se.leap.bitmaskclient.eip.EipCommand; public class CensorshipCircumventionFragment extends Fragment { - public static int DISCOVERY_NONE = 100200000; + public static int DISCOVERY_AUTOMATICALLY = 100200000; public static int DISCOVERY_SNOWFLAKE = 100200001; public static int DISCOVERY_INVITE_PROXY = 100200002; - public static int TUNNELING_NONE = 100300000; + public static int TUNNELING_AUTOMATICALLY = 100300000; public static int TUNNELING_OBFS4 = 100300001; public static int TUNNELING_OBFS4_KCP = 100300002; @@ -68,20 +69,20 @@ public class CensorshipCircumventionFragment extends Fragment { private void initDiscovery() { - - RadioButton noneRadioButton = new RadioButton(binding.getRoot().getContext()); - noneRadioButton.setText(getText(R.string.automatically_select)); - noneRadioButton.setId(DISCOVERY_NONE); - noneRadioButton.setChecked(!(hasSnowflakePrefs() && getUseSnowflake()) && !ProviderObservable.getInstance().getCurrentProvider().hasIntroducer()); - binding.discoveryRadioGroup.addView(noneRadioButton); + boolean hasIntroducer = ProviderObservable.getInstance().getCurrentProvider().hasIntroducer(); + RadioButton automaticallyRadioButton = new RadioButton(binding.getRoot().getContext()); + automaticallyRadioButton.setText(getText(R.string.automatically_select)); + automaticallyRadioButton.setId(DISCOVERY_AUTOMATICALLY); + automaticallyRadioButton.setChecked(!hasSnowflakePrefs() && !hasIntroducer); + binding.discoveryRadioGroup.addView(automaticallyRadioButton); RadioButton snowflakeRadioButton = new RadioButton(binding.getRoot().getContext()); snowflakeRadioButton.setText(getText(R.string.snowflake)); snowflakeRadioButton.setId(DISCOVERY_SNOWFLAKE); - snowflakeRadioButton.setChecked(hasSnowflakePrefs() && getUseSnowflake()); + snowflakeRadioButton.setChecked(!hasIntroducer && hasSnowflakePrefs() && getUseSnowflake()); binding.discoveryRadioGroup.addView(snowflakeRadioButton); - if (ProviderObservable.getInstance().getCurrentProvider().hasIntroducer()) { + if (hasIntroducer) { RadioButton inviteProxyRadioButton = new RadioButton(binding.getRoot().getContext()); inviteProxyRadioButton.setText(getText(R.string.invite_proxy)); inviteProxyRadioButton.setId(DISCOVERY_INVITE_PROXY); @@ -91,15 +92,13 @@ public class CensorshipCircumventionFragment extends Fragment { binding.discoveryRadioGroup.setOnCheckedChangeListener((group, checkedId) -> { useBridges(true); - if (checkedId == DISCOVERY_NONE) { - useSnowflake(false); + if (checkedId == DISCOVERY_AUTOMATICALLY) { + resetSnowflakeSettings(); } else if (checkedId == DISCOVERY_SNOWFLAKE) { useSnowflake(true); } else if (checkedId == DISCOVERY_INVITE_PROXY) { useSnowflake(false); } - - tryReconnectVpn(); }); } @@ -115,7 +114,7 @@ public class CensorshipCircumventionFragment extends Fragment { RadioButton noneRadioButton = new RadioButton(binding.getRoot().getContext()); noneRadioButton.setText(getText(R.string.automatically_select)); noneRadioButton.setChecked(!getUseObfs4() && !getUseObfs4Kcp()); - noneRadioButton.setId(TUNNELING_NONE); + noneRadioButton.setId(TUNNELING_AUTOMATICALLY); binding.tunnelingRadioGroup.addView(noneRadioButton); if (ProviderObservable.getInstance().getCurrentProvider().supportsObfs4()) { 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 eb777abc52384ec3d5352119ff42530158f922d7..4567bf9744cd50fb389a5d9199f3316e34cf30e7 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 @@ -3,7 +3,7 @@ package se.leap.bitmaskclient.base.fragments; 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.fragments.CensorshipCircumventionFragment.TUNNELING_NONE; +import static se.leap.bitmaskclient.base.fragments.CensorshipCircumventionFragment.TUNNELING_AUTOMATICALLY; 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.USE_BRIDGES; @@ -16,6 +16,7 @@ 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.preferUDP; +import static se.leap.bitmaskclient.base.utils.PreferenceHelper.resetSnowflakeSettings; import static se.leap.bitmaskclient.base.utils.PreferenceHelper.setAllowExperimentalTransports; import static se.leap.bitmaskclient.base.utils.PreferenceHelper.setUseObfuscationPinning; import static se.leap.bitmaskclient.base.utils.PreferenceHelper.setUsePortHopping; @@ -23,7 +24,7 @@ import static se.leap.bitmaskclient.base.utils.PreferenceHelper.setUseTunnel; import static se.leap.bitmaskclient.base.utils.PreferenceHelper.useBridges; import static se.leap.bitmaskclient.base.utils.PreferenceHelper.useObfuscationPinning; import static se.leap.bitmaskclient.base.utils.PreferenceHelper.useSnowflake; -import static se.leap.bitmaskclient.base.utils.PreferenceHelper.usesManualBridges; +import static se.leap.bitmaskclient.base.utils.PreferenceHelper.useManualBridgeSettings; import static se.leap.bitmaskclient.base.utils.ViewHelper.setActionBarSubtitle; import android.app.AlertDialog; @@ -37,10 +38,12 @@ import android.view.LayoutInflater; import android.view.View; import android.view.ViewGroup; import android.widget.EditText; +import android.widget.LinearLayout; import android.widget.Toast; import androidx.annotation.NonNull; import androidx.annotation.Nullable; +import androidx.appcompat.widget.AppCompatTextView; import androidx.appcompat.widget.SwitchCompat; import androidx.fragment.app.DialogFragment; import androidx.fragment.app.Fragment; @@ -94,43 +97,42 @@ public class SettingsFragment extends Fragment implements SharedPreferences.OnSh private void initAutomaticCircumventionEntry(View rootView) { IconSwitchEntry automaticCircumvention = rootView.findViewById(R.id.bridge_automatic_switch); - if (ProviderObservable.getInstance().getCurrentProvider().supportsPluggableTransports()) { - automaticCircumvention.setVisibility(VISIBLE); - - automaticCircumvention.setChecked(getUseBridges() && !usesManualBridges()); - automaticCircumvention.setOnCheckedChangeListener((buttonView, isChecked) -> { - if (!buttonView.isPressed()) { - return; - } + automaticCircumvention.setChecked(getUseBridges() && !useManualBridgeSettings()); + automaticCircumvention.setOnCheckedChangeListener((buttonView, isChecked) -> { + if (!buttonView.isPressed()) { + return; + } - if (isChecked) { - useSnowflake(false); - setUseTunnel(TUNNELING_NONE); - setUsePortHopping(false); - } + if (isChecked) { + resetSnowflakeSettings(); + setUseTunnel(TUNNELING_AUTOMATICALLY); + setUsePortHopping(false); + } else { + useSnowflake(false); + } + if (ProviderObservable.getInstance().getCurrentProvider().supportsPluggableTransports()) { useBridges(isChecked); if (VpnStatus.isVPNActive()) { EipCommand.startVPN(getContext(), false); Toast.makeText(getContext(), R.string.reconnecting, Toast.LENGTH_LONG).show(); } - }); + } + }); - //We check the UI state of the useUdpEntry here as well, in order to avoid a situation - //where both entries are disabled, because both preferences are enabled. - //bridges can be enabled not only from here but also from error handling - boolean useUDP = getPreferUDP() && useUdpEntry.isEnabled(); - automaticCircumvention.setEnabled(!useUDP); - automaticCircumvention.setSubtitle(getString(useUDP?R.string.disabled_while_udp_on:R.string.automatic_bridge_description)); - } else { - automaticCircumvention.setVisibility(GONE); - } + //We check the UI state of the useUdpEntry here as well, in order to avoid a situation + //where both entries are disabled, because both preferences are enabled. + //bridges can be enabled not only from here but also from error handling + boolean useUDP = getPreferUDP() && useUdpEntry.isEnabled(); + automaticCircumvention.setEnabled(!useUDP); + automaticCircumvention.setSubtitle(getString(useUDP ? R.string.disabled_while_udp_on : R.string.automatic_bridge_description)); } private void initManualCircumventionEntry(View rootView) { + LinearLayout manualConfigRoot = rootView.findViewById(R.id.bridge_manual_switch_entry); + manualConfigRoot.setVisibility(ProviderObservable.getInstance().getCurrentProvider().supportsPluggableTransports() ? VISIBLE : GONE); IconTextEntry manualConfiguration = rootView.findViewById(R.id.bridge_manual_switch); - manualConfiguration.setVisibility(ProviderObservable.getInstance().getCurrentProvider().supportsPluggableTransports() ? VISIBLE : GONE); SwitchCompat manualConfigurationSwitch = rootView.findViewById(R.id.bridge_manual_switch_control); - boolean usesManualBridge = usesManualBridges(); + boolean usesManualBridge = useManualBridgeSettings(); manualConfigurationSwitch.setChecked(usesManualBridge); manualConfigurationSwitch.setOnCheckedChangeListener((buttonView, isChecked) -> { if (!buttonView.isPressed()) { @@ -148,12 +150,12 @@ public class SettingsFragment extends Fragment implements SharedPreferences.OnSh //bridges can be enabled not only from here but also from error handling boolean useUDP = getPreferUDP() && useUdpEntry.isEnabled(); manualConfiguration.setEnabled(!useUDP); - manualConfiguration.setSubtitle(getString(useUDP? R.string.disabled_while_udp_on:R.string.manual_bridge_description)); + manualConfiguration.setSubtitle(getString(useUDP ? R.string.disabled_while_udp_on : R.string.manual_bridge_description)); } private void resetManualConfig() { useSnowflake(false); - setUseTunnel(TUNNELING_NONE); + setUseTunnel(TUNNELING_AUTOMATICALLY); setUsePortHopping(false); useBridges(false); if (VpnStatus.isVPNActive()) { 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 25a9a3fbbea4df61355bb67c24e903f101e0c9ef..b7c6db5d73991884e0d21bc0adf08e6adff21a13 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 @@ -1,7 +1,7 @@ package se.leap.bitmaskclient.base.utils; import static android.content.Context.MODE_PRIVATE; -import static se.leap.bitmaskclient.base.fragments.CensorshipCircumventionFragment.TUNNELING_NONE; +import static se.leap.bitmaskclient.base.fragments.CensorshipCircumventionFragment.TUNNELING_AUTOMATICALLY; import static se.leap.bitmaskclient.base.fragments.CensorshipCircumventionFragment.TUNNELING_OBFS4; import static se.leap.bitmaskclient.base.fragments.CensorshipCircumventionFragment.TUNNELING_OBFS4_KCP; import static se.leap.bitmaskclient.base.models.Constants.ALLOW_EXPERIMENTAL_TRANSPORTS; @@ -65,15 +65,13 @@ import androidx.annotation.WorkerThread; import androidx.security.crypto.EncryptedSharedPreferences; import androidx.security.crypto.MasterKey; -import com.google.gson.Gson; - import org.json.JSONException; import org.json.JSONObject; import java.io.IOException; -import java.net.MalformedURLException; import java.net.URL; import java.security.GeneralSecurityException; +import java.util.Arrays; import java.util.HashMap; import java.util.HashSet; import java.util.Map; @@ -81,9 +79,6 @@ import java.util.Set; import de.blinkt.openvpn.VpnProfile; import de.blinkt.openvpn.core.NativeUtils; -import io.swagger.client.JSON; -import mobile.BitmaskMobile; -import mobilemodels.BitmaskMobileCore; import se.leap.bitmaskclient.BuildConfig; import se.leap.bitmaskclient.base.models.Introducer; import se.leap.bitmaskclient.base.models.Provider; @@ -218,20 +213,17 @@ public class PreferenceHelper { public static HashMap<String, Provider> getCustomProviders() { Set<String> providerDomains = getCustomProviderDomains(); HashMap<String, Provider> customProviders = new HashMap<>(); - if (providerDomains.size() > 0) { - for (String domain : providerDomains) { - String mainURL = preferences.getString(Provider.MAIN_URL + "." + domain, null); - if (mainURL != null) { - Introducer introducer = null; - try { - introducer = Introducer.fromUrl(BitmaskCoreProvider.getBitmaskMobile().getIntroducerURLByDomain(domain)); - } catch (Exception e) { - e.printStackTrace(); - } - customProviders.put(mainURL, Provider.createCustomProvider(mainURL, domain, introducer)); + for (String domain : providerDomains) { + String mainURL = preferences.getString(Provider.MAIN_URL + "." + domain, null); + if (mainURL != null) { + Introducer introducer = null; + try { + introducer = Introducer.fromUrl(BitmaskCoreProvider.getBitmaskMobile().getIntroducerURLByDomain(domain)); + } catch (Exception e) { + e.printStackTrace(); } + customProviders.put(mainURL, Provider.createCustomProvider(mainURL, domain, introducer)); } - } return customProviders; @@ -491,6 +483,10 @@ public class PreferenceHelper { return hasKey(USE_SNOWFLAKE); } + public static void resetSnowflakeSettings() { + removeKey(USE_SNOWFLAKE); + } + public static Boolean getUseSnowflake() { return getBoolean(USE_SNOWFLAKE, true); } @@ -619,12 +615,8 @@ public class PreferenceHelper { return getUseTunnel() == TUNNELING_OBFS4_KCP; } - public static boolean usesManualBridges(){ - return getUseSnowflake() || usesSpecificTunnel() || getUsePortHopping(); - } - - public static boolean usesSpecificTunnel() { - return getUseObfs4() || getUseObfs4Kcp(); + public static boolean useManualBridgeSettings(){ + return (hasSnowflakePrefs() && getUseSnowflake()) || getUseObfs4() || getUseObfs4Kcp() || getUsePortHopping(); } public static void setUseTunnel(int tunnel) { @@ -632,7 +624,7 @@ public class PreferenceHelper { } public static int getUseTunnel() { - return getInt(USE_TUNNEL, TUNNELING_NONE); + return getInt(USE_TUNNEL, TUNNELING_AUTOMATICALLY); } public static boolean useIpv6Firewall() { @@ -709,6 +701,12 @@ public class PreferenceHelper { } } + public static void removeKey(String key) { + synchronized (LOCK) { + preferences.edit().remove(key).apply(); + } + } + public static long getLong(String key, long defValue) { synchronized (LOCK) { return preferences.getLong(key, defValue); @@ -851,7 +849,7 @@ public class PreferenceHelper { @Override public byte[] getByteArray(String s) { - String encodedString = preferences.getString(s, ""); + String encodedString = preferences.getString(s, Arrays.toString(Base64.encode(new byte[0], Base64.DEFAULT))); try { return Base64.decode(encodedString, Base64.DEFAULT); } catch (IllegalArgumentException e) { 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 d7f3b42ea7357741ffd86de7237d66e02954b5b2..9655013c600a4fa5f3721e0b1ede34ef5ac09e85 100644 --- a/app/src/main/java/se/leap/bitmaskclient/eip/GatewaysManager.java +++ b/app/src/main/java/se/leap/bitmaskclient/eip/GatewaysManager.java @@ -37,7 +37,6 @@ import static se.leap.bitmaskclient.base.utils.PreferenceHelper.getUseBridges; import static se.leap.bitmaskclient.base.utils.PreferenceHelper.getUseObfs4; import static se.leap.bitmaskclient.base.utils.PreferenceHelper.getUseObfs4Kcp; import static se.leap.bitmaskclient.base.utils.PreferenceHelper.getUsePortHopping; -import static se.leap.bitmaskclient.base.utils.PreferenceHelper.usesSpecificTunnel; import android.content.Context; import android.util.Log; @@ -54,10 +53,8 @@ import org.json.JSONObject; import java.io.IOException; import java.lang.reflect.Type; import java.util.ArrayList; -import java.util.Arrays; import java.util.Collections; import java.util.HashMap; -import java.util.HashSet; import java.util.LinkedHashMap; import java.util.List; import java.util.Set; diff --git a/app/src/main/java/se/leap/bitmaskclient/providersetup/ProviderApiManagerV5.java b/app/src/main/java/se/leap/bitmaskclient/providersetup/ProviderApiManagerV5.java index 9af14eda4e83566c746b90bee7a32ad74101b1a8..2e2497d515347ad0431388984d611aa94af02ead 100644 --- a/app/src/main/java/se/leap/bitmaskclient/providersetup/ProviderApiManagerV5.java +++ b/app/src/main/java/se/leap/bitmaskclient/providersetup/ProviderApiManagerV5.java @@ -66,6 +66,7 @@ public class ProviderApiManagerV5 extends ProviderApiManagerBase implements IPro case SET_UP_PROVIDER: result = setupProvider(provider, parameters); if (result.getBoolean(BROADCAST_RESULT_KEY)) { + serviceCallback.saveProvider(provider); eventSender.sendToReceiverOrBroadcast(receiver, PROVIDER_OK, result, provider); } else { eventSender.sendToReceiverOrBroadcast(receiver, PROVIDER_NOK, result, provider); diff --git a/app/src/main/java/se/leap/bitmaskclient/providersetup/ProviderManager.java b/app/src/main/java/se/leap/bitmaskclient/providersetup/ProviderManager.java index 63fbde09e06d82af063ed622d7ead5e93b98bc6b..bcb177e2bf32043645d2f38a217fcf574b526cd6 100644 --- a/app/src/main/java/se/leap/bitmaskclient/providersetup/ProviderManager.java +++ b/app/src/main/java/se/leap/bitmaskclient/providersetup/ProviderManager.java @@ -45,8 +45,11 @@ public class ProviderManager { private boolean addDummyEntry = false; public static ProviderManager getInstance(AssetManager assetsManager) { - if (instance == null) + if (instance == null) { instance = new ProviderManager(assetsManager); + } else { + instance.updateCustomProviders(); + } return instance; } @@ -63,7 +66,7 @@ public class ProviderManager { private ProviderManager(AssetManager assetManager) { this.assetsManager = assetManager; addDefaultProviders(assetManager); - addCustomProviders(); + updateCustomProviders(); } private void addDefaultProviders(AssetManager assetManager) { @@ -117,7 +120,7 @@ public class ProviderManager { } - private void addCustomProviders() { + public void updateCustomProviders() { customProviders = PreferenceHelper.getCustomProviders(); } 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 58fccc6511d989141bd3599cf388dafc1439acf5..d7d8516eb822ac808d090e3687ecfc68cbaca3d2 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,5 +1,6 @@ package se.leap.bitmaskclient.providersetup.fragments; +import static se.leap.bitmaskclient.base.fragments.CensorshipCircumventionFragment.TUNNELING_AUTOMATICALLY; import static se.leap.bitmaskclient.base.utils.BuildConfigHelper.isDefaultBitmask; import android.graphics.Typeface; @@ -35,14 +36,17 @@ public class CircumventionSetupFragment extends BaseSetupFragment implements Can if (binding.rbCircumvention.getId() == checkedId) { PreferenceHelper.useBridges(true); PreferenceHelper.useSnowflake(true); + PreferenceHelper.setUseTunnel(TUNNELING_AUTOMATICALLY); binding.tvCircumventionDetailDescription.setVisibility(View.VISIBLE); binding.rbCircumvention.setTypeface(Typeface.DEFAULT, Typeface.BOLD); binding.rbPlainVpn.setTypeface(Typeface.DEFAULT, Typeface.NORMAL); return; } - + // otherwise don't use obfuscation PreferenceHelper.useBridges(false); - PreferenceHelper.useSnowflake(false); + PreferenceHelper.resetSnowflakeSettings(); + PreferenceHelper.setUsePortHopping(false); + PreferenceHelper.setUseTunnel(TUNNELING_AUTOMATICALLY); binding.tvCircumventionDetailDescription.setVisibility(View.GONE); binding.rbPlainVpn.setTypeface(Typeface.DEFAULT, Typeface.BOLD); binding.rbCircumvention.setTypeface(Typeface.DEFAULT, Typeface.NORMAL); 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 8b4b7ad8b7e51fdf4073b49cbef87bb82f8724df..b9051b1e28b38cae5a8f96a048e272153c3cfa76 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 @@ -7,11 +7,16 @@ import static androidx.recyclerview.widget.RecyclerView.SCROLL_STATE_IDLE; import static se.leap.bitmaskclient.R.string.app_name; import static se.leap.bitmaskclient.R.string.description_configure_provider; import static se.leap.bitmaskclient.R.string.description_configure_provider_circumvention; +import static se.leap.bitmaskclient.base.fragments.CensorshipCircumventionFragment.TUNNELING_AUTOMATICALLY; 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.BuildConfigHelper.isDefaultBitmask; 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.setUsePortHopping; +import static se.leap.bitmaskclient.base.utils.PreferenceHelper.setUseTunnel; +import static se.leap.bitmaskclient.base.utils.PreferenceHelper.useSnowflake; import static se.leap.bitmaskclient.base.utils.ViewHelper.animateContainerVisibility; import static se.leap.bitmaskclient.providersetup.ProviderAPI.CORRECTLY_DOWNLOADED_VPN_CERTIFICATE; import static se.leap.bitmaskclient.providersetup.ProviderAPI.DOWNLOAD_VPN_CERTIFICATE; @@ -48,6 +53,7 @@ import java.beans.PropertyChangeEvent; import java.beans.PropertyChangeListener; import java.util.List; +import de.blinkt.openvpn.core.VpnStatus; import se.leap.bitmaskclient.R; import se.leap.bitmaskclient.base.models.Constants; import se.leap.bitmaskclient.base.models.Provider; @@ -126,7 +132,7 @@ public class ConfigureProviderFragment extends BaseSetupFragment implements Prop public void onFragmentSelected() { super.onFragmentSelected(); ignoreProviderAPIUpdates = false; - binding.detailContainer.setVisibility(getUseSnowflake() ? VISIBLE : GONE); + binding.detailContainer.setVisibility(!VpnStatus.isVPNActive() && hasSnowflakePrefs() && getUseSnowflake() ? VISIBLE : GONE); binding.tvCircumventionDescription.setText(getUseSnowflake() ? getString(description_configure_provider_circumvention, getString(app_name)) : getString(description_configure_provider, getString(app_name))); if (!isDefaultBitmask()) { Drawable drawable = ResourcesCompat.getDrawable(getResources(), R.drawable.setup_progress_spinner, null); @@ -138,6 +144,14 @@ public class ConfigureProviderFragment extends BaseSetupFragment implements Prop if (ProviderSetupObservable.isSetupRunning()) { handleResult(ProviderSetupObservable.getResultCode(), ProviderSetupObservable.getResultData(), true); } else { + Provider provider = setupActivityCallback.getSelectedProvider(); + if (provider != null && provider.hasIntroducer()) { + // enable automatic selection of bridges + useSnowflake(false); + setUseTunnel(TUNNELING_AUTOMATICALLY); + setUsePortHopping(false); + PreferenceHelper.useBridges(true); + } ProviderSetupObservable.startSetup(); Bundle parameters = new Bundle(); parameters.putString(Constants.COUNTRYCODE, PreferenceHelper.getBaseCountry()); diff --git a/app/src/main/java/se/leap/bitmaskclient/providersetup/fragments/ProviderSelectionFragment.java b/app/src/main/java/se/leap/bitmaskclient/providersetup/fragments/ProviderSelectionFragment.java index 66b1dd0064e9a8fc169331e9ced8262066c54b12..823004b2391600f6ea89cf0c6fcb64e4fb205ab1 100644 --- a/app/src/main/java/se/leap/bitmaskclient/providersetup/fragments/ProviderSelectionFragment.java +++ b/app/src/main/java/se/leap/bitmaskclient/providersetup/fragments/ProviderSelectionFragment.java @@ -75,6 +75,7 @@ public class ProviderSelectionFragment extends BaseSetupFragment implements Canc binding = FProviderSelectionBinding.inflate(inflater, container, false); radioButtons = new ArrayList<>(); + // add configured providers for (int i = 0; i < viewModel.size(); i++) { RadioButton radioButton = new RadioButton(binding.getRoot().getContext()); radioButton.setText(viewModel.getProviderName(i)); @@ -83,13 +84,14 @@ public class ProviderSelectionFragment extends BaseSetupFragment implements Canc radioButtons.add(radioButton); } + // add new provider entry RadioButton addProviderRadioButton = new RadioButton(binding.getRoot().getContext()); addProviderRadioButton.setText(getText(R.string.add_provider)); addProviderRadioButton.setId(ADD_PROVIDER); binding.providerRadioGroup.addView(addProviderRadioButton); radioButtons.add(addProviderRadioButton); - + // invite code entry RadioButton inviteCodeRadioButton = new RadioButton(binding.getRoot().getContext()); inviteCodeRadioButton.setText(R.string.enter_invite_code); inviteCodeRadioButton.setId(INVITE_CODE_PROVIDER); diff --git a/app/src/main/res/layout/f_settings.xml b/app/src/main/res/layout/f_settings.xml index e7b4356f92e79f2b6fa5c63ecf5ace924d123c7f..87a97455352ec7a9db5e37d0a6c3f55f2fa8033f 100644 --- a/app/src/main/res/layout/f_settings.xml +++ b/app/src/main/res/layout/f_settings.xml @@ -60,9 +60,11 @@ app:text="@string/automatic_bridge" app:subtitle="@string/automatic_bridge_description" app:icon="@drawable/bridge_automatic" + android:visibility="visible" app:singleLine="false" /> <LinearLayout + android:id="@+id/bridge_manual_switch_entry" android:layout_width="wrap_content" android:layout_height="wrap_content" android:orientation="horizontal"> diff --git a/app/src/main/res/values/strings.xml b/app/src/main/res/values/strings.xml index 57da5bf2ac1e15b8f92128fd0673eeb0f340d766..6351ade7835f2dcbd17699b2ff7992ac6dc1a391 100644 --- a/app/src/main/res/values/strings.xml +++ b/app/src/main/res/values/strings.xml @@ -250,7 +250,7 @@ <string name="scan_qr_code">Scan QR Code</string> <string name="invalid_code">Invalid code</string> <string name="automatic_bridge">Automatic (recommended)</string> - <string name="automatic_bridge_description">Connection wil be attemptd using the best available birdges and protocols.</string> + <string name="automatic_bridge_description">Connection will be attempted using the best available bridges and protocols.</string> <string name="manual_bridge">Manual Configuration</string> <string name="manual_bridge_description">Select private bridges and specific protocols</string> <string name="censorship_circumvention_description">Manual configuration requires technical understanding. Proceed with caution.</string> diff --git a/app/src/normal/assets/riseup.net.json b/app/src/normal/assets/riseup.net.json index 5e14abc38413e5dc23b368e9b25c339a6fbc82a7..407e2e22dd404d0541e6f8601afc7904cb739867 100644 --- a/app/src/normal/assets/riseup.net.json +++ b/app/src/normal/assets/riseup.net.json @@ -1,37 +1,37 @@ { - "api_uri":"https://api.black.riseup.net:4430", - "api_version":"3", - "ca_cert_fingerprint":"SHA256: dd919b7513b4a1368faa20e38cd3314156805677f48b787cdd9b4a92dec64eb0", - "ca_cert_uri":"https://black.riseup.net/ca.crt", - "default_language":"en", - "description":{ - "en": "Riseup is a non-profit collective in Seattle that provides online communication tools for people and groups working toward liberatory social change." + "api_uri": "https://api.black.riseup.net:4430", + "api_version": "3", + "ca_cert_fingerprint": "SHA256: dd919b7513b4a1368faa20e38cd3314156805677f48b787cdd9b4a92dec64eb0", + "ca_cert_uri": "https://black.riseup.net/ca.crt", + "default_language": "en", + "description": { + "en": "Riseup Networks" }, - "domain":"riseup.net", - "enrollment_policy":"open", - "languages":[ + "domain": "riseup.net", + "enrollment_policy": "open", + "languages": [ "en" ], - "name":{ - "en":"Riseup Networks" + "name": { + "en": "Riseup Networks" }, - "service":{ - "allow_anonymous":true, - "allow_free":true, - "allow_limited_bandwidth":false, - "allow_paid":false, - "allow_registration":false, - "allow_unlimited_bandwidth":true, - "bandwidth_limit":102400, - "default_service_level":1, - "levels":{ - "1":{ - "description":"Please donate.", - "name":"free" + "service": { + "allow_anonymous": true, + "allow_free": true, + "allow_limited_bandwidth": false, + "allow_paid": false, + "allow_registration": false, + "allow_unlimited_bandwidth": true, + "bandwidth_limit": 102400, + "default_service_level": 1, + "levels": { + "1": { + "description": "Please donate.", + "name": "free" } } }, - "services":[ + "services": [ "openvpn" ] } \ No newline at end of file diff --git a/app/src/normalProductionFatDebug/assets/demo.bitmask.net.json b/app/src/normalProductionFatDebug/assets/demo.bitmask.net.json deleted file mode 100644 index f5998c9bd6400807d1b38a371a38a65cb0eaeb62..0000000000000000000000000000000000000000 --- a/app/src/normalProductionFatDebug/assets/demo.bitmask.net.json +++ /dev/null @@ -1,37 +0,0 @@ -{ - "api_uri":"https://api.demo.bitmask.net:4430", - "api_version":"3", - "ca_cert_fingerprint":"SHA256: 40ed9d9c13872c1fcba25abdcf26a7b1bdeded433d74fbe1ccb58fbaaab58e23", - "ca_cert_uri":"https://api.demo.bitmask.net/ca.crt", - "default_language":"en", - "description":{ - "en":"This is a demo provider" - }, - "domain":"demo.bitmask.net", - "enrollment_policy":"open", - "languages":[ - "en" - ], - "name":{ - "en":"Demo provider" - }, - "service":{ - "allow_anonymous":true, - "allow_free":true, - "allow_limited_bandwidth":false, - "allow_paid":false, - "allow_registration":false, - "allow_unlimited_bandwidth":true, - "bandwidth_limit":102400, - "default_service_level":1, - "levels":{ - "1":{ - "description":"Please donate.", - "name":"free" - } - } - }, - "services":[ - "openvpn" - ] -} \ No newline at end of file diff --git a/app/src/normalProductionFatDebug/assets/demo.bitmask.net.pem b/app/src/normalProductionFatDebug/assets/demo.bitmask.net.pem deleted file mode 100644 index f1ede7ab4593149f590890a691dcd99bc5403801..0000000000000000000000000000000000000000 --- a/app/src/normalProductionFatDebug/assets/demo.bitmask.net.pem +++ /dev/null @@ -1,10 +0,0 @@ ------BEGIN CERTIFICATE----- -MIIBYTCCAQigAwIBAgIBATAKBggqhkjOPQQDAjAXMRUwEwYDVQQDEwxMRUFQIFJv -b3QgQ0EwHhcNMjQwMjIxMTEzMTUwWhcNMjkwMjIxMTEzNjUwWjAXMRUwEwYDVQQD -EwxMRUFQIFJvb3QgQ0EwWTATBgcqhkjOPQIBBggqhkjOPQMBBwNCAARKTm8AKkqK -aMI7dEarRRGEOPa3i49YE4bGNHxO97h14urXOROJWjnwHJdJ3dJk16oR0HKohXR7 -jSxyukoonJkgo0UwQzAOBgNVHQ8BAf8EBAMCAqQwEgYDVR0TAQH/BAgwBgEB/wIB -ATAdBgNVHQ4EFgQUMVywfKRY9Ec3n98PVIEu7kyWKHwwCgYIKoZIzj0EAwIDRwAw -RAIgeSMNJ51+EvNJzqsISauhOTbFxiUnnmV2z/+dxYeCPzUCIEMXM/X2ekzHEz6V -l7zSfosiYvtQQL3ML3sLnVMmxdmd ------END CERTIFICATE----- \ No newline at end of file diff --git a/app/src/normalProductionFatDebug/assets/urls/demo.bitmask.net.url b/app/src/normalProductionFatDebug/assets/urls/demo.bitmask.net.url deleted file mode 100644 index 459d6d10bad74854c8248f01987028269c994d2b..0000000000000000000000000000000000000000 --- a/app/src/normalProductionFatDebug/assets/urls/demo.bitmask.net.url +++ /dev/null @@ -1,4 +0,0 @@ -{ - "main_url" : "https://demo.bitmask.net", - "geoip_url" : "https://menshen.demo.bitmask.net/json" -} diff --git a/bitmask-core-android b/bitmask-core-android index 8b802cc791d1d913c03fe57c251d3eb40a6a59a2..46b7f48299017d7851f8a16ff395dcac9792df97 160000 --- a/bitmask-core-android +++ b/bitmask-core-android @@ -1 +1 @@ -Subproject commit 8b802cc791d1d913c03fe57c251d3eb40a6a59a2 +Subproject commit 46b7f48299017d7851f8a16ff395dcac9792df97