From a9e47acac093af3c9031a381593bbe40e8162160 Mon Sep 17 00:00:00 2001 From: Arne Schwabe Date: Fri, 24 Nov 2023 15:52:52 +0100 Subject: Allow OpenVPNService to request VPN permission if it is missing With other services no longer being able to easily request permissions the service needs now its own way to request permissions. --- .../de/blinkt/openvpn/core/OpenVPNService.java | 40 +++++++++++++++++++--- .../de/blinkt/openvpn/core/StatusListener.java | 14 ++++---- main/src/main/res/values/strings.xml | 3 +- 3 files changed, 46 insertions(+), 11 deletions(-) diff --git a/main/src/main/java/de/blinkt/openvpn/core/OpenVPNService.java b/main/src/main/java/de/blinkt/openvpn/core/OpenVPNService.java index 0e8793e4..983b63f3 100644 --- a/main/src/main/java/de/blinkt/openvpn/core/OpenVPNService.java +++ b/main/src/main/java/de/blinkt/openvpn/core/OpenVPNService.java @@ -5,6 +5,7 @@ package de.blinkt.openvpn.core; +import static android.content.Intent.FLAG_ACTIVITY_NEW_TASK; 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; @@ -14,8 +15,6 @@ import android.app.Notification; import android.app.NotificationManager; import android.app.PendingIntent; import android.app.UiModeManager; -import android.app.job.JobInfo; -import android.app.job.JobScheduler; import android.content.ComponentName; import android.content.Context; import android.content.Intent; @@ -37,7 +36,6 @@ import android.os.HandlerThread; import android.os.IBinder; import android.os.Message; import android.os.ParcelFileDescriptor; -import android.os.PersistableBundle; import android.os.RemoteException; import android.system.OsConstants; import android.text.TextUtils; @@ -528,6 +526,7 @@ public class OpenVPNService extends VpnService implements StateListener, Callbac return START_REDELIVER_INTENT; } + // Always show notification here to avoid problem with startForeground timeout VpnStatus.logInfo(R.string.building_configration); VpnStatus.updateStateString("VPN_GENERATE_CONFIG", "", R.string.building_configration, ConnectionStatus.LEVEL_START); @@ -596,6 +595,34 @@ public class OpenVPNService extends VpnService implements StateListener, Callbac return mProfile; } + private boolean checkVPNPermission(VpnProfile startprofile) { + if (prepare(this) == null) + return true; + + NotificationManager mNotificationManager = (NotificationManager) getSystemService(Context.NOTIFICATION_SERVICE); + + Notification.Builder nbuilder = new Notification.Builder(this); + nbuilder.setAutoCancel(true); + int icon = android.R.drawable.ic_dialog_info; + nbuilder.setSmallIcon(icon); + + Intent launchVPNIntent = new Intent(this, LaunchVPN.class); + launchVPNIntent.putExtra(LaunchVPN.EXTRA_KEY, startprofile.getUUIDString()); + launchVPNIntent.putExtra(LaunchVPN.EXTRA_START_REASON, "OpenService lacks permission"); + launchVPNIntent.putExtra(de.blinkt.openvpn.LaunchVPN.EXTRA_HIDELOG, true); + launchVPNIntent.addFlags(FLAG_ACTIVITY_NEW_TASK); + launchVPNIntent.setAction(Intent.ACTION_MAIN); + + + showNotification(getString(R.string.permission_requested), + "", NOTIFICATION_CHANNEL_USERREQ_ID, 0, LEVEL_WAITING_FOR_USER_INPUT, launchVPNIntent); + + VpnStatus.updateStateString("USER_INPUT", "waiting for user input", R.string.permission_requested, LEVEL_WAITING_FOR_USER_INPUT, launchVPNIntent); + return false; + } + + + private void startOpenVPN(Intent intent, int startId) { VpnProfile vp = fetchVPNProfile(intent); if (vp == null) { @@ -603,6 +630,9 @@ public class OpenVPNService extends VpnService implements StateListener, Callbac return; } + if (!checkVPNPermission(vp)) + return; + ProfileManager.setConnectedVpnProfile(this, mProfile); VpnStatus.setConnectedVPNProfile(mProfile.getUUIDString()); keepVPNAlive.scheduleKeepVPNAliveJobService(this, vp); @@ -1353,7 +1383,6 @@ public class OpenVPNService extends VpnService implements StateListener, Callbac } public void trigger_sso(String info) { - String channel = NOTIFICATION_CHANNEL_USERREQ_ID; String method = info.split(":", 2)[0]; NotificationManager mNotificationManager = (NotificationManager) getSystemService(Context.NOTIFICATION_SERVICE); @@ -1414,12 +1443,15 @@ public class OpenVPNService extends VpnService implements StateListener, Callbac // updateStateString trigger the notification of the VPN to be refreshed, save this intent // to have that notification also this intent to be set PendingIntent pIntent = PendingIntent.getActivity(this, 0, intent, PendingIntent.FLAG_IMMUTABLE); + VpnStatus.updateStateString("USER_INPUT", "waiting for user input", reason, LEVEL_WAITING_FOR_USER_INPUT, intent); + nbuilder.setContentIntent(pIntent); jbNotificationExtras(PRIORITY_MAX, nbuilder); lpNotificationExtras(nbuilder, Notification.CATEGORY_STATUS); + String channel = NOTIFICATION_CHANNEL_USERREQ_ID; if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) { //noinspection NewApi nbuilder.setChannelId(channel); diff --git a/main/src/main/java/de/blinkt/openvpn/core/StatusListener.java b/main/src/main/java/de/blinkt/openvpn/core/StatusListener.java index 293a6fd4..7eea523a 100644 --- a/main/src/main/java/de/blinkt/openvpn/core/StatusListener.java +++ b/main/src/main/java/de/blinkt/openvpn/core/StatusListener.java @@ -120,9 +120,10 @@ public class StatusListener implements VpnStatus.LogListener { }; private Context mContext; + private String pkgName = "(packageName not yet set)"; void init(Context c) { - + pkgName = c.getPackageName(); Intent intent = new Intent(c, OpenVPNStatusService.class); intent.setAction(OpenVPNService.START_SERVICE); mCacheDir = c.getCacheDir(); @@ -163,22 +164,23 @@ public class StatusListener implements VpnStatus.LogListener { @Override public void newLog(LogItem logItem) { + String tag = pkgName + "(OpenVPN)"; switch (logItem.getLogLevel()) { case INFO: - Log.i("OpenVPN", logItem.getString(mContext)); + Log.i(tag, logItem.getString(mContext)); break; case DEBUG: - Log.d("OpenVPN", logItem.getString(mContext)); + Log.d(tag, logItem.getString(mContext)); break; case ERROR: - Log.e("OpenVPN", logItem.getString(mContext)); + Log.e(tag, logItem.getString(mContext)); break; case VERBOSE: - Log.v("OpenVPN", logItem.getString(mContext)); + Log.v(tag, logItem.getString(mContext)); break; case WARNING: default: - Log.w("OpenVPN", logItem.getString(mContext)); + Log.w(tag, logItem.getString(mContext)); break; } diff --git a/main/src/main/res/values/strings.xml b/main/src/main/res/values/strings.xml index 575933ed..88f98a17 100755 --- a/main/src/main/res/values/strings.xml +++ b/main/src/main/res/values/strings.xml @@ -508,5 +508,6 @@ Try to encrypt profiles on storage (if supported by Android OS) Notification permission missing. This is used to display the status of the VPN and to notify about required user interaction like multi factor authorisation.\n\nClick this message to give the app notification permissions Username - + Permission to start a VPN connection is required + VPN Service is missing permission to connect a VPN. Requesting permission via notification. -- cgit v1.2.3