summaryrefslogtreecommitdiff
path: root/src/se/leap/openvpn/ConfigConverter.java
diff options
context:
space:
mode:
authorSean Leonard <meanderingcode@aetherislands.net>2013-01-22 22:26:08 -0700
committerSean Leonard <meanderingcode@aetherislands.net>2013-01-22 22:26:08 -0700
commit2bb6e8c9a956c56658807c7f2d25ab850243bbe6 (patch)
tree9e3a2e318d0503b33d94514836b8a9bc2db8aaa6 /src/se/leap/openvpn/ConfigConverter.java
parent613543d9c00e607f25e7f745a60fb4e3ec3b5148 (diff)
Start rebranding: a whole lotta string replacement, moving src/ file tree
Diffstat (limited to 'src/se/leap/openvpn/ConfigConverter.java')
-rw-r--r--src/se/leap/openvpn/ConfigConverter.java453
1 files changed, 453 insertions, 0 deletions
diff --git a/src/se/leap/openvpn/ConfigConverter.java b/src/se/leap/openvpn/ConfigConverter.java
new file mode 100644
index 00000000..8b5f316d
--- /dev/null
+++ b/src/se/leap/openvpn/ConfigConverter.java
@@ -0,0 +1,453 @@
+
+package se.leap.openvpn;
+
+import java.io.File;
+import java.io.FileInputStream;
+import java.io.FileNotFoundException;
+import java.io.IOException;
+import java.io.InputStream;
+import java.io.InputStreamReader;
+import java.util.List;
+import java.util.Vector;
+import se.leap.leapclient.R;
+
+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.os.Bundle;
+import android.os.Environment;
+import android.security.KeyChain;
+import android.security.KeyChainAliasCallback;
+import android.util.Base64;
+import android.view.Menu;
+import android.view.MenuInflater;
+import android.view.MenuItem;
+import android.view.View;
+import android.widget.ArrayAdapter;
+import android.widget.CheckBox;
+import se.leap.openvpn.ConfigParser.ConfigParseError;
+
+public class ConfigConverter extends ListActivity {
+
+ public static final String IMPORT_PROFILE = "se.leap.openvpn.IMPORT_PROFILE";
+
+ private VpnProfile mResult;
+ private ArrayAdapter<String> mArrayAdapter;
+
+ private List<String> mPathsegments;
+
+ private String mAliasName=null;
+
+ private int RESULT_INSTALLPKCS12 = 7;
+
+ private String mPossibleName=null;
+
+ @Override
+ protected void onCreate(Bundle savedInstanceState) {
+ super.onCreate(savedInstanceState);
+ setContentView(R.layout.config_converter);
+ }
+
+
+
+ @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();
+
+ if(in != null)
+ startActivityForResult(in, RESULT_INSTALLPKCS12);
+ else
+ saveProfile();
+
+ return true;
+ }
+
+ return super.onOptionsItemSelected(item);
+
+ }
+
+ @Override
+ protected void onActivityResult(int requestCode, int resultCode, Intent data) {
+ if(requestCode==RESULT_INSTALLPKCS12) {
+ if(resultCode==Activity.RESULT_OK) {
+ showCertDialog();
+ }
+ }
+
+ super.onActivityResult(requestCode, resultCode, data);
+ }
+
+ private void saveProfile() {
+ Intent result = new Intent();
+ ProfileManager vpl = ProfileManager.getInstance(this);
+
+ if(((CheckBox)findViewById(R.id.correcttls)).isChecked() && isOldCNFormat()) {
+ convertTLSRemote();
+ }
+
+ setUniqueProfileName(vpl);
+ vpl.addProfile(mResult);
+ vpl.saveProfile(this, mResult);
+ vpl.saveProfileList(this);
+ result.putExtra(VpnProfile.EXTRA_PROFILEUUID,mResult.getUUID().toString());
+ setResult(Activity.RESULT_OK, result);
+ finish();
+ }
+
+
+
+ private void convertTLSRemote() {
+ if(mResult.mRemoteCN.startsWith("/"))
+ mResult.mRemoteCN = mResult.mRemoteCN.substring(1);
+ mResult.mRemoteCN = mResult.mRemoteCN.replace("/", ", ");
+ }
+
+ 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();
+ }
+
+
+ },
+ 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);
+
+
+ inkeyintent.putExtra(KeyChain.EXTRA_PKCS12,pkcs12data );
+
+ if(mAliasName.equals(""))
+ mAliasName=null;
+
+ if(mAliasName!=null){
+ inkeyintent.putExtra(KeyChain.EXTRA_NAME, mAliasName);
+ }
+ return inkeyintent;
+
+ }
+ return null;
+ }
+
+
+
+ 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;
+
+ }
+ }
+
+
+
+
+
+ private void setUniqueProfileName(ProfileManager vpl) {
+ int i=0;
+
+ String newname = mPossibleName;
+
+ while(vpl.getProfileByName(newname)!=null) {
+ i++;
+ if(i==1)
+ newname = getString(R.string.converted_profile);
+ else
+ newname = getString(R.string.converted_profile_i,i);
+ }
+
+ mResult.mName=newname;
+ }
+
+ @Override
+ public boolean onCreateOptionsMenu(Menu menu) {
+ MenuInflater inflater = getMenuInflater();
+ inflater.inflate(R.menu.import_menu, menu);
+ return true;
+ }
+
+ private String embedFile(String filename) {
+ return embedFile(filename, false);
+ }
+
+ private String embedFile(String filename, boolean base64encode)
+ {
+ if(filename==null)
+ return null;
+
+ // Already embedded, nothing to do
+ if(filename.startsWith(VpnProfile.INLINE_TAG))
+ return filename;
+
+ File possibleFile = findFile(filename);
+ if(possibleFile==null)
+ return filename;
+ else
+ return readFileContent(possibleFile,base64encode);
+
+ }
+
+ private File findFile(String filename) {
+ File foundfile =findFileRaw(filename);
+
+ if (foundfile==null && filename!=null && !filename.equals(""))
+ log(R.string.import_could_not_open,filename);
+
+ return foundfile;
+ }
+
+
+
+ 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("/");
+
+ Vector<File> dirlist = new Vector<File>();
+
+ for(int i=mPathsegments.size()-1;i >=0 ;i--){
+ String path = "";
+ for (int j = 0;j<=i;j++) {
+ path += "/" + mPathsegments.get(j);
+ }
+ 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();
+
+
+ // 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);
+ mResult.mClientCertFilename = embedFile(mResult.mClientCertFilename);
+ mResult.mClientKeyFilename = embedFile(mResult.mClientKeyFilename);
+ mResult.mTLSAuthFilename = embedFile(mResult.mTLSAuthFilename);
+ mResult.mPKCS12Filename = embedFile(mResult.mPKCS12Filename,true);
+
+
+ if(mResult.mUsername == null && mResult.mPassword != null ){
+ String data =embedFile(mResult.mPassword);
+ ConfigParser.useEmbbedUserAuth(mResult, data);
+ }
+ }
+
+
+ @Override
+ protected void onStart() {
+ super.onStart();
+
+ mArrayAdapter = new ArrayAdapter<String>(this, android.R.layout.simple_list_item_1);
+ getListView().setAdapter(mArrayAdapter);
+ final android.content.Intent intent = getIntent ();
+
+ 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());
+ try {
+ if(data.getScheme().equals("file")) {
+ mPossibleName = data.getLastPathSegment();
+ if(mPossibleName!=null){
+ mPossibleName =mPossibleName.replace(".ovpn", "");
+ mPossibleName =mPossibleName.replace(".conf", "");
+ }
+ }
+ InputStream is = getContentResolver().openInputStream(data);
+ mPathsegments = data.getPathSegments();
+
+ doImport(is);
+ } catch (FileNotFoundException e) {
+ log(R.string.import_content_resolve_error);
+ }
+ }
+ }
+
+ return;
+ }
+
+ private void log(String logmessage) {
+ mArrayAdapter.add(logmessage);
+ }
+
+ private void doImport(InputStream is) {
+ ConfigParser cp = new ConfigParser();
+ try {
+ InputStreamReader isr = new InputStreamReader(is);
+
+ cp.parseConfig(isr);
+ VpnProfile vp = cp.convertProfile();
+ mResult = vp;
+ embedFiles();
+ displayWarnings();
+ 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);
+ }
+
+ if (isOldCNFormat())
+ findViewById(R.id.correcttls).setVisibility(View.VISIBLE);
+ }
+
+ private boolean isOldCNFormat() {
+ return mResult.mCheckRemoteCN && mResult.mRemoteCN.contains("/") && ! mResult.mRemoteCN.contains("_");
+ }
+
+ private void log(int ressourceId, Object... formatArgs) {
+ log(getString(ressourceId,formatArgs));
+ }
+}