diff options
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!/" /> | 
