summaryrefslogtreecommitdiff
path: root/vpndialogxposed
diff options
context:
space:
mode:
Diffstat (limited to 'vpndialogxposed')
-rw-r--r--vpndialogxposed/build.gradle64
-rw-r--r--vpndialogxposed/libs/XposedBridgeApi.jarbin0 -> 99376 bytes
-rw-r--r--vpndialogxposed/src/main/AndroidManifest.xml33
-rw-r--r--vpndialogxposed/src/main/assets/xposed_init1
-rw-r--r--vpndialogxposed/src/main/java/de/blinkt/vpndialogxposed/AllowedVPNsChooser.java150
-rw-r--r--vpndialogxposed/src/main/java/de/blinkt/vpndialogxposed/IConnectivityManager.java105
-rw-r--r--vpndialogxposed/src/main/java/de/blinkt/vpndialogxposed/VpnDialogPatcher.java99
-rw-r--r--vpndialogxposed/src/main/res/drawable-hdpi/ic_launcher.pngbin0 -> 741 bytes
-rw-r--r--vpndialogxposed/src/main/res/drawable-mdpi/ic_launcher.pngbin0 -> 549 bytes
-rw-r--r--vpndialogxposed/src/main/res/drawable-xhdpi/ic_launcher.pngbin0 -> 1061 bytes
-rw-r--r--vpndialogxposed/src/main/res/drawable-xxhdpi/ic_launcher.pngbin0 -> 1647 bytes
-rw-r--r--vpndialogxposed/src/main/res/layout/vpnapplayout.xml34
-rw-r--r--vpndialogxposed/src/main/res/values/strings.xml8
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
new file mode 100644
index 00000000..a87ddb46
--- /dev/null
+++ b/vpndialogxposed/libs/XposedBridgeApi.jar
Binary files differ
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
new file mode 100644
index 00000000..a134d5fa
--- /dev/null
+++ b/vpndialogxposed/src/main/res/drawable-hdpi/ic_launcher.png
Binary files differ
diff --git a/vpndialogxposed/src/main/res/drawable-mdpi/ic_launcher.png b/vpndialogxposed/src/main/res/drawable-mdpi/ic_launcher.png
new file mode 100644
index 00000000..ad6d2155
--- /dev/null
+++ b/vpndialogxposed/src/main/res/drawable-mdpi/ic_launcher.png
Binary files differ
diff --git a/vpndialogxposed/src/main/res/drawable-xhdpi/ic_launcher.png b/vpndialogxposed/src/main/res/drawable-xhdpi/ic_launcher.png
new file mode 100644
index 00000000..10d3c009
--- /dev/null
+++ b/vpndialogxposed/src/main/res/drawable-xhdpi/ic_launcher.png
Binary files differ
diff --git a/vpndialogxposed/src/main/res/drawable-xxhdpi/ic_launcher.png b/vpndialogxposed/src/main/res/drawable-xxhdpi/ic_launcher.png
new file mode 100644
index 00000000..22db1531
--- /dev/null
+++ b/vpndialogxposed/src/main/res/drawable-xxhdpi/ic_launcher.png
Binary files differ
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>