diff options
Diffstat (limited to 'vpndialogxposed')
-rw-r--r-- | vpndialogxposed/build.gradle | 64 | ||||
-rw-r--r-- | vpndialogxposed/libs/XposedBridgeApi.jar | bin | 0 -> 99376 bytes | |||
-rw-r--r-- | vpndialogxposed/src/main/AndroidManifest.xml | 33 | ||||
-rw-r--r-- | vpndialogxposed/src/main/assets/xposed_init | 1 | ||||
-rw-r--r-- | vpndialogxposed/src/main/java/de/blinkt/vpndialogxposed/AllowedVPNsChooser.java | 150 | ||||
-rw-r--r-- | vpndialogxposed/src/main/java/de/blinkt/vpndialogxposed/IConnectivityManager.java | 105 | ||||
-rw-r--r-- | vpndialogxposed/src/main/java/de/blinkt/vpndialogxposed/VpnDialogPatcher.java | 99 | ||||
-rw-r--r-- | vpndialogxposed/src/main/res/drawable-hdpi/ic_launcher.png | bin | 0 -> 741 bytes | |||
-rw-r--r-- | vpndialogxposed/src/main/res/drawable-mdpi/ic_launcher.png | bin | 0 -> 549 bytes | |||
-rw-r--r-- | vpndialogxposed/src/main/res/drawable-xhdpi/ic_launcher.png | bin | 0 -> 1061 bytes | |||
-rw-r--r-- | vpndialogxposed/src/main/res/drawable-xxhdpi/ic_launcher.png | bin | 0 -> 1647 bytes | |||
-rw-r--r-- | vpndialogxposed/src/main/res/layout/vpnapplayout.xml | 34 | ||||
-rw-r--r-- | vpndialogxposed/src/main/res/values/strings.xml | 8 |
13 files changed, 494 insertions, 0 deletions
diff --git a/vpndialogxposed/build.gradle b/vpndialogxposed/build.gradle new file mode 100644 index 00000000..fa0d0fa1 --- /dev/null +++ b/vpndialogxposed/build.gradle @@ -0,0 +1,64 @@ +buildscript { + repositories { + mavenCentral() + } + dependencies { + classpath 'com.android.tools.build:gradle:0.9.+' + } +} + +repositories { + mavenCentral() +} + +configurations { + provided +} +apply plugin: 'android' + +dependencies { + compile 'com.intellij:annotations:12.0' + provided files ('libs/XposedBridgeApi.jar') +} + + +android { + compileSdkVersion 19 + buildToolsVersion "19.0.3" + + defaultConfig { + minSdkVersion 14 + targetSdkVersion 19 + versionCode = 3 + versionName = "0.3" + + } + + signingConfigs { + release + } + + buildTypes { + release { + signingConfig signingConfigs.release + } + } +} + + + +// ~/.gradle/gradle.properties +if (project.hasProperty('keystoreFile') && + project.hasProperty('keystorePassword') && + project.hasProperty('keystoreAliasPassword')) { + android.signingConfigs.release.storeFile = file(keystoreFile) + android.signingConfigs.release.storePassword = keystorePassword + android.signingConfigs.release.keyPassword = keystoreAliasPassword + android.signingConfigs.release.keyAlias = keystoreAliasXposed +} else { + android.buildTypes.release.signingConfig = null +} + +android.applicationVariants.all { variant -> + variant.javaCompile.classpath += configurations.provided +} diff --git a/vpndialogxposed/libs/XposedBridgeApi.jar b/vpndialogxposed/libs/XposedBridgeApi.jar Binary files differnew file mode 100644 index 00000000..a87ddb46 --- /dev/null +++ b/vpndialogxposed/libs/XposedBridgeApi.jar diff --git a/vpndialogxposed/src/main/AndroidManifest.xml b/vpndialogxposed/src/main/AndroidManifest.xml new file mode 100644 index 00000000..bff95c63 --- /dev/null +++ b/vpndialogxposed/src/main/AndroidManifest.xml @@ -0,0 +1,33 @@ +<?xml version="1.0" encoding="utf-8"?> +<manifest xmlns:android="http://schemas.android.com/apk/res/android" + package="de.blinkt.vpndialogxposed" > + + + <application + android:allowBackup="true" + android:icon="@drawable/ic_launcher" + 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"/> + <meta-data + android:value="2.0*" + android:name="xposedminversion"/> + <meta-data + android:value="Allows OpenVPN for Android to establish a VPN connection without confirmation dialog" + android:name="xposeddescription"/> + </application> + +</manifest> diff --git a/vpndialogxposed/src/main/assets/xposed_init b/vpndialogxposed/src/main/assets/xposed_init new file mode 100644 index 00000000..b228b31c --- /dev/null +++ b/vpndialogxposed/src/main/assets/xposed_init @@ -0,0 +1 @@ +de.blinkt.vpndialogxposed.VpnDialogPatcher 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/java/de/blinkt/vpndialogxposed/IConnectivityManager.java b/vpndialogxposed/src/main/java/de/blinkt/vpndialogxposed/IConnectivityManager.java new file mode 100644 index 00000000..9b26283e --- /dev/null +++ b/vpndialogxposed/src/main/java/de/blinkt/vpndialogxposed/IConnectivityManager.java @@ -0,0 +1,105 @@ +/* + * This file is auto-generated. DO NOT MODIFY. + * Original file: /Users/arne/software/icsopenvpn/vpndialogxposed/src/main/aidl/android/net/IConnectivityManager.aidl + */ +package de.blinkt.vpndialogxposed; +/** + * Interface that answers queries about, and allows changing, the + * state of network connectivity. + */ + +/** + * {@hide} + */ +public interface IConnectivityManager extends android.os.IInterface { + public boolean prepareVpn(java.lang.String oldPackage, java.lang.String newPackage) throws android.os.RemoteException; + + /** Local-side IPC implementation stub class. */ + public static abstract class Stub extends android.os.Binder implements IConnectivityManager { + static final int TRANSACTION_prepareVpn = (android.os.IBinder.FIRST_CALL_TRANSACTION + 0); + private static final java.lang.String DESCRIPTOR = "android.net.IConnectivityManager"; + + /** Construct the stub at attach it to the interface. */ + public Stub() { + this.attachInterface(this, DESCRIPTOR); + } + + /** + * Cast an IBinder object into an android.net.IConnectivityManager interface, + * generating a proxy if needed. + */ + public static IConnectivityManager asInterface(android.os.IBinder obj) { + if ((obj == null)) { + return null; + } + android.os.IInterface iin = obj.queryLocalInterface(DESCRIPTOR); + if (((iin != null) && (iin instanceof IConnectivityManager))) { + return ((IConnectivityManager) iin); + } + return new IConnectivityManager.Stub.Proxy(obj); + } + + @Override + public android.os.IBinder asBinder() { + return this; + } + + @Override + public boolean onTransact(int code, android.os.Parcel data, android.os.Parcel reply, int flags) throws android.os.RemoteException { + switch (code) { + case INTERFACE_TRANSACTION: { + reply.writeString(DESCRIPTOR); + return true; + } + case TRANSACTION_prepareVpn: { + data.enforceInterface(DESCRIPTOR); + java.lang.String _arg0; + _arg0 = data.readString(); + java.lang.String _arg1; + _arg1 = data.readString(); + boolean _result = this.prepareVpn(_arg0, _arg1); + reply.writeNoException(); + reply.writeInt(((_result) ? (1) : (0))); + return true; + } + } + return super.onTransact(code, data, reply, flags); + } + + private static class Proxy implements IConnectivityManager { + private android.os.IBinder mRemote; + + Proxy(android.os.IBinder remote) { + mRemote = remote; + } + + @Override + public android.os.IBinder asBinder() { + return mRemote; + } + + public java.lang.String getInterfaceDescriptor() { + return DESCRIPTOR; + } + + @Override + public boolean prepareVpn(java.lang.String oldPackage, java.lang.String newPackage) throws android.os.RemoteException { + android.os.Parcel _data = android.os.Parcel.obtain(); + android.os.Parcel _reply = android.os.Parcel.obtain(); + boolean _result; + try { + _data.writeInterfaceToken(DESCRIPTOR); + _data.writeString(oldPackage); + _data.writeString(newPackage); + mRemote.transact(Stub.TRANSACTION_prepareVpn, _data, _reply, 0); + _reply.readException(); + _result = (0 != _reply.readInt()); + } finally { + _reply.recycle(); + _data.recycle(); + } + return _result; + } + } + } +} diff --git a/vpndialogxposed/src/main/java/de/blinkt/vpndialogxposed/VpnDialogPatcher.java b/vpndialogxposed/src/main/java/de/blinkt/vpndialogxposed/VpnDialogPatcher.java new file mode 100644 index 00000000..9cf22d0c --- /dev/null +++ b/vpndialogxposed/src/main/java/de/blinkt/vpndialogxposed/VpnDialogPatcher.java @@ -0,0 +1,99 @@ +package de.blinkt.vpndialogxposed; + +import android.app.Activity; +import android.content.Context; +import android.os.IBinder; +import android.widget.Toast; +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"); + + } + + @Override + public void handleLoadPackage(LoadPackageParam lpparam) throws Throwable { + if (!lpparam.packageName.equals("com.android.vpndialogs")) + return; + + + XposedBridge.log("Got VPN Dialog"); + + XposedHelpers.findAndHookMethod("com.android.vpndialogs.ConfirmDialog", lpparam.classLoader, + "onResume", new XC_MethodHook() { + @Override + protected void afterHookedMethod(MethodHookParam param) throws Throwable { + + // IConnectivityManager mService = IConnectivityManager.Stub.asInterface( + // ServiceManager.getService(Context.CONNECTIVITY_SERVICE)); + + try { + + /*Class servicemanager = Class.forName("android.os.ServiceManager"); + Method getService = servicemanager.getMethod("getService",String.class); + + IConnectivityManager mService = IConnectivityManager.Stub.asInterface( + (IBinder) getService.invoke(servicemanager, Context.CONNECTIVITY_SERVICE)); + + */ + Object mService = XposedHelpers.getObjectField(param.thisObject, "mService"); + + String mPackage = ((Activity) param.thisObject).getCallingPackage(); + + // App is already allowed do nothing + /*if (mService.prepareVpn(mPackage, null)) { + return; + }*/ + + + Class<?>[] prepareVPNsignature = {String.class, String.class}; + if((Boolean) XposedHelpers.callMethod(mService,"prepareVpn",prepareVPNsignature, mPackage,(String)null)) + return; + + + 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 VpnService app: " + mPackage,Toast.LENGTH_LONG).show(); + ((Activity) param.thisObject).finish(); + } + + } catch (Exception e) { + e.printStackTrace(); + + } + + } + + + }); + + } +} diff --git a/vpndialogxposed/src/main/res/drawable-hdpi/ic_launcher.png b/vpndialogxposed/src/main/res/drawable-hdpi/ic_launcher.png Binary files differnew file mode 100644 index 00000000..a134d5fa --- /dev/null +++ b/vpndialogxposed/src/main/res/drawable-hdpi/ic_launcher.png diff --git a/vpndialogxposed/src/main/res/drawable-mdpi/ic_launcher.png b/vpndialogxposed/src/main/res/drawable-mdpi/ic_launcher.png Binary files differnew file mode 100644 index 00000000..ad6d2155 --- /dev/null +++ b/vpndialogxposed/src/main/res/drawable-mdpi/ic_launcher.png diff --git a/vpndialogxposed/src/main/res/drawable-xhdpi/ic_launcher.png b/vpndialogxposed/src/main/res/drawable-xhdpi/ic_launcher.png Binary files differnew file mode 100644 index 00000000..10d3c009 --- /dev/null +++ b/vpndialogxposed/src/main/res/drawable-xhdpi/ic_launcher.png diff --git a/vpndialogxposed/src/main/res/drawable-xxhdpi/ic_launcher.png b/vpndialogxposed/src/main/res/drawable-xxhdpi/ic_launcher.png Binary files differnew file mode 100644 index 00000000..22db1531 --- /dev/null +++ b/vpndialogxposed/src/main/res/drawable-xxhdpi/ic_launcher.png diff --git a/vpndialogxposed/src/main/res/layout/vpnapplayout.xml b/vpndialogxposed/src/main/res/layout/vpnapplayout.xml new file mode 100644 index 00000000..af2a824e --- /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="@string/select_apps"/> + + + <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="@string/no_apps_found" + android:textAppearance="?android:attr/textAppearanceMedium" /> + </LinearLayout> + +</LinearLayout>
\ No newline at end of file diff --git a/vpndialogxposed/src/main/res/values/strings.xml b/vpndialogxposed/src/main/res/values/strings.xml new file mode 100644 index 00000000..6eace130 --- /dev/null +++ b/vpndialogxposed/src/main/res/values/strings.xml @@ -0,0 +1,8 @@ +<?xml version="1.0" encoding="utf-8"?> +<resources> + + <string name="app_name">VpnDialog Xposed Module</string> + <string name="select_apps">Select the apps that should be allowed to use the VpnService API without user confirmation</string> + <string name="no_apps_found">No Apps using the VPNService API found</string> + +</resources> |