Skip to content

Commit 1f1dae8

Browse files
thromerschwabe
authored andcommitted
Add setDefaultProfile and getDefaultProfile methods to API.
Also: * add corresponding setDefaultVPN intent * add sample usage to remoteExample * bring remoteExample/.../IOpenVPNAPIService.aidl into sync with main/... * make APIVpnProfile.java in remoteExample/ and main/ identical.
1 parent 14c315f commit 1f1dae8

10 files changed

Lines changed: 134 additions & 24 deletions

File tree

main/src/main/AndroidManifest.xml

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -139,6 +139,10 @@
139139
android:name=".api.ResumeVPN"
140140
android:exported="true"
141141
android:targetActivity=".api.RemoteAction" />
142+
<activity-alias
143+
android:name=".api.SetDefaultVPN"
144+
android:exported="true"
145+
android:targetActivity=".api.RemoteAction" />
142146

143147
</application>
144148

main/src/main/aidl/de/blinkt/openvpn/api/IOpenVPNAPIService.aidl

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -73,4 +73,10 @@ interface IOpenVPNAPIService {
7373
* up to now the only extra that can be put is a boolean "de.blinkt.openvpn.api.ALLOW_VPN_BYPASS"
7474
*/
7575
APIVpnProfile addNewVPNProfileWithExtras (String name, boolean userEditable, String config, in Bundle extras);
76+
77+
/** Get the current default profile, or null if there is no default */
78+
@nullable APIVpnProfile getDefaultProfile();
79+
80+
/** Set the default profile by UUID */
81+
void setDefaultProfile (String profileUUID);
7682
}

main/src/main/java/de/blinkt/openvpn/api/APIVpnProfile.java

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -47,8 +47,8 @@ public void writeToParcel(Parcel dest, int flags) {
4747
//dest.writeString(mProfileCreator);
4848
}
4949

50-
public static final Parcelable.Creator<APIVpnProfile> CREATOR
51-
= new Parcelable.Creator<APIVpnProfile>() {
50+
public static final Creator<APIVpnProfile> CREATOR
51+
= new Creator<APIVpnProfile>() {
5252
public APIVpnProfile createFromParcel(Parcel in) {
5353
return new APIVpnProfile(in);
5454
}

main/src/main/java/de/blinkt/openvpn/api/ExternalOpenVPNService.java

Lines changed: 39 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -13,6 +13,7 @@
1313
import android.content.Intent;
1414
import android.content.IntentFilter;
1515
import android.content.ServiceConnection;
16+
import android.content.SharedPreferences;
1617
import android.net.VpnService;
1718
import android.os.Binder;
1819
import android.os.Build;
@@ -37,6 +38,7 @@
3738
import de.blinkt.openvpn.core.ConnectionStatus;
3839
import de.blinkt.openvpn.core.IOpenVPNServiceInternal;
3940
import de.blinkt.openvpn.core.OpenVPNService;
41+
import de.blinkt.openvpn.core.Preferences;
4042
import de.blinkt.openvpn.core.ProfileManager;
4143
import de.blinkt.openvpn.core.VPNLaunchHelper;
4244
import de.blinkt.openvpn.core.VpnStatus;
@@ -109,6 +111,10 @@ public void onCreate() {
109111

110112
}
111113

114+
private APIVpnProfile apiVpnProfileFromVpnProfile(VpnProfile vp) {
115+
return new APIVpnProfile(vp.getUUIDString(), vp.mName, vp.mUserEditable, vp.mProfileCreator);
116+
}
117+
112118
private final IOpenVPNAPIService.Stub mBinder = new IOpenVPNAPIService.Stub() {
113119

114120
@Override
@@ -121,7 +127,7 @@ public List<APIVpnProfile> getProfiles() throws RemoteException {
121127

122128
for (VpnProfile vp : pm.getProfiles()) {
123129
if (!vp.profileDeleted)
124-
profiles.add(new APIVpnProfile(vp.getUUIDString(), vp.mName, vp.mUserEditable, vp.mProfileCreator));
130+
profiles.add(apiVpnProfileFromVpnProfile(vp));
125131
}
126132

127133
return profiles;
@@ -232,7 +238,7 @@ public APIVpnProfile addNewVPNProfileWithExtras(String name, boolean userEditabl
232238
vp.addChangeLogEntry("AIDL API created profile");
233239
pm.saveProfile(ExternalOpenVPNService.this, vp);
234240
pm.saveProfileList(ExternalOpenVPNService.this);
235-
return new APIVpnProfile(vp.getUUIDString(), vp.mName, vp.mUserEditable, vp.mProfileCreator);
241+
return apiVpnProfileFromVpnProfile(vp);
236242
} catch (IOException e) {
237243
VpnStatus.logException(e);
238244
return null;
@@ -330,6 +336,37 @@ public void resume() throws RemoteException {
330336
mService.userPause(false);
331337

332338
}
339+
340+
@Override
341+
public APIVpnProfile getDefaultProfile() throws RemoteException {
342+
mExtAppDb.checkOpenVPNPermission(getPackageManager());
343+
ProfileManager pm = ProfileManager.getInstance(getBaseContext());
344+
SharedPreferences prefs = Preferences.getDefaultSharedPreferences(getBaseContext());
345+
String profileUUID = prefs.getString("alwaysOnVpn", null);
346+
if (profileUUID == null) {
347+
return null;
348+
}
349+
VpnProfile vp = ProfileManager.get(getBaseContext(), profileUUID);
350+
if (vp.checkProfile(getApplicationContext()) != R.string.no_error_found) {
351+
VpnStatus.logInfo("Default profile is currently set to unknown UUID " + profileUUID);
352+
return null;
353+
}
354+
APIVpnProfile result = apiVpnProfileFromVpnProfile(vp);
355+
return result;
356+
}
357+
358+
@Override
359+
public void setDefaultProfile(String profileUUID) throws RemoteException {
360+
mExtAppDb.checkOpenVPNPermission(getPackageManager());
361+
ProfileManager pm = ProfileManager.getInstance(getBaseContext());
362+
VpnProfile vp = ProfileManager.get(getBaseContext(), profileUUID);
363+
if (vp.checkProfile(getApplicationContext()) != R.string.no_error_found)
364+
throw new RemoteException(getString(vp.checkProfile(getApplicationContext())));
365+
SharedPreferences prefs = Preferences.getDefaultSharedPreferences(getBaseContext());
366+
SharedPreferences.Editor editor = prefs.edit();
367+
editor.putString("alwaysOnVpn", vp.getUUIDString());
368+
editor.apply();
369+
}
333370
};
334371

335372

main/src/main/java/de/blinkt/openvpn/api/RemoteAction.java

Lines changed: 34 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,7 @@
1010
import android.content.Context;
1111
import android.content.Intent;
1212
import android.content.ServiceConnection;
13+
import android.content.SharedPreferences;
1314
import android.os.Bundle;
1415
import android.os.IBinder;
1516
import android.os.RemoteException;
@@ -19,7 +20,9 @@
1920
import de.blinkt.openvpn.VpnProfile;
2021
import de.blinkt.openvpn.core.IOpenVPNServiceInternal;
2122
import de.blinkt.openvpn.core.OpenVPNService;
23+
import de.blinkt.openvpn.core.Preferences;
2224
import de.blinkt.openvpn.core.ProfileManager;
25+
import de.blinkt.openvpn.core.VpnStatus;
2326

2427
public class RemoteAction extends Activity {
2528

@@ -61,6 +64,33 @@ protected void onResume() {
6164

6265
}
6366

67+
private void connectVPN(Intent intent) {
68+
String vpnName = intent.getStringExtra(EXTRA_NAME);
69+
VpnProfile profile = ProfileManager.getInstance(this).getProfileByName(vpnName);
70+
if (profile == null) {
71+
Toast.makeText(this, String.format("Vpn profile %s from API call not found", vpnName), Toast.LENGTH_LONG).show();
72+
} else {
73+
Intent startVPN = new Intent(this, LaunchVPN.class);
74+
startVPN.putExtra(LaunchVPN.EXTRA_KEY, profile.getUUID().toString());
75+
startVPN.putExtra(OpenVPNService.EXTRA_START_REASON, ".api.ConnectVPN call");
76+
startVPN.setAction(Intent.ACTION_MAIN);
77+
startActivity(startVPN);
78+
}
79+
}
80+
81+
private void setDefaultVPN(Intent intent) {
82+
String defaultVpnName = intent.getStringExtra(EXTRA_NAME);
83+
VpnProfile defaultProfile = ProfileManager.getInstance(this).getProfileByName(defaultVpnName);
84+
if (defaultProfile == null) {
85+
Toast.makeText(this, String.format("Vpn profile %s from API call not found", defaultVpnName), Toast.LENGTH_LONG).show();
86+
} else {
87+
SharedPreferences prefs = Preferences.getDefaultSharedPreferences(this);
88+
SharedPreferences.Editor editor = prefs.edit();
89+
editor.putString("alwaysOnVpn", defaultProfile.getUUIDString());
90+
editor.apply();
91+
}
92+
}
93+
6494
private void performAction() throws RemoteException {
6595

6696
if (!mService.isAllowedExternalApp(getCallingPackage())) {
@@ -86,17 +116,10 @@ private void performAction() throws RemoteException {
86116
mService.userPause(false);
87117
break;
88118
case ".api.ConnectVPN":
89-
String vpnName = intent.getStringExtra(EXTRA_NAME);
90-
VpnProfile profile = ProfileManager.getInstance(this).getProfileByName(vpnName);
91-
if (profile == null) {
92-
Toast.makeText(this, String.format("Vpn profile %s from API call not found", vpnName), Toast.LENGTH_LONG).show();
93-
} else {
94-
Intent startVPN = new Intent(this, LaunchVPN.class);
95-
startVPN.putExtra(LaunchVPN.EXTRA_KEY, profile.getUUID().toString());
96-
startVPN.putExtra(OpenVPNService.EXTRA_START_REASON, ".api.ConnectVPN call");
97-
startVPN.setAction(Intent.ACTION_MAIN);
98-
startActivity(startVPN);
99-
}
119+
connectVPN(intent);
120+
break;
121+
case ".api.SetDefaultVPN":
122+
setDefaultVPN(intent);
100123
break;
101124
}
102125
finish();

remoteExample/src/main/aidl/de/blinkt/openvpn/api/IOpenVPNAPIService.aidl

Lines changed: 16 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -18,14 +18,14 @@ interface IOpenVPNAPIService {
1818
boolean addVPNProfile (String name, String config);
1919

2020
/** start a profile using a config as inline string. Make sure that all needed data is inlined,
21-
* e.g., using <ca>...</ca> or <auth-user-data>...</auth-user-data>
21+
* e.g., using <ca>...</ca> or <auth-user-pass>...</auth-user-pass>
2222
* See the OpenVPN manual page for more on inlining files */
23-
void startVPN (String inlineconfig);
23+
void startVPN (in String inlineconfig);
2424

2525
/** This permission framework is used to avoid confused deputy style attack to the VPN
2626
* calling this will give null if the app is allowed to use the external API and an Intent
2727
* that can be launched to request permissions otherwise */
28-
Intent prepare (String packagename);
28+
Intent prepare (in String packagename);
2929

3030
/** Used to trigger to the Android VPN permission dialog (VPNService.prepare()) in advance,
3131
* if this return null OpenVPN for ANdroid already has the permissions otherwise you can start the returned Intent
@@ -44,15 +44,15 @@ interface IOpenVPNAPIService {
4444
/**
4545
* Registers to receive OpenVPN Status Updates
4646
*/
47-
void registerStatusCallback(IOpenVPNStatusCallback cb);
47+
void registerStatusCallback(in IOpenVPNStatusCallback cb);
4848

4949
/**
5050
* Remove a previously registered callback interface.
5151
*/
52-
void unregisterStatusCallback(IOpenVPNStatusCallback cb);
52+
void unregisterStatusCallback(in IOpenVPNStatusCallback cb);
5353

5454
/** Remove a profile by UUID */
55-
void removeProfile (String profileUUID);
55+
void removeProfile (in String profileUUID);
5656

5757
/** Request a socket to be protected as a VPN socket would be. Useful for creating
5858
* a helper socket for an app controlling OpenVPN
@@ -64,9 +64,19 @@ interface IOpenVPNAPIService {
6464
/** Use a profile with all certificates etc. embedded */
6565
APIVpnProfile addNewVPNProfile (String name, boolean userEditable, String config);
6666

67+
/** Same as startVPN(String), but also takes a Bundle with extra parameters,
68+
* which will be applied to the created VPNProfile (e.g. allow vpn bypass). */
69+
void startVPNwithExtras(in String inlineconfig, in Bundle extras);
70+
6771
/** Same as addNewVPNProfile(String, boolean, String) but giving possibility to pass a Bundle like
6872
* in startVPNwithExtras(String, Bundle) to apply e.g. "allow vpn bypass" to profile.
6973
* up to now the only extra that can be put is a boolean "de.blinkt.openvpn.api.ALLOW_VPN_BYPASS"
7074
*/
7175
APIVpnProfile addNewVPNProfileWithExtras (String name, boolean userEditable, String config, in Bundle extras);
76+
77+
/** Get the current default profile, or null if there is no default */
78+
@nullable APIVpnProfile getDefaultProfile();
79+
80+
/** Set the default profile by UUID */
81+
void setDefaultProfile (String profileUUID);
7282
}

remoteExample/src/main/java/de/blinkt/openvpn/api/APIVpnProfile.java

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,8 @@
11
/*
2-
* Copyright (c) 2012-2015 Arne Schwabe
3-
* Distributed under the GNU GPL v2 with additional terms. For full terms see the file doc/LICENSE.txt
2+
* Copyright (c) 2012-2016 Arne Schwabe
3+
* This file is used for implementing the external API and this file like the AIDL and is exempted
4+
* from the GPLv2.
5+
*
46
*/
57

68
package de.blinkt.openvpn.api;

remoteExample/src/main/java/de/blinkt/openvpn/remote/MainFragment.java

Lines changed: 20 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -52,6 +52,7 @@ public class MainFragment extends Fragment implements View.OnClickListener, Hand
5252
public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) {
5353
View v = inflater.inflate(R.layout.fragment_main, container, false);
5454
v.findViewById(R.id.disconnect).setOnClickListener(this);
55+
v.findViewById(R.id.setDefaultProfile).setOnClickListener(this);
5556
v.findViewById(R.id.getMyIP).setOnClickListener(this);
5657
v.findViewById(R.id.startembedded).setOnClickListener(this);
5758
v.findViewById(R.id.addNewProfile).setOnClickListener(this);
@@ -70,6 +71,7 @@ public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle sa
7071
private static final int MSG_UPDATE_MYIP = 1;
7172
private static final int START_PROFILE_EMBEDDED = 2;
7273
private static final int START_PROFILE_BYUUID = 3;
74+
private static final int SET_DEFAULT_PROFILE_BYUUID = 4;
7375
private static final int ICS_OPENVPN_PERMISSION = 7;
7476
private static final int PROFILE_ADD_NEW = 8;
7577
private static final int PROFILE_ADD_NEW_EDIT = 9;
@@ -195,9 +197,12 @@ protected void listVPNs() {
195197

196198
try {
197199
List<APIVpnProfile> list = mService.getProfiles();
200+
APIVpnProfile defaultProfile = mService.getDefaultProfile();
201+
String defaultUUID = defaultProfile != null ? defaultProfile.mUUID : null;
198202
String all="List:";
199203
for(APIVpnProfile vp:list.subList(0, Math.min(5, list.size()))) {
200-
all = all + vp.mName + ":" + vp.mUUID + "\n";
204+
String suffix = (vp.mUUID.equals(defaultUUID)) ? " (default)" : "";
205+
all = all + vp.mName + ":" + vp.mUUID + suffix + "\n";
201206
}
202207

203208
if (list.size() > 5)
@@ -253,6 +258,14 @@ public void onClick(View v) {
253258
e.printStackTrace();
254259
}
255260
break;
261+
case R.id.setDefaultProfile:
262+
try {
263+
prepareStartProfile(SET_DEFAULT_PROFILE_BYUUID);
264+
} catch (RemoteException e) {
265+
// TODO Auto-generated catch block
266+
e.printStackTrace();
267+
}
268+
break;
256269
case R.id.getMyIP:
257270

258271
// Socket handling is not allowed on main thread
@@ -317,6 +330,12 @@ public void onActivityResult(int requestCode, int resultCode, Intent data) {
317330
} catch (RemoteException e) {
318331
e.printStackTrace();
319332
}
333+
if(requestCode==SET_DEFAULT_PROFILE_BYUUID)
334+
try {
335+
mService.setDefaultProfile(mStartUUID);
336+
} catch (RemoteException e) {
337+
e.printStackTrace();
338+
}
320339
if (requestCode == ICS_OPENVPN_PERMISSION) {
321340
listVPNs();
322341
try {

remoteExample/src/main/res/layout/fragment_main.xml

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -63,6 +63,14 @@
6363
android:layout_toRightOf="@+id/startVPN"
6464
android:text="@string/disconnect" />
6565

66+
<Button
67+
android:id="@+id/setDefaultProfile"
68+
android:layout_width="wrap_content"
69+
android:layout_height="wrap_content"
70+
android:layout_alignBottom="@+id/disconnect"
71+
android:layout_toRightOf="@+id/disconnect"
72+
android:text="@string/set_default" />
73+
6674
<Button
6775
android:id="@+id/startembedded"
6876
style="?android:attr/buttonStyleSmall"

remoteExample/src/main/res/values/strings.xml

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -14,6 +14,7 @@
1414
<string name="no_now">Not now</string>
1515
<string name="show_my_ip">Show my IP</string>
1616
<string name="disconnect">Disconnect</string>
17+
<string name="set_default">Set Default</string>
1718
<string name="start_embedded">Start embedded profile</string>
1819
<string name="addNew">Add new Profile</string>
1920
<string name="addNewEdit">Add editable profile</string>

0 commit comments

Comments
 (0)