summaryrefslogtreecommitdiff
path: root/app/src/main/java/se/leap/bitmaskclient/providersetup/ProviderManager.java
diff options
context:
space:
mode:
Diffstat (limited to 'app/src/main/java/se/leap/bitmaskclient/providersetup/ProviderManager.java')
-rw-r--r--app/src/main/java/se/leap/bitmaskclient/providersetup/ProviderManager.java272
1 files changed, 272 insertions, 0 deletions
diff --git a/app/src/main/java/se/leap/bitmaskclient/providersetup/ProviderManager.java b/app/src/main/java/se/leap/bitmaskclient/providersetup/ProviderManager.java
new file mode 100644
index 00000000..d33a175f
--- /dev/null
+++ b/app/src/main/java/se/leap/bitmaskclient/providersetup/ProviderManager.java
@@ -0,0 +1,272 @@
+package se.leap.bitmaskclient.providersetup;
+
+import android.content.res.AssetManager;
+import androidx.annotation.VisibleForTesting;
+
+import com.pedrogomez.renderers.AdapteeCollection;
+
+import org.json.JSONException;
+import org.json.JSONObject;
+
+import java.io.File;
+import java.io.FileNotFoundException;
+import java.io.IOException;
+import java.io.InputStream;
+import java.net.URL;
+import java.util.ArrayList;
+import java.util.Collection;
+import java.util.HashSet;
+import java.util.Iterator;
+import java.util.List;
+import java.util.Set;
+
+import se.leap.bitmaskclient.base.models.Provider;
+
+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.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.loadInputStreamAsString;
+
+/**
+ * Created by parmegv on 4/12/14.
+ */
+public class ProviderManager implements AdapteeCollection<Provider> {
+
+ private AssetManager assetsManager;
+ private File externalFilesDir;
+ private Set<Provider> defaultProviders;
+ private Set<Provider> customProviders;
+ private Set<URL> defaultProviderURLs;
+ private Set<URL> customProviderURLs;
+
+ private static ProviderManager instance;
+
+ final private static String URLS = "urls";
+ final private static String EXT_JSON = ".json";
+ final private static String EXT_PEM = ".pem";
+
+ public static ProviderManager getInstance(AssetManager assetsManager, File externalFilesDir) {
+ if (instance == null)
+ instance = new ProviderManager(assetsManager, externalFilesDir);
+
+ return instance;
+ }
+
+ @VisibleForTesting
+ static void reset() {
+ instance = null;
+ }
+
+ private ProviderManager(AssetManager assetManager, File externalFilesDir) {
+ this.assetsManager = assetManager;
+ addDefaultProviders(assetManager);
+ addCustomProviders(externalFilesDir);
+ }
+
+ private void addDefaultProviders(AssetManager assets_manager) {
+ try {
+ defaultProviders = providersFromAssets(URLS, assets_manager.list(URLS));
+ defaultProviderURLs = getProviderUrlSetFromProviderSet(defaultProviders);
+ } catch (IOException e) {
+ e.printStackTrace();
+ }
+ }
+
+ private Set<URL> getProviderUrlSetFromProviderSet(Set<Provider> providers) {
+ HashSet<URL> providerUrls = new HashSet<>();
+ for (Provider provider : providers) {
+ providerUrls.add(provider.getMainUrl().getUrl());
+ }
+ return providerUrls;
+ }
+
+ private Set<Provider> providersFromAssets(String directory, String[] relativeFilePaths) {
+ Set<Provider> providers = new HashSet<>();
+
+ for (String file : relativeFilePaths) {
+ String mainUrl = null;
+ String providerIp = null;
+ String providerApiIp = null;
+ String certificate = null;
+ String providerDefinition = null;
+ String geoipUrl = null;
+ try {
+ String provider = file.substring(0, file.length() - ".url".length());
+ InputStream providerFile = assetsManager.open(directory + "/" + file);
+ mainUrl = extractKeyFromInputStream(providerFile, MAIN_URL);
+ providerIp = extractKeyFromInputStream(providerFile, PROVIDER_IP);
+ providerApiIp = extractKeyFromInputStream(providerFile, PROVIDER_API_IP);
+ geoipUrl = extractKeyFromInputStream(providerFile, GEOIP_URL);
+ certificate = loadInputStreamAsString(assetsManager.open(provider + EXT_PEM));
+ providerDefinition = loadInputStreamAsString(assetsManager.open(provider + EXT_JSON));
+ } catch (IOException e) {
+ e.printStackTrace();
+ }
+ providers.add(new Provider(mainUrl, geoipUrl, providerIp, providerApiIp, certificate, providerDefinition));
+ }
+
+ return providers;
+ }
+
+
+ private void addCustomProviders(File externalFilesDir) {
+ this.externalFilesDir = externalFilesDir;
+ customProviders = externalFilesDir != null && externalFilesDir.isDirectory() ?
+ providersFromFiles(externalFilesDir.list()) :
+ new HashSet<>();
+ customProviderURLs = getProviderUrlSetFromProviderSet(customProviders);
+ }
+
+ private Set<Provider> providersFromFiles(String[] files) {
+ Set<Provider> providers = new HashSet<>();
+ try {
+ for (String file : files) {
+ InputStream inputStream = getInputStreamFrom(externalFilesDir.getAbsolutePath() + "/" + file);
+ String mainUrl = extractKeyFromInputStream(inputStream, MAIN_URL);
+ String providerIp = extractKeyFromInputStream(inputStream, PROVIDER_IP);
+ String providerApiIp = extractKeyFromInputStream(inputStream, PROVIDER_API_IP);
+ providers.add(new Provider(mainUrl, providerIp, providerApiIp));
+ }
+ } catch (FileNotFoundException | NullPointerException e) {
+ e.printStackTrace();
+ }
+
+ return providers;
+ }
+
+ private String extractKeyFromInputStream(InputStream inputStream, String key) {
+ String value = "";
+
+ JSONObject fileContents = inputStreamToJson(inputStream);
+ if (fileContents != null)
+ value = fileContents.optString(key);
+ return value;
+ }
+
+ private JSONObject inputStreamToJson(InputStream inputStream) {
+ JSONObject json = null;
+ try {
+ byte[] bytes = new byte[inputStream.available()];
+ if (inputStream.read(bytes) > 0)
+ json = new JSONObject(new String(bytes));
+ inputStream.reset();
+ } catch (IOException | JSONException e) {
+ e.printStackTrace();
+ }
+ return json;
+ }
+
+ public List<Provider> providers() {
+ List<Provider> allProviders = new ArrayList<>();
+ allProviders.addAll(defaultProviders);
+ if(customProviders != null)
+ allProviders.addAll(customProviders);
+ //add an option to add a custom provider
+ //TODO: refactor me?
+ allProviders.add(new Provider());
+ return allProviders;
+ }
+
+ @Override
+ public int size() {
+ return providers().size();
+ }
+
+ @Override
+ public Provider get(int index) {
+ Iterator<Provider> iterator = providers().iterator();
+ while (iterator.hasNext() && index > 0) {
+ iterator.next();
+ index--;
+ }
+ return iterator.next();
+ }
+
+ @Override
+ public boolean add(Provider element) {
+ return element != null &&
+ !defaultProviderURLs.contains(element.getMainUrl().getUrl()) &&
+ customProviders.add(element) &&
+ customProviderURLs.add(element.getMainUrl().getUrl());
+ }
+
+ @Override
+ public boolean remove(Object element) {
+ return element instanceof Provider &&
+ customProviders.remove(element) &&
+ customProviderURLs.remove(((Provider) element).getMainUrl().getUrl());
+ }
+
+ @Override
+ public boolean addAll(Collection<? extends Provider> elements) {
+ Iterator iterator = elements.iterator();
+ boolean addedAll = true;
+ while (iterator.hasNext()) {
+ Provider p = (Provider) iterator.next();
+ addedAll = customProviders.add(p) &&
+ customProviderURLs.add(p.getMainUrl().getUrl()) &&
+ addedAll;
+ }
+ return addedAll;
+ }
+
+ @Override
+ 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().getUrl())) ||
+ (customProviders.remove(p) && customProviderURLs.remove(p.getMainUrl().getUrl()))) &&
+ removedAll;
+ }
+ } catch (ClassCastException e) {
+ return false;
+ }
+
+ return removedAll;
+ }
+
+ @Override
+ public void clear() {
+ defaultProviders.clear();
+ customProviders.clear();
+ customProviderURLs.clear();
+ defaultProviderURLs.clear();
+ }
+
+ 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() ?
+ providersFromFiles(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();
+ }
+ }
+ }
+}