diff options
Diffstat (limited to 'app/src/main/java/se/leap/bitmaskclient')
15 files changed, 792 insertions, 686 deletions
diff --git a/app/src/main/java/se/leap/bitmaskclient/ConfigHelper.java b/app/src/main/java/se/leap/bitmaskclient/ConfigHelper.java index a8bd3b7a..c95d0c8b 100644 --- a/app/src/main/java/se/leap/bitmaskclient/ConfigHelper.java +++ b/app/src/main/java/se/leap/bitmaskclient/ConfigHelper.java @@ -18,8 +18,9 @@ package se.leap.bitmaskclient; import java.io.ByteArrayInputStream; import java.io.IOException; -import java.math.BigInteger; import java.io.InputStream; +import java.math.BigInteger; +import java.lang.IllegalArgumentException; import java.security.KeyFactory; import java.security.KeyStore; import java.security.KeyStoreException; @@ -105,6 +106,8 @@ public class ConfigHelper { e.printStackTrace(); } catch (IOException e) { return null; + } catch (IllegalArgumentException e) { + return null; } return (X509Certificate) certificate; diff --git a/app/src/main/java/se/leap/bitmaskclient/Dashboard.java b/app/src/main/java/se/leap/bitmaskclient/Dashboard.java index 761afc0a..364a79af 100644 --- a/app/src/main/java/se/leap/bitmaskclient/Dashboard.java +++ b/app/src/main/java/se/leap/bitmaskclient/Dashboard.java @@ -21,13 +21,14 @@ import org.json.JSONObject; import se.leap.bitmaskclient.R; import se.leap.bitmaskclient.ProviderAPIResultReceiver.Receiver; +import se.leap.bitmaskclient.FragmentManagerEnhanced; import se.leap.bitmaskclient.SignUpDialog; + import de.blinkt.openvpn.activities.LogWindow; + import android.app.Activity; import android.app.AlertDialog; import android.app.DialogFragment; -import android.app.Fragment; -import android.app.FragmentManager; import android.app.FragmentTransaction; import android.content.Context; import android.content.DialogInterface; @@ -65,6 +66,7 @@ public class Dashboard extends Activity implements LogInDialog.LogInDialogInterf public static final String START_ON_BOOT = "dashboard start on boot"; final public static String ON_BOOT = "dashboard on boot"; public static final String APP_VERSION = "bitmask version"; + final public static String TAG = Dashboard.class.getSimpleName(); private EipServiceFragment eipFragment; @@ -74,11 +76,10 @@ public class Dashboard extends Activity implements LogInDialog.LogInDialogInterf protected static SharedPreferences preferences; private static Provider provider; - private TextView providerNameTV; - private boolean authed_eip = false; public ProviderAPIResultReceiver providerAPI_result_receiver; + private FragmentManagerEnhanced fragment_manager; @Override protected void onCreate(Bundle savedInstanceState) { @@ -91,6 +92,7 @@ public class Dashboard extends Activity implements LogInDialog.LogInDialogInterf mProgressBar = (ProgressBar) findViewById(R.id.eipProgress); preferences = getSharedPreferences(SHARED_PREFERENCES, MODE_PRIVATE); + fragment_manager = new FragmentManagerEnhanced(getFragmentManager()); handleVersion(); authed_eip = preferences.getBoolean(EIP.AUTHED_EIP, false); @@ -110,11 +112,13 @@ public class Dashboard extends Activity implements LogInDialog.LogInDialogInterf switch(versionCode) { case 91: // 0.6.0 without Bug #5999 + case 101: // 0.8.0 if(!preferences.getString(EIP.KEY, "").isEmpty()) { Intent rebuildVpnProfiles = new Intent(getApplicationContext(), EIP.class); rebuildVpnProfiles.setAction(EIP.ACTION_REBUILD_PROFILES); startService(rebuildVpnProfiles); } + break; } } catch (NameNotFoundException e) { } @@ -131,21 +135,23 @@ public class Dashboard extends Activity implements LogInDialog.LogInDialogInterf } @Override - protected void onActivityResult(int requestCode, int resultCode, Intent data){ + protected void onActivityResult(int requestCode, int resultCode, final Intent data){ if ( requestCode == CONFIGURE_LEAP || requestCode == SWITCH_PROVIDER) { // It should be equivalent: if ( (requestCode == CONFIGURE_LEAP) || (data!= null && data.hasExtra(STOP_FIRST))) { - if ( resultCode == RESULT_OK ){ - preferences.edit().putInt(EIP.PARSED_SERIAL, 0).commit(); - preferences.edit().putBoolean(EIP.AUTHED_EIP, authed_eip).commit(); - Intent updateEIP = new Intent(getApplicationContext(), EIP.class); - updateEIP.setAction(EIP.ACTION_UPDATE_EIP_SERVICE); - startService(updateEIP); - buildDashboard(false); - invalidateOptionsMenu(); - if(data != null && data.hasExtra(LogInDialog.VERB)) { - View view = ((ViewGroup)findViewById(android.R.id.content)).getChildAt(0); - logInDialog(Bundle.EMPTY); - } + if ( resultCode == RESULT_OK ){ + preferences.edit().putInt(EIP.PARSED_SERIAL, 0).commit(); + preferences.edit().putBoolean(EIP.AUTHED_EIP, authed_eip).commit(); + + Intent updateEIP = new Intent(getApplicationContext(), EIP.class); + updateEIP.setAction(EIP.ACTION_UPDATE_EIP_SERVICE); + startService(updateEIP); + + buildDashboard(false); + invalidateOptionsMenu(); + if(data != null && data.hasExtra(LogInDialog.TAG)) { + View view = ((ViewGroup)findViewById(android.R.id.content)).getChildAt(0); + logInDialog(Bundle.EMPTY); + } } else if(resultCode == RESULT_CANCELED && (data == null || data.hasExtra(ACTION_QUIT))) { finish(); } else @@ -189,13 +195,12 @@ public class Dashboard extends Activity implements LogInDialog.LogInDialogInterf setContentView(R.layout.client_dashboard); - providerNameTV = (TextView) findViewById(R.id.providerName); + TextView providerNameTV = (TextView) findViewById(R.id.providerName); providerNameTV.setText(provider.getDomain()); providerNameTV.setTextSize(28); mProgressBar = (ProgressBar) findViewById(R.id.eipProgress); - FragmentManager fragMan = getFragmentManager(); if ( provider.hasEIP()){ eipFragment = new EipServiceFragment(); if (hide_and_turn_on_eip) { @@ -204,7 +209,7 @@ public class Dashboard extends Activity implements LogInDialog.LogInDialogInterf arguments.putBoolean(EipServiceFragment.START_ON_BOOT, true); eipFragment.setArguments(arguments); } - fragMan.beginTransaction().replace(R.id.servicesCollection, eipFragment, EipServiceFragment.TAG).commit(); + fragment_manager.replace(R.id.servicesCollection, eipFragment, EipServiceFragment.TAG); if (hide_and_turn_on_eip) { onBackPressed(); @@ -212,31 +217,35 @@ public class Dashboard extends Activity implements LogInDialog.LogInDialogInterf } } - @Override - public boolean onPrepareOptionsMenu(Menu menu) { - JSONObject provider_json; - try { - provider_json = new JSONObject(preferences.getString(Provider.KEY, "")); - JSONObject service_description = provider_json.getJSONObject(Provider.SERVICE); - boolean authed_eip = preferences.getBoolean(EIP.AUTHED_EIP, false); - boolean allow_registered_eip = service_description.getBoolean(Provider.ALLOW_REGISTRATION); - preferences.edit().putBoolean(EIP.ALLOWED_REGISTERED, allow_registered_eip); - if(allow_registered_eip) { - if(authed_eip) { - menu.findItem(R.id.login_button).setVisible(false); - menu.findItem(R.id.logout_button).setVisible(true); - } else { - menu.findItem(R.id.login_button).setVisible(true); - menu.findItem(R.id.logout_button).setVisible(false); - } - menu.findItem(R.id.signup_button).setVisible(true); - } - } catch (JSONException e) { - // TODO Auto-generated catch block - e.printStackTrace(); - } - return true; + @Override + public boolean onPrepareOptionsMenu(Menu menu) { + JSONObject provider_json; + try { + String provider_json_string = preferences.getString(Provider.KEY, ""); + if(provider_json_string.isEmpty() == false) { + provider_json = new JSONObject(provider_json_string); + JSONObject service_description = provider_json.getJSONObject(Provider.SERVICE); + boolean authed_eip = !LeapSRPSession.getToken().isEmpty(); + boolean allow_registered_eip = service_description.getBoolean(Provider.ALLOW_REGISTRATION); + preferences.edit().putBoolean(EIP.ALLOWED_REGISTERED, allow_registered_eip); + + if(allow_registered_eip) { + if(authed_eip) { + menu.findItem(R.id.login_button).setVisible(false); + menu.findItem(R.id.logout_button).setVisible(true); + } else { + menu.findItem(R.id.login_button).setVisible(true); + menu.findItem(R.id.logout_button).setVisible(false); + } + menu.findItem(R.id.signup_button).setVisible(true); + } + } + } catch (JSONException e) { + // TODO Auto-generated catch block + e.printStackTrace(); } + return true; + } @Override public boolean onCreateOptionsMenu(Menu menu) { @@ -268,14 +277,13 @@ public class Dashboard extends Activity implements LogInDialog.LogInDialogInterf startActivityForResult(new Intent(this,ConfigurationWizard.class), SWITCH_PROVIDER); return true; case R.id.login_button: - View view = ((ViewGroup)findViewById(android.R.id.content)).getChildAt(0); logInDialog(Bundle.EMPTY); return true; case R.id.logout_button: logOut(); return true; case R.id.signup_button: - signUpDialog(((ViewGroup)findViewById(android.R.id.content)).getChildAt(0), Bundle.EMPTY); + signUpDialog(Bundle.EMPTY); return true; default: return super.onOptionsItemSelected(item); @@ -283,38 +291,48 @@ public class Dashboard extends Activity implements LogInDialog.LogInDialogInterf } - @Override - public void authenticate(String username, String password) { - mProgressBar = (ProgressBar) findViewById(R.id.eipProgress); - eipStatus = (TextView) findViewById(R.id.eipStatus); + private Intent prepareProviderAPICommand() { + mProgressBar = (ProgressBar) findViewById(R.id.eipProgress); + eipStatus = (TextView) findViewById(R.id.eipStatus); - providerAPI_result_receiver = new ProviderAPIResultReceiver(new Handler()); - providerAPI_result_receiver.setReceiver(this); + providerAPI_result_receiver = new ProviderAPIResultReceiver(new Handler()); + providerAPI_result_receiver.setReceiver(this); - Intent provider_API_command = new Intent(this, ProviderAPI.class); + Intent command = new Intent(this, ProviderAPI.class); - Bundle parameters = new Bundle(); - parameters.putString(LogInDialog.USERNAME, username); - parameters.putString(LogInDialog.PASSWORD, password); - - JSONObject provider_json; - try { - provider_json = new JSONObject(preferences.getString(Provider.KEY, "")); - parameters.putString(Provider.API_URL, provider_json.getString(Provider.API_URL) + "/" + provider_json.getString(Provider.API_VERSION)); - } catch (JSONException e) { - // TODO Auto-generated catch block - e.printStackTrace(); - } + command.putExtra(ProviderAPI.RECEIVER_KEY, providerAPI_result_receiver); + return command; + } + + /** + * Shows the log in dialog. + */ + public void logInDialog(Bundle resultData) { + FragmentTransaction transaction = fragment_manager.removePreviousFragment(LogInDialog.TAG); + + DialogFragment newFragment = LogInDialog.newInstance(); + if(resultData != null && !resultData.isEmpty()) + newFragment.setArguments(resultData); + newFragment.show(transaction, LogInDialog.TAG); + } - provider_API_command.setAction(ProviderAPI.SRP_AUTH); - provider_API_command.putExtra(ProviderAPI.PARAMETERS, parameters); - provider_API_command.putExtra(ProviderAPI.RECEIVER_KEY, providerAPI_result_receiver); - - mProgressBar.setVisibility(ProgressBar.VISIBLE); - eipStatus.setText(R.string.authenticating_message); - //mProgressBar.setMax(4); - startService(provider_API_command); - } + @Override + public void logIn(String username, String password) { + Intent provider_API_command = prepareProviderAPICommand(); + Bundle parameters = provider_API_command.getExtras().getBundle(ProviderAPI.PARAMETERS); + if(parameters == null) + parameters = new Bundle(); + + parameters.putString(SessionDialogInterface.USERNAME, username); + parameters.putString(SessionDialogInterface.PASSWORD, password); + + mProgressBar.setVisibility(ProgressBar.VISIBLE); + eipStatus.setText(R.string.authenticating_message); + + provider_API_command.putExtra(ProviderAPI.PARAMETERS, parameters); + provider_API_command.setAction(ProviderAPI.SRP_AUTH); + startService(provider_API_command); + } public void cancelAuthedEipOn() { EipServiceFragment eipFragment = (EipServiceFragment) getFragmentManager().findFragmentByTag(EipServiceFragment.TAG); @@ -322,125 +340,59 @@ public class Dashboard extends Activity implements LogInDialog.LogInDialogInterf } public void cancelLoginOrSignup() { - if(mProgressBar == null) mProgressBar = (ProgressBar) findViewById(R.id.eipProgress); - if(mProgressBar != null) { - mProgressBar.setVisibility(ProgressBar.GONE); - if(eipStatus == null) eipStatus = (TextView) findViewById(R.id.eipStatus); - if(eipStatus != null) eipStatus.setText(""); - } - cancelAuthedEipOn(); + hideProgressBar(); } - /** - * Asks ProviderAPI to log out. - */ - public void logOut() { - providerAPI_result_receiver = new ProviderAPIResultReceiver(new Handler()); - providerAPI_result_receiver.setReceiver(this); - Intent provider_API_command = new Intent(this, ProviderAPI.class); - - Bundle parameters = new Bundle(); - - JSONObject provider_json; - try { - provider_json = new JSONObject(preferences.getString(Provider.KEY, "")); - parameters.putString(Provider.API_URL, provider_json.getString(Provider.API_URL) + "/" + provider_json.getString(Provider.API_VERSION)); - } catch (JSONException e) { - // TODO Auto-generated catch block - e.printStackTrace(); - } - - provider_API_command.setAction(ProviderAPI.LOG_OUT); - provider_API_command.putExtra(ProviderAPI.PARAMETERS, parameters); - provider_API_command.putExtra(ProviderAPI.RECEIVER_KEY, providerAPI_result_receiver); - - if(mProgressBar == null) mProgressBar = (ProgressBar) findViewById(R.id.eipProgress); - mProgressBar.setVisibility(ProgressBar.VISIBLE); - if(eipStatus == null) eipStatus = (TextView) findViewById(R.id.eipStatus); - eipStatus.setText(R.string.logout_message); - // eipStatus.setText("Starting to logout"); - - startService(provider_API_command); - //mProgressBar.setMax(1); - - } - - /** - * Shows the log in dialog. - */ - public void logInDialog(Bundle resultData) { - Log.d("Dashboard", "Log In Dialog"); - FragmentTransaction fragment_transaction = getFragmentManager().beginTransaction(); - Fragment previous_log_in_dialog = getFragmentManager().findFragmentByTag(LogInDialog.TAG); - if (previous_log_in_dialog != null) { - fragment_transaction.remove(previous_log_in_dialog); - } - fragment_transaction.addToBackStack(null); - - DialogFragment newFragment = LogInDialog.newInstance(); - if(resultData != null && !resultData.isEmpty()) { - newFragment.setArguments(resultData); - } - newFragment.show(fragment_transaction, LogInDialog.TAG); - } - - @Override - public void signUp(String username, String password) { - mProgressBar = (ProgressBar) findViewById(R.id.eipProgress); - eipStatus = (TextView) findViewById(R.id.eipStatus); - - providerAPI_result_receiver = new ProviderAPIResultReceiver(new Handler()); - providerAPI_result_receiver.setReceiver(this); - - Intent provider_API_command = new Intent(this, ProviderAPI.class); - - Bundle parameters = new Bundle(); - parameters.putString(SignUpDialog.USERNAME, username); - parameters.putString(SignUpDialog.PASSWORD, password); - - JSONObject provider_json; - try { - provider_json = new JSONObject(preferences.getString(Provider.KEY, "")); - parameters.putString(Provider.API_URL, provider_json.getString(Provider.API_URL) + "/" + provider_json.getString(Provider.API_VERSION)); - } catch (JSONException e) { - // TODO Auto-generated catch block - e.printStackTrace(); - } - - provider_API_command.setAction(ProviderAPI.SRP_REGISTER); - provider_API_command.putExtra(ProviderAPI.PARAMETERS, parameters); - provider_API_command.putExtra(ProviderAPI.RECEIVER_KEY, providerAPI_result_receiver); + /** + * Asks ProviderAPI to log out. + */ + public void logOut() { + Intent provider_API_command = prepareProviderAPICommand(); + + if(mProgressBar == null) mProgressBar = (ProgressBar) findViewById(R.id.eipProgress); + mProgressBar.setVisibility(ProgressBar.VISIBLE); + if(eipStatus == null) eipStatus = (TextView) findViewById(R.id.eipStatus); + eipStatus.setText(R.string.logout_message); - mProgressBar.setVisibility(ProgressBar.VISIBLE); - eipStatus.setText(R.string.signingup_message); - //mProgressBar.setMax(4); - startService(provider_API_command); - } + provider_API_command.setAction(ProviderAPI.LOG_OUT); + startService(provider_API_command); + } - /** - * Shows the sign up dialog. - * @param view from which the dialog is created. - */ - public void signUpDialog(View view, Bundle resultData) { - FragmentTransaction fragment_transaction = getFragmentManager().beginTransaction(); - Fragment previous_sign_up_dialog = getFragmentManager().findFragmentByTag(SignUpDialog.TAG); - if (previous_sign_up_dialog != null) { - fragment_transaction.remove(previous_sign_up_dialog); - } - fragment_transaction.addToBackStack(null); - - DialogFragment newFragment = SignUpDialog.newInstance(); - if(resultData != null && !resultData.isEmpty()) { - newFragment.setArguments(resultData); - } - newFragment.show(fragment_transaction, SignUpDialog.TAG); + /** + * Shows the sign up dialog. + */ + public void signUpDialog(Bundle resultData) { + FragmentTransaction transaction = fragment_manager.removePreviousFragment(SignUpDialog.TAG); + + DialogFragment newFragment = SignUpDialog.newInstance(); + if(resultData != null && !resultData.isEmpty()) { + newFragment.setArguments(resultData); } + newFragment.show(transaction, SignUpDialog.TAG); + } + + @Override + public void signUp(String username, String password) { + Intent provider_API_command = prepareProviderAPICommand(); + Bundle parameters = provider_API_command.getExtras().getBundle(ProviderAPI.PARAMETERS); + if(parameters == null) + parameters = new Bundle(); + + parameters.putString(SessionDialogInterface.USERNAME, username); + parameters.putString(SessionDialogInterface.PASSWORD, password); + + mProgressBar.setVisibility(ProgressBar.VISIBLE); + eipStatus.setText(R.string.signingup_message); + + provider_API_command.putExtra(ProviderAPI.PARAMETERS, parameters); + provider_API_command.setAction(ProviderAPI.SRP_REGISTER); + startService(provider_API_command); + } /** * Asks ProviderAPI to download an authenticated OpenVPN certificate. - * @param session_id cookie for the server to allow us to download the certificate. */ - private void downloadAuthedUserCertificate(/*Cookie session_id*/) { + private void downloadAuthedUserCertificate() { providerAPI_result_receiver = new ProviderAPIResultReceiver(new Handler()); providerAPI_result_receiver.setReceiver(this); @@ -448,8 +400,6 @@ public class Dashboard extends Activity implements LogInDialog.LogInDialogInterf Bundle parameters = new Bundle(); parameters.putString(ConfigurationWizard.TYPE_OF_CERTIFICATE, ConfigurationWizard.AUTHED_CERTIFICATE); - /*parameters.putString(ConfigHelper.SESSION_ID_COOKIE_KEY, session_id.getName()); - parameters.putString(ConfigHelper.SESSION_ID_KEY, session_id.getValue());*/ provider_API_command.setAction(ProviderAPI.DOWNLOAD_CERTIFICATE); provider_API_command.putExtra(ProviderAPI.PARAMETERS, parameters); @@ -460,53 +410,70 @@ public class Dashboard extends Activity implements LogInDialog.LogInDialogInterf @Override public void onReceiveResult(int resultCode, Bundle resultData) { - if(resultCode == ProviderAPI.SRP_REGISTRATION_SUCCESSFUL){ - authenticate(resultData.getString(LogInDialog.USERNAME), resultData.getString(LogInDialog.PASSWORD)); - } else if(resultCode == ProviderAPI.SRP_REGISTRATION_FAILED){ - signUpDialog(((ViewGroup)findViewById(android.R.id.content)).getChildAt(0), resultData); - } else if(resultCode == ProviderAPI.SRP_AUTHENTICATION_SUCCESSFUL){ - String session_id_cookie_key = resultData.getString(ProviderAPI.SESSION_ID_COOKIE_KEY); - String session_id_string = resultData.getString(ProviderAPI.SESSION_ID_KEY); - setResult(RESULT_OK); - - authed_eip = true; - preferences.edit().putBoolean(EIP.AUTHED_EIP, authed_eip).commit(); + if(resultCode == ProviderAPI.SRP_REGISTRATION_SUCCESSFUL) { + String username = resultData.getString(SessionDialogInterface.USERNAME); + String password = resultData.getString(SessionDialogInterface.PASSWORD); + logIn(username, password); + } else if(resultCode == ProviderAPI.SRP_REGISTRATION_FAILED) { + changeStatusMessage(resultCode); + hideProgressBar(); + + signUpDialog(resultData); + } else if(resultCode == ProviderAPI.SRP_AUTHENTICATION_SUCCESSFUL) { + changeStatusMessage(resultCode); + hideProgressBar(); + + invalidateOptionsMenu(); + + authed_eip = true; + preferences.edit().putBoolean(EIP.AUTHED_EIP, authed_eip).commit(); - invalidateOptionsMenu(); - mProgressBar.setVisibility(ProgressBar.GONE); - changeStatusMessage(resultCode); + downloadAuthedUserCertificate(); + } else if(resultCode == ProviderAPI.SRP_AUTHENTICATION_FAILED) { + changeStatusMessage(resultCode); + hideProgressBar(); + + logInDialog(resultData); + } else if(resultCode == ProviderAPI.LOGOUT_SUCCESSFUL) { + changeStatusMessage(resultCode); + hideProgressBar(); + + invalidateOptionsMenu(); + + authed_eip = false; + preferences.edit().putBoolean(EIP.AUTHED_EIP, authed_eip).commit(); - //Cookie session_id = new BasicClientCookie(session_id_cookie_key, session_id_string); - downloadAuthedUserCertificate(/*session_id*/); - } else if(resultCode == ProviderAPI.SRP_AUTHENTICATION_FAILED) { - logInDialog(resultData); - } else if(resultCode == ProviderAPI.LOGOUT_SUCCESSFUL) { - authed_eip = false; - preferences.edit().putBoolean(EIP.AUTHED_EIP, authed_eip).commit(); - mProgressBar.setVisibility(ProgressBar.GONE); - mProgressBar.setProgress(0); - invalidateOptionsMenu(); - setResult(RESULT_OK); - changeStatusMessage(resultCode); - - } else if(resultCode == ProviderAPI.LOGOUT_FAILED) { - setResult(RESULT_CANCELED); - changeStatusMessage(resultCode); - mProgressBar.setVisibility(ProgressBar.GONE); - } else if(resultCode == ProviderAPI.CORRECTLY_DOWNLOADED_CERTIFICATE) { + } else if(resultCode == ProviderAPI.LOGOUT_FAILED) { + changeStatusMessage(resultCode); + hideProgressBar(); + + setResult(RESULT_CANCELED); + } else if(resultCode == ProviderAPI.CORRECTLY_DOWNLOADED_CERTIFICATE) { + changeStatusMessage(resultCode); + hideProgressBar(); + setResult(RESULT_OK); + Intent updateEIP = new Intent(getApplicationContext(), EIP.class); + ResultReceiver eip_receiver = new ResultReceiver(new Handler()){ + protected void onReceiveResult(int resultCode, Bundle resultData){ + super.onReceiveResult(resultCode, resultData); + String request = resultData.getString(EIP.REQUEST_TAG); + if (resultCode == Activity.RESULT_OK){ + if(authed_eip) + eipStart(); + else + eipStatus.setText("Certificate updated"); + } + } + }; + updateEIP.putExtra(EIP.RECEIVER_TAG, eip_receiver); + updateEIP.setAction(EIP.ACTION_UPDATE_EIP_SERVICE); + startService(updateEIP); + } else if(resultCode == ProviderAPI.INCORRECTLY_DOWNLOADED_CERTIFICATE) { changeStatusMessage(resultCode); - if(mProgressBar != null) - mProgressBar.setVisibility(ProgressBar.GONE); - if(EipServiceFragment.isEipSwitchChecked()) - eipStart(); - else - eipStatus.setText(R.string.eip_state_not_connected); - } else if(resultCode == ProviderAPI.INCORRECTLY_DOWNLOADED_CERTIFICATE) { + hideProgressBar(); setResult(RESULT_CANCELED); - changeStatusMessage(resultCode); - mProgressBar.setVisibility(ProgressBar.GONE); - } + } } private void changeStatusMessage(final int previous_result_code) { @@ -515,6 +482,7 @@ public class Dashboard extends Activity implements LogInDialog.LogInDialogInterf protected void onReceiveResult(int resultCode, Bundle resultData){ super.onReceiveResult(resultCode, resultData); String request = resultData.getString(EIP.REQUEST_TAG); + if(eipStatus == null) eipStatus = (TextView) findViewById(R.id.eipStatus); if (request.equalsIgnoreCase(EIP.ACTION_IS_EIP_RUNNING)){ if (resultCode == Activity.RESULT_OK){ @@ -534,6 +502,7 @@ public class Dashboard extends Activity implements LogInDialog.LogInDialogInterf case ProviderAPI.SRP_AUTHENTICATION_SUCCESSFUL: eipStatus.setText(R.string.succesful_authentication_message); break; case ProviderAPI.SRP_AUTHENTICATION_FAILED: eipStatus.setText(R.string.authentication_failed_message); break; + case ProviderAPI.SRP_REGISTRATION_FAILED: eipStatus.setText(R.string.registration_failed_message); break; case ProviderAPI.CORRECTLY_DOWNLOADED_CERTIFICATE: break; case ProviderAPI.INCORRECTLY_DOWNLOADED_CERTIFICATE: eipStatus.setText(R.string.incorrectly_downloaded_certificate_message); break; case ProviderAPI.LOGOUT_SUCCESSFUL: eipStatus.setText(R.string.logged_out_message); break; @@ -547,6 +516,14 @@ public class Dashboard extends Activity implements LogInDialog.LogInDialogInterf eipIsRunning(eip_status_receiver); } + private void hideProgressBar() { + if(mProgressBar == null) + mProgressBar = (ProgressBar) findViewById(R.id.eipProgress); + + mProgressBar.setProgress(0); + mProgressBar.setVisibility(ProgressBar.GONE); + } + /** * For retrieving the base application Context in classes that don't extend * Android's Activity class @@ -558,17 +535,12 @@ public class Dashboard extends Activity implements LogInDialog.LogInDialogInterf } - @Override + @Override public void startActivityForResult(Intent intent, int requestCode) { intent.putExtra(Dashboard.REQUEST_CODE, requestCode); super.startActivityForResult(intent, requestCode); } - /** - * Send a command to EIP - * - * @param action A valid String constant from EIP class representing an Intent - * filter for the EIP class - */ + private void eipIsRunning(ResultReceiver eip_receiver){ // TODO validate "action"...how do we get the list of intent-filters for a class via Android API? Intent eip_intent = new Intent(this, EIP.class); @@ -577,30 +549,19 @@ public class Dashboard extends Activity implements LogInDialog.LogInDialogInterf startService(eip_intent); } - /** - * Send a command to EIP - * - */ - private void eipStop(){ - // TODO validate "action"...how do we get the list of intent-filters for a class via Android API? - Intent eip_intent = new Intent(this, EIP.class); - eip_intent.setAction(EIP.ACTION_STOP_EIP); - // eip_intent.putExtra(EIP.RECEIVER_TAG, eip_receiver);fi - startService(eip_intent); - - } - - private void eipStart(){ - Intent eip_intent = new Intent(this, EIP.class); - eip_intent.setAction(EIP.ACTION_START_EIP); - eip_intent.putExtra(EIP.RECEIVER_TAG, EipServiceFragment.getReceiver()); - startService(eip_intent); + private void eipStop(){ + EipServiceFragment eipFragment = (EipServiceFragment) getFragmentManager().findFragmentByTag(EipServiceFragment.TAG); + eipFragment.stopEIP(); + } + private void eipStart() { + EipServiceFragment eipFragment = (EipServiceFragment) getFragmentManager().findFragmentByTag(EipServiceFragment.TAG); + eipFragment.startEipFromScratch(); } - protected void setProgressBarVisibility(int visibility) { + protected void showProgressBar() { if(mProgressBar == null) mProgressBar = (ProgressBar) findViewById(R.id.eipProgress); - mProgressBar.setVisibility(visibility); + mProgressBar.setVisibility(ProgressBar.VISIBLE); } } diff --git a/app/src/main/java/se/leap/bitmaskclient/EIP.java b/app/src/main/java/se/leap/bitmaskclient/EIP.java index 43fe0b7c..2f06def3 100644 --- a/app/src/main/java/se/leap/bitmaskclient/EIP.java +++ b/app/src/main/java/se/leap/bitmaskclient/EIP.java @@ -16,35 +16,23 @@ */ package se.leap.bitmaskclient; - - - - import android.app.Activity; import android.app.IntentService; -import android.content.ComponentName; import android.content.Context; import android.content.Intent; -import android.content.ServiceConnection; import android.content.SharedPreferences; -import android.drm.DrmStore.Action; import android.os.Bundle; -import android.os.IBinder; import android.os.ResultReceiver; import android.util.Log; import de.blinkt.openvpn.LaunchVPN; import de.blinkt.openvpn.VpnProfile; import de.blinkt.openvpn.activities.DisconnectVPN; -import de.blinkt.openvpn.core.ConfigParser.ConfigParseError; import de.blinkt.openvpn.core.ConfigParser; -import de.blinkt.openvpn.core.OpenVpnManagementThread; -import de.blinkt.openvpn.core.OpenVPNService.LocalBinder; -import de.blinkt.openvpn.core.OpenVPNService; +import de.blinkt.openvpn.core.ConfigParser.ConfigParseError; import de.blinkt.openvpn.core.ProfileManager; import de.blinkt.openvpn.core.VpnStatus.ConnectionStatus; import java.io.IOException; import java.io.StringReader; -import java.lang.StringBuffer; import java.security.cert.CertificateExpiredException; import java.security.cert.CertificateNotYetValidException; import java.security.cert.X509Certificate; @@ -99,17 +87,13 @@ public final class EIP extends IntentService { public final static String SERVICE_API_PATH = "config/eip-service.json"; public final static String RECEIVER_TAG = "receiverTag"; public final static String REQUEST_TAG = "requestTag"; - public final static String TAG = "se.leap.bitmaskclient.EIP"; + public final static String TAG = EIP.class.getSimpleName(); + private static SharedPreferences preferences; - public final static SimpleDateFormat certificate_date_format = new SimpleDateFormat("yyyy-MM-dd HH:mm", Locale.US); - private static Context context; private static ResultReceiver mReceiver; private static boolean mBound = false; - // Used to store actions to "resume" onServiceConnection - private static String mPending = null; - private static int parsedEipSerial; private static JSONObject eipDefinition = null; private static OVPNGateway activeGateway = null; @@ -118,6 +102,7 @@ public final class EIP extends IntentService { protected static boolean mIsDisconnecting = false; protected static boolean mIsStarting = false; + public static SimpleDateFormat certificate_date_format = new SimpleDateFormat("yyyy-MM-dd HH:mm", Locale.US); public EIP(){ super("LEAPEIP"); } @@ -127,8 +112,8 @@ public final class EIP extends IntentService { super.onCreate(); context = getApplicationContext(); - - updateEIPService(); + + preferences = getSharedPreferences(Dashboard.SHARED_PREFERENCES, MODE_PRIVATE); } @Override @@ -140,59 +125,137 @@ public final class EIP extends IntentService { } - @Override - protected void onHandleIntent(Intent intent) { - String action = intent.getAction(); - mReceiver = intent.getParcelableExtra(RECEIVER_TAG); - - if ( action == ACTION_IS_EIP_RUNNING ) - this.isRunning(); - if ( action == ACTION_UPDATE_EIP_SERVICE ) - this.updateEIPService(); - else if ( action == ACTION_START_EIP ) - this.startEIP(); - else if ( action == ACTION_STOP_EIP ) - this.stopEIP(); - else if ( action == ACTION_CHECK_CERT_VALIDITY ) - this.checkCertValidity(); - else if ( action == ACTION_REBUILD_PROFILES ) { - this.updateGateways(); - } - } + @Override + protected void onHandleIntent(Intent intent) { + String action = intent.getAction(); + mReceiver = intent.getParcelableExtra(RECEIVER_TAG); - /** - * Checks the last stored status notified by ics-openvpn - * Sends <code>Activity.RESULT_CANCELED</code> to the ResultReceiver that made the - * request if it's not connected, <code>Activity.RESULT_OK</code> otherwise. - */ + if ( action == ACTION_START_EIP ) + startEIP(); + else if ( action == ACTION_STOP_EIP ) + stopEIP(); + else if ( action == ACTION_IS_EIP_RUNNING ) + isRunning(); + else if ( action == ACTION_UPDATE_EIP_SERVICE ) + updateEIPService(); + else if ( action == ACTION_CHECK_CERT_VALIDITY ) + checkCertValidity(); + else if ( action == ACTION_REBUILD_PROFILES ) + updateGateways(); + } - private void isRunning() { - Bundle resultData = new Bundle(); - resultData.putString(REQUEST_TAG, ACTION_IS_EIP_RUNNING); - int resultCode = Activity.RESULT_CANCELED; - boolean is_connected = isConnected(); + /** + * Initiates an EIP connection by selecting a gateway and preparing and sending an + * Intent to {@link se.leap.openvpn.LaunchVPN}. + * It also sets up early routes. + */ + private void startEIP() { + earlyRoutes(); + activeGateway = selectGateway(); + + if(activeGateway != null && activeGateway.mVpnProfile != null) { + mReceiver = EipServiceFragment.getReceiver(); + launchActiveGateway(); + } + } - resultCode = (is_connected) ? Activity.RESULT_OK : Activity.RESULT_CANCELED; - - if (mReceiver != null){ - mReceiver.send(resultCode, resultData); - } + /** + * Early routes are routes that block traffic until a new + * VpnService is started properly. + */ + private void earlyRoutes() { + Intent void_vpn_launcher = new Intent(context, VoidVpnLauncher.class); + void_vpn_launcher.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK); + startActivity(void_vpn_launcher); + } + + /** + * Choose a gateway to connect to based on timezone from system locale data + * + * @return The gateway to connect to + */ + private OVPNGateway selectGateway() { + String closest_location = closestGateway(); + String chosen_host = chooseHost(closest_location); + + return new OVPNGateway(chosen_host); + } - Log.d(TAG, "isRunning() = " + is_connected); - } + private String closestGateway() { + TreeMap<Integer, Set<String>> offsets = calculateOffsets(); + return offsets.isEmpty() ? "" : offsets.firstEntry().getValue().iterator().next(); + } + + private TreeMap<Integer, Set<String>> calculateOffsets() { + TreeMap<Integer, Set<String>> offsets = new TreeMap<Integer, Set<String>>(); - /** - * Initiates an EIP connection by selecting a gateway and preparing and sending an - * Intent to {@link se.leap.openvpn.LaunchVPN} - */ - private void startEIP() { - activeGateway = selectGateway(); + int localOffset = Calendar.getInstance().get(Calendar.ZONE_OFFSET) / 3600000; + + JSONObject locations = availableLocations(); + Iterator<String> locations_names = locations.keys(); + while(locations_names.hasNext()) { + try { + String location_name = locations_names.next(); + JSONObject location = locations.getJSONObject(location_name); + + int dist = timezoneDistance(localOffset, location.optInt("timezone")); + + Set<String> set = (offsets.get(dist) != null) ? + offsets.get(dist) : new HashSet<String>(); - if(activeGateway != null && activeGateway.mVpnProfile != null) { - launchActiveGateway(); - } + set.add(location_name); + offsets.put(dist, set); + } catch (JSONException e) { + // TODO Auto-generated catch block + e.printStackTrace(); + } + } + + return offsets; + } + + private JSONObject availableLocations() { + JSONObject locations = null; + try { + if(eipDefinition == null) updateEIPService(); + locations = eipDefinition.getJSONObject("locations"); + } catch (JSONException e1) { + // TODO Auto-generated catch block + e1.printStackTrace(); } + return locations; + } + + private int timezoneDistance(int local_timezone, int remote_timezone) { + // Distance along the numberline of Prime Meridian centric, assumes UTC-11 through UTC+12 + int dist = Math.abs(local_timezone - remote_timezone); + + // Farther than 12 timezones and it's shorter around the "back" + if (dist > 12) + dist = 12 - (dist -12); // Well i'll be. Absolute values make equations do funny things. + + return dist; + } + + private String chooseHost(String location) { + String chosen_host = ""; + try { + JSONArray gateways = eipDefinition.getJSONArray("gateways"); + for (int i = 0; i < gateways.length(); i++) { + JSONObject gw = gateways.getJSONObject(i); + if ( gw.getString("location").equalsIgnoreCase(location) || location.isEmpty()){ + chosen_host = eipDefinition.getJSONObject("locations").getJSONObject(gw.getString("location")).getString("name"); + break; + } + } + } catch (JSONException e) { + // TODO Auto-generated catch block + e.printStackTrace(); + } + return chosen_host; + } + private void launchActiveGateway() { Intent intent = new Intent(this,LaunchVPN.class); intent.setAction(Intent.ACTION_MAIN); @@ -202,30 +265,48 @@ public final class EIP extends IntentService { intent.putExtra(LaunchVPN.EXTRA_HIDELOG, true); intent.putExtra(RECEIVER_TAG, mReceiver); startActivity(intent); - mPending = ACTION_START_EIP; } - - /** - * Disconnects the EIP connection gracefully through the bound service or forcefully - * if there is no bound service. Sends a message to the requesting ResultReceiver. - */ - private void stopEIP() { - if(isConnected()) { - Intent disconnect_vpn = new Intent(this, DisconnectVPN.class); - disconnect_vpn.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK); - startActivity(disconnect_vpn); - mIsDisconnecting = true; - lastConnectionStatusLevel = ConnectionStatus.UNKNOWN_LEVEL; // Wait for the decision of the user - Log.d(TAG, "mIsDisconnecting = true"); - } + + /** + * Disconnects the EIP connection gracefully through the bound service or forcefully + * if there is no bound service. Sends a message to the requesting ResultReceiver. + */ + private void stopEIP() { + if(isConnected()) { + Intent disconnect_vpn = new Intent(this, DisconnectVPN.class); + disconnect_vpn.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK); + startActivity(disconnect_vpn); + mIsDisconnecting = true; + lastConnectionStatusLevel = ConnectionStatus.UNKNOWN_LEVEL; // Wait for the decision of the user + Log.d(TAG, "mIsDisconnecting = true"); + } - if (mReceiver != null){ - Bundle resultData = new Bundle(); - resultData.putString(REQUEST_TAG, ACTION_STOP_EIP); - mReceiver.send(Activity.RESULT_OK, resultData); - } + tellToReceiver(ACTION_STOP_EIP, Activity.RESULT_OK); + } + + private void tellToReceiver(String action, int resultCode) { + if (mReceiver != null){ + Bundle resultData = new Bundle(); + resultData.putString(REQUEST_TAG, action); + mReceiver.send(resultCode, resultData); } + } + + /** + * Checks the last stored status notified by ics-openvpn + * Sends <code>Activity.RESULT_CANCELED</code> to the ResultReceiver that made the + * request if it's not connected, <code>Activity.RESULT_OK</code> otherwise. + */ + + private void isRunning() { + int resultCode = Activity.RESULT_CANCELED; + boolean is_connected = isConnected(); + resultCode = (is_connected) ? Activity.RESULT_OK : Activity.RESULT_CANCELED; + + tellToReceiver(ACTION_IS_EIP_RUNNING, resultCode); + } + protected static boolean isConnected() { return lastConnectionStatusLevel != null && lastConnectionStatusLevel.equals(ConnectionStatus.LEVEL_CONNECTED) && !mIsDisconnecting; } @@ -237,89 +318,23 @@ public final class EIP extends IntentService { */ private void updateEIPService() { try { - eipDefinition = new JSONObject(getSharedPreferences(Dashboard.SHARED_PREFERENCES, MODE_PRIVATE).getString(KEY, "")); - parsedEipSerial = getSharedPreferences(Dashboard.SHARED_PREFERENCES, MODE_PRIVATE).getInt(PARSED_SERIAL, 0); + String eip_definition_string = preferences.getString(KEY, ""); + if(eip_definition_string.isEmpty() == false) { + eipDefinition = new JSONObject(eip_definition_string); + } + deleteAllVpnProfiles(); + updateGateways(); + if(mReceiver != null) mReceiver.send(Activity.RESULT_OK, Bundle.EMPTY); } catch (JSONException e) { // TODO Auto-generated catch block e.printStackTrace(); } - if(parsedEipSerial == 0) { - deleteAllVpnProfiles(); - } - if (eipDefinition != null && eipDefinition.optInt("serial") > parsedEipSerial) - updateGateways(); } private void deleteAllVpnProfiles() { ProfileManager vpl = ProfileManager.getInstance(context); - VpnProfile[] profiles = (VpnProfile[]) vpl.getProfiles().toArray(new VpnProfile[vpl.getProfiles().size()]); - for (int current_profile = 0; current_profile < profiles.length; current_profile++){ - vpl.removeProfile(context, profiles[current_profile]); - } - } - /** - * Choose a gateway to connect to based on timezone from system locale data - * - * @return The gateway to connect to - */ - private OVPNGateway selectGateway() { - String closestLocation = closestGateway(); - - JSONArray gateways = null; - String chosenHost = null; - try { - gateways = eipDefinition.getJSONArray("gateways"); - for (int i = 0; i < gateways.length(); i++) { - JSONObject gw = gateways.getJSONObject(i); - if ( gw.getString("location").equalsIgnoreCase(closestLocation) || closestLocation.isEmpty()){ - chosenHost = eipDefinition.getJSONObject("locations").getJSONObject(gw.getString("location")).getString("name"); - break; - } - } - } catch (JSONException e) { - // TODO Auto-generated catch block - e.printStackTrace(); - } - - return new OVPNGateway(chosenHost); - } - - private String closestGateway() { - Calendar cal = Calendar.getInstance(); - int localOffset = cal.get(Calendar.ZONE_OFFSET) / 3600000; - TreeMap<Integer, Set<String>> offsets = new TreeMap<Integer, Set<String>>(); - JSONObject locationsObjects = null; - Iterator<String> locations = null; - try { - locationsObjects = eipDefinition.getJSONObject("locations"); - locations = locationsObjects.keys(); - } catch (JSONException e1) { - // TODO Auto-generated catch block - e1.printStackTrace(); - } - - while (locations.hasNext()) { - String locationName = locations.next(); - JSONObject location = null; - try { - location = locationsObjects.getJSONObject(locationName); - - // Distance along the numberline of Prime Meridian centric, assumes UTC-11 through UTC+12 - int dist = Math.abs(localOffset - location.optInt("timezone")); - // Farther than 12 timezones and it's shorter around the "back" - if (dist > 12) - dist = 12 - (dist -12); // Well i'll be. Absolute values make equations do funny things. - - Set<String> set = offsets.get(dist); - if (set == null) set = new HashSet<String>(); - set.add(locationName); - offsets.put(dist, set); - } catch (JSONException e) { - // TODO Auto-generated catch block - e.printStackTrace(); - } - } - return offsets.isEmpty() ? "" : offsets.firstEntry().getValue().iterator().next(); + Collection<VpnProfile> profiles = vpl.getProfiles(); + profiles.removeAll(profiles); } /** @@ -329,8 +344,8 @@ public final class EIP extends IntentService { */ private void updateGateways(){ JSONArray gatewaysDefined = null; - try { + if(eipDefinition == null) updateEIPService(); gatewaysDefined = eipDefinition.getJSONArray("gateways"); for ( int i=0 ; i < gatewaysDefined.length(); i++ ){ JSONObject gw = null; @@ -343,43 +358,54 @@ public final class EIP extends IntentService { // TODO Auto-generated catch block e.printStackTrace(); } - - getSharedPreferences(Dashboard.SHARED_PREFERENCES, MODE_PRIVATE).edit().putInt(PARSED_SERIAL, eipDefinition.optInt(Provider.API_RETURN_SERIAL)).commit(); + preferences.edit().putInt(PARSED_SERIAL, eipDefinition.optInt(Provider.API_RETURN_SERIAL)).commit(); } private void checkCertValidity() { - String certificate_string = getSharedPreferences(Dashboard.SHARED_PREFERENCES, MODE_PRIVATE).getString(CERTIFICATE, ""); - if(!certificate_string.isEmpty()) { - String date_from_certificate_string = getSharedPreferences(Dashboard.SHARED_PREFERENCES, MODE_PRIVATE).getString(DATE_FROM_CERTIFICATE, certificate_date_format.format(Calendar.getInstance().getTime()).toString()); - X509Certificate certificate_x509 = ConfigHelper.parseX509CertificateFromString(certificate_string); + String certificate = preferences.getString(CERTIFICATE, ""); + checkCertValidity(certificate); + } - Calendar offset_date = Calendar.getInstance(); - try { - Date date_from_certificate = certificate_date_format.parse(date_from_certificate_string); - long difference = Math.abs(date_from_certificate.getTime() - certificate_x509.getNotAfter().getTime())/2; - long current_date_millis = offset_date.getTimeInMillis(); - offset_date.setTimeInMillis(current_date_millis + difference); - Log.d(TAG, "certificate not after = " + certificate_x509.getNotAfter()); - } catch(ParseException e) { - e.printStackTrace(); - } - - Bundle result_data = new Bundle(); - result_data.putString(REQUEST_TAG, ACTION_CHECK_CERT_VALIDITY); + private void checkCertValidity(String certificate_string) { + if(!certificate_string.isEmpty()) { + X509Certificate certificate = ConfigHelper.parseX509CertificateFromString(certificate_string); + + Calendar offset_date = calculateOffsetCertificateValidity(certificate); + Bundle result = new Bundle(); + result.putString(REQUEST_TAG, ACTION_CHECK_CERT_VALIDITY); try { Log.d(TAG, "offset_date = " + offset_date.getTime().toString()); - certificate_x509.checkValidity(offset_date.getTime()); - mReceiver.send(Activity.RESULT_OK, result_data); + certificate.checkValidity(offset_date.getTime()); + mReceiver.send(Activity.RESULT_OK, result); Log.d(TAG, "Valid certificate"); } catch(CertificateExpiredException e) { - mReceiver.send(Activity.RESULT_CANCELED, result_data); + mReceiver.send(Activity.RESULT_CANCELED, result); Log.d(TAG, "Updating certificate"); } catch(CertificateNotYetValidException e) { - mReceiver.send(Activity.RESULT_CANCELED, result_data); + mReceiver.send(Activity.RESULT_CANCELED, result); } } } + private Calendar calculateOffsetCertificateValidity(X509Certificate certificate) { + String current_date = certificate_date_format.format(Calendar.getInstance().getTime()).toString(); + + String date_string = preferences.getString(DATE_FROM_CERTIFICATE, current_date); + + Calendar offset_date = Calendar.getInstance(); + try { + Date date = certificate_date_format.parse(date_string); + long difference = Math.abs(date.getTime() - certificate.getNotAfter().getTime())/2; + long current_date_millis = offset_date.getTimeInMillis(); + offset_date.setTimeInMillis(current_date_millis + difference); + Log.d(TAG, "certificate not after = " + certificate.getNotAfter()); + } catch(ParseException e) { + e.printStackTrace(); + } + + return offset_date; + } + /** * OVPNGateway provides objects defining gateways and their options and metadata. * Each instance contains a VpnProfile for OpenVPN specific data and member @@ -460,17 +486,19 @@ public final class EIP extends IntentService { protected void createVPNProfile(){ try { ConfigParser cp = new ConfigParser(); - cp.parseConfig(new StringReader(configFromEipServiceDotJson())); - cp.parseConfig(new StringReader(caSecretFromSharedPreferences())); - cp.parseConfig(new StringReader(keySecretFromSharedPreferences())); - cp.parseConfig(new StringReader(certSecretFromSharedPreferences())); - cp.parseConfig(new StringReader("remote-cert-tls server")); - cp.parseConfig(new StringReader("persist-tun")); - VpnProfile vp = cp.convertProfile(); - //vp.mAuthenticationType=VpnProfile.TYPE_STATICKEYS; - mVpnProfile = vp; + + JSONObject openvpn_configuration = eipDefinition.getJSONObject("openvpn_configuration"); + VpnConfigGenerator vpn_configuration_generator = new VpnConfigGenerator(preferences, openvpn_configuration, mGateway); + String configuration = vpn_configuration_generator.generate(); + + cp.parseConfig(new StringReader(configuration)); + mVpnProfile = cp.convertProfile(); mVpnProfile.mName = mName = locationAsName(); Log.v(TAG,"Created VPNProfile"); + + } catch (JSONException e) { + // TODO Auto-generated catch block + e.printStackTrace(); } catch (ConfigParseError e) { // FIXME We didn't get a VpnProfile! Error handling! and log level Log.v(TAG,"Error creating VPNProfile"); @@ -482,124 +510,6 @@ public final class EIP extends IntentService { } } - /** - * Parses data from eip-service.json to a section of the openvpn config file - */ - private String configFromEipServiceDotJson() { - String parsed_configuration = ""; - - String location_key = "location"; - String locations = "locations"; - - parsed_configuration += extractCommonOptionsFromEipServiceDotJson(); - parsed_configuration += extractRemotesFromEipServiceDotJson(); - - return parsed_configuration; - } - - private String extractCommonOptionsFromEipServiceDotJson() { - String common_options = ""; - try { - String common_options_key = "openvpn_configuration"; - JSONObject openvpn_configuration = eipDefinition.getJSONObject(common_options_key); - Iterator keys = openvpn_configuration.keys(); - Vector<Vector<String>> value = new Vector<Vector<String>>(); - while ( keys.hasNext() ){ - String key = keys.next().toString(); - - common_options += key + " "; - for ( String word : openvpn_configuration.getString(key).split(" ") ) - common_options += word + " "; - common_options += System.getProperty("line.separator"); - - } - } catch (JSONException e) { - // TODO Auto-generated catch block - e.printStackTrace(); - } - - common_options += "client" + System.getProperty("line.separator"); - - return common_options; - } - - - private String extractRemotesFromEipServiceDotJson() { - String remotes = ""; - - String remote = "ip_address"; - String remote_openvpn_keyword = "remote"; - String ports = "ports"; - String protos = "protocols"; - String capabilities = "capabilities"; - String udp = "udp"; - - try { - JSONArray protocolsJSON = mGateway.getJSONObject(capabilities).getJSONArray(protos); - for ( int i=0; i<protocolsJSON.length(); i++ ) { - String remote_line = remote_openvpn_keyword; - remote_line += " " + mGateway.getString(remote); - remote_line += " " + mGateway.getJSONObject(capabilities).getJSONArray(ports).optString(0); - remote_line += " " + protocolsJSON.optString(i); - if(remote_line.endsWith(udp)) - remotes = remotes.replaceFirst(remote_openvpn_keyword, remote_line + System.getProperty("line.separator") + remote_openvpn_keyword); - else - remotes += remote_line; - remotes += System.getProperty("line.separator"); - } - } catch (JSONException e) { - // TODO Auto-generated catch block - e.printStackTrace(); - } - - Log.d(TAG, "remotes = " + remotes); - return remotes; - } - - private String caSecretFromSharedPreferences() { - String secret_lines = ""; - SharedPreferences preferences = context.getSharedPreferences(Dashboard.SHARED_PREFERENCES, context.MODE_PRIVATE); - - System.getProperty("line.separator"); - secret_lines += "<ca>"; - secret_lines += System.getProperty("line.separator"); - secret_lines += preferences.getString(Provider.CA_CERT, ""); - secret_lines += System.getProperty("line.separator"); - secret_lines += "</ca>"; - - return secret_lines; - } - - private String keySecretFromSharedPreferences() { - String secret_lines = ""; - SharedPreferences preferences = context.getSharedPreferences(Dashboard.SHARED_PREFERENCES, context.MODE_PRIVATE); - - secret_lines += System.getProperty("line.separator"); - secret_lines +="<key>"; - secret_lines += System.getProperty("line.separator"); - secret_lines += preferences.getString(EIP.PRIVATE_KEY, ""); - secret_lines += System.getProperty("line.separator"); - secret_lines += "</key>"; - secret_lines += System.getProperty("line.separator"); - - return secret_lines; - } - - private String certSecretFromSharedPreferences() { - String secret_lines = ""; - SharedPreferences preferences = context.getSharedPreferences(Dashboard.SHARED_PREFERENCES, context.MODE_PRIVATE); - - secret_lines += System.getProperty("line.separator"); - secret_lines +="<cert>"; - secret_lines += System.getProperty("line.separator"); - secret_lines += preferences.getString(EIP.CERTIFICATE, ""); - secret_lines += System.getProperty("line.separator"); - secret_lines += "</cert>"; - secret_lines += System.getProperty("line.separator"); - - return secret_lines; - } - public String locationAsName() { try { diff --git a/app/src/main/java/se/leap/bitmaskclient/EipServiceFragment.java b/app/src/main/java/se/leap/bitmaskclient/EipServiceFragment.java index 18ee0262..6d223dd6 100644 --- a/app/src/main/java/se/leap/bitmaskclient/EipServiceFragment.java +++ b/app/src/main/java/se/leap/bitmaskclient/EipServiceFragment.java @@ -85,8 +85,8 @@ public class EipServiceFragment extends Fragment implements StateListener, OnChe super.onResume(); VpnStatus.addStateListener(this); - - eipCommand(EIP.ACTION_CHECK_CERT_VALIDITY); + + eipCommand(EIP.ACTION_CHECK_CERT_VALIDITY); } @Override @@ -146,7 +146,7 @@ public class EipServiceFragment extends Fragment implements StateListener, OnChe private boolean canLogInToStartEIP() { boolean isAllowedRegistered = Dashboard.preferences.getBoolean(EIP.ALLOWED_REGISTERED, false); - boolean isLoggedIn = Dashboard.preferences.getBoolean(EIP.AUTHED_EIP, false); + boolean isLoggedIn = !LeapSRPSession.getToken().isEmpty(); Log.d(TAG, "Allow registered? " + isAllowedRegistered); Log.d(TAG, "Is logged in? " + isLoggedIn); return isAllowedRegistered && !isLoggedIn && !EIP.mIsStarting && !EIP.isConnected(); @@ -195,7 +195,7 @@ public class EipServiceFragment extends Fragment implements StateListener, OnChe eipCommand(EIP.ACTION_START_EIP); } - private void stopEIP() { + protected void stopEIP() { EIP.mIsStarting = false; View eipProgressBar = getActivity().findViewById(R.id.eipProgress); if(eipProgressBar != null) @@ -236,7 +236,8 @@ public class EipServiceFragment extends Fragment implements StateListener, OnChe } else if(justDecidedOnDisconnect && level == ConnectionStatus.LEVEL_CONNECTED) { EIP.lastConnectionStatusLevel = ConnectionStatus.LEVEL_NOTCONNECTED; updateState(state, logmessage, localizedResId, level); - } + } // else if(isNewLevel || level == ConnectionStatus.LEVEL_AUTH_FAILED) + // handleNewState(state, logmessage, localizedResId, level); } private void handleNewState(final String state, final String logmessage, final int localizedResId, final ConnectionStatus level) { @@ -248,6 +249,8 @@ public class EipServiceFragment extends Fragment implements StateListener, OnChe setNoServerReplyUI(localizedResId, logmessage); else if (level == ConnectionStatus.LEVEL_CONNECTING_SERVER_REPLIED) setServerReplyUI(state, localizedResId, logmessage); + // else if (level == ConnectionStatus.LEVEL_AUTH_FAILED) + // handleSwitchOn(); } private boolean isDisconnectedLevel(final ConnectionStatus level) { @@ -380,19 +383,24 @@ public class EipServiceFragment extends Fragment implements StateListener, OnChe case Activity.RESULT_CANCELED: Dashboard dashboard = (Dashboard) getActivity(); - dashboard.setProgressBarVisibility(ProgressBar.VISIBLE); + dashboard.showProgressBar(); String status = getResources().getString(R.string.updating_certificate_message); setEipStatus(status); - - Intent provider_API_command = new Intent(getActivity(), ProviderAPI.class); - if(dashboard.providerAPI_result_receiver == null) { - dashboard.providerAPI_result_receiver = new ProviderAPIResultReceiver(new Handler()); - dashboard.providerAPI_result_receiver.setReceiver(dashboard); - } - - provider_API_command.setAction(ProviderAPI.DOWNLOAD_CERTIFICATE); - provider_API_command.putExtra(ProviderAPI.RECEIVER_KEY, dashboard.providerAPI_result_receiver); - getActivity().startService(provider_API_command); + + if(LeapSRPSession.getToken().isEmpty() && !Dashboard.preferences.getBoolean(EIP.ALLOWED_ANON, false)) { + dashboard.logInDialog(Bundle.EMPTY); + } else { + + Intent provider_API_command = new Intent(getActivity(), ProviderAPI.class); + if (dashboard.providerAPI_result_receiver == null) { + dashboard.providerAPI_result_receiver = new ProviderAPIResultReceiver(new Handler()); + dashboard.providerAPI_result_receiver.setReceiver(dashboard); + } + + provider_API_command.setAction(ProviderAPI.DOWNLOAD_CERTIFICATE); + provider_API_command.putExtra(ProviderAPI.RECEIVER_KEY, dashboard.providerAPI_result_receiver); + getActivity().startService(provider_API_command); + } break; } } diff --git a/app/src/main/java/se/leap/bitmaskclient/FragmentManagerEnhanced.java b/app/src/main/java/se/leap/bitmaskclient/FragmentManagerEnhanced.java new file mode 100644 index 00000000..c4844be9 --- /dev/null +++ b/app/src/main/java/se/leap/bitmaskclient/FragmentManagerEnhanced.java @@ -0,0 +1,51 @@ +/** + * Copyright (c) 2013 LEAP Encryption Access Project and contributers + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see <http://www.gnu.org/licenses/>. + */ +package se.leap.bitmaskclient; + +import android.app.Fragment; +import android.app.FragmentManager; +import android.app.FragmentTransaction; + +public class FragmentManagerEnhanced { + + private FragmentManager generic_fragment_manager; + + public FragmentManagerEnhanced(FragmentManager generic_fragment_manager) { + this.generic_fragment_manager = generic_fragment_manager; + } + + public FragmentTransaction removePreviousFragment(String tag) { + FragmentTransaction transaction = generic_fragment_manager.beginTransaction(); + Fragment previous_fragment = generic_fragment_manager.findFragmentByTag(tag); + if (previous_fragment != null) { + transaction.remove(previous_fragment); + } + transaction.addToBackStack(null); + + return transaction; + } + + public void replace(int containerViewId, Fragment fragment, String tag) { + FragmentTransaction transaction = generic_fragment_manager.beginTransaction(); + + transaction.replace(containerViewId, fragment, tag).commit(); + } + + public Fragment findFragmentByTag(String tag) { + return generic_fragment_manager.findFragmentByTag(tag); + } +} diff --git a/app/src/main/java/se/leap/bitmaskclient/LeapHttpClient.java b/app/src/main/java/se/leap/bitmaskclient/LeapHttpClient.java deleted file mode 100644 index 885b5105..00000000 --- a/app/src/main/java/se/leap/bitmaskclient/LeapHttpClient.java +++ /dev/null @@ -1,77 +0,0 @@ -/** - * Copyright (c) 2013 LEAP Encryption Access Project and contributers - * - * This program is free software: you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation, either version 3 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program. If not, see <http://www.gnu.org/licenses/>. - */ - package se.leap.bitmaskclient; - -import java.security.KeyStore; - -import org.apache.http.conn.ClientConnectionManager; -import org.apache.http.conn.scheme.PlainSocketFactory; -import org.apache.http.conn.scheme.Scheme; -import org.apache.http.conn.scheme.SchemeRegistry; -import org.apache.http.conn.ssl.SSLSocketFactory; -import org.apache.http.impl.client.DefaultHttpClient; -import org.apache.http.impl.conn.SingleClientConnManager; -import android.content.Context; - -/** - * Implements an HTTP client, enabling LEAP Android app to manage its own runtime keystore or bypass default Android security measures. - * - * @author rafa - * - */ -public class LeapHttpClient extends DefaultHttpClient { - - private static LeapHttpClient client; - - /** - * If the class scope client is null, it creates one and imports, if existing, the main certificate from Shared Preferences. - * @param context - * @return the new client. - */ - public static LeapHttpClient getInstance(String cert_string) { - if(client == null) { - if(cert_string != null) { - ConfigHelper.addTrustedCertificate("provider_ca_certificate", cert_string); - } - } - return client; - } - - @Override - protected ClientConnectionManager createClientConnectionManager() { - SchemeRegistry registry = new SchemeRegistry(); - registry.register(new Scheme("http", PlainSocketFactory.getSocketFactory(), 80)); - registry.register(new Scheme("https", newSslSocketFactory(), 443)); - - return new SingleClientConnManager(getParams(), registry); - } - - /** - * Uses keystore from ConfigHelper for the SSLSocketFactory. - * @return - */ - private SSLSocketFactory newSslSocketFactory() { - try { - KeyStore trusted = ConfigHelper.getKeystore(); - SSLSocketFactory sf = new SSLSocketFactory(trusted); - - return sf; - } catch (Exception e) { - throw new AssertionError(e); - } - } -} diff --git a/app/src/main/java/se/leap/bitmaskclient/LeapSRPSession.java b/app/src/main/java/se/leap/bitmaskclient/LeapSRPSession.java index 29b429d1..a953a710 100644 --- a/app/src/main/java/se/leap/bitmaskclient/LeapSRPSession.java +++ b/app/src/main/java/se/leap/bitmaskclient/LeapSRPSession.java @@ -63,15 +63,16 @@ public class LeapSRPSession { private static int A_LEN; + /** Creates a new SRP server session object from the username, password verifier, @param username, the user ID @param password, the user clear text password @param params, the SRP parameters for the session */ - public LeapSRPSession(String username, String password, SRPParameters params) + public LeapSRPSession(String username, String password) { - this(username, password, params, null); + this(username, password, null); } /** Creates a new SRP server session object from the username, password @@ -81,9 +82,9 @@ public class LeapSRPSession { @param params, the SRP parameters for the session @param abytes, the random exponent used in the A public key */ - public LeapSRPSession(String username, String password, SRPParameters params, - byte[] abytes) { - this.params = params; + public LeapSRPSession(String username, String password, byte[] abytes) { + + params = new SRPParameters(new BigInteger(ConfigHelper.NG_1024, 16).toByteArray(), ConfigHelper.G.toByteArray(), BigInteger.ZERO.toByteArray(), "SHA-256"); this.g = new BigInteger(1, params.g); N_bytes = ConfigHelper.trim(params.N); this.N = new BigInteger(1, N_bytes); @@ -159,7 +160,7 @@ public class LeapSRPSession { public byte[] calculateNewSalt() { try { BigInteger salt = new BigInteger(64, SecureRandom.getInstance("SHA1PRNG")); - return salt.toByteArray(); + return ConfigHelper.trim(salt.toByteArray()); } catch(NoSuchAlgorithmException e) { e.printStackTrace(); } diff --git a/app/src/main/java/se/leap/bitmaskclient/LogInDialog.java b/app/src/main/java/se/leap/bitmaskclient/LogInDialog.java index 45d3a373..5a0c9a6d 100644 --- a/app/src/main/java/se/leap/bitmaskclient/LogInDialog.java +++ b/app/src/main/java/se/leap/bitmaskclient/LogInDialog.java @@ -42,15 +42,10 @@ import android.widget.TextView; * @author parmegv * */ -public class LogInDialog extends DialogFragment { +public class LogInDialog extends SessionDialogInterface { - final public static String TAG = "logInDialog"; - final public static String VERB = "log in"; - final public static String USERNAME = "username"; - final public static String PASSWORD = "password"; - final public static String USERNAME_MISSING = "username missing"; - final public static String PASSWORD_INVALID_LENGTH = "password_invalid_length"; + final public static String TAG = LogInDialog.class.getSimpleName(); private static boolean is_eip_pending = false; @@ -93,7 +88,7 @@ public class LogInDialog extends DialogFragment { String username = username_field.getText().toString(); String password = password_field.getText().toString(); dialog.dismiss(); - interface_with_Dashboard.authenticate(username, password); + interface_with_Dashboard.logIn(username, password); } }) .setNegativeButton(R.string.cancel, new DialogInterface.OnClickListener() { @@ -120,7 +115,7 @@ public class LogInDialog extends DialogFragment { * */ public interface LogInDialogInterface { - public void authenticate(String username, String password); + public void logIn(String username, String password); public void cancelAuthedEipOn(); public void signUp(String username, String password); public void cancelLoginOrSignup(); @@ -149,8 +144,8 @@ public class LogInDialog extends DialogFragment { @Override public void onCancel(DialogInterface dialog) { + super.onCancel(dialog); if(is_eip_pending) interface_with_Dashboard.cancelAuthedEipOn(); - super.onCancel(dialog); } } diff --git a/app/src/main/java/se/leap/bitmaskclient/Provider.java b/app/src/main/java/se/leap/bitmaskclient/Provider.java index 5326709f..8d6385e0 100644 --- a/app/src/main/java/se/leap/bitmaskclient/Provider.java +++ b/app/src/main/java/se/leap/bitmaskclient/Provider.java @@ -52,6 +52,7 @@ public final class Provider implements Serializable { KEY = "provider", CA_CERT = "ca_cert", CA_CERT_URI = "ca_cert_uri", + CA_CERT_FINGERPRINT = "ca_cert_fingerprint", NAME = "name", DESCRIPTION = "description", DOMAIN = "domain", diff --git a/app/src/main/java/se/leap/bitmaskclient/ProviderAPIResultReceiver.java b/app/src/main/java/se/leap/bitmaskclient/ProviderAPIResultReceiver.java index 7b256124..7e4e95d3 100644 --- a/app/src/main/java/se/leap/bitmaskclient/ProviderAPIResultReceiver.java +++ b/app/src/main/java/se/leap/bitmaskclient/ProviderAPIResultReceiver.java @@ -14,7 +14,7 @@ * You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
- package se.leap.bitmaskclient;
+package se.leap.bitmaskclient;
import android.os.Bundle;
import android.os.Handler;
diff --git a/app/src/main/java/se/leap/bitmaskclient/SessionDialogInterface.java b/app/src/main/java/se/leap/bitmaskclient/SessionDialogInterface.java new file mode 100644 index 00000000..7b08a4d1 --- /dev/null +++ b/app/src/main/java/se/leap/bitmaskclient/SessionDialogInterface.java @@ -0,0 +1,39 @@ +/** + * Copyright (c) 2013 LEAP Encryption Access Project and contributers + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see <http://www.gnu.org/licenses/>. + */ +package se.leap.bitmaskclient; + +import android.app.Activity; +import android.app.AlertDialog; +import android.app.DialogFragment; +import android.content.DialogInterface; +import android.os.Bundle; + +/** + * @author parmegv + */ +public abstract class SessionDialogInterface extends DialogFragment { + final public static String USERNAME = "username"; + final public static String PASSWORD = "password"; + final public static String USERNAME_MISSING = "username missing"; + final public static String PASSWORD_INVALID_LENGTH = "password_invalid_length"; + + @Override + public void onAttach(Activity activity) { super.onAttach(activity); } + + @Override + public void onCancel(DialogInterface dialog) { super.onCancel(dialog); } +} diff --git a/app/src/main/java/se/leap/bitmaskclient/SignUpDialog.java b/app/src/main/java/se/leap/bitmaskclient/SignUpDialog.java index 120d4eec..3cb41f4f 100644 --- a/app/src/main/java/se/leap/bitmaskclient/SignUpDialog.java +++ b/app/src/main/java/se/leap/bitmaskclient/SignUpDialog.java @@ -42,14 +42,9 @@ import android.widget.TextView; * @author parmegv * */ -public class SignUpDialog extends DialogFragment { - - final public static String TAG = "signUpDialog"; - final public static String VERB = "log in"; - final public static String USERNAME = "username"; - final public static String PASSWORD = "password"; - final public static String USERNAME_MISSING = "username missing"; - final public static String PASSWORD_INVALID_LENGTH = "password_invalid_length"; +public class SignUpDialog extends SessionDialogInterface { + + final public static String TAG = SignUpDialog.class.getSimpleName(); private static boolean is_eip_pending = false; diff --git a/app/src/main/java/se/leap/bitmaskclient/VoidVpnLauncher.java b/app/src/main/java/se/leap/bitmaskclient/VoidVpnLauncher.java new file mode 100644 index 00000000..3b286fbf --- /dev/null +++ b/app/src/main/java/se/leap/bitmaskclient/VoidVpnLauncher.java @@ -0,0 +1,37 @@ +package se.leap.bitmaskclient; + +import android.app.Activity; +import android.content.Intent; +import android.net.VpnService; +import android.os.Bundle; + +public class VoidVpnLauncher extends Activity { + + private static final int VPN_USER_PERMISSION = 71; + + @Override + protected void onCreate(Bundle savedInstanceState) { + super.onCreate(savedInstanceState); + setUp(); + } + + public void setUp() { + Intent blocking_intent = VpnService.prepare(getApplicationContext()); // stops the VPN connection created by another application. + if(blocking_intent != null) + startActivityForResult(blocking_intent, VPN_USER_PERMISSION); + else { + onActivityResult(VPN_USER_PERMISSION, RESULT_OK, null); + } + } + + protected void onActivityResult(int requestCode, int resultCode, Intent data){ + if(requestCode == VPN_USER_PERMISSION) { + if(resultCode == RESULT_OK) { + Intent void_vpn_service = new Intent(getApplicationContext(), VoidVpnService.class); + void_vpn_service.setAction(VoidVpnService.START_BLOCKING_VPN_PROFILE); + startService(void_vpn_service); + } + } + finish(); + } +} diff --git a/app/src/main/java/se/leap/bitmaskclient/VoidVpnService.java b/app/src/main/java/se/leap/bitmaskclient/VoidVpnService.java new file mode 100644 index 00000000..7b597554 --- /dev/null +++ b/app/src/main/java/se/leap/bitmaskclient/VoidVpnService.java @@ -0,0 +1,36 @@ +package se.leap.bitmaskclient; + +import android.content.Intent; +import android.os.Process; +import android.net.VpnService; +import android.util.Log; + +public class VoidVpnService extends VpnService { + + static final String START_BLOCKING_VPN_PROFILE = "se.leap.bitmaskclient.START_BLOCKING_VPN_PROFILE"; + static final String TAG = VoidVpnService.class.getSimpleName(); + + @Override + public int onStartCommand(Intent intent, int flags, int startId) { + String action = intent.getAction(); + if (action == START_BLOCKING_VPN_PROFILE) { + new Thread(new Runnable() { + public void run() { + Builder builder = new Builder(); + builder.setSession("Blocking until running"); + builder.addAddress("10.42.0.8",16); + builder.addRoute("0.0.0.0", 1); + builder.addRoute("192.168.1.0", 24); + builder.addDnsServer("10.42.0.1"); + try { + builder.establish(); + } catch (Exception e) { + e.printStackTrace(); + } + android.util.Log.d(TAG, "VoidVpnService set up"); + } + }).run(); + } + return 0; + } +} diff --git a/app/src/main/java/se/leap/bitmaskclient/VpnConfigGenerator.java b/app/src/main/java/se/leap/bitmaskclient/VpnConfigGenerator.java new file mode 100644 index 00000000..ef049a3c --- /dev/null +++ b/app/src/main/java/se/leap/bitmaskclient/VpnConfigGenerator.java @@ -0,0 +1,146 @@ +/** + * Copyright (c) 2013 LEAP Encryption Access Project and contributers + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see <http://www.gnu.org/licenses/>. + */ +package se.leap.bitmaskclient; + +import android.content.SharedPreferences; +import android.util.Log; +import java.util.Iterator; +import java.util.Vector; +import org.json.JSONArray; +import org.json.JSONObject; +import org.json.JSONException; + +import se.leap.bitmaskclient.Provider; +import se.leap.bitmaskclient.EIP; + +public class VpnConfigGenerator { + + private JSONObject general_configuration; + private JSONObject gateway; + + private static SharedPreferences preferences; + public final static String TAG = VpnConfigGenerator.class.getSimpleName(); + private final String new_line = System.getProperty("line.separator"); // Platform new line + + public VpnConfigGenerator(SharedPreferences preferences, JSONObject general_configuration, JSONObject gateway) { + this.general_configuration = general_configuration; + this.gateway = gateway; + this.preferences = preferences; + } + + public String generate() { + return + generalConfiguration() + + new_line + + gatewayConfiguration() + + new_line + + secretsConfiguration() + + new_line + + androidCustomizations(); + } + + private String generalConfiguration() { + String common_options = ""; + try { + Iterator keys = general_configuration.keys(); + Vector<Vector<String>> value = new Vector<Vector<String>>(); + while ( keys.hasNext() ){ + String key = keys.next().toString(); + + common_options += key + " "; + for ( String word : general_configuration.getString(key).split(" ") ) + common_options += word + " "; + common_options += new_line; + + } + } catch (JSONException e) { + // TODO Auto-generated catch block + e.printStackTrace(); + } + + common_options += "client"; + + return common_options; + } + + private String gatewayConfiguration() { + String remotes = ""; + + String remote = "ip_address"; + String remote_openvpn_keyword = "remote"; + String ports = "ports"; + String protos = "protocols"; + String capabilities = "capabilities"; + String udp = "udp"; + + try { + JSONArray protocolsJSON = gateway.getJSONObject(capabilities).getJSONArray(protos); + for ( int i=0; i<protocolsJSON.length(); i++ ) { + String remote_line = remote_openvpn_keyword; + remote_line += " " + gateway.getString(remote); + remote_line += " " + gateway.getJSONObject(capabilities).getJSONArray(ports).optString(0); + remote_line += " " + protocolsJSON.optString(i); + if(remote_line.endsWith(udp)) + remotes = remotes.replaceFirst(remote_openvpn_keyword, remote_line + new_line + remote_openvpn_keyword); + else + remotes += remote_line; + remotes += new_line; + } + } catch (JSONException e) { + // TODO Auto-generated catch block + e.printStackTrace(); + } + + Log.d(TAG, "remotes = " + remotes); + return remotes; + } + + private String secretsConfiguration() { + + String ca = + "<ca>" + + new_line + + preferences.getString(Provider.CA_CERT, "") + + new_line + + "</ca>"; + + String key = + "<key>" + + new_line + + preferences.getString(EIP.PRIVATE_KEY, "") + + new_line + + "</key>"; + + String openvpn_cert = + "<cert>" + + new_line + + preferences.getString(EIP.CERTIFICATE, "") + + new_line + + "</cert>"; + + return ca + new_line + key + new_line + openvpn_cert; + } + + private String androidCustomizations() { + return + "remote-cert-tls server" + + new_line + + "persist-tun" + + new_line + + "auth-retry nointeract"; + } +} |