From c373af42b1a75b0f23c2f0edbf196dfbb1ef0a0e Mon Sep 17 00:00:00 2001 From: Arne Schwabe Date: Tue, 11 Feb 2014 23:36:48 +0100 Subject: Rework and fix config import --- res/values/strings.xml | 1 + src/de/blinkt/openvpn/VpnProfile.java | 34 +- .../blinkt/openvpn/activities/ConfigConverter.java | 749 +++++++++++---------- src/de/blinkt/openvpn/activities/FileSelect.java | 6 +- src/de/blinkt/openvpn/core/ConfigParser.java | 28 +- src/de/blinkt/openvpn/core/X509Utils.java | 6 +- .../openvpn/fragments/Settings_Authentication.java | 7 +- src/de/blinkt/openvpn/fragments/Utils.java | 67 +- src/de/blinkt/openvpn/views/FileSelectLayout.java | 10 +- 9 files changed, 503 insertions(+), 405 deletions(-) diff --git a/res/values/strings.xml b/res/values/strings.xml index d96f51a0..f4f7f6eb 100755 --- a/res/values/strings.xml +++ b/res/values/strings.xml @@ -314,4 +314,5 @@ Networks directly connected to the local interfaces will not be routed over the VPN. Unchecking this option will redirect all traffic indented for local networks to VPN. Bypass VPN for local networks Username/Password file + [Imported from: %s] diff --git a/src/de/blinkt/openvpn/VpnProfile.java b/src/de/blinkt/openvpn/VpnProfile.java index d18fc72a..1ec34b51 100644 --- a/src/de/blinkt/openvpn/VpnProfile.java +++ b/src/de/blinkt/openvpn/VpnProfile.java @@ -47,6 +47,7 @@ public class VpnProfile implements Serializable { // Don't change this, not all parts of the program use this constant public static final String EXTRA_PROFILEUUID = "de.blinkt.openvpn.profileUUID"; public static final String INLINE_TAG = "[[INLINE]]"; + public static final String DISPLAYNAME_TAG = "[[NAME]]"; public static final String MINIVPN = "miniopenvpn"; private static final long serialVersionUID = 7085688938959334563L; private static final String OVPNCONFIGFILE = "android.conf"; @@ -462,9 +463,9 @@ public class VpnProfile implements Serializable { if (filedata == null) { // TODO: generate good error return String.format("%s %s\n", cfgentry, "missing"); - } else if (filedata.startsWith(VpnProfile.INLINE_TAG)) { - String datawoheader = filedata.substring(VpnProfile.INLINE_TAG.length()); - return String.format(Locale.ENGLISH, "<%s>\n%s\n\n", cfgentry, datawoheader, cfgentry); + } else if (isEmbedded(filedata)) { + String dataWithOutHeader = getEmbeddedContent(filedata); + return String.format(Locale.ENGLISH, "<%s>\n%s\n\n", cfgentry, dataWithOutHeader, cfgentry); } else { return String.format(Locale.ENGLISH, "%s %s\n", cfgentry, openVpnEscape(filedata)); } @@ -583,6 +584,31 @@ public class VpnProfile implements Serializable { return getKeyStoreCertificates(context, 5); } + public static String getDisplayName(String embeddedFile) { + int start = DISPLAYNAME_TAG.length(); + int end = embeddedFile.indexOf(INLINE_TAG); + return embeddedFile.substring(start,end); + } + + public static String getEmbeddedContent(String data) + { + if (!data.contains(INLINE_TAG)) + return data; + + int start = data.indexOf(INLINE_TAG) + INLINE_TAG.length(); + return data.substring(start); + } + + public static boolean isEmbedded(String data) { + if (data==null) + return false; + if(data.startsWith(INLINE_TAG) || data.startsWith(DISPLAYNAME_TAG)) + return true; + else + return false; + } + + class NoCertReturnedException extends Exception { public NoCertReturnedException (String msg) { super(msg); @@ -760,7 +786,7 @@ public class VpnProfile implements Serializable { return false; String data = ""; - if (mClientKeyFilename.startsWith(INLINE_TAG)) + if (isEmbedded(mClientKeyFilename)) data = mClientKeyFilename; else { char[] buf = new char[2048]; diff --git a/src/de/blinkt/openvpn/activities/ConfigConverter.java b/src/de/blinkt/openvpn/activities/ConfigConverter.java index 50253915..e999fe9f 100644 --- a/src/de/blinkt/openvpn/activities/ConfigConverter.java +++ b/src/de/blinkt/openvpn/activities/ConfigConverter.java @@ -1,24 +1,24 @@ package de.blinkt.openvpn.activities; -import java.io.*; -import java.util.*; - import android.app.Activity; import android.app.AlertDialog; import android.app.AlertDialog.Builder; import android.app.ListActivity; import android.content.ActivityNotFoundException; import android.content.Intent; +import android.database.Cursor; import android.os.Bundle; import android.os.Environment; +import android.provider.OpenableColumns; import android.security.KeyChain; import android.security.KeyChainAliasCallback; +import android.text.TextUtils; import android.util.Base64; +import android.util.Log; import android.view.*; import android.widget.ArrayAdapter; import android.widget.CheckBox; - import android.widget.LinearLayout; import de.blinkt.openvpn.R; import de.blinkt.openvpn.VpnProfile; @@ -29,71 +29,75 @@ import de.blinkt.openvpn.fragments.Utils; import de.blinkt.openvpn.views.FileSelectLayout; import junit.framework.Assert; -import static de.blinkt.openvpn.views.FileSelectLayout.*; +import java.io.*; +import java.util.*; + +import static de.blinkt.openvpn.views.FileSelectLayout.FileSelectCallback; public class ConfigConverter extends ListActivity implements FileSelectCallback { - public static final String IMPORT_PROFILE = "de.blinkt.openvpn.IMPORT_PROFILE"; + public static final String IMPORT_PROFILE = "de.blinkt.openvpn.IMPORT_PROFILE"; private static final int RESULT_INSTALLPKCS12 = 7; private static final int CHOOSE_FILE_OFFSET = 1000; public static final String VPNPROFILE = "vpnProfile"; private VpnProfile mResult; - private transient ArrayAdapter mArrayAdapter; + private transient ArrayAdapter mArrayAdapter; - private transient List mPathsegments; + private transient List mPathsegments; - private String mAliasName=null; + private String mAliasName = null; private Map fileSelectMap = new HashMap(); + private String mEmbeddedPwFile; - @Override - public boolean onOptionsItemSelected(MenuItem item) { - if(item.getItemId()==R.id.cancel){ - setResult(Activity.RESULT_CANCELED); - finish(); - } else if(item.getItemId()==R.id.ok) { - if(mResult==null) { - log("Importing the config had error, cannot save it"); - return true; - } + @Override + public boolean onOptionsItemSelected(MenuItem item) { + if (item.getItemId() == R.id.cancel) { + setResult(Activity.RESULT_CANCELED); + finish(); + } else if (item.getItemId() == R.id.ok) { + if (mResult == null) { + log("Importing the config had error, cannot save it"); + return true; + } - Intent in = installPKCS12(); + Intent in = installPKCS12(); - if(in != null) - startActivityForResult(in, RESULT_INSTALLPKCS12); - else - saveProfile(); + if (in != null) + startActivityForResult(in, RESULT_INSTALLPKCS12); + else + saveProfile(); - return true; - } + return true; + } - return super.onOptionsItemSelected(item); + return super.onOptionsItemSelected(item); - } + } @Override protected void onSaveInstanceState(Bundle outState) { super.onSaveInstanceState(outState); - if(mResult!=null) - outState.putSerializable(VPNPROFILE,mResult); + if (mResult != null) + outState.putSerializable(VPNPROFILE, mResult); outState.putString("mAliasName", mAliasName); String[] logentries = new String[mArrayAdapter.getCount()]; - for(int i =0; i < mArrayAdapter.getCount();i++){ + for (int i = 0; i < mArrayAdapter.getCount(); i++) { logentries[i] = mArrayAdapter.getItem(i); } outState.putStringArray("logentries", logentries); int[] fileselects = new int[fileSelectMap.size()]; - int k=0; - for (Utils.FileType key :fileSelectMap.keySet()){ - fileselects[k]=key.getValue(); + int k = 0; + for (Utils.FileType key : fileSelectMap.keySet()) { + fileselects[k] = key.getValue(); k++; } - outState.putIntArray("fileselects",fileselects); - + outState.putIntArray("fileselects", fileselects); + outState.putString("pwfile",mEmbeddedPwFile); } @Override @@ -111,224 +115,222 @@ public class ConfigConverter extends ListActivity implements FileSelectCallback String data = fs.getData(); - switch (type){ - case USERPW_FILE: - ConfigParser.useEmbbedUserAuth(mResult, data); - break; - case PKCS12: - mResult.mPKCS12Filename = data; - break; - case TLS_AUTH_FILE: - mResult.mTLSAuthFilename = data; - break; - case CA_CERTIFICATE: - mResult.mCaFilename = data; - break; - case CLIENT_CERTIFICATE: - mResult.mClientCertFilename = data; - break; - case KEYFILE: - mResult.mClientKeyFilename = data; - break; - default: - Assert.fail(); - } + switch (type) { + case USERPW_FILE: + mEmbeddedPwFile = data; + break; + case PKCS12: + mResult.mPKCS12Filename = data; + break; + case TLS_AUTH_FILE: + mResult.mTLSAuthFilename = data; + break; + case CA_CERTIFICATE: + mResult.mCaFilename = data; + break; + case CLIENT_CERTIFICATE: + mResult.mClientCertFilename = data; + break; + case KEYFILE: + mResult.mClientKeyFilename = data; + break; + default: + Assert.fail(); + } } super.onActivityResult(requestCode, resultCode, result); } - private void saveProfile() { - Intent result = new Intent(); - ProfileManager vpl = ProfileManager.getInstance(this); + private void saveProfile() { + Intent result = new Intent(); + ProfileManager vpl = ProfileManager.getInstance(this); + if (!TextUtils.isEmpty(mEmbeddedPwFile)) + ConfigParser.useEmbbedUserAuth(mResult, mEmbeddedPwFile); - vpl.addProfile(mResult); - vpl.saveProfile(this, mResult); - vpl.saveProfileList(this); - result.putExtra(VpnProfile.EXTRA_PROFILEUUID,mResult.getUUID().toString()); - setResult(Activity.RESULT_OK, result); - finish(); - } + vpl.addProfile(mResult); + vpl.saveProfile(this, mResult); + vpl.saveProfileList(this); + result.putExtra(VpnProfile.EXTRA_PROFILEUUID, mResult.getUUID().toString()); + setResult(Activity.RESULT_OK, result); + finish(); + } - public void showCertDialog () { - try { - KeyChain.choosePrivateKeyAlias(this, - new KeyChainAliasCallback() { + public void showCertDialog() { + try { + KeyChain.choosePrivateKeyAlias(this, + new KeyChainAliasCallback() { - public void alias(String alias) { - // Credential alias selected. Remember the alias selection for future use. - mResult.mAlias=alias; - saveProfile(); - } + public void alias(String alias) { + // Credential alias selected. Remember the alias selection for future use. + mResult.mAlias = alias; + saveProfile(); + } - }, - new String[] {"RSA"}, // List of acceptable key types. null for any - null, // issuer, null for any - mResult.mServerName, // host name of server requesting the cert, null if unavailable - -1, // port of server requesting the cert, -1 if unavailable - mAliasName); // alias to preselect, null if unavailable - } catch (ActivityNotFoundException anf) { - Builder ab = new AlertDialog.Builder(this); - ab.setTitle(R.string.broken_image_cert_title); - ab.setMessage(R.string.broken_image_cert); - ab.setPositiveButton(android.R.string.ok, null); - ab.show(); - } - } + }, + new String[]{"RSA"}, // List of acceptable key types. null for any + null, // issuer, null for any + mResult.mServerName, // host name of server requesting the cert, null if unavailable + -1, // port of server requesting the cert, -1 if unavailable + mAliasName); // alias to preselect, null if unavailable + } catch (ActivityNotFoundException anf) { + Builder ab = new AlertDialog.Builder(this); + ab.setTitle(R.string.broken_image_cert_title); + ab.setMessage(R.string.broken_image_cert); + ab.setPositiveButton(android.R.string.ok, null); + ab.show(); + } + } - private Intent installPKCS12() { - - if(!((CheckBox)findViewById(R.id.importpkcs12)).isChecked()) { - setAuthTypeToEmbeddedPKCS12(); - return null; - - } - String pkcs12datastr = mResult.mPKCS12Filename; - if(pkcs12datastr!=null && pkcs12datastr.startsWith(VpnProfile.INLINE_TAG)) { - Intent inkeyintent = KeyChain.createInstallIntent(); - - pkcs12datastr= pkcs12datastr.substring(VpnProfile.INLINE_TAG.length()); - - - byte[] pkcs12data = Base64.decode(pkcs12datastr, Base64.DEFAULT); + private Intent installPKCS12() { + if (!((CheckBox) findViewById(R.id.importpkcs12)).isChecked()) { + setAuthTypeToEmbeddedPKCS12(); + return null; - inkeyintent.putExtra(KeyChain.EXTRA_PKCS12,pkcs12data ); + } + String pkcs12datastr = mResult.mPKCS12Filename; + if (VpnProfile.isEmbedded(pkcs12datastr)) { + Intent inkeyIntent = KeyChain.createInstallIntent(); - if(mAliasName.equals("")) - mAliasName=null; + pkcs12datastr = VpnProfile.getEmbeddedContent(pkcs12datastr); - if(mAliasName!=null){ - inkeyintent.putExtra(KeyChain.EXTRA_NAME, mAliasName); - } - return inkeyintent; - } - return null; - } + byte[] pkcs12data = Base64.decode(pkcs12datastr, Base64.DEFAULT); + inkeyIntent.putExtra(KeyChain.EXTRA_PKCS12, pkcs12data); - private void setAuthTypeToEmbeddedPKCS12() { - if(mResult.mPKCS12Filename!=null && mResult.mPKCS12Filename.startsWith(VpnProfile.INLINE_TAG)) { - if(mResult.mAuthenticationType==VpnProfile.TYPE_USERPASS_KEYSTORE) - mResult.mAuthenticationType=VpnProfile.TYPE_USERPASS_PKCS12; - - if(mResult.mAuthenticationType==VpnProfile.TYPE_KEYSTORE) - mResult.mAuthenticationType=VpnProfile.TYPE_PKCS12; - - } - } + if (mAliasName.equals("")) + mAliasName = null; + if (mAliasName != null) { + inkeyIntent.putExtra(KeyChain.EXTRA_NAME, mAliasName); + } + return inkeyIntent; + } + return null; + } + + + private void setAuthTypeToEmbeddedPKCS12() { + if (VpnProfile.isEmbedded(mResult.mPKCS12Filename)) { + if (mResult.mAuthenticationType == VpnProfile.TYPE_USERPASS_KEYSTORE) + mResult.mAuthenticationType = VpnProfile.TYPE_USERPASS_PKCS12; + if (mResult.mAuthenticationType == VpnProfile.TYPE_KEYSTORE) + mResult.mAuthenticationType = VpnProfile.TYPE_PKCS12; + + } + } - private String getUniqueProfileName(String possibleName) { + private String getUniqueProfileName(String possibleName) { - int i=0; + int i = 0; ProfileManager vpl = ProfileManager.getInstance(this); - String newname = possibleName; - - // Default to - if(mResult.mName!=null && !ConfigParser.CONVERTED_PROFILE.equals(mResult.mName)) - newname=mResult.mName; - - while(newname==null || vpl.getProfileByName(newname)!=null) { - i++; - if(i==1) - newname = getString(R.string.converted_profile); - else - newname = getString(R.string.converted_profile_i,i); - } - - return newname; - } - - @Override - public boolean onCreateOptionsMenu(Menu menu) { - MenuInflater inflater = getMenuInflater(); - inflater.inflate(R.menu.import_menu, menu); - return true; - } - - private String embedFile(String filename, Utils.FileType type) - { - if(filename==null) - return null; - - // Already embedded, nothing to do - if(filename.startsWith(VpnProfile.INLINE_TAG)) - return filename; - - File possibleFile = findFile(filename, type); - if(possibleFile==null) - return filename; - else - return readFileContent(possibleFile,type == Utils.FileType.PKCS12); - - } - - private File findFile(String filename, Utils.FileType fileType) { - File foundfile =findFileRaw(filename); - - if (foundfile==null && filename!=null && !filename.equals("")) { - log(R.string.import_could_not_open,filename); + String newname = possibleName; + + // Default to + if (mResult.mName != null && !ConfigParser.CONVERTED_PROFILE.equals(mResult.mName)) + newname = mResult.mName; + + while (newname == null || vpl.getProfileByName(newname) != null) { + i++; + if (i == 1) + newname = getString(R.string.converted_profile); + else + newname = getString(R.string.converted_profile_i, i); + } + + return newname; + } + + @Override + public boolean onCreateOptionsMenu(Menu menu) { + MenuInflater inflater = getMenuInflater(); + inflater.inflate(R.menu.import_menu, menu); + return true; + } + + private String embedFile(String filename, Utils.FileType type) { + if (filename == null) + return null; + + // Already embedded, nothing to do + if (VpnProfile.isEmbedded(filename)) + return filename; + + File possibleFile = findFile(filename, type); + if (possibleFile == null) + return filename; + else + return readFileContent(possibleFile, type == Utils.FileType.PKCS12); + + } + + private File findFile(String filename, Utils.FileType fileType) { + File foundfile = findFileRaw(filename); + + if (foundfile == null && filename != null && !filename.equals("")) { + log(R.string.import_could_not_open, filename); addFileSelectDialog(fileType); } - return foundfile; - } + return foundfile; + } private void addFileSelectDialog(Utils.FileType type) { int titleRes = 0; - String value=null; + String value = null; switch (type) { case KEYFILE: titleRes = R.string.client_key_title; - if (mResult!=null) + if (mResult != null) value = mResult.mClientKeyFilename; break; case CLIENT_CERTIFICATE: titleRes = R.string.client_certificate_title; - if (mResult!=null) + if (mResult != null) value = mResult.mClientCertFilename; break; case CA_CERTIFICATE: titleRes = R.string.ca_title; - if (mResult!=null) + if (mResult != null) value = mResult.mCaFilename; break; case TLS_AUTH_FILE: titleRes = R.string.tls_auth_file; - if (mResult!=null) + if (mResult != null) value = mResult.mTLSAuthFilename; break; case PKCS12: titleRes = R.string.client_pkcs12_title; - if (mResult!=null) + if (mResult != null) value = mResult.mPKCS12Filename; break; case USERPW_FILE: titleRes = R.string.userpw_file; - return; + value = mEmbeddedPwFile; + break; } boolean isCert = type == Utils.FileType.CA_CERTIFICATE || type == Utils.FileType.CLIENT_CERTIFICATE; - FileSelectLayout fl = new FileSelectLayout(this,getString(titleRes), isCert); + FileSelectLayout fl = new FileSelectLayout(this, getString(titleRes), isCert); fileSelectMap.put(type, fl); fl.setLayoutParams(new LinearLayout.LayoutParams(LinearLayout.LayoutParams.MATCH_PARENT, ViewGroup.LayoutParams.WRAP_CONTENT)); ((LinearLayout) findViewById(R.id.config_convert_root)).addView(fl, 1); - fl.setData(value,this); + fl.setData(value, this); int i = getFileLayoutOffset(type); fl.setCaller(this, i, type); @@ -339,132 +341,127 @@ public class ConfigConverter extends ListActivity implements FileSelectCallback } - private File findFileRaw(String filename) - { - if(filename == null || filename.equals("")) - return null; + private File findFileRaw(String filename) { + if (filename == null || filename.equals("")) + return null; - // Try diffent path relative to /mnt/sdcard - File sdcard = Environment.getExternalStorageDirectory(); - File root = new File("/"); + // Try diffent path relative to /mnt/sdcard + File sdcard = Environment.getExternalStorageDirectory(); + File root = new File("/"); - HashSet dirlist = new HashSet(); + HashSet dirlist = new HashSet(); - for(int i=mPathsegments.size()-1;i >=0 ;i--){ - String path = ""; - for (int j = 0;j<=i;j++) { - path += "/" + mPathsegments.get(j); - } + for (int i = mPathsegments.size() - 1; i >= 0; i--) { + String path = ""; + for (int j = 0; j <= i; j++) { + path += "/" + mPathsegments.get(j); + } // Do a little hackish dance for the Android File Importer // /document/primary:ovpn/openvpn-imt.conf - if (path.indexOf(':')!=-1) { - String possibleDir = path.substring(path.indexOf(':')+1,path.length()); - possibleDir = possibleDir.substring(0,possibleDir.lastIndexOf('/')); + if (path.indexOf(':') != -1) { + String possibleDir = path.substring(path.indexOf(':') + 1, path.length()); + possibleDir = possibleDir.substring(0, possibleDir.lastIndexOf('/')); + + + dirlist.add(new File(sdcard, possibleDir)); + + } + dirlist.add(new File(path)); + + + } + dirlist.add(sdcard); + dirlist.add(root); + + + String[] fileparts = filename.split("/"); + for (File rootdir : dirlist) { + String suffix = ""; + for (int i = fileparts.length - 1; i >= 0; i--) { + if (i == fileparts.length - 1) + suffix = fileparts[i]; + else + suffix = fileparts[i] + "/" + suffix; + File possibleFile = new File(rootdir, suffix); + if (!possibleFile.canRead()) + continue; - dirlist.add(new File(sdcard,possibleDir)); + // read the file inline + return possibleFile; } - dirlist.add(new File(path)); - - - } - dirlist.add(sdcard); - dirlist.add(root); - - - String[] fileparts = filename.split("/"); - for(File rootdir:dirlist){ - String suffix=""; - for(int i=fileparts.length-1; i >=0;i--) { - if(i==fileparts.length-1) - suffix = fileparts[i]; - else - suffix = fileparts[i] + "/" + suffix; - - File possibleFile = new File(rootdir,suffix); - if(!possibleFile.canRead()) - continue; - - // read the file inline - return possibleFile; - - } - } - return null; - } - - String readFileContent(File possibleFile, boolean base64encode) { - byte [] filedata; - try { - filedata = readBytesFromFile(possibleFile); - } catch (IOException e) { - log(e.getLocalizedMessage()); - return null; - } - - String data; - if(base64encode) { - data = Base64.encodeToString(filedata, Base64.DEFAULT); - } else { - data = new String(filedata); - - } - return VpnProfile.INLINE_TAG + data; - - } - - - private byte[] readBytesFromFile(File file) throws IOException { - InputStream input = new FileInputStream(file); - - long len= file.length(); + } + return null; + } + + String readFileContent(File possibleFile, boolean base64encode) { + byte[] filedata; + try { + filedata = readBytesFromFile(possibleFile); + } catch (IOException e) { + log(e.getLocalizedMessage()); + return null; + } + + String data; + if (base64encode) { + data = Base64.encodeToString(filedata, Base64.DEFAULT); + } else { + data = new String(filedata); + + } + + return VpnProfile.DISPLAYNAME_TAG + possibleFile.getName() + VpnProfile.INLINE_TAG + data; + + } + + + private byte[] readBytesFromFile(File file) throws IOException { + InputStream input = new FileInputStream(file); + + long len = file.length(); if (len > VpnProfile.MAX_EMBED_FILE_SIZE) throw new IOException("File size of file to import too large."); - // Create the byte array to hold the data - byte[] bytes = new byte[(int) len]; - - // Read in the bytes - int offset = 0; - int bytesRead = 0; - while (offset < bytes.length - && (bytesRead=input.read(bytes, offset, bytes.length-offset)) >= 0) { - offset += bytesRead; - } - - input.close(); - return bytes; - } - - void embedFiles() { - // This where I would like to have a c++ style - // void embedFile(std::string & option) - - if (mResult.mPKCS12Filename!=null) { - File pkcs12file = findFileRaw(mResult.mPKCS12Filename); - if(pkcs12file!=null) { - mAliasName = pkcs12file.getName().replace(".p12", ""); - } else { - mAliasName = "Imported PKCS12"; - } - } - - - mResult.mCaFilename = embedFile(mResult.mCaFilename, Utils.FileType.CA_CERTIFICATE); - mResult.mClientCertFilename = embedFile(mResult.mClientCertFilename, Utils.FileType.CLIENT_CERTIFICATE); - mResult.mClientKeyFilename = embedFile(mResult.mClientKeyFilename, Utils.FileType.KEYFILE); - mResult.mTLSAuthFilename = embedFile(mResult.mTLSAuthFilename, Utils.FileType.TLS_AUTH_FILE); - mResult.mPKCS12Filename = embedFile(mResult.mPKCS12Filename, Utils.FileType.PKCS12); - - - if(mResult.mUsername == null && mResult.mPassword != null ){ - String data =embedFile(mResult.mPassword, Utils.FileType.USERPW_FILE); - ConfigParser.useEmbbedUserAuth(mResult, data); + // Create the byte array to hold the data + byte[] bytes = new byte[(int) len]; + + // Read in the bytes + int offset = 0; + int bytesRead = 0; + while (offset < bytes.length + && (bytesRead = input.read(bytes, offset, bytes.length - offset)) >= 0) { + offset += bytesRead; + } + + input.close(); + return bytes; + } + + void embedFiles() { + // This where I would like to have a c++ style + // void embedFile(std::string & option) + + if (mResult.mPKCS12Filename != null) { + File pkcs12file = findFileRaw(mResult.mPKCS12Filename); + if (pkcs12file != null) { + mAliasName = pkcs12file.getName().replace(".p12", ""); + } else { + mAliasName = "Imported PKCS12"; + } } - } + + + mResult.mCaFilename = embedFile(mResult.mCaFilename, Utils.FileType.CA_CERTIFICATE); + mResult.mClientCertFilename = embedFile(mResult.mClientCertFilename, Utils.FileType.CLIENT_CERTIFICATE); + mResult.mClientKeyFilename = embedFile(mResult.mClientKeyFilename, Utils.FileType.KEYFILE); + mResult.mTLSAuthFilename = embedFile(mResult.mTLSAuthFilename, Utils.FileType.TLS_AUTH_FILE); + mResult.mPKCS12Filename = embedFile(mResult.mPKCS12Filename, Utils.FileType.PKCS12); + mEmbeddedPwFile = embedFile(mResult.mPassword, Utils.FileType.USERPW_FILE); + } @Override protected void onCreate(Bundle savedInstanceState) { @@ -477,11 +474,12 @@ public class ConfigConverter extends ListActivity implements FileSelectCallback super.onCreate(savedInstanceState); - if (savedInstanceState !=null && savedInstanceState.containsKey(VPNPROFILE)) { + if (savedInstanceState != null && savedInstanceState.containsKey(VPNPROFILE)) { mResult = (VpnProfile) savedInstanceState.getSerializable(VPNPROFILE); mAliasName = savedInstanceState.getString("mAliasName"); + mEmbeddedPwFile = savedInstanceState.getString("pwfile"); mArrayAdapter.addAll(savedInstanceState.getStringArray("logentries")); - for (int k: savedInstanceState.getIntArray("fileselects")) { + for (int k : savedInstanceState.getIntArray("fileselects")) { addFileSelectDialog(Utils.FileType.getFileTypeByValue(k)); } @@ -489,34 +487,52 @@ public class ConfigConverter extends ListActivity implements FileSelectCallback } + final android.content.Intent intent = getIntent(); - final android.content.Intent intent = getIntent (); - - if (intent != null ) - { - final android.net.Uri data = intent.getData (); - if (data != null) - { + if (intent != null) { + final android.net.Uri data = intent.getData(); + if (data != null) { //log(R.string.import_experimental); - log(R.string.importing_config,data.toString()); + log(R.string.importing_config, data.toString()); try { String possibleName = null; - if(data.getScheme().equals("file") || + if (data.getScheme().equals("file") || data.getLastPathSegment().endsWith(".ovpn") || - data.getLastPathSegment().endsWith(".conf")) - { + data.getLastPathSegment().endsWith(".conf")) { possibleName = data.getLastPathSegment(); - if (possibleName.lastIndexOf('/')!=-1) - possibleName = possibleName.substring(possibleName.lastIndexOf('/')+1); + if (possibleName.lastIndexOf('/') != -1) + possibleName = possibleName.substring(possibleName.lastIndexOf('/') + 1); - if(possibleName!=null){ - possibleName =possibleName.replace(".ovpn", ""); - possibleName =possibleName.replace(".conf", ""); - } } InputStream is = getContentResolver().openInputStream(data); mPathsegments = data.getPathSegments(); + + Cursor cursor = getContentResolver().query(data, null, null, null, null); + try { + + + if (cursor.moveToFirst()) { + int cidx = cursor.getColumnIndex(OpenableColumns.DISPLAY_NAME); + + if (cidx != -1) { + String displayName = cursor.getString(cidx); + if (displayName != null) + possibleName = displayName; + } + cidx = cursor.getColumnIndex("mime_type"); + if (cidx != -1) { + log("Opening Mime TYPE: " + cursor.getString(cidx)); + } + } + } finally { + cursor.close(); + } + if (possibleName != null) { + possibleName = possibleName.replace(".ovpn", ""); + possibleName = possibleName.replace(".conf", ""); + } + doImport(is, possibleName); } catch (FileNotFoundException e) { @@ -532,66 +548,65 @@ public class ConfigConverter extends ListActivity implements FileSelectCallback } - @Override - protected void onStart() { - super.onStart(); - + @Override + protected void onStart() { + super.onStart(); - } + } - private void log(String logmessage) { - mArrayAdapter.add(logmessage); - } + private void log(String logmessage) { + mArrayAdapter.add(logmessage); + } - private void doImport(InputStream is, String newName) { - ConfigParser cp = new ConfigParser(); - try { - InputStreamReader isr = new InputStreamReader(is); + private void doImport(InputStream is, String newName) { + ConfigParser cp = new ConfigParser(); + try { + InputStreamReader isr = new InputStreamReader(is); - cp.parseConfig(isr); - VpnProfile vp = cp.convertProfile(); - mResult = vp; - embedFiles(); - displayWarnings(); + cp.parseConfig(isr); + VpnProfile vp = cp.convertProfile(); + mResult = vp; + embedFiles(); + displayWarnings(); mResult.mName = getUniqueProfileName(newName); log(R.string.import_done); - return; - - } catch (IOException e) { - log(R.string.error_reading_config_file); - log(e.getLocalizedMessage()); - } catch (ConfigParseError e) { - log(R.string.error_reading_config_file); - log(e.getLocalizedMessage()); - } - mResult=null; - - } - - private void displayWarnings() { - if(mResult.mUseCustomConfig) { - log(R.string.import_warning_custom_options); - String copt = mResult.mCustomConfigOptions; - if(copt.startsWith("#")) { - int until = copt.indexOf('\n'); - copt = copt.substring(until+1); - } - - log(copt); - } - - if(mResult.mAuthenticationType==VpnProfile.TYPE_KEYSTORE || - mResult.mAuthenticationType == VpnProfile.TYPE_USERPASS_KEYSTORE) { - findViewById(R.id.importpkcs12).setVisibility(View.VISIBLE); - } - - } - - private void log(int ressourceId, Object... formatArgs) { - log(getString(ressourceId,formatArgs)); - } + return; + + } catch (IOException e) { + log(R.string.error_reading_config_file); + log(e.getLocalizedMessage()); + } catch (ConfigParseError e) { + log(R.string.error_reading_config_file); + log(e.getLocalizedMessage()); + } + mResult = null; + + } + + private void displayWarnings() { + if (mResult.mUseCustomConfig) { + log(R.string.import_warning_custom_options); + String copt = mResult.mCustomConfigOptions; + if (copt.startsWith("#")) { + int until = copt.indexOf('\n'); + copt = copt.substring(until + 1); + } + + log(copt); + } + + if (mResult.mAuthenticationType == VpnProfile.TYPE_KEYSTORE || + mResult.mAuthenticationType == VpnProfile.TYPE_USERPASS_KEYSTORE) { + findViewById(R.id.importpkcs12).setVisibility(View.VISIBLE); + } + + } + + private void log(int ressourceId, Object... formatArgs) { + log(getString(ressourceId, formatArgs)); + } } diff --git a/src/de/blinkt/openvpn/activities/FileSelect.java b/src/de/blinkt/openvpn/activities/FileSelect.java index 50584063..8967b1bf 100644 --- a/src/de/blinkt/openvpn/activities/FileSelect.java +++ b/src/de/blinkt/openvpn/activities/FileSelect.java @@ -185,15 +185,15 @@ public class FileSelect extends Activity { } public String getSelectPath() { - if(!mData.startsWith(VpnProfile.INLINE_TAG)) + if(VpnProfile.isEmbedded(mData)) return mData; else return Environment.getExternalStorageDirectory().getPath(); } public CharSequence getInlineData() { - if(mData.startsWith(VpnProfile.INLINE_TAG)) - return mData.substring(VpnProfile.INLINE_TAG.length()); + if(VpnProfile.isEmbedded(mData)) + return VpnProfile.getEmbeddedContent(mData); else return ""; } diff --git a/src/de/blinkt/openvpn/core/ConfigParser.java b/src/de/blinkt/openvpn/core/ConfigParser.java index 06acdf98..22cc5dce 100644 --- a/src/de/blinkt/openvpn/core/ConfigParser.java +++ b/src/de/blinkt/openvpn/core/ConfigParser.java @@ -398,10 +398,18 @@ public class ConfigParser { if(direction!=null) np.mTLSAuthDirection=direction.get(1); + Vector> defgw = getAllOption("redirect-gateway", 0, 5); + if(defgw != null) + { + np.mUseDefaultRoute=true; + checkRedirectParameters(np, defgw); + } - if(getAllOption("redirect-gateway", 0, 5) != null) - np.mUseDefaultRoute=true; - + Vector> redirectPrivate = getAllOption("redirect-private",0,5); + if (redirectPrivate != null) + { + checkRedirectParameters(np,redirectPrivate); + } Vector dev =getOption("dev",1,1); Vector devtype =getOption("dev-type",1,1); @@ -621,7 +629,17 @@ public class ConfigParser { return np; } - public void useExtraRemotesAsCustom(boolean b) { + private void checkRedirectParameters(VpnProfile np, Vector> defgw) { + for (Vector redirect: defgw) + for (int i=1;i= 2) { np.mUsername=parts[0]; diff --git a/src/de/blinkt/openvpn/core/X509Utils.java b/src/de/blinkt/openvpn/core/X509Utils.java index 5781cbf5..da1e4ed5 100644 --- a/src/de/blinkt/openvpn/core/X509Utils.java +++ b/src/de/blinkt/openvpn/core/X509Utils.java @@ -25,7 +25,7 @@ public class X509Utils { InputStream inStream; - if(certfilename.startsWith(VpnProfile.INLINE_TAG)) { + if(VpnProfile.isEmbedded(certfilename)) { // The java certifcate reader is ... kind of stupid // It does NOT ignore chars before the --BEGIN ... int subIndex = certfilename.indexOf("-----BEGIN CERTIFICATE-----"); @@ -45,8 +45,8 @@ public class X509Utils { Reader inStream; - if(keyfilename.startsWith(VpnProfile.INLINE_TAG)) - inStream = new StringReader(keyfilename.replace(VpnProfile.INLINE_TAG,"")); + if(VpnProfile.isEmbedded(keyfilename)) + inStream = new StringReader(VpnProfile.getEmbeddedContent(keyfilename)); else inStream = new FileReader(new File(keyfilename)); diff --git a/src/de/blinkt/openvpn/fragments/Settings_Authentication.java b/src/de/blinkt/openvpn/fragments/Settings_Authentication.java index b153ce4d..236d7947 100644 --- a/src/de/blinkt/openvpn/fragments/Settings_Authentication.java +++ b/src/de/blinkt/openvpn/fragments/Settings_Authentication.java @@ -191,7 +191,7 @@ public class Settings_Authentication extends OpenVpnPreferencesFragment implemen setTlsAuthSummary(result); } else if (requestCode == SELECT_TLS_FILE_KITKAT && resultCode == Activity.RESULT_OK) { try { - mTlsAuthFileData= VpnProfile.INLINE_TAG + Utils.getStringFromFilePickerResult(Utils.FileType.TLS_AUTH_FILE,data,getActivity()); + mTlsAuthFileData= Utils.getFilePickerResult(Utils.FileType.TLS_AUTH_FILE,data,getActivity()); setTlsAuthSummary(mTlsAuthFileData); } catch (IOException e) { VpnStatus.logException(e); @@ -200,9 +200,12 @@ public class Settings_Authentication extends OpenVpnPreferencesFragment implemen } private void setTlsAuthSummary(String result) { - if(result==null) result = getString(R.string.no_certificate); + if(result==null) + result = getString(R.string.no_certificate); if(result.startsWith(VpnProfile.INLINE_TAG)) mTLSAuthFile.setSummary(R.string.inline_file_data); + else if (result.startsWith(VpnProfile.DISPLAYNAME_TAG)) + mExpectTLSCert.setSummary(getString(R.string.imported_from_file, VpnProfile.getDisplayName(result))); else mTLSAuthFile.setSummary(result); } diff --git a/src/de/blinkt/openvpn/fragments/Utils.java b/src/de/blinkt/openvpn/fragments/Utils.java index f13b1987..6f06f35a 100644 --- a/src/de/blinkt/openvpn/fragments/Utils.java +++ b/src/de/blinkt/openvpn/fragments/Utils.java @@ -3,10 +3,14 @@ package de.blinkt.openvpn.fragments; import android.annotation.TargetApi; import android.content.Context; import android.content.Intent; +import android.database.Cursor; import android.net.Uri; import android.os.Build; +import android.provider.OpenableColumns; import android.util.Base64; +import android.util.Log; import android.webkit.MimeTypeMap; +import de.blinkt.openvpn.VpnProfile; import junit.framework.Assert; import java.io.*; @@ -44,6 +48,21 @@ public class Utils { i.setType("application/x-pem-file"); supportedMimeTypes.add("application/x-pem-file"); supportedMimeTypes.add("application/pkcs8"); + + // Google drive .... + supportedMimeTypes.add("application/x-iwork-keynote-sffkey"); + extensions.add("key"); + break; + + case TLS_AUTH_FILE: + i.setType("text/plain"); + + // Backup .... + supportedMimeTypes.add("application/pkcs8"); + // Google Drive is kind of crazy ..... + supportedMimeTypes.add("application/x-iwork-keynote-sffkey"); + + extensions.add("txt"); extensions.add("key"); break; @@ -52,19 +71,14 @@ public class Utils { supportedMimeTypes.add("application/x-openvpn-profile"); supportedMimeTypes.add("application/openvpn-profile"); supportedMimeTypes.add("application/ovpn"); + supportedMimeTypes.add("text/plain"); extensions.add("ovpn"); extensions.add("conf"); break; - case TLS_AUTH_FILE: - i.setType("text/plain"); - // Backup .... - supportedMimeTypes.add("application/pkcs8"); - extensions.add("txt"); - extensions.add("key"); - break; case USERPW_FILE: - Assert.fail(); + i.setType("text/plain"); + supportedMimeTypes.add("text/plain"); break; } @@ -74,10 +88,11 @@ public class Utils { String mimeType = mtm.getMimeTypeFromExtension(ext); if (mimeType != null) supportedMimeTypes.add(mimeType); - else - supportedMimeTypes.add("application/octet-stream"); } + // Always add this as fallback + supportedMimeTypes.add("application/octet-stream"); + i.putExtra(Intent.EXTRA_MIME_TYPES, supportedMimeTypes.toArray(new String[supportedMimeTypes.size()])); return i; } @@ -94,12 +109,11 @@ public class Utils { private int value; FileType(int i) { - value=i; + value = i; } - public static FileType getFileTypeByValue(int value) - { - switch(value) { + public static FileType getFileTypeByValue(int value) { + switch (value) { case 0: return PKCS12; case 1: @@ -140,14 +154,32 @@ public class Utils { return buffer.toByteArray(); } - public static String getStringFromFilePickerResult(FileType ft, Intent result, Context c) throws IOException { + public static String getFilePickerResult(FileType ft, Intent result, Context c) throws IOException { Uri uri = result.getData(); - if (uri ==null) + if (uri == null) return null; byte[] fileData = readBytesFromStream(c.getContentResolver().openInputStream(uri)); String newData = null; + + Cursor cursor = c.getContentResolver().query(uri, null, null, null, null); + + String prefix = ""; + try { + if (cursor.moveToFirst()) { + int cidx = cursor.getColumnIndex(OpenableColumns.DISPLAY_NAME); + if (cidx != -1) { + String displayName = cursor.getString(cidx); + + if (!displayName.contains(VpnProfile.INLINE_TAG) && !displayName.contains(VpnProfile.DISPLAYNAME_TAG)) + prefix = VpnProfile.DISPLAYNAME_TAG + displayName; + } + } + } finally { + cursor.close(); + } + switch (ft) { case PKCS12: newData = Base64.encodeToString(fileData, Base64.DEFAULT); @@ -156,6 +188,7 @@ public class Utils { newData = new String(fileData, "UTF-8"); break; } - return newData; + + return prefix + VpnProfile.INLINE_TAG + newData; } } diff --git a/src/de/blinkt/openvpn/views/FileSelectLayout.java b/src/de/blinkt/openvpn/views/FileSelectLayout.java index 04392b47..362777e4 100644 --- a/src/de/blinkt/openvpn/views/FileSelectLayout.java +++ b/src/de/blinkt/openvpn/views/FileSelectLayout.java @@ -29,9 +29,9 @@ public class FileSelectLayout extends LinearLayout implements OnClickListener { setData(fileData, c); } else if (data != null) { try { - String newData = Utils.getStringFromFilePickerResult(fileType,data,c); + String newData = Utils.getFilePickerResult(fileType, data, c); if (newData!=null) - setData(VpnProfile.INLINE_TAG + newData, c); + setData(newData, c); } catch (IOException e) { VpnStatus.logException(e); @@ -119,10 +119,12 @@ public class FileSelectLayout extends LinearLayout implements OnClickListener { public void setData(String data, Context c) { mData = data; if (data == null) { - mDataView.setText(mFragment.getString(R.string.no_data)); + mDataView.setText(c.getString(R.string.no_data)); mDataDetails.setText(""); } else { - if (mData.startsWith(VpnProfile.INLINE_TAG)) + if (mData.startsWith(VpnProfile.DISPLAYNAME_TAG)) { + mDataView.setText(c.getString(R.string.imported_from_file, VpnProfile.getDisplayName(mData))); + } else if (mData.startsWith(VpnProfile.INLINE_TAG)) mDataView.setText(R.string.inline_file_data); else mDataView.setText(data); -- cgit v1.2.3