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 --- 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 +- 8 files changed, 502 insertions(+), 405 deletions(-) (limited to 'src/de') 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