summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--app/src/main/AndroidManifest.xml4
-rw-r--r--app/src/main/java/de/blinkt/openvpn/LaunchVPN.java19
-rw-r--r--app/src/main/java/de/blinkt/openvpn/VpnProfile.java53
-rw-r--r--app/src/main/java/de/blinkt/openvpn/activities/BaseActivity.java27
-rw-r--r--app/src/main/java/de/blinkt/openvpn/activities/DisconnectVPN.java99
-rw-r--r--app/src/main/java/de/blinkt/openvpn/core/DeviceStateReceiver.java2
-rw-r--r--app/src/main/java/de/blinkt/openvpn/core/ICSOpenVPNApplication.java68
-rw-r--r--app/src/main/java/de/blinkt/openvpn/core/OpenVPNService.java65
-rw-r--r--app/src/main/java/de/blinkt/openvpn/core/OpenVPNStatusService.java2
-rw-r--r--app/src/main/java/de/blinkt/openvpn/core/ProfileManager.java267
-rw-r--r--app/src/main/java/de/blinkt/openvpn/core/StatusListener.java109
-rw-r--r--app/src/main/java/de/blinkt/openvpn/core/VpnStatus.java45
-rw-r--r--app/src/main/java/se/leap/bitmaskclient/Constants.java3
-rw-r--r--app/src/main/java/se/leap/bitmaskclient/EipFragment.java9
-rw-r--r--app/src/main/java/se/leap/bitmaskclient/EipSetupObserver.java5
-rw-r--r--app/src/main/java/se/leap/bitmaskclient/OnBootReceiver.java5
-rw-r--r--app/src/main/java/se/leap/bitmaskclient/eip/EIP.java6
-rw-r--r--app/src/main/java/se/leap/bitmaskclient/eip/EipStatus.java5
-rw-r--r--app/src/main/java/se/leap/bitmaskclient/eip/Gateway.java14
-rw-r--r--app/src/main/java/se/leap/bitmaskclient/eip/GatewaysManager.java80
-rw-r--r--app/src/main/java/se/leap/bitmaskclient/fragments/AlwaysOnDialog.java32
-rw-r--r--app/src/main/java/se/leap/bitmaskclient/fragments/LogFragment.java114
-rw-r--r--app/src/main/java/se/leap/bitmaskclient/utils/PreferenceHelper.java56
-rw-r--r--app/src/main/res/drawable/cust_button_secondary.xml8
-rw-r--r--app/src/main/res/layout/d_checkbox_confirm.xml73
-rw-r--r--app/src/main/res/values-de/strings.xml1
-rw-r--r--app/src/main/res/values/strings.xml1
-rw-r--r--app/src/test/java/se/leap/bitmaskclient/eip/EipStatusTest.java19
-rw-r--r--app/src/test/java/se/leap/bitmaskclient/eip/GatewaysManagerTest.java3
29 files changed, 294 insertions, 900 deletions
diff --git a/app/src/main/AndroidManifest.xml b/app/src/main/AndroidManifest.xml
index 86c9a74b..a00582cc 100644
--- a/app/src/main/AndroidManifest.xml
+++ b/app/src/main/AndroidManifest.xml
@@ -34,14 +34,14 @@
android:logo="@mipmap/ic_launcher"
android:theme="@style/BitmaskTheme">
<service
- android:name=".eip.VoidVpnService"
+ android:name="de.blinkt.openvpn.core.OpenVPNService"
android:permission="android.permission.BIND_VPN_SERVICE">
<intent-filter>
<action android:name="android.net.VpnService" />
</intent-filter>
</service>
<service
- android:name="de.blinkt.openvpn.core.OpenVPNService"
+ android:name=".eip.VoidVpnService"
android:permission="android.permission.BIND_VPN_SERVICE">
<intent-filter>
<action android:name="android.net.VpnService" />
diff --git a/app/src/main/java/de/blinkt/openvpn/LaunchVPN.java b/app/src/main/java/de/blinkt/openvpn/LaunchVPN.java
index 5bf178ae..60e4abb6 100644
--- a/app/src/main/java/de/blinkt/openvpn/LaunchVPN.java
+++ b/app/src/main/java/de/blinkt/openvpn/LaunchVPN.java
@@ -5,10 +5,6 @@
package de.blinkt.openvpn;
-import se.leap.bitmaskclient.R;
-
-import se.leap.bitmaskclient.R;
-
import android.annotation.TargetApi;
import android.app.Activity;
import android.app.AlertDialog;
@@ -25,10 +21,12 @@ import java.io.IOException;
import de.blinkt.openvpn.core.ConnectionStatus;
import de.blinkt.openvpn.core.Preferences;
-import de.blinkt.openvpn.core.ProfileManager;
import de.blinkt.openvpn.core.VPNLaunchHelper;
import de.blinkt.openvpn.core.VpnStatus;
import se.leap.bitmaskclient.MainActivity;
+import se.leap.bitmaskclient.R;
+
+import static se.leap.bitmaskclient.Constants.PROVIDER_PROFILE;
/**
* This Activity actually handles two stages of a launcher shortcut's life cycle.
@@ -61,7 +59,6 @@ public class LaunchVPN extends Activity {
public static final String EXTRA_NAME = "de.blinkt.openvpn.shortcutProfileName";
public static final String EXTRA_HIDELOG = "de.blinkt.openvpn.showNoLogWindow";
public static final String CLEARLOG = "clearlogconnect";
- public static final String EXTRA_TEMP_VPN_PROFILE = "se.leap.bitmask.tempVpnProfile";
private static final int START_VPN_PROFILE = 70;
@@ -94,15 +91,8 @@ public class LaunchVPN extends Activity {
VpnStatus.clearLog();
// we got called to be the starting point, most likely a shortcut
- String shortcutUUID = intent.getStringExtra(EXTRA_KEY);
- String shortcutName = intent.getStringExtra(EXTRA_NAME);
mhideLog = intent.getBooleanExtra(EXTRA_HIDELOG, false);
- VpnProfile profileToConnect = (VpnProfile) intent.getExtras().getSerializable(EXTRA_TEMP_VPN_PROFILE);
- if (profileToConnect == null)
- profileToConnect = ProfileManager.get(this, shortcutUUID);
-
- if (shortcutName != null && profileToConnect == null)
- profileToConnect = ProfileManager.getInstance(this).getProfileByName(shortcutName);
+ VpnProfile profileToConnect = (VpnProfile) intent.getExtras().getSerializable(PROVIDER_PROFILE);
if (profileToConnect == null) {
VpnStatus.logError(R.string.shortcut_profile_notfound);
@@ -126,7 +116,6 @@ public class LaunchVPN extends Activity {
if(!mhideLog && showLogWindow)
showLogWindow();
- ProfileManager.updateLRU(this, mSelectedProfile);
VPNLaunchHelper.startOpenVpn(mSelectedProfile, getBaseContext());
finish();
diff --git a/app/src/main/java/de/blinkt/openvpn/VpnProfile.java b/app/src/main/java/de/blinkt/openvpn/VpnProfile.java
index bd28ae16..7b9003aa 100644
--- a/app/src/main/java/de/blinkt/openvpn/VpnProfile.java
+++ b/app/src/main/java/de/blinkt/openvpn/VpnProfile.java
@@ -5,9 +5,6 @@
package de.blinkt.openvpn;
-import se.leap.bitmaskclient.R;
-import se.leap.bitmaskclient.BuildConfig;
-
import android.annotation.SuppressLint;
import android.content.Context;
import android.content.Intent;
@@ -15,7 +12,6 @@ import android.content.SharedPreferences;
import android.content.pm.PackageInfo;
import android.content.pm.PackageManager;
import android.os.Build;
-import android.os.RemoteException;
import android.preference.PreferenceManager;
import android.security.KeyChain;
import android.security.KeyChainException;
@@ -24,7 +20,8 @@ import android.support.annotation.Nullable;
import android.text.TextUtils;
import android.util.Base64;
-import de.blinkt.openvpn.core.*;
+import com.google.gson.Gson;
+
import org.spongycastle.util.io.pem.PemObject;
import org.spongycastle.util.io.pem.PemWriter;
@@ -37,7 +34,11 @@ import java.io.Serializable;
import java.io.StringWriter;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
-import java.security.*;
+import java.security.InvalidKeyException;
+import java.security.NoSuchAlgorithmException;
+import java.security.PrivateKey;
+import java.security.Signature;
+import java.security.SignatureException;
import java.security.cert.Certificate;
import java.security.cert.CertificateException;
import java.security.cert.X509Certificate;
@@ -52,6 +53,21 @@ import javax.crypto.Cipher;
import javax.crypto.IllegalBlockSizeException;
import javax.crypto.NoSuchPaddingException;
+import de.blinkt.openvpn.core.Connection;
+import de.blinkt.openvpn.core.ExtAuthHelper;
+import de.blinkt.openvpn.core.NativeUtils;
+import de.blinkt.openvpn.core.OpenVPNService;
+import de.blinkt.openvpn.core.OrbotHelper;
+import de.blinkt.openvpn.core.PasswordCache;
+import de.blinkt.openvpn.core.Preferences;
+import de.blinkt.openvpn.core.VPNLaunchHelper;
+import de.blinkt.openvpn.core.VpnStatus;
+import de.blinkt.openvpn.core.X509Utils;
+import se.leap.bitmaskclient.BuildConfig;
+import se.leap.bitmaskclient.R;
+
+import static se.leap.bitmaskclient.Constants.PROVIDER_PROFILE;
+
public class VpnProfile implements Serializable, Cloneable {
// Note that this class cannot be moved to core where it belongs since
// the profile loading depends on it being here
@@ -755,11 +771,8 @@ public class VpnProfile implements Serializable, Cloneable {
}
public Intent getStartServiceIntent(Context context) {
- String prefix = context.getPackageName();
-
Intent intent = new Intent(context, OpenVPNService.class);
- intent.putExtra(prefix + ".profileUUID", mUuid.toString());
- intent.putExtra(prefix + ".profileVersion", mVersion);
+ intent.putExtra(PROVIDER_PROFILE, this);
return intent;
}
@@ -1113,6 +1126,26 @@ public class VpnProfile implements Serializable, Cloneable {
return mName;
}
+ public String toJson() {
+ Gson gson = new Gson();
+ try {
+ return gson.toJson(this);
+ } catch (Exception e) {
+ e.printStackTrace();
+ }
+ return null;
+ }
+
+ public static VpnProfile fromJson(String json) {
+ try {
+ Gson gson = new Gson();
+ return gson.fromJson(json, VpnProfile.class);
+ } catch (Exception e) {
+ e.printStackTrace();
+ }
+ return null;
+ }
+
public String getUUIDString() {
return mUuid.toString().toLowerCase(Locale.ENGLISH);
}
diff --git a/app/src/main/java/de/blinkt/openvpn/activities/BaseActivity.java b/app/src/main/java/de/blinkt/openvpn/activities/BaseActivity.java
deleted file mode 100644
index 8cdc1e90..00000000
--- a/app/src/main/java/de/blinkt/openvpn/activities/BaseActivity.java
+++ /dev/null
@@ -1,27 +0,0 @@
-/*
- * Copyright (c) 2012-2015 Arne Schwabe
- * Distributed under the GNU GPL v2 with additional terms. For full terms see the file doc/LICENSE.txt
- */
-
-package de.blinkt.openvpn.activities;
-
-import android.app.Activity;
-import android.app.UiModeManager;
-import android.content.res.Configuration;
-import android.os.Bundle;
-import android.view.Window;
-
-public class BaseActivity extends Activity {
- private boolean isAndroidTV() {
- final UiModeManager uiModeManager = (UiModeManager) getSystemService(Activity.UI_MODE_SERVICE);
- return uiModeManager.getCurrentModeType() == Configuration.UI_MODE_TYPE_TELEVISION;
- }
-
- @Override
- protected void onCreate(Bundle savedInstanceState) {
- if (isAndroidTV()) {
- requestWindowFeature(Window.FEATURE_OPTIONS_PANEL);
- }
- super.onCreate(savedInstanceState);
- }
-}
diff --git a/app/src/main/java/de/blinkt/openvpn/activities/DisconnectVPN.java b/app/src/main/java/de/blinkt/openvpn/activities/DisconnectVPN.java
deleted file mode 100644
index 068821f5..00000000
--- a/app/src/main/java/de/blinkt/openvpn/activities/DisconnectVPN.java
+++ /dev/null
@@ -1,99 +0,0 @@
-/*
- * Copyright (c) 2012-2016 Arne Schwabe
- * Distributed under the GNU GPL v2 with additional terms. For full terms see the file doc/LICENSE.txt
- */
-
-package de.blinkt.openvpn.activities;
-
-import android.app.Activity;
-import android.app.AlertDialog;
-import android.content.ComponentName;
-import android.content.Context;
-import android.content.DialogInterface;
-import android.content.Intent;
-import android.content.ServiceConnection;
-import android.os.IBinder;
-import android.os.RemoteException;
-
-import de.blinkt.openvpn.LaunchVPN;
-import se.leap.bitmaskclient.R;
-import de.blinkt.openvpn.core.IOpenVPNServiceInternal;
-import de.blinkt.openvpn.core.OpenVPNService;
-import de.blinkt.openvpn.core.ProfileManager;
-import de.blinkt.openvpn.core.VpnStatus;
-
-/**
- * Created by arne on 13.10.13.
- */
-public class DisconnectVPN extends Activity implements DialogInterface.OnClickListener, DialogInterface.OnCancelListener {
- private IOpenVPNServiceInternal mService;
- private ServiceConnection mConnection = new ServiceConnection() {
-
-
-
- @Override
- public void onServiceConnected(ComponentName className,
- IBinder service) {
-
- mService = IOpenVPNServiceInternal.Stub.asInterface(service);
- }
-
- @Override
- public void onServiceDisconnected(ComponentName arg0) {
- mService = null;
- }
-
- };
-
- @Override
- protected void onResume() {
- super.onResume();
- Intent intent = new Intent(this, OpenVPNService.class);
- intent.setAction(OpenVPNService.START_SERVICE);
- bindService(intent, mConnection, Context.BIND_AUTO_CREATE);
- showDisconnectDialog();
- }
-
- @Override
- protected void onPause() {
- super.onPause();
- unbindService(mConnection);
- }
-
- private void showDisconnectDialog() {
- AlertDialog.Builder builder = new AlertDialog.Builder(this);
- builder.setTitle(R.string.title_cancel);
- builder.setMessage(R.string.cancel_connection_query);
- builder.setNegativeButton(android.R.string.cancel, this);
- builder.setPositiveButton(R.string.cancel_connection, this);
- builder.setNeutralButton(R.string.reconnect, this);
- builder.setOnCancelListener(this);
-
- builder.show();
- }
-
- @Override
- public void onClick(DialogInterface dialog, int which) {
- if (which == DialogInterface.BUTTON_POSITIVE) {
- ProfileManager.setConntectedVpnProfileDisconnected(this);
- if (mService != null) {
- try {
- mService.stopVPN(false);
- } catch (RemoteException e) {
- VpnStatus.logException(e);
- }
- }
- } else if (which == DialogInterface.BUTTON_NEUTRAL) {
- Intent intent = new Intent(this, LaunchVPN.class);
- intent.putExtra(LaunchVPN.EXTRA_KEY, VpnStatus.getLastConnectedVPNProfile());
- intent.setAction(Intent.ACTION_MAIN);
- startActivity(intent);
- }
- finish();
- }
-
- @Override
- public void onCancel(DialogInterface dialog) {
- finish();
- }
-}
diff --git a/app/src/main/java/de/blinkt/openvpn/core/DeviceStateReceiver.java b/app/src/main/java/de/blinkt/openvpn/core/DeviceStateReceiver.java
index c396f181..eeed29bc 100644
--- a/app/src/main/java/de/blinkt/openvpn/core/DeviceStateReceiver.java
+++ b/app/src/main/java/de/blinkt/openvpn/core/DeviceStateReceiver.java
@@ -145,7 +145,7 @@ public class DeviceStateReceiver extends BroadcastReceiver implements ByteCountL
boolean screenOffPause = prefs.getBoolean("screenoff", false);
if (screenOffPause) {
- if (ProfileManager.getLastConnectedVpn() != null && !ProfileManager.getLastConnectedVpn().mPersistTun)
+ if (VpnStatus.getLastConnectedVpnProfile() != null && !VpnStatus.getLastConnectedVpnProfile().mPersistTun)
VpnStatus.logError(R.string.screen_nopersistenttun);
screen = connectState.PENDINGDISCONNECT;
diff --git a/app/src/main/java/de/blinkt/openvpn/core/ICSOpenVPNApplication.java b/app/src/main/java/de/blinkt/openvpn/core/ICSOpenVPNApplication.java
deleted file mode 100644
index 5b1307b7..00000000
--- a/app/src/main/java/de/blinkt/openvpn/core/ICSOpenVPNApplication.java
+++ /dev/null
@@ -1,68 +0,0 @@
-/*
- * Copyright (c) 2012-2016 Arne Schwabe
- * Distributed under the GNU GPL v2 with additional terms. For full terms see the file doc/LICENSE.txt
- */
-
-package de.blinkt.openvpn.core;
-
-import android.annotation.TargetApi;
-import android.app.Application;
-import android.app.NotificationChannel;
-import android.app.NotificationManager;
-import android.content.Context;
-import android.graphics.Color;
-import android.os.Build;
-
-/*
-import org.acra.ACRA;
-import org.acra.ReportingInteractionMode;
-import org.acra.annotation.ReportsCrashes;
-*/
-
-import se.leap.bitmaskclient.R;
-
-public class ICSOpenVPNApplication extends Application {
- private StatusListener mStatus;
-
- @Override
- public void onCreate() {
- super.onCreate();
- PRNGFixes.apply();
-
- if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O)
-
- createNotificationChannels();
- mStatus = new StatusListener();
- mStatus.init(getApplicationContext());
-
- }
-
- @TargetApi(Build.VERSION_CODES.O)
- private void createNotificationChannels() {
- NotificationManager mNotificationManager =
- (NotificationManager) getSystemService(Context.NOTIFICATION_SERVICE);
-
- // Background message
- CharSequence name = getString(R.string.channel_name_background);
- NotificationChannel mChannel = new NotificationChannel(OpenVPNService.NOTIFICATION_CHANNEL_BG_ID,
- name, NotificationManager.IMPORTANCE_MIN);
-
- mChannel.setDescription(getString(R.string.channel_description_background));
- mChannel.enableLights(false);
-
- mChannel.setLightColor(Color.DKGRAY);
- mNotificationManager.createNotificationChannel(mChannel);
-
- // Connection status change messages
-
- name = getString(R.string.channel_name_status);
- mChannel = new NotificationChannel(OpenVPNService.NOTIFICATION_CHANNEL_NEWSTATUS_ID,
- name, NotificationManager.IMPORTANCE_LOW);
-
- mChannel.setDescription(getString(R.string.channel_description_status));
- mChannel.enableLights(true);
-
- mChannel.setLightColor(Color.BLUE);
- mNotificationManager.createNotificationChannel(mChannel);
- }
-} \ No newline at end of file
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 af31e977..82c4e1df 100644
--- a/app/src/main/java/de/blinkt/openvpn/core/OpenVPNService.java
+++ b/app/src/main/java/de/blinkt/openvpn/core/OpenVPNService.java
@@ -48,6 +48,7 @@ import se.leap.bitmaskclient.VpnNotificationManager;
import static de.blinkt.openvpn.core.ConnectionStatus.LEVEL_CONNECTED;
import static de.blinkt.openvpn.core.ConnectionStatus.LEVEL_WAITING_FOR_USER_INPUT;
import static de.blinkt.openvpn.core.NetworkSpace.IpAddress;
+import static se.leap.bitmaskclient.Constants.PROVIDER_PROFILE;
public class OpenVPNService extends VpnService implements StateListener, Callback, ByteCountListener, IOpenVPNServiceInternal, VpnNotificationManager.VpnServiceCallback {
@@ -61,6 +62,7 @@ public class OpenVPNService extends VpnService implements StateListener, Callbac
public final static String ORBOT_PACKAGE_NAME = "org.torproject.android";
private static final String PAUSE_VPN = "de.blinkt.openvpn.PAUSE_VPN";
private static final String RESUME_VPN = "se.leap.bitmaskclient.RESUME_VPN";
+ private static final String TAG = OpenVPNService.class.getSimpleName();
private static boolean mNotificationAlwaysVisible = false;
private final Vector<String> mDnslist = new Vector<>();
private final NetworkSpace mRoutes = new NetworkSpace();
@@ -177,7 +179,6 @@ public class OpenVPNService extends VpnService implements StateListener, Callbac
}
VpnStatus.removeByteCountListener(this);
unregisterDeviceStateReceiver();
- ProfileManager.setConntectedVpnProfileDisconnected(this);
mOpenVPNThread = null;
if (!mStarting) {
stopForeground(!mNotificationAlwaysVisible);
@@ -312,51 +313,38 @@ public class OpenVPNService extends VpnService implements StateListener, Callbac
0,
NOTIFICATION_CHANNEL_NEWSTATUS_ID);
- if (intent != null && intent.hasExtra(getPackageName() + ".profileUUID")) {
- String profileUUID = intent.getStringExtra(getPackageName() + ".profileUUID");
- int profileVersion = intent.getIntExtra(getPackageName() + ".profileVersion", 0);
- // Try for 10s to get current version of the profile
- mProfile = ProfileManager.get(this, profileUUID, profileVersion, 100);
+ if (intent != null && intent.hasExtra(PROVIDER_PROFILE)) {
+ mProfile = (VpnProfile) intent.getSerializableExtra(PROVIDER_PROFILE);
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.N_MR1) {
updateShortCutUsage(mProfile);
}
+ VpnStatus.setAlwaysOn(false);
} else {
/* The intent is null when we are set as always-on or the service has been restarted. */
- mProfile = ProfileManager.getLastConnectedProfile(this);
+ mProfile = VpnStatus.getLastConnectedVpnProfile(this);
VpnStatus.logInfo(R.string.service_restarted);
- /* Got no profile, just stop */
- if (mProfile == null) {
- Log.d("OpenVPN", "Got no last connected profile on null intent. Assuming always on.");
- mProfile = ProfileManager.getAlwaysOnVPN(this);
-
- if (mProfile == null) {
- stopSelf(startId);
- return START_NOT_STICKY;
- }
+ if (mProfile != null) {
+ VpnStatus.setAlwaysOn(true);
}
- /* Do the asynchronous keychain certificate stuff */
- mProfile.checkForRestart(this);
}
if (mProfile == null) {
- stopSelf(startId);
+ stopService(startId);
+ Log.d(TAG, "Stopping service, no profile found");
return START_NOT_STICKY;
+ } else {
+ Log.d(TAG, "Found profile: " + mProfile.mName);
+ /* Do the asynchronous keychain certificate stuff */
+ mProfile.checkForRestart(this);
}
/* start the OpenVPN process itself in a background thread */
- new Thread(new Runnable() {
- @Override
- public void run() {
- startOpenVPN();
- }
- }).start();
+ new Thread(this::startOpenVPN).start();
-
- ProfileManager.setConnectedVpnProfile(this, mProfile);
- VpnStatus.setConnectedVPNProfile(mProfile.getUUIDString());
+ VpnStatus.setLastConnectedVpnProfile(getApplicationContext(), mProfile);
return START_STICKY;
}
@@ -369,6 +357,11 @@ public class OpenVPNService extends VpnService implements StateListener, Callbac
shortcutManager.reportShortcutUsed(profile.getUUIDString());
}
+ private void stopService(int startId) {
+ VpnStatus.updateStateString("NOPROCESS", "VPN STOPPED", R.string.state_noprocess, ConnectionStatus.LEVEL_NOTCONNECTED);
+ stopSelf(startId);
+ }
+
private void startOpenVPN() {
/**
* see change above (l. 292 ff)
@@ -428,21 +421,17 @@ public class OpenVPNService extends VpnService implements StateListener, Callbac
}
synchronized (mProcessLock)
-
{
mProcessThread = new Thread(processThread, "OpenVPNProcessThread");
mProcessThread.start();
}
- new Handler(getMainLooper()).post(new Runnable() {
- @Override
- public void run() {
- if (mDeviceStateReceiver != null)
- unregisterDeviceStateReceiver();
-
- registerDeviceStateReceiver(mManagement);
- }
- }
+ new Handler(getMainLooper()).post(() -> {
+ if (mDeviceStateReceiver != null) {
+ unregisterDeviceStateReceiver();
+ }
+ registerDeviceStateReceiver(mManagement);
+ }
);
}
diff --git a/app/src/main/java/de/blinkt/openvpn/core/OpenVPNStatusService.java b/app/src/main/java/de/blinkt/openvpn/core/OpenVPNStatusService.java
index 6df1379a..b52e39a2 100644
--- a/app/src/main/java/de/blinkt/openvpn/core/OpenVPNStatusService.java
+++ b/app/src/main/java/de/blinkt/openvpn/core/OpenVPNStatusService.java
@@ -114,7 +114,7 @@ public class OpenVPNStatusService extends Service implements VpnStatus.LogListen
@Override
public String getLastConnectedVPN() throws RemoteException {
- return VpnStatus.getLastConnectedVPNProfile();
+ return VpnStatus.getLastConnectedVPNProfileId();
}
@Override
diff --git a/app/src/main/java/de/blinkt/openvpn/core/ProfileManager.java b/app/src/main/java/de/blinkt/openvpn/core/ProfileManager.java
deleted file mode 100644
index b9edc4b2..00000000
--- a/app/src/main/java/de/blinkt/openvpn/core/ProfileManager.java
+++ /dev/null
@@ -1,267 +0,0 @@
-/*
- * Copyright (c) 2012-2016 Arne Schwabe
- * Distributed under the GNU GPL v2 with additional terms. For full terms see the file doc/LICENSE.txt
- */
-
-package de.blinkt.openvpn.core;
-
-import android.app.Activity;
-import android.content.Context;
-import android.content.SharedPreferences;
-import android.content.SharedPreferences.Editor;
-
-import java.io.IOException;
-import java.io.ObjectInputStream;
-import java.io.ObjectOutputStream;
-import java.util.Collection;
-import java.util.HashMap;
-import java.util.HashSet;
-import java.util.Locale;
-import java.util.Set;
-import java.util.UUID;
-
-import de.blinkt.openvpn.VpnProfile;
-
-public class ProfileManager {
- private static final String PREFS_NAME = "VPNList";
-
- private static final String LAST_CONNECTED_PROFILE = "lastConnectedProfile";
- private static final String TEMPORARY_PROFILE_FILENAME = "temporary-vpn-profile";
- private static ProfileManager instance;
-
- private static VpnProfile mLastConnectedVpn = null;
- private HashMap<String, VpnProfile> profiles = new HashMap<>();
- private static VpnProfile tmpprofile = null;
-
-
- private static VpnProfile get(String key) {
- if (tmpprofile != null && tmpprofile.getUUIDString().equals(key))
- return tmpprofile;
-
- if (instance == null)
- return null;
- return instance.profiles.get(key);
-
- }
-
-
- private ProfileManager() {
- }
-
- private static void checkInstance(Context context) {
- if (instance == null) {
- instance = new ProfileManager();
- instance.loadVPNList(context);
- }
- }
-
- synchronized public static ProfileManager getInstance(Context context) {
- checkInstance(context);
- return instance;
- }
-
- public static void setConntectedVpnProfileDisconnected(Context c) {
- SharedPreferences prefs = Preferences.getDefaultSharedPreferences(c);
- Editor prefsedit = prefs.edit();
- prefsedit.putString(LAST_CONNECTED_PROFILE, null);
- prefsedit.apply();
-
- }
-
- /**
- * Sets the profile that is connected (to connect if the service restarts)
- */
- public static void setConnectedVpnProfile(Context c, VpnProfile connectedProfile) {
- SharedPreferences prefs = Preferences.getDefaultSharedPreferences(c);
- Editor prefsedit = prefs.edit();
-
- prefsedit.putString(LAST_CONNECTED_PROFILE, connectedProfile.getUUIDString());
- prefsedit.apply();
- mLastConnectedVpn = connectedProfile;
-
- }
-
- /**
- * Returns the profile that was last connected (to connect if the service restarts)
- */
- public static VpnProfile getLastConnectedProfile(Context c) {
- SharedPreferences prefs = Preferences.getDefaultSharedPreferences(c);
-
- String lastConnectedProfile = prefs.getString(LAST_CONNECTED_PROFILE, null);
- if (lastConnectedProfile != null)
- return get(c, lastConnectedProfile);
- else
- return null;
- }
-
-
- public Collection<VpnProfile> getProfiles() {
- return profiles.values();
- }
-
- public VpnProfile getProfileByName(String name) {
- for (VpnProfile vpnp : profiles.values()) {
- if (vpnp.getName().equals(name)) {
- return vpnp;
- }
- }
- return null;
- }
-
- public void saveProfileList(Context context) {
- SharedPreferences sharedprefs = Preferences.getSharedPreferencesMulti(PREFS_NAME, context);
- Editor editor = sharedprefs.edit();
- editor.putStringSet("vpnlist", profiles.keySet());
-
- // For reasing I do not understand at all
- // Android saves my prefs file only one time
- // if I remove the debug code below :(
- int counter = sharedprefs.getInt("counter", 0);
- editor.putInt("counter", counter + 1);
- editor.apply();
-
- }
-
- public void addProfile(VpnProfile profile) {
- profiles.put(profile.getUUID().toString(), profile);
-
- }
-
- public static void setTemporaryProfile(Context c, VpnProfile tmp) {
- tmp.mTemporaryProfile = true;
- ProfileManager.tmpprofile = tmp;
- saveProfile(c, tmp, true, true);
- }
-
- public static boolean isTempProfile() {
- return mLastConnectedVpn != null && mLastConnectedVpn == tmpprofile;
- }
-
- public void saveProfile(Context context, VpnProfile profile) {
- saveProfile(context, profile, true, false);
- }
-
- private static void saveProfile(Context context, VpnProfile profile, boolean updateVersion, boolean isTemporary) {
-
- if (updateVersion)
- profile.mVersion += 1;
- ObjectOutputStream vpnFile;
-
- String filename = profile.getUUID().toString() + ".vp";
- if (isTemporary)
- filename = TEMPORARY_PROFILE_FILENAME + ".vp";
-
- try {
- vpnFile = new ObjectOutputStream(context.openFileOutput(filename, Activity.MODE_PRIVATE));
-
- vpnFile.writeObject(profile);
- vpnFile.flush();
- vpnFile.close();
- } catch (IOException e) {
- VpnStatus.logException("saving VPN profile", e);
- throw new RuntimeException(e);
- }
- }
-
-
- private void loadVPNList(Context context) {
- profiles = new HashMap<>();
- SharedPreferences listpref = Preferences.getSharedPreferencesMulti(PREFS_NAME, context);
- Set<String> vlist = listpref.getStringSet("vpnlist", null);
- if (vlist == null) {
- vlist = new HashSet<>();
- }
- // Always try to load the temporary profile
- vlist.add(TEMPORARY_PROFILE_FILENAME);
-
- for (String vpnentry : vlist) {
- ObjectInputStream vpnfile=null;
- try {
- vpnfile = new ObjectInputStream(context.openFileInput(vpnentry + ".vp"));
- VpnProfile vp = ((VpnProfile) vpnfile.readObject());
-
- // Sanity check
- if (vp == null || vp.mName == null || vp.getUUID() == null)
- continue;
-
- vp.upgradeProfile();
- if (vpnentry.equals(TEMPORARY_PROFILE_FILENAME)) {
- tmpprofile = vp;
- } else {
- profiles.put(vp.getUUID().toString(), vp);
- }
-
-
- } catch (IOException | ClassNotFoundException e) {
- if (!vpnentry.equals(TEMPORARY_PROFILE_FILENAME))
- VpnStatus.logException("Loading VPN List", e);
- } finally {
- if (vpnfile!=null) {
- try {
- vpnfile.close();
- } catch (IOException e) {
- e.printStackTrace();
- }
- }
- }
- }
- }
-
-
- public void removeProfile(Context context, VpnProfile profile) {
- String vpnentry = profile.getUUID().toString();
- profiles.remove(vpnentry);
- saveProfileList(context);
- context.deleteFile(vpnentry + ".vp");
- if (mLastConnectedVpn == profile)
- mLastConnectedVpn = null;
-
- }
-
- public static VpnProfile get(Context context, String profileUUID) {
- return get(context, profileUUID, 0, 10);
- }
-
- public static VpnProfile get(Context context, String profileUUID, int version, int tries) {
- checkInstance(context);
- VpnProfile profile = get(profileUUID);
- int tried = 0;
- while ((profile == null || profile.mVersion < version) && (tried++ < tries)) {
- try {
- Thread.sleep(100);
- } catch (InterruptedException ignored) {
- }
- instance.loadVPNList(context);
- profile = get(profileUUID);
- int ver = profile == null ? -1 : profile.mVersion;
- }
-
- if (tried > 5)
-
- {
- int ver = profile == null ? -1 : profile.mVersion;
- VpnStatus.logError(String.format(Locale.US, "Used x %d tries to get current version (%d/%d) of the profile", tried, ver, version));
- }
- return profile;
- }
-
- public static VpnProfile getLastConnectedVpn() {
- return mLastConnectedVpn;
- }
-
- public static VpnProfile getAlwaysOnVPN(Context context) {
- checkInstance(context);
- SharedPreferences prefs = Preferences.getDefaultSharedPreferences(context);
-
- String uuid = prefs.getString("alwaysOnVpn", null);
- return get(uuid);
-
- }
-
- public static void updateLRU(Context c, VpnProfile profile) {
- profile.mLastUsed = System.currentTimeMillis();
- // LRU does not change the profile, no need for the service to refresh
- if (profile!=tmpprofile)
- saveProfile(c, profile, false, false);
- }
-}
diff --git a/app/src/main/java/de/blinkt/openvpn/core/StatusListener.java b/app/src/main/java/de/blinkt/openvpn/core/StatusListener.java
deleted file mode 100644
index 5d0b7037..00000000
--- a/app/src/main/java/de/blinkt/openvpn/core/StatusListener.java
+++ /dev/null
@@ -1,109 +0,0 @@
-/*
- * Copyright (c) 2012-2016 Arne Schwabe
- * Distributed under the GNU GPL v2 with additional terms. For full terms see the file doc/LICENSE.txt
- */
-
-package de.blinkt.openvpn.core;
-
-import android.content.ComponentName;
-import android.content.Context;
-import android.content.Intent;
-import android.content.ServiceConnection;
-import android.os.IBinder;
-import android.os.ParcelFileDescriptor;
-import android.os.RemoteException;
-
-import java.io.DataInputStream;
-import java.io.File;
-import java.io.IOException;
-
-/**
- * Created by arne on 09.11.16.
- */
-
-public class StatusListener {
- private File mCacheDir;
- 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
- IServiceStatus serviceStatus = IServiceStatus.Stub.asInterface(service);
- try {
- /* Check if this a local service ... */
- if (service.queryLocalInterface("de.blinkt.openvpn.core.IServiceStatus") == null) {
- // Not a local service
- VpnStatus.setConnectedVPNProfile(serviceStatus.getLastConnectedVPN());
- VpnStatus.setTrafficHistory(serviceStatus.getTrafficHistory());
- ParcelFileDescriptor pfd = serviceStatus.registerStatusCallback(mCallback);
- DataInputStream fd = new DataInputStream(new ParcelFileDescriptor.AutoCloseInputStream(pfd));
-
- short len = fd.readShort();
- byte[] buf = new byte[65336];
- while (len != 0x7fff) {
- fd.readFully(buf, 0, len);
- LogItem logitem = new LogItem(buf, len);
- VpnStatus.newLogItem(logitem, false);
- len = fd.readShort();
- }
- fd.close();
-
-
-
- } else {
- VpnStatus.initLogCache(mCacheDir);
- }
-
- } catch (RemoteException | IOException e) {
- e.printStackTrace();
- VpnStatus.logException(e);
- }
- }
-
- @Override
- public void onServiceDisconnected(ComponentName arg0) {
-
- }
-
- };
-
- void init(Context c) {
-
- Intent intent = new Intent(c, OpenVPNStatusService.class);
- intent.setAction(OpenVPNService.START_SERVICE);
- mCacheDir = c.getCacheDir();
-
- c.bindService(intent, mConnection, Context.BIND_AUTO_CREATE);
-
-
- }
-
-
- private IStatusCallbacks mCallback = new IStatusCallbacks.Stub()
-
- {
- @Override
- public void newLogItem(LogItem item) throws RemoteException {
- VpnStatus.newLogItem(item);
- }
-
- @Override
- public void updateStateString(String state, String msg, int resid, ConnectionStatus
- level) throws RemoteException {
- VpnStatus.updateStateString(state, msg, resid, level);
- }
-
- @Override
- public void updateByteCount(long inBytes, long outBytes) throws RemoteException {
- VpnStatus.updateByteCount(inBytes, outBytes);
- }
-
- @Override
- public void connectedVPN(String uuid) throws RemoteException {
- VpnStatus.setConnectedVPNProfile(uuid);
- }
- };
-
-}
diff --git a/app/src/main/java/de/blinkt/openvpn/core/VpnStatus.java b/app/src/main/java/de/blinkt/openvpn/core/VpnStatus.java
index fa28a875..c362e299 100644
--- a/app/src/main/java/de/blinkt/openvpn/core/VpnStatus.java
+++ b/app/src/main/java/de/blinkt/openvpn/core/VpnStatus.java
@@ -17,8 +17,11 @@ import java.util.LinkedList;
import java.util.Locale;
import java.util.Vector;
import java.util.concurrent.CopyOnWriteArrayList;
+import java.util.concurrent.atomic.AtomicBoolean;
+import de.blinkt.openvpn.VpnProfile;
import se.leap.bitmaskclient.R;
+import se.leap.bitmaskclient.utils.PreferenceHelper;
import static se.leap.bitmaskclient.utils.ConfigHelper.getProviderFormattedString;
@@ -31,6 +34,8 @@ public class VpnStatus {
private static CopyOnWriteArrayList<StateListener> stateListener;
private static Vector<ByteCountListener> byteCountListener;
+ private static AtomicBoolean isAlwaysOnBooting = new AtomicBoolean(false);
+
private static String mLaststatemsg = "";
private static String mLaststate = "NOPROCESS";
@@ -39,10 +44,10 @@ public class VpnStatus {
private static HandlerThread mHandlerThread;
- private static String mLastConnectedVPNUUID;
static boolean readFileLog =false;
final static java.lang.Object readFileLock = new Object();
+ private static VpnProfile lastConnectedProfile;
public static TrafficHistory trafficHistory;
@@ -136,17 +141,40 @@ public class VpnStatus {
}
public static void setConnectedVPNProfile(String uuid) {
- mLastConnectedVPNUUID = uuid;
for (StateListener sl: stateListener)
sl.setConnectedVPN(uuid);
}
- public static String getLastConnectedVPNProfile()
+ public static String getLastConnectedVPNProfileId()
{
- return mLastConnectedVPNUUID;
+ return lastConnectedProfile != null ? lastConnectedProfile.getUUIDString() : null;
+ }
+
+ public static VpnProfile getLastConnectedVpnProfile() {
+ return lastConnectedProfile;
+ }
+
+ public static VpnProfile getLastConnectedVpnProfile(Context context) {
+ return PreferenceHelper.getLastConnectedVpnProfile(context);
}
+
+ /**
+ * Sets the profile that is connected (to connect if the service restarts)
+ */
+ public static void setLastConnectedVpnProfile(Context context, VpnProfile connectedProfile) {
+ PreferenceHelper.setLastUsedVpnProfile(context, connectedProfile);
+ lastConnectedProfile = connectedProfile;
+ setConnectedVPNProfile(lastConnectedProfile.getUUIDString());
+ }
+
+
+ public static String getLastConnectedVpnName() {
+ return lastConnectedProfile != null ? lastConnectedProfile.mName : null;
+ }
+
+
public static void setTrafficHistory(TrafficHistory trafficHistory) {
VpnStatus.trafficHistory = trafficHistory;
}
@@ -479,7 +507,6 @@ public class VpnStatus {
}
-
public static synchronized void updateByteCount(long in, long out) {
TrafficHistory.LastDiff diff = trafficHistory.add(in, out);
@@ -487,4 +514,12 @@ public class VpnStatus {
bcl.updateByteCount(in, out, diff.getDiffIn(), diff.getDiffOut());
}
}
+
+ public static void setAlwaysOn(boolean alwaysOn) {
+ isAlwaysOnBooting.set(alwaysOn);
+ }
+
+ public static boolean isAlwaysOn() {
+ return isAlwaysOnBooting.get();
+ }
}
diff --git a/app/src/main/java/se/leap/bitmaskclient/Constants.java b/app/src/main/java/se/leap/bitmaskclient/Constants.java
index f9ee8fcf..42df6d1d 100644
--- a/app/src/main/java/se/leap/bitmaskclient/Constants.java
+++ b/app/src/main/java/se/leap/bitmaskclient/Constants.java
@@ -11,6 +11,8 @@ public interface Constants {
String SHARED_PREFERENCES = "LEAPPreferences";
String PREFERENCES_APP_VERSION = "bitmask version";
String ALWAYS_ON_SHOW_DIALOG = "DIALOG.ALWAYS_ON_SHOW_DIALOG";
+ String CLEARLOG = "clearlogconnect";
+ String LAST_USED_PROFILE = "last_used_profile";
//////////////////////////////////////////////
@@ -68,6 +70,7 @@ public interface Constants {
String PROVIDER_CONFIGURED = "Constants.PROVIDER_CONFIGURED";
String PROVIDER_EIP_DEFINITION = "Constants.EIP_DEFINITION";
String PROVIDER_PROFILE_UUID = "Constants.PROVIDER_PROFILE_UUID";
+ String PROVIDER_PROFILE = "Constants.PROVIDER_PROFILE";
//////////////////////////////////////////////
// CREDENTIAL CONSTANTS
diff --git a/app/src/main/java/se/leap/bitmaskclient/EipFragment.java b/app/src/main/java/se/leap/bitmaskclient/EipFragment.java
index 11ad8da3..269bf61f 100644
--- a/app/src/main/java/se/leap/bitmaskclient/EipFragment.java
+++ b/app/src/main/java/se/leap/bitmaskclient/EipFragment.java
@@ -50,10 +50,9 @@ import java.util.Observer;
import butterknife.ButterKnife;
import butterknife.InjectView;
import butterknife.OnClick;
-import de.blinkt.openvpn.VpnProfile;
import de.blinkt.openvpn.core.IOpenVPNServiceInternal;
import de.blinkt.openvpn.core.OpenVPNService;
-import de.blinkt.openvpn.core.ProfileManager;
+import de.blinkt.openvpn.core.VpnStatus;
import se.leap.bitmaskclient.eip.EipCommand;
import se.leap.bitmaskclient.eip.EipStatus;
import se.leap.bitmaskclient.fragments.DonationReminderDialog;
@@ -537,9 +536,9 @@ public class EipFragment extends Fragment implements Observer {
private void setVpnRouteText() {
String vpnRouteString = provider.getName();
- VpnProfile vpnProfile = ProfileManager.getLastConnectedVpn();
- if (vpnProfile != null && !TextUtils.isEmpty(vpnProfile.mName)) {
- vpnRouteString += " (" + vpnProfile.mName + ")";
+ String profileName = VpnStatus.getLastConnectedVpnName();
+ if (!TextUtils.isEmpty(profileName)) {
+ vpnRouteString += " (" + profileName + ")";
}
vpnRoute.setText(vpnRouteString);
}
diff --git a/app/src/main/java/se/leap/bitmaskclient/EipSetupObserver.java b/app/src/main/java/se/leap/bitmaskclient/EipSetupObserver.java
index ff94fe82..a8aa2dfb 100644
--- a/app/src/main/java/se/leap/bitmaskclient/EipSetupObserver.java
+++ b/app/src/main/java/se/leap/bitmaskclient/EipSetupObserver.java
@@ -35,6 +35,7 @@ import static se.leap.bitmaskclient.Constants.EIP_ACTION_START;
import static se.leap.bitmaskclient.Constants.EIP_ACTION_START_ALWAYS_ON_VPN;
import static se.leap.bitmaskclient.Constants.EIP_REQUEST;
import static se.leap.bitmaskclient.Constants.PROVIDER_KEY;
+import static se.leap.bitmaskclient.Constants.PROVIDER_PROFILE;
import static se.leap.bitmaskclient.Constants.SHARED_PREFERENCES;
import static se.leap.bitmaskclient.ProviderAPI.CORRECTLY_DOWNLOADED_EIP_SERVICE;
import static se.leap.bitmaskclient.ProviderAPI.CORRECTLY_UPDATED_INVALID_VPN_CERTIFICATE;
@@ -186,7 +187,7 @@ class EipSetupObserver extends BroadcastReceiver implements VpnStatus.StateListe
finishGatewaySetup(true);
}
- VpnProfile vpnProfile = (VpnProfile) event.getSerializableExtra(LaunchVPN.EXTRA_TEMP_VPN_PROFILE);
+ VpnProfile vpnProfile = (VpnProfile) event.getSerializableExtra(PROVIDER_PROFILE);
if (vpnProfile == null) {
Log.e(TAG, "Tried to setup non existing vpn profile.");
return;
@@ -204,7 +205,7 @@ class EipSetupObserver extends BroadcastReceiver implements VpnStatus.StateListe
intent.setAction(Intent.ACTION_MAIN);
intent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
intent.putExtra(LaunchVPN.EXTRA_HIDELOG, true);
- intent.putExtra(LaunchVPN.EXTRA_TEMP_VPN_PROFILE, vpnProfile);
+ intent.putExtra(PROVIDER_PROFILE, vpnProfile);
intent.putExtra(Gateway.KEY_N_CLOSEST_GATEWAY, setupNClosestGateway.get());
context.startActivity(intent);
}
diff --git a/app/src/main/java/se/leap/bitmaskclient/OnBootReceiver.java b/app/src/main/java/se/leap/bitmaskclient/OnBootReceiver.java
index f33bc27e..2efce9e4 100644
--- a/app/src/main/java/se/leap/bitmaskclient/OnBootReceiver.java
+++ b/app/src/main/java/se/leap/bitmaskclient/OnBootReceiver.java
@@ -6,6 +6,9 @@ import android.content.Intent;
import android.content.SharedPreferences;
import android.util.Log;
+import de.blinkt.openvpn.core.VpnStatus;
+import se.leap.bitmaskclient.utils.PreferenceHelper;
+
import static android.content.Intent.ACTION_BOOT_COMPLETED;
import static se.leap.bitmaskclient.Constants.APP_ACTION_CONFIGURE_ALWAYS_ON_PROFILE;
import static se.leap.bitmaskclient.Constants.EIP_IS_ALWAYS_ON;
@@ -27,7 +30,7 @@ public class OnBootReceiver extends BroadcastReceiver {
preferences = context.getSharedPreferences(SHARED_PREFERENCES, Context.MODE_PRIVATE);
boolean providerConfigured = !preferences.getString(PROVIDER_VPN_CERTIFICATE, "").isEmpty();
boolean startOnBoot = preferences.getBoolean(EIP_RESTART_ON_BOOT, false);
- boolean isAlwaysOnConfigured = preferences.getBoolean(EIP_IS_ALWAYS_ON, false);
+ boolean isAlwaysOnConfigured = VpnStatus.isAlwaysOn();
Log.d("OpenVPN", "OpenVPN onBoot intent received. Provider configured? " + providerConfigured + " Start on boot? " + startOnBoot + " isAlwaysOn feature configured: " + isAlwaysOnConfigured);
if (providerConfigured) {
if (isAlwaysOnConfigured) {
diff --git a/app/src/main/java/se/leap/bitmaskclient/eip/EIP.java b/app/src/main/java/se/leap/bitmaskclient/eip/EIP.java
index 29e2199f..a5434871 100644
--- a/app/src/main/java/se/leap/bitmaskclient/eip/EIP.java
+++ b/app/src/main/java/se/leap/bitmaskclient/eip/EIP.java
@@ -46,7 +46,6 @@ import java.util.concurrent.LinkedBlockingQueue;
import de.blinkt.openvpn.core.ConnectionStatus;
import de.blinkt.openvpn.core.IOpenVPNServiceInternal;
import de.blinkt.openvpn.core.OpenVPNService;
-import de.blinkt.openvpn.core.ProfileManager;
import de.blinkt.openvpn.core.VpnStatus;
import se.leap.bitmaskclient.OnBootReceiver;
import se.leap.bitmaskclient.R;
@@ -54,7 +53,6 @@ import se.leap.bitmaskclient.R;
import static android.app.Activity.RESULT_CANCELED;
import static android.app.Activity.RESULT_OK;
import static android.content.Intent.CATEGORY_DEFAULT;
-import static de.blinkt.openvpn.LaunchVPN.EXTRA_TEMP_VPN_PROFILE;
import static se.leap.bitmaskclient.Constants.BROADCAST_EIP_EVENT;
import static se.leap.bitmaskclient.Constants.BROADCAST_GATEWAY_SETUP_OBSERVER_EVENT;
import static se.leap.bitmaskclient.Constants.BROADCAST_RESULT_CODE;
@@ -70,6 +68,7 @@ import static se.leap.bitmaskclient.Constants.EIP_N_CLOSEST_GATEWAY;
import static se.leap.bitmaskclient.Constants.EIP_RECEIVER;
import static se.leap.bitmaskclient.Constants.EIP_REQUEST;
import static se.leap.bitmaskclient.Constants.EIP_RESTART_ON_BOOT;
+import static se.leap.bitmaskclient.Constants.PROVIDER_PROFILE;
import static se.leap.bitmaskclient.Constants.PROVIDER_VPN_CERTIFICATE;
import static se.leap.bitmaskclient.Constants.SHARED_PREFERENCES;
import static se.leap.bitmaskclient.MainActivityErrorDialog.DOWNLOAD_ERRORS.ERROR_INVALID_VPN_CERTIFICATE;
@@ -243,7 +242,7 @@ public final class EIP extends JobIntentService implements Observer {
*/
private void launchActiveGateway(@NonNull Gateway gateway, int nClosestGateway) {
Intent intent = new Intent(BROADCAST_GATEWAY_SETUP_OBSERVER_EVENT);
- intent.putExtra(EXTRA_TEMP_VPN_PROFILE, gateway.getProfile());
+ intent.putExtra(PROVIDER_PROFILE, gateway.getProfile());
intent.putExtra(Gateway.KEY_N_CLOSEST_GATEWAY, nClosestGateway);
LocalBroadcastManager.getInstance(this).sendBroadcast(intent);
@@ -401,7 +400,6 @@ public final class EIP extends JobIntentService implements Observer {
return false;
}
- ProfileManager.setConntectedVpnProfileDisconnected(this);
try {
return openVpnServiceConnection.getService().stopVPN(false);
} catch (RemoteException e) {
diff --git a/app/src/main/java/se/leap/bitmaskclient/eip/EipStatus.java b/app/src/main/java/se/leap/bitmaskclient/eip/EipStatus.java
index fc07c521..64904816 100644
--- a/app/src/main/java/se/leap/bitmaskclient/eip/EipStatus.java
+++ b/app/src/main/java/se/leap/bitmaskclient/eip/EipStatus.java
@@ -25,9 +25,7 @@ import java.util.Observable;
import de.blinkt.openvpn.core.ConnectionStatus;
import de.blinkt.openvpn.core.LogItem;
-import de.blinkt.openvpn.core.ProfileManager;
import de.blinkt.openvpn.core.VpnStatus;
-import se.leap.bitmaskclient.Provider;
/**
* EipStatus is a Singleton that represents a reduced set of a vpn's ConnectionStatus.
@@ -37,6 +35,7 @@ import se.leap.bitmaskclient.Provider;
public class EipStatus extends Observable implements VpnStatus.StateListener {
public static String TAG = EipStatus.class.getSimpleName();
private static EipStatus currentStatus;
+
public enum EipLevel {
CONNECTING,
DISCONNECTING,
@@ -99,7 +98,7 @@ public class EipStatus extends Observable implements VpnStatus.StateListener {
currentEipLevel = EipLevel.CONNECTED;
break;
case LEVEL_VPNPAUSED:
- if (ProfileManager.getLastConnectedVpn() != null && ProfileManager.getLastConnectedVpn().mPersistTun) {
+ if (VpnStatus.getLastConnectedVpnProfile() != null && VpnStatus.getLastConnectedVpnProfile().mPersistTun) {
//if persistTun is enabled, treat EipLevel as connecting as it *shouldn't* allow passing traffic in the clear...
currentEipLevel = EipLevel.CONNECTING;
} else {
diff --git a/app/src/main/java/se/leap/bitmaskclient/eip/Gateway.java b/app/src/main/java/se/leap/bitmaskclient/eip/Gateway.java
index 317a91bd..55ade1ae 100644
--- a/app/src/main/java/se/leap/bitmaskclient/eip/Gateway.java
+++ b/app/src/main/java/se/leap/bitmaskclient/eip/Gateway.java
@@ -132,4 +132,18 @@ public class Gateway {
public String toString() {
return new Gson().toJson(this, Gateway.class);
}
+
+ @Override
+ public boolean equals(Object obj) {
+ return obj instanceof Gateway &&
+ (this.mVpnProfile != null &&
+ ((Gateway) obj).mVpnProfile != null &&
+ this.mVpnProfile.mConnections != null &&
+ ((Gateway) obj).mVpnProfile != null &&
+ this.mVpnProfile.mConnections.length > 0 &&
+ ((Gateway) obj).mVpnProfile.mConnections.length > 0 &&
+ this.mVpnProfile.mConnections[0].mServerName != null &&
+ this.mVpnProfile.mConnections[0].mServerName.equals(((Gateway) obj).mVpnProfile.mConnections[0].mServerName)) ||
+ this.mVpnProfile == null && ((Gateway) obj).mVpnProfile == null;
+ }
}
diff --git a/app/src/main/java/se/leap/bitmaskclient/eip/GatewaysManager.java b/app/src/main/java/se/leap/bitmaskclient/eip/GatewaysManager.java
index 003cef7d..060843fd 100644
--- a/app/src/main/java/se/leap/bitmaskclient/eip/GatewaysManager.java
+++ b/app/src/main/java/se/leap/bitmaskclient/eip/GatewaysManager.java
@@ -1,5 +1,5 @@
/**
- * Copyright (c) 2013, 2014, 2015 LEAP Encryption Access Project and contributers
+ * Copyright (c) 2013 - 2019 LEAP Encryption Access Project and contributors
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
@@ -18,7 +18,6 @@ package se.leap.bitmaskclient.eip;
import android.content.Context;
import android.content.SharedPreferences;
-import android.util.Log;
import com.google.gson.Gson;
import com.google.gson.reflect.TypeToken;
@@ -29,13 +28,8 @@ import org.json.JSONObject;
import java.lang.reflect.Type;
import java.util.ArrayList;
-import java.util.Collection;
-import java.util.Iterator;
import java.util.List;
-import de.blinkt.openvpn.VpnProfile;
-import de.blinkt.openvpn.core.Connection;
-import de.blinkt.openvpn.core.ProfileManager;
import se.leap.bitmaskclient.Provider;
import se.leap.bitmaskclient.utils.PreferenceHelper;
@@ -52,13 +46,11 @@ public class GatewaysManager {
private Context context;
private SharedPreferences preferences;
private List<Gateway> gateways = new ArrayList<>();
- private ProfileManager profileManager;
private Type listType = new TypeToken<ArrayList<Gateway>>() {}.getType();
GatewaysManager(Context context, SharedPreferences preferences) {
this.context = context;
this.preferences = preferences;
- profileManager = ProfileManager.getInstance(context);
}
/**
@@ -102,7 +94,7 @@ public class GatewaysManager {
if (isOpenVpnGateway(gw)) {
JSONObject secrets = secretsConfiguration();
Gateway aux = new Gateway(eipDefinition, secrets, gw);
- if (!containsProfileWithSecrets(aux.getProfile())) {
+ if (!gateways.contains(aux)) {
addGateway(aux);
}
}
@@ -139,85 +131,19 @@ public class GatewaysManager {
return result;
}
- private boolean containsProfileWithSecrets(VpnProfile profile) {
- boolean result = false;
- Collection<VpnProfile> profiles = profileManager.getProfiles();
- for (VpnProfile aux : profiles) {
- result = result || sameConnections(profile.mConnections, aux.mConnections)
- && profile.mClientCertFilename.equalsIgnoreCase(aux.mClientCertFilename)
- && profile.mClientKeyFilename.equalsIgnoreCase(aux.mClientKeyFilename);
- }
- return result;
- }
-
- void clearGatewaysAndProfiles() {
+ void clearGateways() {
gateways.clear();
- ArrayList<VpnProfile> profiles = new ArrayList<>(profileManager.getProfiles());
- for (VpnProfile profile : profiles) {
- profileManager.removeProfile(context, profile);
- }
}
private void addGateway(Gateway gateway) {
- removeDuplicatedGateway(gateway);
gateways.add(gateway);
-
- VpnProfile profile = gateway.getProfile();
- profileManager.addProfile(profile);
- }
-
- private void removeDuplicatedGateway(Gateway gateway) {
- Iterator<Gateway> it = gateways.iterator();
- List<Gateway> gatewaysToRemove = new ArrayList<>();
- while (it.hasNext()) {
- Gateway aux = it.next();
- if (sameConnections(aux.getProfile().mConnections, gateway.getProfile().mConnections)) {
- gatewaysToRemove.add(aux);
- }
- }
- gateways.removeAll(gatewaysToRemove);
- removeDuplicatedProfiles(gateway.getProfile());
- }
-
- private void removeDuplicatedProfiles(VpnProfile original) {
- Collection<VpnProfile> profiles = profileManager.getProfiles();
- List<VpnProfile> removeList = new ArrayList<>();
- for (VpnProfile aux : profiles) {
- if (sameConnections(original.mConnections, aux.mConnections)) {
- removeList.add(aux);
- }
- }
- for (VpnProfile profile : removeList) {
- profileManager.removeProfile(context, profile);
- }
- }
-
- /**
- * check if all connections in c1 are also in c2
- * @param c1 array of connections
- * @param c2 array of connections
- * @return true if all connections of c1 exist in c2 and vice versa
- */
- private boolean sameConnections(Connection[] c1, Connection[] c2) {
- int sameConnections = 0;
- for (Connection c1_aux : c1) {
- for (Connection c2_aux : c2)
- if (c2_aux.mServerName.equals(c1_aux.mServerName)) {
- sameConnections++;
- break;
- }
- }
- return c1.length == c2.length && c1.length == sameConnections;
}
/**
* read EipServiceJson from preferences and set gateways
*/
void configureFromPreferences() {
- //TODO: THIS IS A QUICK FIX - it deletes all profiles in ProfileManager, thus it's possible
- // to add all gateways from prefs without duplicates, but this should be refactored.
- clearGatewaysAndProfiles();
fromEipServiceJson(
PreferenceHelper.getEipDefinitionFromPreferences(preferences)
);
diff --git a/app/src/main/java/se/leap/bitmaskclient/fragments/AlwaysOnDialog.java b/app/src/main/java/se/leap/bitmaskclient/fragments/AlwaysOnDialog.java
index e3d004f5..09817b78 100644
--- a/app/src/main/java/se/leap/bitmaskclient/fragments/AlwaysOnDialog.java
+++ b/app/src/main/java/se/leap/bitmaskclient/fragments/AlwaysOnDialog.java
@@ -1,13 +1,14 @@
package se.leap.bitmaskclient.fragments;
import android.app.Dialog;
-import android.content.DialogInterface;
import android.content.Intent;
+import android.os.Build;
import android.os.Bundle;
import android.support.annotation.NonNull;
import android.support.annotation.Nullable;
import android.support.v7.app.AlertDialog;
import android.support.v7.app.AppCompatDialogFragment;
+import android.support.v7.widget.AppCompatTextView;
import android.view.LayoutInflater;
import android.view.View;
import android.widget.CheckBox;
@@ -36,6 +37,10 @@ public class AlwaysOnDialog extends AppCompatDialogFragment {
@InjectView(R.id.user_message)
IconTextView userMessage;
+ @InjectView(R.id.block_vpn_user_message)
+ AppCompatTextView blockVpnUserMessage;
+
+
@Override
public void onCreate(@Nullable Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
@@ -51,22 +56,21 @@ public class AlwaysOnDialog extends AppCompatDialogFragment {
userMessage.setIcon(R.drawable.ic_settings);
userMessage.setText(getString(R.string.always_on_vpn_user_message));
+
+ if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {
+ blockVpnUserMessage.setVisibility(View.VISIBLE);
+ }
+
builder.setView(view)
- .setPositiveButton(android.R.string.ok, new DialogInterface.OnClickListener() {
- public void onClick(DialogInterface dialog, int id) {
- if (doNotShowAgainCheckBox.isChecked()) {
- saveShowAlwaysOnDialog(getContext(), false);
- }
- Intent intent = new Intent("android.net.vpn.SETTINGS");
- intent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
- startActivity(intent);
+ .setPositiveButton(android.R.string.ok, (dialog, id) -> {
+ if (doNotShowAgainCheckBox.isChecked()) {
+ saveShowAlwaysOnDialog(getContext(), false);
}
+ Intent intent = new Intent("android.net.vpn.SETTINGS");
+ intent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
+ startActivity(intent);
})
- .setNegativeButton(R.string.cancel, new DialogInterface.OnClickListener() {
- public void onClick(DialogInterface dialog, int id) {
- dialog.cancel();
- }
- });
+ .setNegativeButton(R.string.cancel, (dialog, id) -> dialog.cancel());
return builder.create();
}
}
diff --git a/app/src/main/java/se/leap/bitmaskclient/fragments/LogFragment.java b/app/src/main/java/se/leap/bitmaskclient/fragments/LogFragment.java
index 268d326d..64d199dc 100644
--- a/app/src/main/java/se/leap/bitmaskclient/fragments/LogFragment.java
+++ b/app/src/main/java/se/leap/bitmaskclient/fragments/LogFragment.java
@@ -8,16 +8,12 @@ package se.leap.bitmaskclient.fragments;
import android.animation.Animator;
import android.animation.AnimatorListenerAdapter;
import android.animation.ObjectAnimator;
-import android.app.Activity;
-import android.app.AlertDialog;
import android.content.ClipData;
import android.content.ClipboardManager;
import android.content.Context;
-import android.content.DialogInterface;
import android.content.Intent;
import android.content.res.Resources;
import android.database.DataSetObserver;
-import android.graphics.drawable.Drawable;
import android.os.Bundle;
import android.os.Handler;
import android.os.Handler.Callback;
@@ -27,7 +23,6 @@ import android.support.annotation.Nullable;
import android.support.v4.app.ListFragment;
import android.text.SpannableString;
import android.text.format.DateFormat;
-import android.text.style.ImageSpan;
import android.view.LayoutInflater;
import android.view.Menu;
import android.view.MenuInflater;
@@ -37,7 +32,6 @@ import android.view.ViewGroup;
import android.widget.AdapterView;
import android.widget.AdapterView.OnItemLongClickListener;
import android.widget.CheckBox;
-import android.widget.CompoundButton;
import android.widget.LinearLayout;
import android.widget.ListAdapter;
import android.widget.ListView;
@@ -52,17 +46,16 @@ import java.util.Date;
import java.util.Locale;
import java.util.Vector;
-import de.blinkt.openvpn.LaunchVPN;
import de.blinkt.openvpn.VpnProfile;
import de.blinkt.openvpn.core.ConnectionStatus;
import de.blinkt.openvpn.core.LogItem;
import de.blinkt.openvpn.core.OpenVPNManagement;
import de.blinkt.openvpn.core.OpenVPNService;
import de.blinkt.openvpn.core.Preferences;
-import de.blinkt.openvpn.core.ProfileManager;
import de.blinkt.openvpn.core.VpnStatus;
import de.blinkt.openvpn.core.VpnStatus.LogListener;
import de.blinkt.openvpn.core.VpnStatus.StateListener;
+import se.leap.bitmaskclient.Constants;
import se.leap.bitmaskclient.R;
import static de.blinkt.openvpn.core.OpenVPNService.humanReadableByteCount;
@@ -70,7 +63,6 @@ import static de.blinkt.openvpn.core.OpenVPNService.humanReadableByteCount;
public class LogFragment extends ListFragment implements StateListener, SeekBar.OnSeekBarChangeListener, RadioGroup.OnCheckedChangeListener, VpnStatus.ByteCountListener {
public static final String TAG = LogFragment.class.getSimpleName();
private static final String LOGTIMEFORMAT = "logtimeformat";
- private static final int START_VPN_CONFIG = 0;
private static final String VERBOSITYLEVEL = "verbositylevel";
@@ -242,7 +234,6 @@ public class LogFragment extends ListFragment implements StateListener, SeekBar.
SpannableString t = new SpannableString(msg);
- //t.setSpan(getSpanImage(le,(int)v.getTextSize()),spanStart,spanStart+1, Spanned.SPAN_INCLUSIVE_INCLUSIVE);
v.setText(t);
return v;
}
@@ -264,34 +255,6 @@ public class LogFragment extends ListFragment implements StateListener, SeekBar.
}
- private ImageSpan getSpanImage(LogItem li, int imageSize) {
- int imageRes = android.R.drawable.ic_menu_call;
-
- switch (li.getLogLevel()) {
- case ERROR:
- imageRes = android.R.drawable.ic_notification_clear_all;
- break;
- case INFO:
- imageRes = android.R.drawable.ic_menu_compass;
- break;
- case VERBOSE:
- imageRes = android.R.drawable.ic_menu_info_details;
- break;
- case WARNING:
- imageRes = android.R.drawable.ic_menu_camera;
- break;
- }
-
- Drawable d = getResources().getDrawable(imageRes);
-
-
- //d.setBounds(0, 0, d.getIntrinsicWidth(), d.getIntrinsicHeight());
- d.setBounds(0, 0, imageSize, imageSize);
- ImageSpan span = new ImageSpan(d, ImageSpan.ALIGN_BOTTOM);
-
- return span;
- }
-
@Override
public int getItemViewType(int position) {
return 0;
@@ -488,39 +451,6 @@ public class LogFragment extends ListFragment implements StateListener, SeekBar.
}
@Override
- public void onActivityResult(int requestCode, int resultCode, Intent data) {
- if (requestCode == START_VPN_CONFIG && resultCode == Activity.RESULT_OK) {
- String configuredVPN = data.getStringExtra(VpnProfile.EXTRA_PROFILEUUID);
-
- final VpnProfile profile = ProfileManager.get(getActivity(), configuredVPN);
- ProfileManager.getInstance(getActivity()).saveProfile(getActivity(), profile);
- // Name could be modified, reset List adapter
-
- AlertDialog.Builder dialog = new AlertDialog.Builder(getActivity());
- dialog.setTitle(R.string.configuration_changed);
- dialog.setMessage(R.string.restart_vpn_after_change);
-
-
- dialog.setPositiveButton(R.string.restart,
- new DialogInterface.OnClickListener() {
- @Override
- public void onClick(DialogInterface dialog, int which) {
- Intent intent = new Intent(getActivity(), LaunchVPN.class);
- intent.putExtra(LaunchVPN.EXTRA_KEY, profile.getUUIDString());
- intent.setAction(Intent.ACTION_MAIN);
- startActivity(intent);
- }
-
-
- });
- dialog.setNegativeButton(R.string.ignore, null);
- dialog.create().show();
- }
- super.onActivityResult(requestCode, resultCode, data);
- }
-
-
- @Override
public void onStop() {
super.onStop();
VpnStatus.removeStateListener(this);
@@ -566,7 +496,7 @@ public class LogFragment extends ListFragment implements StateListener, SeekBar.
setListAdapter(ladapter);
- mTimeRadioGroup = (RadioGroup) v.findViewById(R.id.timeFormatRadioGroup);
+ mTimeRadioGroup = v.findViewById(R.id.timeFormatRadioGroup);
mTimeRadioGroup.setOnCheckedChangeListener(this);
if (ladapter.mTimeFormat == LogWindowListAdapter.TIME_FORMAT_ISO) {
@@ -577,19 +507,15 @@ public class LogFragment extends ListFragment implements StateListener, SeekBar.
mTimeRadioGroup.check(R.id.radioShort);
}
- mClearLogCheckBox = (CheckBox) v.findViewById(R.id.clearlogconnect);
- mClearLogCheckBox.setChecked(PreferenceManager.getDefaultSharedPreferences(getActivity()).getBoolean(LaunchVPN.CLEARLOG, true));
- mClearLogCheckBox.setOnCheckedChangeListener(new CompoundButton.OnCheckedChangeListener() {
- @Override
- public void onCheckedChanged(CompoundButton buttonView, boolean isChecked) {
- Preferences.getDefaultSharedPreferences(getActivity()).edit().putBoolean(LaunchVPN.CLEARLOG, isChecked).apply();
- }
- });
+ mClearLogCheckBox = v.findViewById(R.id.clearlogconnect);
+ mClearLogCheckBox.setChecked(PreferenceManager.getDefaultSharedPreferences(getActivity()).getBoolean(Constants.CLEARLOG, true));
+ mClearLogCheckBox.setOnCheckedChangeListener((buttonView, isChecked) ->
+ Preferences.getDefaultSharedPreferences(getActivity()).edit().putBoolean(Constants.CLEARLOG, isChecked).apply());
- mSpeedView = (TextView) v.findViewById(R.id.speed);
+ mSpeedView = v.findViewById(R.id.speed);
- mOptionsLayout = (LinearLayout) v.findViewById(R.id.logOptionsLayout);
- mLogLevelSlider = (SeekBar) v.findViewById(R.id.LogLevelSlider);
+ mOptionsLayout = v.findViewById(R.id.logOptionsLayout);
+ mLogLevelSlider = v.findViewById(R.id.LogLevelSlider);
mLogLevelSlider.setMax(VpnProfile.MAXLOGLEVEL - 1);
mLogLevelSlider.setProgress(logLevel - 1);
@@ -598,9 +524,9 @@ public class LogFragment extends ListFragment implements StateListener, SeekBar.
if (getResources().getBoolean(R.bool.logSildersAlwaysVisible))
mOptionsLayout.setVisibility(View.VISIBLE);
- mUpStatus = (TextView) v.findViewById(R.id.speedUp);
- mDownStatus = (TextView) v.findViewById(R.id.speedDown);
- mConnectStatus = (TextView) v.findViewById(R.id.speedStatus);
+ mUpStatus = v.findViewById(R.id.speedUp);
+ mDownStatus = v.findViewById(R.id.speedDown);
+ mConnectStatus = v.findViewById(R.id.speedStatus);
if (mShowOptionsLayout)
mOptionsLayout.setVisibility(View.VISIBLE);
return v;
@@ -635,17 +561,13 @@ public class LogFragment extends ListFragment implements StateListener, SeekBar.
if (isAdded()) {
final String cleanLogMessage = VpnStatus.getLastCleanLogMessage(getActivity());
- getActivity().runOnUiThread(new Runnable() {
-
- @Override
- public void run() {
- if (isAdded()) {
- if (mSpeedView != null) {
- mSpeedView.setText(cleanLogMessage);
- }
- if (mConnectStatus != null)
- mConnectStatus.setText(cleanLogMessage);
+ getActivity().runOnUiThread(() -> {
+ if (isAdded()) {
+ if (mSpeedView != null) {
+ mSpeedView.setText(cleanLogMessage);
}
+ if (mConnectStatus != null)
+ mConnectStatus.setText(cleanLogMessage);
}
});
}
diff --git a/app/src/main/java/se/leap/bitmaskclient/utils/PreferenceHelper.java b/app/src/main/java/se/leap/bitmaskclient/utils/PreferenceHelper.java
index 44831049..f5cf590b 100644
--- a/app/src/main/java/se/leap/bitmaskclient/utils/PreferenceHelper.java
+++ b/app/src/main/java/se/leap/bitmaskclient/utils/PreferenceHelper.java
@@ -16,10 +16,13 @@ import java.util.List;
import java.util.Locale;
import java.util.Map;
+import de.blinkt.openvpn.VpnProfile;
import se.leap.bitmaskclient.Provider;
+import static android.content.Context.MODE_PRIVATE;
import static se.leap.bitmaskclient.Constants.ALWAYS_ON_SHOW_DIALOG;
import static se.leap.bitmaskclient.Constants.DEFAULT_SHARED_PREFS_BATTERY_SAVER;
+import static se.leap.bitmaskclient.Constants.LAST_USED_PROFILE;
import static se.leap.bitmaskclient.Constants.PREFERENCES_APP_VERSION;
import static se.leap.bitmaskclient.Constants.PROVIDER_CONFIGURED;
import static se.leap.bitmaskclient.Constants.PROVIDER_EIP_DEFINITION;
@@ -140,6 +143,27 @@ public class PreferenceHelper {
apply();
}
+ /**
+ * Sets the profile that is connected (to connect if the service restarts)
+ */
+ public static void setLastUsedVpnProfile(Context context, VpnProfile connectedProfile) {
+ SharedPreferences prefs = context.getSharedPreferences(SHARED_PREFERENCES, MODE_PRIVATE);
+ SharedPreferences.Editor prefsedit = prefs.edit();
+ prefsedit.putString(LAST_USED_PROFILE, connectedProfile.toJson());
+ prefsedit.apply();
+ }
+
+ /**
+ * Returns the profile that was last connected (to connect if the service restarts)
+ */
+ public static VpnProfile getLastConnectedVpnProfile(Context context) {
+ SharedPreferences preferences = context.getSharedPreferences(SHARED_PREFERENCES, MODE_PRIVATE);
+ String lastConnectedProfileJson = preferences.getString(LAST_USED_PROFILE, null);
+ return VpnProfile.fromJson(lastConnectedProfileJson);
+ }
+
+
+
public static void clearDataOfLastProvider(SharedPreferences preferences) {
clearDataOfLastProvider(preferences, false);
@@ -206,7 +230,7 @@ public class PreferenceHelper {
if (context == null) {
return;
}
- SharedPreferences preferences = context.getSharedPreferences(SHARED_PREFERENCES, Context.MODE_PRIVATE);
+ SharedPreferences preferences = context.getSharedPreferences(SHARED_PREFERENCES, MODE_PRIVATE);
preferences.edit().putBoolean(ALWAYS_ON_SHOW_DIALOG, showAlwaysOnDialog).apply();
}
@@ -214,7 +238,7 @@ public class PreferenceHelper {
if (context == null) {
return true;
}
- SharedPreferences preferences = context.getSharedPreferences(SHARED_PREFERENCES, Context.MODE_PRIVATE);
+ SharedPreferences preferences = context.getSharedPreferences(SHARED_PREFERENCES, MODE_PRIVATE);
return preferences.getBoolean(ALWAYS_ON_SHOW_DIALOG, true);
}
@@ -232,36 +256,14 @@ public class PreferenceHelper {
return result;
}
- /*public static void saveLastProfile(Context context, String uuid) {
- if (context == null) {
- return;
- }
- putString(context, PROVIDER_PROFILE_UUID, uuid);
- }
-
- public static void clearLastProfile(Context context) {
- if (context == null) {
- return;
- }
- SharedPreferences preferences = context.getSharedPreferences(SHARED_PREFERENCES, Context.MODE_PRIVATE);
- preferences.edit().remove(PROVIDER_PROFILE_UUID).apply();
- }
-
- public static String getLastProfile(Context context){
- return getString(context, PROVIDER_PROFILE_UUID, null);
- }
-
- public static void saveLastGatewayNumber(Context context, int number) {
-
- }
-*/
public static String getString(Context context, String key, String defValue) {
- SharedPreferences preferences = context.getSharedPreferences(SHARED_PREFERENCES, Context.MODE_PRIVATE);
+ SharedPreferences preferences = context.getSharedPreferences(SHARED_PREFERENCES, MODE_PRIVATE);
return preferences.getString(key, defValue);
}
public static void putString(Context context, String key, String value){
- SharedPreferences preferences = context.getSharedPreferences(SHARED_PREFERENCES, Context.MODE_PRIVATE);
+ SharedPreferences preferences = context.getSharedPreferences(SHARED_PREFERENCES, MODE_PRIVATE);
preferences.edit().putString(key, value).apply();
}
+
}
diff --git a/app/src/main/res/drawable/cust_button_secondary.xml b/app/src/main/res/drawable/cust_button_secondary.xml
index 553adca8..baed7b44 100644
--- a/app/src/main/res/drawable/cust_button_secondary.xml
+++ b/app/src/main/res/drawable/cust_button_secondary.xml
@@ -4,16 +4,16 @@
<shape android:shape="rectangle" >
<corners android:radius="50dp" />
<padding android:left="8dp" android:right="8dp"/>
- <solid android:color="@android:color/transparent"/>
- <stroke android:width="2dp" android:color="@color/colorPrimary"/>
+ <solid android:color="#20000000"/>
+ <stroke android:width="2dp" android:color="@color/colorPrimaryDark"/>
</shape>
</item>
<item android:state_focused="true">
<shape android:shape="rectangle" >
<corners android:radius="50dp" />
<padding android:left="8dp" android:right="8dp"/>
- <solid android:color="@android:color/transparent"/>
- <stroke android:width="2dp" android:color="@color/colorPrimary"/>
+ <solid android:color="#20000000"/>
+ <stroke android:width="2dp" android:color="@color/colorPrimaryDark"/>
</shape>
</item>
<item >
diff --git a/app/src/main/res/layout/d_checkbox_confirm.xml b/app/src/main/res/layout/d_checkbox_confirm.xml
index 6dd22417..a9a84c0e 100644
--- a/app/src/main/res/layout/d_checkbox_confirm.xml
+++ b/app/src/main/res/layout/d_checkbox_confirm.xml
@@ -1,24 +1,63 @@
<?xml version="1.0" encoding="utf-8"?>
-<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
- android:layout_width="wrap_content"
- android:layout_height="wrap_content"
- android:orientation="vertical">
+<ScrollView xmlns:android="http://schemas.android.com/apk/res/android"
+ android:layout_width="match_parent"
+ android:layout_height="wrap_content">
- <se.leap.bitmaskclient.views.IconTextView
- android:id="@+id/user_message"
+
+ <LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="wrap_content"
- android:layout_margin="@dimen/activity_horizontal_margin"
- android:layout_marginBottom="0dp"
- android:autoLink="web"
- />
+ xmlns:tools="http://schemas.android.com/tools"
+ android:orientation="vertical">
+ <android.support.v7.widget.AppCompatTextView
+ android:id="@+id/tvTitle"
+ android:layout_width="match_parent"
+ android:layout_height="wrap_content"
+ android:layout_marginBottom="@dimen/standard_margin"
+ android:layout_marginTop="@dimen/add_button_margin"
+ android:layout_marginLeft="@dimen/activity_horizontal_margin"
+ android:layout_marginRight="@dimen/activity_horizontal_margin"
+ android:text="@string/always_on_vpn"
+ android:textAllCaps="true"
+ android:textAppearance="@style/TextAppearance.AppCompat.Title"
+ android:textStyle="bold"
+ />
- <CheckBox
- android:id="@+id/do_not_show_again"
- android:layout_width="wrap_content"
- android:layout_height="wrap_content"
- android:layout_margin="@dimen/stdpadding"
- android:text="@string/do_not_show_again" />
+ <se.leap.bitmaskclient.views.IconTextView
+ android:id="@+id/user_message"
+ android:layout_width="match_parent"
+ android:layout_height="wrap_content"
+ android:layout_marginLeft="@dimen/activity_horizontal_margin"
+ android:layout_marginRight="@dimen/activity_horizontal_margin"
+ android:layout_marginBottom="0dp"
+ android:autoLink="web"
+ tools:text="@string/always_on_vpn_user_message"
+ android:textSize="17sp"
+ />
+
+ <android.support.v7.widget.AppCompatTextView
+ android:id="@+id/block_vpn_user_message"
+ android:layout_width="match_parent"
+ android:layout_height="wrap_content"
+ android:layout_marginLeft="@dimen/activity_horizontal_margin"
+ android:layout_marginRight="@dimen/activity_horizontal_margin"
+ android:layout_marginTop="@dimen/standard_margin"
+ android:layout_marginBottom="@dimen/standard_margin"
+ android:text="@string/always_on_blocking_vpn_user_message"
+ android:visibility="gone"
+ tools:visibility="visible"
+ android:textSize="17sp"
+ />
+
+
+ <CheckBox
+ android:id="@+id/do_not_show_again"
+ android:textAppearance="@style/TextAppearance.AppCompat"
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:layout_margin="@dimen/stdpadding"
+ android:text="@string/do_not_show_again" />
-</LinearLayout> \ No newline at end of file
+ </LinearLayout>
+</ScrollView> \ No newline at end of file
diff --git a/app/src/main/res/values-de/strings.xml b/app/src/main/res/values-de/strings.xml
index 0fba388e..0b25a2a2 100644
--- a/app/src/main/res/values-de/strings.xml
+++ b/app/src/main/res/values-de/strings.xml
@@ -113,6 +113,7 @@
<string name="always_on_vpn">VPN immer anlassen</string>
<string name="do_not_show_again">Nicht erneut anzeigen</string>
<string name="always_on_vpn_user_message">Um durchgehend aktives VPN in den Android VPN Einstellungen einzuschalten, klicke auf das Zahnrad [img src] und aktiviere den Schalter.</string>
+ <string name="always_on_blocking_vpn_user_message">Aktiviere zusätzlich die Option \"Verbindungen nur über VPN zulassen\", um deine Privatsphäre optimal zu schützen.</string>
<string name="donate_title">Spenden</string>
<string name="donate_default_message">Spende noch heute, wenn du sichere Kommunikation wertschätzt, die sowohl für Endnutzer*innen als auch Menschen die den Service bereit stellen leicht nutzbar ist.</string>
<string name="donate_message">LEAP benötigt Spenden und Stipendien. Spende noch heute wenn du sichere Kommunikation wertschätzt, die sowohl für Enandwender*innen als auch Menschen die den Dienst anbieten leicht nutzbar ist.</string>
diff --git a/app/src/main/res/values/strings.xml b/app/src/main/res/values/strings.xml
index 551b7cb1..1b22592a 100644
--- a/app/src/main/res/values/strings.xml
+++ b/app/src/main/res/values/strings.xml
@@ -104,6 +104,7 @@
<string name="always_on_vpn">Always-on VPN</string>
<string name="do_not_show_again">Do not show again</string>
<string name="always_on_vpn_user_message">To enable always-on VPN in Android VPN Settings click on the configure icon [img src] and turn the switch on.</string>
+ <string name="always_on_blocking_vpn_user_message">To protect your privacy optimally, you should also activate the option \"Block connections without VPN\".</string>
<string name="donate_title">Donate</string>
<string name="donate_default_message">Please donate today if you value secure communication that is easy for both the end-user and the service provider.</string>
<string name="donate_message">LEAP depends on donations and grants. Please donate today if you value secure communication that is easy for both the end-user and the service provider.</string>
diff --git a/app/src/test/java/se/leap/bitmaskclient/eip/EipStatusTest.java b/app/src/test/java/se/leap/bitmaskclient/eip/EipStatusTest.java
index f332b094..8495f962 100644
--- a/app/src/test/java/se/leap/bitmaskclient/eip/EipStatusTest.java
+++ b/app/src/test/java/se/leap/bitmaskclient/eip/EipStatusTest.java
@@ -3,14 +3,17 @@ package se.leap.bitmaskclient.eip;
import org.junit.Before;
import org.junit.Test;
import org.junit.runner.RunWith;
+import org.mockito.ArgumentMatchers;
import org.powermock.core.classloader.annotations.PrepareForTest;
import org.powermock.modules.junit4.PowerMockRunner;
import de.blinkt.openvpn.VpnProfile;
import de.blinkt.openvpn.core.ConnectionStatus;
-import de.blinkt.openvpn.core.ProfileManager;
import de.blinkt.openvpn.core.VpnStatus;
import se.leap.bitmaskclient.R;
+import se.leap.bitmaskclient.testutils.MockHelper;
+import se.leap.bitmaskclient.testutils.TestSetupHelper;
+import se.leap.bitmaskclient.utils.PreferenceHelper;
import static de.blinkt.openvpn.core.ConnectionStatus.LEVEL_AUTH_FAILED;
import static de.blinkt.openvpn.core.ConnectionStatus.LEVEL_CONNECTED;
@@ -21,6 +24,8 @@ import static de.blinkt.openvpn.core.ConnectionStatus.LEVEL_VPNPAUSED;
import static de.blinkt.openvpn.core.ConnectionStatus.LEVEL_WAITING_FOR_USER_INPUT;
import static de.blinkt.openvpn.core.ConnectionStatus.UNKNOWN_LEVEL;
import static junit.framework.Assert.assertTrue;
+import static org.mockito.ArgumentMatchers.anyString;
+import static org.powermock.api.mockito.PowerMockito.doNothing;
import static org.powermock.api.mockito.PowerMockito.mockStatic;
import static org.powermock.api.mockito.PowerMockito.when;
import static se.leap.bitmaskclient.eip.EipStatus.EipLevel.CONNECTING;
@@ -32,7 +37,7 @@ import static se.leap.bitmaskclient.eip.EipStatus.EipLevel.UNKNOWN;
* TODO: Mock AsyncTask
*/
@RunWith(PowerMockRunner.class)
-@PrepareForTest({ProfileManager.class})
+@PrepareForTest({PreferenceHelper.class})
public class EipStatusTest {
EipStatus eipStatus;
@@ -55,10 +60,11 @@ public class EipStatusTest {
@Test
public void testUpdateState_LEVEL_VPNPAUSED_hasPersistentTun() throws Exception {
- mockStatic(ProfileManager.class);
+ mockStatic(PreferenceHelper.class);
VpnProfile mockVpnProfile = new VpnProfile("mockProfile");
mockVpnProfile.mPersistTun = true;
- when(ProfileManager.getLastConnectedVpn()).thenReturn(mockVpnProfile);
+ doNothing().when(PreferenceHelper.class);
+ VpnStatus.setLastConnectedVpnProfile(null, mockVpnProfile);
VpnStatus.updateStateString("SCREENOFF", "", R.string.state_screenoff, LEVEL_VPNPAUSED);
assertTrue("LEVEL_VPN_PAUSED eipLevel", eipStatus.getEipLevel() == CONNECTING);
assertTrue("LEVEL_VPN_PAUSED level", eipStatus.getLevel() == LEVEL_VPNPAUSED);
@@ -67,10 +73,11 @@ public class EipStatusTest {
@Test
public void testUpdateState_LEVEL_VPNPAUSED_hasNotPersistentTun() throws Exception {
- mockStatic(ProfileManager.class);
+ mockStatic(PreferenceHelper.class);
VpnProfile mockVpnProfile = new VpnProfile("mockProfile");
mockVpnProfile.mPersistTun = false;
- when(ProfileManager.getLastConnectedVpn()).thenReturn(mockVpnProfile);
+ doNothing().when(PreferenceHelper.class);
+ VpnStatus.setLastConnectedVpnProfile(null, mockVpnProfile);
VpnStatus.updateStateString("SCREENOFF", "", R.string.state_screenoff, LEVEL_VPNPAUSED);
assertTrue("LEVEL_VPN_PAUSED eipLevel", eipStatus.getEipLevel() == DISCONNECTED);
assertTrue("LEVEL_VPN_PAUSED level", eipStatus.getLevel() == LEVEL_VPNPAUSED);
diff --git a/app/src/test/java/se/leap/bitmaskclient/eip/GatewaysManagerTest.java b/app/src/test/java/se/leap/bitmaskclient/eip/GatewaysManagerTest.java
index 4726cab7..160e5ddd 100644
--- a/app/src/test/java/se/leap/bitmaskclient/eip/GatewaysManagerTest.java
+++ b/app/src/test/java/se/leap/bitmaskclient/eip/GatewaysManagerTest.java
@@ -46,7 +46,6 @@ public class GatewaysManagerTest {
when(sharedPreferences.getString(eq(Constants.PROVIDER_PRIVATE_KEY), anyString())).thenReturn(secrets.getString(Constants.PROVIDER_PRIVATE_KEY));
when(sharedPreferences.getString(eq(Provider.CA_CERT), anyString())).thenReturn(secrets.getString(Provider.CA_CERT));
when(sharedPreferences.getString(eq(Constants.PROVIDER_VPN_CERTIFICATE), anyString())).thenReturn(secrets.getString(Constants.PROVIDER_VPN_CERTIFICATE));
- when(mockContext.getSharedPreferences(anyString(), anyInt())).thenReturn(sharedPreferences);
gatewaysManager = new GatewaysManager(mockContext, sharedPreferences);
@@ -74,7 +73,7 @@ public class GatewaysManagerTest {
String eipServiceJson = TestSetupHelper.getInputAsString(getClass().getClassLoader().getResourceAsStream("eip-service-two-gateways.json"));
gatewaysManager.fromEipServiceJson(new JSONObject(eipServiceJson));
assertEquals(2, gatewaysManager.size());
- gatewaysManager.clearGatewaysAndProfiles();
+ gatewaysManager.clearGateways();
assertEquals(0, gatewaysManager.size());
}