Skip to content

Commit

Permalink
Allow OpenVPNService to request VPN permission if it is missing
Browse files Browse the repository at this point in the history
With other services no longer being able to easily request permissions
the service needs now its own way to request permissions.
  • Loading branch information
schwabe committed Nov 24, 2023
1 parent 2544bd3 commit a9e47ac
Show file tree
Hide file tree
Showing 3 changed files with 46 additions and 11 deletions.
40 changes: 36 additions & 4 deletions main/src/main/java/de/blinkt/openvpn/core/OpenVPNService.java
Original file line number Diff line number Diff line change
Expand Up @@ -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;
Expand All @@ -14,8 +15,6 @@
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;
Expand All @@ -37,7 +36,6 @@
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;
Expand Down Expand Up @@ -528,6 +526,7 @@ public int onStartCommand(Intent intent, int flags, int startId) {
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);
Expand Down Expand Up @@ -596,13 +595,44 @@ private VpnProfile fetchVPNProfile(Intent intent)
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) {
stopSelf(startId);
return;
}

if (!checkVPNPermission(vp))
return;

ProfileManager.setConnectedVpnProfile(this, mProfile);
VpnStatus.setConnectedVPNProfile(mProfile.getUUIDString());
keepVPNAlive.scheduleKeepVPNAliveJobService(this, vp);
Expand Down Expand Up @@ -1353,7 +1383,6 @@ private Intent getWebAuthIntent(String url, boolean external, Notification.Build
}

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);
Expand Down Expand Up @@ -1414,12 +1443,15 @@ public void trigger_sso(String info) {
// 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);
Expand Down
14 changes: 8 additions & 6 deletions main/src/main/java/de/blinkt/openvpn/core/StatusListener.java
Original file line number Diff line number Diff line change
Expand Up @@ -120,9 +120,10 @@ public void onServiceDisconnected(ComponentName arg0) {

};
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();
Expand Down Expand Up @@ -163,22 +164,23 @@ private void logExitNotification(ApplicationExitInfo aei, String s) {

@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;
}

Expand Down
3 changes: 2 additions & 1 deletion main/src/main/res/values/strings.xml
Original file line number Diff line number Diff line change
Expand Up @@ -508,5 +508,6 @@
<string name="encrypt_profiles">Try to encrypt profiles on storage (if supported by Android OS)</string>
<string name="missing_notification_permission">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</string>
<string name="proxy_auth_username">Username</string>

<string name="permission_requested">Permission to start a VPN connection is required</string>
<string name="missing_vpn_permission_log">VPN Service is missing permission to connect a VPN. Requesting permission via notification.</string>
</resources>

0 comments on commit a9e47ac

Please sign in to comment.