Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 4 additions & 0 deletions main/src/main/AndroidManifest.xml
Original file line number Diff line number Diff line change
Expand Up @@ -139,6 +139,10 @@
android:name=".api.ResumeVPN"
android:exported="true"
android:targetActivity=".api.RemoteAction" />
<activity-alias
android:name=".api.SetDefaultVPN"
android:exported="true"
android:targetActivity=".api.RemoteAction" />

</application>

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -73,4 +73,10 @@ interface IOpenVPNAPIService {
* up to now the only extra that can be put is a boolean "de.blinkt.openvpn.api.ALLOW_VPN_BYPASS"
*/
APIVpnProfile addNewVPNProfileWithExtras (String name, boolean userEditable, String config, in Bundle extras);

/** Get the current default profile, or null if there is no default */
@nullable APIVpnProfile getDefaultProfile();

/** Set the default profile by UUID */
void setDefaultProfile (String profileUUID);
}
4 changes: 2 additions & 2 deletions main/src/main/java/de/blinkt/openvpn/api/APIVpnProfile.java
Original file line number Diff line number Diff line change
Expand Up @@ -47,8 +47,8 @@ public void writeToParcel(Parcel dest, int flags) {
//dest.writeString(mProfileCreator);
}

public static final Parcelable.Creator<APIVpnProfile> CREATOR
= new Parcelable.Creator<APIVpnProfile>() {
public static final Creator<APIVpnProfile> CREATOR
= new Creator<APIVpnProfile>() {
public APIVpnProfile createFromParcel(Parcel in) {
return new APIVpnProfile(in);
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,7 @@
import android.content.Intent;
import android.content.IntentFilter;
import android.content.ServiceConnection;
import android.content.SharedPreferences;
import android.net.VpnService;
import android.os.Binder;
import android.os.Build;
Expand All @@ -37,6 +38,7 @@
import de.blinkt.openvpn.core.ConnectionStatus;
import de.blinkt.openvpn.core.IOpenVPNServiceInternal;
import de.blinkt.openvpn.core.OpenVPNService;
import de.blinkt.openvpn.core.Preferences;
import de.blinkt.openvpn.core.ProfileManager;
import de.blinkt.openvpn.core.VPNLaunchHelper;
import de.blinkt.openvpn.core.VpnStatus;
Expand Down Expand Up @@ -109,6 +111,10 @@ public void onCreate() {

}

private APIVpnProfile apiVpnProfileFromVpnProfile(VpnProfile vp) {
return new APIVpnProfile(vp.getUUIDString(), vp.mName, vp.mUserEditable, vp.mProfileCreator);
}

private final IOpenVPNAPIService.Stub mBinder = new IOpenVPNAPIService.Stub() {

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

for (VpnProfile vp : pm.getProfiles()) {
if (!vp.profileDeleted)
profiles.add(new APIVpnProfile(vp.getUUIDString(), vp.mName, vp.mUserEditable, vp.mProfileCreator));
profiles.add(apiVpnProfileFromVpnProfile(vp));
}

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

}

@Override
public APIVpnProfile getDefaultProfile() throws RemoteException {
mExtAppDb.checkOpenVPNPermission(getPackageManager());
ProfileManager pm = ProfileManager.getInstance(getBaseContext());
Copy link
Owner

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Missing permission check.

Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Done

SharedPreferences prefs = Preferences.getDefaultSharedPreferences(getBaseContext());
String profileUUID = prefs.getString("alwaysOnVpn", null);
if (profileUUID == null) {
return null;
}
VpnProfile vp = ProfileManager.get(getBaseContext(), profileUUID);
if (vp.checkProfile(getApplicationContext()) != R.string.no_error_found) {
VpnStatus.logInfo("Default profile is currently set to unknown UUID " + profileUUID);
return null;
}
APIVpnProfile result = apiVpnProfileFromVpnProfile(vp);
return result;
}

@Override
public void setDefaultProfile(String profileUUID) throws RemoteException {
mExtAppDb.checkOpenVPNPermission(getPackageManager());
ProfileManager pm = ProfileManager.getInstance(getBaseContext());
VpnProfile vp = ProfileManager.get(getBaseContext(), profileUUID);
if (vp.checkProfile(getApplicationContext()) != R.string.no_error_found)
throw new RemoteException(getString(vp.checkProfile(getApplicationContext())));
SharedPreferences prefs = Preferences.getDefaultSharedPreferences(getBaseContext());
SharedPreferences.Editor editor = prefs.edit();
editor.putString("alwaysOnVpn", vp.getUUIDString());
editor.apply();
}
};


Expand Down Expand Up @@ -425,4 +462,4 @@ private void sendUpdate(IOpenVPNStatusCallback broadcastItem,



}
}
45 changes: 34 additions & 11 deletions main/src/main/java/de/blinkt/openvpn/api/RemoteAction.java
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@
import android.content.Context;
import android.content.Intent;
import android.content.ServiceConnection;
import android.content.SharedPreferences;
import android.os.Bundle;
import android.os.IBinder;
import android.os.RemoteException;
Expand All @@ -19,7 +20,9 @@
import de.blinkt.openvpn.VpnProfile;
import de.blinkt.openvpn.core.IOpenVPNServiceInternal;
import de.blinkt.openvpn.core.OpenVPNService;
import de.blinkt.openvpn.core.Preferences;
import de.blinkt.openvpn.core.ProfileManager;
import de.blinkt.openvpn.core.VpnStatus;

public class RemoteAction extends Activity {

Expand Down Expand Up @@ -61,6 +64,33 @@ protected void onResume() {

}

private void connectVPN(Intent intent) {
String vpnName = intent.getStringExtra(EXTRA_NAME);
VpnProfile profile = ProfileManager.getInstance(this).getProfileByName(vpnName);
if (profile == null) {
Toast.makeText(this, String.format("Vpn profile %s from API call not found", vpnName), Toast.LENGTH_LONG).show();
} else {
Intent startVPN = new Intent(this, LaunchVPN.class);
startVPN.putExtra(LaunchVPN.EXTRA_KEY, profile.getUUID().toString());
startVPN.putExtra(OpenVPNService.EXTRA_START_REASON, ".api.ConnectVPN call");
startVPN.setAction(Intent.ACTION_MAIN);
startActivity(startVPN);
}
}

private void setDefaultVPN(Intent intent) {
String defaultVpnName = intent.getStringExtra(EXTRA_NAME);
VpnProfile defaultProfile = ProfileManager.getInstance(this).getProfileByName(defaultVpnName);
if (defaultProfile == null) {
Toast.makeText(this, String.format("Vpn profile %s from API call not found", defaultVpnName), Toast.LENGTH_LONG).show();
} else {
SharedPreferences prefs = Preferences.getDefaultSharedPreferences(this);
SharedPreferences.Editor editor = prefs.edit();
editor.putString("alwaysOnVpn", defaultProfile.getUUIDString());
editor.apply();
}
}

private void performAction() throws RemoteException {

if (!mService.isAllowedExternalApp(getCallingPackage())) {
Expand All @@ -86,17 +116,10 @@ private void performAction() throws RemoteException {
mService.userPause(false);
break;
case ".api.ConnectVPN":
String vpnName = intent.getStringExtra(EXTRA_NAME);
VpnProfile profile = ProfileManager.getInstance(this).getProfileByName(vpnName);
if (profile == null) {
Toast.makeText(this, String.format("Vpn profile %s from API call not found", vpnName), Toast.LENGTH_LONG).show();
} else {
Intent startVPN = new Intent(this, LaunchVPN.class);
startVPN.putExtra(LaunchVPN.EXTRA_KEY, profile.getUUID().toString());
startVPN.putExtra(OpenVPNService.EXTRA_START_REASON, ".api.ConnectVPN call");
startVPN.setAction(Intent.ACTION_MAIN);
startActivity(startVPN);
}
connectVPN(intent);
break;
case ".api.SetDefaultVPN":
setDefaultVPN(intent);
break;
}
finish();
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -18,14 +18,14 @@ interface IOpenVPNAPIService {
boolean addVPNProfile (String name, String config);

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

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

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

/**
* Remove a previously registered callback interface.
*/
void unregisterStatusCallback(IOpenVPNStatusCallback cb);
void unregisterStatusCallback(in IOpenVPNStatusCallback cb);

/** Remove a profile by UUID */
void removeProfile (String profileUUID);
void removeProfile (in String profileUUID);

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

/** Same as startVPN(String), but also takes a Bundle with extra parameters,
* which will be applied to the created VPNProfile (e.g. allow vpn bypass). */
void startVPNwithExtras(in String inlineconfig, in Bundle extras);

/** Same as addNewVPNProfile(String, boolean, String) but giving possibility to pass a Bundle like
* in startVPNwithExtras(String, Bundle) to apply e.g. "allow vpn bypass" to profile.
* up to now the only extra that can be put is a boolean "de.blinkt.openvpn.api.ALLOW_VPN_BYPASS"
*/
APIVpnProfile addNewVPNProfileWithExtras (String name, boolean userEditable, String config, in Bundle extras);

/** Get the current default profile, or null if there is no default */
@nullable APIVpnProfile getDefaultProfile();

/** Set the default profile by UUID */
void setDefaultProfile (String profileUUID);
}
Original file line number Diff line number Diff line change
@@ -1,6 +1,8 @@
/*
* Copyright (c) 2012-2015 Arne Schwabe
* Distributed under the GNU GPL v2 with additional terms. For full terms see the file doc/LICENSE.txt
* Copyright (c) 2012-2016 Arne Schwabe
* This file is used for implementing the external API and this file like the AIDL and is exempted
* from the GPLv2.
*
*/
Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@schwabe Note that I updated the copyright notice in remoteExample/.../APIVpnProfile.java to match main/.../APIVpnProfile.java.


package de.blinkt.openvpn.api;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -52,6 +52,7 @@ public class MainFragment extends Fragment implements View.OnClickListener, Hand
public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) {
View v = inflater.inflate(R.layout.fragment_main, container, false);
v.findViewById(R.id.disconnect).setOnClickListener(this);
v.findViewById(R.id.setDefaultProfile).setOnClickListener(this);
v.findViewById(R.id.getMyIP).setOnClickListener(this);
v.findViewById(R.id.startembedded).setOnClickListener(this);
v.findViewById(R.id.addNewProfile).setOnClickListener(this);
Expand All @@ -70,6 +71,7 @@ public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle sa
private static final int MSG_UPDATE_MYIP = 1;
private static final int START_PROFILE_EMBEDDED = 2;
private static final int START_PROFILE_BYUUID = 3;
private static final int SET_DEFAULT_PROFILE_BYUUID = 4;
private static final int ICS_OPENVPN_PERMISSION = 7;
private static final int PROFILE_ADD_NEW = 8;
private static final int PROFILE_ADD_NEW_EDIT = 9;
Expand Down Expand Up @@ -195,9 +197,12 @@ protected void listVPNs() {

try {
List<APIVpnProfile> list = mService.getProfiles();
APIVpnProfile defaultProfile = mService.getDefaultProfile();
String defaultUUID = defaultProfile != null ? defaultProfile.mUUID : null;
String all="List:";
for(APIVpnProfile vp:list.subList(0, Math.min(5, list.size()))) {
all = all + vp.mName + ":" + vp.mUUID + "\n";
String suffix = (vp.mUUID.equals(defaultUUID)) ? " (default)" : "";
all = all + vp.mName + ":" + vp.mUUID + suffix + "\n";
}

if (list.size() > 5)
Expand Down Expand Up @@ -253,6 +258,14 @@ public void onClick(View v) {
e.printStackTrace();
}
break;
case R.id.setDefaultProfile:
try {
prepareStartProfile(SET_DEFAULT_PROFILE_BYUUID);
} catch (RemoteException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
break;
case R.id.getMyIP:

// Socket handling is not allowed on main thread
Expand Down Expand Up @@ -317,6 +330,12 @@ public void onActivityResult(int requestCode, int resultCode, Intent data) {
} catch (RemoteException e) {
e.printStackTrace();
}
if(requestCode==SET_DEFAULT_PROFILE_BYUUID)
try {
mService.setDefaultProfile(mStartUUID);
} catch (RemoteException e) {
e.printStackTrace();
}
if (requestCode == ICS_OPENVPN_PERMISSION) {
listVPNs();
try {
Expand Down
8 changes: 8 additions & 0 deletions remoteExample/src/main/res/layout/fragment_main.xml
Original file line number Diff line number Diff line change
Expand Up @@ -63,6 +63,14 @@
android:layout_toRightOf="@+id/startVPN"
android:text="@string/disconnect" />

<Button
android:id="@+id/setDefaultProfile"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_alignBottom="@+id/disconnect"
android:layout_toRightOf="@+id/disconnect"
android:text="@string/set_default" />

<Button
android:id="@+id/startembedded"
style="?android:attr/buttonStyleSmall"
Expand Down
1 change: 1 addition & 0 deletions remoteExample/src/main/res/values/strings.xml
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,7 @@
<string name="no_now">Not now</string>
<string name="show_my_ip">Show my IP</string>
<string name="disconnect">Disconnect</string>
<string name="set_default">Set Default</string>
<string name="start_embedded">Start embedded profile</string>
<string name="addNew">Add new Profile</string>
<string name="addNewEdit">Add editable profile</string>
Expand Down