diff options
author | Arne Schwabe <arne@rfc2549.org> | 2013-10-06 15:10:56 +0200 |
---|---|---|
committer | Arne Schwabe <arne@rfc2549.org> | 2013-10-06 15:10:56 +0200 |
commit | 967caeefc314e4f5b944b0e90c47f1f3b09f5a27 (patch) | |
tree | d3e7ac539af5641cf52a0fea13d395b71e3e4075 | |
parent | 911f3855f184ecdb1339c1d8383ea19e86fe918e (diff) |
Update Xposed module to allow arbitrary VPN apps
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!/" /> |