diff options
21 files changed, 844 insertions, 443 deletions
| diff --git a/res/layout/basic_settings.xml b/res/layout/basic_settings.xml index cfe8c6e3..4e6f549f 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 00000000..5ae34ef0 --- /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 15fc91ab..fbb18115 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 79b7f8a7..ee2a4113 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 949093d6..3781211f 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. "Server" matches "Server-1" and "Server-2"" +        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 424b4411..faaa6cdd 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 8aacaaca..79356e69 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 8f4fc770..e80651e5 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 fd4fc6a2..5eaf146c 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 7385726b..b49bdf68 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 5af0ae8f..db6dd95a 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 00000000..078403e1 --- /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 00000000..1f96c6ca --- /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 00000000..a1bb16e0 --- /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 00000000..83754663 --- /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 91471e84..a69d835a 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 0387ebdb..aebc8bc0 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 e69de29b..00000000 --- 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 27731453..75788d74 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 59e231cc..48c7a7a2 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 0eddabaa..c199cf8b 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"; + +	} +  } + + + + | 
