summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--res/layout/basic_settings.xml16
-rw-r--r--res/layout/viewconfig.xml11
-rw-r--r--res/layout/vpn_preference_layout.xml2
-rw-r--r--res/values/strings.xml1
-rw-r--r--res/xml/vpn_authentification.xml12
-rw-r--r--res/xml/vpn_headers.xml22
-rw-r--r--res/xml/vpn_ipsettings.xml6
-rw-r--r--src/de/blinkt/openvpn/BasicSettings.java38
-rw-r--r--src/de/blinkt/openvpn/MainActivity.java11
-rw-r--r--src/de/blinkt/openvpn/OpenVPN.java3
-rw-r--r--src/de/blinkt/openvpn/OpenVPNClient.java207
-rw-r--r--src/de/blinkt/openvpn/ProfileManager.java96
-rw-r--r--src/de/blinkt/openvpn/Settings_Authentication.java66
-rw-r--r--src/de/blinkt/openvpn/Settings_IP.java146
-rw-r--r--src/de/blinkt/openvpn/Settings_Obscure.java21
-rw-r--r--src/de/blinkt/openvpn/ShowConfigFragment.java16
-rw-r--r--src/de/blinkt/openvpn/VPNConfigPreference.java42
-rw-r--r--src/de/blinkt/openvpn/VPNPreferenceFragment.java0
-rw-r--r--src/de/blinkt/openvpn/VPNPreferences.java193
-rw-r--r--src/de/blinkt/openvpn/VPNProfileList.java142
-rw-r--r--src/de/blinkt/openvpn/VpnProfile.java236
21 files changed, 844 insertions, 443 deletions
diff --git a/res/layout/basic_settings.xml b/res/layout/basic_settings.xml
index cfe8c6e..4e6f549 100644
--- a/res/layout/basic_settings.xml
+++ b/res/layout/basic_settings.xml
@@ -27,6 +27,20 @@
<TextView
style="@style/item"
+ android:text="@string/profilename"
+ android:textAppearance="?android:attr/textAppearanceSmall" />
+
+ <EditText
+ android:id="@+id/profilename"
+ style="@style/item"
+ android:inputType="text"
+ />
+
+
+
+
+ <TextView
+ style="@style/item"
android:text="@string/address"
android:textAppearance="?android:attr/textAppearanceSmall" />
@@ -38,7 +52,7 @@
<!-- <requestFocus /> -->
</EditText>
-
+
<TextView
style="@style/item"
android:text="@string/port"
diff --git a/res/layout/viewconfig.xml b/res/layout/viewconfig.xml
new file mode 100644
index 0000000..5ae34ef
--- /dev/null
+++ b/res/layout/viewconfig.xml
@@ -0,0 +1,11 @@
+<?xml version="1.0" encoding="utf-8"?>
+<ScrollView xmlns:android="http://schemas.android.com/apk/res/android"
+ android:layout_width="match_parent"
+ android:layout_height="match_parent" >
+
+ <TextView
+ android:id="@+id/configview"
+ android:layout_width="match_parent"
+ android:layout_height="wrap_content" />
+
+</ScrollView> \ No newline at end of file
diff --git a/res/layout/vpn_preference_layout.xml b/res/layout/vpn_preference_layout.xml
index 15fc91a..fbb1811 100644
--- a/res/layout/vpn_preference_layout.xml
+++ b/res/layout/vpn_preference_layout.xml
@@ -22,7 +22,7 @@
android:minHeight="?android:attr/listPreferredItemHeight" >
<LinearLayout
- android:id="@+id/inputmethod_pref"
+ android:id="@+id/vpnconfig_pref"
android:layout_width="wrap_content"
android:layout_height="match_parent"
android:layout_weight="1"
diff --git a/res/values/strings.xml b/res/values/strings.xml
index 79b7f8a..ee2a411 100644
--- a/res/values/strings.xml
+++ b/res/values/strings.xml
@@ -96,6 +96,7 @@
<string name="menu_add_profile">Add Profile</string>
<string name="add_profile_name_prompt">Enter a name identifying the new Profile</string>
<string name="duplicate_profile_name">Duplicate Profile Name</string>
+ <string name="profilename">Profile Name</string>
</resources>
diff --git a/res/xml/vpn_authentification.xml b/res/xml/vpn_authentification.xml
index 949093d..3781211 100644
--- a/res/xml/vpn_authentification.xml
+++ b/res/xml/vpn_authentification.xml
@@ -5,7 +5,15 @@
android:key="remoteServerTLS"
android:summary="Checks whether the server uses a TLS Server Certificate"
android:title="Except TLS Server" />
+ <CheckBoxPreference
+ android:key="checkRemoteCN"
+ android:summary="Checks the Remote Server Certificate CN against a String"
+ android:title="Certificate Hostname Check" />
+
+ <EditTextPreference
+ android:dependency="checkRemoteCN"
+ android:dialogMessage="Enter the String against which the remote Server is checked. Openvpn will use prefix matching. &quot;Server&quot; matches &quot;Server-1&quot; and &quot;Server-2&quot;"
+ android:title="Remote Hostname(CN)"
+ android:key="remotecn"/>
-
- <CheckBoxPreference android:key="useTLSAuth"/>
</PreferenceScreen> \ No newline at end of file
diff --git a/res/xml/vpn_headers.xml b/res/xml/vpn_headers.xml
index 424b441..faaa6cd 100644
--- a/res/xml/vpn_headers.xml
+++ b/res/xml/vpn_headers.xml
@@ -2,34 +2,30 @@
<preference-headers xmlns:android="http://schemas.android.com/apk/res/android" >
<header
+ android:tag="BasicSettings"
android:fragment="de.blinkt.openvpn.BasicSettings"
android:summary="Server, port and authentication method. Normally you should only settings specified here."
- android:title="Basic Settings" />
+ android:title="Basic Settings"
+ android:id="@+id/basicsettingsid"/>
<!-- android:icon="@drawable/ic_settings_applications" -->
<header
- android:fragment="de.blinkt.openvpn.VPNPreferences$IP_Settings"
+ android:fragment="de.blinkt.openvpn.Settings_IP"
android:summary="IP Address and Routing"
android:title="IP Settings" />
<header
- android:fragment="de.blinkt.openvpn.VPNPreferences$Authentication"
+ android:fragment="de.blinkt.openvpn.Settings_Authentication"
android:summary="Authentication"
android:title="Authentication" />
<!-- android:icon="@drawable/ic_settings_display" -->
- <header
- android:fragment="de.blinkt.openvpn.VPNPreferences$Obscure"
+ <!--
+ <header
+ android:fragment="de.blinkt.openvpn.Settings_Obscure"
android:summary="Obscure OpenVPN Settings. Normaly not needed."
android:title="Obscure" >
-
- <!--
- Arbitrary key/value pairs can be included with a header as
- arguments to its fragment.
- -->
- <extra
- android:name="someKey"
- android:value="someHeaderValue" />
</header>
+ -->
<header
android:fragment="de.blinkt.openvpn.ShowConfigFragment"
android:summary="Shows the generated openvpn Configuration File"
diff --git a/res/xml/vpn_ipsettings.xml b/res/xml/vpn_ipsettings.xml
index 8aacaac..79356e6 100644
--- a/res/xml/vpn_ipsettings.xml
+++ b/res/xml/vpn_ipsettings.xml
@@ -4,7 +4,9 @@
<SwitchPreference
android:disableDependentsState="true"
android:key="usePull"
- android:title="Pull Settings" />
+ android:title="Pull Settings"
+ android:summaryOn="Requests IP addresses, routes and timing options from the server."
+ android:summaryOff="No information is requested from the server. Settings need to be specified below." />
<PreferenceCategory android:title="IP" >
<EditTextPreference
@@ -29,9 +31,11 @@
android:title="searchDomain" />
<EditTextPreference
android:key="dns1"
+ android:dialogMessage="DNS Server to be used."
android:title="DNS Server" />
<EditTextPreference
android:key="dns2"
+ android:dialogMessage="Secondary DNS Server used if the normal DNS Server cannot be reached."
android:title="Backup DNS Server" />
</PreferenceCategory>
<PreferenceCategory android:title="Routing" >
diff --git a/src/de/blinkt/openvpn/BasicSettings.java b/src/de/blinkt/openvpn/BasicSettings.java
index 8f4fc77..e80651e 100644
--- a/src/de/blinkt/openvpn/BasicSettings.java
+++ b/src/de/blinkt/openvpn/BasicSettings.java
@@ -40,18 +40,10 @@ import android.widget.ToggleButton;
import de.blinkt.openvpn.R.id;
public class BasicSettings extends Fragment implements View.OnClickListener, OnItemSelectedListener, Callback, OnCheckedChangeListener {
- private static final String TAG = "OpenVpnClient";
-
-
- private static final int START_OPENVPN = 0;
private static final int CHOOSE_FILE_OFFSET = 1000;
private static final int UPDATE_ALIAS = 20;
- private static final String PREFS_NAME = "OVPN_SERVER";
-
- private static final String OVPNCONFIGFILE = "android.conf";
- private static final String OVPNCONFIGPKCS12 = "android.pkcs12";
-
+
private TextView mServerAddress;
private TextView mServerPort;
@@ -92,6 +84,7 @@ public class BasicSettings extends Fragment implements View.OnClickListener, OnI
private VpnProfile mProfile;
+ private EditText mProfileName;
@@ -100,17 +93,22 @@ public class BasicSettings extends Fragment implements View.OnClickListener, OnI
fileselects.put(i, fsl);
fsl.setActivity(getActivity(),i);
}
-
+
+
public void onCreate(Bundle savedInstanceState) {
+ Bundle foo = getArguments();
+ String profileuuid =getArguments().getString(getActivity().getPackageName() + ".profileUUID");
+ mProfile=ProfileManager.get(profileuuid);
super.onCreate(savedInstanceState);
}
@Override
public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) {
+
mView = inflater.inflate(R.layout.basic_settings,container,false);
-
-
+
+ mProfileName = (EditText) mView.findViewById(R.id.profilename);
mServerAddress = (TextView) mView.findViewById(R.id.address);
mServerPort = (TextView) mView.findViewById(R.id.port);
mClientCert = (FileSelectLayout) mView.findViewById(R.id.certselect);
@@ -130,6 +128,8 @@ public class BasicSettings extends Fragment implements View.OnClickListener, OnI
mUserName = (EditText) mView.findViewById(R.id.auth_username);
mPassword = (EditText) mView.findViewById(R.id.auth_password);
+
+
addFileSelectLayout(mCaCert);
addFileSelectLayout(mClientCert);
@@ -152,9 +152,15 @@ public class BasicSettings extends Fragment implements View.OnClickListener, OnI
if (mHandler == null) {
mHandler = new Handler(this);
}
+
return mView;
}
+ @Override
+ public void onActivityCreated(Bundle savedInstanceState) {
+ super.onActivityCreated(savedInstanceState);
+ ((VPNPreferences) getActivity()).setmBS(this);
+ }
@Override
public void onItemSelected(AdapterView<?> parent, View view, int position, long id) {
@@ -194,8 +200,7 @@ public class BasicSettings extends Fragment implements View.OnClickListener, OnI
}
private void loadPreferences() {
- mProfile = ((VPNPreferences)getActivity()).getVPNProfile();
-
+ mProfileName.setText(mProfile.mName);
mClientCert.setData(mProfile.mClientCertFilename);
mClientKey.setData(mProfile.mClientKeyFilename);
mCaCert.setData(mProfile.mCaFilename);
@@ -217,11 +222,11 @@ public class BasicSettings extends Fragment implements View.OnClickListener, OnI
}
- private void savePreferences() {
+ void savePreferences() {
// We need an Editor object to make preference changes.
// All objects are from android.context.Context
-
+ mProfile.mName = mProfileName.getText().toString();
mProfile.mCaFilename = mCaCert.getData();
mProfile.mClientCertFilename = mClientCert.getData();
mProfile.mClientKeyFilename = mClientKey.getData();
@@ -303,5 +308,6 @@ public class BasicSettings extends Fragment implements View.OnClickListener, OnI
} else if (buttonView == mUseTlsAuth) {
mView.findViewById(R.id.tlsauth_options).setVisibility(visibility);
}
+
}
}
diff --git a/src/de/blinkt/openvpn/MainActivity.java b/src/de/blinkt/openvpn/MainActivity.java
index fd4fc6a..5eaf146 100644
--- a/src/de/blinkt/openvpn/MainActivity.java
+++ b/src/de/blinkt/openvpn/MainActivity.java
@@ -2,11 +2,22 @@ package de.blinkt.openvpn;
import java.util.List;
+import android.content.Intent;
import android.preference.PreferenceActivity;
public class MainActivity extends PreferenceActivity {
+
@Override
public void onBuildHeaders(List<Header> target) {
loadHeadersFromResource(R.xml.main_headers, target);
}
+
+ @Override
+ protected void onActivityResult(int requestCode, int resultCode, Intent data) {
+ super.onActivityResult(requestCode, resultCode, data);
+
+ System.out.println(data);
+
+
+ }
}
diff --git a/src/de/blinkt/openvpn/OpenVPN.java b/src/de/blinkt/openvpn/OpenVPN.java
index 7385726..b49bdf6 100644
--- a/src/de/blinkt/openvpn/OpenVPN.java
+++ b/src/de/blinkt/openvpn/OpenVPN.java
@@ -72,6 +72,9 @@ public class OpenVPN {
public static void foo() { }
synchronized public static String[] getlogbuffer() {
+
+ // The stoned way of java to return an array from a vector
+ // brought to you by eclipse auto complete
return (String[]) logbuffer.toArray(new String[logbuffer.size()]);
}
diff --git a/src/de/blinkt/openvpn/OpenVPNClient.java b/src/de/blinkt/openvpn/OpenVPNClient.java
index 5af0ae8..db6dd95 100644
--- a/src/de/blinkt/openvpn/OpenVPNClient.java
+++ b/src/de/blinkt/openvpn/OpenVPNClient.java
@@ -16,25 +16,16 @@
package de.blinkt.openvpn;
-import java.io.FileNotFoundException;
-import java.io.FileOutputStream;
-import java.io.FileWriter;
-import java.io.IOException;
import java.security.KeyStore;
import java.security.KeyStoreException;
import java.security.NoSuchAlgorithmException;
-import java.security.PrivateKey;
-import java.security.cert.CertificateException;
import java.security.cert.X509Certificate;
import java.util.HashMap;
-import java.util.Random;
-import java.util.Vector;
import javax.net.ssl.TrustManagerFactory;
import javax.net.ssl.X509TrustManager;
import android.app.Activity;
-import android.content.Context;
import android.content.Intent;
import android.content.SharedPreferences;
import android.net.VpnService;
@@ -44,7 +35,6 @@ import android.os.Handler.Callback;
import android.os.Message;
import android.security.KeyChain;
import android.security.KeyChainAliasCallback;
-import android.security.KeyChainException;
import android.util.Log;
import android.view.View;
import android.widget.AdapterView;
@@ -71,8 +61,6 @@ public class OpenVPNClient extends Activity implements View.OnClickListener, OnI
private static final String PREFS_NAME = "OVPN_SERVER";
- private static final String OVPNCONFIGFILE = "android.conf";
- private static final String OVPNCONFIGPKCS12 = "android.pkcs12";
private TextView mServerAddress;
@@ -117,133 +105,14 @@ public class OpenVPNClient extends Activity implements View.OnClickListener, OnI
}
- public void writeConfigFile()
- {
-
- try {
- FileWriter cfg = new FileWriter(getCacheDir().getAbsolutePath() + "/" + OVPNCONFIGFILE);
-
-
-
- // TODO "--remote-cert-eku", "TLS Web Server Authentication"
-
-
- // The stoned way of java to return an array from a vector
- // brought to you by eclipse auto complete
-
- cfg.write("client\n");
- cfg.write("verb 2\n");
-
-
- // /tmp does not exist on Android
- cfg.write("tmp-dir ");
- cfg.write(getCacheDir().getAbsolutePath());
- cfg.write("\n");
-
- // quit after 5 tries
- cfg.write("--connect-retry-max 5\n");
- cfg.write("--resolv-retry 5\n");
-
-
-
- // We cannot use anything else than tun
- cfg.write("dev tun\n");
-
- // Server Address
- cfg.write("remote ");
- cfg.write(mServerAddress.getText().toString());
- cfg.write(" ");
- cfg.write(mServerPort.getText().toString());
- if(mTcpUdp.isChecked())
- cfg.write(" udp\n");
- else
- cfg.write(" tcp\n");
-
-
-
- switch(mType.getSelectedItemPosition()) {
- case VpnProfile.TYPE_CERTIFICATES:
- // Ca
- cfg.write("ca ");
- cfg.write(mCaCert.getData());
- cfg.write("\n");
-
- // Client Cert + Key
- cfg.write("key ");
- cfg.write(mClientKey.getData());
- cfg.write("\n");
- cfg.write("cert ");
- cfg.write(mClientCert.getData());
- cfg.write("\n");
- break;
- case VpnProfile.TYPE_PKCS12:
- cfg.write("pkcs12 ");
- cfg.write(mpkcs12.getData());
- cfg.write("\n");
- cfg.write("management-query-passwords\n");
- break;
-
- case VpnProfile.TYPE_KEYSTORE:
- cfg.write("pkcs12 ");
- cfg.write(getCacheDir().getAbsolutePath() + "/" + OVPNCONFIGPKCS12);
- cfg.write("\n");
- cfg.write("management-query-passwords\n");
- break;
-
- }
-
- if(mUseLzo.isChecked()) {
- cfg.write("comp-lzo\n");
- }
-
- if(mUseTlsAuth.isChecked()) {
- cfg.write("tls-auth ");
- cfg.write(mTlsFile.getData());
- int tlsdir= mTLSDirection.getSelectedItemPosition();
- // 2 is unspecified
- if(tlsdir == 1 || tlsdir==2) {
- cfg.write(" ");
- cfg.write(new Integer(tlsdir).toString());
- }
- cfg.write("\n");
- }
- cfg.flush();
- cfg.close();
-
- } catch (IOException e) {
- // TODO Auto-generated catch block
- e.printStackTrace();
- }
-
- }
-
+
private void addFileSelectLayout (FileSelectLayout fsl) {
int i = fileselects.size() + CHOOSE_FILE_OFFSET;
fileselects.put(i, fsl);
fsl.setActivity(this,i);
}
- public String[] buildOpenvpnArgv()
- {
- Vector<String> args = new Vector<String>();
- // Add fixed paramenters
- args.add("openvpn");
-
- // Enable managment interface to
- // stop openvpn
- args.add("--management");
-
- args.add(getCacheDir().getAbsolutePath() + "/" + "mgmtsocket");
- args.add("unix");
- //args.add("--management-hold");
-
- args.add("--config");
- args.add(getCacheDir().getAbsolutePath() + "/" + OVPNCONFIGFILE);
-
-
- return (String[]) args.toArray(new String[args.size()]);
- }
@@ -415,52 +284,7 @@ public class OpenVPNClient extends Activity implements View.OnClickListener, OnI
null); // alias to preselect, null if unavailable
}
- private String getRandomPW() {
- String pw= "";
- // Put enough digits togher to make a password :)
- Random r = new Random();
- for(int i=0;i < 4;i++) {
- pw += new Integer(r.nextInt(1000)).toString();
- }
-
- return pw;
-
- }
-
- private String savePKCS12() {
- Context context = getBaseContext();
- PrivateKey privateKey = null;
- X509Certificate[] cachain=null;
- try {
- privateKey = KeyChain.getPrivateKey(context,certalias);
- cachain = KeyChain.getCertificateChain(context, certalias);
-
- KeyStore ks = KeyStore.getInstance("PKCS12");
- ks.load(null, null);
- ks.setKeyEntry("usercert", privateKey, null, cachain);
- String mypw = getRandomPW();
- FileOutputStream fout = new FileOutputStream(getCacheDir().getAbsolutePath() + "/" + OVPNCONFIGPKCS12);
- ks.store(fout,mypw.toCharArray());
- fout.flush(); fout.close();
- return mypw;
- } catch (KeyChainException e) {
- e.printStackTrace();
- } catch (InterruptedException e) {
- e.printStackTrace();
- } catch (KeyStoreException e) {
- e.printStackTrace();
- } catch (FileNotFoundException e) {
- e.printStackTrace();
- } catch (NoSuchAlgorithmException e) {
- e.printStackTrace();
- } catch (CertificateException e) {
- e.printStackTrace();
- } catch (IOException e) {
- e.printStackTrace();
- }
- return "ERROR";
-
- }
+
public void testGetallCerts() throws NoSuchAlgorithmException, KeyStoreException {
TrustManagerFactory tmf = TrustManagerFactory
@@ -497,32 +321,7 @@ public class OpenVPNClient extends Activity implements View.OnClickListener, OnI
}
}
- void startOpenVpn() {
- String prefix = getPackageName();
- writeConfigFile();
-
- Intent intent = new Intent(this, OpenVpnService.class)
- .putExtra(prefix + ".ARGV" , buildOpenvpnArgv());
- if(mType.getSelectedItemPosition()== VpnProfile.TYPE_PKCS12){
- intent.putExtra(prefix + ".PKCS12PASS",
- mPKCS12Password.getText().toString());
- }
-
- if(mType.getSelectedItemPosition() == VpnProfile.TYPE_KEYSTORE) {
- String pkcs12pw = savePKCS12();
- intent.putExtra(prefix + ".PKCS12PASS", pkcs12pw);
- }
-
- if(mType.getSelectedItemPosition() == VpnProfile.TYPE_USERPASS) {
- intent.putExtra(prefix + ".USERNAME", mUserName.getText().toString());
- intent.putExtra(prefix + ".PASSWORD", mPassword.getText().toString());
- }
-
- startService(intent);
- Intent startLW = new Intent(getBaseContext(),LogWindow.class);
- startActivity(startLW);
- }
/* (non-Javadoc)
* @see android.app.Activity#onActivityResult(int, int, android.content.Intent)
@@ -550,7 +349,7 @@ public class OpenVPNClient extends Activity implements View.OnClickListener, OnI
@Override
public void run() {
- startOpenVpn();
+ // startOpenVpn();
}
}
diff --git a/src/de/blinkt/openvpn/ProfileManager.java b/src/de/blinkt/openvpn/ProfileManager.java
new file mode 100644
index 0000000..078403e
--- /dev/null
+++ b/src/de/blinkt/openvpn/ProfileManager.java
@@ -0,0 +1,96 @@
+package de.blinkt.openvpn;
+
+import java.io.FileNotFoundException;
+import java.io.IOException;
+import java.io.ObjectInputStream;
+import java.io.StreamCorruptedException;
+import java.util.Collection;
+import java.util.HashMap;
+import java.util.HashSet;
+import java.util.Set;
+
+import android.app.Activity;
+import android.content.Context;
+import android.content.SharedPreferences;
+import android.content.SharedPreferences.Editor;
+
+public class ProfileManager {
+ private static final String PREFS_NAME = "VPNList";
+
+
+
+ private static ProfileManager instance;
+ private HashMap<String,VpnProfile> profiles=new HashMap<String, VpnProfile>();
+
+ public static VpnProfile get(String key) {
+ checkInstance();
+ return instance.profiles.get(key);
+
+ }
+
+ private ProfileManager() { }
+
+ private static void checkInstance() {
+ if(instance == null)
+ instance = new ProfileManager();
+ }
+
+ public static ProfileManager getInstance() {
+ checkInstance();
+ return instance;
+ }
+
+
+
+ public Collection<VpnProfile> getProfiles() {
+ return profiles.values();
+ }
+
+ public VpnProfile getProfileByName(String name) {
+ for (VpnProfile vpnp : profiles.values()) {
+ if(vpnp.getName().equals(name)) {
+ return vpnp;
+ }
+ }
+ return null;
+ }
+
+ public void saveProfileList(Activity activity) {
+ SharedPreferences sharedprefs = activity.getSharedPreferences(PREFS_NAME,Activity.MODE_PRIVATE);
+ Editor editor = sharedprefs.edit();
+ editor.putStringSet("vpnlist", profiles.keySet());
+ editor.commit();
+ }
+
+ public void addProfile(VpnProfile profile) {
+ profiles.put(profile.getUUID().toString(),profile);
+
+ }
+ void loadVPNList(Context context) {
+ profiles = new HashMap<String, VpnProfile>();
+ SharedPreferences settings =context.getSharedPreferences(PREFS_NAME,Activity.MODE_PRIVATE);
+ Set<String> vlist = settings.getStringSet("vpnlist", null);
+ if(vlist==null){
+ vlist = new HashSet<String>();
+ }
+
+ for (String vpnentry : vlist) {
+ try {
+ ObjectInputStream vpnfile = new ObjectInputStream(context.openFileInput(vpnentry + ".vp"));
+ VpnProfile vp = ((VpnProfile) vpnfile.readObject());
+
+ profiles.put(vp.getUUID().toString(), vp);
+
+ } catch (StreamCorruptedException e) {
+ e.printStackTrace();
+ } catch (FileNotFoundException e) {
+ e.printStackTrace();
+ } catch (IOException e) {
+ e.printStackTrace();
+ } catch (ClassNotFoundException e) {
+ e.printStackTrace();
+ }
+ }
+ }
+
+}
diff --git a/src/de/blinkt/openvpn/Settings_Authentication.java b/src/de/blinkt/openvpn/Settings_Authentication.java
new file mode 100644
index 0000000..1f96c6c
--- /dev/null
+++ b/src/de/blinkt/openvpn/Settings_Authentication.java
@@ -0,0 +1,66 @@
+package de.blinkt.openvpn;
+
+import android.os.Bundle;
+import android.preference.CheckBoxPreference;
+import android.preference.EditTextPreference;
+import android.preference.Preference;
+import android.preference.Preference.OnPreferenceChangeListener;
+import android.preference.PreferenceFragment;
+
+public class Settings_Authentication extends PreferenceFragment implements OnPreferenceChangeListener {
+ private CheckBoxPreference mExpectTLSCert;
+ private CheckBoxPreference mCheckRemoteCN;
+ private EditTextPreference mRemoteCN;
+ private VpnProfile mProfile;
+
+ @Override
+ public void onCreate(Bundle savedInstanceState) {
+ super.onCreate(savedInstanceState);
+
+ // Load the preferences from an XML resource
+ addPreferencesFromResource(R.xml.vpn_authentification);
+
+ mExpectTLSCert = (CheckBoxPreference) findPreference("remoteServerTLS");
+ mCheckRemoteCN = (CheckBoxPreference) findPreference("checkRemoteCN");
+ mRemoteCN = (EditTextPreference) findPreference("remotecn");
+ mRemoteCN.setOnPreferenceChangeListener(this);
+ String profileUUID = getArguments().getString(getActivity().getPackageName() + ".profileUUID");
+ mProfile = ProfileManager.get(profileUUID);
+
+ loadSettings();
+
+ }
+
+ private void loadSettings() {
+
+ mExpectTLSCert.setChecked(mProfile.mExpectTLSCert);
+ mCheckRemoteCN.setChecked(mProfile.mCheckRemoteCN);
+ mRemoteCN.setText(mProfile.mRemoteCN);
+ onPreferenceChange(mRemoteCN, mProfile.mRemoteCN);
+
+ }
+
+ private void saveSettings() {
+ mProfile.mExpectTLSCert=mExpectTLSCert.isChecked();
+ mProfile.mCheckRemoteCN=mCheckRemoteCN.isChecked();
+ mProfile.mRemoteCN=mRemoteCN.getText();
+ }
+
+ @Override
+ public void onPause() {
+ super.onPause();
+ saveSettings();
+ }
+
+ @Override
+ public boolean onPreferenceChange(Preference preference, Object newValue) {
+ if(preference==mRemoteCN) {
+ if ("".equals(newValue))
+ preference.setSummary(mProfile.mServerName);
+ else
+ preference.setSummary((String)newValue);
+ }
+ saveSettings();
+ return true;
+ }
+} \ No newline at end of file
diff --git a/src/de/blinkt/openvpn/Settings_IP.java b/src/de/blinkt/openvpn/Settings_IP.java
new file mode 100644
index 0000000..a1bb16e
--- /dev/null
+++ b/src/de/blinkt/openvpn/Settings_IP.java
@@ -0,0 +1,146 @@
+package de.blinkt.openvpn;
+import android.os.Bundle;
+import android.preference.CheckBoxPreference;
+import android.preference.EditTextPreference;
+import android.preference.Preference;
+import android.preference.Preference.OnPreferenceChangeListener;
+import android.preference.PreferenceFragment;
+import android.preference.PreferenceManager;
+import android.preference.SwitchPreference;
+
+public class Settings_IP extends PreferenceFragment implements OnPreferenceChangeListener {
+ private EditTextPreference mIPv4;
+ private EditTextPreference mIPv6;
+ private SwitchPreference mUsePull;
+ private CheckBoxPreference mOverrideDNS;
+ private EditTextPreference mSearchdomain;
+ private EditTextPreference mDNS1;
+ private EditTextPreference mDNS2;
+ private EditTextPreference mCustomRoutes;
+ private CheckBoxPreference mUseDefaultRoute;
+ private VpnProfile mProfile;
+
+ @Override
+ public void onCreate(Bundle savedInstanceState) {
+ super.onCreate(savedInstanceState);
+
+ String profileUUID = getArguments().getString(getActivity().getPackageName() + ".profileUUID");
+ mProfile = ProfileManager.get(profileUUID);
+
+
+ // Make sure default values are applied. In a real app, you would
+ // want this in a shared function that is used to retrieve the
+ // SharedPreferences wherever they are needed.
+ PreferenceManager.setDefaultValues(getActivity(),
+ R.xml.vpn_ipsettings, false);
+
+ // Load the preferences from an XML resource
+ addPreferencesFromResource(R.xml.vpn_ipsettings);
+ mIPv4 = (EditTextPreference) findPreference("ipv4_address");
+ mIPv6 = (EditTextPreference) findPreference("ipv6_address");
+ mUsePull = (SwitchPreference) findPreference("usePull");
+ mOverrideDNS = (CheckBoxPreference) findPreference("overrideDNS");
+ mSearchdomain =(EditTextPreference) findPreference("searchdomain");
+ mDNS1 = (EditTextPreference) findPreference("dns1");
+ mDNS2 = (EditTextPreference) findPreference("dns2");
+ mCustomRoutes = (EditTextPreference) findPreference("customRoutes");
+ mUseDefaultRoute = (CheckBoxPreference) findPreference("useDefaultRoute");
+
+ mIPv4.setOnPreferenceChangeListener(this);
+ mIPv6.setOnPreferenceChangeListener(this);
+ mDNS1.setOnPreferenceChangeListener(this);
+ mDNS2.setOnPreferenceChangeListener(this);
+ mUsePull.setOnPreferenceChangeListener(this);
+ mOverrideDNS.setOnPreferenceChangeListener(this);
+ mSearchdomain.setOnPreferenceChangeListener(this);
+ mCustomRoutes.setOnPreferenceChangeListener(this);
+
+
+
+
+ loadSettings();
+ }
+
+ private void loadSettings() {
+
+ mUsePull.setChecked(mProfile.mUsePull);
+ mIPv4.setText(mProfile.mIPv4Address);
+ mIPv6.setText(mProfile.mIPv6Address);
+ mDNS1.setText(mProfile.mDNS1);
+ mDNS2.setText(mProfile.mDNS2);
+ mOverrideDNS.setChecked(mProfile.mOverrideDNS);
+ mSearchdomain.setText(mProfile.mSearchDomain);
+ mUseDefaultRoute.setChecked(mProfile.mUseDefaultRoute);
+ mCustomRoutes.setText(mProfile.mCustomRoutes);
+
+ // Sets Summary
+ onPreferenceChange(mIPv4, mIPv4.getText());
+ onPreferenceChange(mIPv6, mIPv6.getText());
+ onPreferenceChange(mDNS1, mDNS1.getText());
+ onPreferenceChange(mDNS2, mDNS2.getText());
+ onPreferenceChange(mSearchdomain, mSearchdomain.getText());
+ onPreferenceChange(mCustomRoutes, mCustomRoutes.getText());
+
+ setDNSState();
+ }
+
+ public void onSaveInstanceState (Bundle outState) {
+ saveSettings();
+ }
+
+ @Override
+ public void onStop() {
+ saveSettings();
+ super.onStop();
+
+ }
+
+ private void saveSettings() {
+ mProfile.mUsePull = mUsePull.isChecked();
+ mProfile.mIPv4Address = mIPv4.getText();
+ mProfile.mIPv6Address = mIPv6.getText();
+ mProfile.mDNS1 = mDNS1.getText();
+ mProfile.mDNS2 = mDNS2.getText();
+ mProfile.mOverrideDNS = mOverrideDNS.isChecked();
+ mProfile.mSearchDomain = mSearchdomain.getText();
+ mProfile.mUseDefaultRoute = mUseDefaultRoute.isChecked();
+ mProfile.mCustomRoutes = mCustomRoutes.getText();
+
+
+ }
+
+ @Override
+ public boolean onPreferenceChange(Preference preference,
+ Object newValue) {
+ if(preference==mIPv4 || preference == mIPv6
+ || preference==mDNS1 || preference == mDNS2
+ || preference == mSearchdomain || preference == mCustomRoutes
+ )
+
+ preference.setSummary((String)newValue);
+
+ if(preference== mUsePull || preference == mOverrideDNS)
+ setDNSState();
+
+ saveSettings();
+ return true;
+ }
+
+ private void setDNSState() {
+ boolean enabled;
+ mOverrideDNS.setEnabled(mUsePull.isChecked());
+ if(!mUsePull.isChecked())
+ enabled =true;
+ else if (mOverrideDNS.isChecked())
+ enabled = true;
+ else
+ enabled = false;
+
+ mDNS1.setEnabled(enabled);
+ mDNS2.setEnabled(enabled);
+ mSearchdomain.setEnabled(enabled);
+
+ }
+
+
+ } \ No newline at end of file
diff --git a/src/de/blinkt/openvpn/Settings_Obscure.java b/src/de/blinkt/openvpn/Settings_Obscure.java
new file mode 100644
index 0000000..8375466
--- /dev/null
+++ b/src/de/blinkt/openvpn/Settings_Obscure.java
@@ -0,0 +1,21 @@
+package de.blinkt.openvpn;
+
+import android.os.Bundle;
+import android.preference.PreferenceFragment;
+import android.preference.PreferenceManager;
+
+public class Settings_Obscure extends PreferenceFragment {
+ @Override
+ public void onCreate(Bundle savedInstanceState) {
+ super.onCreate(savedInstanceState);
+
+ // Make sure default values are applied. In a real app, you would
+ // want this in a shared function that is used to retrieve the
+ // SharedPreferences wherever they are needed.
+ PreferenceManager.setDefaultValues(getActivity(),
+ R.xml.vpn_ipsettings, false);
+
+ // Load the preferences from an XML resource
+ addPreferencesFromResource(R.xml.vpn_obscure);
+ }
+} \ No newline at end of file
diff --git a/src/de/blinkt/openvpn/ShowConfigFragment.java b/src/de/blinkt/openvpn/ShowConfigFragment.java
index 91471e8..a69d835 100644
--- a/src/de/blinkt/openvpn/ShowConfigFragment.java
+++ b/src/de/blinkt/openvpn/ShowConfigFragment.java
@@ -1,8 +1,22 @@
package de.blinkt.openvpn;
import android.app.Fragment;
+import android.os.Bundle;
+import android.view.LayoutInflater;
+import android.view.View;
+import android.view.ViewGroup;
+import android.widget.TextView;
public class ShowConfigFragment extends Fragment {
-
+ public android.view.View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState)
+ {
+ String profileUUID = getArguments().getString(getActivity().getPackageName() + ".profileUUID");
+ VpnProfile vp = ProfileManager.get(profileUUID);
+ String cfg=vp.getConfigFile(getActivity().getCacheDir());
+ View v=inflater.inflate(R.layout.viewconfig, container,false);
+ TextView cv = (TextView) v.findViewById(R.id.configview);
+ cv.setText(cfg);
+ return v;
+ };
}
diff --git a/src/de/blinkt/openvpn/VPNConfigPreference.java b/src/de/blinkt/openvpn/VPNConfigPreference.java
index 0387ebd..aebc8bc 100644
--- a/src/de/blinkt/openvpn/VPNConfigPreference.java
+++ b/src/de/blinkt/openvpn/VPNConfigPreference.java
@@ -7,28 +7,48 @@ import android.view.View.OnClickListener;
import android.widget.ImageView;
public class VPNConfigPreference extends Preference implements OnClickListener {
+ class startClickListener implements OnClickListener{
+ private VPNConfigPreference mvp;
+ public startClickListener(VPNConfigPreference vp) {
+ mvp = vp;
+ }
- private OnQuickSettingsClickListener mOnQuickSettingsListener;
+ @Override
+ public void onClick(View v) {
+ mOnQuickSettingsListener.onStartVPNClick(mvp);
+ }
+
+ }
+
+ private VpnPreferencesClickListener mOnQuickSettingsListener;
private ImageView mQuickPrefButton;
public VPNConfigPreference(VPNProfileList vpnProfileList, Bundle args) {
-
super(vpnProfileList.getActivity());
- setWidgetLayoutResource(R.layout.vpn_preference_layout);
-
-
+ setLayoutResource(R.layout.vpn_preference_layout);
+
}
+
+ private View mProfilesPref;
@Override
protected void onBindView(View view) {
super.onBindView(view);
+ mProfilesPref = view.findViewById(R.id.vpnconfig_pref);
+ mProfilesPref.setOnClickListener(new startClickListener(this));
+ mProfilesPref.setClickable(true);
+
mQuickPrefButton = (ImageView) view.findViewById(R.id.quickedit_settings);
mQuickPrefButton.setOnClickListener(this);
+
+ // Quick Fix, until I know what really goes wrong here :(
+ //view.findViewById(android.R.id.widget_frame).setOnClickListener(this);
}
+
- public interface OnQuickSettingsClickListener {
+ public interface VpnPreferencesClickListener {
/**
* Called when a Preference has been clicked.
*
@@ -36,19 +56,19 @@ public class VPNConfigPreference extends Preference implements OnClickListener {
* @return True if the click was handled.
*/
boolean onQuickSettingsClick(Preference preference);
+
+ void onStartVPNClick(VPNConfigPreference vpnConfigPreference);
}
+
- public void setOnQuickSettingsClickListener(OnQuickSettingsClickListener onQuickSettingsListener) {
+ public void setOnQuickSettingsClickListener(VpnPreferencesClickListener onQuickSettingsListener) {
mOnQuickSettingsListener = onQuickSettingsListener;
}
@Override
public void onClick(View v) {
- if (mOnQuickSettingsListener != null) {
- mOnQuickSettingsListener.onQuickSettingsClick(this);
- }
-
+ mOnQuickSettingsListener.onQuickSettingsClick(this);
}
diff --git a/src/de/blinkt/openvpn/VPNPreferenceFragment.java b/src/de/blinkt/openvpn/VPNPreferenceFragment.java
deleted file mode 100644
index e69de29..0000000
--- a/src/de/blinkt/openvpn/VPNPreferenceFragment.java
+++ /dev/null
diff --git a/src/de/blinkt/openvpn/VPNPreferences.java b/src/de/blinkt/openvpn/VPNPreferences.java
index 2773145..75788d7 100644
--- a/src/de/blinkt/openvpn/VPNPreferences.java
+++ b/src/de/blinkt/openvpn/VPNPreferences.java
@@ -1,151 +1,104 @@
package de.blinkt.openvpn;
+import java.io.FileNotFoundException;
+import java.io.IOException;
+import java.io.ObjectOutputStream;
import java.util.List;
+import android.app.Activity;
+import android.content.Intent;
import android.os.Bundle;
-import android.preference.CheckBoxPreference;
-import android.preference.EditTextPreference;
-import android.preference.Preference;
-import android.preference.Preference.OnPreferenceChangeListener;
import android.preference.PreferenceActivity;
-import android.preference.PreferenceFragment;
-import android.preference.PreferenceManager;
-import android.preference.SwitchPreference;
import android.widget.Button;
public class VPNPreferences extends PreferenceActivity {
private VpnProfile mProfile;
+ private BasicSettings mBS;
+ public void setmBS(BasicSettings mBS) {
+ this.mBS = mBS;
+ }
+
public VPNPreferences() {
super();
+
+ }
+
+
+ protected void onPause() {
+ super.onPause();
+ saveSettings();
+
+ }
+
+
+ @Override
+ protected void onStop() {
+ super.onStop();
+ };
+
+
+ private void saveSettings() {
+ // First let basic settings save its state
+ if(mBS!=null)
+ mBS.savePreferences();
+
+ ObjectOutputStream vpnfile;
+ try {
+ vpnfile = new ObjectOutputStream(openFileOutput((mProfile.getUUID().toString() + ".vp"),Activity.MODE_PRIVATE));
+
+ vpnfile.writeObject(mProfile);
+ vpnfile.flush();
+ vpnfile.close();
+ } catch (FileNotFoundException e) {
+
+ e.printStackTrace();
+ } catch (IOException e) {
+
+ e.printStackTrace();
+ }
+ }
+
+ @Override
+ protected void onSaveInstanceState(Bundle outState) {
+ super.onSaveInstanceState(outState);
+ outState.putSerializable(getPackageName() + ".VpnProfile",mProfile);
}
+
+ @Override
+ protected void onRestoreInstanceState(Bundle state) {
+ super.onRestoreInstanceState(state);
+ mProfile = (VpnProfile) state.getSerializable(getPackageName() + ".VpnProfile");
+ }
+
+
@Override
protected void onCreate(Bundle savedInstanceState) {
+ mProfile = (VpnProfile) getIntent().getSerializableExtra(getPackageName() + ".VpnProfile");
super.onCreate(savedInstanceState);
- mProfile = getIntent().getParcelableExtra("VpnProfile");
+
if (hasHeaders()) {
Button button = new Button(this);
- button.setText("Some action");
+ button.setText("Save");
setListFooter(button);
}
}
+
+
@Override
public void onBuildHeaders(List<Header> target) {
- loadHeadersFromResource(R.xml.vpn_headers, target);
- }
-
- public static class IP_Settings extends PreferenceFragment implements OnPreferenceChangeListener {
- private EditTextPreference mIPv4;
- private EditTextPreference mIPv6;
- private SwitchPreference mUsePull;
- private CheckBoxPreference mOverrideDNS;
- private Preference mSearchdomain;
- private Preference mDNS1;
- private Preference mDNS2;
-
- @Override
- public void onCreate(Bundle savedInstanceState) {
- super.onCreate(savedInstanceState);
-
-
- // Make sure default values are applied. In a real app, you would
- // want this in a shared function that is used to retrieve the
- // SharedPreferences wherever they are needed.
- PreferenceManager.setDefaultValues(getActivity(),
- R.xml.vpn_ipsettings, false);
-
- // Load the preferences from an XML resource
- addPreferencesFromResource(R.xml.vpn_ipsettings);
- mIPv4 = (EditTextPreference) findPreference("ipv4_address");
- mIPv6 = (EditTextPreference) findPreference("ipv6_address");
- mUsePull = (SwitchPreference) findPreference("usePull");
- mOverrideDNS = (CheckBoxPreference) findPreference("overrideDNS");
- mSearchdomain =findPreference("searchdomain");
- mDNS1 = findPreference("dns1");
- mDNS2 = findPreference("dns2");
-
- mIPv4.setOnPreferenceChangeListener(this);
- mIPv6.setOnPreferenceChangeListener(this);
- mDNS1.setOnPreferenceChangeListener(this);
- mDNS2.setOnPreferenceChangeListener(this);
- mUsePull.setOnPreferenceChangeListener(this);
- mOverrideDNS.setOnPreferenceChangeListener(this);
-
-
- VpnProfile vp = ((VPNPreferences) getActivity()).getVPNProfile();
-
-
- setDNSState();
-
-
+ loadHeadersFromResource(R.xml.vpn_headers, target);
+ for (Header header : target) {
+ if(header.fragmentArguments==null)
+ header.fragmentArguments = new Bundle();
+ header.fragmentArguments.putString(getPackageName() + ".profileUUID",mProfile.getUUID().toString());
+ if(header.extras==null)
+ header.extras = new Bundle();
+ header.extras.putString(getPackageName() + ".profileUUID",mProfile.getUUID().toString());
}
-
- @Override
- public boolean onPreferenceChange(Preference preference,
- Object newValue) {
- if(preference==mIPv4 || preference == mIPv6 ||
- preference==mDNS1 || preference == mDNS2)
- preference.setSummary((String)newValue);
-
- if(preference== mUsePull || preference == mOverrideDNS)
- setDNSState();
-
- return true;
- }
-
- private void setDNSState() {
- boolean enabled;
- mOverrideDNS.setEnabled(mUsePull.isChecked());
- if(!mUsePull.isChecked())
- enabled =true;
- else if (mOverrideDNS.isChecked())
- enabled = true;
- else
- enabled = false;
-
- mDNS1.setEnabled(enabled);
- mDNS2.setEnabled(enabled);
- mSearchdomain.setEnabled(enabled);
-
- }
-
-
- }
- public static class Authentication extends PreferenceFragment {
- @Override
- public void onCreate(Bundle savedInstanceState) {
- super.onCreate(savedInstanceState);
-
- // Make sure default values are applied. In a real app, you would
- // want this in a shared function that is used to retrieve the
- // SharedPreferences wherever they are needed.
- PreferenceManager.setDefaultValues(getActivity(),
- R.xml.vpn_authentification, false);
-
- // Load the preferences from an XML resource
- addPreferencesFromResource(R.xml.vpn_authentification);
- }
- }
- public static class Obscure extends PreferenceFragment {
- @Override
- public void onCreate(Bundle savedInstanceState) {
- super.onCreate(savedInstanceState);
-
- // Make sure default values are applied. In a real app, you would
- // want this in a shared function that is used to retrieve the
- // SharedPreferences wherever they are needed.
- PreferenceManager.setDefaultValues(getActivity(),
- R.xml.vpn_ipsettings, false);
-
- // Load the preferences from an XML resource
- addPreferencesFromResource(R.xml.vpn_obscure);
- }
- }
- public VpnProfile getVPNProfile() {
- return mProfile;
}
}
diff --git a/src/de/blinkt/openvpn/VPNProfileList.java b/src/de/blinkt/openvpn/VPNProfileList.java
index 59e231c..48c7a7a 100644
--- a/src/de/blinkt/openvpn/VPNProfileList.java
+++ b/src/de/blinkt/openvpn/VPNProfileList.java
@@ -2,24 +2,16 @@ package de.blinkt.openvpn;
import java.io.FileNotFoundException;
import java.io.IOException;
-import java.io.ObjectInputStream;
import java.io.ObjectOutputStream;
-import java.io.StreamCorruptedException;
-import java.util.HashMap;
-import java.util.HashSet;
-import java.util.Set;
import android.app.Activity;
import android.app.AlertDialog;
import android.content.Context;
import android.content.DialogInterface;
import android.content.Intent;
-import android.content.SharedPreferences;
-import android.content.SharedPreferences.Editor;
+import android.net.VpnService;
import android.os.Bundle;
-import android.os.Parcelable;
import android.preference.Preference;
-import android.preference.Preference.OnPreferenceClickListener;
import android.preference.PreferenceFragment;
import android.preference.PreferenceScreen;
import android.view.Menu;
@@ -27,15 +19,15 @@ import android.view.MenuInflater;
import android.view.MenuItem;
import android.widget.EditText;
import android.widget.Toast;
-import de.blinkt.openvpn.VPNConfigPreference.OnQuickSettingsClickListener;
-
-public class VPNProfileList extends PreferenceFragment implements OnPreferenceClickListener, OnQuickSettingsClickListener {
- private static final String PREFS_NAME = "VPNList";
+import de.blinkt.openvpn.VPNConfigPreference.VpnPreferencesClickListener;
+public class VPNProfileList extends PreferenceFragment implements VpnPreferencesClickListener {
private static final int MENU_ADD_PROFILE = Menu.FIRST;
+ private static final int START_VPN_PROFILECONFIG = 70;
+
- private HashMap<String,VpnProfile> profiles;
+ private VpnProfile mSelectedVPN;
@Override
public void onCreate(Bundle savedInstanceState) {
@@ -56,10 +48,10 @@ public class VPNProfileList extends PreferenceFragment implements OnPreferenceCl
@Override
public void onCreateOptionsMenu(Menu menu, MenuInflater inflater) {
menu.add(0, MENU_ADD_PROFILE, 0, R.string.menu_add_profile)
- .setIcon(android.R.drawable.ic_menu_add)
- .setAlphabeticShortcut('a')
- .setShowAsAction(MenuItem.SHOW_AS_ACTION_IF_ROOM
- | MenuItem.SHOW_AS_ACTION_WITH_TEXT);
+ .setIcon(android.R.drawable.ic_menu_add)
+ .setAlphabeticShortcut('a')
+ .setShowAsAction(MenuItem.SHOW_AS_ACTION_IF_ROOM
+ | MenuItem.SHOW_AS_ACTION_WITH_TEXT);
}
@@ -91,7 +83,7 @@ public class VPNProfileList extends PreferenceFragment implements OnPreferenceCl
@Override
public void onClick(DialogInterface dialog, int which) {
String name = entry.getText().toString();
- if (getProfileByName(name)==null) {
+ if (getPM().getProfileByName(name)==null) {
VpnProfile profile = new VpnProfile(name);
addProfile(profile);
refreshList();
@@ -113,20 +105,10 @@ public class VPNProfileList extends PreferenceFragment implements OnPreferenceCl
}
- public VpnProfile getProfileByName(String name) {
- for (VpnProfile vpnp : profiles.values()) {
- if(vpnp.getName().equals(name)) {
- return vpnp;
- }
- }
- return null;
- }
-
+
private void addProfile(VpnProfile profile) {
- profiles.put(profile.getUUID().toString(),profile);
- Editor editor = getActivity().getSharedPreferences(PREFS_NAME,Activity.MODE_PRIVATE).edit();
- editor.putStringSet("vpnlist", profiles.keySet());
- editor.commit();
+ getPM().addProfile(profile);
+ getPM().saveProfileList(getActivity());
saveProfile(profile);
}
@@ -149,81 +131,99 @@ public class VPNProfileList extends PreferenceFragment implements OnPreferenceCl
}
}
- private void loadVPNList() {
- profiles = new HashMap<String, VpnProfile>();
- SharedPreferences settings =getActivity().getSharedPreferences(PREFS_NAME,Activity.MODE_PRIVATE);
- Set<String> vlist = settings.getStringSet("vpnlist", null);
- if(vlist==null){
- vlist = new HashSet<String>();
- }
-
- for (String vpnentry : vlist) {
- try {
- ObjectInputStream vpnfile = new ObjectInputStream(getActivity().openFileInput(vpnentry + ".vp"));
- VpnProfile vp = ((VpnProfile) vpnfile.readObject());
-
- profiles.put(vp.getUUID().toString(), vp);
-
- } catch (StreamCorruptedException e) {
- e.printStackTrace();
- } catch (FileNotFoundException e) {
- e.printStackTrace();
- } catch (IOException e) {
- e.printStackTrace();
- } catch (ClassNotFoundException e) {
- e.printStackTrace();
- }
- }
- }
-
+
public void refreshList() {
PreferenceScreen plist = getPreferenceScreen();
if (plist != null) {
plist.removeAll();
- loadVPNList();
+ getPM().loadVPNList(getActivity());
- for (VpnProfile vpnprofile: profiles.values()) {
+ for (VpnProfile vpnprofile: getPM().getProfiles()) {
Bundle args = new Bundle();
//TODO
String profileuuid = vpnprofile.getUUID().toString();
- args.putParcelable("Profile", vpnprofile);
+ args.putSerializable(getActivity().getPackageName() + ".VpnProfile", vpnprofile);
//args.putString("name", vpnentry);
VPNConfigPreference vpref = new VPNConfigPreference(this, args);
vpref.setKey(profileuuid);
vpref.setTitle(vpnprofile.getName());
vpref.setPersistent(false);
// vpref.setSelectable(true);
- vpref.setOnPreferenceClickListener(this);
vpref.setOnQuickSettingsClickListener(this);
plist.addPreference(vpref);
}
+
}
}
- @Override
- public boolean onPreferenceClick(Preference preference) {
- String key= preference.getKey();
- return true;
-
+ private ProfileManager getPM() {
+ return ProfileManager.getInstance();
}
@Override
public boolean onQuickSettingsClick(Preference preference) {
String key = preference.getKey();
- VpnProfile vprofile = profiles.get(key);
+ VpnProfile vprofile = ProfileManager.get(key);
Intent vprefintent = new Intent(getActivity(),VPNPreferences.class)
- .putExtra("VpnProfile", (Parcelable)vprofile);
+ .putExtra(getActivity().getPackageName() + ".VpnProfile", vprofile);
- startActivity(vprefintent);
+ startActivityForResult(vprefintent,START_VPN_PROFILECONFIG);
return true;
}
+
+
+
+
+
+ @Override
+ public void onActivityResult(int requestCode, int resultCode, Intent data) {
+ super.onActivityResult(requestCode, resultCode, data);
+ if(requestCode==START_VPN_PROFILECONFIG) {
+ new startOpenVpnThread().start();;
+
+ }
+
+ }
+
+ private class startOpenVpnThread extends Thread {
+
+ @Override
+ public void run() {
+ startOpenVpn();
+ }
+
+ void startOpenVpn() {
+ Intent startVPN = mSelectedVPN.prepareIntent(getActivity());
+
+ getActivity().startService(startVPN);
+ Intent startLW = new Intent(getActivity().getBaseContext(),LogWindow.class);
+ startActivity(startLW);
+ getActivity().finish();
+ }
+ }
+
+ @Override
+ public void onStartVPNClick(VPNConfigPreference preference) {
+ // Query the System for permission
+ mSelectedVPN = getPM().get(preference.getKey());
+ Intent intent = VpnService.prepare(getActivity());
+
+ if (intent != null) {
+ // Start the query
+ intent.putExtra("FOO", "WAR BIER");
+ startActivityForResult(intent, 0);
+ } else {
+ onActivityResult(START_VPN_PROFILECONFIG, Activity.RESULT_OK, null);
+ }
+
+ }
}
diff --git a/src/de/blinkt/openvpn/VpnProfile.java b/src/de/blinkt/openvpn/VpnProfile.java
index 0eddaba..c199cf8 100644
--- a/src/de/blinkt/openvpn/VpnProfile.java
+++ b/src/de/blinkt/openvpn/VpnProfile.java
@@ -1,12 +1,31 @@
package de.blinkt.openvpn;
+import java.io.File;
+import java.io.FileNotFoundException;
+import java.io.FileOutputStream;
+import java.io.FileWriter;
+import java.io.IOException;
import java.io.Serializable;
+import java.security.KeyStore;
+import java.security.KeyStoreException;
+import java.security.NoSuchAlgorithmException;
+import java.security.PrivateKey;
+import java.security.cert.CertificateException;
+import java.security.cert.X509Certificate;
+import java.util.Random;
import java.util.UUID;
+import java.util.Vector;
+import android.app.Activity;
+import android.content.Context;
+import android.content.Intent;
import android.os.Parcel;
import android.os.Parcelable;
+import android.security.KeyChain;
+import android.security.KeyChainException;
-public class VpnProfile implements Parcelable, Serializable{
+public class VpnProfile implements Serializable{
+ // Parcable
/**
*
*/
@@ -16,7 +35,8 @@ public class VpnProfile implements Parcelable, Serializable{
static final int TYPE_KEYSTORE=2;
public static final int TYPE_USERPASS = 3;
public static final int TYPE_STATICKEYS = 4;
-
+
+ private static final String OVPNCONFIGFILE = "android.conf";
// Keep in order of parceling
// Public attributes, since I got mad with getter/setter
@@ -37,6 +57,20 @@ public class VpnProfile implements Parcelable, Serializable{
public String mPKCS12Password;
public boolean mUseTLSAuth = false;
public String mServerName = "openvpn.blinkt.de" ;
+ public String mDNS1="131.234.137.23";
+ public String mDNS2="131.234.137.24";
+ public String mIPv4Address;
+ public String mIPv6Address;
+ public boolean mOverrideDNS=false;
+ public String mSearchDomain="blinkt.de";
+ public boolean mUseDefaultRoute=true;
+ public boolean mUsePull=true;
+ public String mCustomRoutes;
+ public boolean mCheckRemoteCN=false;
+ public boolean mExpectTLSCert=true;
+ public String mRemoteCN="";
+ private String mPassword;
+ private String mUsername;
public int describeContents() {
@@ -93,6 +127,9 @@ public class VpnProfile implements Parcelable, Serializable{
}
};
+
+ static final String OVPNCONFIGPKCS12 = "android.pkcs12";
+
public VpnProfile(String name) {
mUuid = UUID.randomUUID();
mName = name;
@@ -108,7 +145,202 @@ public class VpnProfile implements Parcelable, Serializable{
return mName;
}
+
+ public String getConfigFile(File cacheDir)
+ {
+
+ String cfg="";
+
+
+ // TODO "--remote-cert-eku", "TLS Web Server Authentication"
+
+
+
+ cfg+="client\n";
+ cfg+="verb 2\n";
+
+
+ // /tmp does not exist on Android
+ cfg+="tmp-dir ";
+ cfg+=cacheDir.getAbsolutePath();
+ cfg+="\n";
+
+ // quit after 5 tries
+ cfg+="connect-retry-max 5\n";
+ cfg+="resolv-retry 5\n";
+
+
+
+ // We cannot use anything else than tun
+ cfg+="dev tun\n";
+
+ // Server Address
+ cfg+="remote ";
+ cfg+=mServerName;
+ cfg+=" ";
+ cfg+=mServerPort;
+ if(mUseUdp)
+ cfg+=" udp\n";
+ else
+ cfg+=" tcp\n";
+
+
+ switch(mAuthenticationType) {
+ case VpnProfile.TYPE_CERTIFICATES:
+ // Ca
+ cfg+="ca ";
+ cfg+=mCaFilename;
+ cfg+="\n";
+
+ // Client Cert + Key
+ cfg+="key ";
+ cfg+=mClientKeyFilename;
+ cfg+="\n";
+ cfg+="cert ";
+ cfg+=mClientCertFilename;
+ cfg+="\n";
+ break;
+ case VpnProfile.TYPE_PKCS12:
+ cfg+="pkcs12 ";
+ cfg+=mPKCS12Filename;
+ cfg+="\n";
+ cfg+="management-query-passwords\n";
+ break;
+
+ case VpnProfile.TYPE_KEYSTORE:
+ cfg+="pkcs12 ";
+ cfg+=cacheDir.getAbsolutePath() + "/" + OVPNCONFIGPKCS12;
+ cfg+="\n";
+ cfg+="management-query-passwords\n";
+ break;
+
+ }
+
+ if(mUseLzo) {
+ cfg+="comp-lzo\n";
+ }
+
+ if(mUseTLSAuth) {
+ cfg+="tls-auth ";
+ cfg+=mTLSAuthFilename;
+ int tlsdir= mTLSAuthDirection;
+ // 2 is unspecified
+ if(tlsdir == 0 || tlsdir==1) {
+ cfg+=" ";
+ cfg+=new Integer(tlsdir).toString();
+ }
+ cfg+="\n";
+ }
+
+ return cfg;
+ }
+ private String[] buildOpenvpnArgv(File cacheDir)
+ {
+ Vector<String> args = new Vector<String>();
+
+ // Add fixed paramenters
+ args.add("openvpn");
+
+ // Enable managment interface to
+ // stop openvpn
+ args.add("--management");
+
+ args.add(cacheDir.getAbsolutePath() + "/" + "mgmtsocket");
+ args.add("unix");
+ //args.add("--management-hold");
+
+ args.add("--config");
+ args.add(cacheDir.getAbsolutePath() + "/" + OVPNCONFIGFILE);
+
+
+ return (String[]) args.toArray(new String[args.size()]);
+ }
+
+ public Intent prepareIntent(Activity activity) {
+ String prefix = activity.getPackageName();
+
+ Intent intent = new Intent(activity,OpenVpnService.class);
+
+ intent.putExtra(prefix + ".ARGV" , buildOpenvpnArgv(activity.getCacheDir()));
+
+ if(mAuthenticationType == TYPE_PKCS12){
+ intent.putExtra(prefix + ".PKCS12PASS",
+ mPKCS12Password);
+ }
+
+ if(mAuthenticationType == VpnProfile.TYPE_KEYSTORE) {
+ String pkcs12pw = savePKCS12(activity);
+ intent.putExtra(prefix + ".PKCS12PASS", pkcs12pw);
+ }
+
+ if(mAuthenticationType == VpnProfile.TYPE_USERPASS) {
+ intent.putExtra(prefix + ".USERNAME", mUsername);
+ intent.putExtra(prefix + ".PASSWORD", mPassword);
+ }
+
+ try {
+ FileWriter cfg = new FileWriter(activity.getCacheDir().getAbsolutePath() + "/" + OVPNCONFIGFILE);
+ cfg.write(getConfigFile(activity.getCacheDir()));
+ cfg.flush();
+ cfg.close();
+ } catch (IOException e) {
+ e.printStackTrace();
+ }
+
+ return intent;
+ }
+
+ private String getRandomPW() {
+ String pw= "";
+ // Put enough digits togher to make a password :)
+ Random r = new Random();
+ for(int i=0;i < 4;i++) {
+ pw += new Integer(r.nextInt(1000)).toString();
+ }
+
+ return pw;
+
+ }
+
+ private String savePKCS12(Context context) {
+ PrivateKey privateKey = null;
+ X509Certificate[] cachain=null;
+ try {
+ privateKey = KeyChain.getPrivateKey(context,mAlias);
+ cachain = KeyChain.getCertificateChain(context, mAlias);
+
+ KeyStore ks = KeyStore.getInstance("PKCS12");
+ ks.load(null, null);
+ ks.setKeyEntry("usercert", privateKey, null, cachain);
+ String mypw = getRandomPW();
+ FileOutputStream fout = new FileOutputStream(context.getCacheDir().getAbsolutePath() + "/" + VpnProfile.OVPNCONFIGPKCS12);
+ ks.store(fout,mypw.toCharArray());
+ fout.flush(); fout.close();
+ return mypw;
+ } catch (KeyChainException e) {
+ e.printStackTrace();
+ } catch (InterruptedException e) {
+ e.printStackTrace();
+ } catch (KeyStoreException e) {
+ e.printStackTrace();
+ } catch (FileNotFoundException e) {
+ e.printStackTrace();
+ } catch (NoSuchAlgorithmException e) {
+ e.printStackTrace();
+ } catch (CertificateException e) {
+ e.printStackTrace();
+ } catch (IOException e) {
+ e.printStackTrace();
+ }
+ return "ERROR";
+
+ }
+
}
+
+
+
+