summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorArne Schwabe <arne@rfc2549.org>2013-10-06 15:10:56 +0200
committerArne Schwabe <arne@rfc2549.org>2013-10-06 15:10:56 +0200
commit967caeefc314e4f5b944b0e90c47f1f3b09f5a27 (patch)
treed3e7ac539af5641cf52a0fea13d395b71e3e4075
parent911f3855f184ecdb1339c1d8383ea19e86fe918e (diff)
Update Xposed module to allow arbitrary VPN apps
-rw-r--r--vpndialogxposed/src/main/AndroidManifest.xml14
-rw-r--r--vpndialogxposed/src/main/java/de/blinkt/vpndialogxposed/VpnDialogPatcher.java31
-rw-r--r--vpndialogxposed/src/main/java/de/blinkt/vpndialogxposed/allowedVPNsChooser.java150
-rw-r--r--vpndialogxposed/src/main/res/layout/vpnapplayout.xml34
-rw-r--r--vpndialogxposed/vpndialogxposed.iml26
5 files changed, 243 insertions, 12 deletions
diff --git a/vpndialogxposed/src/main/AndroidManifest.xml b/vpndialogxposed/src/main/AndroidManifest.xml
index 2942105e..2a58277d 100644
--- a/vpndialogxposed/src/main/AndroidManifest.xml
+++ b/vpndialogxposed/src/main/AndroidManifest.xml
@@ -1,8 +1,6 @@
<?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
- package="de.blinkt.vpndialogxposed"
- android:versionCode="2"
- android:versionName="1.0.1">
+ package="de.blinkt.vpndialogxposed" >
<uses-sdk
android:minSdkVersion="14"
@@ -14,6 +12,16 @@
android:label="@string/app_name"
>
+ <activity
+ android:name=".AllowedVPNsChooser">
+ <intent-filter>
+ <action android:name="android.intent.action.MAIN"/>
+
+ <category android:name="android.intent.category.BROWSABLE"/>
+ <category android:name="android.intent.category.LAUNCHER"/>
+ </intent-filter>
+ </activity>
+
<meta-data
android:value="true"
android:name="xposedmodule"/>
diff --git a/vpndialogxposed/src/main/java/de/blinkt/vpndialogxposed/VpnDialogPatcher.java b/vpndialogxposed/src/main/java/de/blinkt/vpndialogxposed/VpnDialogPatcher.java
index d87b2d89..9cf22d0c 100644
--- a/vpndialogxposed/src/main/java/de/blinkt/vpndialogxposed/VpnDialogPatcher.java
+++ b/vpndialogxposed/src/main/java/de/blinkt/vpndialogxposed/VpnDialogPatcher.java
@@ -8,11 +8,26 @@ import de.robv.android.xposed.IXposedHookLoadPackage;
import de.robv.android.xposed.XC_MethodHook;
import de.robv.android.xposed.XposedBridge;
import de.robv.android.xposed.XposedHelpers;
+import de.robv.android.xposed.XSharedPreferences;
import de.robv.android.xposed.callbacks.XC_LoadPackage.LoadPackageParam;
+import de.robv.android.xposed.IXposedHookZygoteInit;
+
import java.lang.reflect.Method;
+import java.util.HashSet;
+import java.util.Set;
+
+public class VpnDialogPatcher implements IXposedHookLoadPackage, IXposedHookZygoteInit {
+ public static final String MY_PACKAGE_NAME = AllowedVPNsChooser.class.getPackage().getName();
+ private static XSharedPreferences pref;
+
+
+ @Override
+ public void initZygote(StartupParam startupParam) throws Throwable {
+ pref = new XSharedPreferences(MY_PACKAGE_NAME, "AllowedVPNsChooser");
+
+ }
-public class VpnDialogPatcher implements IXposedHookLoadPackage {
@Override
public void handleLoadPackage(LoadPackageParam lpparam) throws Throwable {
if (!lpparam.packageName.equals("com.android.vpndialogs"))
@@ -52,11 +67,21 @@ public class VpnDialogPatcher implements IXposedHookLoadPackage {
if((Boolean) XposedHelpers.callMethod(mService,"prepareVpn",prepareVPNsignature, mPackage,(String)null))
return;
- if (mPackage.equals("de.blinkt.openvpn")) {
+
+ HashSet<String> blinktapp = new HashSet<String>();
+ blinktapp.add("de.blinkt.openvpn");
+ // blinktapp.add("de.blinkt.nothingset");
+
+ pref.reload();
+ Set<String> allowedApps = pref.getStringSet("allowedApps",blinktapp);
+
+ //Toast.makeText((Context)param.thisObject, "Allowed apps: " + allowedApps, Toast.LENGTH_LONG).show();
+
+ if (allowedApps.contains(mPackage)) {
//mService.prepareVpn(null, mPackage);
XposedHelpers.callMethod(mService,"prepareVpn",prepareVPNsignature, (String)null,mPackage);
((Activity) param.thisObject).setResult(Activity.RESULT_OK);
- Toast.makeText((Context)param.thisObject,"Allowed de.blinkt.openvpn",Toast.LENGTH_LONG).show();
+ Toast.makeText((Context)param.thisObject,"Allowed VpnService app: " + mPackage,Toast.LENGTH_LONG).show();
((Activity) param.thisObject).finish();
}
diff --git a/vpndialogxposed/src/main/java/de/blinkt/vpndialogxposed/allowedVPNsChooser.java b/vpndialogxposed/src/main/java/de/blinkt/vpndialogxposed/allowedVPNsChooser.java
new file mode 100644
index 00000000..199f23fb
--- /dev/null
+++ b/vpndialogxposed/src/main/java/de/blinkt/vpndialogxposed/allowedVPNsChooser.java
@@ -0,0 +1,150 @@
+package de.blinkt.vpndialogxposed;
+
+import android.Manifest;
+import android.app.ListActivity;
+import android.content.Context;
+import android.content.Intent;
+import android.content.SharedPreferences;
+import android.content.pm.*;
+import android.os.Bundle;
+import android.widget.AbsListView;
+import android.widget.ArrayAdapter;
+import android.widget.ListAdapter;
+
+import java.lang.reflect.InvocationTargetException;
+import java.lang.reflect.Method;
+import java.util.*;
+
+
+/**
+ * Created by arne on 06.10.13.
+ */
+public class AllowedVPNsChooser extends ListActivity {
+
+ public static final String ALLOWED_APPS = "allowedApps";
+
+
+ @Override
+ protected void onCreate(Bundle savedInstanceState) {
+ super.onCreate(savedInstanceState);
+
+ Collection<VpnApp> vpnApps = getVpnAppList();
+ ListAdapter la = new ArrayAdapter<VpnApp>(this, android.R.layout.simple_list_item_multiple_choice, vpnApps.toArray(new VpnApp[vpnApps.size()]));
+ setListAdapter(la);
+ setContentView(R.layout.vpnapplayout);
+ getListView().setChoiceMode(AbsListView.CHOICE_MODE_MULTIPLE);
+
+
+ Collection<String> allowedapps = getAllowedApps();
+ for(int i=0; i < vpnApps.size(); i++) {
+ VpnApp va= (VpnApp) getListView().getItemAtPosition(i);
+ boolean allowed = allowedapps.contains(va.mPkg);
+ getListView().setItemChecked(i,allowed);
+ }
+
+ }
+
+
+
+ private Collection<String> getAllowedApps(){
+ SharedPreferences prefs = getPreferences(MODE_WORLD_READABLE);
+ HashSet<String> defaultapps = new HashSet<String>();
+ defaultapps.add("de.blinkt.openvpn");
+ return prefs.getStringSet(ALLOWED_APPS,defaultapps );
+ }
+
+ private void saveAllowedApps(Set<String> allowedApps)
+ {
+ SharedPreferences prefs = getPreferences(MODE_WORLD_READABLE);
+ prefs.edit().putStringSet(ALLOWED_APPS,allowedApps)
+ .putInt("random",new Random().nextInt()).apply();
+ }
+
+
+ @Override
+ protected void onStop() {
+ super.onStop();
+
+ HashSet<String> allowedPkgs= new HashSet<String>();
+ for(int i=0;i < getListView().getChildCount();i++) {
+ if(getListView().getCheckedItemPositions().get(i)) {
+ allowedPkgs.add(((VpnApp)getListView().getItemAtPosition(i)).mPkg);
+ }
+ }
+ saveAllowedApps(allowedPkgs);
+ }
+
+ private Collection<VpnApp> getVpnAppList() {
+ PackageManager pm = getPackageManager();
+ Intent vpnOpen = new Intent();
+ vpnOpen.setAction("android.net.VpnService");
+ Vector<VpnApp> vpnApps = new Vector<VpnApp>();
+
+ // Hack but should work
+ for(PackageInfo pkg : pm.getInstalledPackages(PackageManager.GET_SERVICES)) {
+ if (pkg.services != null) {
+ for(ServiceInfo serviceInfo:pkg.services) {
+ if(Manifest.permission.BIND_VPN_SERVICE.equals(serviceInfo.permission))
+ vpnApps.add(new VpnApp(pkg.applicationInfo.loadLabel(pm), pkg.packageName));
+ }
+ }
+ }
+
+
+ /* public abstract List<ResolveInfo> queryIntentServicesAsUser(Intent intent,
+ int flags, int userId);
+ */
+
+ /* This does not work ... */
+ /*
+ Class<?>[] queryIntentServicesAsUserSignature = {Intent.class, int.class, int.class};
+ try {
+ Method queryIntentServicesAsUser = pm.getClass().getMethod("queryIntentServicesAsUser", queryIntentServicesAsUserSignature);
+
+ List<ApplicationInfo> installedApps = pm.getInstalledApplications(0);
+
+
+
+ for (ApplicationInfo app : installedApps) {
+
+ List<ResolveInfo> apps;
+ if (app.packageName.equals(getPackageName())) {
+ apps = pm.queryIntentServices(vpnOpen, 0);
+ } else {
+ apps = (List<ResolveInfo>) queryIntentServicesAsUser.invoke(pm, vpnOpen, 0, app.uid);
+ }
+
+
+
+ for (ResolveInfo ri : apps) {
+ vpnApps.add(new VpnApp(ri.toString()));
+ }
+ }
+ } catch (NoSuchMethodException e) {
+ e.printStackTrace();
+ } catch (InvocationTargetException e) {
+ e.printStackTrace();
+ } catch (IllegalAccessException e) {
+ e.printStackTrace();
+ }
+ */
+
+ return vpnApps;
+ }
+
+ static class VpnApp {
+
+ private final String mPkg;
+ private CharSequence mName;
+
+ public VpnApp(CharSequence name, String pkg) {
+ mName = name;
+ mPkg = pkg;
+ }
+
+ @Override
+ public String toString() {
+ return mName.toString();
+ }
+ }
+}
diff --git a/vpndialogxposed/src/main/res/layout/vpnapplayout.xml b/vpndialogxposed/src/main/res/layout/vpnapplayout.xml
new file mode 100644
index 00000000..3042ee2b
--- /dev/null
+++ b/vpndialogxposed/src/main/res/layout/vpnapplayout.xml
@@ -0,0 +1,34 @@
+<?xml version="1.0" encoding="utf-8"?>
+<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
+ xmlns:tools="http://schemas.android.com/tools"
+ android:layout_width="match_parent"
+ android:layout_height="match_parent"
+ android:orientation="vertical"
+ >
+
+ <TextView
+ android:layout_width="match_parent"
+ android:layout_height="wrap_content"
+ android:text="Select the apps that should be allowed to use the VpnService API without user confirmation"/>
+
+
+ <ListView
+ android:id="@android:id/list"
+ android:layout_width="fill_parent"
+ android:layout_height="fill_parent" />
+
+ <LinearLayout
+ android:id="@android:id/empty"
+ android:layout_width="match_parent"
+ android:layout_height="match_parent"
+ android:gravity="center"
+ android:orientation="vertical" >
+
+ <TextView
+ android:layout_width="fill_parent"
+ android:layout_height="wrap_content"
+ android:text="No Apps using the VPNService API found"
+ android:textAppearance="?android:attr/textAppearanceMedium" />
+ </LinearLayout>
+
+</LinearLayout> \ No newline at end of file
diff --git a/vpndialogxposed/vpndialogxposed.iml b/vpndialogxposed/vpndialogxposed.iml
index 3de4565c..11def943 100644
--- a/vpndialogxposed/vpndialogxposed.iml
+++ b/vpndialogxposed/vpndialogxposed.iml
@@ -1,8 +1,24 @@
<?xml version="1.0" encoding="UTF-8"?>
-<module external.linked.project.path="$MODULE_DIR$/.." external.system.id="GRADLE" type="JAVA_MODULE" version="4">
+<module external.linked.project.path="$MODULE_DIR$" external.root.project.path="$MODULE_DIR$/.." external.system.id="GRADLE" type="JAVA_MODULE" version="4">
<component name="FacetManager">
<facet type="android" name="Android">
- <configuration />
+ <configuration>
+ <option name="SELECTED_BUILD_VARIANT" value="Debug" />
+ <option name="ASSEMBLE_TASK_NAME" value="assembleDebug" />
+ <option name="COMPILE_JAVA_TASK_NAME" value="compileDebug" />
+ <option name="ASSEMBLE_TEST_TASK_NAME" value="assembleTest" />
+ <option name="SOURCE_GEN_TASK_NAME" value="generateDebugSources" />
+ <option name="ALLOW_USER_CONFIGURATION" value="false" />
+ <option name="MANIFEST_FILE_RELATIVE_PATH" value="/src/main/AndroidManifest.xml" />
+ <option name="RES_FOLDER_RELATIVE_PATH" value="/src/main/res" />
+ <option name="RES_FOLDERS_RELATIVE_PATH" value="file://$MODULE_DIR$/src/main/res" />
+ <option name="ASSETS_FOLDER_RELATIVE_PATH" value="/src/main/assets" />
+ </configuration>
+ </facet>
+ <facet type="android-gradle" name="Android-Gradle">
+ <configuration>
+ <option name="GRADLE_PROJECT_PATH" value=":vpndialogxposed" />
+ </configuration>
</facet>
</component>
<component name="NewModuleRootManager" inherit-compiler-output="false">
@@ -40,23 +56,21 @@
<sourceFolder url="file://$MODULE_DIR$/src/instrumentTest/rs" isTestSource="true" />
<sourceFolder url="file://$MODULE_DIR$/src/instrumentTest/res" isTestSource="true" />
<sourceFolder url="file://$MODULE_DIR$/src/instrumentTest/resources" isTestSource="true" />
- <sourceFolder url="file://$MODULE_DIR$/gen" isTestSource="false" />
<excludeFolder url="file://$MODULE_DIR$/build/apk" />
<excludeFolder url="file://$MODULE_DIR$/build/assets" />
<excludeFolder url="file://$MODULE_DIR$/build/bundles" />
<excludeFolder url="file://$MODULE_DIR$/build/classes" />
<excludeFolder url="file://$MODULE_DIR$/build/dependency-cache" />
- <excludeFolder url="file://$MODULE_DIR$/build/exploded-bundles" />
<excludeFolder url="file://$MODULE_DIR$/build/incremental" />
<excludeFolder url="file://$MODULE_DIR$/build/libs" />
<excludeFolder url="file://$MODULE_DIR$/build/manifests" />
<excludeFolder url="file://$MODULE_DIR$/build/symbols" />
<excludeFolder url="file://$MODULE_DIR$/build/tmp" />
</content>
- <orderEntry type="jdk" jdkName="Android 4.2.2" jdkType="Android SDK" />
+ <orderEntry type="jdk" jdkName="Android 4.3 Platform" jdkType="Android SDK" />
<orderEntry type="sourceFolder" forTests="false" />
<orderEntry type="library" exported="" name="annotations-12.0" level="project" />
- <orderEntry type="module-library">
+ <orderEntry type="module-library" scope="PROVIDED">
<library>
<CLASSES>
<root url="jar://$MODULE_DIR$/libs/XposedBridgeApi.jar!/" />