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/src | |
| parent | ab4c3397c501e059849d16f05fa211d5ebd3c4db (diff) | |
update bitmask-core API, store v5 provider details
Diffstat (limited to 'app/src')
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);      } | 
