diff options
author | cyBerta <cyberta@riseup.net> | 2024-02-26 21:33:52 +0100 |
---|---|---|
committer | cyBerta <cyberta@riseup.net> | 2024-02-26 21:33:52 +0100 |
commit | 5b07bb3df03cc95d6b50a8eec2bd30563a6d5b43 (patch) | |
tree | 3737978877d4779221680e4591d792fc795796a3 /app/src/main | |
parent | 2522e75f41b2bc2f3d21baee09338527f271ba7c (diff) |
save manually added providers in encrypted shared preferences instead of external files dir
Diffstat (limited to 'app/src/main')
9 files changed, 82 insertions, 127 deletions
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 18590f0b..754491f8 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 @@ -53,6 +53,7 @@ public interface Constants { String OBFUSCATION_PINNING_KCP = "obfuscation_pinning_udp"; String OBFUSCATION_PINNING_LOCATION = "obfuscation_pinning_location"; String USE_SYSTEM_PROXY = "usesystemproxy"; + String CUSTOM_PROVIDER_DOMAINS = "custom_provider_domains"; ////////////////////////////////////////////// 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 6dfe0861..34082bcb 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 @@ -15,30 +15,6 @@ import de.blinkt.openvpn.core.NativeUtils; */ 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 instance.getInputStreamFrom(filePath); - } public static String loadInputStreamAsString(InputStream is) { java.util.Scanner s = new java.util.Scanner(is).useDelimiter("\\A"); 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 2420a797..eee3bfb2 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 @@ -7,6 +7,7 @@ import static se.leap.bitmaskclient.base.models.Constants.ALLOW_TETHERING_USB; 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.CLEARLOG; +import static se.leap.bitmaskclient.base.models.Constants.CUSTOM_PROVIDER_DOMAINS; import static se.leap.bitmaskclient.base.models.Constants.DEFAULT_SHARED_PREFS_BATTERY_SAVER; import static se.leap.bitmaskclient.base.models.Constants.EIP_IS_ALWAYS_ON; import static se.leap.bitmaskclient.base.models.Constants.EIP_RESTART_ON_BOOT; @@ -59,6 +60,7 @@ import java.io.IOException; import java.net.MalformedURLException; import java.net.URL; import java.security.GeneralSecurityException; +import java.util.HashMap; import java.util.HashSet; import java.util.Map; import java.util.Set; @@ -185,8 +187,49 @@ public class PreferenceHelper { } } + /** + * + * @return HashMap with main URL string as key and Provider as value + */ + public static HashMap<String, Provider> getCustomProviders() { + Set<String> providerDomains = getCustomProviderDomains(); + HashMap<String, Provider> customProviders = new HashMap<>(); + for (String domain : providerDomains) { + String mainURL = preferences.getString(Provider.MAIN_URL + "." + domain, null); + if (mainURL != null) { + customProviders.put(mainURL, Provider.createCustomProvider(mainURL, domain)); + } + } + return customProviders; + } + + public static void setCustomProviders(Set<Provider> providers) { + Set<String> newProviderDomains = new HashSet<>(); + + // add + SharedPreferences.Editor editor = preferences.edit(); + for (Provider provider : providers) { + String providerDomain = provider.getDomain(); + editor.putString(Provider.MAIN_URL + "." + providerDomain, provider.getMainUrlString()); + newProviderDomains.add(providerDomain); + } + + // remove + Set<String> removedProviderDomains = getCustomProviderDomains(); + removedProviderDomains.removeAll(newProviderDomains); + for (String providerDomain : removedProviderDomains) { + editor.remove(Provider.MAIN_URL + "." + providerDomain); + } + + editor.putStringSet(CUSTOM_PROVIDER_DOMAINS, newProviderDomains); + editor.apply(); + } + + static Set<String> getCustomProviderDomains() { + return preferences.getStringSet(CUSTOM_PROVIDER_DOMAINS, new HashSet<>()); + } + // TODO: replace commit with apply after refactoring EIP - //FIXME: don't save private keys in shared preferences! use the keystore public static void storeProviderInPreferences(Provider provider, boolean async) { synchronized (LOCK) { SharedPreferences.Editor editor = preferences.edit(); diff --git a/app/src/main/java/se/leap/bitmaskclient/providersetup/ProviderAPI.java b/app/src/main/java/se/leap/bitmaskclient/providersetup/ProviderAPI.java index bb6f5e01..68699da2 100644 --- a/app/src/main/java/se/leap/bitmaskclient/providersetup/ProviderAPI.java +++ b/app/src/main/java/se/leap/bitmaskclient/providersetup/ProviderAPI.java @@ -31,7 +31,6 @@ import androidx.localbroadcastmanager.content.LocalBroadcastManager; import java.util.concurrent.TimeoutException; import se.leap.bitmaskclient.base.models.Provider; -import se.leap.bitmaskclient.base.utils.PreferenceHelper; import se.leap.bitmaskclient.providersetup.connectivity.OkHttpClientGenerator; import se.leap.bitmaskclient.tor.TorServiceCommand; @@ -180,9 +179,9 @@ public class ProviderAPI extends JobIntentService implements ProviderApiManagerB @Override public void saveProvider(Provider p) { - ProviderManager pm = ProviderManager.getInstance(this.getAssets(), this.getExternalFilesDir(null)); + ProviderManager pm = ProviderManager.getInstance(this.getAssets()); pm.add(p); - pm.saveCustomProvidersToFile(); + pm.saveCustomProviders(); } 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 39f117ea..9eacae5d 100644 --- a/app/src/main/java/se/leap/bitmaskclient/providersetup/ProviderManager.java +++ b/app/src/main/java/se/leap/bitmaskclient/providersetup/ProviderManager.java @@ -3,15 +3,11 @@ package se.leap.bitmaskclient.providersetup; import static se.leap.bitmaskclient.base.models.Constants.EXT_JSON; import static se.leap.bitmaskclient.base.models.Constants.EXT_PEM; import static se.leap.bitmaskclient.base.models.Constants.URLS; -import static se.leap.bitmaskclient.base.models.Provider.DOMAIN; import static se.leap.bitmaskclient.base.models.Provider.GEOIP_URL; import static se.leap.bitmaskclient.base.models.Provider.MAIN_URL; import static se.leap.bitmaskclient.base.models.Provider.MOTD_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.FileHelper.createFile; -import static se.leap.bitmaskclient.base.utils.FileHelper.persistFile; -import static se.leap.bitmaskclient.base.utils.InputStreamHelper.getInputStreamFrom; import static se.leap.bitmaskclient.base.utils.InputStreamHelper.inputStreamToJson; import static se.leap.bitmaskclient.base.utils.InputStreamHelper.loadInputStreamAsString; @@ -21,18 +17,18 @@ import androidx.annotation.VisibleForTesting; import org.json.JSONObject; -import java.io.File; -import java.io.FileNotFoundException; import java.io.IOException; import java.io.InputStream; import java.util.ArrayList; import java.util.Collection; +import java.util.HashMap; import java.util.HashSet; import java.util.Iterator; import java.util.List; import java.util.Set; import se.leap.bitmaskclient.base.models.Provider; +import se.leap.bitmaskclient.base.utils.PreferenceHelper; /** * Created by parmegv on 4/12/14. @@ -40,18 +36,17 @@ import se.leap.bitmaskclient.base.models.Provider; public class ProviderManager { private final AssetManager assetsManager; - private File externalFilesDir; private Set<Provider> defaultProviders; - private Set<Provider> customProviders; + // key: MainURL String, value: Provider + private HashMap<String, Provider> customProviders; private Set<String> defaultProviderURLs; - private Set<String> customProviderURLs; private static ProviderManager instance; private boolean addDummyEntry = false; - public static ProviderManager getInstance(AssetManager assetsManager, File externalFilesDir) { + public static ProviderManager getInstance(AssetManager assetsManager) { if (instance == null) - instance = new ProviderManager(assetsManager, externalFilesDir); + instance = new ProviderManager(assetsManager); return instance; } @@ -65,10 +60,10 @@ public class ProviderManager { this.addDummyEntry = addDummyEntry; } - private ProviderManager(AssetManager assetManager, File externalFilesDir) { + private ProviderManager(AssetManager assetManager) { this.assetsManager = assetManager; addDefaultProviders(assetManager); - addCustomProviders(externalFilesDir); + addCustomProviders(); } private void addDefaultProviders(AssetManager assetManager) { @@ -122,29 +117,8 @@ public class ProviderManager { } - private void addCustomProviders(File externalFilesDir) { - this.externalFilesDir = externalFilesDir; - customProviders = externalFilesDir != null && externalFilesDir.isDirectory() ? - customProvidersFromFiles(externalFilesDir.list()) : - new HashSet<>(); - customProviderURLs = getProviderUrlSetFromProviderSet(customProviders); - } - - private Set<Provider> customProvidersFromFiles(String[] files) { - Set<Provider> providers = new HashSet<>(); - try { - for (String file : files) { - InputStream inputStream = getInputStreamFrom(externalFilesDir.getAbsolutePath() + "/" + file); - JSONObject providerConfig = inputStreamToJson(inputStream); - String mainUrl = providerConfig.optString(MAIN_URL); - String domain = providerConfig.optString(DOMAIN); - providers.add(Provider.createCustomProvider(mainUrl, domain)); - } - } catch (FileNotFoundException | NullPointerException e) { - e.printStackTrace(); - } - - return providers; + private void addCustomProviders() { + customProviders = PreferenceHelper.getCustomProviders(); } public List<Provider> providers() { @@ -155,7 +129,7 @@ public class ProviderManager { List<Provider> allProviders = new ArrayList<>(); allProviders.addAll(defaultProviders); if(customProviders != null) - allProviders.addAll(customProviders); + allProviders.addAll(customProviders.values()); if (addEmptyProvider) { //add an option to add a custom provider allProviders.add(new Provider()); @@ -177,16 +151,19 @@ public class ProviderManager { } public boolean add(Provider element) { - return element != null && - !defaultProviderURLs.contains(element.getMainUrl().toString()) && - customProviders.add(element) && - customProviderURLs.add(element.getMainUrl().toString()); + boolean addElement = element != null && + !defaultProviderURLs.contains(element.getMainUrlString()) && + !customProviders.containsKey(element.getMainUrlString()); + if (addElement) { + customProviders.put(element.getMainUrlString(), element); + return true; + } + return false; } public boolean remove(Object element) { return element instanceof Provider && - customProviders.remove(element) && - customProviderURLs.remove(((Provider) element).getMainUrl().toString()); + customProviders.remove(((Provider) element).getMainUrlString()) != null; } public boolean addAll(Collection<? extends Provider> elements) { @@ -194,9 +171,11 @@ public class ProviderManager { boolean addedAll = true; while (iterator.hasNext()) { Provider p = (Provider) iterator.next(); - addedAll = customProviders.add(p) && - customProviderURLs.add(p.getMainUrl().toString()) && - addedAll; + boolean containsKey = customProviders.containsKey(p.getMainUrlString()); + if (!containsKey) { + customProviders.put(p.getMainUrlString(), p); + } + addedAll = !containsKey && addedAll; } return addedAll; } @@ -204,15 +183,8 @@ public class ProviderManager { public boolean removeAll(Collection<?> elements) { Iterator iterator = elements.iterator(); boolean removedAll = true; - try { - while (iterator.hasNext()) { - Provider p = (Provider) iterator.next(); - removedAll = ((defaultProviders.remove(p) && defaultProviderURLs.remove(p.getMainUrl().toString())) || - (customProviders.remove(p) && customProviderURLs.remove(p.getMainUrl().toString()))) && - removedAll; - } - } catch (ClassCastException e) { - return false; + while (iterator.hasNext()) { + removedAll = remove(iterator.next()) && removedAll; } return removedAll; @@ -221,37 +193,10 @@ public class ProviderManager { public void clear() { defaultProviders.clear(); customProviders.clear(); - customProviderURLs.clear(); defaultProviderURLs.clear(); } - public void saveCustomProvidersToFile() { - try { - deleteLegacyCustomProviders(); - - for (Provider provider : customProviders) { - File providerFile = createFile(externalFilesDir, provider.getName() + EXT_JSON); - if (!providerFile.exists()) { - persistFile(providerFile, provider.toJson().toString()); - } - } - } catch (IOException | SecurityException e) { - e.printStackTrace(); - } - } - - /** - * Deletes persisted custom providers from from internal storage that are not in customProviders list anymore - */ - private void deleteLegacyCustomProviders() throws IOException, SecurityException { - Set<Provider> persistedCustomProviders = externalFilesDir != null && externalFilesDir.isDirectory() ? - customProvidersFromFiles(externalFilesDir.list()) : new HashSet<Provider>(); - persistedCustomProviders.removeAll(customProviders); - for (Provider providerToDelete : persistedCustomProviders) { - File providerFile = createFile(externalFilesDir, providerToDelete.getName() + EXT_JSON); - if (providerFile.exists()) { - providerFile.delete(); - } - } + public void saveCustomProviders() { + PreferenceHelper.setCustomProviders(new HashSet<>(customProviders.values())); } } 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 cdb8bd78..58fccc65 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 @@ -78,8 +78,7 @@ public class CircumventionSetupFragment extends BaseSetupFragment implements Can } private void loadProviderFromAssets() { - ProviderManager providerManager = ProviderManager.getInstance(getContext().getApplicationContext().getAssets(), - getContext().getExternalFilesDir(null)); + ProviderManager providerManager = ProviderManager.getInstance(getContext().getApplicationContext().getAssets()); providerManager.setAddDummyEntry(false); setupActivityCallback.onProviderSelected(providerManager.providers().get(0)); } 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 e8f37e43..8ccfee22 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 @@ -2,7 +2,6 @@ package se.leap.bitmaskclient.providersetup.fragments; import static se.leap.bitmaskclient.providersetup.fragments.viewmodel.ProviderSelectionViewModel.ADD_PROVIDER; -import android.content.Context; import android.graphics.Typeface; import android.os.Bundle; import android.text.Editable; @@ -20,7 +19,6 @@ import java.util.ArrayList; import se.leap.bitmaskclient.R; import se.leap.bitmaskclient.base.models.Provider; -import se.leap.bitmaskclient.base.models.ProviderObservable; import se.leap.bitmaskclient.base.utils.ViewHelper; import se.leap.bitmaskclient.databinding.FProviderSelectionBinding; import se.leap.bitmaskclient.providersetup.activities.CancelCallback; @@ -46,8 +44,7 @@ public class ProviderSelectionFragment extends BaseSetupFragment implements Canc super.onCreate(savedInstanceState); viewModel = new ViewModelProvider(this, new ProviderSelectionViewModelFactory( - getContext().getApplicationContext().getAssets(), - getContext().getExternalFilesDir(null))). + getContext().getApplicationContext().getAssets())). get(ProviderSelectionViewModel.class); } diff --git a/app/src/main/java/se/leap/bitmaskclient/providersetup/fragments/viewmodel/ProviderSelectionViewModel.java b/app/src/main/java/se/leap/bitmaskclient/providersetup/fragments/viewmodel/ProviderSelectionViewModel.java index aa2fe7cb..53d02b46 100644 --- a/app/src/main/java/se/leap/bitmaskclient/providersetup/fragments/viewmodel/ProviderSelectionViewModel.java +++ b/app/src/main/java/se/leap/bitmaskclient/providersetup/fragments/viewmodel/ProviderSelectionViewModel.java @@ -8,7 +8,6 @@ import android.webkit.URLUtil; import androidx.lifecycle.ViewModel; -import java.io.File; import java.util.List; import se.leap.bitmaskclient.R; @@ -22,8 +21,8 @@ public class ProviderSelectionViewModel extends ViewModel { private int selected = 0; private String customUrl; - public ProviderSelectionViewModel(AssetManager assetManager, File externalFilesDir) { - providerManager = ProviderManager.getInstance(assetManager, externalFilesDir); + public ProviderSelectionViewModel(AssetManager assetManager) { + providerManager = ProviderManager.getInstance(assetManager); providerManager.setAddDummyEntry(false); } diff --git a/app/src/main/java/se/leap/bitmaskclient/providersetup/fragments/viewmodel/ProviderSelectionViewModelFactory.java b/app/src/main/java/se/leap/bitmaskclient/providersetup/fragments/viewmodel/ProviderSelectionViewModelFactory.java index a21e4924..f6d86e07 100644 --- a/app/src/main/java/se/leap/bitmaskclient/providersetup/fragments/viewmodel/ProviderSelectionViewModelFactory.java +++ b/app/src/main/java/se/leap/bitmaskclient/providersetup/fragments/viewmodel/ProviderSelectionViewModelFactory.java @@ -6,22 +6,18 @@ import androidx.annotation.NonNull; import androidx.lifecycle.ViewModel; import androidx.lifecycle.ViewModelProvider; -import java.io.File; - public class ProviderSelectionViewModelFactory implements ViewModelProvider.Factory { private final AssetManager assetManager; - private final File externalFilesDir; - public ProviderSelectionViewModelFactory(AssetManager assetManager, File externalFilesDir) { + public ProviderSelectionViewModelFactory(AssetManager assetManager) { this.assetManager = assetManager; - this.externalFilesDir = externalFilesDir; } @NonNull @Override public <T extends ViewModel> T create(@NonNull Class<T> modelClass) { if (modelClass.isAssignableFrom(ProviderSelectionViewModel.class)) { - return (T) new ProviderSelectionViewModel(assetManager, externalFilesDir); + return (T) new ProviderSelectionViewModel(assetManager); } throw new IllegalArgumentException("Unknown ViewModel class"); } |