summaryrefslogtreecommitdiff
path: root/app/src/main
diff options
context:
space:
mode:
Diffstat (limited to 'app/src/main')
-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.java23
-rw-r--r--app/src/main/java/se/leap/bitmaskclient/EIP.java666
-rw-r--r--app/src/main/java/se/leap/bitmaskclient/EipServiceFragment.java65
-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.xml8
-rw-r--r--app/src/main/res/values/untranslatable.xml118
34 files changed, 626 insertions, 501 deletions
diff --git a/app/src/main/AndroidManifest.xml b/app/src/main/AndroidManifest.xml
index a2c2a82f..a90d6396 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="86"
+ android:versionName="0.5.4" >
<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..117e45d8 100644
--- a/app/src/main/java/se/leap/bitmaskclient/Dashboard.java
+++ b/app/src/main/java/se/leap/bitmaskclient/Dashboard.java
@@ -472,9 +472,12 @@ public class Dashboard extends Activity implements LogInDialog.LogInDialogInterf
} else if(resultCode == ProviderAPI.CORRECTLY_DOWNLOADED_CERTIFICATE) {
setResult(RESULT_OK);
changeStatusMessage(resultCode);
- mProgressBar.setVisibility(ProgressBar.GONE);
+ if(mProgressBar != null)
+ mProgressBar.setVisibility(ProgressBar.GONE);
if(EipServiceFragment.isEipSwitchChecked())
eipStart();
+ else
+ eipStatus.setText(R.string.eip_state_not_connected);
} else if(resultCode == ProviderAPI.INCORRECTLY_DOWNLOADED_CERTIFICATE) {
setResult(RESULT_CANCELED);
changeStatusMessage(resultCode);
@@ -496,7 +499,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 +510,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;
}
}
@@ -570,4 +573,16 @@ public class Dashboard extends Activity implements LogInDialog.LogInDialogInterf
startService(eip_intent);
}
+
+ protected void setProgressBarVisibility(int visibility) {
+ if(mProgressBar == null)
+ mProgressBar = (ProgressBar) findViewById(R.id.eipProgress);
+ mProgressBar.setVisibility(visibility);
+ }
+
+ protected void setEipStatus(int status) {
+ if(eipStatus == null)
+ eipStatus = (TextView) findViewById(R.id.eipStatus);
+ eipStatus.setText(status);
+ }
}
diff --git a/app/src/main/java/se/leap/bitmaskclient/EIP.java b/app/src/main/java/se/leap/bitmaskclient/EIP.java
index 59faf93f..7374d5ed 100644
--- a/app/src/main/java/se/leap/bitmaskclient/EIP.java
+++ b/app/src/main/java/se/leap/bitmaskclient/EIP.java
@@ -14,43 +14,56 @@
* 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.util.Calendar;
-import java.util.Collection;
-import java.util.HashMap;
-import java.util.HashSet;
-import java.util.Iterator;
-import java.util.NoSuchElementException;
-import java.util.Set;
-import java.util.TreeMap;
-import java.util.Vector;
-import org.json.JSONArray;
-import org.json.JSONException;
-import org.json.JSONObject;
-import se.leap.bitmaskclient.R;
-import de.blinkt.openvpn.activities.DisconnectVPN;
-import de.blinkt.openvpn.core.ConfigParser;
-import de.blinkt.openvpn.core.ConfigParser.ConfigParseError;
-import de.blinkt.openvpn.LaunchVPN;
-import de.blinkt.openvpn.core.OpenVpnManagementThread;
-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;
import android.os.ResultReceiver;
import android.util.Log;
+import de.blinkt.openvpn.LaunchVPN;
+import de.blinkt.openvpn.VpnProfile;
+import de.blinkt.openvpn.activities.DisconnectVPN;
+import de.blinkt.openvpn.core.ConfigParser.ConfigParseError;
+import de.blinkt.openvpn.core.ConfigParser;
+import de.blinkt.openvpn.core.OpenVpnManagementThread;
+import de.blinkt.openvpn.core.OpenVpnService.LocalBinder;
+import de.blinkt.openvpn.core.OpenVpnService;
+import de.blinkt.openvpn.core.ProfileManager;
+import java.io.IOException;
+import java.io.StringReader;
+import java.security.cert.CertificateExpiredException;
+import java.security.cert.CertificateNotYetValidException;
+import java.security.cert.X509Certificate;
+import java.text.ParseException;
+import java.text.SimpleDateFormat;
+import java.util.Calendar;
+import java.util.Collection;
+import java.util.HashMap;
+import java.util.HashSet;
+import java.util.Iterator;
+import java.util.Locale;
+import java.util.NoSuchElementException;
+import java.util.Set;
+import java.util.TreeMap;
+import java.util.Vector;
+import org.json.JSONArray;
+import org.json.JSONException;
+import org.json.JSONObject;
+import se.leap.bitmaskclient.Dashboard;
+import se.leap.bitmaskclient.Provider;
+import se.leap.bitmaskclient.R;
/**
* EIP is the abstract base class for interacting with and managing the Encrypted
@@ -60,16 +73,19 @@ 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 {
public final static String AUTHED_EIP = "authed eip";
+ public final static String ACTION_CHECK_CERT_VALIDITY = "se.leap.bitmaskclient.CHECK_CERT_VALIDITY";
public final static String ACTION_START_EIP = "se.leap.bitmaskclient.START_EIP";
public final static String ACTION_STOP_EIP = "se.leap.bitmaskclient.STOP_EIP";
public final static String ACTION_UPDATE_EIP_SERVICE = "se.leap.bitmaskclient.UPDATE_EIP_SERVICE";
public final static String ACTION_IS_EIP_RUNNING = "se.leap.bitmaskclient.IS_RUNNING";
public final static String EIP_NOTIFICATION = "EIP_NOTIFICATION";
public final static String STATUS = "eip status";
+ public final static String DATE_FROM_CERTIFICATE = "date from certificate";
public final static String ALLOWED_ANON = "allow_anonymous";
public final static String CERTIFICATE = "cert";
public final static String PRIVATE_KEY = "private_key";
@@ -79,8 +95,9 @@ public final class EIP extends IntentService {
public final static String RECEIVER_TAG = "receiverTag";
public final static String REQUEST_TAG = "requestTag";
public final static String TAG = "se.leap.bitmaskclient.EIP";
-
-
+
+ public final static SimpleDateFormat certificate_date_format = new SimpleDateFormat("yyyy-MM-dd HH:mm", Locale.US);
+
private static Context context;
private static ResultReceiver mReceiver;
private static OpenVpnService mVpnService;
@@ -104,13 +121,11 @@ public final class EIP extends IntentService {
context = getApplicationContext();
updateEIPService();
-
- this.retreiveVpnService();
}
@Override
public void onDestroy() {
- unbindService(mVpnServiceConn);
+
mBound = false;
super.onDestroy();
@@ -130,136 +145,70 @@ public final class EIP extends IntentService {
this.startEIP();
else if ( action == ACTION_STOP_EIP )
this.stopEIP();
+ else if ( action == ACTION_CHECK_CERT_VALIDITY )
+ this.checkCertValidity();
}
/**
- * Sends an Intent to bind OpenVpnService.
- * Used when OpenVpnService isn't bound but might be running.
+ * Checks the last stored status notified by ics-openvpn
+ * Sends <code>Activity.RESULT_CANCELED</code> to the ResultReceiver that made the
+ * request if it's not connected, <code>Activity.RESULT_OK</code> otherwise.
*/
- private boolean retreiveVpnService() {
- Intent bindIntent = new Intent(this,OpenVpnService.class);
- bindIntent.setAction(OpenVpnService.START_SERVICE);
- return bindService(bindIntent, mVpnServiceConn, BIND_AUTO_CREATE);
- }
- private static ServiceConnection mVpnServiceConn = new ServiceConnection() {
- @Override
- public void onServiceConnected(ComponentName name, IBinder service) {
- LocalBinder binder = (LocalBinder) service;
- mVpnService = binder.getService();
- mBound = true;
+ private void isRunning() {
+ Bundle resultData = new Bundle();
+ resultData.putString(REQUEST_TAG, ACTION_IS_EIP_RUNNING);
+ int resultCode = Activity.RESULT_CANCELED;
+ boolean is_connected = isConnected();
- if (mReceiver != null && mPending != null) {
+ resultCode = (is_connected) ? Activity.RESULT_OK : Activity.RESULT_CANCELED;
+
+ if (mReceiver != null){
+ mReceiver.send(resultCode, resultData);
+ }
- boolean running = mVpnService.isRunning();
-
- int resultCode = Activity.RESULT_CANCELED;
-
- if (mPending.equals(ACTION_IS_EIP_RUNNING)){
- resultCode = (running) ? Activity.RESULT_OK : Activity.RESULT_CANCELED;
+ Log.d(TAG, "isRunning() = " + is_connected);
+ }
- }
- else if (mPending.equals(ACTION_START_EIP)){
- resultCode = (running) ? Activity.RESULT_OK : Activity.RESULT_CANCELED;
- }
- else if (mPending.equals(ACTION_STOP_EIP)){
- resultCode = (running) ? Activity.RESULT_CANCELED
- : Activity.RESULT_OK;
- }
- Bundle resultData = new Bundle();
- resultData.putString(REQUEST_TAG, ACTION_IS_EIP_RUNNING);
- mReceiver.send(resultCode, resultData);
-
- mPending = null;
- }
- }
-
- @Override
- public void onServiceDisconnected(ComponentName name) {
- mBound = false;
-
- if (mReceiver != null){
- Bundle resultData = new Bundle();
- resultData.putString(REQUEST_TAG, EIP_NOTIFICATION);
- mReceiver.send(Activity.RESULT_CANCELED, resultData);
- }
- }
-
-
- };
-
- /**
- * Attempts to determine if OpenVpnService has an established VPN connection
- * through the bound ServiceConnection. If there is no bound service, this
- * method will attempt to bind a running OpenVpnService and send
- * <code>Activity.RESULT_CANCELED</code> to the ResultReceiver that made the
- * request.
- * Note: If the request to bind OpenVpnService is successful, the ResultReceiver
- * will be notified in {@link onServiceConnected()}
- */
-
- private void isRunning() {
- 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");
- if (mBound) {
- resultCode = (is_connected) ? Activity.RESULT_OK : Activity.RESULT_CANCELED;
-
- if (mReceiver != null){
- mReceiver.send(resultCode, resultData);
- }
- } else {
- mPending = ACTION_IS_EIP_RUNNING;
- boolean retrieved_vpn_service = retreiveVpnService();
- try {
- Thread.sleep(1000);
- } catch (InterruptedException e) {
- // TODO Auto-generated catch block
- e.printStackTrace();
- }
- boolean running = is_connected;
-
- if (retrieved_vpn_service && running && mReceiver != null){
- mReceiver.send(Activity.RESULT_OK, resultData);
- }
- else{
- mReceiver.send(Activity.RESULT_CANCELED, resultData);
- }
- }
- }
+ 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();
- Intent intent = new Intent(this,LaunchVPN.class);
- intent.setAction(Intent.ACTION_MAIN);
- intent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
- intent.putExtra(LaunchVPN.EXTRA_KEY, activeGateway.mVpnProfile.getUUID().toString() );
- intent.putExtra(LaunchVPN.EXTRA_NAME, activeGateway.mVpnProfile.getName() );
- intent.putExtra(LaunchVPN.EXTRA_HIDELOG, true);
- intent.putExtra(RECEIVER_TAG, mReceiver);
- startActivity(intent);
- mPending = ACTION_START_EIP;
+ if(activeGateway != null && activeGateway.mVpnProfile != null) {
+ launchActiveGateway();
+ }
}
+
+ private void launchActiveGateway() {
+ Intent intent = new Intent(this,LaunchVPN.class);
+ intent.setAction(Intent.ACTION_MAIN);
+ intent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
+ intent.putExtra(LaunchVPN.EXTRA_KEY, activeGateway.mVpnProfile.getUUID().toString() );
+ intent.putExtra(LaunchVPN.EXTRA_NAME, activeGateway.mVpnProfile.getName() );
+ intent.putExtra(LaunchVPN.EXTRA_HIDELOG, true);
+ intent.putExtra(RECEIVER_TAG, mReceiver);
+ startActivity(intent);
+ mPending = ACTION_START_EIP;
+ }
/**
* Disconnects the EIP connection gracefully through the bound service or forcefully
* if there is no bound service. Sends a message to the requesting ResultReceiver.
*/
private void stopEIP() {
- if (mBound)
- mVpnService.onRevoke();
- else if(getSharedPreferences(Dashboard.SHARED_PREFERENCES, MODE_PRIVATE).getString(STATUS, "").startsWith("LEVEL_CONNECT")){
+ if(isConnected()) {
Intent disconnect_vpn = new Intent(this, DisconnectVPN.class);
disconnect_vpn.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
startActivity(disconnect_vpn);
}
-
+
if (mReceiver != null){
Bundle resultData = new Bundle();
resultData.putString(REQUEST_TAG, ACTION_STOP_EIP);
@@ -281,62 +230,27 @@ public final class EIP extends IntentService {
e.printStackTrace();
}
if(parsedEipSerial == 0) {
- // Delete all vpn profiles
- ProfileManager vpl = ProfileManager.getInstance(context);
- VpnProfile[] profiles = (VpnProfile[]) vpl.getProfiles().toArray(new VpnProfile[vpl.getProfiles().size()]);
- for (int current_profile = 0; current_profile < profiles.length; current_profile++){
- vpl.removeProfile(context, profiles[current_profile]);
- }
+ deleteAllVpnProfiles();
}
- if (eipDefinition.optInt("serial") > parsedEipSerial)
+ if (eipDefinition != null && eipDefinition.optInt("serial") > parsedEipSerial)
updateGateways();
}
-
+
+ private void deleteAllVpnProfiles() {
+ ProfileManager vpl = ProfileManager.getInstance(context);
+ VpnProfile[] profiles = (VpnProfile[]) vpl.getProfiles().toArray(new VpnProfile[vpl.getProfiles().size()]);
+ for (int current_profile = 0; current_profile < profiles.length; current_profile++){
+ vpl.removeProfile(context, profiles[current_profile]);
+ }
+ }
/**
* Choose a gateway to connect to based on timezone from system locale data
*
* @return The gateway to connect to
*/
private OVPNGateway selectGateway() {
- // TODO Remove String arg constructor in favor of findGatewayByName(String)
-
- Calendar cal = Calendar.getInstance();
- int localOffset = cal.get(Calendar.ZONE_OFFSET) / 3600000;
- TreeMap<Integer, Set<String>> offsets = new TreeMap<Integer, Set<String>>();
- JSONObject locationsObjects = null;
- Iterator<String> locations = null;
- try {
- locationsObjects = eipDefinition.getJSONObject("locations");
- locations = locationsObjects.keys();
- } catch (JSONException e1) {
- // TODO Auto-generated catch block
- e1.printStackTrace();
- }
-
- while (locations.hasNext()) {
- String locationName = locations.next();
- JSONObject location = null;
- try {
- location = locationsObjects.getJSONObject(locationName);
-
- // Distance along the numberline of Prime Meridian centric, assumes UTC-11 through UTC+12
- int dist = Math.abs(localOffset - location.optInt("timezone"));
- // Farther than 12 timezones and it's shorter around the "back"
- if (dist > 12)
- dist = 12 - (dist -12); // Well i'll be. Absolute values make equations do funny things.
-
- Set<String> set = offsets.get(dist);
- if (set == null) set = new HashSet<String>();
- set.add(locationName);
- offsets.put(dist, set);
- } catch (JSONException e) {
- // TODO Auto-generated catch block
- e.printStackTrace();
- }
- }
-
+ String closestLocation = closestGateway();
- String closestLocation = offsets.isEmpty() ? "" : offsets.firstEntry().getValue().iterator().next();
JSONArray gateways = null;
String chosenHost = null;
try {
@@ -344,7 +258,7 @@ public final class EIP extends IntentService {
for (int i = 0; i < gateways.length(); i++) {
JSONObject gw = gateways.getJSONObject(i);
if ( gw.getString("location").equalsIgnoreCase(closestLocation) || closestLocation.isEmpty()){
- chosenHost = gw.getString("host");
+ chosenHost = eipDefinition.getJSONObject("locations").getJSONObject(gw.getString("location")).getString("name");
break;
}
}
@@ -355,6 +269,44 @@ public final class EIP extends IntentService {
return new OVPNGateway(chosenHost);
}
+
+ private String closestGateway() {
+ Calendar cal = Calendar.getInstance();
+ int localOffset = cal.get(Calendar.ZONE_OFFSET) / 3600000;
+ TreeMap<Integer, Set<String>> offsets = new TreeMap<Integer, Set<String>>();
+ JSONObject locationsObjects = null;
+ Iterator<String> locations = null;
+ try {
+ locationsObjects = eipDefinition.getJSONObject("locations");
+ locations = locationsObjects.keys();
+ } catch (JSONException e1) {
+ // TODO Auto-generated catch block
+ e1.printStackTrace();
+ }
+
+ while (locations.hasNext()) {
+ String locationName = locations.next();
+ JSONObject location = null;
+ try {
+ location = locationsObjects.getJSONObject(locationName);
+
+ // Distance along the numberline of Prime Meridian centric, assumes UTC-11 through UTC+12
+ int dist = Math.abs(localOffset - location.optInt("timezone"));
+ // Farther than 12 timezones and it's shorter around the "back"
+ if (dist > 12)
+ dist = 12 - (dist -12); // Well i'll be. Absolute values make equations do funny things.
+
+ Set<String> set = offsets.get(dist);
+ if (set == null) set = new HashSet<String>();
+ set.add(locationName);
+ offsets.put(dist, set);
+ } catch (JSONException e) {
+ // TODO Auto-generated catch block
+ e.printStackTrace();
+ }
+ }
+ return offsets.isEmpty() ? "" : offsets.firstEntry().getValue().iterator().next();
+ }
/**
* Walk the list of gateways defined in eip-service.json and parse them into
@@ -365,35 +317,52 @@ public final class EIP extends IntentService {
JSONArray gatewaysDefined = null;
try {
- gatewaysDefined = eipDefinition.getJSONArray("gateways");
- } catch (JSONException e1) {
- // TODO Auto-generated catch block
- e1.printStackTrace();
- }
-
- for ( int i=0 ; i < gatewaysDefined.length(); i++ ){
+ gatewaysDefined = eipDefinition.getJSONArray("gateways");
+ for ( int i=0 ; i < gatewaysDefined.length(); i++ ){
+ JSONObject gw = null;
+ gw = gatewaysDefined.getJSONObject(i);
- JSONObject gw = null;
-
- try {
- gw = gatewaysDefined.getJSONObject(i);
- } catch (JSONException e) {
- // TODO Auto-generated catch block
- e.printStackTrace();
- }
-
- try {
- if ( gw.getJSONObject("capabilities").getJSONArray("transport").toString().contains("openvpn") ){
- new OVPNGateway(gw);
- }
- } catch (JSONException e) {
- // TODO Auto-generated catch block
- e.printStackTrace();
+ if ( gw.getJSONObject("capabilities").getJSONArray("transport").toString().contains("openvpn") )
+ new OVPNGateway(gw);
}
+ } catch (JSONException e) {
+ // TODO Auto-generated catch block
+ e.printStackTrace();
}
+
getSharedPreferences(Dashboard.SHARED_PREFERENCES, MODE_PRIVATE).edit().putInt(PARSED_SERIAL, eipDefinition.optInt(Provider.API_RETURN_SERIAL)).commit();
}
+ private void checkCertValidity() {
+ String certificate_string = getSharedPreferences(Dashboard.SHARED_PREFERENCES, MODE_PRIVATE).getString(CERTIFICATE, "");
+ String date_from_certificate_string = getSharedPreferences(Dashboard.SHARED_PREFERENCES, MODE_PRIVATE).getString(DATE_FROM_CERTIFICATE, Calendar.getInstance().getTime().toString());
+ X509Certificate certificate_x509 = ConfigHelper.parseX509CertificateFromString(certificate_string);
+
+ Calendar offset_date = Calendar.getInstance();
+ try {
+ long difference = Math.abs(certificate_date_format.parse(date_from_certificate_string).getTime() - certificate_x509.getNotAfter().getTime())/2;
+ long current_date_millis = offset_date.getTimeInMillis();
+ offset_date.setTimeInMillis(current_date_millis + difference);
+ Log.d(TAG, "certificate not after = " + certificate_x509.getNotAfter());
+ } catch(ParseException e) {
+ e.printStackTrace();
+ }
+
+ Bundle result_data = new Bundle();
+ result_data.putString(REQUEST_TAG, ACTION_CHECK_CERT_VALIDITY);
+ try {
+ Log.d(TAG, "offset_date = " + offset_date.getTime().toString());
+ certificate_x509.checkValidity(offset_date.getTime());
+ mReceiver.send(Activity.RESULT_OK, result_data);
+ Log.d(TAG, "Valid certificate");
+ } catch(CertificateExpiredException e) {
+ mReceiver.send(Activity.RESULT_CANCELED, result_data);
+ Log.d(TAG, "Updating certificate");
+ } catch(CertificateNotYetValidException e) {
+ mReceiver.send(Activity.RESULT_CANCELED, result_data);
+ }
+ }
+
/**
* OVPNGateway provides objects defining gateways and their options and metadata.
* Each instance contains a VpnProfile for OpenVPN specific data and member
@@ -425,7 +394,6 @@ public final class EIP extends IntentService {
private void loadVpnProfile() {
ProfileManager vpl = ProfileManager.getInstance(context);
-
try {
if ( mName == null )
mVpnProfile = vpl.getProfiles().iterator().next();
@@ -455,175 +423,187 @@ public final class EIP extends IntentService {
Collection<VpnProfile> profiles = vpl.getProfiles();
for (Iterator<VpnProfile> it = profiles.iterator(); it.hasNext(); ){
VpnProfile p = it.next();
- try {
- if ( p.mName.equalsIgnoreCase( gateway.getString("host") ) ){
- it.remove();
- vpl.removeProfile(context, p);
- }
- } catch (JSONException e) {
- // TODO Auto-generated catch block
- e.printStackTrace();
+
+ if ( p.mName.equalsIgnoreCase( mName ) ) {
+ it.remove();
+ vpl.removeProfile(context, p);
}
}
- this.parseOptions();
this.createVPNProfile();
- setUniqueProfileName(vpl);
+ setUniqueProfileName();
vpl.addProfile(mVpnProfile);
vpl.saveProfile(context, mVpnProfile);
vpl.saveProfileList(context);
}
-
- /**
- * Attempts to create a unique profile name from the hostname of the gateway
- *
- * @param profileManager
- */
- private void setUniqueProfileName(ProfileManager profileManager) {
- int i=0;
-
- String newname;
- try {
- newname = mGateway.getString("host");
- while(profileManager.getProfileByName(newname)!=null) {
- i++;
- if(i==1)
- newname = getString(R.string.converted_profile);
- else
- newname = getString(R.string.converted_profile_i,i);
- }
- mVpnProfile.mName=newname;
- } catch (JSONException e) {
- // TODO Auto-generated catch block
- Log.v(TAG,"Couldn't read gateway name for profile creation!");
- e.printStackTrace();
- }
+
+ public String locationAsName() {
+ try {
+ return eipDefinition.getJSONObject("locations").getJSONObject(mGateway.getString("location")).getString("name");
+ } catch (JSONException e) {
+ Log.v(TAG,"Couldn't read gateway name for profile creation! Returning original name = " + mName);
+ e.printStackTrace();
+ return (mName != null) ? mName : "";
}
+ }
+
/**
- * FIXME This method is really the outline of the refactoring needed in se.leap.openvpn.ConfigParser
+ * Attempts to create a unique profile name
+ * based on the location of the gateway.
*/
- 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>>();
-
- 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();
-
- 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();
- }
-
- // We are always client, because the ifconfig will be received by a needed command
- options.put("client", null);
-
- 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 {
- // 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();
+ private void setUniqueProfileName() {
+ mVpnProfile.mName = mName = locationAsName();
}
-
+
/**
* 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();
}
}
+
+ /**
+ * Parses data from eip-service.json to a section of the openvpn config file
+ */
+ private String configFromEipServiceDotJson() {
+ String parsed_configuration = "";
+
+ String location_key = "location";
+ String locations = "locations";
+
+ parsed_configuration += extractCommonOptionsFromEipServiceDotJson();
+ parsed_configuration += extractRemotesFromEipServiceDotJson();
+
+ return parsed_configuration;
+ }
+
+ private String extractCommonOptionsFromEipServiceDotJson() {
+ String common_options = "";
+ try {
+ String common_options_key = "openvpn_configuration";
+ JSONObject openvpn_configuration = eipDefinition.getJSONObject(common_options_key);
+ Iterator keys = openvpn_configuration.keys();
+ Vector<Vector<String>> value = new Vector<Vector<String>>();
+ while ( keys.hasNext() ){
+ String key = keys.next().toString();
+
+ common_options += key + " ";
+ for ( String word : openvpn_configuration.getString(key).split(" ") )
+ common_options += word + " ";
+ common_options += System.getProperty("line.separator");
+
+ }
+ } catch (JSONException e) {
+ // TODO Auto-generated catch block
+ e.printStackTrace();
+ }
+
+ common_options += "client" + System.getProperty("line.separator");
+
+ return common_options;
+ }
+
+
+ private String extractRemotesFromEipServiceDotJson() {
+ String remotes = "";
+
+ String remote = "ip_address";
+ String remote_openvpn_keyword = "remote";
+ String ports = "ports";
+ String protos = "protocols";
+ String capabilities = "capabilities";
+ String udp = "udp";
+
+ try {
+ JSONArray protocolsJSON = mGateway.getJSONObject(capabilities).getJSONArray(protos);
+ for ( int i=0; i<protocolsJSON.length(); i++ ) {
+ String remote_line = remote_openvpn_keyword;
+ remote_line += " " + mGateway.getString(remote);
+ remote_line += " " + mGateway.getJSONObject(capabilities).getJSONArray(ports).optString(0);
+ remote_line += " " + protocolsJSON.optString(i);
+ if(remote_line.endsWith(udp))
+ remotes = remotes.replaceFirst(remote_openvpn_keyword, remote_line + System.getProperty("line.separator") + remote_openvpn_keyword);
+ else
+ remotes += remote_line;
+ remotes += System.getProperty("line.separator");
+ }
+ } catch (JSONException e) {
+ // TODO Auto-generated catch block
+ e.printStackTrace();
+ }
+
+ Log.d(TAG, "remotes = " + remotes);
+ return remotes;
+ }
+
+ 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;
+ }
}
}
diff --git a/app/src/main/java/se/leap/bitmaskclient/EipServiceFragment.java b/app/src/main/java/se/leap/bitmaskclient/EipServiceFragment.java
index 446ba1d9..5a5bb568 100644
--- a/app/src/main/java/se/leap/bitmaskclient/EipServiceFragment.java
+++ b/app/src/main/java/se/leap/bitmaskclient/EipServiceFragment.java
@@ -1,6 +1,10 @@
package se.leap.bitmaskclient;
import se.leap.bitmaskclient.R;
+import se.leap.bitmaskclient.ProviderAPIResultReceiver;
+import se.leap.bitmaskclient.ProviderAPIResultReceiver.Receiver;
+import se.leap.bitmaskclient.Dashboard;
+
import de.blinkt.openvpn.activities.LogWindow;
import de.blinkt.openvpn.core.VpnStatus;
import de.blinkt.openvpn.core.VpnStatus.ConnectionStatus;
@@ -21,6 +25,7 @@ import android.view.View.OnClickListener;
import android.view.ViewGroup;
import android.widget.CompoundButton.OnCheckedChangeListener;
import android.widget.CompoundButton;
+import android.widget.ProgressBar;
import android.widget.RelativeLayout;
import android.widget.Switch;
import android.widget.TextView;
@@ -37,9 +42,7 @@ public class EipServiceFragment extends Fragment implements StateListener, OnChe
private boolean eipAutoSwitched = true;
- private boolean mEipStartPending = false;
-
- private boolean set_switch_off = false;
+ private boolean mEipStartPending = false;
private static EIPReceiver mEIPReceiver;
@@ -96,15 +99,9 @@ public class EipServiceFragment extends Fragment implements StateListener, OnChe
super.onResume();
VpnStatus.addStateListener(this);
- if(set_switch_off) {
- eipSwitch.setChecked(false);
- set_switch_off = false;
- }
+
+ eipCommand(EIP.ACTION_CHECK_CERT_VALIDITY);
}
-
- protected void setSwitchOff(boolean value) {
- set_switch_off = value;
- }
@Override
public void onPause() {
@@ -131,8 +128,7 @@ public class EipServiceFragment extends Fragment implements StateListener, OnChe
}
@Override
public void onCheckedChanged(CompoundButton buttonView, boolean isChecked) {
- Log.d("bitmask", "onCheckChanged");
- if (buttonView.equals(eipSwitch) && !eipAutoSwitched){
+ if (buttonView.equals(eipSwitch) && !eipAutoSwitched){
boolean allowed_anon = getActivity().getSharedPreferences(Dashboard.SHARED_PREFERENCES, Activity.MODE_PRIVATE).getBoolean(EIP.ALLOWED_ANON, false);
String certificate = getActivity().getSharedPreferences(Dashboard.SHARED_PREFERENCES, Activity.MODE_PRIVATE).getString(EIP.CERTIFICATE, "");
if(allowed_anon || !certificate.isEmpty()) {
@@ -173,8 +169,12 @@ public class EipServiceFragment extends Fragment implements StateListener, OnChe
}
}
else {
- if(!eipSwitch.isChecked())
- eipStatus.setText(R.string.state_noprocess);
+ if(!eipSwitch.isChecked()) {
+ if(getActivity().getSharedPreferences(Dashboard.SHARED_PREFERENCES, Activity.MODE_PRIVATE).getString(EIP.STATUS, "").equalsIgnoreCase(ConnectionStatus.LEVEL_AUTH_FAILED.toString()))
+ startEipFromScratch();
+ else
+ eipStatus.setText(R.string.state_noprocess);
+ }
}
eipAutoSwitched = true;
saveEipStatus();
@@ -198,9 +198,10 @@ public class EipServiceFragment extends Fragment implements StateListener, OnChe
*/
private void eipCommand(String action){
// TODO validate "action"...how do we get the list of intent-filters for a class via Android API?
- Intent vpnIntent = new Intent(action);
- vpnIntent.putExtra(EIP.RECEIVER_TAG, mEIPReceiver);
- getActivity().startService(vpnIntent);
+ Intent vpn_intent = new Intent(getActivity().getApplicationContext(), EIP.class);
+ vpn_intent.setAction(action);
+ vpn_intent.putExtra(EIP.RECEIVER_TAG, mEIPReceiver);
+ getActivity().startService(vpn_intent);
}
@Override
@@ -221,7 +222,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) {
@@ -255,7 +257,7 @@ public class EipServiceFragment extends Fragment implements StateListener, OnChe
@Override
protected void onReceiveResult(int resultCode, Bundle resultData) {
super.onReceiveResult(resultCode, resultData);
-
+
String request = resultData.getString(EIP.REQUEST_TAG);
boolean checked = false;
@@ -297,6 +299,29 @@ public class EipServiceFragment extends Fragment implements StateListener, OnChe
checked = false;
break;
}
+ } else if (request == EIP.ACTION_CHECK_CERT_VALIDITY) {
+ checked = eipSwitch.isChecked();
+
+ switch (resultCode) {
+ case Activity.RESULT_OK:
+ break;
+ case Activity.RESULT_CANCELED:
+ Dashboard dashboard = (Dashboard) getActivity();
+
+ dashboard.setProgressBarVisibility(ProgressBar.VISIBLE);
+ dashboard.setEipStatus(R.string.updating_certificate_message);
+
+ Intent provider_API_command = new Intent(getActivity(), ProviderAPI.class);
+ if(dashboard.providerAPI_result_receiver == null) {
+ dashboard.providerAPI_result_receiver = new ProviderAPIResultReceiver(new Handler());
+ dashboard.providerAPI_result_receiver.setReceiver(dashboard);
+ }
+
+ provider_API_command.setAction(ProviderAPI.DOWNLOAD_CERTIFICATE);
+ provider_API_command.putExtra(ProviderAPI.RECEIVER_KEY, dashboard.providerAPI_result_receiver);
+ getActivity().startService(provider_API_command);
+ break;
+ }
}
eipAutoSwitched = true;
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..1dbe8fee 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,14 @@
<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="updating_certificate_message">Updating EIP certificate</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