summaryrefslogtreecommitdiff
path: root/app
diff options
context:
space:
mode:
Diffstat (limited to 'app')
-rw-r--r--app/build.gradle2
-rw-r--r--app/src/debug/java/se/leap/bitmaskclient/ProviderAPI.java79
-rw-r--r--app/src/main/AndroidManifest.xml4
-rw-r--r--app/src/main/java/de/blinkt/openvpn/LaunchVPN.java30
-rw-r--r--app/src/main/java/de/blinkt/openvpn/VpnProfile.java21
-rw-r--r--app/src/main/java/de/blinkt/openvpn/core/ConfigParser.java8
-rw-r--r--app/src/main/java/de/blinkt/openvpn/core/OpenVpnService.java12
-rw-r--r--app/src/main/java/de/blinkt/openvpn/fragments/LogFragment.java93
-rw-r--r--app/src/main/java/se/leap/bitmaskclient/Dashboard.java6
-rw-r--r--app/src/main/java/se/leap/bitmaskclient/EIP.java254
-rw-r--r--app/src/main/java/se/leap/bitmaskclient/EipServiceFragment.java3
-rw-r--r--app/src/main/java/se/leap/bitmaskclient/Provider.java1
-rw-r--r--app/src/main/res/drawable-hdpi/ic_stat_vpn.pngbin0 -> 539 bytes
-rw-r--r--app/src/main/res/drawable-hdpi/ic_stat_vpn_empty_halo.pngbin816 -> 721 bytes
-rw-r--r--app/src/main/res/drawable-hdpi/ic_stat_vpn_offline.pngbin637 -> 801 bytes
l---------[-rw-r--r--]app/src/main/res/drawable-hdpi/ic_stat_vpn_outline.pngbin863 -> 28 bytes
-rw-r--r--app/src/main/res/drawable-hdpi/ic_vpn_disconnected.pngbin801 -> 0 bytes
-rw-r--r--app/src/main/res/drawable-ldpi/ic_stat_vpn.pngbin461 -> 757 bytes
-rw-r--r--app/src/main/res/drawable-ldpi/ic_stat_vpn_empty_halo.pngbin0 -> 404 bytes
-rw-r--r--app/src/main/res/drawable-ldpi/ic_stat_vpn_offline.pngbin0 -> 455 bytes
l---------app/src/main/res/drawable-ldpi/ic_stat_vpn_outline.png1
-rw-r--r--app/src/main/res/drawable-mdpi/ic_stat_vpn.pngbin0 -> 502 bytes
-rw-r--r--app/src/main/res/drawable-mdpi/ic_stat_vpn_empty_halo.pngbin545 -> 504 bytes
-rw-r--r--app/src/main/res/drawable-mdpi/ic_stat_vpn_offline.pngbin451 -> 586 bytes
l---------[-rw-r--r--]app/src/main/res/drawable-mdpi/ic_stat_vpn_outline.pngbin609 -> 28 bytes
-rw-r--r--app/src/main/res/drawable-xhdpi/ic_stat_vpn.pngbin0 -> 688 bytes
-rw-r--r--app/src/main/res/drawable-xhdpi/ic_stat_vpn_empty_halo.pngbin1033 -> 902 bytes
-rw-r--r--app/src/main/res/drawable-xhdpi/ic_stat_vpn_offline.pngbin834 -> 1091 bytes
l---------[-rw-r--r--]app/src/main/res/drawable-xhdpi/ic_stat_vpn_outline.pngbin1151 -> 28 bytes
-rw-r--r--app/src/main/res/layout/about.xml6
-rw-r--r--app/src/main/res/layout/client_dashboard.xml58
-rw-r--r--app/src/main/res/menu/logmenu.xml5
-rwxr-xr-xapp/src/main/res/values-de/strings-icsopenvpn.xml6
-rw-r--r--app/src/main/res/values-es/strings.xml2
-rw-r--r--app/src/main/res/values/strings.xml7
-rw-r--r--app/src/main/res/values/untranslatable.xml118
-rw-r--r--app/src/release/java/se/leap/bitmaskclient/ProviderAPI.java99
37 files changed, 503 insertions, 312 deletions
diff --git a/app/build.gradle b/app/build.gradle
index 8c60eb0f..a57a2763 100644
--- a/app/build.gradle
+++ b/app/build.gradle
@@ -144,4 +144,4 @@ task mergeUntranslatable( type: Copy, dependsOn: 'removeDuplicatedStrings') {
delete ics_openvpn_untranslatable
}
-build.dependsOn ':app:mergeUntranslatable' \ No newline at end of file
+//build.dependsOn ':app:mergeUntranslatable' \ No newline at end of file
diff --git a/app/src/debug/java/se/leap/bitmaskclient/ProviderAPI.java b/app/src/debug/java/se/leap/bitmaskclient/ProviderAPI.java
index dd7af633..b17d6bb4 100644
--- a/app/src/debug/java/se/leap/bitmaskclient/ProviderAPI.java
+++ b/app/src/debug/java/se/leap/bitmaskclient/ProviderAPI.java
@@ -16,12 +16,20 @@
*/
package se.leap.bitmaskclient;
+import android.app.IntentService;
+import android.content.Intent;
+import android.os.Bundle;
+import android.os.Handler;
+import android.os.ResultReceiver;
+import android.util.Base64;
+import android.util.Log;
import java.io.DataOutputStream;
import java.io.FileNotFoundException;
import java.io.IOException;
import java.io.InputStream;
import java.io.UnsupportedEncodingException;
import java.math.BigInteger;
+import java.net.ConnectException;
import java.net.CookieHandler;
import java.net.CookieManager;
import java.net.CookiePolicy;
@@ -45,30 +53,21 @@ import java.util.HashMap;
import java.util.Iterator;
import java.util.Map;
import java.util.Scanner;
-
import javax.net.ssl.HostnameVerifier;
import javax.net.ssl.HttpsURLConnection;
import javax.net.ssl.KeyManager;
import javax.net.ssl.SSLContext;
+import javax.net.ssl.SSLHandshakeException;
import javax.net.ssl.SSLSession;
import javax.net.ssl.TrustManager;
import javax.net.ssl.TrustManagerFactory;
import javax.net.ssl.X509TrustManager;
-
import org.apache.http.client.ClientProtocolException;
import org.jboss.security.srp.SRPParameters;
import org.json.JSONException;
import org.json.JSONObject;
-
-import se.leap.bitmaskclient.R;
import se.leap.bitmaskclient.ProviderListContent.ProviderItem;
-import android.app.IntentService;
-import android.content.Intent;
-import android.os.Bundle;
-import android.os.Handler;
-import android.os.ResultReceiver;
-import android.util.Base64;
-import android.util.Log;
+import se.leap.bitmaskclient.R;
/**
@@ -193,7 +192,7 @@ public class ProviderAPI extends IntentService {
receiver.send(LOGOUT_FAILED, Bundle.EMPTY);
}
} else if (action.equalsIgnoreCase(DOWNLOAD_CERTIFICATE)) {
- if(getNewCert(parameters)) {
+ if(updateVpnCertificate()) {
receiver.send(CORRECTLY_DOWNLOADED_CERTIFICATE, Bundle.EMPTY);
} else {
receiver.send(INCORRECTLY_DOWNLOADED_CERTIFICATE, Bundle.EMPTY);
@@ -426,7 +425,7 @@ public class ProviderAPI extends IntentService {
parameters.put("user[password_verifier]", password_verifier);
Log.d(TAG, server_url);
Log.d(TAG, parameters.toString());
- return sendToServer(server_url + "/users", "POST", parameters);
+ return sendToServer(server_url + "/users.json", "POST", parameters);
}
/**
@@ -538,16 +537,16 @@ public class ProviderAPI extends IntentService {
CA_CERT_DOWNLOADED = PROVIDER_JSON_DOWNLOADED = EIP_SERVICE_JSON_DOWNLOADED = false;
}
- if(!CA_CERT_DOWNLOADED)
- current_download = downloadCACert(last_provider_main_url, last_danger_on);
- if(CA_CERT_DOWNLOADED || (current_download.containsKey(RESULT_KEY) && current_download.getBoolean(RESULT_KEY))) {
- broadcast_progress(progress++);
- CA_CERT_DOWNLOADED = true;
if(!PROVIDER_JSON_DOWNLOADED)
current_download = getAndSetProviderJson(last_provider_main_url, last_danger_on);
if(PROVIDER_JSON_DOWNLOADED || (current_download.containsKey(RESULT_KEY) && current_download.getBoolean(RESULT_KEY))) {
+ broadcast_progress(progress++);
+ PROVIDER_JSON_DOWNLOADED = true;
+ current_download = downloadCACert(last_danger_on);
+
+ if(CA_CERT_DOWNLOADED || (current_download.containsKey(RESULT_KEY) && current_download.getBoolean(RESULT_KEY))) {
broadcast_progress(progress++);
- PROVIDER_JSON_DOWNLOADED = true;
+ CA_CERT_DOWNLOADED = true;
current_download = getAndSetEipServiceJson();
if(current_download.containsKey(RESULT_KEY) && current_download.getBoolean(RESULT_KEY)) {
broadcast_progress(progress++);
@@ -559,17 +558,25 @@ public class ProviderAPI extends IntentService {
return current_download;
}
- private Bundle downloadCACert(String provider_main_url, boolean danger_on) {
+ private Bundle downloadCACert(boolean danger_on) {
Bundle result = new Bundle();
- String cert_string = downloadWithCommercialCA(provider_main_url + "/ca.crt", danger_on);
+ try {
+ JSONObject provider_json = new JSONObject(getSharedPreferences(Dashboard.SHARED_PREFERENCES, MODE_PRIVATE).getString(Provider.KEY, ""));
+ String ca_cert_url = provider_json.getString(Provider.CA_CERT_URI);
+ String cert_string = downloadWithCommercialCA(ca_cert_url, danger_on);
- if(validCertificate(cert_string) && setting_up_provider) {
- getSharedPreferences(Dashboard.SHARED_PREFERENCES, MODE_PRIVATE).edit().putString(Provider.CA_CERT, cert_string).commit();
+ if(validCertificate(cert_string) && setting_up_provider) {
+ getSharedPreferences(Dashboard.SHARED_PREFERENCES, MODE_PRIVATE).edit().putString(Provider.CA_CERT, cert_string).commit();
result.putBoolean(RESULT_KEY, true);
- } else {
+ } else {
String reason_to_fail = pickErrorMessage(cert_string);
result.putString(ERRORS, reason_to_fail);
result.putBoolean(RESULT_KEY, false);
+ }
+ } catch (JSONException e) {
+ String reason_to_fail = formatErrorMessage(R.string.malformed_url);
+ result.putString(ERRORS, reason_to_fail);
+ result.putBoolean(RESULT_KEY, false);
}
return result;
@@ -697,12 +704,16 @@ public class ProviderAPI extends IntentService {
json_file_content = formatErrorMessage(R.string.malformed_url);
} catch(SocketTimeoutException e) {
json_file_content = formatErrorMessage(R.string.server_unreachable_message);
- } catch (IOException e) {
+ } catch (SSLHandshakeException e) {
if(provider_url != null) {
- json_file_content = downloadWithProviderCA(string_url, danger_on);
+ json_file_content = downloadWithProviderCA(string_url, danger_on);
} else {
json_file_content = formatErrorMessage(R.string.certificate_error);
}
+ } catch(ConnectException e) {
+ json_file_content = formatErrorMessage(R.string.service_is_down_error);
+ } catch (FileNotFoundException e) {
+ json_file_content = formatErrorMessage(R.string.malformed_url);
} catch (Exception e) {
if(provider_url != null && danger_on) {
json_file_content = downloadWithProviderCA(string_url, danger_on);
@@ -817,7 +828,7 @@ public class ProviderAPI extends IntentService {
System.out.println("String ignoring certificate = " + string);
} catch (FileNotFoundException e) {
e.printStackTrace();
- string = formatErrorMessage(R.string.server_unreachable_message);
+ string = formatErrorMessage(R.string.malformed_url);
} catch (IOException e) {
// The downloaded certificate doesn't validate our https connection.
e.printStackTrace();
@@ -878,16 +889,24 @@ public class ProviderAPI extends IntentService {
return true;
}
+ private boolean updateVpnCertificate() {
+ getNewCert();
+
+ getSharedPreferences(Dashboard.SHARED_PREFERENCES, MODE_PRIVATE).edit().putInt(EIP.PARSED_SERIAL, 0).commit();
+ Intent updateEIP = new Intent(getApplicationContext(), EIP.class);
+ updateEIP.setAction(EIP.ACTION_UPDATE_EIP_SERVICE);
+ startService(updateEIP);
+
+ return true;
+ }
/**
* Downloads a new OpenVPN certificate, attaching authenticated cookie for authenticated certificate.
*
- * @param task containing the type of the certificate to be downloaded
* @return true if certificate was downloaded correctly, false if provider.json or danger_on flag are not present in SharedPreferences, or if the certificate url could not be parsed as a URI, or if there was an SSL error.
*/
- private boolean getNewCert(Bundle task) {
+ private boolean getNewCert() {
try {
- String type_of_certificate = task.getString(ConfigurationWizard.TYPE_OF_CERTIFICATE);
JSONObject provider_json = new JSONObject(getSharedPreferences(Dashboard.SHARED_PREFERENCES, MODE_PRIVATE).getString(Provider.KEY, ""));
String provider_main_url = provider_json.getString(Provider.API_URL);
diff --git a/app/src/main/AndroidManifest.xml b/app/src/main/AndroidManifest.xml
index a2c2a82f..f73d59cb 100644
--- a/app/src/main/AndroidManifest.xml
+++ b/app/src/main/AndroidManifest.xml
@@ -17,8 +17,8 @@
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
package="se.leap.bitmaskclient"
- android:versionCode="79"
- android:versionName="0.5.2" >
+ android:versionCode="84"
+ android:versionName="0.5.3" >
<uses-permission android:name="android.permission.INTERNET" />
<uses-permission android:name="android.permission.ACCESS_NETWORK_STATE" />
diff --git a/app/src/main/java/de/blinkt/openvpn/LaunchVPN.java b/app/src/main/java/de/blinkt/openvpn/LaunchVPN.java
index f8487891..a39e780a 100644
--- a/app/src/main/java/de/blinkt/openvpn/LaunchVPN.java
+++ b/app/src/main/java/de/blinkt/openvpn/LaunchVPN.java
@@ -110,28 +110,28 @@ public class LaunchVPN extends Activity {
}
}
-
+
+
@Override
protected void onActivityResult (int requestCode, int resultCode, Intent data) {
super.onActivityResult(requestCode, resultCode, data);
if(requestCode==START_VPN_PROFILE) {
- if(resultCode == Activity.RESULT_OK) {
- SharedPreferences prefs = PreferenceManager.getDefaultSharedPreferences(this);
- boolean showlogwindow = prefs.getBoolean("showlogwindow", true);
-
- if(!mhideLog && showlogwindow)
- showLogWindow();
- new startOpenVpnThread().start();
- } else if (resultCode == Activity.RESULT_CANCELED) {
- // User does not want us to start, so we just vanish
- VpnStatus.updateStateString("USER_VPN_PERMISSION_CANCELLED", "", R.string.state_user_vpn_permission_cancelled,
- ConnectionStatus.LEVEL_NOTCONNECTED);
-
- finish();
- }
+ SharedPreferences prefs = PreferenceManager.getDefaultSharedPreferences(this);
+ boolean showlogwindow = prefs.getBoolean("showlogwindow", true);
+
+ if(!mhideLog && showlogwindow)
+ showLogWindow();
+ new startOpenVpnThread().start();
+ } else if (resultCode == Activity.RESULT_CANCELED) {
+ // User does not want us to start, so we just vanish
+ VpnStatus.updateStateString("USER_VPN_PERMISSION_CANCELLED", "", R.string.state_user_vpn_permission_cancelled,
+ ConnectionStatus.LEVEL_NOTCONNECTED);
+
+ finish();
}
}
+
void showLogWindow() {
Intent startLW = new Intent(getBaseContext(),LogWindow.class);
diff --git a/app/src/main/java/de/blinkt/openvpn/VpnProfile.java b/app/src/main/java/de/blinkt/openvpn/VpnProfile.java
index d21a085f..0166eb98 100644
--- a/app/src/main/java/de/blinkt/openvpn/VpnProfile.java
+++ b/app/src/main/java/de/blinkt/openvpn/VpnProfile.java
@@ -4,10 +4,6 @@ import se.leap.bitmaskclient.R;
import se.leap.bitmaskclient.R;
-import se.leap.bitmaskclient.EIP;
-import se.leap.bitmaskclient.Dashboard;
-import se.leap.bitmaskclient.Provider;
-
import android.content.Context;
import android.content.Intent;
import android.content.SharedPreferences;
@@ -95,7 +91,7 @@ public class VpnProfile implements Serializable {
// but needs to keep wrong name to guarante loading of old
// profiles
public transient boolean profileDleted = false;
- public int mAuthenticationType = TYPE_CERTIFICATES;
+ public int mAuthenticationType = TYPE_KEYSTORE;
public String mName;
public String mAlias;
public String mClientCertFilename;
@@ -281,13 +277,14 @@ public class VpnProfile implements Serializable {
switch (mAuthenticationType) {
case VpnProfile.TYPE_USERPASS_CERTIFICATES:
cfg += "auth-user-pass\n";
- case VpnProfile.TYPE_CERTIFICATES:
- // FIXME This is all we need...The whole switch statement can go...
- SharedPreferences preferences = context.getSharedPreferences(Dashboard.SHARED_PREFERENCES, context.MODE_PRIVATE);
- cfg+="<ca>\n"+preferences.getString(Provider.CA_CERT, "")+"\n</ca>\n";
- cfg+="<key>\n"+preferences.getString(EIP.PRIVATE_KEY, "")+"\n</key>\n";
- cfg+="<cert>\n"+preferences.getString(EIP.CERTIFICATE, "")+"\n</cert>\n";
-
+ case VpnProfile.TYPE_CERTIFICATES:
+ // Ca
+ cfg += insertFileData("ca", mCaFilename);
+
+ // Client Cert + Key
+ cfg += insertFileData("key", mClientKeyFilename);
+ cfg += insertFileData("cert", mClientCertFilename);
+
break;
case VpnProfile.TYPE_USERPASS_PKCS12:
cfg += "auth-user-pass\n";
diff --git a/app/src/main/java/de/blinkt/openvpn/core/ConfigParser.java b/app/src/main/java/de/blinkt/openvpn/core/ConfigParser.java
index 4fbbe165..378b6b92 100644
--- a/app/src/main/java/de/blinkt/openvpn/core/ConfigParser.java
+++ b/app/src/main/java/de/blinkt/openvpn/core/ConfigParser.java
@@ -26,14 +26,6 @@ public class ConfigParser {
private boolean extraRemotesAsCustom=false;
- /*
- * TODO: We shouldn't be using this method.
- * We need to figure out how to use just parseConfig, probably removing parseOptions.
- */
- public void setDefinition(HashMap<String,Vector<Vector<String>>> args) {
- options = args;
- }
-
public void parseConfig(Reader reader) throws IOException, ConfigParseError {
diff --git a/app/src/main/java/de/blinkt/openvpn/core/OpenVpnService.java b/app/src/main/java/de/blinkt/openvpn/core/OpenVpnService.java
index b5bba5d4..43b27212 100644
--- a/app/src/main/java/de/blinkt/openvpn/core/OpenVpnService.java
+++ b/app/src/main/java/de/blinkt/openvpn/core/OpenVpnService.java
@@ -34,7 +34,6 @@ import se.leap.bitmaskclient.BuildConfig;
import se.leap.bitmaskclient.R;
import de.blinkt.openvpn.VpnProfile;
import de.blinkt.openvpn.activities.DisconnectVPN;
-import de.blinkt.openvpn.activities.LogWindow;
import de.blinkt.openvpn.core.VpnStatus.ByteCountListener;
import de.blinkt.openvpn.core.VpnStatus.ConnectionStatus;
import de.blinkt.openvpn.core.VpnStatus.StateListener;
@@ -44,6 +43,8 @@ import static de.blinkt.openvpn.core.VpnStatus.ConnectionStatus.LEVEL_CONNECTED;
import static de.blinkt.openvpn.core.VpnStatus.ConnectionStatus.LEVEL_CONNECTING_NO_SERVER_REPLY_YET;
import static de.blinkt.openvpn.core.VpnStatus.ConnectionStatus.LEVEL_WAITING_FOR_USER_INPUT;
+import se.leap.bitmaskclient.Dashboard;
+
public class OpenVpnService extends VpnService implements StateListener, Callback, ByteCountListener {
public static final String START_SERVICE = "de.blinkt.openvpn.START_SERVICE";
public static final String START_SERVICE_STICKY = "de.blinkt.openvpn.START_SERVICE_STICKY";
@@ -72,13 +73,6 @@ public class OpenVpnService extends VpnService implements StateListener, Callbac
private String mLastTunCfg;
private String mRemoteGW;
- //TODO We should know if this is running or not without this method
- public boolean isRunning() {
- if (mStarting == true || mProcessThread != null)
- return true;
- else
- return false;
- }
// From: http://stackoverflow.com/questions/3758606/how-to-convert-byte-size-into-human-readable-format-in-java
public static String humanReadableByteCount(long bytes, boolean mbit) {
if (mbit)
@@ -243,7 +237,7 @@ public class OpenVpnService extends VpnService implements StateListener, Callbac
PendingIntent getLogPendingIntent() {
// Let the configure Button show the Log
- Intent intent = new Intent(getBaseContext(), se.leap.bitmaskclient.Dashboard.class);
+ Intent intent = new Intent(getBaseContext(), Dashboard.class);
intent.addFlags(Intent.FLAG_ACTIVITY_REORDER_TO_FRONT);
PendingIntent startLW = PendingIntent.getActivity(this, 0, intent, 0);
intent.addFlags(Intent.FLAG_ACTIVITY_REORDER_TO_FRONT);
diff --git a/app/src/main/java/de/blinkt/openvpn/fragments/LogFragment.java b/app/src/main/java/de/blinkt/openvpn/fragments/LogFragment.java
index 2f04d235..6e592121 100644
--- a/app/src/main/java/de/blinkt/openvpn/fragments/LogFragment.java
+++ b/app/src/main/java/de/blinkt/openvpn/fragments/LogFragment.java
@@ -7,33 +7,39 @@ import se.leap.bitmaskclient.R;
import android.animation.Animator;
import android.animation.AnimatorListenerAdapter;
import android.animation.ObjectAnimator;
-import android.app.*;
-import android.content.*;
+import android.app.Activity;
+import android.app.AlertDialog;
+import android.app.ListFragment;
+import android.content.ClipData;
+import android.content.ClipboardManager;
+import android.content.Context;
+import android.content.DialogInterface;
+import android.content.Intent;
import android.database.DataSetObserver;
import android.graphics.drawable.Drawable;
import android.os.Bundle;
import android.os.Handler;
import android.os.Handler.Callback;
-import android.os.IBinder;
import android.os.Message;
import android.text.SpannableString;
import android.text.format.DateFormat;
import android.text.style.ImageSpan;
-import android.view.*;
-import android.widget.*;
+import android.view.LayoutInflater;
+import android.view.Menu;
+import android.view.MenuInflater;
+import android.view.MenuItem;
+import android.view.View;
+import android.view.ViewGroup;
+import android.widget.AdapterView;
import android.widget.AdapterView.OnItemLongClickListener;
-import de.blinkt.openvpn.*;
-import de.blinkt.openvpn.activities.DisconnectVPN;
-import se.leap.bitmaskclient.Dashboard;
-import de.blinkt.openvpn.core.OpenVPNManagement;
-import de.blinkt.openvpn.core.VpnStatus;
-import de.blinkt.openvpn.core.VpnStatus.ConnectionStatus;
-import de.blinkt.openvpn.core.VpnStatus.LogItem;
-import de.blinkt.openvpn.core.VpnStatus.LogListener;
-import de.blinkt.openvpn.core.VpnStatus.StateListener;
-import de.blinkt.openvpn.core.OpenVpnService;
-import de.blinkt.openvpn.core.OpenVpnService.LocalBinder;
-import de.blinkt.openvpn.core.ProfileManager;
+import android.widget.LinearLayout;
+import android.widget.ListAdapter;
+import android.widget.ListView;
+import android.widget.RadioGroup;
+import android.widget.SeekBar;
+import android.widget.TextView;
+import android.widget.Toast;
+
import org.jetbrains.annotations.Nullable;
import java.text.SimpleDateFormat;
@@ -42,31 +48,29 @@ import java.util.Date;
import java.util.Locale;
import java.util.Vector;
+import de.blinkt.openvpn.LaunchVPN;
+import se.leap.bitmaskclient.R;
+import de.blinkt.openvpn.VpnProfile;
+import de.blinkt.openvpn.activities.DisconnectVPN;
+import de.blinkt.openvpn.core.OpenVPNManagement;
+import de.blinkt.openvpn.core.OpenVpnService;
+import de.blinkt.openvpn.core.ProfileManager;
+import de.blinkt.openvpn.core.VpnStatus;
+import de.blinkt.openvpn.core.VpnStatus.ConnectionStatus;
+import de.blinkt.openvpn.core.VpnStatus.LogItem;
+import de.blinkt.openvpn.core.VpnStatus.LogListener;
+import de.blinkt.openvpn.core.VpnStatus.StateListener;
+
import static de.blinkt.openvpn.core.OpenVpnService.humanReadableByteCount;
+import se.leap.bitmaskclient.Dashboard;
+
public class LogFragment extends ListFragment implements StateListener, SeekBar.OnSeekBarChangeListener, RadioGroup.OnCheckedChangeListener, VpnStatus.ByteCountListener {
private static final String LOGTIMEFORMAT = "logtimeformat";
private static final int START_VPN_CONFIG = 0;
private static final String VERBOSITYLEVEL = "verbositylevel";
- protected OpenVpnService mService;
- private ServiceConnection mConnection = new ServiceConnection() {
- @Override
- public void onServiceConnected(ComponentName className,
- IBinder service) {
- // We've bound to LocalService, cast the IBinder and get LocalService instance
- LocalBinder binder = (LocalBinder) service;
- mService = binder.getService();
- }
-
- @Override
- public void onServiceDisconnected(ComponentName arg0) {
- mService =null;
- }
-
- };
-
private SeekBar mLogLevelSlider;
private LinearLayout mOptionsLayout;
private RadioGroup mTimeRadioGroup;
@@ -425,8 +429,18 @@ public class LogFragment extends ListFragment implements StateListener, SeekBar.
Intent intent = new Intent(getActivity(),DisconnectVPN.class);
startActivity(intent);
return true;
- } else if(item.getItemId()==R.id.send) {
+ } else if(item.getItemId()==R.id.send) {
ladapter.shareLog();
+ } else if(item.getItemId()==R.id.edit_vpn) {
+ VpnProfile lastConnectedprofile = ProfileManager.getLastConnectedVpn();
+
+ if(lastConnectedprofile!=null) {
+ Intent vprefintent = new Intent(getActivity(),Dashboard.class)
+ .putExtra(VpnProfile.EXTRA_PROFILEUUID,lastConnectedprofile.getUUIDString());
+ startActivityForResult(vprefintent,START_VPN_CONFIG);
+ } else {
+ Toast.makeText(getActivity(), R.string.log_no_last_vpn, Toast.LENGTH_LONG).show();
+ }
} else if(item.getItemId() == R.id.toggle_time) {
showHideOptionsPanel();
} else if(item.getItemId() == android.R.id.home) {
@@ -492,10 +506,6 @@ public class LogFragment extends ListFragment implements StateListener, SeekBar.
Intent intent = new Intent(getActivity(), OpenVpnService.class);
intent.setAction(OpenVpnService.START_SERVICE);
- getActivity().bindService(intent, mConnection, Context.BIND_AUTO_CREATE);
-
-
-
}
@@ -531,14 +541,13 @@ public class LogFragment extends ListFragment implements StateListener, SeekBar.
super.onActivityResult(requestCode, resultCode, data);
}
- @Override
+
+ @Override
public void onStop() {
super.onStop();
VpnStatus.removeStateListener(this);
VpnStatus.removeByteCountListener(this);
- if(mService!=null)
- getActivity().unbindService(mConnection);
getActivity().getPreferences(0).edit().putInt(LOGTIMEFORMAT, ladapter.mTimeFormat)
.putInt(VERBOSITYLEVEL, ladapter.mLogLevel).apply();
diff --git a/app/src/main/java/se/leap/bitmaskclient/Dashboard.java b/app/src/main/java/se/leap/bitmaskclient/Dashboard.java
index f2763d84..cb451b86 100644
--- a/app/src/main/java/se/leap/bitmaskclient/Dashboard.java
+++ b/app/src/main/java/se/leap/bitmaskclient/Dashboard.java
@@ -496,7 +496,7 @@ public class Dashboard extends Activity implements LogInDialog.LogInDialogInterf
case ProviderAPI.SRP_AUTHENTICATION_FAILED: eipStatus.setText(R.string.authentication_failed_message); break;
case ProviderAPI.CORRECTLY_DOWNLOADED_CERTIFICATE: eipStatus.setText(R.string.authed_secured_status); break;
case ProviderAPI.INCORRECTLY_DOWNLOADED_CERTIFICATE: eipStatus.setText(R.string.incorrectly_downloaded_certificate_message); break;
- case ProviderAPI.LOGOUT_SUCCESSFUL: eipStatus.setText(R.string.anonymous_secured_status); break;
+ case ProviderAPI.LOGOUT_SUCCESSFUL: eipStatus.setText(R.string.logged_out_message); break;
case ProviderAPI.LOGOUT_FAILED: eipStatus.setText(R.string.log_out_failed_message); break;
}
@@ -507,9 +507,9 @@ public class Dashboard extends Activity implements LogInDialog.LogInDialogInterf
case ProviderAPI.SRP_AUTHENTICATION_SUCCESSFUL: eipStatus.setText(R.string.succesful_authentication_message); break;
case ProviderAPI.SRP_AUTHENTICATION_FAILED: eipStatus.setText(R.string.authentication_failed_message); break;
- case ProviderAPI.CORRECTLY_DOWNLOADED_CERTIFICATE: eipStatus.setText(R.string.future_authed_secured_status); break;
+ case ProviderAPI.CORRECTLY_DOWNLOADED_CERTIFICATE: break;
case ProviderAPI.INCORRECTLY_DOWNLOADED_CERTIFICATE: eipStatus.setText(R.string.incorrectly_downloaded_certificate_message); break;
- case ProviderAPI.LOGOUT_SUCCESSFUL: eipStatus.setText(R.string.future_anonymous_secured_status); break;
+ case ProviderAPI.LOGOUT_SUCCESSFUL: eipStatus.setText(R.string.logged_out_message); break;
case ProviderAPI.LOGOUT_FAILED: eipStatus.setText(R.string.log_out_failed_message); break;
}
}
diff --git a/app/src/main/java/se/leap/bitmaskclient/EIP.java b/app/src/main/java/se/leap/bitmaskclient/EIP.java
index 59faf93f..21a573fe 100644
--- a/app/src/main/java/se/leap/bitmaskclient/EIP.java
+++ b/app/src/main/java/se/leap/bitmaskclient/EIP.java
@@ -14,8 +14,10 @@
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
- package se.leap.bitmaskclient;
+package se.leap.bitmaskclient;
+import java.io.StringReader;
+import java.io.IOException;
import java.util.Calendar;
import java.util.Collection;
import java.util.HashMap;
@@ -31,6 +33,9 @@ import org.json.JSONException;
import org.json.JSONObject;
import se.leap.bitmaskclient.R;
+import se.leap.bitmaskclient.Dashboard;
+import se.leap.bitmaskclient.Provider;
+
import de.blinkt.openvpn.activities.DisconnectVPN;
import de.blinkt.openvpn.core.ConfigParser;
import de.blinkt.openvpn.core.ConfigParser.ConfigParseError;
@@ -40,12 +45,14 @@ import de.blinkt.openvpn.core.OpenVpnService;
import de.blinkt.openvpn.core.OpenVpnService.LocalBinder;
import de.blinkt.openvpn.core.ProfileManager;
import de.blinkt.openvpn.VpnProfile;
+
import android.app.Activity;
import android.app.IntentService;
import android.content.ComponentName;
import android.content.Context;
import android.content.Intent;
import android.content.ServiceConnection;
+import android.content.SharedPreferences;
import android.drm.DrmStore.Action;
import android.os.Bundle;
import android.os.IBinder;
@@ -60,6 +67,7 @@ import android.util.Log;
* gateways, and controlling {@link de.blinkt.openvpn.core.OpenVpnService} connections.
*
* @author Sean Leonard <meanderingcode@aetherislands.net>
+ * @author Parménides GV <parmegv@sdf.org>
*/
public final class EIP extends IntentService {
@@ -142,7 +150,7 @@ public final class EIP extends IntentService {
return bindService(bindIntent, mVpnServiceConn, BIND_AUTO_CREATE);
}
- private static ServiceConnection mVpnServiceConn = new ServiceConnection() {
+ private ServiceConnection mVpnServiceConn = new ServiceConnection() {
@Override
public void onServiceConnected(ComponentName name, IBinder service) {
LocalBinder binder = (LocalBinder) service;
@@ -151,7 +159,7 @@ public final class EIP extends IntentService {
if (mReceiver != null && mPending != null) {
- boolean running = mVpnService.isRunning();
+ boolean running = isConnected();
int resultCode = Activity.RESULT_CANCELED;
@@ -202,7 +210,7 @@ public final class EIP extends IntentService {
Bundle resultData = new Bundle();
resultData.putString(REQUEST_TAG, ACTION_IS_EIP_RUNNING);
int resultCode = Activity.RESULT_CANCELED;
- boolean is_connected = getSharedPreferences(Dashboard.SHARED_PREFERENCES, MODE_PRIVATE).getString(STATUS, "").equalsIgnoreCase("LEVEL_CONNECTED");
+ boolean is_connected = isConnected();
if (mBound) {
resultCode = (is_connected) ? Activity.RESULT_OK : Activity.RESULT_CANCELED;
@@ -228,14 +236,19 @@ public final class EIP extends IntentService {
}
}
}
+
+ private boolean isConnected() {
+ return getSharedPreferences(Dashboard.SHARED_PREFERENCES, MODE_PRIVATE).getString(STATUS, "").equalsIgnoreCase("LEVEL_CONNECTED");
+ }
/**
* Initiates an EIP connection by selecting a gateway and preparing and sending an
* Intent to {@link se.leap.openvpn.LaunchVPN}
*/
private void startEIP() {
- activeGateway = selectGateway();
+ activeGateway = selectGateway();
+ if(activeGateway != null && activeGateway.mVpnProfile != null) {
Intent intent = new Intent(this,LaunchVPN.class);
intent.setAction(Intent.ACTION_MAIN);
intent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
@@ -245,6 +258,7 @@ public final class EIP extends IntentService {
intent.putExtra(RECEIVER_TAG, mReceiver);
startActivity(intent);
mPending = ACTION_START_EIP;
+ }
}
/**
@@ -466,7 +480,6 @@ public final class EIP extends IntentService {
}
}
- this.parseOptions();
this.createVPNProfile();
setUniqueProfileName(vpl);
@@ -502,125 +515,152 @@ public final class EIP extends IntentService {
}
}
- /**
- * FIXME This method is really the outline of the refactoring needed in se.leap.openvpn.ConfigParser
- */
- private void parseOptions(){
-
- // FIXME move these to a common API (& version) definition place, like ProviderAPI or ConfigHelper
- String common_options = "openvpn_configuration";
- String remote = "ip_address";
- String ports = "ports";
- String protos = "protocols";
- String capabilities = "capabilities";
- String location_key = "location";
- String locations = "locations";
-
- Vector<String> arg = new Vector<String>();
- Vector<Vector<String>> args = new Vector<Vector<String>>();
+ /**
+ * Parses data from eip-service.json to a section of the openvpn config file
+ */
+ private String configFromEipServiceDotJson() {
+ String parsed_configuration = "";
+
+ String common_options = "openvpn_configuration";
+ String remote = "ip_address";
+ String ports = "ports";
+ String protos = "protocols";
+ String capabilities = "capabilities";
+ String location_key = "location";
+ String locations = "locations";
+
+ Vector<String> arg = new Vector<String>();
+ Vector<Vector<String>> args = new Vector<Vector<String>>();
- try {
- JSONObject def = (JSONObject) eipDefinition.get(common_options);
- Iterator keys = def.keys();
- Vector<Vector<String>> value = new Vector<Vector<String>>();
- while ( keys.hasNext() ){
- String key = keys.next().toString();
+ try {
+ JSONObject openvpn_configuration = eipDefinition.getJSONObject(common_options);
+ Iterator keys = openvpn_configuration.keys();
+ Vector<Vector<String>> value = new Vector<Vector<String>>();
+ while ( keys.hasNext() ){
+ String key = keys.next().toString();
- arg.add(key);
- for ( String word : def.getString(key).split(" ") )
- arg.add(word);
- value.add( (Vector<String>) arg.clone() );
- options.put(key, (Vector<Vector<String>>) value.clone());
- value.clear();
- arg.clear();
- }
- } catch (JSONException e) {
- // TODO Auto-generated catch block
- e.printStackTrace();
- }
+ parsed_configuration += key + " ";
+ for ( String word : openvpn_configuration.getString(key).split(" ") )
+ parsed_configuration += word + " ";
+ parsed_configuration += System.getProperty("line.separator");
+
+ }
+ } catch (JSONException e) {
+ // TODO Auto-generated catch block
+ e.printStackTrace();
+ }
- // We are always client, because the ifconfig will be received by a needed command
- options.put("client", null);
+ parsed_configuration += "client" + System.getProperty("line.separator");
- try {
- arg.add(remote);
- arg.add(mGateway.getString(remote));
- } catch (JSONException e) {
- // TODO Auto-generated catch block
- e.printStackTrace();
- }
- args.add((Vector<String>) arg.clone());
- options.put("remote", (Vector<Vector<String>>) args.clone() );
- arg.clear();
- args.clear();
+ try {
+ JSONArray protocolsJSON = mGateway.getJSONObject(capabilities).getJSONArray(protos);
+ String remote_line = "remote";
+ for ( int i=0; i<protocolsJSON.length(); i++ ) {
+ remote_line += " " + mGateway.getString(remote);
+ remote_line += " " + mGateway.getJSONObject(capabilities).getJSONArray(ports).optString(0);
+ remote_line += " " + protocolsJSON.optString(i);
+ if(remote_line.endsWith("udp"))
+ parsed_configuration = parsed_configuration.replaceFirst(System.getProperty("line.separator") + "remote", System.getProperty("line.separator") + remote_line + System.getProperty("line.separator") + "remote");
+ else
+ parsed_configuration += remote_line;
+ remote_line = "remote";
+ parsed_configuration += System.getProperty("line.separator");
+ }
+ } catch (JSONException e) {
+ // TODO Auto-generated catch block
+ e.printStackTrace();
+ }
+
+ // try {
+ // arg.add(location_key);
+ // String locationText = "";
+ // locationText = eipDefinition.getJSONObject(locations).getJSONObject(mGateway.getString(location_key)).getString("name");
+ // arg.add(locationText);
+ // Log.d(TAG, "location = " + locationText);
+ // } catch (JSONException e) {
+ // // TODO Auto-generated catch block
+ // e.printStackTrace();
+ // }
+ // args.add((Vector<String>) arg.clone());
+ // options.put("location", (Vector<Vector<String>>) args.clone() );
-
- // try {
- // arg.add(location_key);
- // String locationText = "";
- // locationText = eipDefinition.getJSONObject(locations).getJSONObject(mGateway.getString(location_key)).getString("name");
- // arg.add(locationText);
- // Log.d(TAG, "location = " + locationText);
-
- // } catch (JSONException e) {
- // // TODO Auto-generated catch block
- // e.printStackTrace();
- // }
- // args.add((Vector<String>) arg.clone());
- // options.put("location", (Vector<Vector<String>>) args.clone() );
-
- // arg.clear();
- // args.clear();
- JSONArray protocolsJSON = null;
- arg.add("proto");
- try {
- protocolsJSON = mGateway.getJSONObject(capabilities).getJSONArray(protos);
- } catch (JSONException e) {
- // TODO Auto-generated catch block
- e.printStackTrace();
- }
- Vector<String> protocols = new Vector<String>();
- for ( int i=0; i<protocolsJSON.length(); i++ )
- protocols.add(protocolsJSON.optString(i));
- if ( protocols.contains("udp"))
- arg.add("udp");
- else if ( protocols.contains("tcp"))
- arg.add("tcp");
- args.add((Vector<String>) arg.clone());
- options.put("proto", (Vector<Vector<String>>) args.clone());
- arg.clear();
- args.clear();
-
-
- String port = null;
- arg.add("port");
- try {
- port = mGateway.getJSONObject(capabilities).getJSONArray(ports).optString(0);
- } catch (JSONException e) {
- // TODO Auto-generated catch block
- e.printStackTrace();
- }
- arg.add(port);
- args.add((Vector<String>) arg.clone());
- options.put("port", (Vector<Vector<String>>) args.clone());
- args.clear();
- arg.clear();
- }
+ // arg.clear();
+ // args.clear();
+ return parsed_configuration;
+ }
+
+
+ private String caSecretFromSharedPreferences() {
+ String secret_lines = "";
+ SharedPreferences preferences = context.getSharedPreferences(Dashboard.SHARED_PREFERENCES, context.MODE_PRIVATE);
+
+ System.getProperty("line.separator");
+ secret_lines += "<ca>";
+ secret_lines += System.getProperty("line.separator");
+ secret_lines += preferences.getString(Provider.CA_CERT, "");
+ secret_lines += System.getProperty("line.separator");
+ secret_lines += "</ca>";
+
+ return secret_lines;
+ }
+
+ private String keySecretFromSharedPreferences() {
+ String secret_lines = "";
+ SharedPreferences preferences = context.getSharedPreferences(Dashboard.SHARED_PREFERENCES, context.MODE_PRIVATE);
+
+ secret_lines += System.getProperty("line.separator");
+ secret_lines +="<key>";
+ secret_lines += System.getProperty("line.separator");
+ secret_lines += preferences.getString(EIP.PRIVATE_KEY, "");
+ secret_lines += System.getProperty("line.separator");
+ secret_lines += "</key>";
+ secret_lines += System.getProperty("line.separator");
+
+ return secret_lines;
+ }
+
+ private String certSecretFromSharedPreferences() {
+ String secret_lines = "";
+ SharedPreferences preferences = context.getSharedPreferences(Dashboard.SHARED_PREFERENCES, context.MODE_PRIVATE);
+
+ secret_lines += System.getProperty("line.separator");
+ secret_lines +="<cert>";
+ secret_lines += System.getProperty("line.separator");
+ secret_lines += preferences.getString(EIP.CERTIFICATE, "");
+ secret_lines += System.getProperty("line.separator");
+ secret_lines += "</cert>";
+ secret_lines += System.getProperty("line.separator");
+
+ return secret_lines;
+ }
+
/**
* Create and attach the VpnProfile to our gateway object
*/
protected void createVPNProfile(){
try {
ConfigParser cp = new ConfigParser();
- cp.setDefinition(options);
+ Log.d(TAG, configFromEipServiceDotJson());
+ Log.d(TAG, caSecretFromSharedPreferences());
+ Log.d(TAG, keySecretFromSharedPreferences());
+ Log.d(TAG, certSecretFromSharedPreferences());
+ cp.parseConfig(new StringReader(configFromEipServiceDotJson()));
+ cp.parseConfig(new StringReader(caSecretFromSharedPreferences()));
+ cp.parseConfig(new StringReader(keySecretFromSharedPreferences()));
+ cp.parseConfig(new StringReader(certSecretFromSharedPreferences()));
VpnProfile vp = cp.convertProfile();
+ //vp.mAuthenticationType=VpnProfile.TYPE_STATICKEYS;
mVpnProfile = vp;
Log.v(TAG,"Created VPNProfile");
} catch (ConfigParseError e) {
// FIXME We didn't get a VpnProfile! Error handling! and log level
- Log.v(TAG,"Error createing VPNProfile");
+ Log.v(TAG,"Error creating VPNProfile");
+ e.printStackTrace();
+ } catch (IOException e) {
+ // FIXME We didn't get a VpnProfile! Error handling! and log level
+ Log.v(TAG,"Error creating VPNProfile");
e.printStackTrace();
}
}
diff --git a/app/src/main/java/se/leap/bitmaskclient/EipServiceFragment.java b/app/src/main/java/se/leap/bitmaskclient/EipServiceFragment.java
index 446ba1d9..299d89a4 100644
--- a/app/src/main/java/se/leap/bitmaskclient/EipServiceFragment.java
+++ b/app/src/main/java/se/leap/bitmaskclient/EipServiceFragment.java
@@ -221,7 +221,8 @@ public class EipServiceFragment extends Fragment implements StateListener, OnChe
mEipStartPending = false;
} else if ( level == ConnectionStatus.LEVEL_NONETWORK || level == ConnectionStatus.LEVEL_NOTCONNECTED || level == ConnectionStatus.LEVEL_AUTH_FAILED) {
statusMessage = getString(R.string.eip_state_not_connected);
- getActivity().findViewById(R.id.eipProgress).setVisibility(View.GONE);
+ if(getActivity() != null && getActivity().findViewById(R.id.eipProgress) != null)
+ getActivity().findViewById(R.id.eipProgress).setVisibility(View.GONE);
mEipStartPending = false;
switchState = false;
} else if (level == ConnectionStatus.LEVEL_CONNECTING_SERVER_REPLIED) {
diff --git a/app/src/main/java/se/leap/bitmaskclient/Provider.java b/app/src/main/java/se/leap/bitmaskclient/Provider.java
index 216f4261..5326709f 100644
--- a/app/src/main/java/se/leap/bitmaskclient/Provider.java
+++ b/app/src/main/java/se/leap/bitmaskclient/Provider.java
@@ -51,6 +51,7 @@ public final class Provider implements Serializable {
SERVICE = "service",
KEY = "provider",
CA_CERT = "ca_cert",
+ CA_CERT_URI = "ca_cert_uri",
NAME = "name",
DESCRIPTION = "description",
DOMAIN = "domain",
diff --git a/app/src/main/res/drawable-hdpi/ic_stat_vpn.png b/app/src/main/res/drawable-hdpi/ic_stat_vpn.png
new file mode 100644
index 00000000..c3547e85
--- /dev/null
+++ b/app/src/main/res/drawable-hdpi/ic_stat_vpn.png
Binary files differ
diff --git a/app/src/main/res/drawable-hdpi/ic_stat_vpn_empty_halo.png b/app/src/main/res/drawable-hdpi/ic_stat_vpn_empty_halo.png
index 7df5b670..25f82a95 100644
--- a/app/src/main/res/drawable-hdpi/ic_stat_vpn_empty_halo.png
+++ b/app/src/main/res/drawable-hdpi/ic_stat_vpn_empty_halo.png
Binary files differ
diff --git a/app/src/main/res/drawable-hdpi/ic_stat_vpn_offline.png b/app/src/main/res/drawable-hdpi/ic_stat_vpn_offline.png
index 8aa48803..dfb962b9 100644
--- a/app/src/main/res/drawable-hdpi/ic_stat_vpn_offline.png
+++ b/app/src/main/res/drawable-hdpi/ic_stat_vpn_offline.png
Binary files differ
diff --git a/app/src/main/res/drawable-hdpi/ic_stat_vpn_outline.png b/app/src/main/res/drawable-hdpi/ic_stat_vpn_outline.png
index b5583d99..96d8d34d 100644..120000
--- a/app/src/main/res/drawable-hdpi/ic_stat_vpn_outline.png
+++ b/app/src/main/res/drawable-hdpi/ic_stat_vpn_outline.png
Binary files differ
diff --git a/app/src/main/res/drawable-hdpi/ic_vpn_disconnected.png b/app/src/main/res/drawable-hdpi/ic_vpn_disconnected.png
deleted file mode 100644
index dfb962b9..00000000
--- a/app/src/main/res/drawable-hdpi/ic_vpn_disconnected.png
+++ /dev/null
Binary files differ
diff --git a/app/src/main/res/drawable-ldpi/ic_stat_vpn.png b/app/src/main/res/drawable-ldpi/ic_stat_vpn.png
index f973015c..65fc6db7 100644
--- a/app/src/main/res/drawable-ldpi/ic_stat_vpn.png
+++ b/app/src/main/res/drawable-ldpi/ic_stat_vpn.png
Binary files differ
diff --git a/app/src/main/res/drawable-ldpi/ic_stat_vpn_empty_halo.png b/app/src/main/res/drawable-ldpi/ic_stat_vpn_empty_halo.png
new file mode 100644
index 00000000..2df0a9bd
--- /dev/null
+++ b/app/src/main/res/drawable-ldpi/ic_stat_vpn_empty_halo.png
Binary files differ
diff --git a/app/src/main/res/drawable-ldpi/ic_stat_vpn_offline.png b/app/src/main/res/drawable-ldpi/ic_stat_vpn_offline.png
new file mode 100644
index 00000000..22f3497e
--- /dev/null
+++ b/app/src/main/res/drawable-ldpi/ic_stat_vpn_offline.png
Binary files differ
diff --git a/app/src/main/res/drawable-ldpi/ic_stat_vpn_outline.png b/app/src/main/res/drawable-ldpi/ic_stat_vpn_outline.png
new file mode 120000
index 00000000..482dafd3
--- /dev/null
+++ b/app/src/main/res/drawable-ldpi/ic_stat_vpn_outline.png
@@ -0,0 +1 @@
+./ic_stat_vpn_offline.png \ No newline at end of file
diff --git a/app/src/main/res/drawable-mdpi/ic_stat_vpn.png b/app/src/main/res/drawable-mdpi/ic_stat_vpn.png
new file mode 100644
index 00000000..7e167f84
--- /dev/null
+++ b/app/src/main/res/drawable-mdpi/ic_stat_vpn.png
Binary files differ
diff --git a/app/src/main/res/drawable-mdpi/ic_stat_vpn_empty_halo.png b/app/src/main/res/drawable-mdpi/ic_stat_vpn_empty_halo.png
index fc039a82..a658d9e9 100644
--- a/app/src/main/res/drawable-mdpi/ic_stat_vpn_empty_halo.png
+++ b/app/src/main/res/drawable-mdpi/ic_stat_vpn_empty_halo.png
Binary files differ
diff --git a/app/src/main/res/drawable-mdpi/ic_stat_vpn_offline.png b/app/src/main/res/drawable-mdpi/ic_stat_vpn_offline.png
index f31387a4..f8b02bfb 100644
--- a/app/src/main/res/drawable-mdpi/ic_stat_vpn_offline.png
+++ b/app/src/main/res/drawable-mdpi/ic_stat_vpn_offline.png
Binary files differ
diff --git a/app/src/main/res/drawable-mdpi/ic_stat_vpn_outline.png b/app/src/main/res/drawable-mdpi/ic_stat_vpn_outline.png
index 052aef9d..96d8d34d 100644..120000
--- a/app/src/main/res/drawable-mdpi/ic_stat_vpn_outline.png
+++ b/app/src/main/res/drawable-mdpi/ic_stat_vpn_outline.png
Binary files differ
diff --git a/app/src/main/res/drawable-xhdpi/ic_stat_vpn.png b/app/src/main/res/drawable-xhdpi/ic_stat_vpn.png
new file mode 100644
index 00000000..1f46be2c
--- /dev/null
+++ b/app/src/main/res/drawable-xhdpi/ic_stat_vpn.png
Binary files differ
diff --git a/app/src/main/res/drawable-xhdpi/ic_stat_vpn_empty_halo.png b/app/src/main/res/drawable-xhdpi/ic_stat_vpn_empty_halo.png
index 2f61e890..f4f28ef7 100644
--- a/app/src/main/res/drawable-xhdpi/ic_stat_vpn_empty_halo.png
+++ b/app/src/main/res/drawable-xhdpi/ic_stat_vpn_empty_halo.png
Binary files differ
diff --git a/app/src/main/res/drawable-xhdpi/ic_stat_vpn_offline.png b/app/src/main/res/drawable-xhdpi/ic_stat_vpn_offline.png
index e9411518..7f44c46f 100644
--- a/app/src/main/res/drawable-xhdpi/ic_stat_vpn_offline.png
+++ b/app/src/main/res/drawable-xhdpi/ic_stat_vpn_offline.png
Binary files differ
diff --git a/app/src/main/res/drawable-xhdpi/ic_stat_vpn_outline.png b/app/src/main/res/drawable-xhdpi/ic_stat_vpn_outline.png
index 5d27240d..96d8d34d 100644..120000
--- a/app/src/main/res/drawable-xhdpi/ic_stat_vpn_outline.png
+++ b/app/src/main/res/drawable-xhdpi/ic_stat_vpn_outline.png
Binary files differ
diff --git a/app/src/main/res/layout/about.xml b/app/src/main/res/layout/about.xml
index 4b3f16e0..ccb1ea26 100644
--- a/app/src/main/res/layout/about.xml
+++ b/app/src/main/res/layout/about.xml
@@ -37,6 +37,12 @@
android:autoLink="all"
android:text="@string/repository_url_text" />
+ <TextView
+ android:layout_width="match_parent"
+ android:layout_height="wrap_content"
+ android:autoLink="all"
+ android:text="@string/leap_tracker" />
+
<Space
android:layout_width="match_parent"
android:layout_height="10sp" />
diff --git a/app/src/main/res/layout/client_dashboard.xml b/app/src/main/res/layout/client_dashboard.xml
index a5387efd..f33ac285 100644
--- a/app/src/main/res/layout/client_dashboard.xml
+++ b/app/src/main/res/layout/client_dashboard.xml
@@ -10,44 +10,28 @@
android:layout_width="match_parent"
android:layout_height="40dp"
android:background="?android:attr/selectableItemBackground" >
-
- <LinearLayout
- android:layout_width="wrap_content"
- android:layout_height="match_parent"
- android:gravity="center_vertical"
- android:orientation="vertical"
- android:paddingLeft="10dp" >
-
- <TextView
- android:layout_width="wrap_content"
- android:layout_height="wrap_content"
- android:ellipsize="marquee"
- android:fadingEdge="horizontal"
- android:singleLine="true"
- android:text="@string/provider_label"
- android:textAppearance="?android:attr/textAppearanceMedium"
- android:textSize="24sp" />
-
- </LinearLayout>
-
- <LinearLayout
- android:layout_width="match_parent"
- android:layout_height="match_parent"
- android:gravity="center_vertical"
- android:orientation="vertical"
- android:paddingLeft="15dp" >
-
- <TextView
- android:id="@+id/providerName"
- android:layout_width="wrap_content"
- android:layout_height="wrap_content"
- android:ellipsize="marquee"
- android:fadingEdge="horizontal"
- android:singleLine="true"
- android:text="@string/provider_label_none"
- android:textAppearance="?android:attr/textAppearanceMedium" />
+
+ <TextView
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:layout_marginLeft="5dp"
+ android:ellipsize="marquee"
+ android:fadingEdge="horizontal"
+ android:singleLine="true"
+ android:text="@string/provider_label"
+ android:textAppearance="?android:attr/textAppearanceMedium" />
+
+ <TextView
+ android:id="@+id/providerName"
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:layout_marginLeft="10dp"
+ android:ellipsize="marquee"
+ android:fadingEdge="horizontal"
+ android:singleLine="true"
+ android:text="@string/provider_label_none"
+ android:textAppearance="?android:attr/textAppearanceMedium" />
- </LinearLayout>
</LinearLayout>
<View
diff --git a/app/src/main/res/menu/logmenu.xml b/app/src/main/res/menu/logmenu.xml
index c498eefc..c8c9e815 100644
--- a/app/src/main/res/menu/logmenu.xml
+++ b/app/src/main/res/menu/logmenu.xml
@@ -33,6 +33,7 @@
android:alphabeticShortcut="e"
android:icon="@android:drawable/ic_menu_edit"
android:showAsAction="withText|ifRoom"
- android:title="@string/edit_vpn"/>
+ android:title="@string/edit_vpn"
+ android:visible="false"/>
-</menu> \ No newline at end of file
+</menu>
diff --git a/app/src/main/res/values-de/strings-icsopenvpn.xml b/app/src/main/res/values-de/strings-icsopenvpn.xml
index 9bf58685..bf115be5 100755
--- a/app/src/main/res/values-de/strings-icsopenvpn.xml
+++ b/app/src/main/res/values-de/strings-icsopenvpn.xml
@@ -62,7 +62,7 @@
<string name="remove_vpn">VPN löschen</string>
<string name="check_remote_tlscert">Überprüfe, ob der Server ein Zertifikat mit TLS-Servererweiterungen verwendet (--remote-cert-tls server)</string>
<string name="check_remote_tlscert_title">TLS-Serverzertifikat erwarten</string>
- <string name="remote_tlscn_check_summary">Server Zertifikatssubjekt überprüfen</string>
+ <string name="remote_tlscn_check_summary">Server Zertifikatssubjekt DN überprüfen</string>
<string name="remote_tlscn_check_title">Zertifikat Namen überprüfen</string>
<string name="enter_tlscn_dialog">Spezifizieren Sie die Methode mit welcher der DN des Serverzertifikates (z. B. C=DE, L=Paderborn, OU=Avian IP-Carrier, CN=openvpn.blinkt.de) überprüft wird.\n\nSie können den vollständigen DN oder den RDN (openvpn.blinkt.de im Beispiel) oder ein RDN-Präfix angeben.\n\nDer RDN Präfix \"Server\" erlaubt z.B. \"Server-1\" und \"Server-2\" \n\nWenn Sie das Eingabefeld leer lassen, wird der RDN gegen den Servernamen geprüft.\n\n Für weitere Details sehen Sie die Manpage von OpenVPN 2.3.1+ unter —verify-x509-name</string>
<string name="enter_tlscn_title">Serverzertifikat Subject</string>
@@ -84,7 +84,7 @@
<string name="default_route_summary">Leitet allen Internet Verkehr über das VPN</string>
<string name="use_default_title">Benutze Default Route</string>
<string name="custom_route_message">Benutze eigene Routen. Geben Sie Zielnetzwerk im CIDR Format an. Z.b. \"10.0.0.0/8 2002::/16\" würde die Netzwerke 10.0.0.0/8 und 2002::/16 über das VPN routen.</string>
- <string name="custom_route_message_excluded">Netze, die nicht über das VPN weitergeleitet werden sollen. Nutzt die gleiche Syntax wie die eigenen Routen.</string>
+ <string name="custom_route_message_excluded">Netze, die nicht über das VPN geleitet werden sollen. Nutzt die gleiche Syntax wie die eigenen Routen.</string>
<string name="custom_routes_title">Eigene Routen</string>
<string name="custom_routes_title_excluded">Ausgeschlossene Netze</string>
<string name="log_verbosity_level">Log Detail Level</string>
@@ -312,7 +312,7 @@
<string name="unhandled_exception_context">%3$s: %1$s\n\n%2$s</string>
<string name="faq_system_dialog_xposed">Wenn Sie ihr Gerät gerootet haben können Sie das &lt;a href=\"http://xposed.info/\"&gt;Xposed Framework&lt;/a&gt; und das &lt;a href=\"http://repo.xposed.info/module/de.blinkt.vpndialogxposed\"&gt;VPN Dialog confirm Modul&lt;/a&gt; auf eigene Gefahr installieren.</string>
<string name="full_licenses">Komplette Lizenzen</string>
- <string name="blocklocal_summary">Netze, die direkt über ein lokales Interfaces erreicht werden können werden nicht über das VPN gerottet. Deaktivieren dieser Option leitet allen Verkehr, der für lokale Netzwerke bestimmt ist, über das VPN.</string>
+ <string name="blocklocal_summary">Netze, die direkt über ein lokales Interfaces erreicht werden können werden nicht über das VPN geroutet. Deaktivieren dieser Option leitet allen Verkehr, der für lokale Netzwerke bestimmt ist, über das VPN.</string>
<string name="blocklocal_title">VPN für lokale Netzwerke umgehen</string>
<string name="userpw_file">Datei mit Benutzername und Passwort</string>
<string name="imported_from_file">[Importiert aus %s]</string>
diff --git a/app/src/main/res/values-es/strings.xml b/app/src/main/res/values-es/strings.xml
index 6a9cce29..ec8c21ff 100644
--- a/app/src/main/res/values-es/strings.xml
+++ b/app/src/main/res/values-es/strings.xml
@@ -6,4 +6,6 @@
<string name="routes_info6">Rutas IPv6: %s</string>
<string name="error_empty_username">El nombre de usuario no debe estar vacío.</string>
<string name="cert_from_keystore">Conseguido el certificado de \'%s\' de almacén de claves</string>
+ <string name="repository_url_text">Código fuente disponible en https://github.com/leapcode/bitmask_android/</string>
+ <string name="leap_tracker">Tracker disponible en https://leap.se/code</string>
</resources>
diff --git a/app/src/main/res/values/strings.xml b/app/src/main/res/values/strings.xml
index d7114b73..c928f001 100644
--- a/app/src/main/res/values/strings.xml
+++ b/app/src/main/res/values/strings.xml
@@ -2,7 +2,8 @@
<resources>
<string name="retry">Retry</string>
- <string name="repository_url_text">Source code and issue tracker available at https://github.com/leapcode/bitmask_android/</string>
+ <string name="repository_url_text">Source code available at https://github.com/leapcode/bitmask_android/</string>
+ <string name="leap_tracker">Tracker available at https://leap.se/code</string>
<string name="translation_project_text">Translations welcome and appreciated. See our Transifex project at https://www.transifex.com/projects/p/bitmask-android/</string>
<string name="switch_provider_menu_option">Switch provider</string>
<string name="info">info</string>
@@ -16,9 +17,7 @@
<string name="provider_label_none">No provider configured</string>
<string name="eip_settings_button_description">Access EIP connection settings</string>
<string name="status_unknown">Status unknown.</string>
- <string name="future_anonymous_secured_status">Connection will be secure using an anonymous certificate.</string>
<string name="anonymous_secured_status">Connection secure using an anonymous certificate.</string>
- <string name="future_authed_secured_status">Connection will be secure using your own certificate.</string>
<string name="authed_secured_status">Connection secure using your own certificate.</string>
<string name="eip_service_label">Encrypted Internet</string>
<string name="title_activity_configuration_wizard">Select a service provider</string>
@@ -52,11 +51,13 @@
<string name="server_unreachable_message">Server is unreachable, please try again.</string>
<string name="malformed_url">It doesn\'t seem to be a Bitmask provider.</string>
<string name="certificate_error">This is not a trusted Bitmask provider.</string>
+ <string name="service_is_down_error">Service is down.</string>
<string name="configuring_provider">Configuring provider</string>
<string name="incorrectly_downloaded_certificate_message">Your anon cert was not downloaded</string>
<string name="authenticating_message">Logging in</string>
<string name="signingup_message">Signing up</string>
<string name="logout_message">Logging out from this session.</string>
+ <string name="logged_out_message">Logged out.</string>
<string name="log_out_failed_message">Didn\'t logged out.</string>
<string name="succesful_authentication_message">Authentication succeeded.</string>
<string name="authentication_failed_message">Authentication failed.</string>
diff --git a/app/src/main/res/values/untranslatable.xml b/app/src/main/res/values/untranslatable.xml
index 50e598ac..f956b6bd 100644
--- a/app/src/main/res/values/untranslatable.xml
+++ b/app/src/main/res/values/untranslatable.xml
@@ -3,7 +3,7 @@
<string name="app" translatable="false">Bitmask</string>
<string name="app_name" translatable="false">Bitmask</string>
- <string name="copyright_leapgui" translatable="false">Copyright 2012\nLEAP Encryption Access Project &lt;info@leap.se></string>
+ <string name="copyright_leapgui" translatable="false">Copyright 2012-2014\nLEAP Encryption Access Project &lt;info@leap.se></string>
<string name="opevpn_copyright" translatable="false">Copyright © 2002–2010 OpenVPN Technologies, Inc. &lt;sales@openvpn.net>\n
"OpenVPN" is a trademark of OpenVPN Technologies, Inc.</string>
@@ -777,4 +777,120 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
</resources> \ No newline at end of file
diff --git a/app/src/release/java/se/leap/bitmaskclient/ProviderAPI.java b/app/src/release/java/se/leap/bitmaskclient/ProviderAPI.java
index 6d1ff879..cdac8197 100644
--- a/app/src/release/java/se/leap/bitmaskclient/ProviderAPI.java
+++ b/app/src/release/java/se/leap/bitmaskclient/ProviderAPI.java
@@ -25,6 +25,7 @@ import java.math.BigInteger;
import java.net.CookieHandler;
import java.net.CookieManager;
import java.net.CookiePolicy;
+import java.net.ConnectException;
import java.net.MalformedURLException;
import java.net.SocketTimeoutException;
import java.net.URISyntaxException;
@@ -32,6 +33,7 @@ import java.net.URL;
import java.net.URLConnection;
import java.net.URLEncoder;
import java.net.UnknownHostException;
+import javax.net.ssl.SSLHandshakeException;
import java.security.KeyManagementException;
import java.security.KeyStore;
import java.security.KeyStoreException;
@@ -188,7 +190,7 @@ public class ProviderAPI extends IntentService {
receiver.send(LOGOUT_FAILED, Bundle.EMPTY);
}
} else if (action.equalsIgnoreCase(DOWNLOAD_CERTIFICATE)) {
- if(getNewCert(parameters)) {
+ if(updateVpnCertificate()) {
receiver.send(CORRECTLY_DOWNLOADED_CERTIFICATE, Bundle.EMPTY);
} else {
receiver.send(INCORRECTLY_DOWNLOADED_CERTIFICATE, Bundle.EMPTY);
@@ -421,7 +423,7 @@ public class ProviderAPI extends IntentService {
parameters.put("user[password_verifier]", password_verifier);
Log.d(TAG, server_url);
Log.d(TAG, parameters.toString());
- return sendToServer(server_url + "/users", "POST", parameters);
+ return sendToServer(server_url + "/users.json", "POST", parameters);
}
/**
@@ -530,47 +532,57 @@ public class ProviderAPI extends IntentService {
* @param task containing a boolean meaning if the provider is custom or not, another boolean meaning if the user completely trusts this provider, the provider name and its provider.json url.
* @return a bundle with a boolean value mapped to a key named RESULT_KEY, and which is true if the update was successful.
*/
- private Bundle setUpProvider(Bundle task) {
- int progress = 0;
- Bundle current_download = new Bundle();
+ private Bundle setUpProvider(Bundle task) {
+ int progress = 0;
+ Bundle current_download = new Bundle();
- if(task != null && task.containsKey(Provider.MAIN_URL)) {
- last_provider_main_url = task.getString(Provider.MAIN_URL);
- CA_CERT_DOWNLOADED = PROVIDER_JSON_DOWNLOADED = EIP_SERVICE_JSON_DOWNLOADED = false;
- }
+ if(task != null && task.containsKey(Provider.MAIN_URL)) {
+ last_provider_main_url = task.getString(Provider.MAIN_URL);
+ CA_CERT_DOWNLOADED = PROVIDER_JSON_DOWNLOADED = EIP_SERVICE_JSON_DOWNLOADED = false;
+ }
- if(!CA_CERT_DOWNLOADED)
- current_download = downloadCACert(last_provider_main_url);
- if(CA_CERT_DOWNLOADED || (current_download.containsKey(RESULT_KEY) && current_download.getBoolean(RESULT_KEY))) {
- broadcast_progress(progress++);
- CA_CERT_DOWNLOADED = true;
- if(!PROVIDER_JSON_DOWNLOADED)
- current_download = getAndSetProviderJson(last_provider_main_url);
- if(PROVIDER_JSON_DOWNLOADED || (current_download.containsKey(RESULT_KEY) && current_download.getBoolean(RESULT_KEY))) {
- broadcast_progress(progress++);
- PROVIDER_JSON_DOWNLOADED = true;
- current_download = getAndSetEipServiceJson();
- if(current_download.containsKey(RESULT_KEY) && current_download.getBoolean(RESULT_KEY)) {
- broadcast_progress(progress++);
- EIP_SERVICE_JSON_DOWNLOADED = true;
- }
- }
+ if(!PROVIDER_JSON_DOWNLOADED)
+ current_download = getAndSetProviderJson(last_provider_main_url);
+ if(PROVIDER_JSON_DOWNLOADED || (current_download.containsKey(RESULT_KEY) && current_download.getBoolean(RESULT_KEY))) {
+ broadcast_progress(progress++);
+ PROVIDER_JSON_DOWNLOADED = true;
+
+ if(!CA_CERT_DOWNLOADED)
+ current_download = downloadCACert();
+ if(CA_CERT_DOWNLOADED || (current_download.containsKey(RESULT_KEY) && current_download.getBoolean(RESULT_KEY))) {
+ broadcast_progress(progress++);
+ CA_CERT_DOWNLOADED = true;
+ current_download = getAndSetEipServiceJson();
+ if(current_download.containsKey(RESULT_KEY) && current_download.getBoolean(RESULT_KEY)) {
+ broadcast_progress(progress++);
+ EIP_SERVICE_JSON_DOWNLOADED = true;
}
+ }
+ }
- return current_download;
+ return current_download;
}
- private Bundle downloadCACert(String provider_main_url) {
+ private Bundle downloadCACert() {
Bundle result = new Bundle();
- String cert_string = downloadWithCommercialCA(provider_main_url + "/ca.crt");
+ try {
+ JSONObject provider_json = new JSONObject(getSharedPreferences(Dashboard.SHARED_PREFERENCES, MODE_PRIVATE).getString(Provider.KEY, ""));
+ String ca_cert_url = provider_json.getString(Provider.CA_CERT_URI);
+ String cert_string = downloadWithCommercialCA(ca_cert_url);
+ result.putBoolean(RESULT_KEY, true);
- if(validCertificate(cert_string) && setting_up_provider) {
- getSharedPreferences(Dashboard.SHARED_PREFERENCES, MODE_PRIVATE).edit().putString(Provider.CA_CERT, cert_string).commit();
+ if(validCertificate(cert_string) && setting_up_provider) {
+ getSharedPreferences(Dashboard.SHARED_PREFERENCES, MODE_PRIVATE).edit().putString(Provider.CA_CERT, cert_string).commit();
result.putBoolean(RESULT_KEY, true);
- } else {
+ } else {
String reason_to_fail = pickErrorMessage(cert_string);
result.putString(ERRORS, reason_to_fail);
result.putBoolean(RESULT_KEY, false);
+ }
+ } catch (JSONException e) {
+ String reason_to_fail = formatErrorMessage(R.string.malformed_url);
+ result.putString(ERRORS, reason_to_fail);
+ result.putBoolean(RESULT_KEY, false);
}
return result;
@@ -695,14 +707,20 @@ public class ProviderAPI extends IntentService {
} catch (MalformedURLException e) {
json_file_content = formatErrorMessage(R.string.malformed_url);
} catch(SocketTimeoutException e) {
+ e.printStackTrace();
json_file_content = formatErrorMessage(R.string.server_unreachable_message);
- } catch (IOException e) {
+ } catch (SSLHandshakeException e) {
if(provider_url != null) {
json_file_content = downloadWithProviderCA(string_url);
} else {
json_file_content = formatErrorMessage(R.string.certificate_error);
}
+ } catch(ConnectException e) {
+ json_file_content = formatErrorMessage(R.string.service_is_down_error);
+ } catch (FileNotFoundException e) {
+ json_file_content = formatErrorMessage(R.string.malformed_url);
} catch (Exception e) {
+ e.printStackTrace();
if(provider_url != null) {
json_file_content = downloadWithProviderCA(string_url);
}
@@ -811,7 +829,7 @@ public class ProviderAPI extends IntentService {
System.out.println("String ignoring certificate = " + string);
} catch (FileNotFoundException e) {
e.printStackTrace();
- string = formatErrorMessage(R.string.server_unreachable_message);
+ string = formatErrorMessage(R.string.malformed_url);
} catch (IOException e) {
// The downloaded certificate doesn't validate our https connection.
e.printStackTrace();
@@ -872,16 +890,25 @@ public class ProviderAPI extends IntentService {
return true;
}
+ private boolean updateVpnCertificate() {
+ getNewCert();
+
+ getSharedPreferences(Dashboard.SHARED_PREFERENCES, MODE_PRIVATE).edit().putInt(EIP.PARSED_SERIAL, 0).commit();
+ Intent updateEIP = new Intent(getApplicationContext(), EIP.class);
+ updateEIP.setAction(EIP.ACTION_UPDATE_EIP_SERVICE);
+ startService(updateEIP);
+
+ return true;
+ }
+
/**
* Downloads a new OpenVPN certificate, attaching authenticated cookie for authenticated certificate.
*
- * @param task containing the type of the certificate to be downloaded
* @return true if certificate was downloaded correctly, false if provider.json is not present in SharedPreferences, or if the certificate url could not be parsed as a URI, or if there was an SSL error.
*/
- private boolean getNewCert(Bundle task) {
+ private boolean getNewCert() {
try {
- String type_of_certificate = task.getString(ConfigurationWizard.TYPE_OF_CERTIFICATE);
JSONObject provider_json = new JSONObject(getSharedPreferences(Dashboard.SHARED_PREFERENCES, MODE_PRIVATE).getString(Provider.KEY, ""));
String provider_main_url = provider_json.getString(Provider.API_URL);