diff options
author | cyBerta <cyberta@riseup.net> | 2024-11-07 19:13:53 +0100 |
---|---|---|
committer | cyberta <cyberta@riseup.net> | 2024-12-11 00:09:34 +0000 |
commit | bbf98bb94648bb9c7a8aebe866a7bc61a79c14ca (patch) | |
tree | 0147212802abbc01c64b4c36c26ff1464a3719a2 /app | |
parent | ab4c3397c501e059849d16f05fa211d5ebd3c4db (diff) |
update bitmask-core API, store v5 provider details
Diffstat (limited to 'app')
8 files changed, 254 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 b49061c9..5a5d1d6e 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 @@ -126,6 +126,10 @@ public interface Constants { String PROVIDER_MOTD_HASHES = "Constants.PROVIDER_MOTD_HASHES"; String PROVIDER_MOTD_LAST_SEEN = "Constants.PROVIDER_MOTD_LAST_SEEN"; String PROVIDER_MOTD_LAST_UPDATED = "Constants.PROVIDER_MOTD_LAST_UPDATED"; + String PROVIDER_MODELS_PROVIDER = "Constants.PROVIDER_MODELS_PROVIDER"; + String PROVIDER_MODELS_EIPSERVICE = "Constants.PROVIDER_MDOELS_EIPSERVICE"; + String PROVIDER_MODELS_GATEWAYS = "Constants.PROVIDER_MODELS_GATEWAYS"; + String PROVIDER_MODELS_BRIDGES = "Constants.PROVIDER_MODELS_BRIDGES"; //////////////////////////////////////////////// // PRESHIPPED PROVIDER CONFIG 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 51183e5e..cdec9e7a 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 @@ -39,12 +39,14 @@ import android.os.Parcelable; import androidx.annotation.NonNull; import com.google.gson.Gson; +import com.google.gson.JsonSyntaxException; import org.json.JSONArray; import org.json.JSONException; import org.json.JSONObject; import java.net.MalformedURLException; +import java.net.URISyntaxException; import java.net.URL; import java.security.PrivateKey; import java.util.ArrayList; @@ -145,7 +147,7 @@ public final class Provider implements Parcelable { setGeoipUrl(geoipUrl); } - public static Provider createCustomProvider(String mainUrl, String domain) { + public static Provider createCustomProvider(String mainUrl, String domain, Introducer introducer) { Provider p = new Provider(mainUrl); p.domain = domain; return p; @@ -189,29 +191,93 @@ public final class Provider implements Parcelable { } }; - public void setBridges(ModelsBridge[] bridges) { - this.modelsBridges = bridges; + public void setBridges(String bridgesJson) { + if (bridgesJson == null) { + this.modelsBridges = null; + return; + } + try { + this.modelsBridges = JSON.createGson().create().fromJson(bridgesJson, ModelsBridge[].class); + } catch (JsonSyntaxException e) { + e.printStackTrace(); + } } public ModelsBridge[] getBridges() { return this.modelsBridges; } - public void setGateways(ModelsGateway[] gateways) { - this.modelsGateways = gateways; + + public String getBridgesJson() { + return getJsonString(modelsBridges); + } + + public void setGateways(String gatewaysJson) { + if (gatewaysJson == null) { + this.modelsGateways = null; + return; + } + try { + this.modelsGateways = JSON.createGson().create().fromJson(gatewaysJson, ModelsGateway[].class); + } catch (JsonSyntaxException e) { + e.printStackTrace(); + } } public ModelsGateway[] getGateways() { return modelsGateways; } - public void setService(ModelsEIPService service) { - this.modelsEIPService = service; + public String getGatewaysJson() { + return getJsonString(modelsGateways); } + public void setService(String serviceJson) { + if (serviceJson == null) { + this.modelsEIPService = null; + return; + } + try { + this.modelsEIPService = JSON.createGson().create().fromJson(serviceJson, ModelsEIPService.class); + } catch (JsonSyntaxException e) { + e.printStackTrace(); + } + } public ModelsEIPService getService() { return this.modelsEIPService; } + public String getServiceJson() { + return getJsonString(modelsEIPService); + } + + public void setModelsProvider(String json) { + if (json == null) { + this.modelsProvider = null; + return; + } + try { + this.modelsProvider = JSON.createGson().create().fromJson(json, ModelsProvider.class); + } catch (JsonSyntaxException e) { + e.printStackTrace(); + } + } + + public String getModelsProviderJson() { + return getJsonString(modelsProvider); + } + + private String getJsonString(Object model) { + if (model == null) { + return null; + } + try { + return JSON.createGson().create().toJson(model); + } catch (JsonSyntaxException e) { + e.printStackTrace(); + return null; + } + } + public boolean isConfigured() { if (apiVersion < 5) { return !mainUrl.isEmpty() && @@ -583,23 +649,10 @@ public final class Provider implements Parcelable { this.shouldUpdateVpnCertificate = in.readInt() == 0; this.introducer = in.readParcelable(Introducer.class.getClassLoader()); if (this.apiVersion == 5) { - Gson gson = JSON.createGson().create(); - tmpString = in.readString(); - if (!tmpString.isEmpty()) { - this.setModelsProvider(gson.fromJson(tmpString, ModelsProvider.class)); - } - tmpString = in.readString(); - if (!tmpString.isEmpty()) { - this.setService(gson.fromJson(tmpString, ModelsEIPService.class)); - } - tmpString = in.readString(); - if (!tmpString.isEmpty()) { - this.setBridges(gson.fromJson(tmpString, ModelsBridge[].class)); - } - tmpString = in.readString(); - if (!tmpString.isEmpty()) { - this.setGateways(gson.fromJson(tmpString, ModelsGateway[].class)); - } + this.setModelsProvider(in.readString()); + this.setService(in.readString()); + this.setBridges(in.readString()); + this.setGateways(in.readString()); } } catch (MalformedURLException | JSONException e) { e.printStackTrace(); @@ -904,6 +957,10 @@ public final class Provider implements Parcelable { return introducer; } + public void setIntroducer(String introducerUrl) throws URISyntaxException { + this.introducer = Introducer.fromUrl(introducerUrl); + } + /** * resets everything except the main url, the providerIp and the geoip * service url (currently preseeded) @@ -926,7 +983,4 @@ public final class Provider implements Parcelable { lastEipServiceUpdate = 0L; } - public void setModelsProvider(ModelsProvider p) { - this.modelsProvider = p; - } } 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 bb342f0f..5cc3ff70 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 @@ -31,6 +31,10 @@ import static se.leap.bitmaskclient.base.models.Constants.PREFERRED_CITY; import static se.leap.bitmaskclient.base.models.Constants.PREFER_UDP; import static se.leap.bitmaskclient.base.models.Constants.PROVIDER_CONFIGURED; import static se.leap.bitmaskclient.base.models.Constants.PROVIDER_EIP_DEFINITION; +import static se.leap.bitmaskclient.base.models.Constants.PROVIDER_MODELS_BRIDGES; +import static se.leap.bitmaskclient.base.models.Constants.PROVIDER_MODELS_EIPSERVICE; +import static se.leap.bitmaskclient.base.models.Constants.PROVIDER_MODELS_GATEWAYS; +import static se.leap.bitmaskclient.base.models.Constants.PROVIDER_MODELS_PROVIDER; import static se.leap.bitmaskclient.base.models.Constants.PROVIDER_MOTD; import static se.leap.bitmaskclient.base.models.Constants.PROVIDER_MOTD_HASHES; import static se.leap.bitmaskclient.base.models.Constants.PROVIDER_MOTD_LAST_SEEN; @@ -60,6 +64,8 @@ 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; @@ -74,7 +80,10 @@ import java.util.Set; import de.blinkt.openvpn.VpnProfile; import de.blinkt.openvpn.core.NativeUtils; +import io.swagger.client.JSON; +import mobile.BitmaskMobile; import se.leap.bitmaskclient.BuildConfig; +import se.leap.bitmaskclient.base.models.Introducer; import se.leap.bitmaskclient.base.models.Provider; import se.leap.bitmaskclient.tor.TorStatusObservable; @@ -156,7 +165,14 @@ public class PreferenceHelper { provider.setLastMotdSeen(preferences.getLong(PROVIDER_MOTD_LAST_SEEN, 0L)); provider.setLastMotdUpdate(preferences.getLong(PROVIDER_MOTD_LAST_UPDATED, 0L)); provider.setMotdLastSeenHashes(preferences.getStringSet(PROVIDER_MOTD_HASHES, new HashSet<>())); - } catch (MalformedURLException | JSONException e) { + provider.setModelsProvider(preferences.getString(PROVIDER_MODELS_PROVIDER, null)); + provider.setService(preferences.getString(PROVIDER_MODELS_EIPSERVICE, null)); + provider.setBridges(preferences.getString(PROVIDER_MODELS_BRIDGES, null)); + provider.setGateways(preferences.getString(PROVIDER_MODELS_GATEWAYS, null)); + BitmaskMobile bm = new BitmaskMobile(new SharedPreferenceStore()); + provider.setIntroducer(bm.getIntroducerURLByDomain(provider.getDomain())); + + } catch (Exception e) { e.printStackTrace(); } } @@ -201,12 +217,23 @@ public class PreferenceHelper { 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)); + if (providerDomains.size() > 0) { + BitmaskMobile bm = new BitmaskMobile(new PreferenceHelper.SharedPreferenceStore()); + for (String domain : providerDomains) { + String mainURL = preferences.getString(Provider.MAIN_URL + "." + domain, null); + if (mainURL != null) { + Introducer introducer = null; + try { + introducer = Introducer.fromUrl(bm.getIntroducerURLByDomain(domain)); + } catch (Exception e) { + e.printStackTrace(); + } + customProviders.put(mainURL, Provider.createCustomProvider(mainURL, domain, introducer)); + } } + } + return customProviders; } @@ -254,7 +281,11 @@ public class PreferenceHelper { putString(PROVIDER_MOTD, provider.getMotdJsonString()). putStringSet(PROVIDER_MOTD_HASHES, provider.getMotdLastSeenHashes()). putLong(PROVIDER_MOTD_LAST_SEEN, provider.getLastMotdSeen()). - putLong(PROVIDER_MOTD_LAST_UPDATED, provider.getLastMotdUpdate()); + putLong(PROVIDER_MOTD_LAST_UPDATED, provider.getLastMotdUpdate()). + putString(PROVIDER_MODELS_GATEWAYS, provider.getGatewaysJson()). + putString(PROVIDER_MODELS_BRIDGES, provider.getBridgesJson()). + putString(PROVIDER_MODELS_EIPSERVICE, provider.getServiceJson()). + putString(PROVIDER_MODELS_PROVIDER, provider.getModelsProviderJson()); if (async) { editor.apply(); } else { 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 4093f25c..85af48b0 100644 --- a/app/src/main/java/se/leap/bitmaskclient/providersetup/ProviderApiManagerBase.java +++ b/app/src/main/java/se/leap/bitmaskclient/providersetup/ProviderApiManagerBase.java @@ -19,6 +19,10 @@ package se.leap.bitmaskclient.providersetup; import static se.leap.bitmaskclient.R.string.vpn_certificate_is_invalid; import static se.leap.bitmaskclient.base.models.Constants.BROADCAST_RESULT_KEY; +import static se.leap.bitmaskclient.base.models.Constants.PROVIDER_MODELS_BRIDGES; +import static se.leap.bitmaskclient.base.models.Constants.PROVIDER_MODELS_EIPSERVICE; +import static se.leap.bitmaskclient.base.models.Constants.PROVIDER_MODELS_GATEWAYS; +import static se.leap.bitmaskclient.base.models.Constants.PROVIDER_MODELS_PROVIDER; import static se.leap.bitmaskclient.base.models.Constants.PROVIDER_MOTD; import static se.leap.bitmaskclient.base.models.Constants.PROVIDER_MOTD_HASHES; import static se.leap.bitmaskclient.base.models.Constants.PROVIDER_MOTD_LAST_SEEN; @@ -31,7 +35,6 @@ 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.CertificateHelper.getFingerprintFromCertificate; import static se.leap.bitmaskclient.base.utils.ConfigHelper.getDomainFromMainURL; -import static se.leap.bitmaskclient.base.utils.PreferenceHelper.deleteProviderDetailsFromPreferences; import static se.leap.bitmaskclient.base.utils.PreferenceHelper.getFromPersistedProvider; import static se.leap.bitmaskclient.base.utils.PreferenceHelper.getLongFromPersistedProvider; import static se.leap.bitmaskclient.base.utils.PreferenceHelper.getStringSetFromPersistedProvider; @@ -46,6 +49,8 @@ import android.content.res.Resources; import android.os.Bundle; import android.util.Base64; +import com.google.gson.JsonSyntaxException; + import org.json.JSONException; import org.json.JSONObject; @@ -59,10 +64,12 @@ import java.util.ArrayList; import java.util.Set; import java.util.concurrent.TimeoutException; +import io.swagger.client.JSON; +import io.swagger.client.model.ModelsBridge; +import io.swagger.client.model.ModelsProvider; import se.leap.bitmaskclient.base.models.Provider; import se.leap.bitmaskclient.base.utils.ConfigHelper; import se.leap.bitmaskclient.base.utils.PreferenceHelper; -import se.leap.bitmaskclient.base.utils.PrivateKeyHelper; /** * Implements the logic of the http api calls. The methods of this class needs to be called from @@ -99,7 +106,6 @@ public abstract class ProviderApiManagerBase { void resetProviderDetails(Provider provider) { provider.reset(); - deleteProviderDetailsFromPreferences(provider.getDomain()); } protected boolean isValidJson(String jsonString) { @@ -157,6 +163,10 @@ public abstract class ProviderApiManagerBase { provider.setMotdLastSeenHashes(getPersistedMotdHashes(providerDomain)); provider.setLastMotdUpdate(getPersistedMotdLastUpdate(providerDomain)); provider.setMotdJson(getPersistedMotd(providerDomain)); + provider.setModelsProvider(getFromPersistedProvider(PROVIDER_MODELS_PROVIDER, providerDomain)); + provider.setService(getFromPersistedProvider(PROVIDER_MODELS_EIPSERVICE, providerDomain)); + provider.setGateways(getFromPersistedProvider(PROVIDER_MODELS_GATEWAYS, providerDomain)); + provider.setBridges(getFromPersistedProvider(PROVIDER_MODELS_BRIDGES, providerDomain)); } } @@ -203,6 +213,24 @@ public abstract class ProviderApiManagerBase { } } + protected ModelsProvider getPersistedModelsProvider(String providerDomain) { + try { + String json = getFromPersistedProvider(PROVIDER_MODELS_PROVIDER, providerDomain); + return json != null ? JSON.createGson().create().fromJson(json, ModelsProvider.class) : null; + } catch (JsonSyntaxException e) { + return null; + } + } + + protected ModelsBridge[] getPersistedModelsBridge(String providerDomain) { + try { + String json = getFromPersistedProvider(PROVIDER_MODELS_BRIDGES, providerDomain); + return json != null ? JSON.createGson().create().fromJson(json, ModelsBridge[].class) : null; + } catch (JsonSyntaxException e) { + return null; + } + } + protected long getPersistedMotdLastSeen(String providerDomain) { return getLongFromPersistedProvider(PROVIDER_MOTD_LAST_SEEN, providerDomain); } @@ -220,43 +248,4 @@ public abstract class ProviderApiManagerBase { return PreferenceHelper.hasKey(Provider.KEY + "." + domain) && PreferenceHelper.hasKey(CA_CERT + "." + domain); } - protected Bundle loadCertificate(Provider provider, String certString) { - Bundle result = new Bundle(); - if (certString == null) { - eventSender.setErrorResult(result, vpn_certificate_is_invalid, null); - return result; - } - - try { - // API returns concatenated cert & key. Split them for OpenVPN options - String certificateString = null, keyString = null; - String[] certAndKey = certString.split("(?<=-\n)"); - for (int i = 0; i < certAndKey.length - 1; i++) { - if (certAndKey[i].contains("KEY")) { - keyString = certAndKey[i++] + certAndKey[i]; - } else if (certAndKey[i].contains("CERTIFICATE")) { - certificateString = certAndKey[i++] + certAndKey[i]; - } - } - - PrivateKey key = parsePrivateKeyFromString(keyString); - keyString = Base64.encodeToString(key.getEncoded(), Base64.DEFAULT); - - if (key instanceof RSAPrivateKey) { - provider.setPrivateKeyString(RSA_KEY_BEGIN + keyString + RSA_KEY_END); - } else { - provider.setPrivateKeyString(ED_25519_KEY_BEGIN + keyString + ED_25519_KEY_END); - } - - ArrayList<X509Certificate> certificates = ConfigHelper.parseX509CertificatesFromString(certificateString); - certificates.get(0).checkValidity(); - certificateString = Base64.encodeToString(certificates.get(0).getEncoded(), Base64.DEFAULT); - provider.setVpnCertificate( "-----BEGIN CERTIFICATE-----\n" + certificateString + "-----END CERTIFICATE-----"); - result.putBoolean(BROADCAST_RESULT_KEY, true); - } catch (CertificateException | NullPointerException e) { - e.printStackTrace(); - eventSender.setErrorResult(result, vpn_certificate_is_invalid, null); - } - return result; - } -} + } diff --git a/app/src/main/java/se/leap/bitmaskclient/providersetup/ProviderApiManagerV3.java b/app/src/main/java/se/leap/bitmaskclient/providersetup/ProviderApiManagerV3.java index f827d85d..0c6878c6 100644 --- a/app/src/main/java/se/leap/bitmaskclient/providersetup/ProviderApiManagerV3.java +++ b/app/src/main/java/se/leap/bitmaskclient/providersetup/ProviderApiManagerV3.java @@ -28,6 +28,7 @@ import static se.leap.bitmaskclient.R.string.server_unreachable_message; import static se.leap.bitmaskclient.R.string.service_is_down_error; import static se.leap.bitmaskclient.R.string.setup_error_text; import static se.leap.bitmaskclient.R.string.setup_error_text_custom; +import static se.leap.bitmaskclient.R.string.vpn_certificate_is_invalid; import static se.leap.bitmaskclient.R.string.warning_corrupted_provider_cert; import static se.leap.bitmaskclient.R.string.warning_corrupted_provider_details; import static se.leap.bitmaskclient.R.string.warning_expired_provider_cert; @@ -38,6 +39,11 @@ import static se.leap.bitmaskclient.base.models.Constants.PROVIDER_VPN_CERTIFICA import static se.leap.bitmaskclient.base.utils.BuildConfigHelper.isDefaultBitmask; 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.PrivateKeyHelper.ED_25519_KEY_BEGIN; +import static se.leap.bitmaskclient.base.utils.PrivateKeyHelper.ED_25519_KEY_END; +import static se.leap.bitmaskclient.base.utils.PrivateKeyHelper.RSA_KEY_BEGIN; +import static se.leap.bitmaskclient.base.utils.PrivateKeyHelper.RSA_KEY_END; +import static se.leap.bitmaskclient.base.utils.PrivateKeyHelper.parsePrivateKeyFromString; import static se.leap.bitmaskclient.providersetup.ProviderAPI.CORRECTLY_DOWNLOADED_EIP_SERVICE; import static se.leap.bitmaskclient.providersetup.ProviderAPI.CORRECTLY_DOWNLOADED_GEOIP_JSON; import static se.leap.bitmaskclient.providersetup.ProviderAPI.CORRECTLY_DOWNLOADED_VPN_CERTIFICATE; @@ -70,6 +76,7 @@ import static se.leap.bitmaskclient.tor.TorStatusObservable.getProxyPort; import android.content.res.Resources; import android.os.Bundle; import android.os.ResultReceiver; +import android.util.Base64; import android.util.Log; import android.util.Pair; @@ -86,12 +93,16 @@ import java.net.URL; import java.net.UnknownHostException; import java.net.UnknownServiceException; import java.security.NoSuchAlgorithmException; +import java.security.PrivateKey; import java.security.cert.CertificateEncodingException; +import java.security.cert.CertificateException; import java.security.cert.CertificateExpiredException; import java.security.cert.CertificateNotYetValidException; import java.security.cert.X509Certificate; +import java.security.interfaces.RSAPrivateKey; import java.util.ArrayList; import java.util.List; +import java.util.StringTokenizer; import java.util.concurrent.TimeoutException; import javax.net.ssl.SSLHandshakeException; @@ -354,6 +365,47 @@ public class ProviderApiManagerV3 extends ProviderApiManagerBase implements IPro return loadCertificate(provider, certString); } + private Bundle loadCertificate(Provider provider, String certString) { + Bundle result = new Bundle(); + if (certString == null) { + eventSender.setErrorResult(result, vpn_certificate_is_invalid, null); + return result; + } + + try { + // API returns concatenated cert & key. Split them for OpenVPN options + String certificateString = null, keyString = null; + String[] certAndKey = certString.split("(?<=-\n)"); + + for (int i = 0; i < certAndKey.length - 1; i++) { + if (certAndKey[i].contains("KEY")) { + keyString += certAndKey[i++] + certAndKey[i]; + } else if (certAndKey[i].contains("CERTIFICATE")) { + certificateString += certAndKey[i++] + certAndKey[i]; + } + } + + PrivateKey key = parsePrivateKeyFromString(keyString); + keyString = Base64.encodeToString(key.getEncoded(), Base64.DEFAULT); + + if (key instanceof RSAPrivateKey) { + provider.setPrivateKeyString(RSA_KEY_BEGIN + keyString + RSA_KEY_END); + } else { + provider.setPrivateKeyString(ED_25519_KEY_BEGIN + keyString + ED_25519_KEY_END); + } + + ArrayList<X509Certificate> certificates = ConfigHelper.parseX509CertificatesFromString(certificateString); + certificates.get(0).checkValidity(); + certificateString = Base64.encodeToString(certificates.get(0).getEncoded(), Base64.DEFAULT); + provider.setVpnCertificate( "-----BEGIN CERTIFICATE-----\n" + certificateString + "-----END CERTIFICATE-----"); + result.putBoolean(BROADCAST_RESULT_KEY, true); + } catch (CertificateException | NullPointerException e) { + e.printStackTrace(); + eventSender.setErrorResult(result, vpn_certificate_is_invalid, null); + } + return result; + } + /** * Fetches the geo ip Json, containing a list of gateways sorted by distance from the users current location. * Fetching is only allowed if the cache timeout of 1 h was reached, a valid geoip service URL exists and the 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 9981feb1..5b822be7 100644 --- a/app/src/main/java/se/leap/bitmaskclient/providersetup/ProviderApiManagerV5.java +++ b/app/src/main/java/se/leap/bitmaskclient/providersetup/ProviderApiManagerV5.java @@ -2,6 +2,7 @@ package se.leap.bitmaskclient.providersetup; import static android.text.TextUtils.isEmpty; import static se.leap.bitmaskclient.R.string.malformed_url; +import static se.leap.bitmaskclient.R.string.vpn_certificate_is_invalid; import static se.leap.bitmaskclient.R.string.warning_corrupted_provider_cert; import static se.leap.bitmaskclient.R.string.warning_expired_provider_cert; import static se.leap.bitmaskclient.base.models.Constants.BROADCAST_RESULT_KEY; @@ -32,23 +33,22 @@ import android.util.Log; import androidx.annotation.Nullable; +import org.xmlpull.v1.XmlPullParserException; + +import java.io.IOException; import java.security.cert.CertificateExpiredException; import java.security.cert.CertificateNotYetValidException; import java.security.cert.X509Certificate; import java.util.ArrayList; import de.blinkt.openvpn.core.VpnStatus; -import io.swagger.client.JSON; -import io.swagger.client.model.ModelsBridge; -import io.swagger.client.model.ModelsEIPService; -import io.swagger.client.model.ModelsGateway; -import io.swagger.client.model.ModelsProvider; import mobile.BitmaskMobile; import se.leap.bitmaskclient.BuildConfig; 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.ConfigHelper; +import se.leap.bitmaskclient.base.utils.CredentialsParser; import se.leap.bitmaskclient.base.utils.PreferenceHelper; import se.leap.bitmaskclient.eip.EipStatus; import se.leap.bitmaskclient.tor.TorStatusObservable; @@ -124,8 +124,7 @@ public class ProviderApiManagerV5 extends ProviderApiManagerBase implements IPro try { String serviceJson = bm.getService(); - ModelsEIPService service = JSON.createGson().create().fromJson(serviceJson, ModelsEIPService.class); - provider.setService(service); + provider.setService(serviceJson); } catch (Exception e) { return eventSender.setErrorResult(currentDownload, R.string.config_error_found, null); } @@ -133,23 +132,14 @@ public class ProviderApiManagerV5 extends ProviderApiManagerBase implements IPro if (PreferenceHelper.getUseBridges()) { try { String bridgesJson = bm.getAllBridges("", "", "", ""); - if (bridgesJson.isEmpty()) { - //TODO send no bridges error event - } - ModelsBridge[] bridges = JSON.createGson().create().fromJson(bridgesJson, ModelsBridge[].class); - provider.setBridges(bridges); + provider.setBridges(bridgesJson); } catch (Exception e) { // TODO: send failed to fetch bridges event } } else { try { String gatewaysJson = bm.getAllGateways("", "", ""); - if (gatewaysJson.isEmpty()) { - //TODO send no bridges error event - } - ModelsGateway[] gateways = JSON.createGson().create().fromJson(gatewaysJson, ModelsGateway[].class); - - provider.setGateways(gateways); + provider.setGateways(gatewaysJson); } catch (Exception e) { // TODO: send return eventSender.setErrorResult(currentDownload, R.string.config_error_found, null); @@ -171,29 +161,20 @@ public class ProviderApiManagerV5 extends ProviderApiManagerBase implements IPro return currentDownload; } - getPersistedProviderUpdates(provider); - currentDownload = validateProviderDetails(provider); - //provider certificate invalid if (currentDownload.containsKey(ERRORS)) { currentDownload.putParcelable(PROVIDER_KEY, provider); return currentDownload; } - //no provider json or certificate available - if (currentDownload.containsKey(BROADCAST_RESULT_KEY) && !currentDownload.getBoolean(BROADCAST_RESULT_KEY)) { - resetProviderDetails(provider); - } - - if (currentDownload.containsKey(PROVIDER_KEY)) { - provider = currentDownload.getParcelable(PROVIDER_KEY); - } BitmaskMobile bm; try { bm = new BitmaskMobile(provider.getMainUrl(), new PreferenceHelper.SharedPreferenceStore()); + bm.setDebug(BuildConfig.DEBUG); if (TorStatusObservable.isRunning() && TorStatusObservable.getSocksProxyPort() != -1) { bm.setSocksProxy(SOCKS_PROXY_SCHEME + PROXY_HOST + ":" + TorStatusObservable.getSocksProxyPort()); } + // TODO bm.setIntroducer(); } catch (IllegalStateException e) { // TODO: improve error message return eventSender.setErrorResult(currentDownload, R.string.config_error_found, null); @@ -204,8 +185,7 @@ public class ProviderApiManagerV5 extends ProviderApiManagerBase implements IPro try { String providerJson = bm.getProvider(); Log.d(TAG, "provider Json reponse: " + providerJson); - ModelsProvider p = JSON.createGson().create().fromJson(providerJson, ModelsProvider.class); - provider.setModelsProvider(p); + provider.setModelsProvider(providerJson); ProviderSetupObservable.updateProgress(DOWNLOADED_PROVIDER_JSON); } catch (Exception e) { Log.w(TAG, "failed fo fetch provider.json: " + e.getMessage()); @@ -215,8 +195,7 @@ public class ProviderApiManagerV5 extends ProviderApiManagerBase implements IPro try { String serviceJson = bm.getService(); Log.d(TAG, "service Json reponse: " + serviceJson); - ModelsEIPService service = JSON.createGson().create().fromJson(serviceJson, ModelsEIPService.class); - provider.setService(service); + provider.setService(serviceJson); ProviderSetupObservable.updateProgress(DOWNLOADED_EIP_SERVICE_JSON); } catch (Exception e) { Log.w(TAG, "failed to fetch service.json: " + e.getMessage()); @@ -228,8 +207,7 @@ public class ProviderApiManagerV5 extends ProviderApiManagerBase implements IPro // TODO: check if provider supports this API endpoint? String gatewaysJson = bm.getAllGateways("", "", ""); Log.d(TAG, "gateways Json reponse: " + gatewaysJson); - ModelsGateway[] gateways = JSON.createGson().create().fromJson(gatewaysJson, ModelsGateway[].class); - provider.setGateways(gateways); + provider.setGateways(gatewaysJson); } catch (Exception e) { Log.w(TAG, "failed to fetch gateways: " + e.getMessage()); e.printStackTrace(); @@ -240,8 +218,7 @@ public class ProviderApiManagerV5 extends ProviderApiManagerBase implements IPro // TODO: check if provider supports this API endpoint? String bridgesJson = bm.getAllBridges("", "", "", ""); Log.d(TAG, "bridges Json reponse: " + bridgesJson); - ModelsBridge[] bridges = JSON.createGson().create().fromJson(bridgesJson, ModelsBridge[].class); - provider.setBridges(bridges); + provider.setBridges(bridgesJson); } catch (Exception e) { Log.w(TAG, "failed to fetch bridges: " + e.getMessage()); e.printStackTrace(); @@ -250,7 +227,7 @@ public class ProviderApiManagerV5 extends ProviderApiManagerBase implements IPro try { String cert = bm.getOpenVPNCert(); - currentDownload = loadCertificate(provider, cert); + currentDownload = loadCredentials(provider, cert); } catch (Exception e) { return eventSender.setErrorResult(currentDownload, R.string.error_json_exception_user_message, null); } @@ -258,6 +235,19 @@ public class ProviderApiManagerV5 extends ProviderApiManagerBase implements IPro return currentDownload; } + private Bundle loadCredentials(Provider provider, String credentials) { + Bundle result = new Bundle(); + + try { + CredentialsParser.parseXml(credentials, provider); + } catch (XmlPullParserException | IOException e) { + return eventSender.setErrorResult(result, vpn_certificate_is_invalid, null); + } + + result.putBoolean(BROADCAST_RESULT_KEY, true); + return result; + } + @Nullable private void configureBaseCountryCode(BitmaskMobile bm, Bundle parameters) { String cc = parameters.getString(COUNTRYCODE, null); 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 2b322586..8b4b7ad8 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 @@ -228,23 +228,19 @@ public class ConfigureProviderFragment extends BaseSetupFragment implements Prop switch (resultCode) { case PROVIDER_OK: setupActivityCallback.onProviderSelected(provider); - if (provider.allowsAnonymous()) { - ProviderAPICommand.execute(this.getContext(), DOWNLOAD_VPN_CERTIFICATE, provider); + if (provider.getApiVersion() < 5) { + if (provider.allowsAnonymous()) { + ProviderAPICommand.execute(this.getContext(), DOWNLOAD_VPN_CERTIFICATE, provider); + } else { + // TODO: implement error message that this client only supports anonymous usage + } } else { - // TODO: implement error message that this client only supports anonymous usage + sendSuccess(resumeSetup); } break; case CORRECTLY_DOWNLOADED_VPN_CERTIFICATE: setupActivityCallback.onProviderSelected(provider); - handler.postDelayed(() -> { - if (!ProviderSetupObservable.isCanceled()) { - try { - setupActivityCallback.onConfigurationSuccess(); - } catch (NullPointerException npe) { - // callback disappeared in the meanwhile - } - } - }, resumeSetup ? 0 : 750); + sendSuccess(resumeSetup); break; case PROVIDER_NOK: case INCORRECTLY_DOWNLOADED_VPN_CERTIFICATE: @@ -258,4 +254,15 @@ public class ConfigureProviderFragment extends BaseSetupFragment implements Prop } } + private void sendSuccess(boolean resumeSetup) { + handler.postDelayed(() -> { + if (!ProviderSetupObservable.isCanceled()) { + try { + setupActivityCallback.onConfigurationSuccess(); + } catch (NullPointerException npe) { + // callback disappeared in the meanwhile + } + } + }, resumeSetup ? 0 : 750); + } }
\ No newline at end of file diff --git a/app/src/test/java/se/leap/bitmaskclient/providersetup/ProviderManagerTest.java b/app/src/test/java/se/leap/bitmaskclient/providersetup/ProviderManagerTest.java index d76e87c2..7cca9c2f 100644 --- a/app/src/test/java/se/leap/bitmaskclient/providersetup/ProviderManagerTest.java +++ b/app/src/test/java/se/leap/bitmaskclient/providersetup/ProviderManagerTest.java @@ -67,7 +67,7 @@ public class ProviderManagerTest { preferenceHelper = new PreferenceHelper(mockSharedPrefs); HashSet<Provider> customProviders = new HashSet<>(); - customProviders.add(Provider.createCustomProvider("https://leapcolombia.org", "leapcolombia.org")); + customProviders.add(Provider.createCustomProvider("https://leapcolombia.org", "leapcolombia.org", null)); PreferenceHelper.setCustomProviders(customProviders); } |