Commit 665b9651 authored by cyberta's avatar cyberta

Merge branch 'beta-release' into 'master'

Beta release

See merge request !131
parents 8bb73089 401e2843
Pipeline #54899 passed with stages
in 21 minutes and 12 seconds
......@@ -216,6 +216,7 @@ android {
//runProguard true
if(signingConfigs.contains(release))
signingConfig signingConfigs.release.isSigningReady() ? signingConfigs.release : signingConfigs.debug
//ndk.debugSymbolLevel = "full"
//minifyEnabled = true
//shrinkResources true
buildConfigField "Boolean", "DEBUG_MODE", "false"
......@@ -426,7 +427,7 @@ android.applicationVariants.all { variant ->
}
// remove unrelated abi specific assets
variant.mergeAssets.doLast {
variant.mergeAssetsProvider.get().doLast {
// if not a fat build
if (abiDimension.abiVersionCode > 0) {
def filesToDelete = fileTree(dir: variant.mergeAssets.outputDir, excludes: ["*pie_openvpn.${abiDimension.abiFilter}",
......
......@@ -204,7 +204,7 @@ public class ProviderApiManager extends ProviderApiManagerBase {
result.putBoolean(BROADCAST_RESULT_KEY, true);
}
} catch (NullPointerException | JSONException e) {
setErrorResult(result, eipServiceJsonString);
setErrorResult(result, R.string.error_json_exception_user_message, null);
}
//TODO: check why the following line is not in production
result.putParcelable(PROVIDER_KEY, provider);
......
......@@ -23,4 +23,6 @@ interface IOpenVPNServiceInternal {
boolean isVpnRunning();
void startWithForegroundNotification();
}
......@@ -5,29 +5,25 @@
package de.blinkt.openvpn;
import android.annotation.TargetApi;
import android.app.Activity;
import android.app.AlertDialog;
import android.content.ActivityNotFoundException;
import android.content.DialogInterface;
import android.content.DialogInterface.OnClickListener;
import android.content.Intent;
import android.content.SharedPreferences;
import android.net.VpnService;
import android.os.Build;
import android.os.Bundle;
import java.io.IOException;
import androidx.annotation.StringRes;
import de.blinkt.openvpn.core.ConnectionStatus;
import de.blinkt.openvpn.core.Preferences;
import de.blinkt.openvpn.core.VPNLaunchHelper;
import de.blinkt.openvpn.core.VpnStatus;
import se.leap.bitmaskclient.base.MainActivity;
import se.leap.bitmaskclient.R;
import se.leap.bitmaskclient.eip.EipCommand;
import static se.leap.bitmaskclient.base.models.Constants.BROADCAST_RESULT_KEY;
import static se.leap.bitmaskclient.base.models.Constants.EIP_ACTION_PREPARE_VPN;
import static se.leap.bitmaskclient.base.models.Constants.EIP_N_CLOSEST_GATEWAY;
import static se.leap.bitmaskclient.base.models.Constants.PROVIDER_PROFILE;
import static se.leap.bitmaskclient.eip.EIP.ERRORS;
import static se.leap.bitmaskclient.eip.EipResultBroadcast.tellToReceiverOrBroadcast;
/**
......@@ -57,54 +53,52 @@ import static se.leap.bitmaskclient.eip.EipResultBroadcast.tellToReceiverOrBroad
*/
public class LaunchVPN extends Activity {
public static final String EXTRA_KEY = "de.blinkt.openvpn.shortcutProfileUUID";
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";
private static final int START_VPN_PROFILE = 70;
private static final String TAG = LaunchVPN.class.getName();
private VpnProfile selectedProfile;
private int selectedGateway;
private VpnProfile mSelectedProfile;
private boolean mhideLog = false;
private boolean mCmfixed = false;
@Override
public void onCreate(Bundle icicle) {
super.onCreate(icicle);
startVpnFromIntent();
}
protected void startVpnFromIntent() {
// Resolve the intent
final Intent intent = getIntent();
final String action = intent.getAction();
if (!Intent.ACTION_MAIN.equals(action)) {
finish();
}
// If the intent is a request to create a shortcut, we'll do that and exit
VpnProfile profileToConnect = (VpnProfile) intent.getExtras().getSerializable(PROVIDER_PROFILE);
selectedGateway = intent.getExtras().getInt(EIP_N_CLOSEST_GATEWAY, 0);
if (profileToConnect == null) {
showAlertInMainActivity(R.string.shortcut_profile_notfound);
finish();
} else {
selectedProfile = profileToConnect;
}
if (Intent.ACTION_MAIN.equals(action)) {
// Check if we need to clear the log
if (Preferences.getDefaultSharedPreferences(this).getBoolean(CLEARLOG, true))
VpnStatus.clearLog();
Intent vpnIntent;
try {
vpnIntent = VpnService.prepare(this.getApplicationContext());
} catch (NullPointerException npe) {
showAlertInMainActivity(R.string.vpn_error_establish);
finish();
return;
}
// we got called to be the starting point, most likely a shortcut
mhideLog = intent.getBooleanExtra(EXTRA_HIDELOG, false);
VpnProfile profileToConnect = (VpnProfile) intent.getExtras().getSerializable(PROVIDER_PROFILE);
if (vpnIntent != null) {
// we don't have the permission yet to start the VPN
if (profileToConnect == null) {
VpnStatus.logError(R.string.shortcut_profile_notfound);
// show Log window to display error
showLogWindow();
finish();
} else {
mSelectedProfile = profileToConnect;
launchVPN();
VpnStatus.updateStateString("USER_VPN_PERMISSION", "", R.string.state_user_vpn_permission,
ConnectionStatus.LEVEL_WAITING_FOR_USER_INPUT);
// Start the query
try {
startActivityForResult(vpnIntent, START_VPN_PROFILE);
} catch (ActivityNotFoundException ane) {
// Shame on you Sony! At least one user reported that
// an official Sony Xperia Arc S image triggers this exception
showAlertInMainActivity(R.string.no_vpn_support_image);
}
}
}
......@@ -113,13 +107,8 @@ public class LaunchVPN extends Activity {
protected void onActivityResult(int requestCode, int resultCode, Intent data) {
super.onActivityResult(requestCode, resultCode, data);
if(requestCode==START_VPN_PROFILE) {
SharedPreferences prefs = Preferences.getDefaultSharedPreferences(this);
boolean showLogWindow = prefs.getBoolean("showlogwindow", true);
if(!mhideLog && showLogWindow)
showLogWindow();
VPNLaunchHelper.startOpenVpn(mSelectedProfile, getBaseContext());
if(requestCode==START_VPN_PROFILE && resultCode == Activity.RESULT_OK) {
EipCommand.launchVPNProfile(getApplicationContext(), selectedProfile, selectedGateway);
finish();
} else if (resultCode == Activity.RESULT_CANCELED) {
......@@ -127,110 +116,29 @@ public class LaunchVPN extends Activity {
VpnStatus.updateStateString("USER_VPN_PERMISSION_CANCELLED", "", R.string.state_user_vpn_permission_cancelled,
ConnectionStatus.LEVEL_NOTCONNECTED);
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.N)
VpnStatus.logError(R.string.nought_alwayson_warning);
finish();
}
}
void showLogWindow() {
Intent startLW = new Intent(getBaseContext(), MainActivity.class);
startLW.putExtra(MainActivity.ACTION_SHOW_LOG_FRAGMENT, true);
startLW.addFlags(Intent.FLAG_ACTIVITY_REORDER_TO_FRONT);
startActivity(startLW);
}
void showConfigErrorDialog(int vpnok) {
AlertDialog.Builder d = new AlertDialog.Builder(this);
d.setTitle(R.string.config_error_found);
d.setMessage(vpnok);
d.setPositiveButton(android.R.string.ok, new OnClickListener() {
@Override
public void onClick(DialogInterface dialog, int which) {
finish();
}
});
d.setOnCancelListener(new DialogInterface.OnCancelListener() {
@Override
public void onCancel(DialogInterface dialog) {
finish();
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.N) {
showAlertInMainActivity(R.string.nought_alwayson_warning);
}
});
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP_MR1)
setOnDismissListener(d);
d.show();
}
@TargetApi(Build.VERSION_CODES.JELLY_BEAN_MR1)
private void setOnDismissListener(AlertDialog.Builder d) {
d.setOnDismissListener(new DialogInterface.OnDismissListener() {
@Override
public void onDismiss(DialogInterface dialog) {
finish();
}
});
}
void launchVPN() {
int vpnok = mSelectedProfile.checkProfile(this);
if (vpnok != R.string.no_error_found) {
showConfigErrorDialog(vpnok);
return;
}
Intent intent = null;
try {
intent = VpnService.prepare(this.getApplicationContext());
} catch (NullPointerException npe) {
tellToReceiverOrBroadcast(this.getApplicationContext(), EIP_ACTION_PREPARE_VPN, RESULT_CANCELED);
finish();
return;
}
// Check if we want to fix /dev/tun
SharedPreferences prefs = Preferences.getDefaultSharedPreferences(this);
boolean usecm9fix = prefs.getBoolean("useCM9Fix", false);
boolean loadTunModule = prefs.getBoolean("loadTunModule", false);
if (loadTunModule)
execeuteSUcmd("insmod /system/lib/modules/tun.ko");
if (usecm9fix && !mCmfixed) {
execeuteSUcmd("chown system /dev/tun");
}
if (intent != null) {
VpnStatus.updateStateString("USER_VPN_PERMISSION", "", R.string.state_user_vpn_permission,
ConnectionStatus.LEVEL_WAITING_FOR_USER_INPUT);
// Start the query
try {
startActivityForResult(intent, START_VPN_PROFILE);
} catch (ActivityNotFoundException ane) {
// Shame on you Sony! At least one user reported that
// an official Sony Xperia Arc S image triggers this exception
VpnStatus.logError(R.string.no_vpn_support_image);
showLogWindow();
}
} else {
onActivityResult(START_VPN_PROFILE, Activity.RESULT_OK, null);
}
}
void showAlertInMainActivity(@StringRes int errorString) {
Bundle result = new Bundle();
setErrorResult(result, errorString);
tellToReceiverOrBroadcast(this.getApplicationContext(), EIP_ACTION_PREPARE_VPN, RESULT_CANCELED, result);
}
private void execeuteSUcmd(String command) {
try {
ProcessBuilder pb = new ProcessBuilder("su", "-c", command);
Process p = pb.start();
int ret = p.waitFor();
if (ret == 0)
mCmfixed = true;
} catch (InterruptedException | IOException e) {
VpnStatus.logException("SU command", e);
}
/**
* helper function to add error to result bundle
*
* @param result - result of an action
* @param errorMessageId - id of string resource describing the error
*/
void setErrorResult(Bundle result, @StringRes int errorMessageId) {
VpnStatus.logError(errorMessageId);
result.putString(ERRORS, getResources().getString(errorMessageId));
result.putBoolean(BROADCAST_RESULT_KEY, false);
}
}
\ No newline at end of file
......@@ -8,12 +8,10 @@ package de.blinkt.openvpn.core;
import android.Manifest.permission;
import android.annotation.TargetApi;
import android.app.Notification;
import android.app.UiModeManager;
import android.content.Intent;
import android.content.IntentFilter;
import android.content.pm.PackageManager;
import android.content.pm.ShortcutManager;
import android.content.res.Configuration;
import android.content.res.Resources;
import android.net.ConnectivityManager;
import android.net.VpnService;
......@@ -24,12 +22,13 @@ import android.os.IBinder;
import android.os.Message;
import android.os.ParcelFileDescriptor;
import android.os.RemoteException;
import androidx.annotation.RequiresApi;
import android.system.OsConstants;
import android.text.TextUtils;
import android.util.Log;
import android.widget.Toast;
import androidx.annotation.RequiresApi;
import java.io.IOException;
import java.lang.reflect.InvocationTargetException;
import java.net.Inet6Address;
......@@ -45,9 +44,10 @@ import de.blinkt.openvpn.core.VpnStatus.StateListener;
import de.blinkt.openvpn.core.connection.Connection;
import de.blinkt.openvpn.core.connection.Obfs4Connection;
import se.leap.bitmaskclient.R;
import se.leap.bitmaskclient.eip.EipStatus;
import se.leap.bitmaskclient.eip.VpnNotificationManager;
import se.leap.bitmaskclient.pluggableTransports.Shapeshifter;
import se.leap.bitmaskclient.firewall.FirewallManager;
import se.leap.bitmaskclient.pluggableTransports.Shapeshifter;
import static de.blinkt.openvpn.core.ConnectionStatus.LEVEL_CONNECTED;
import static de.blinkt.openvpn.core.ConnectionStatus.LEVEL_WAITING_FOR_USER_INPUT;
......@@ -61,7 +61,6 @@ public class OpenVPNService extends VpnService implements StateListener, Callbac
public static final String START_SERVICE_STICKY = "de.blinkt.openvpn.START_SERVICE_STICKY";
public static final String ALWAYS_SHOW_NOTIFICATION = "de.blinkt.openvpn.NOTIFICATION_ALWAYS_VISIBLE";
public static final String DISCONNECT_VPN = "de.blinkt.openvpn.DISCONNECT_VPN";
public static final String NOTIFICATION_CHANNEL_BG_ID = "openvpn_bg";
public static final String NOTIFICATION_CHANNEL_NEWSTATUS_ID = "openvpn_newstat";
public static final String VPNSERVICE_TUN = "vpnservice-tun";
public final static String ORBOT_PACKAGE_NAME = "org.torproject.android";
......@@ -92,11 +91,6 @@ public class OpenVPNService extends VpnService implements StateListener, Callbac
private Shapeshifter shapeshifter;
private FirewallManager firewallManager;
private static final int PRIORITY_MIN = -2;
private static final int PRIORITY_DEFAULT = 0;
private static final int PRIORITY_MAX = 2;
private final IBinder mBinder = new IOpenVPNServiceInternal.Stub() {
@Override
......@@ -118,6 +112,11 @@ public class OpenVPNService extends VpnService implements StateListener, Callbac
public boolean isVpnRunning() throws RemoteException {
return OpenVPNService.this.isVpnRunning();
}
@Override
public void startWithForegroundNotification() throws RemoteException {
OpenVPNService.this.startWithForegroundNotification();
}
};
// From: http://stackoverflow.com/questions/3758606/how-to-convert-byte-size-into-human-readable-format-in-java
......@@ -197,13 +196,6 @@ public class OpenVPNService extends VpnService implements StateListener, Callbac
firewallManager.stop();
}
private boolean runningOnAndroidTV() {
UiModeManager uiModeManager = (UiModeManager) getSystemService(UI_MODE_SERVICE);
if (uiModeManager == null)
return false;
return uiModeManager.getCurrentModeType() == Configuration.UI_MODE_TYPE_TELEVISION;
}
synchronized void registerDeviceStateReceiver(OpenVPNManagement magnagement) {
// Registers BroadcastReceiver to track network connection changes.
IntentFilter filter = new IntentFilter();
......@@ -218,8 +210,6 @@ public class OpenVPNService extends VpnService implements StateListener, Callbac
registerReceiver(mDeviceStateReceiver, filter);
VpnStatus.addByteCountListener(mDeviceStateReceiver);
/*if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP)
addLollipopCMListener(); */
}
synchronized void unregisterDeviceStateReceiver() {
......@@ -235,9 +225,6 @@ public class OpenVPNService extends VpnService implements StateListener, Callbac
}
mDeviceStateReceiver = null;
/*if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP)
removeLollipopCMListener();*/
}
@Override
......@@ -280,6 +267,13 @@ public class OpenVPNService extends VpnService implements StateListener, Callbac
}
@Override
public void startWithForegroundNotification() {
// Always show notification here to avoid problem with startForeground timeout
notificationManager.createOpenVpnNotificationChannel();
notificationManager.buildForegroundServiceNotification(EipStatus.getInstance().getLevel(), this::onNotificationBuild);
}
@Override
public int onStartCommand(Intent intent, int flags, int startId) {
......@@ -334,6 +328,8 @@ public class OpenVPNService extends VpnService implements StateListener, Callbac
} else {
/* The intent is null when we are set as always-on or the service has been restarted. */
Log.d(TAG, "Starting VPN due to isAlwaysOn system settings or app crash.");
startWithForegroundNotification();
mProfile = VpnStatus.getLastConnectedVpnProfile(this);
VpnStatus.logInfo(R.string.service_restarted);
......@@ -375,9 +371,6 @@ public class OpenVPNService extends VpnService implements StateListener, Callbac
}
private void startOpenVPN() {
/**
* see change above (l. 292 ff)
*/
//TODO: investigate how connections[n] with n>0 get called during vpn setup (on connection refused?)
// Do we need to check if there's any obfs4 connection in mProfile.mConnections and start
// the dispatcher here? Can we start the dispatcher at a later point of execution, e.g. when
......@@ -524,8 +517,7 @@ public class OpenVPNService extends VpnService implements StateListener, Callbac
@Override
public void onCreate() {
super.onCreate();
notificationManager = new VpnNotificationManager(this, this);
notificationManager.createOpenVpnNotificationChannel();
notificationManager = new VpnNotificationManager(this);
firewallManager = new FirewallManager(this, true);
}
......@@ -543,9 +535,8 @@ public class OpenVPNService extends VpnService implements StateListener, Callbac
// Just in case unregister for state
VpnStatus.removeStateListener(this);
VpnStatus.flushLog();
notificationManager.deleteNotificationChannel(NOTIFICATION_CHANNEL_BG_ID);
notificationManager.deleteNotificationChannel(NOTIFICATION_CHANNEL_NEWSTATUS_ID);
firewallManager.onDestroy();
notificationManager.cancelAll();
}
private String getTunConfigString() {
......@@ -1013,14 +1004,10 @@ public class OpenVPNService extends VpnService implements StateListener, Callbac
if (mProcessThread == null && !mNotificationAlwaysVisible)
return;
String channel = NOTIFICATION_CHANNEL_NEWSTATUS_ID;
// Display byte count only after being connected
if (level == LEVEL_CONNECTED) {
mDisplayBytecount = true;
mConnecttime = System.currentTimeMillis();
if (!runningOnAndroidTV())
channel = NOTIFICATION_CHANNEL_BG_ID;
firewallManager.start();
} else {
mDisplayBytecount = false;
......@@ -1033,7 +1020,7 @@ public class OpenVPNService extends VpnService implements StateListener, Callbac
VpnStatus.getLastCleanLogMessage(this),
level,
0,
channel);
NOTIFICATION_CHANNEL_NEWSTATUS_ID);
}
......@@ -1064,7 +1051,7 @@ public class OpenVPNService extends VpnService implements StateListener, Callbac
null,
LEVEL_CONNECTED,
mConnecttime,
NOTIFICATION_CHANNEL_BG_ID);
NOTIFICATION_CHANNEL_NEWSTATUS_ID);
}
}
......@@ -1108,7 +1095,7 @@ public class OpenVPNService extends VpnService implements StateListener, Callbac
getString(resid),
LEVEL_WAITING_FOR_USER_INPUT,
0,
NOTIFICATION_CHANNEL_BG_ID);
NOTIFICATION_CHANNEL_NEWSTATUS_ID);
}
......@@ -1117,11 +1104,6 @@ public class OpenVPNService extends VpnService implements StateListener, Callbac
startForeground(notificationId, notification);
}
@Override
public void onNotificationStop() {
stopForeground(true);
}
public void trigger_url_open(String info) {
/*
String channel = NOTIFICATION_CHANNEL_USERREQ_ID;
......
......@@ -7,7 +7,6 @@ package de.blinkt.openvpn.core;
import android.annotation.TargetApi;
import android.content.Context;
import android.content.Intent;
import android.os.Build;
import java.io.File;
......@@ -18,7 +17,6 @@ import java.util.Arrays;
import java.util.Vector;
import se.leap.bitmaskclient.R;
import de.blinkt.openvpn.VpnProfile;
public class VPNLaunchHelper {
private static final String MININONPIEVPN = "nopie_openvpn";
......@@ -120,7 +118,6 @@ public class VPNLaunchHelper {
return false;
}
return true;
} catch (IOException e) {
VpnStatus.logException(e);
......@@ -129,20 +126,6 @@ public class VPNLaunchHelper {
}
public static void startOpenVpn(VpnProfile startprofile, Context context) {
Intent startVPN = startprofile.prepareStartService(context);
if (startVPN != null) {
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O)
//noinspection NewApi
context.startForegroundService(startVPN);
else
context.startService(startVPN);
}
}
public static String getConfigFilePath(Context context) {
return context.getCacheDir().getAbsolutePath() + "/" + OVPNCONFIGFILE;
}
......
......@@ -20,13 +20,14 @@ package se.leap.bitmaskclient.base;
import android.content.Intent;
import android.content.SharedPreferences;
import android.os.Bundle;
import android.util.Log;
import androidx.annotation.StringRes;
import androidx.appcompat.app.ActionBar;
import androidx.appcompat.app.AppCompatActivity;
import androidx.fragment.app.DialogFragment;
import androidx.fragment.app.Fragment;
import androidx.fragment.app.FragmentTransaction;
import androidx.appcompat.app.ActionBar;
import androidx.appcompat.app.AppCompatActivity;
import android.util.Log;
import org.json.JSONException;
import org.json.JSONObject;
......@@ -35,24 +36,27 @@ import java.util.Observable;
import java.util.Observer;
import se.leap.bitmaskclient.R;
import se.leap.bitmaskclient.base.fragments.NavigationDrawerFragment;
import se.leap.bitmaskclient.eip.EIP;
import se.leap.bitmaskclient.eip.EipCommand;
import se.leap.bitmaskclient.eip.EipSetupListener;
import se.leap.bitmaskclient.eip.EipSetupObserver;
import se.leap.bitmaskclient.base.fragments.EipFragment;
import se.leap.bitmaskclient.base.fragments.ExcludeAppsFragment;
import se.leap.bitmaskclient.base.fragments.LogFragment;
import se.leap.bitmaskclient.base.fragments.MainActivityErrorDialog;
import se.leap.bitmaskclient.base.fragments.NavigationDrawerFragment;
import se.leap.bitmaskclient.base.models.Provider;
import se.leap.bitmaskclient.base.models.ProviderObservable;
import se.leap.bitmaskclient.providersetup.models.LeapSRPSession;
import se.leap.bitmaskclient.providersetup.activities.LoginActivity;
import se.leap.bitmaskclient.base.utils.PreferenceHelper;
import se.leap.bitmaskclient.base.fragments.MainActivityErrorDialog;