From 381956b28a5b015767b884cff099e0956ef38d96 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Parm=C3=A9nides=20GV?= Date: Mon, 29 Jul 2013 18:33:55 +0200 Subject: LeapHttpClient verifies hostname. This fixes #3287 --- src/se/leap/leapclient/LeapHttpClient.java | 3 --- 1 file changed, 3 deletions(-) diff --git a/src/se/leap/leapclient/LeapHttpClient.java b/src/se/leap/leapclient/LeapHttpClient.java index 686d3cc0..d28476c3 100644 --- a/src/se/leap/leapclient/LeapHttpClient.java +++ b/src/se/leap/leapclient/LeapHttpClient.java @@ -65,15 +65,12 @@ public class LeapHttpClient extends DefaultHttpClient { /** * Uses keystore from ConfigHelper for the SSLSocketFactory. - * - * Sets hostname verifier to allow all hostname verifier. * @return */ private SSLSocketFactory newSslSocketFactory() { try { KeyStore trusted = ConfigHelper.getKeystore(); SSLSocketFactory sf = new SSLSocketFactory(trusted); - sf.setHostnameVerifier(SSLSocketFactory.ALLOW_ALL_HOSTNAME_VERIFIER); return sf; } catch (Exception e) { -- cgit v1.2.3 From d82b11d09ef70ac71f30188c3c89ad64b11e8703 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Parm=C3=A9nides=20GV?= Date: Mon, 29 Jul 2013 21:11:21 +0200 Subject: Backstack OK from notification bar. Pressing back after entering Dashboard from notification bar, the user goes back to home. --- src/se/leap/openvpn/OpenVpnService.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/se/leap/openvpn/OpenVpnService.java b/src/se/leap/openvpn/OpenVpnService.java index 3ac80497..47f9ca44 100644 --- a/src/se/leap/openvpn/OpenVpnService.java +++ b/src/se/leap/openvpn/OpenVpnService.java @@ -161,7 +161,7 @@ public class OpenVpnService extends VpnService implements StateListener, Callbac PendingIntent getLogPendingIntent() { // Let the configure Button show the Dashboard Intent intent = new Intent(Dashboard.getAppContext(),Dashboard.class); - intent.addFlags(Intent.FLAG_ACTIVITY_REORDER_TO_FRONT); + intent.addFlags(Intent.FLAG_ACTIVITY_CLEAR_TOP); PendingIntent startLW = PendingIntent.getActivity(getApplicationContext(), 0, intent, PendingIntent.FLAG_UPDATE_CURRENT); intent.addFlags(Intent.FLAG_ACTIVITY_REORDER_TO_FRONT); return startLW; -- cgit v1.2.3 From de28df6f62949e6142f8bc1b5363137906a6d7a3 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Parm=C3=A9nides=20GV?= Date: Tue, 30 Jul 2013 18:46:53 +0200 Subject: Retains username if login process failed. New login dialog shows the original username, so that if the user failed writing his/her password, s/he does not have to write again the username. --- src/se/leap/leapclient/Dashboard.java | 13 ++++++++----- src/se/leap/leapclient/LogInDialog.java | 8 ++++++++ src/se/leap/leapclient/ProviderAPI.java | 12 ++++++++---- 3 files changed, 24 insertions(+), 9 deletions(-) diff --git a/src/se/leap/leapclient/Dashboard.java b/src/se/leap/leapclient/Dashboard.java index 063cd3cd..6dba4ebf 100644 --- a/src/se/leap/leapclient/Dashboard.java +++ b/src/se/leap/leapclient/Dashboard.java @@ -90,7 +90,7 @@ public class Dashboard extends Activity implements LogInDialog.LogInDialogInterf buildDashboard(); if(data != null && data.hasExtra(ConfigHelper.LOG_IN)) { View view = ((ViewGroup)findViewById(android.R.id.content)).getChildAt(0); - logInDialog(view, ""); + logInDialog(view, Bundle.EMPTY); } } else if(resultCode == RESULT_CANCELED && data.hasExtra(ConfigHelper.QUIT)) { finish(); @@ -195,7 +195,7 @@ public class Dashboard extends Activity implements LogInDialog.LogInDialogInterf return true; case R.id.login_button: View view = ((ViewGroup)findViewById(android.R.id.content)).getChildAt(0); - logInDialog(view, ""); + logInDialog(view, Bundle.EMPTY); return true; case R.id.logout_button: logOut(); @@ -265,7 +265,7 @@ public class Dashboard extends Activity implements LogInDialog.LogInDialogInterf * Shows the log in dialog. * @param view from which the dialog is created. */ - public void logInDialog(View view, String user_message) { + public void logInDialog(View view, Bundle resultData) { FragmentTransaction fragment_transaction = getFragmentManager().beginTransaction(); Fragment previous_log_in_dialog = getFragmentManager().findFragmentByTag(ConfigHelper.LOG_IN_DIALOG); if (previous_log_in_dialog != null) { @@ -274,9 +274,12 @@ public class Dashboard extends Activity implements LogInDialog.LogInDialogInterf fragment_transaction.addToBackStack(null); DialogFragment newFragment = LogInDialog.newInstance(); - if(user_message != null && !user_message.isEmpty()) { + if(resultData != null && !resultData.isEmpty()) { Bundle user_message_bundle = new Bundle(); + String user_message = resultData.getString(getResources().getString(R.string.user_message)); + String username = resultData.getString(ConfigHelper.USERNAME_KEY); user_message_bundle.putString(getResources().getString(R.string.user_message), user_message); + user_message_bundle.putString(ConfigHelper.USERNAME_KEY, username); newFragment.setArguments(user_message_bundle); } newFragment.show(fragment_transaction, ConfigHelper.LOG_IN_DIALOG); @@ -316,7 +319,7 @@ public class Dashboard extends Activity implements LogInDialog.LogInDialogInterf downloadAuthedUserCertificate(session_id); } else if(resultCode == ConfigHelper.SRP_AUTHENTICATION_FAILED) { mProgressDialog.dismiss(); - logInDialog(getCurrentFocus(), resultData.getString(getResources().getString(R.string.user_message))); + logInDialog(getCurrentFocus(), resultData); } else if(resultCode == ConfigHelper.LOGOUT_SUCCESSFUL) { authed = false; invalidateOptionsMenu(); diff --git a/src/se/leap/leapclient/LogInDialog.java b/src/se/leap/leapclient/LogInDialog.java index 8b3f9e80..8e8bb65a 100644 --- a/src/se/leap/leapclient/LogInDialog.java +++ b/src/se/leap/leapclient/LogInDialog.java @@ -48,8 +48,16 @@ public class LogInDialog extends DialogFragment { if(getArguments() != null && getArguments().containsKey(getResources().getString(R.string.user_message))) { user_message.setText(getArguments().getString(getResources().getString(R.string.user_message))); } else user_message.setVisibility(View.GONE); + final EditText username_field = (EditText)log_in_dialog_view.findViewById(R.id.username_entered); + if(getArguments() != null && getArguments().containsKey(getResources().getString(R.string.user_message))) { + String username = getArguments().getString(ConfigHelper.USERNAME_KEY); + username_field.setText(username); + username_field.setHint(""); + } final EditText password_field = (EditText)log_in_dialog_view.findViewById(R.id.password_entered); + if(!username_field.getText().toString().isEmpty() && password_field.isFocusable()) + password_field.requestFocus(); builder.setView(log_in_dialog_view) .setPositiveButton(R.string.login_button, new DialogInterface.OnClickListener() { diff --git a/src/se/leap/leapclient/ProviderAPI.java b/src/se/leap/leapclient/ProviderAPI.java index 944a0e7f..d92b48fb 100644 --- a/src/se/leap/leapclient/ProviderAPI.java +++ b/src/se/leap/leapclient/ProviderAPI.java @@ -142,10 +142,7 @@ public class ProviderAPI extends IntentService { if(session_id_bundle.getBoolean(ConfigHelper.RESULT_KEY)) { receiver.send(ConfigHelper.SRP_AUTHENTICATION_SUCCESSFUL, session_id_bundle); } else { - Bundle user_message_bundle = new Bundle(); - String user_message_key = getResources().getString(R.string.user_message); - user_message_bundle.putString(user_message_key, session_id_bundle.getString(user_message_key)); - receiver.send(ConfigHelper.SRP_AUTHENTICATION_FAILED, user_message_bundle); + receiver.send(ConfigHelper.SRP_AUTHENTICATION_FAILED, session_id_bundle); } } else if ((task = task_for.getBundleExtra(ConfigHelper.LOG_OUT)) != null) { @@ -215,27 +212,34 @@ public class ProviderAPI extends IntentService { } else { session_id_bundle.putBoolean(ConfigHelper.RESULT_KEY, false); session_id_bundle.putString(getResources().getString(R.string.user_message), getResources().getString(R.string.error_bad_user_password_user_message)); + session_id_bundle.putString(ConfigHelper.USERNAME_KEY, username); } } else { session_id_bundle.putString(getResources().getString(R.string.user_message), getResources().getString(R.string.error_bad_user_password_user_message)); + session_id_bundle.putString(ConfigHelper.USERNAME_KEY, username); session_id_bundle.putBoolean(ConfigHelper.RESULT_KEY, false); } } catch (ClientProtocolException e) { session_id_bundle.putBoolean(ConfigHelper.RESULT_KEY, false); session_id_bundle.putString(getResources().getString(R.string.user_message), getResources().getString(R.string.error_client_http_user_message)); + session_id_bundle.putString(ConfigHelper.USERNAME_KEY, username); } catch (IOException e) { session_id_bundle.putBoolean(ConfigHelper.RESULT_KEY, false); session_id_bundle.putString(getResources().getString(R.string.user_message), getResources().getString(R.string.error_io_exception_user_message)); + session_id_bundle.putString(ConfigHelper.USERNAME_KEY, username); } catch (JSONException e) { session_id_bundle.putBoolean(ConfigHelper.RESULT_KEY, false); session_id_bundle.putString(getResources().getString(R.string.user_message), getResources().getString(R.string.error_json_exception_user_message)); + session_id_bundle.putString(ConfigHelper.USERNAME_KEY, username); } catch (NoSuchAlgorithmException e) { session_id_bundle.putBoolean(ConfigHelper.RESULT_KEY, false); session_id_bundle.putString(getResources().getString(R.string.user_message), getResources().getString(R.string.error_no_such_algorithm_exception_user_message)); + session_id_bundle.putString(ConfigHelper.USERNAME_KEY, username); } } else { session_id_bundle.putBoolean(ConfigHelper.RESULT_KEY, false); session_id_bundle.putString(getResources().getString(R.string.user_message), getResources().getString(R.string.error_not_valid_password_user_message)); + session_id_bundle.putString(ConfigHelper.USERNAME_KEY, username); } return session_id_bundle; -- cgit v1.2.3 From 21e71b0b8916264d7499254fb36a0ee533018224 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Parm=C3=A9nides=20GV?= Date: Thu, 1 Aug 2013 12:22:48 +0200 Subject: ProviderAPI intent receives actions and parameters. We no longer use BundleExtras named as the action ProviderAPI is intended to perform, but we standardise this name (ProviderAPI.PARAMETERS), and use setAction to pass that action string. --- src/se/leap/leapclient/ConfigHelper.java | 7 ---- src/se/leap/leapclient/ConfigurationWizard.java | 40 +++++++++++--------- src/se/leap/leapclient/Dashboard.java | 29 ++++++++------- src/se/leap/leapclient/ProviderAPI.java | 49 ++++++++++++++----------- 4 files changed, 66 insertions(+), 59 deletions(-) diff --git a/src/se/leap/leapclient/ConfigHelper.java b/src/se/leap/leapclient/ConfigHelper.java index 62ebf8f1..e139bf62 100644 --- a/src/se/leap/leapclient/ConfigHelper.java +++ b/src/se/leap/leapclient/ConfigHelper.java @@ -52,18 +52,11 @@ public class ConfigHelper { final public static String ABOUT_FRAGMENT = "aboutFragment", - DOWNLOAD_JSON_FILES_BUNDLE_EXTRA = "downloadJSONFiles", - UPDATE_PROVIDER_DOTJSON = "updateProviderDotJSON", - DOWNLOAD_NEW_PROVIDER_DOTJSON = "downloadNewProviderDotJSON", LOG_IN_DIALOG = "logInDialog", NEW_PROVIDER_DIALOG = "logInDialog", - SRP_REGISTER = "srpRegister", - SRP_AUTH = "srpAuth", M1_KEY = "M1", M2_KEY = "M2", LOG_IN = "logIn", - LOG_OUT = "logOut", - DOWNLOAD_CERTIFICATE = "downloadUserAuthedCertificate", API_VERSION_KEY = "api_version", API_RETURN_SERIAL_KEY = "serial", RESULT_KEY = "result", diff --git a/src/se/leap/leapclient/ConfigurationWizard.java b/src/se/leap/leapclient/ConfigurationWizard.java index 934e2ea0..4ddac803 100644 --- a/src/se/leap/leapclient/ConfigurationWizard.java +++ b/src/se/leap/leapclient/ConfigurationWizard.java @@ -265,14 +265,15 @@ implements ProviderListFragment.Callbacks, NewProviderDialog.NewProviderDialogIn private void downloadJSONFiles(ProviderItem provider) { Intent provider_API_command = new Intent(this, ProviderAPI.class); - Bundle method_and_parameters = new Bundle(); + Bundle parameters = new Bundle(); - method_and_parameters.putString(ConfigHelper.PROVIDER_KEY, provider.name); - method_and_parameters.putString(ConfigHelper.MAIN_CERT_KEY, provider.cert_json_url); - method_and_parameters.putString(ConfigHelper.EIP_SERVICE_KEY, provider.eip_service_json_url); - method_and_parameters.putBoolean(ConfigHelper.DANGER_ON, provider.danger_on); + parameters.putString(ConfigHelper.PROVIDER_KEY, provider.name); + parameters.putString(ConfigHelper.MAIN_CERT_KEY, provider.cert_json_url); + parameters.putString(ConfigHelper.EIP_SERVICE_KEY, provider.eip_service_json_url); + parameters.putBoolean(ConfigHelper.DANGER_ON, provider.danger_on); - provider_API_command.putExtra(ConfigHelper.DOWNLOAD_JSON_FILES_BUNDLE_EXTRA, method_and_parameters); + provider_API_command.setAction(ProviderAPI.DOWNLOAD_JSON_FILES_BUNDLE_EXTRA); + provider_API_command.putExtra(ProviderAPI.PARAMETERS, parameters); provider_API_command.putExtra(ConfigHelper.RECEIVER_KEY, providerAPI_result_receiver); startService(provider_API_command); @@ -284,11 +285,12 @@ implements ProviderListFragment.Callbacks, NewProviderDialog.NewProviderDialogIn private void downloadAnonCert() { Intent provider_API_command = new Intent(this, ProviderAPI.class); - Bundle method_and_parameters = new Bundle(); + Bundle parameters = new Bundle(); - method_and_parameters.putString(ConfigHelper.TYPE_OF_CERTIFICATE, ConfigHelper.ANON_CERTIFICATE); + parameters.putString(ConfigHelper.TYPE_OF_CERTIFICATE, ConfigHelper.ANON_CERTIFICATE); - provider_API_command.putExtra(ConfigHelper.DOWNLOAD_CERTIFICATE, method_and_parameters); + provider_API_command.setAction(ProviderAPI.DOWNLOAD_CERTIFICATE); + provider_API_command.putExtra(ProviderAPI.PARAMETERS, parameters); provider_API_command.putExtra(ConfigHelper.RECEIVER_KEY, providerAPI_result_receiver); startService(provider_API_command); @@ -332,11 +334,12 @@ implements ProviderListFragment.Callbacks, NewProviderDialog.NewProviderDialogIn public void saveAndSelectProvider(String provider_main_url, boolean danger_on) { Intent provider_API_command = new Intent(this, ProviderAPI.class); - Bundle method_and_parameters = new Bundle(); - method_and_parameters.putString(ConfigHelper.PROVIDER_MAIN_URL, provider_main_url); - method_and_parameters.putBoolean(ConfigHelper.DANGER_ON, danger_on); + Bundle parameters = new Bundle(); + parameters.putString(ConfigHelper.PROVIDER_MAIN_URL, provider_main_url); + parameters.putBoolean(ConfigHelper.DANGER_ON, danger_on); - provider_API_command.putExtra(ConfigHelper.DOWNLOAD_NEW_PROVIDER_DOTJSON, method_and_parameters); + provider_API_command.setAction(ProviderAPI.DOWNLOAD_NEW_PROVIDER_DOTJSON); + provider_API_command.putExtra(ProviderAPI.PARAMETERS, parameters); provider_API_command.putExtra(ConfigHelper.RECEIVER_KEY, providerAPI_result_receiver); startService(provider_API_command); @@ -351,12 +354,13 @@ implements ProviderListFragment.Callbacks, NewProviderDialog.NewProviderDialogIn public void updateProviderDotJson(String provider_name, String provider_json_url, boolean danger_on) { Intent provider_API_command = new Intent(this, ProviderAPI.class); - Bundle method_and_parameters = new Bundle(); - method_and_parameters.putString(ConfigHelper.PROVIDER_NAME, provider_name); - method_and_parameters.putString(ConfigHelper.PROVIDER_JSON_URL, provider_json_url); - method_and_parameters.putBoolean(ConfigHelper.DANGER_ON, danger_on); + Bundle parameters = new Bundle(); + parameters.putString(ConfigHelper.PROVIDER_NAME, provider_name); + parameters.putString(ConfigHelper.PROVIDER_JSON_URL, provider_json_url); + parameters.putBoolean(ConfigHelper.DANGER_ON, danger_on); - provider_API_command.putExtra(ConfigHelper.UPDATE_PROVIDER_DOTJSON, method_and_parameters); + provider_API_command.setAction(ProviderAPI.UPDATE_PROVIDER_DOTJSON); + provider_API_command.putExtra(ProviderAPI.PARAMETERS, parameters); provider_API_command.putExtra(ConfigHelper.RECEIVER_KEY, providerAPI_result_receiver); startService(provider_API_command); diff --git a/src/se/leap/leapclient/Dashboard.java b/src/se/leap/leapclient/Dashboard.java index 063cd3cd..b652bb73 100644 --- a/src/se/leap/leapclient/Dashboard.java +++ b/src/se/leap/leapclient/Dashboard.java @@ -213,20 +213,21 @@ public class Dashboard extends Activity implements LogInDialog.LogInDialogInterf Intent provider_API_command = new Intent(this, ProviderAPI.class); - Bundle method_and_parameters = new Bundle(); - method_and_parameters.putString(ConfigHelper.USERNAME_KEY, username); - method_and_parameters.putString(ConfigHelper.PASSWORD_KEY, password); + Bundle parameters = new Bundle(); + parameters.putString(ConfigHelper.USERNAME_KEY, username); + parameters.putString(ConfigHelper.PASSWORD_KEY, password); JSONObject provider_json; try { provider_json = new JSONObject(preferences.getString(ConfigHelper.PROVIDER_KEY, "")); - method_and_parameters.putString(ConfigHelper.API_URL_KEY, provider_json.getString(ConfigHelper.API_URL_KEY) + "/" + provider_json.getString(ConfigHelper.API_VERSION_KEY)); + parameters.putString(ConfigHelper.API_URL_KEY, provider_json.getString(ConfigHelper.API_URL_KEY) + "/" + provider_json.getString(ConfigHelper.API_VERSION_KEY)); } catch (JSONException e) { // TODO Auto-generated catch block e.printStackTrace(); } - provider_API_command.putExtra(ConfigHelper.SRP_AUTH, method_and_parameters); + provider_API_command.setAction(ProviderAPI.SRP_AUTH); + provider_API_command.putExtra(ProviderAPI.PARAMETERS, parameters); provider_API_command.putExtra(ConfigHelper.RECEIVER_KEY, providerAPI_result_receiver); if(mProgressDialog != null) mProgressDialog.dismiss(); @@ -242,18 +243,19 @@ public class Dashboard extends Activity implements LogInDialog.LogInDialogInterf providerAPI_result_receiver.setReceiver(this); Intent provider_API_command = new Intent(this, ProviderAPI.class); - Bundle method_and_parameters = new Bundle(); + Bundle parameters = new Bundle(); JSONObject provider_json; try { provider_json = new JSONObject(preferences.getString(ConfigHelper.PROVIDER_KEY, "")); - method_and_parameters.putString(ConfigHelper.API_URL_KEY, provider_json.getString(ConfigHelper.API_URL_KEY) + "/" + provider_json.getString(ConfigHelper.API_VERSION_KEY)); + parameters.putString(ConfigHelper.API_URL_KEY, provider_json.getString(ConfigHelper.API_URL_KEY) + "/" + provider_json.getString(ConfigHelper.API_VERSION_KEY)); } catch (JSONException e) { // TODO Auto-generated catch block e.printStackTrace(); } - provider_API_command.putExtra(ConfigHelper.LOG_OUT, method_and_parameters); + provider_API_command.setAction(ProviderAPI.LOG_OUT); + provider_API_command.putExtra(ProviderAPI.PARAMETERS, parameters); provider_API_command.putExtra(ConfigHelper.RECEIVER_KEY, providerAPI_result_receiver); if(mProgressDialog != null) mProgressDialog.dismiss(); @@ -292,12 +294,13 @@ public class Dashboard extends Activity implements LogInDialog.LogInDialogInterf Intent provider_API_command = new Intent(this, ProviderAPI.class); - Bundle method_and_parameters = new Bundle(); - method_and_parameters.putString(ConfigHelper.TYPE_OF_CERTIFICATE, ConfigHelper.AUTHED_CERTIFICATE); - method_and_parameters.putString(ConfigHelper.SESSION_ID_COOKIE_KEY, session_id.getName()); - method_and_parameters.putString(ConfigHelper.SESSION_ID_KEY, session_id.getValue()); + Bundle parameters = new Bundle(); + parameters.putString(ConfigHelper.TYPE_OF_CERTIFICATE, ConfigHelper.AUTHED_CERTIFICATE); + parameters.putString(ConfigHelper.SESSION_ID_COOKIE_KEY, session_id.getName()); + parameters.putString(ConfigHelper.SESSION_ID_KEY, session_id.getValue()); - provider_API_command.putExtra(ConfigHelper.DOWNLOAD_CERTIFICATE, method_and_parameters); + provider_API_command.setAction(ProviderAPI.DOWNLOAD_CERTIFICATE); + provider_API_command.putExtra(ProviderAPI.PARAMETERS, parameters); provider_API_command.putExtra(ConfigHelper.RECEIVER_KEY, providerAPI_result_receiver); startService(provider_API_command); diff --git a/src/se/leap/leapclient/ProviderAPI.java b/src/se/leap/leapclient/ProviderAPI.java index 944a0e7f..11dfabf1 100644 --- a/src/se/leap/leapclient/ProviderAPI.java +++ b/src/se/leap/leapclient/ProviderAPI.java @@ -88,6 +88,17 @@ public class ProviderAPI extends IntentService { private Handler mHandler; + final public static String + DOWNLOAD_JSON_FILES_BUNDLE_EXTRA = "downloadJSONFiles", + UPDATE_PROVIDER_DOTJSON = "updateProviderDotJSON", + DOWNLOAD_NEW_PROVIDER_DOTJSON = "downloadNewProviderDotJSON", + SRP_REGISTER = "srpRegister", + SRP_AUTH = "srpAuth", + LOG_OUT = "logOut", + DOWNLOAD_CERTIFICATE = "downloadUserAuthedCertificate", + PARAMETERS = "parameters" + ; + public ProviderAPI() { super("ProviderAPI"); Log.v("ClassName", "Provider API"); @@ -110,35 +121,33 @@ public class ProviderAPI extends IntentService { } @Override - protected void onHandleIntent(Intent task_for) { - final ResultReceiver receiver = task_for.getParcelableExtra("receiver"); + protected void onHandleIntent(Intent command) { + final ResultReceiver receiver = command.getParcelableExtra("receiver"); + String action = command.getAction(); + Bundle parameters = command.getBundleExtra(PARAMETERS); - Bundle task; - if((task = task_for.getBundleExtra(ConfigHelper.DOWNLOAD_JSON_FILES_BUNDLE_EXTRA)) != null) { - if(!downloadJsonFiles(task)) { + if(action.equalsIgnoreCase(DOWNLOAD_JSON_FILES_BUNDLE_EXTRA)) { + if(!downloadJsonFiles(parameters)) { receiver.send(ConfigHelper.INCORRECTLY_DOWNLOADED_JSON_FILES, Bundle.EMPTY); } else { receiver.send(ConfigHelper.CORRECTLY_DOWNLOADED_JSON_FILES, Bundle.EMPTY); } - } - else if ((task = task_for.getBundleExtra(ConfigHelper.UPDATE_PROVIDER_DOTJSON)) != null) { - Bundle result = updateProviderDotJSON(task); + } else if(action.equalsIgnoreCase(UPDATE_PROVIDER_DOTJSON)) { + Bundle result = updateProviderDotJSON(parameters); if(result.getBoolean(ConfigHelper.RESULT_KEY)) { receiver.send(ConfigHelper.CORRECTLY_UPDATED_PROVIDER_DOT_JSON, result); - } else { + } else { receiver.send(ConfigHelper.INCORRECTLY_UPDATED_PROVIDER_DOT_JSON, Bundle.EMPTY); } - } - else if ((task = task_for.getBundleExtra(ConfigHelper.DOWNLOAD_NEW_PROVIDER_DOTJSON)) != null) { - Bundle result = downloadNewProviderDotJSON(task); + } else if (action.equalsIgnoreCase(DOWNLOAD_NEW_PROVIDER_DOTJSON)) { + Bundle result = downloadNewProviderDotJSON(parameters); if(result.getBoolean(ConfigHelper.RESULT_KEY)) { receiver.send(ConfigHelper.CORRECTLY_UPDATED_PROVIDER_DOT_JSON, result); } else { receiver.send(ConfigHelper.INCORRECTLY_DOWNLOADED_JSON_FILES, Bundle.EMPTY); } - } - else if ((task = task_for.getBundleExtra(ConfigHelper.SRP_AUTH)) != null) { - Bundle session_id_bundle = authenticateBySRP(task); + } else if (action.equalsIgnoreCase(SRP_AUTH)) { + Bundle session_id_bundle = authenticateBySRP(parameters); if(session_id_bundle.getBoolean(ConfigHelper.RESULT_KEY)) { receiver.send(ConfigHelper.SRP_AUTHENTICATION_SUCCESSFUL, session_id_bundle); } else { @@ -147,16 +156,14 @@ public class ProviderAPI extends IntentService { user_message_bundle.putString(user_message_key, session_id_bundle.getString(user_message_key)); receiver.send(ConfigHelper.SRP_AUTHENTICATION_FAILED, user_message_bundle); } - } - else if ((task = task_for.getBundleExtra(ConfigHelper.LOG_OUT)) != null) { - if(logOut(task)) { + } else if (action.equalsIgnoreCase(LOG_OUT)) { + if(logOut(parameters)) { receiver.send(ConfigHelper.LOGOUT_SUCCESSFUL, Bundle.EMPTY); } else { receiver.send(ConfigHelper.LOGOUT_FAILED, Bundle.EMPTY); } - } - else if ((task = task_for.getBundleExtra(ConfigHelper.DOWNLOAD_CERTIFICATE)) != null) { - if(getNewCert(task)) { + } else if (action.equalsIgnoreCase(DOWNLOAD_CERTIFICATE)) { + if(getNewCert(parameters)) { receiver.send(ConfigHelper.CORRECTLY_DOWNLOADED_CERTIFICATE, Bundle.EMPTY); } else { receiver.send(ConfigHelper.INCORRECTLY_DOWNLOADED_CERTIFICATE, Bundle.EMPTY); -- cgit v1.2.3 From 17903a5221f66d18e90119590c1a29b1f418cafd Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Parm=C3=A9nides=20GV?= Date: Sat, 3 Aug 2013 11:42:15 +0200 Subject: FileNotFoundException catched in all downloads. Added a new catch block in all downloads methods. --- src/se/leap/leapclient/ProviderAPI.java | 13 +++++++++++++ 1 file changed, 13 insertions(+) diff --git a/src/se/leap/leapclient/ProviderAPI.java b/src/se/leap/leapclient/ProviderAPI.java index 944a0e7f..b7df172a 100644 --- a/src/se/leap/leapclient/ProviderAPI.java +++ b/src/se/leap/leapclient/ProviderAPI.java @@ -17,6 +17,7 @@ package se.leap.leapclient; import java.io.ByteArrayInputStream; +import java.io.FileNotFoundException; import java.io.IOException; import java.io.InputStream; import java.math.BigInteger; @@ -407,6 +408,9 @@ public class ProviderAPI extends IntentService { displayToast(R.string.malformed_url); } catch(SocketTimeoutException e) { displayToast(R.string.server_is_down_message); + } catch (FileNotFoundException e) { + e.printStackTrace(); + displayToast(R.string.server_is_down_message); } catch (IOException e) { if(provider_url != null) { json_file_content = getStringFromProviderWithCACertAdded(provider_url, danger_on); @@ -447,6 +451,9 @@ public class ProviderAPI extends IntentService { json_string = new Scanner(urlConnection.getInputStream()).useDelimiter("\\A").next(); } catch (MalformedURLException e) { displayToast(R.string.malformed_url); + } catch (FileNotFoundException e) { + e.printStackTrace(); + displayToast(R.string.server_is_down_message); } catch (IOException e) { json_string = getStringFromProviderIgnoringCertificate(string_url); } @@ -499,6 +506,9 @@ public class ProviderAPI extends IntentService { e.printStackTrace(); } catch (UnknownHostException e) { displayToast(R.string.server_is_down_message); + } catch (FileNotFoundException e) { + e.printStackTrace(); + displayToast(R.string.server_is_down_message); } catch (IOException e) { // The downloaded certificate doesn't validate our https connection. if(danger_on) { @@ -552,6 +562,9 @@ public class ProviderAPI extends IntentService { }); string = new Scanner(urlConnection.getInputStream()).useDelimiter("\\A").next(); System.out.println("String ignoring certificate = " + string); + } catch (FileNotFoundException e) { + e.printStackTrace(); + displayToast(R.string.server_is_down_message); } catch (IOException e) { // The downloaded certificate doesn't validate our https connection. e.printStackTrace(); -- cgit v1.2.3 From 9d8bbb7f806757fd62cbba886af111278e625774 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Parm=C3=A9nides=20GV?= Date: Sat, 3 Aug 2013 12:19:19 +0200 Subject: EIP fragment is replaced if provider is switched. We were checking if eip existed before adding it again, but that check can be removed if we make a replace instead of an add. --- src/se/leap/leapclient/Dashboard.java | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/se/leap/leapclient/Dashboard.java b/src/se/leap/leapclient/Dashboard.java index 063cd3cd..d81c3def 100644 --- a/src/se/leap/leapclient/Dashboard.java +++ b/src/se/leap/leapclient/Dashboard.java @@ -141,9 +141,9 @@ public class Dashboard extends Activity implements LogInDialog.LogInDialogInterf providerNameTV.setTextSize(28); FragmentManager fragMan = getFragmentManager(); - if ( provider.hasEIP() && fragMan.findFragmentByTag(TAG_EIP_FRAGMENT) == null){ + if ( provider.hasEIP()){ EipServiceFragment eipFragment = new EipServiceFragment(); - fragMan.beginTransaction().add(R.id.servicesCollection, eipFragment, TAG_EIP_FRAGMENT).commit(); + fragMan.beginTransaction().replace(R.id.servicesCollection, eipFragment, TAG_EIP_FRAGMENT).commit(); } } -- cgit v1.2.3 From 2e85b3c70fa6f1b74b51fec4666cc3f1407688cb Mon Sep 17 00:00:00 2001 From: Sean Leonard Date: Tue, 13 Aug 2013 12:10:58 -0600 Subject: Disallow export of EIP service Intents --- AndroidManifest.xml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/AndroidManifest.xml b/AndroidManifest.xml index 9833032c..320d4fc4 100644 --- a/AndroidManifest.xml +++ b/AndroidManifest.xml @@ -154,7 +154,7 @@ android:label="@string/title_activity_configuration_wizard" > - + -- cgit v1.2.3 From b376b820640ed9f097c3d62011c5e9cf2462304b Mon Sep 17 00:00:00 2001 From: Sean Leonard Date: Tue, 13 Aug 2013 14:30:49 -0600 Subject: Use java.security classes to validate string certificates and keys from provider --- src/se/leap/leapclient/ConfigHelper.java | 31 ++++++++++++++++ src/se/leap/leapclient/ProviderAPI.java | 62 ++++++++++++++++++++------------ 2 files changed, 71 insertions(+), 22 deletions(-) diff --git a/src/se/leap/leapclient/ConfigHelper.java b/src/se/leap/leapclient/ConfigHelper.java index e139bf62..fd7e527f 100644 --- a/src/se/leap/leapclient/ConfigHelper.java +++ b/src/se/leap/leapclient/ConfigHelper.java @@ -23,12 +23,18 @@ import java.io.FileNotFoundException; import java.io.IOException; import java.math.BigInteger; import java.io.InputStream; +import java.security.KeyFactory; import java.security.KeyStore; import java.security.KeyStoreException; import java.security.NoSuchAlgorithmException; +import java.security.NoSuchProviderException; +import java.security.PrivateKey; import java.security.cert.CertificateException; import java.security.cert.CertificateFactory; import java.security.cert.X509Certificate; +import java.security.interfaces.RSAPrivateKey; +import java.security.spec.InvalidKeySpecException; +import java.security.spec.PKCS8EncodedKeySpec; import org.json.JSONException; import org.json.JSONObject; @@ -315,6 +321,31 @@ public class ConfigHelper { return (X509Certificate) certificate; } + + protected static RSAPrivateKey parseRsaKeyFromString(String RsaKeyString) { + RSAPrivateKey key = null; + try { + KeyFactory kf = KeyFactory.getInstance("RSA", "BC"); + + RsaKeyString = RsaKeyString.replaceFirst("-----BEGIN RSA PRIVATE KEY-----", "").replaceFirst("-----END RSA PRIVATE KEY-----", ""); + PKCS8EncodedKeySpec keySpec = new PKCS8EncodedKeySpec( Base64.decode(RsaKeyString, Base64.DEFAULT) ); + key = (RSAPrivateKey) kf.generatePrivate(keySpec); + } catch (InvalidKeySpecException e) { + // TODO Auto-generated catch block + e.printStackTrace(); + return null; + } catch (NoSuchAlgorithmException e) { + // TODO Auto-generated catch block + e.printStackTrace(); + return null; + } catch (NoSuchProviderException e) { + // TODO Auto-generated catch block + e.printStackTrace(); + return null; + } + + return key; + } /** * Adds a new X509 certificate given its input stream and its provider name diff --git a/src/se/leap/leapclient/ProviderAPI.java b/src/se/leap/leapclient/ProviderAPI.java index dc0b2aa6..935d6a87 100644 --- a/src/se/leap/leapclient/ProviderAPI.java +++ b/src/se/leap/leapclient/ProviderAPI.java @@ -16,20 +16,9 @@ */ package se.leap.leapclient; -import java.io.ByteArrayInputStream; import java.io.FileNotFoundException; import java.io.IOException; -import java.io.InputStream; import java.math.BigInteger; -import java.security.KeyManagementException; -import java.security.KeyStore; -import java.security.KeyStoreException; -import java.security.NoSuchAlgorithmException; -import java.security.cert.CertificateException; -import java.security.cert.CertificateFactory; -import java.security.cert.X509Certificate; -import java.security.SecureRandom; -import javax.net.ssl.KeyManager; import java.net.CookieHandler; import java.net.CookieManager; import java.net.HttpCookie; @@ -39,14 +28,23 @@ import java.net.URISyntaxException; import java.net.URL; import java.net.URLConnection; import java.net.UnknownHostException; +import java.security.KeyManagementException; +import java.security.KeyStore; +import java.security.KeyStoreException; +import java.security.NoSuchAlgorithmException; +import java.security.SecureRandom; +import java.security.cert.CertificateException; +import java.security.cert.X509Certificate; +import java.security.interfaces.RSAPrivateKey; import java.util.Scanner; import javax.net.ssl.HostnameVerifier; import javax.net.ssl.HttpsURLConnection; +import javax.net.ssl.KeyManager; import javax.net.ssl.SSLContext; import javax.net.ssl.SSLSession; -import javax.net.ssl.TrustManagerFactory; import javax.net.ssl.TrustManager; +import javax.net.ssl.TrustManagerFactory; import javax.net.ssl.X509TrustManager; import org.apache.http.HttpEntity; @@ -66,7 +64,6 @@ import org.json.JSONException; import org.json.JSONObject; import se.leap.leapclient.ProviderListContent.ProviderItem; - import android.app.IntentService; import android.content.Intent; import android.os.Bundle; @@ -180,12 +177,19 @@ public class ProviderAPI extends IntentService { boolean danger_on = task.getBoolean(ConfigHelper.DANGER_ON); try { String cert_string = getStringFromProvider(cert_url, danger_on); - ConfigHelper.saveSharedPref(ConfigHelper.MAIN_CERT_KEY, cert_string); + X509Certificate certCert = ConfigHelper.parseX509CertificateFromString(cert_string); + cert_string = Base64.encodeToString( certCert.getEncoded(), Base64.DEFAULT); + ConfigHelper.saveSharedPref(ConfigHelper.MAIN_CERT_KEY, "-----BEGIN CERTIFICATE-----\n"+cert_string+"-----END CERTIFICATE-----"); + JSONObject eip_service_json = getJSONFromProvider(eip_service_json_url, danger_on); ConfigHelper.saveSharedPref(ConfigHelper.EIP_SERVICE_KEY, eip_service_json); return true; } catch (JSONException e) { return false; + } catch (CertificateException e) { + // TODO Auto-generated catch block + e.printStackTrace(); + return false; } } @@ -726,17 +730,31 @@ public class ProviderAPI extends IntentService { String cert_string = getStringFromProvider(new_cert_string_url, danger_on); if(!cert_string.isEmpty()) { // API returns concatenated cert & key. Split them for OpenVPN options - String certificate = null, key = null; + String certificateString = null, keyString = null; String[] certAndKey = cert_string.split("(?<=-\n)"); for (int i=0; i < certAndKey.length-1; i++){ - if ( certAndKey[i].contains("KEY") ) - key = certAndKey[i++] + certAndKey[i]; - else if ( certAndKey[i].contains("CERTIFICATE") ) - certificate = certAndKey[i++] + certAndKey[i]; + if ( certAndKey[i].contains("KEY") ) { + keyString = certAndKey[i++] + certAndKey[i]; + } + else if ( certAndKey[i].contains("CERTIFICATE") ) { + certificateString = certAndKey[i++] + certAndKey[i]; + } + } + try { + RSAPrivateKey keyCert = ConfigHelper.parseRsaKeyFromString(keyString); + keyString = Base64.encodeToString( keyCert.getEncoded(), Base64.DEFAULT ); + ConfigHelper.saveSharedPref(ConfigHelper.KEY_KEY, "-----BEGIN RSA PRIVATE KEY-----\n"+keyString+"-----END RSA PRIVATE KEY-----"); + + X509Certificate certCert = ConfigHelper.parseX509CertificateFromString(certificateString); + certificateString = Base64.encodeToString( certCert.getEncoded(), Base64.DEFAULT); + ConfigHelper.saveSharedPref(ConfigHelper.CERT_KEY, "-----BEGIN CERTIFICATE-----\n"+certificateString+"-----END CERTIFICATE-----"); + + return true; + } catch (CertificateException e) { + // TODO Auto-generated catch block + e.printStackTrace(); + return false; } - ConfigHelper.saveSharedPref(ConfigHelper.CERT_KEY, certificate); - ConfigHelper.saveSharedPref(ConfigHelper.KEY_KEY, key); - return true; } else { return false; } -- cgit v1.2.3 From a21b15ec7ac4c9eb2ce73e370cdce25359491634 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Parm=C3=A9nides=20GV?= Date: Wed, 14 Aug 2013 09:52:35 +0200 Subject: Assets providers have danger_on "false". --- src/se/leap/leapclient/ConfigurationWizard.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/se/leap/leapclient/ConfigurationWizard.java b/src/se/leap/leapclient/ConfigurationWizard.java index 4ddac803..05338bf4 100644 --- a/src/se/leap/leapclient/ConfigurationWizard.java +++ b/src/se/leap/leapclient/ConfigurationWizard.java @@ -216,7 +216,7 @@ implements ProviderListFragment.Callbacks, NewProviderDialog.NewProviderDialogIn boolean custom = false; provider_name = url_filepath.subSequence(0, url_filepath.indexOf(".")).toString(); if(ProviderListContent.ITEMS.isEmpty()) //TODO I have to implement a way of checking if a provider new or is already present in that ITEMS list - ProviderListContent.addItem(new ProviderItem(provider_name, asset_manager.open(url_files_folder + "/" + url_filepath), custom, true)); // By default, it trusts the provider + ProviderListContent.addItem(new ProviderItem(provider_name, asset_manager.open(url_files_folder + "/" + url_filepath), custom, false)); loaded_preseeded_providers = true; } } catch (IOException e) { -- cgit v1.2.3 From 98348e2e3b6f02aafbe9756bdebbf27f66ab494f Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Parm=C3=A9nides=20GV?= Date: Mon, 5 Aug 2013 11:33:02 +0200 Subject: Renamed certificate handling methods. I still let one method to bypass hostname verifier, otherwise dev.bm will not work. I've reduced downloading functions to 3: download without CA, download with commercial CA and download with provider CA. I only download CA cert once, when the user selects the corresponding provider. Each time a user switch provider, the cert is downloaded (along with other json files). --- src/se/leap/leapclient/LeapHttpClient.java | 2 +- src/se/leap/leapclient/ProviderAPI.java | 173 ++++++----------------------- 2 files changed, 34 insertions(+), 141 deletions(-) diff --git a/src/se/leap/leapclient/LeapHttpClient.java b/src/se/leap/leapclient/LeapHttpClient.java index d28476c3..ed926d28 100644 --- a/src/se/leap/leapclient/LeapHttpClient.java +++ b/src/se/leap/leapclient/LeapHttpClient.java @@ -48,7 +48,7 @@ public class LeapHttpClient extends DefaultHttpClient { client = new LeapHttpClient(context); String cert_string = ConfigHelper.getStringFromSharedPref(ConfigHelper.MAIN_CERT_KEY); if(cert_string != null) { - ConfigHelper.addTrustedCertificate("recovered_certificate", cert_string); + ConfigHelper.addTrustedCertificate("provider_ca_certificate", cert_string); } } return client; diff --git a/src/se/leap/leapclient/ProviderAPI.java b/src/se/leap/leapclient/ProviderAPI.java index 935d6a87..645b5e29 100644 --- a/src/se/leap/leapclient/ProviderAPI.java +++ b/src/se/leap/leapclient/ProviderAPI.java @@ -176,13 +176,14 @@ public class ProviderAPI extends IntentService { String eip_service_json_url = task.getString(ConfigHelper.EIP_SERVICE_KEY); boolean danger_on = task.getBoolean(ConfigHelper.DANGER_ON); try { - String cert_string = getStringFromProvider(cert_url, danger_on); + String cert_string = downloadWithCommercialCA(cert_url, danger_on); X509Certificate certCert = ConfigHelper.parseX509CertificateFromString(cert_string); cert_string = Base64.encodeToString( certCert.getEncoded(), Base64.DEFAULT); ConfigHelper.saveSharedPref(ConfigHelper.MAIN_CERT_KEY, "-----BEGIN CERTIFICATE-----\n"+cert_string+"-----END CERTIFICATE-----"); - JSONObject eip_service_json = getJSONFromProvider(eip_service_json_url, danger_on); - ConfigHelper.saveSharedPref(ConfigHelper.EIP_SERVICE_KEY, eip_service_json); + String eip_service_string = downloadWithCommercialCA(eip_service_json_url, danger_on); + ConfigHelper.saveSharedPref(ConfigHelper.EIP_SERVICE_KEY, new JSONObject(eip_service_string)); + return true; } catch (JSONException e) { return false; @@ -343,10 +344,11 @@ public class ProviderAPI extends IntentService { String provider_name = task.getString(ConfigHelper.PROVIDER_NAME); try { - JSONObject provider_json = getJSONFromProvider(provider_json_url, danger_on); - if(provider_json == null) { + String provider_dot_json_string = downloadWithCommercialCA(provider_json_url, danger_on); + if(provider_dot_json_string.isEmpty()) { result.putBoolean(ConfigHelper.RESULT_KEY, false); - } else { + } else { + JSONObject provider_json = new JSONObject(provider_dot_json_string); ConfigHelper.saveSharedPref(ConfigHelper.ALLOWED_ANON, provider_json.getJSONObject(ConfigHelper.SERVICE_KEY).getBoolean(ConfigHelper.ALLOWED_ANON)); //ProviderListContent.addItem(new ProviderItem(provider_name, provider_json_url, provider_json, custom, danger_on)); @@ -375,12 +377,12 @@ public class ProviderAPI extends IntentService { String provider_name = provider_main_url.replaceFirst("http[s]?://", "").replaceFirst("\\/", "_"); String provider_json_url = guessProviderDotJsonURL(provider_main_url); - JSONObject provider_json; + String provider_json_string = downloadWithCommercialCA(provider_json_url, danger_on); try { - provider_json = getJSONFromProvider(provider_json_url, danger_on); - if(provider_json == null) { + if(provider_json_string.isEmpty()) { result.putBoolean(ConfigHelper.RESULT_KEY, false); } else { + JSONObject provider_json = new JSONObject(provider_json_string); ConfigHelper.saveSharedPref(ConfigHelper.PROVIDER_KEY, provider_json); ConfigHelper.saveSharedPref(ConfigHelper.DANGER_ON, danger_on); @@ -401,14 +403,14 @@ public class ProviderAPI extends IntentService { } /** - * Tries to download whatever is pointed by the string_url. + * Tries to download the contents of the provided url using commercially validated CA certificate from chosen provider. * * If danger_on flag is true, SSL exceptions will be managed by futher methods that will try to use some bypass methods. * @param string_url * @param danger_on if the user completely trusts this provider * @return */ - private String getStringFromProvider(String string_url, boolean danger_on) { + private String downloadWithCommercialCA(String string_url, boolean danger_on) { String json_file_content = ""; @@ -428,13 +430,13 @@ public class ProviderAPI extends IntentService { displayToast(R.string.server_is_down_message); } catch (IOException e) { if(provider_url != null) { - json_file_content = getStringFromProviderWithCACertAdded(provider_url, danger_on); + json_file_content = downloadWithProviderCA(provider_url, danger_on); } else { displayToast(R.string.certificate_error); } } catch (Exception e) { if(provider_url != null && danger_on) { - json_file_content = getStringFromProviderWithCACertAdded(provider_url, danger_on); + json_file_content = downloadWithProviderCA(provider_url, danger_on); } } @@ -442,65 +444,24 @@ public class ProviderAPI extends IntentService { } /** - * Tries to download a string from given url without verifying the hostname. - * - * If a IOException still occurs, it tries with another bypass method: getStringFromProviderWithCACertAdded. - * @param string_url - * @return an empty string if everything fails, the url content if not. - */ - private String getStringFromProviderWithoutValidate( - URL string_url) { - - String json_string = ""; - HostnameVerifier hostnameVerifier = new HostnameVerifier() { - @Override - public boolean verify(String hostname, SSLSession session) { - return true; - } - }; - - try { - HttpsURLConnection urlConnection = - (HttpsURLConnection)string_url.openConnection(); - urlConnection.setHostnameVerifier(hostnameVerifier); - json_string = new Scanner(urlConnection.getInputStream()).useDelimiter("\\A").next(); - } catch (MalformedURLException e) { - displayToast(R.string.malformed_url); - } catch (FileNotFoundException e) { - e.printStackTrace(); - displayToast(R.string.server_is_down_message); - } catch (IOException e) { - json_string = getStringFromProviderIgnoringCertificate(string_url); - } - - return json_string; - } - - /** - * Tries to download the contents of the provided url using main certificate from choosen provider. + * Tries to download the contents of the provided url using not commercially validated CA certificate from chosen provider. * @param url * @param danger_on true to download CA certificate in case it has not been downloaded. * @return an empty string if it fails, the url content if not. */ - private String getStringFromProviderWithCACertAdded(URL url, boolean danger_on) { + private String downloadWithProviderCA(URL url, boolean danger_on) { String json_file_content = ""; - // Load CAs from an InputStream - // (could be from a resource or ByteArrayInputStream or ...) - String cert_string = ConfigHelper.getStringFromSharedPref(ConfigHelper.MAIN_CERT_KEY); - if(cert_string.isEmpty() && danger_on) { - cert_string = downloadCertificateWithoutTrusting(url.getProtocol() + "://" + url.getHost() + "/" + "ca.crt"); - ConfigHelper.saveSharedPref(ConfigHelper.MAIN_CERT_KEY, cert_string); - } + String provider_cert_string = ConfigHelper.getStringFromSharedPref(ConfigHelper.MAIN_CERT_KEY); try { - java.security.cert.Certificate dangerous_certificate = ConfigHelper.parseX509CertificateFromString(cert_string); + java.security.cert.Certificate provider_certificate = ConfigHelper.parseX509CertificateFromString(provider_cert_string); // Create a KeyStore containing our trusted CAs String keyStoreType = KeyStore.getDefaultType(); KeyStore keyStore = KeyStore.getInstance(keyStoreType); keyStore.load(null, null); - keyStore.setCertificateEntry("provider_ca_certificate", dangerous_certificate); + keyStore.setCertificateEntry("provider_ca_certificate", provider_certificate); // Create a TrustManager that trusts the CAs in our KeyStore String tmfAlgorithm = TrustManagerFactory.getDefaultAlgorithm(); @@ -527,7 +488,7 @@ public class ProviderAPI extends IntentService { } catch (IOException e) { // The downloaded certificate doesn't validate our https connection. if(danger_on) { - json_file_content = getStringFromProviderWithoutValidate(url); + json_file_content = downloadWithoutCA(url); } else { displayToast(R.string.certificate_error); } @@ -545,11 +506,19 @@ public class ProviderAPI extends IntentService { } /** - * Downloads the string that's in the url without regarding certificate validity + * Downloads the string that's in the url with any certificate. */ - private String getStringFromProviderIgnoringCertificate(URL url) { + private String downloadWithoutCA(URL url) { String string = ""; try { + + HostnameVerifier hostnameVerifier = new HostnameVerifier() { + @Override + public boolean verify(String hostname, SSLSession session) { + return true; + } + }; + class DefaultTrustManager implements X509TrustManager { @Override @@ -569,12 +538,7 @@ public class ProviderAPI extends IntentService { HttpsURLConnection urlConnection = (HttpsURLConnection)url.openConnection(); urlConnection.setSSLSocketFactory(context.getSocketFactory()); - urlConnection.setHostnameVerifier(new HostnameVerifier() { - @Override - public boolean verify(String arg0, SSLSession arg1) { - return true; - } - }); + urlConnection.setHostnameVerifier(hostnameVerifier); string = new Scanner(urlConnection.getInputStream()).useDelimiter("\\A").next(); System.out.println("String ignoring certificate = " + string); } catch (FileNotFoundException e) { @@ -594,77 +558,6 @@ public class ProviderAPI extends IntentService { return string; } - /** - * Downloads the certificate from the parameter url bypassing self signed certificate SSL errors. - * @param certificate_url_string - * @return the certificate, as a string - */ - private String downloadCertificateWithoutTrusting(String certificate_url_string) { - - String cert_string = ""; - HostnameVerifier hostnameVerifier = new HostnameVerifier() { - @Override - public boolean verify(String hostname, SSLSession session) { - return true; - } - }; - - TrustManager[] trustAllCerts = new TrustManager[]{ - new X509TrustManager() { - public java.security.cert.X509Certificate[] getAcceptedIssuers() { - return null; - } - public void checkClientTrusted( java.security.cert.X509Certificate[] certs, String authType) { - } - public void checkServerTrusted( java.security.cert.X509Certificate[] certs, String authType) { - } - } - }; - - try { - URL certificate_url = new URL(certificate_url_string); - HttpsURLConnection urlConnection = - (HttpsURLConnection)certificate_url.openConnection(); - urlConnection.setHostnameVerifier(hostnameVerifier); - - SSLContext sc = SSLContext.getInstance("TLS"); - sc.init(null, trustAllCerts, new java.security.SecureRandom()); - - urlConnection.setSSLSocketFactory(sc.getSocketFactory()); - - cert_string = new Scanner(urlConnection.getInputStream()).useDelimiter("\\A").next(); - - } catch (MalformedURLException e) { - // TODO Auto-generated catch block - e.printStackTrace(); - } catch (IOException e) { - // This should never happen - e.printStackTrace(); - } catch (NoSuchAlgorithmException e) { - // TODO Auto-generated catch block - e.printStackTrace(); - } catch (KeyManagementException e) { - // TODO Auto-generated catch block - e.printStackTrace(); - } - - return cert_string; - } - - /** - * Downloads a JSON object from the given url. - * - * It first downloads the JSON object as a String, and then parses it to JSON object. - * @param json_url - * @param danger_on if the user completely trusts the certificate of the url address. - * @return - * @throws JSONException - */ - private JSONObject getJSONFromProvider(String json_url, boolean danger_on) throws JSONException { - String json_file_content = getStringFromProvider(json_url, danger_on); - return new JSONObject(json_file_content); - } - /** * Tries to guess the provider.json url given the main provider url. * @param provider_main_url @@ -727,7 +620,7 @@ public class ProviderAPI extends IntentService { } boolean danger_on = ConfigHelper.getBoolFromSharedPref(ConfigHelper.DANGER_ON); - String cert_string = getStringFromProvider(new_cert_string_url, danger_on); + String cert_string = downloadWithCommercialCA(new_cert_string_url, danger_on); if(!cert_string.isEmpty()) { // API returns concatenated cert & key. Split them for OpenVPN options String certificateString = null, keyString = null; -- cgit v1.2.3 From 4ce663f2c8f4b5aa858b44a6e030f8c9ad15dae4 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Parm=C3=A9nides=20GV?= Date: Tue, 30 Jul 2013 19:48:46 +0200 Subject: Removed cookie to logout chain. --- src/se/leap/leapclient/ProviderAPI.java | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/src/se/leap/leapclient/ProviderAPI.java b/src/se/leap/leapclient/ProviderAPI.java index 645b5e29..db374b49 100644 --- a/src/se/leap/leapclient/ProviderAPI.java +++ b/src/se/leap/leapclient/ProviderAPI.java @@ -574,10 +574,8 @@ public class ProviderAPI extends IntentService { */ private boolean logOut(Bundle task) { DefaultHttpClient client = LeapHttpClient.getInstance(getApplicationContext()); - int session_id_index = 0; - //String delete_url = task.getString(ConfigHelper.srp_server_url_key) + "/sessions/" + client.getCookieStore().getCookies().get(0).getValue(); try { - String delete_url = task.getString(ConfigHelper.API_URL_KEY) + "/logout" + "?authenticity_token=" + client.getCookieStore().getCookies().get(session_id_index).getValue(); + String delete_url = task.getString(ConfigHelper.API_URL_KEY) + "/logout"; HttpDelete delete = new HttpDelete(delete_url); HttpResponse getResponse = client.execute(delete); HttpEntity responseEntity = getResponse.getEntity(); -- cgit v1.2.3 From ddba20593b8e1d59dc12001107d5247368b089e6 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Parm=C3=A9nides=20GV?= Date: Wed, 31 Jul 2013 11:28:36 +0200 Subject: Commented all manual cookie management. I send session_id cookie in the request for 1/cert, getting it from LeapHttpClient directly. --- src/se/leap/leapclient/ConfigHelper.java | 2 +- src/se/leap/leapclient/Dashboard.java | 10 +++++----- src/se/leap/leapclient/ProviderAPI.java | 32 +++++++++++++++++++++----------- 3 files changed, 27 insertions(+), 17 deletions(-) diff --git a/src/se/leap/leapclient/ConfigHelper.java b/src/se/leap/leapclient/ConfigHelper.java index fd7e527f..c88348f1 100644 --- a/src/se/leap/leapclient/ConfigHelper.java +++ b/src/se/leap/leapclient/ConfigHelper.java @@ -79,7 +79,7 @@ public class ConfigHelper { ANON_CERTIFICATE = "anon_certificate", AUTHED_CERTIFICATE = "authed_certificate", SALT_KEY = "salt", - SESSION_ID_COOKIE_KEY = "session_id_cookie_key", + SESSION_ID_COOKIE_KEY = "_session_id", SESSION_ID_KEY = "session_id", PREFERENCES_KEY = "LEAPPreferences", USER_DIRECTORY = "leap_android", diff --git a/src/se/leap/leapclient/Dashboard.java b/src/se/leap/leapclient/Dashboard.java index bb4331d5..2f1418e8 100644 --- a/src/se/leap/leapclient/Dashboard.java +++ b/src/se/leap/leapclient/Dashboard.java @@ -291,7 +291,7 @@ public class Dashboard extends Activity implements LogInDialog.LogInDialogInterf * 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(/*Cookie session_id*/) { providerAPI_result_receiver = new ProviderAPIResultReceiver(new Handler()); providerAPI_result_receiver.setReceiver(this); @@ -299,8 +299,8 @@ public class Dashboard extends Activity implements LogInDialog.LogInDialogInterf Bundle parameters = new Bundle(); parameters.putString(ConfigHelper.TYPE_OF_CERTIFICATE, ConfigHelper.AUTHED_CERTIFICATE); - parameters.putString(ConfigHelper.SESSION_ID_COOKIE_KEY, session_id.getName()); - parameters.putString(ConfigHelper.SESSION_ID_KEY, session_id.getValue()); + /*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); @@ -318,8 +318,8 @@ public class Dashboard extends Activity implements LogInDialog.LogInDialogInterf authed = true; invalidateOptionsMenu(); - Cookie session_id = new BasicClientCookie(session_id_cookie_key, session_id_string); - downloadAuthedUserCertificate(session_id); + //Cookie session_id = new BasicClientCookie(session_id_cookie_key, session_id_string); + downloadAuthedUserCertificate(/*session_id*/); } else if(resultCode == ConfigHelper.SRP_AUTHENTICATION_FAILED) { mProgressDialog.dismiss(); logInDialog(getCurrentFocus(), resultData); diff --git a/src/se/leap/leapclient/ProviderAPI.java b/src/se/leap/leapclient/ProviderAPI.java index db374b49..a81cc788 100644 --- a/src/se/leap/leapclient/ProviderAPI.java +++ b/src/se/leap/leapclient/ProviderAPI.java @@ -36,6 +36,7 @@ import java.security.SecureRandom; import java.security.cert.CertificateException; import java.security.cert.X509Certificate; import java.security.interfaces.RSAPrivateKey; +import java.util.List; import java.util.Scanner; import javax.net.ssl.HostnameVerifier; @@ -220,8 +221,8 @@ public class ProviderAPI extends IntentService { JSONObject session_idAndM2 = sendM1ToSRPServer(authentication_server, username, M1); if(session_idAndM2.has("M2") && client.verify((byte[])session_idAndM2.get("M2"))) { session_id_bundle.putBoolean(ConfigHelper.RESULT_KEY, true); - session_id_bundle.putString(ConfigHelper.SESSION_ID_KEY, session_idAndM2.getString(ConfigHelper.SESSION_ID_KEY)); - session_id_bundle.putString(ConfigHelper.SESSION_ID_COOKIE_KEY, session_idAndM2.getString(ConfigHelper.SESSION_ID_COOKIE_KEY)); + //session_id_bundle.putString(ConfigHelper.SESSION_ID_KEY, session_idAndM2.getString(ConfigHelper.SESSION_ID_KEY)); + //session_id_bundle.putString(ConfigHelper.SESSION_ID_COOKIE_KEY, session_idAndM2.getString(ConfigHelper.SESSION_ID_COOKIE_KEY)); } else { session_id_bundle.putBoolean(ConfigHelper.RESULT_KEY, false); session_id_bundle.putString(getResources().getString(R.string.user_message), getResources().getString(R.string.error_bad_user_password_user_message)); @@ -299,9 +300,9 @@ public class ProviderAPI extends IntentService { JSONObject session_idAndM2 = new JSONObject(); if(json_response.length() > 0) { byte[] M2_not_trimmed = new BigInteger(json_response.getString(ConfigHelper.M2_KEY), 16).toByteArray(); - Cookie session_id_cookie = LeapHttpClient.getInstance(getApplicationContext()).getCookieStore().getCookies().get(0); + /*Cookie session_id_cookie = LeapHttpClient.getInstance(getApplicationContext()).getCookieStore().getCookies().get(0); session_idAndM2.put(ConfigHelper.SESSION_ID_COOKIE_KEY, session_id_cookie.getName()); - session_idAndM2.put(ConfigHelper.SESSION_ID_KEY, session_id_cookie.getValue()); + session_idAndM2.put(ConfigHelper.SESSION_ID_KEY, session_id_cookie.getValue());*/ session_idAndM2.put(ConfigHelper.M2_KEY, ConfigHelper.trim(M2_not_trimmed)); } return session_idAndM2; @@ -317,10 +318,10 @@ public class ProviderAPI extends IntentService { */ private JSONObject sendToServer(HttpUriRequest request) throws ClientProtocolException, IOException, JSONException { DefaultHttpClient client = LeapHttpClient.getInstance(getApplicationContext()); - HttpContext localContext = new BasicHttpContext(); - localContext.setAttribute(ClientContext.COOKIE_STORE, client.getCookieStore()); + /*HttpContext localContext = new BasicHttpContext(); + localContext.setAttribute(ClientContext.COOKIE_STORE, client.getCookieStore());*/ - HttpResponse getResponse = client.execute(request, localContext); + HttpResponse getResponse = client.execute(request/*, localContext*/); HttpEntity responseEntity = getResponse.getEntity(); String plain_response = new Scanner(responseEntity.getContent()).useDelimiter("\\A").next(); JSONObject json_response = new JSONObject(plain_response); @@ -609,12 +610,21 @@ public class ProviderAPI extends IntentService { URL provider_main_url = new URL(provider_json.getString(ConfigHelper.API_URL_KEY)); String new_cert_string_url = provider_main_url.toString() + "/" + provider_json.getString(ConfigHelper.API_VERSION_KEY) + "/" + ConfigHelper.CERT_KEY; + Cookie cookie = null; if(type_of_certificate.equalsIgnoreCase(ConfigHelper.AUTHED_CERTIFICATE)) { - HttpCookie session_id_cookie = new HttpCookie(task.getString(ConfigHelper.SESSION_ID_COOKIE_KEY), task.getString(ConfigHelper.SESSION_ID_KEY)); + List list_cookies = LeapHttpClient.getInstance(getApplicationContext()).getCookieStore().getCookies(); + for(Cookie aux_cookie : list_cookies) { + if(aux_cookie.getName().equalsIgnoreCase(ConfigHelper.SESSION_ID_COOKIE_KEY)) { + cookie = aux_cookie; + break; + } + } + //HttpCookie session_id_cookie = new HttpCookie(task.getString(ConfigHelper.SESSION_ID_COOKIE_KEY), task.getString(ConfigHelper.SESSION_ID_KEY)); + /*HttpCookie session_id_cookie = new HttpCookie(cookie.getName(), cookie.getValue()); CookieManager cookieManager = new CookieManager(); cookieManager.getCookieStore().add(provider_main_url.toURI(), session_id_cookie); - CookieHandler.setDefault(cookieManager); + CookieHandler.setDefault(cookieManager);*/ } boolean danger_on = ConfigHelper.getBoolFromSharedPref(ConfigHelper.DANGER_ON); @@ -657,10 +667,10 @@ public class ProviderAPI extends IntentService { // TODO Auto-generated catch block e.printStackTrace(); return false; - } catch (URISyntaxException e) { + } /*catch (URISyntaxException e) { // TODO Auto-generated catch block e.printStackTrace(); return false; - } + }*/ } } -- cgit v1.2.3 From 344cdb1aafe11ba238a8189fd9f8729b688dd1e9 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Parm=C3=A9nides=20GV?= Date: Fri, 9 Aug 2013 08:58:58 +0200 Subject: Apache HTTP to Android HttpsURLConnection started. SRP parameter A tries to be sent via HttpsURLConnection. Right now, we have a problem with certificates because I'm not using provider CA cert to get the response. I'm going to merge the branch with better method names to download response using already existing code. --- src/se/leap/leapclient/ProviderAPI.java | 54 +++++++++++++++++++++++++++------ tests/.project | 34 +++++++++++++++++++++ 2 files changed, 78 insertions(+), 10 deletions(-) create mode 100644 tests/.project diff --git a/src/se/leap/leapclient/ProviderAPI.java b/src/se/leap/leapclient/ProviderAPI.java index a81cc788..d4402aa5 100644 --- a/src/se/leap/leapclient/ProviderAPI.java +++ b/src/se/leap/leapclient/ProviderAPI.java @@ -16,15 +16,13 @@ */ package se.leap.leapclient; +import java.io.BufferedInputStream; import java.io.FileNotFoundException; import java.io.IOException; +import java.io.InputStream; import java.math.BigInteger; -import java.net.CookieHandler; -import java.net.CookieManager; -import java.net.HttpCookie; import java.net.MalformedURLException; import java.net.SocketTimeoutException; -import java.net.URISyntaxException; import java.net.URL; import java.net.URLConnection; import java.net.UnknownHostException; @@ -36,7 +34,10 @@ import java.security.SecureRandom; import java.security.cert.CertificateException; import java.security.cert.X509Certificate; import java.security.interfaces.RSAPrivateKey; +import java.util.HashMap; +import java.util.Iterator; import java.util.List; +import java.util.Map; import java.util.Scanner; import javax.net.ssl.HostnameVerifier; @@ -52,14 +53,10 @@ import org.apache.http.HttpEntity; import org.apache.http.HttpResponse; import org.apache.http.client.ClientProtocolException; import org.apache.http.client.methods.HttpDelete; -import org.apache.http.client.methods.HttpPost; import org.apache.http.client.methods.HttpPut; import org.apache.http.client.methods.HttpUriRequest; -import org.apache.http.client.protocol.ClientContext; import org.apache.http.cookie.Cookie; import org.apache.http.impl.client.DefaultHttpClient; -import org.apache.http.protocol.BasicHttpContext; -import org.apache.http.protocol.HttpContext; import org.jboss.security.srp.SRPParameters; import org.json.JSONException; import org.json.JSONObject; @@ -279,8 +276,10 @@ public class ProviderAPI extends IntentService { * @throws JSONException */ private JSONObject sendAToSRPServer(String server_url, String username, String clientA) throws ClientProtocolException, IOException, JSONException { - HttpPost post = new HttpPost(server_url + "/sessions.json" + "?" + "login=" + username + "&&" + "A=" + clientA); - return sendToServer(post); + Map parameters = new HashMap(); + parameters.put("login", username); + parameters.put("A", clientA); + return sendToServer(server_url + "/sessions.json", "POST", parameters); } /** @@ -331,6 +330,41 @@ public class ProviderAPI extends IntentService { return json_response; } + + /** + * Executes an HTTP request expecting a JSON response. + * @param url + * @param request_method + * @param parameters + * @return response from authentication server + * @throws IOException + * @throws JSONException + * @throws MalformedURLException + */ + private JSONObject sendToServer(String url, String request_method, Map parameters) throws JSONException, MalformedURLException, IOException { + JSONObject json_response; + HttpsURLConnection urlConnection = (HttpsURLConnection)new URL(url).openConnection(); + try { + urlConnection.setRequestMethod(request_method); + Iterator parameter_iterator = parameters.keySet().iterator(); + while(parameter_iterator.hasNext()) { + String key = parameter_iterator.next(); + urlConnection.addRequestProperty(key, parameters.get(key)); + } + //urlConnection.setChunkedStreamingMode(0); + + InputStream in = new BufferedInputStream(urlConnection.getInputStream()); + String plain_response = new Scanner(in).useDelimiter("\\A").next(); + json_response = new JSONObject(plain_response); + if(!json_response.isNull(ConfigHelper.ERRORS_KEY) || json_response.has(ConfigHelper.ERRORS_KEY)) { + return new JSONObject(); + } + } finally { + urlConnection.disconnect(); + } + + return json_response; + } /** * Downloads a provider.json from a given URL, adding a new provider using the given name. diff --git a/tests/.project b/tests/.project new file mode 100644 index 00000000..851db452 --- /dev/null +++ b/tests/.project @@ -0,0 +1,34 @@ + + + leap_androidTest + + + leap_android + + + + com.android.ide.eclipse.adt.ResourceManagerBuilder + + + + + com.android.ide.eclipse.adt.PreCompilerBuilder + + + + + org.eclipse.jdt.core.javabuilder + + + + + com.android.ide.eclipse.adt.ApkBuilder + + + + + + com.android.ide.eclipse.adt.AndroidNature + org.eclipse.jdt.core.javanature + + -- cgit v1.2.3 From 112be4f505bd46d74eccc6a344ce1402a32957c5 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Parm=C3=A9nides=20GV?= Date: Sat, 10 Aug 2013 10:02:43 +0200 Subject: Replaced Apache HTTP client with HttpURLConnection I do not manually manage cookies anymore, letting HttpURLConnection manage them via default CookieHandler (using CookiePolicy.ACCEPT_ORIGINAL_SERVER). --- src/se/leap/leapclient/ProviderAPI.java | 207 ++++++++++++++++++++------------ 1 file changed, 127 insertions(+), 80 deletions(-) diff --git a/src/se/leap/leapclient/ProviderAPI.java b/src/se/leap/leapclient/ProviderAPI.java index d4402aa5..0b3e6f45 100644 --- a/src/se/leap/leapclient/ProviderAPI.java +++ b/src/se/leap/leapclient/ProviderAPI.java @@ -16,15 +16,20 @@ */ package se.leap.leapclient; -import java.io.BufferedInputStream; +import java.io.DataOutputStream; import java.io.FileNotFoundException; import java.io.IOException; import java.io.InputStream; +import java.io.UnsupportedEncodingException; import java.math.BigInteger; +import java.net.CookieHandler; +import java.net.CookieManager; +import java.net.CookiePolicy; import java.net.MalformedURLException; import java.net.SocketTimeoutException; import java.net.URL; import java.net.URLConnection; +import java.net.URLEncoder; import java.net.UnknownHostException; import java.security.KeyManagementException; import java.security.KeyStore; @@ -36,7 +41,6 @@ import java.security.cert.X509Certificate; import java.security.interfaces.RSAPrivateKey; import java.util.HashMap; import java.util.Iterator; -import java.util.List; import java.util.Map; import java.util.Scanner; @@ -49,14 +53,7 @@ import javax.net.ssl.TrustManager; import javax.net.ssl.TrustManagerFactory; import javax.net.ssl.X509TrustManager; -import org.apache.http.HttpEntity; -import org.apache.http.HttpResponse; import org.apache.http.client.ClientProtocolException; -import org.apache.http.client.methods.HttpDelete; -import org.apache.http.client.methods.HttpPut; -import org.apache.http.client.methods.HttpUriRequest; -import org.apache.http.cookie.Cookie; -import org.apache.http.impl.client.DefaultHttpClient; import org.jboss.security.srp.SRPParameters; import org.json.JSONException; import org.json.JSONObject; @@ -104,6 +101,7 @@ public class ProviderAPI extends IntentService { public void onCreate() { super.onCreate(); mHandler = new Handler(); + CookieHandler.setDefault(new CookieManager(null, CookiePolicy.ACCEPT_ORIGINAL_SERVER) ); } private void displayToast(final int toast_string_id) { @@ -246,6 +244,15 @@ public class ProviderAPI extends IntentService { session_id_bundle.putBoolean(ConfigHelper.RESULT_KEY, false); session_id_bundle.putString(getResources().getString(R.string.user_message), getResources().getString(R.string.error_no_such_algorithm_exception_user_message)); session_id_bundle.putString(ConfigHelper.USERNAME_KEY, username); + } catch (KeyManagementException e) { + // TODO Auto-generated catch block + e.printStackTrace(); + } catch (KeyStoreException e) { + // TODO Auto-generated catch block + e.printStackTrace(); + } catch (CertificateException e) { + // TODO Auto-generated catch block + e.printStackTrace(); } } else { session_id_bundle.putBoolean(ConfigHelper.RESULT_KEY, false); @@ -274,12 +281,19 @@ public class ProviderAPI extends IntentService { * @throws ClientProtocolException * @throws IOException * @throws JSONException + * @throws CertificateException + * @throws NoSuchAlgorithmException + * @throws KeyStoreException + * @throws KeyManagementException */ - private JSONObject sendAToSRPServer(String server_url, String username, String clientA) throws ClientProtocolException, IOException, JSONException { + private JSONObject sendAToSRPServer(String server_url, String username, String clientA) throws ClientProtocolException, IOException, JSONException, KeyManagementException, KeyStoreException, NoSuchAlgorithmException, CertificateException { Map parameters = new HashMap(); parameters.put("login", username); parameters.put("A", clientA); return sendToServer(server_url + "/sessions.json", "POST", parameters); + + /*HttpPost post = new HttpPost(server_url + "/sessions.json" + "?" + "login=" + username + "&&" + "A=" + clientA); + return sendToServer(post);*/ } /** @@ -291,10 +305,17 @@ public class ProviderAPI extends IntentService { * @throws ClientProtocolException * @throws IOException * @throws JSONException + * @throws CertificateException + * @throws NoSuchAlgorithmException + * @throws KeyStoreException + * @throws KeyManagementException */ - private JSONObject sendM1ToSRPServer(String server_url, String username, byte[] m1) throws ClientProtocolException, IOException, JSONException { - HttpPut put = new HttpPut(server_url + "/sessions/" + username +".json" + "?" + "client_auth" + "=" + new BigInteger(1, ConfigHelper.trim(m1)).toString(16)); - JSONObject json_response = sendToServer(put); + private JSONObject sendM1ToSRPServer(String server_url, String username, byte[] m1) throws ClientProtocolException, IOException, JSONException, KeyManagementException, KeyStoreException, NoSuchAlgorithmException, CertificateException { + Map parameters = new HashMap(); + parameters.put("client_auth", new BigInteger(1, ConfigHelper.trim(m1)).toString(16)); + + //HttpPut put = new HttpPut(server_url + "/sessions/" + username +".json" + "?" + "client_auth" + "=" + new BigInteger(1, ConfigHelper.trim(m1)).toString(16)); + JSONObject json_response = sendToServer(server_url + "/sessions/" + username +".json", "PUT", parameters); JSONObject session_idAndM2 = new JSONObject(); if(json_response.length() > 0) { @@ -307,30 +328,6 @@ public class ProviderAPI extends IntentService { return session_idAndM2; } - /** - * Executes an HTTP request expecting a JSON response. - * @param request - * @return response from authentication server - * @throws ClientProtocolException - * @throws IOException - * @throws JSONException - */ - private JSONObject sendToServer(HttpUriRequest request) throws ClientProtocolException, IOException, JSONException { - DefaultHttpClient client = LeapHttpClient.getInstance(getApplicationContext()); - /*HttpContext localContext = new BasicHttpContext(); - localContext.setAttribute(ClientContext.COOKIE_STORE, client.getCookieStore());*/ - - HttpResponse getResponse = client.execute(request/*, localContext*/); - HttpEntity responseEntity = getResponse.getEntity(); - String plain_response = new Scanner(responseEntity.getContent()).useDelimiter("\\A").next(); - JSONObject json_response = new JSONObject(plain_response); - if(!json_response.isNull(ConfigHelper.ERRORS_KEY) || json_response.has(ConfigHelper.ERRORS_KEY)) { - return new JSONObject(); - } - - return json_response; - } - /** * Executes an HTTP request expecting a JSON response. * @param url @@ -340,32 +337,64 @@ public class ProviderAPI extends IntentService { * @throws IOException * @throws JSONException * @throws MalformedURLException + * @throws CertificateException + * @throws NoSuchAlgorithmException + * @throws KeyStoreException + * @throws KeyManagementException */ - private JSONObject sendToServer(String url, String request_method, Map parameters) throws JSONException, MalformedURLException, IOException { + private JSONObject sendToServer(String url, String request_method, Map parameters) throws JSONException, MalformedURLException, IOException, KeyManagementException, KeyStoreException, NoSuchAlgorithmException, CertificateException { JSONObject json_response; + InputStream is = null; HttpsURLConnection urlConnection = (HttpsURLConnection)new URL(url).openConnection(); + urlConnection.setRequestMethod(request_method); + urlConnection.setChunkedStreamingMode(0); + urlConnection.setSSLSocketFactory(getProviderSSLSocketFactory()); try { - urlConnection.setRequestMethod(request_method); - Iterator parameter_iterator = parameters.keySet().iterator(); - while(parameter_iterator.hasNext()) { - String key = parameter_iterator.next(); - urlConnection.addRequestProperty(key, parameters.get(key)); - } - //urlConnection.setChunkedStreamingMode(0); + + DataOutputStream writer = new DataOutputStream(urlConnection.getOutputStream()); + writer.writeBytes(formatHttpParameters(parameters)); + writer.close(); - InputStream in = new BufferedInputStream(urlConnection.getInputStream()); - String plain_response = new Scanner(in).useDelimiter("\\A").next(); + is = urlConnection.getInputStream(); + String plain_response = new Scanner(is).useDelimiter("\\A").next(); json_response = new JSONObject(plain_response); - if(!json_response.isNull(ConfigHelper.ERRORS_KEY) || json_response.has(ConfigHelper.ERRORS_KEY)) { - return new JSONObject(); - } } finally { - urlConnection.disconnect(); + InputStream error_stream = urlConnection.getErrorStream(); + if(error_stream != null) { + String error_response = new Scanner(error_stream).useDelimiter("\\A").next(); + urlConnection.disconnect(); + Log.d("Error", error_response); + json_response = new JSONObject(error_response); + if(!json_response.isNull(ConfigHelper.ERRORS_KEY) || json_response.has(ConfigHelper.ERRORS_KEY)) { + return new JSONObject(); + } + } } return json_response; } + + private String formatHttpParameters(Map parameters) throws UnsupportedEncodingException { + StringBuilder result = new StringBuilder(); + boolean first = true; + + Iterator parameter_iterator = parameters.keySet().iterator(); + while(parameter_iterator.hasNext()) { + if(first) + first = false; + else + result.append("&&"); + + String key = parameter_iterator.next(); + String value = parameters.get(key); + + result.append(URLEncoder.encode(key, "UTF-8")); + result.append("="); + result.append(URLEncoder.encode(value, "UTF-8")); + } + return result.toString(); + } /** * Downloads a provider.json from a given URL, adding a new provider using the given name. * @param task containing a boolean meaning if the provider is custom or not, another boolean meaning if the user completely trusts this provider, the provider name and its provider.json url. @@ -487,30 +516,11 @@ public class ProviderAPI extends IntentService { private String downloadWithProviderCA(URL url, boolean danger_on) { String json_file_content = ""; - String provider_cert_string = ConfigHelper.getStringFromSharedPref(ConfigHelper.MAIN_CERT_KEY); - try { - java.security.cert.Certificate provider_certificate = ConfigHelper.parseX509CertificateFromString(provider_cert_string); - - // Create a KeyStore containing our trusted CAs - String keyStoreType = KeyStore.getDefaultType(); - KeyStore keyStore = KeyStore.getInstance(keyStoreType); - keyStore.load(null, null); - keyStore.setCertificateEntry("provider_ca_certificate", provider_certificate); - - // Create a TrustManager that trusts the CAs in our KeyStore - String tmfAlgorithm = TrustManagerFactory.getDefaultAlgorithm(); - TrustManagerFactory tmf = TrustManagerFactory.getInstance(tmfAlgorithm); - tmf.init(keyStore); - - // Create an SSLContext that uses our TrustManager - SSLContext context = SSLContext.getInstance("TLS"); - context.init(null, tmf.getTrustManagers(), null); - // Tell the URLConnection to use a SocketFactory from our SSLContext HttpsURLConnection urlConnection = (HttpsURLConnection)url.openConnection(); - urlConnection.setSSLSocketFactory(context.getSocketFactory()); + urlConnection.setSSLSocketFactory(getProviderSSLSocketFactory()); json_file_content = new Scanner(urlConnection.getInputStream()).useDelimiter("\\A").next(); } catch (CertificateException e) { // TODO Auto-generated catch block @@ -540,6 +550,29 @@ public class ProviderAPI extends IntentService { return json_file_content; } + private javax.net.ssl.SSLSocketFactory getProviderSSLSocketFactory() throws KeyStoreException, NoSuchAlgorithmException, CertificateException, IOException, KeyManagementException { + String provider_cert_string = ConfigHelper.getStringFromSharedPref(ConfigHelper.MAIN_CERT_KEY); + + java.security.cert.Certificate provider_certificate = ConfigHelper.parseX509CertificateFromString(provider_cert_string); + + // Create a KeyStore containing our trusted CAs + String keyStoreType = KeyStore.getDefaultType(); + KeyStore keyStore = KeyStore.getInstance(keyStoreType); + keyStore.load(null, null); + keyStore.setCertificateEntry("provider_ca_certificate", provider_certificate); + + // Create a TrustManager that trusts the CAs in our KeyStore + String tmfAlgorithm = TrustManagerFactory.getDefaultAlgorithm(); + TrustManagerFactory tmf = TrustManagerFactory.getInstance(tmfAlgorithm); + tmf.init(keyStore); + + // Create an SSLContext that uses our TrustManager + SSLContext context = SSLContext.getInstance("TLS"); + context.init(null, tmf.getTrustManagers(), null); + + return context.getSocketFactory(); + } + /** * Downloads the string that's in the url with any certificate. */ @@ -608,13 +641,15 @@ public class ProviderAPI extends IntentService { * @return true if there were no exceptions */ private boolean logOut(Bundle task) { - DefaultHttpClient client = LeapHttpClient.getInstance(getApplicationContext()); try { String delete_url = task.getString(ConfigHelper.API_URL_KEY) + "/logout"; - HttpDelete delete = new HttpDelete(delete_url); - HttpResponse getResponse = client.execute(delete); - HttpEntity responseEntity = getResponse.getEntity(); - responseEntity.consumeContent(); + + HttpsURLConnection urlConnection = (HttpsURLConnection)new URL(delete_url).openConnection(); + urlConnection.setRequestMethod("DELETE"); + urlConnection.setSSLSocketFactory(getProviderSSLSocketFactory()); + + int responseCode = urlConnection.getResponseCode(); + Log.d("logout", Integer.toString(responseCode)); } catch (ClientProtocolException e) { // TODO Auto-generated catch block e.printStackTrace(); @@ -627,6 +662,18 @@ public class ProviderAPI extends IntentService { // TODO Auto-generated catch block e.printStackTrace(); return false; + } catch (KeyManagementException e) { + // TODO Auto-generated catch block + e.printStackTrace(); + } catch (KeyStoreException e) { + // TODO Auto-generated catch block + e.printStackTrace(); + } catch (NoSuchAlgorithmException e) { + // TODO Auto-generated catch block + e.printStackTrace(); + } catch (CertificateException e) { + // TODO Auto-generated catch block + e.printStackTrace(); } return true; } @@ -638,13 +685,13 @@ public class ProviderAPI extends IntentService { * @return true if certificate was downloaded correctly, false if provider.json or danger_on flag are not present in SharedPreferences, or if the certificate url could not be parsed as a URI, or if there was an SSL error. */ private boolean getNewCert(Bundle task) { - String type_of_certificate = task.getString(ConfigHelper.TYPE_OF_CERTIFICATE); + //String type_of_certificate = task.getString(ConfigHelper.TYPE_OF_CERTIFICATE); try { JSONObject provider_json = ConfigHelper.getJsonFromSharedPref(ConfigHelper.PROVIDER_KEY); URL provider_main_url = new URL(provider_json.getString(ConfigHelper.API_URL_KEY)); String new_cert_string_url = provider_main_url.toString() + "/" + provider_json.getString(ConfigHelper.API_VERSION_KEY) + "/" + ConfigHelper.CERT_KEY; - Cookie cookie = null; + /*Cookie cookie = null; if(type_of_certificate.equalsIgnoreCase(ConfigHelper.AUTHED_CERTIFICATE)) { List list_cookies = LeapHttpClient.getInstance(getApplicationContext()).getCookieStore().getCookies(); for(Cookie aux_cookie : list_cookies) { @@ -652,14 +699,14 @@ public class ProviderAPI extends IntentService { cookie = aux_cookie; break; } - } + }*/ //HttpCookie session_id_cookie = new HttpCookie(task.getString(ConfigHelper.SESSION_ID_COOKIE_KEY), task.getString(ConfigHelper.SESSION_ID_KEY)); /*HttpCookie session_id_cookie = new HttpCookie(cookie.getName(), cookie.getValue()); CookieManager cookieManager = new CookieManager(); cookieManager.getCookieStore().add(provider_main_url.toURI(), session_id_cookie); CookieHandler.setDefault(cookieManager);*/ - } + //} boolean danger_on = ConfigHelper.getBoolFromSharedPref(ConfigHelper.DANGER_ON); String cert_string = downloadWithCommercialCA(new_cert_string_url, danger_on); -- cgit v1.2.3 From 571b935f6ef8a3662fb506d3228efbfced6f24af Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Parm=C3=A9nides=20GV?= Date: Wed, 4 Sep 2013 18:16:45 +0200 Subject: Moved result constants to ProviderAPI. --- src/se/leap/leapclient/ConfigHelper.java | 18 ----------- src/se/leap/leapclient/ConfigurationWizard.java | 12 +++---- src/se/leap/leapclient/Dashboard.java | 12 +++---- src/se/leap/leapclient/ProviderAPI.java | 42 ++++++++++++++++++------- 4 files changed, 42 insertions(+), 42 deletions(-) diff --git a/src/se/leap/leapclient/ConfigHelper.java b/src/se/leap/leapclient/ConfigHelper.java index c88348f1..05c78641 100644 --- a/src/se/leap/leapclient/ConfigHelper.java +++ b/src/se/leap/leapclient/ConfigHelper.java @@ -107,24 +107,6 @@ public class ConfigHelper { final public static String NG_1024 = "eeaf0ab9adb38dd69c33f80afa8fc5e86072618775ff3c0b9ea2314c9c256576d674df7496ea81d3383b4813d692c6e0e0d5d8e250b98be48e495c1d6089dad15dc7d7b46154d6b6ce8ef4ad69b15d4982559b297bcf1885c529f566660e57ec68edbc3c05726cc02fd4cbf4976eaa9afd5138fe8376435b9fc61d2fc0eb06e3"; final public static BigInteger G = new BigInteger("2"); - - final public static int - CUSTOM_PROVIDER_ADDED = 0, - CORRECTLY_DOWNLOADED_JSON_FILES = 1, - INCORRECTLY_DOWNLOADED_JSON_FILES = 2, - SRP_AUTHENTICATION_SUCCESSFUL = 3, - SRP_AUTHENTICATION_FAILED = 4, - SRP_REGISTRATION_SUCCESSFUL = 5, - SRP_REGISTRATION_FAILED = 6, - LOGOUT_SUCCESSFUL = 7, - LOGOUT_FAILED = 8, - CORRECTLY_DOWNLOADED_CERTIFICATE = 9, - INCORRECTLY_DOWNLOADED_CERTIFICATE = 10, - CORRECTLY_UPDATED_PROVIDER_DOT_JSON = 11, - INCORRECTLY_UPDATED_PROVIDER_DOT_JSON = 12, - CORRECTLY_DOWNLOADED_ANON_CERTIFICATE = 13, - INCORRECTLY_DOWNLOADED_ANON_CERTIFICATE = 14 - ; private static boolean checkSharedPrefs() { diff --git a/src/se/leap/leapclient/ConfigurationWizard.java b/src/se/leap/leapclient/ConfigurationWizard.java index 05338bf4..f160d825 100644 --- a/src/se/leap/leapclient/ConfigurationWizard.java +++ b/src/se/leap/leapclient/ConfigurationWizard.java @@ -91,7 +91,7 @@ implements ProviderListFragment.Callbacks, NewProviderDialog.NewProviderDialogIn @Override public void onReceiveResult(int resultCode, Bundle resultData) { - if(resultCode == ConfigHelper.CORRECTLY_UPDATED_PROVIDER_DOT_JSON) { + if(resultCode == ProviderAPI.CORRECTLY_UPDATED_PROVIDER_DOT_JSON) { JSONObject provider_json; try { provider_json = new JSONObject(resultData.getString(ConfigHelper.PROVIDER_KEY)); @@ -123,11 +123,11 @@ implements ProviderListFragment.Callbacks, NewProviderDialog.NewProviderDialogIn setResult(RESULT_CANCELED, mConfigState); } } - else if(resultCode == ConfigHelper.INCORRECTLY_UPDATED_PROVIDER_DOT_JSON) { + else if(resultCode == ProviderAPI.INCORRECTLY_UPDATED_PROVIDER_DOT_JSON) { mProgressDialog.dismiss(); setResult(RESULT_CANCELED, mConfigState); } - else if(resultCode == ConfigHelper.CORRECTLY_DOWNLOADED_JSON_FILES) { + else if(resultCode == ProviderAPI.CORRECTLY_DOWNLOADED_JSON_FILES) { if (ConfigHelper.getBoolFromSharedPref(ConfigHelper.ALLOWED_ANON)){ mProgressDialog.setMessage(getResources().getString(R.string.config_downloading_certificates)); mConfigState.putExtra(SERVICES_RETRIEVED, true); @@ -139,15 +139,15 @@ implements ProviderListFragment.Callbacks, NewProviderDialog.NewProviderDialogIn finish(); } } - else if(resultCode == ConfigHelper.INCORRECTLY_DOWNLOADED_JSON_FILES) { + else if(resultCode == ProviderAPI.INCORRECTLY_DOWNLOADED_JSON_FILES) { //Toast.makeText(getApplicationContext(), R.string.incorrectly_downloaded_json_files_message, Toast.LENGTH_LONG).show(); setResult(RESULT_CANCELED, mConfigState); } - else if(resultCode == ConfigHelper.CORRECTLY_DOWNLOADED_CERTIFICATE) { + else if(resultCode == ProviderAPI.CORRECTLY_DOWNLOADED_CERTIFICATE) { mProgressDialog.dismiss(); setResult(RESULT_OK); showProviderDetails(getCurrentFocus()); - } else if(resultCode == ConfigHelper.INCORRECTLY_DOWNLOADED_CERTIFICATE) { + } else if(resultCode == ProviderAPI.INCORRECTLY_DOWNLOADED_CERTIFICATE) { mProgressDialog.dismiss(); //Toast.makeText(getApplicationContext(), R.string.incorrectly_downloaded_certificate_message, Toast.LENGTH_LONG).show(); setResult(RESULT_CANCELED, mConfigState); diff --git a/src/se/leap/leapclient/Dashboard.java b/src/se/leap/leapclient/Dashboard.java index 2f1418e8..e8da030c 100644 --- a/src/se/leap/leapclient/Dashboard.java +++ b/src/se/leap/leapclient/Dashboard.java @@ -311,7 +311,7 @@ public class Dashboard extends Activity implements LogInDialog.LogInDialogInterf @Override public void onReceiveResult(int resultCode, Bundle resultData) { - if(resultCode == ConfigHelper.SRP_AUTHENTICATION_SUCCESSFUL){ + if(resultCode == ProviderAPI.SRP_AUTHENTICATION_SUCCESSFUL){ String session_id_cookie_key = resultData.getString(ConfigHelper.SESSION_ID_COOKIE_KEY); String session_id_string = resultData.getString(ConfigHelper.SESSION_ID_KEY); setResult(RESULT_OK); @@ -320,23 +320,23 @@ public class Dashboard extends Activity implements LogInDialog.LogInDialogInterf //Cookie session_id = new BasicClientCookie(session_id_cookie_key, session_id_string); downloadAuthedUserCertificate(/*session_id*/); - } else if(resultCode == ConfigHelper.SRP_AUTHENTICATION_FAILED) { + } else if(resultCode == ProviderAPI.SRP_AUTHENTICATION_FAILED) { mProgressDialog.dismiss(); logInDialog(getCurrentFocus(), resultData); - } else if(resultCode == ConfigHelper.LOGOUT_SUCCESSFUL) { + } else if(resultCode == ProviderAPI.LOGOUT_SUCCESSFUL) { authed = false; invalidateOptionsMenu(); setResult(RESULT_OK); mProgressDialog.dismiss(); - } else if(resultCode == ConfigHelper.LOGOUT_FAILED) { + } else if(resultCode == ProviderAPI.LOGOUT_FAILED) { setResult(RESULT_CANCELED); mProgressDialog.dismiss(); Toast.makeText(getApplicationContext(), R.string.log_out_failed_message, Toast.LENGTH_LONG).show(); - } else if(resultCode == ConfigHelper.CORRECTLY_DOWNLOADED_CERTIFICATE) { + } else if(resultCode == ProviderAPI.CORRECTLY_DOWNLOADED_CERTIFICATE) { setResult(RESULT_OK); mProgressDialog.dismiss(); Toast.makeText(getApplicationContext(), R.string.successful_authed_cert_downloaded_message, Toast.LENGTH_LONG).show(); - } else if(resultCode == ConfigHelper.INCORRECTLY_DOWNLOADED_CERTIFICATE) { + } else if(resultCode == ProviderAPI.INCORRECTLY_DOWNLOADED_CERTIFICATE) { setResult(RESULT_CANCELED); mProgressDialog.dismiss(); Toast.makeText(getApplicationContext(), R.string.authed_cert_download_failed_message, Toast.LENGTH_LONG).show(); diff --git a/src/se/leap/leapclient/ProviderAPI.java b/src/se/leap/leapclient/ProviderAPI.java index 0b3e6f45..58dc8214 100644 --- a/src/se/leap/leapclient/ProviderAPI.java +++ b/src/se/leap/leapclient/ProviderAPI.java @@ -90,6 +90,24 @@ public class ProviderAPI extends IntentService { LOG_OUT = "logOut", DOWNLOAD_CERTIFICATE = "downloadUserAuthedCertificate", PARAMETERS = "parameters" + ; + + final public static int + CUSTOM_PROVIDER_ADDED = 0, + CORRECTLY_DOWNLOADED_JSON_FILES = 1, + INCORRECTLY_DOWNLOADED_JSON_FILES = 2, + SRP_AUTHENTICATION_SUCCESSFUL = 3, + SRP_AUTHENTICATION_FAILED = 4, + SRP_REGISTRATION_SUCCESSFUL = 5, + SRP_REGISTRATION_FAILED = 6, + LOGOUT_SUCCESSFUL = 7, + LOGOUT_FAILED = 8, + CORRECTLY_DOWNLOADED_CERTIFICATE = 9, + INCORRECTLY_DOWNLOADED_CERTIFICATE = 10, + CORRECTLY_UPDATED_PROVIDER_DOT_JSON = 11, + INCORRECTLY_UPDATED_PROVIDER_DOT_JSON = 12, + CORRECTLY_DOWNLOADED_ANON_CERTIFICATE = 13, + INCORRECTLY_DOWNLOADED_ANON_CERTIFICATE = 14 ; public ProviderAPI() { @@ -122,42 +140,42 @@ public class ProviderAPI extends IntentService { if(action.equalsIgnoreCase(DOWNLOAD_JSON_FILES_BUNDLE_EXTRA)) { if(!downloadJsonFiles(parameters)) { - receiver.send(ConfigHelper.INCORRECTLY_DOWNLOADED_JSON_FILES, Bundle.EMPTY); + receiver.send(INCORRECTLY_DOWNLOADED_JSON_FILES, Bundle.EMPTY); } else { - receiver.send(ConfigHelper.CORRECTLY_DOWNLOADED_JSON_FILES, Bundle.EMPTY); + receiver.send(CORRECTLY_DOWNLOADED_JSON_FILES, Bundle.EMPTY); } } else if(action.equalsIgnoreCase(UPDATE_PROVIDER_DOTJSON)) { Bundle result = updateProviderDotJSON(parameters); if(result.getBoolean(ConfigHelper.RESULT_KEY)) { - receiver.send(ConfigHelper.CORRECTLY_UPDATED_PROVIDER_DOT_JSON, result); + receiver.send(CORRECTLY_UPDATED_PROVIDER_DOT_JSON, result); } else { - receiver.send(ConfigHelper.INCORRECTLY_UPDATED_PROVIDER_DOT_JSON, Bundle.EMPTY); + receiver.send(INCORRECTLY_UPDATED_PROVIDER_DOT_JSON, Bundle.EMPTY); } } else if (action.equalsIgnoreCase(DOWNLOAD_NEW_PROVIDER_DOTJSON)) { Bundle result = downloadNewProviderDotJSON(parameters); if(result.getBoolean(ConfigHelper.RESULT_KEY)) { - receiver.send(ConfigHelper.CORRECTLY_UPDATED_PROVIDER_DOT_JSON, result); + receiver.send(CORRECTLY_UPDATED_PROVIDER_DOT_JSON, result); } else { - receiver.send(ConfigHelper.INCORRECTLY_DOWNLOADED_JSON_FILES, Bundle.EMPTY); + receiver.send(INCORRECTLY_DOWNLOADED_JSON_FILES, Bundle.EMPTY); } } else if (action.equalsIgnoreCase(SRP_AUTH)) { Bundle session_id_bundle = authenticateBySRP(parameters); if(session_id_bundle.getBoolean(ConfigHelper.RESULT_KEY)) { - receiver.send(ConfigHelper.SRP_AUTHENTICATION_SUCCESSFUL, session_id_bundle); + receiver.send(SRP_AUTHENTICATION_SUCCESSFUL, session_id_bundle); } else { - receiver.send(ConfigHelper.SRP_AUTHENTICATION_FAILED, session_id_bundle); + receiver.send(SRP_AUTHENTICATION_FAILED, session_id_bundle); } } else if (action.equalsIgnoreCase(LOG_OUT)) { if(logOut(parameters)) { - receiver.send(ConfigHelper.LOGOUT_SUCCESSFUL, Bundle.EMPTY); + receiver.send(LOGOUT_SUCCESSFUL, Bundle.EMPTY); } else { - receiver.send(ConfigHelper.LOGOUT_FAILED, Bundle.EMPTY); + receiver.send(LOGOUT_FAILED, Bundle.EMPTY); } } else if (action.equalsIgnoreCase(DOWNLOAD_CERTIFICATE)) { if(getNewCert(parameters)) { - receiver.send(ConfigHelper.CORRECTLY_DOWNLOADED_CERTIFICATE, Bundle.EMPTY); + receiver.send(CORRECTLY_DOWNLOADED_CERTIFICATE, Bundle.EMPTY); } else { - receiver.send(ConfigHelper.INCORRECTLY_DOWNLOADED_CERTIFICATE, Bundle.EMPTY); + receiver.send(INCORRECTLY_DOWNLOADED_CERTIFICATE, Bundle.EMPTY); } } } -- cgit v1.2.3 From fdc8d5376c6d44c2a78ee023e89417cddabfbd44 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Parm=C3=A9nides=20GV?= Date: Thu, 5 Sep 2013 17:40:36 +0200 Subject: Moved all constants from ConfigHelper. They have been relocated to the corresponding classes. --- src/se/leap/leapclient/AboutFragment.java | 2 + src/se/leap/leapclient/ConfigHelper.java | 75 +--------- src/se/leap/leapclient/ConfigurationWizard.java | 80 +++++------ src/se/leap/leapclient/Dashboard.java | 52 +++---- src/se/leap/leapclient/EIP.java | 28 ++-- src/se/leap/leapclient/EipServiceFragment.java | 4 +- src/se/leap/leapclient/LeapHttpClient.java | 2 +- src/se/leap/leapclient/LeapSRPSession.java | 4 + src/se/leap/leapclient/LogInDialog.java | 11 +- src/se/leap/leapclient/NewProviderDialog.java | 4 +- src/se/leap/leapclient/Provider.java | 18 ++- src/se/leap/leapclient/ProviderAPI.java | 153 ++++++++++----------- src/se/leap/leapclient/ProviderDetailFragment.java | 29 ++-- src/se/leap/leapclient/ProviderListContent.java | 15 +- src/se/leap/openvpn/LaunchVPN.java | 6 +- src/se/leap/openvpn/VpnProfile.java | 8 +- 16 files changed, 230 insertions(+), 261 deletions(-) diff --git a/src/se/leap/leapclient/AboutFragment.java b/src/se/leap/leapclient/AboutFragment.java index a3fbbf93..97cfb584 100644 --- a/src/se/leap/leapclient/AboutFragment.java +++ b/src/se/leap/leapclient/AboutFragment.java @@ -14,6 +14,8 @@ import android.widget.TextView; import se.leap.leapclient.R; public class AboutFragment extends Fragment { + + final public static String TAG = "aboutFragment"; public static Fragment newInstance() { AboutFragment provider_detail_fragment = new AboutFragment(); diff --git a/src/se/leap/leapclient/ConfigHelper.java b/src/se/leap/leapclient/ConfigHelper.java index 05c78641..14b29787 100644 --- a/src/se/leap/leapclient/ConfigHelper.java +++ b/src/se/leap/leapclient/ConfigHelper.java @@ -17,9 +17,6 @@ package se.leap.leapclient; import java.io.ByteArrayInputStream; -import java.io.File; -import java.io.FileInputStream; -import java.io.FileNotFoundException; import java.io.IOException; import java.math.BigInteger; import java.io.InputStream; @@ -28,7 +25,6 @@ import java.security.KeyStore; import java.security.KeyStoreException; import java.security.NoSuchAlgorithmException; import java.security.NoSuchProviderException; -import java.security.PrivateKey; import java.security.cert.CertificateException; import java.security.cert.CertificateFactory; import java.security.cert.X509Certificate; @@ -41,7 +37,6 @@ import org.json.JSONObject; import android.content.Context; import android.content.SharedPreferences; -import android.os.Environment; import android.util.Base64; /** @@ -55,55 +50,7 @@ public class ConfigHelper { public static SharedPreferences shared_preferences; private static KeyStore keystore_trusted; - - final public static String - ABOUT_FRAGMENT = "aboutFragment", - LOG_IN_DIALOG = "logInDialog", - NEW_PROVIDER_DIALOG = "logInDialog", - M1_KEY = "M1", - M2_KEY = "M2", - LOG_IN = "logIn", - API_VERSION_KEY = "api_version", - API_RETURN_SERIAL_KEY = "serial", - RESULT_KEY = "result", - RECEIVER_KEY = "receiver", - PROVIDER_KEY = "provider", - SERVICE_KEY = "service", - ALLOWED_ANON = "allow_anonymous", - MAIN_CERT_KEY = "main_cert", - CERT_KEY = "cert", - KEY_KEY = "key", - EIP_SERVICE_KEY = "eip", - EIP_PARSED_SERIAL = "eip_parsed_serial", - TYPE_OF_CERTIFICATE = "type_of_certificate", - ANON_CERTIFICATE = "anon_certificate", - AUTHED_CERTIFICATE = "authed_certificate", - SALT_KEY = "salt", - SESSION_ID_COOKIE_KEY = "_session_id", - SESSION_ID_KEY = "session_id", - PREFERENCES_KEY = "LEAPPreferences", - USER_DIRECTORY = "leap_android", - PROVIDER_NAME = "provider_name", - PROVIDER_ID = "provider_id", - PROVIDER_MAIN_URL = "provider_main_url", - PROVIDER_JSON_URL = "provider_json_url", - CUSTOM = "custom", - DANGER_ON = "danger_on", - API_URL_KEY = "api_uri", - USERNAME_KEY = "username", - PASSWORD_KEY = "password", - ALLOW_REGISTRATION_KEY = "allow_registration", - EIP_SERVICE_API_PATH = "config/eip-service.json", - ERRORS_KEY = "errors", - RECEIVER_TAG = "receiverTag", - REQUEST_TAG = "requestTag", - PROVIDER_DETAILS_DIALOG = "providerDetailsFragment", - DOMAIN = "domain", - NAME = "name", - DESCRIPTION = "description", - QUIT = "quit" - ; - + final public static String NG_1024 = "eeaf0ab9adb38dd69c33f80afa8fc5e86072618775ff3c0b9ea2314c9c256576d674df7496ea81d3383b4813d692c6e0e0d5d8e250b98be48e495c1d6089dad15dc7d7b46154d6b6ce8ef4ad69b15d4982559b297bcf1885c529f566660e57ec68edbc3c05726cc02fd4cbf4976eaa9afd5138fe8376435b9fc61d2fc0eb06e3"; final public static BigInteger G = new BigInteger("2"); @@ -111,7 +58,7 @@ public class ConfigHelper { private static boolean checkSharedPrefs() { try { - shared_preferences = Dashboard.getAppContext().getSharedPreferences(PREFERENCES_KEY,Context.MODE_PRIVATE); + shared_preferences = Dashboard.getAppContext().getSharedPreferences(Dashboard.SHARED_PREFERENCES,Context.MODE_PRIVATE); } catch (Exception e) { return false; } @@ -232,24 +179,6 @@ public class ConfigHelper { return shared_preferences_editor.commit(); } - /** - * Opens a FileInputStream from the user directory of the external storage directory. - * @param filename - * @return a file input stream - */ - public static FileInputStream openFileInputStream(String filename) { - FileInputStream input_stream = null; - File root = Environment.getExternalStorageDirectory(); - File leap_dir = new File(root.getAbsolutePath() + File.separator + USER_DIRECTORY); - try { - input_stream = new FileInputStream(leap_dir + File.separator + filename); - } catch (FileNotFoundException e) { - // TODO Auto-generated catch block - e.printStackTrace(); - } - return input_stream; - } - /** * Treat the input as the MSB representation of a number, * and lop off leading zero elements. For efficiency, the diff --git a/src/se/leap/leapclient/ConfigurationWizard.java b/src/se/leap/leapclient/ConfigurationWizard.java index f160d825..4a8158d6 100644 --- a/src/se/leap/leapclient/ConfigurationWizard.java +++ b/src/se/leap/leapclient/ConfigurationWizard.java @@ -25,7 +25,6 @@ import org.json.JSONObject; import se.leap.leapclient.ProviderAPIResultReceiver.Receiver; import se.leap.leapclient.ProviderListContent.ProviderItem; import se.leap.leapclient.R; -import se.leap.openvpn.MainActivity; import android.app.Activity; import android.app.DialogFragment; import android.app.Fragment; @@ -39,7 +38,6 @@ import android.os.Handler; import android.view.Menu; import android.view.MenuItem; import android.view.View; -import android.view.ViewGroup; /** * Activity that builds and shows the list of known available providers. @@ -55,9 +53,13 @@ implements ProviderListFragment.Callbacks, NewProviderDialog.NewProviderDialogIn private ProviderItem mSelectedProvider; private ProgressDialog mProgressDialog; private Intent mConfigState = new Intent(); + + final public static String TYPE_OF_CERTIFICATE = "type_of_certificate"; + final public static String ANON_CERTIFICATE = "anon_certificate"; + final public static String AUTHED_CERTIFICATE = "authed_certificate"; - protected static final String PROVIDER_SET = "PROVIDER SET"; - protected static final String SERVICES_RETRIEVED = "SERVICES RETRIEVED"; + final protected static String PROVIDER_SET = "PROVIDER SET"; + final protected static String SERVICES_RETRIEVED = "SERVICES RETRIEVED"; public ProviderAPIResultReceiver providerAPI_result_receiver; @@ -70,7 +72,7 @@ implements ProviderListFragment.Callbacks, NewProviderDialog.NewProviderDialogIn providerAPI_result_receiver = new ProviderAPIResultReceiver(new Handler()); providerAPI_result_receiver.setReceiver(this); - ConfigHelper.setSharedPreferences(getSharedPreferences(ConfigHelper.PREFERENCES_KEY, MODE_PRIVATE)); + ConfigHelper.setSharedPreferences(getSharedPreferences(Dashboard.SHARED_PREFERENCES, MODE_PRIVATE)); loadPreseededProviders(); @@ -94,18 +96,18 @@ implements ProviderListFragment.Callbacks, NewProviderDialog.NewProviderDialogIn if(resultCode == ProviderAPI.CORRECTLY_UPDATED_PROVIDER_DOT_JSON) { JSONObject provider_json; try { - provider_json = new JSONObject(resultData.getString(ConfigHelper.PROVIDER_KEY)); - boolean danger_on = resultData.getBoolean(ConfigHelper.DANGER_ON); - ConfigHelper.saveSharedPref(ConfigHelper.PROVIDER_KEY, provider_json); - ConfigHelper.saveSharedPref(ConfigHelper.DANGER_ON, danger_on); - ConfigHelper.saveSharedPref(ConfigHelper.ALLOWED_ANON, provider_json.getJSONObject(ConfigHelper.SERVICE_KEY).getBoolean(ConfigHelper.ALLOWED_ANON)); + provider_json = new JSONObject(resultData.getString(Provider.KEY)); + boolean danger_on = resultData.getBoolean(ProviderItem.DANGER_ON); + ConfigHelper.saveSharedPref(Provider.KEY, provider_json); + ConfigHelper.saveSharedPref(ProviderItem.DANGER_ON, danger_on); + ConfigHelper.saveSharedPref(EIP.ALLOWED_ANON, provider_json.getJSONObject(Provider.SERVICE).getBoolean(EIP.ALLOWED_ANON)); mConfigState.setAction(PROVIDER_SET); if(mProgressDialog != null) mProgressDialog.dismiss(); mProgressDialog = ProgressDialog.show(this, getResources().getString(R.string.config_wait_title), getResources().getString(R.string.config_connecting_provider), true); mProgressDialog.setMessage(getResources().getString(R.string.config_downloading_services)); - if(resultData.containsKey(ConfigHelper.PROVIDER_ID)) - mSelectedProvider = getProvider(resultData.getString(ConfigHelper.PROVIDER_ID)); + if(resultData.containsKey(Provider.NAME)) + mSelectedProvider = getProvider(resultData.getString(Provider.NAME)); ProviderListFragment providerList = new ProviderListFragment(); @@ -128,7 +130,7 @@ implements ProviderListFragment.Callbacks, NewProviderDialog.NewProviderDialogIn setResult(RESULT_CANCELED, mConfigState); } else if(resultCode == ProviderAPI.CORRECTLY_DOWNLOADED_JSON_FILES) { - if (ConfigHelper.getBoolFromSharedPref(ConfigHelper.ALLOWED_ANON)){ + if (ConfigHelper.getBoolFromSharedPref(EIP.ALLOWED_ANON)){ mProgressDialog.setMessage(getResources().getString(R.string.config_downloading_certificates)); mConfigState.putExtra(SERVICES_RETRIEVED, true); downloadAnonCert(); @@ -170,7 +172,7 @@ implements ProviderListFragment.Callbacks, NewProviderDialog.NewProviderDialogIn @Override public void onBackPressed() { try { - if(ConfigHelper.getJsonFromSharedPref(ConfigHelper.PROVIDER_KEY) == null || ConfigHelper.getJsonFromSharedPref(ConfigHelper.PROVIDER_KEY).length() == 0) { + if(ConfigHelper.getJsonFromSharedPref(Provider.KEY) == null || ConfigHelper.getJsonFromSharedPref(Provider.KEY).length() == 0) { askDashboardToQuitApp(); } else { setResult(RESULT_OK); @@ -183,7 +185,7 @@ implements ProviderListFragment.Callbacks, NewProviderDialog.NewProviderDialogIn private void askDashboardToQuitApp() { Intent ask_quit = new Intent(); - ask_quit.putExtra(ConfigHelper.QUIT, ConfigHelper.QUIT); + ask_quit.putExtra(Dashboard.ACTION_QUIT, Dashboard.ACTION_QUIT); setResult(RESULT_CANCELED, ask_quit); } @@ -243,9 +245,9 @@ implements ProviderListFragment.Callbacks, NewProviderDialog.NewProviderDialogIn // I think yes, but if so, where does this list live? leap.se, as it's the non-profit project for the software? // If not, we should just be getting names/urls, and fetching the provider.json like in custom entries provider_json = provider.provider_json; - ConfigHelper.saveSharedPref(ConfigHelper.PROVIDER_KEY, provider_json); - ConfigHelper.saveSharedPref(ConfigHelper.ALLOWED_ANON, provider_json.getJSONObject(ConfigHelper.SERVICE_KEY).getBoolean(ConfigHelper.ALLOWED_ANON)); - ConfigHelper.saveSharedPref(ConfigHelper.DANGER_ON, provider.danger_on); + ConfigHelper.saveSharedPref(Provider.KEY, provider_json); + ConfigHelper.saveSharedPref(EIP.ALLOWED_ANON, provider_json.getJSONObject(Provider.SERVICE).getBoolean(EIP.ALLOWED_ANON)); + ConfigHelper.saveSharedPref(ProviderItem.DANGER_ON, provider.danger_on); mProgressDialog.setMessage(getResources().getString(R.string.config_downloading_services)); downloadJSONFiles(mSelectedProvider); @@ -267,14 +269,14 @@ implements ProviderListFragment.Callbacks, NewProviderDialog.NewProviderDialogIn Bundle parameters = new Bundle(); - parameters.putString(ConfigHelper.PROVIDER_KEY, provider.name); - parameters.putString(ConfigHelper.MAIN_CERT_KEY, provider.cert_json_url); - parameters.putString(ConfigHelper.EIP_SERVICE_KEY, provider.eip_service_json_url); - parameters.putBoolean(ConfigHelper.DANGER_ON, provider.danger_on); + parameters.putString(Provider.KEY, provider.name); + parameters.putString(Provider.CA_CERT, provider.cert_json_url); + parameters.putString(EIP.KEY, provider.eip_service_json_url); + parameters.putBoolean(ProviderItem.DANGER_ON, provider.danger_on); provider_API_command.setAction(ProviderAPI.DOWNLOAD_JSON_FILES_BUNDLE_EXTRA); provider_API_command.putExtra(ProviderAPI.PARAMETERS, parameters); - provider_API_command.putExtra(ConfigHelper.RECEIVER_KEY, providerAPI_result_receiver); + provider_API_command.putExtra(ProviderAPI.RECEIVER_KEY, providerAPI_result_receiver); startService(provider_API_command); } @@ -287,11 +289,11 @@ implements ProviderListFragment.Callbacks, NewProviderDialog.NewProviderDialogIn Bundle parameters = new Bundle(); - parameters.putString(ConfigHelper.TYPE_OF_CERTIFICATE, ConfigHelper.ANON_CERTIFICATE); + parameters.putString(TYPE_OF_CERTIFICATE, ANON_CERTIFICATE); provider_API_command.setAction(ProviderAPI.DOWNLOAD_CERTIFICATE); provider_API_command.putExtra(ProviderAPI.PARAMETERS, parameters); - provider_API_command.putExtra(ConfigHelper.RECEIVER_KEY, providerAPI_result_receiver); + provider_API_command.putExtra(ProviderAPI.RECEIVER_KEY, providerAPI_result_receiver); startService(provider_API_command); } @@ -302,14 +304,14 @@ implements ProviderListFragment.Callbacks, NewProviderDialog.NewProviderDialogIn */ public void addAndSelectNewProvider(View view) { FragmentTransaction fragment_transaction = getFragmentManager().beginTransaction(); - Fragment previous_new_provider_dialog = getFragmentManager().findFragmentByTag(ConfigHelper.NEW_PROVIDER_DIALOG); + Fragment previous_new_provider_dialog = getFragmentManager().findFragmentByTag(NewProviderDialog.TAG); if (previous_new_provider_dialog != null) { fragment_transaction.remove(previous_new_provider_dialog); } fragment_transaction.addToBackStack(null); DialogFragment newFragment = NewProviderDialog.newInstance(); - newFragment.show(fragment_transaction, ConfigHelper.NEW_PROVIDER_DIALOG); + newFragment.show(fragment_transaction, NewProviderDialog.TAG); } /** @@ -320,14 +322,14 @@ implements ProviderListFragment.Callbacks, NewProviderDialog.NewProviderDialogIn */ public void showProviderDetails(View view) { FragmentTransaction fragment_transaction = getFragmentManager().beginTransaction(); - Fragment previous_provider_details_dialog = getFragmentManager().findFragmentByTag(ConfigHelper.PROVIDER_DETAILS_DIALOG); + Fragment previous_provider_details_dialog = getFragmentManager().findFragmentByTag(ProviderDetailFragment.TAG); if (previous_provider_details_dialog != null) { fragment_transaction.remove(previous_provider_details_dialog); } fragment_transaction.addToBackStack(null); DialogFragment newFragment = ProviderDetailFragment.newInstance(); - newFragment.show(fragment_transaction, ConfigHelper.PROVIDER_DETAILS_DIALOG); + newFragment.show(fragment_transaction, ProviderDetailFragment.TAG); } @Override @@ -335,12 +337,12 @@ implements ProviderListFragment.Callbacks, NewProviderDialog.NewProviderDialogIn Intent provider_API_command = new Intent(this, ProviderAPI.class); Bundle parameters = new Bundle(); - parameters.putString(ConfigHelper.PROVIDER_MAIN_URL, provider_main_url); - parameters.putBoolean(ConfigHelper.DANGER_ON, danger_on); + parameters.putString(Provider.MAIN_URL, provider_main_url); + parameters.putBoolean(ProviderItem.DANGER_ON, danger_on); provider_API_command.setAction(ProviderAPI.DOWNLOAD_NEW_PROVIDER_DOTJSON); provider_API_command.putExtra(ProviderAPI.PARAMETERS, parameters); - provider_API_command.putExtra(ConfigHelper.RECEIVER_KEY, providerAPI_result_receiver); + provider_API_command.putExtra(ProviderAPI.RECEIVER_KEY, providerAPI_result_receiver); startService(provider_API_command); } @@ -355,13 +357,13 @@ implements ProviderListFragment.Callbacks, NewProviderDialog.NewProviderDialogIn Intent provider_API_command = new Intent(this, ProviderAPI.class); Bundle parameters = new Bundle(); - parameters.putString(ConfigHelper.PROVIDER_NAME, provider_name); - parameters.putString(ConfigHelper.PROVIDER_JSON_URL, provider_json_url); - parameters.putBoolean(ConfigHelper.DANGER_ON, danger_on); + parameters.putString(Provider.NAME, provider_name); + parameters.putString(Provider.DOT_JSON_URL, provider_json_url); + parameters.putBoolean(ProviderItem.DANGER_ON, danger_on); provider_API_command.setAction(ProviderAPI.UPDATE_PROVIDER_DOTJSON); provider_API_command.putExtra(ProviderAPI.PARAMETERS, parameters); - provider_API_command.putExtra(ConfigHelper.RECEIVER_KEY, providerAPI_result_receiver); + provider_API_command.putExtra(ProviderAPI.RECEIVER_KEY, providerAPI_result_receiver); startService(provider_API_command); } @@ -390,19 +392,19 @@ implements ProviderListFragment.Callbacks, NewProviderDialog.NewProviderDialogIn */ public void showAboutFragment(View view) { FragmentTransaction fragment_transaction = getFragmentManager().beginTransaction(); - Fragment previous_about_fragment = getFragmentManager().findFragmentByTag(ConfigHelper.ABOUT_FRAGMENT); + Fragment previous_about_fragment = getFragmentManager().findFragmentByTag(AboutFragment.TAG); if (previous_about_fragment == null) { fragment_transaction.addToBackStack(null); Fragment newFragment = AboutFragment.newInstance(); - fragment_transaction.replace(R.id.configuration_wizard_layout, newFragment, ConfigHelper.ABOUT_FRAGMENT).commit(); + fragment_transaction.replace(R.id.configuration_wizard_layout, newFragment, AboutFragment.TAG).commit(); } } @Override public void login() { Intent ask_login = new Intent(); - ask_login.putExtra(ConfigHelper.LOG_IN, ConfigHelper.LOG_IN); + ask_login.putExtra(LogInDialog.VERB, LogInDialog.VERB); setResult(RESULT_OK, ask_login); finish(); } diff --git a/src/se/leap/leapclient/Dashboard.java b/src/se/leap/leapclient/Dashboard.java index e8da030c..371663b7 100644 --- a/src/se/leap/leapclient/Dashboard.java +++ b/src/se/leap/leapclient/Dashboard.java @@ -54,6 +54,8 @@ public class Dashboard extends Activity implements LogInDialog.LogInDialogInterf protected static final int CONFIGURE_LEAP = 0; private static final String TAG_EIP_FRAGMENT = "EIP_DASHBOARD_FRAGMENT"; + final public static String SHARED_PREFERENCES = "LEAPPreferences"; + final public static String ACTION_QUIT = "quit"; private ProgressDialog mProgressDialog; @@ -73,10 +75,10 @@ public class Dashboard extends Activity implements LogInDialog.LogInDialogInterf app = this; - ConfigHelper.setSharedPreferences(getSharedPreferences(ConfigHelper.PREFERENCES_KEY, MODE_PRIVATE)); + ConfigHelper.setSharedPreferences(getSharedPreferences(SHARED_PREFERENCES, MODE_PRIVATE)); preferences = ConfigHelper.shared_preferences; - if (ConfigHelper.getStringFromSharedPref(ConfigHelper.PROVIDER_KEY).isEmpty()) + if (ConfigHelper.getStringFromSharedPref(Provider.KEY).isEmpty()) startActivityForResult(new Intent(this,ConfigurationWizard.class),CONFIGURE_LEAP); else buildDashboard(); @@ -88,11 +90,11 @@ public class Dashboard extends Activity implements LogInDialog.LogInDialogInterf if ( resultCode == RESULT_OK ){ startService( new Intent(EIP.ACTION_UPDATE_EIP_SERVICE) ); buildDashboard(); - if(data != null && data.hasExtra(ConfigHelper.LOG_IN)) { + if(data != null && data.hasExtra(LogInDialog.VERB)) { View view = ((ViewGroup)findViewById(android.R.id.content)).getChildAt(0); logInDialog(view, Bundle.EMPTY); } - } else if(resultCode == RESULT_CANCELED && data.hasExtra(ConfigHelper.QUIT)) { + } else if(resultCode == RESULT_CANCELED && data.hasExtra(ACTION_QUIT)) { finish(); } else configErrorDialog(); @@ -118,8 +120,8 @@ public class Dashboard extends Activity implements LogInDialog.LogInDialogInterf .setNegativeButton(getResources().getString(R.string.setup_error_close_button), new DialogInterface.OnClickListener() { @Override public void onClick(DialogInterface dialog, int which) { - SharedPreferences.Editor prefsEdit = getSharedPreferences(ConfigHelper.PREFERENCES_KEY, MODE_PRIVATE).edit(); - prefsEdit.remove(ConfigHelper.PROVIDER_KEY).commit(); + SharedPreferences.Editor prefsEdit = getSharedPreferences(SHARED_PREFERENCES, MODE_PRIVATE).edit(); + prefsEdit.remove(Provider.KEY).commit(); finish(); } }) @@ -151,9 +153,9 @@ public class Dashboard extends Activity implements LogInDialog.LogInDialogInterf public boolean onPrepareOptionsMenu(Menu menu) { JSONObject provider_json; try { - provider_json = ConfigHelper.getJsonFromSharedPref(ConfigHelper.PROVIDER_KEY); - JSONObject service_description = provider_json.getJSONObject(ConfigHelper.SERVICE_KEY); - if(service_description.getBoolean(ConfigHelper.ALLOW_REGISTRATION_KEY)) { + provider_json = ConfigHelper.getJsonFromSharedPref(Provider.KEY); + JSONObject service_description = provider_json.getJSONObject(Provider.SERVICE); + if(service_description.getBoolean(Provider.ALLOW_REGISTRATION)) { if(authed) { menu.findItem(R.id.login_button).setVisible(false); menu.findItem(R.id.logout_button).setVisible(true); @@ -214,13 +216,13 @@ public class Dashboard extends Activity implements LogInDialog.LogInDialogInterf Intent provider_API_command = new Intent(this, ProviderAPI.class); Bundle parameters = new Bundle(); - parameters.putString(ConfigHelper.USERNAME_KEY, username); - parameters.putString(ConfigHelper.PASSWORD_KEY, password); + parameters.putString(LogInDialog.USERNAME, username); + parameters.putString(LogInDialog.PASSWORD, password); JSONObject provider_json; try { - provider_json = new JSONObject(preferences.getString(ConfigHelper.PROVIDER_KEY, "")); - parameters.putString(ConfigHelper.API_URL_KEY, provider_json.getString(ConfigHelper.API_URL_KEY) + "/" + provider_json.getString(ConfigHelper.API_VERSION_KEY)); + 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(); @@ -228,7 +230,7 @@ public class Dashboard extends Activity implements LogInDialog.LogInDialogInterf provider_API_command.setAction(ProviderAPI.SRP_AUTH); provider_API_command.putExtra(ProviderAPI.PARAMETERS, parameters); - provider_API_command.putExtra(ConfigHelper.RECEIVER_KEY, providerAPI_result_receiver); + provider_API_command.putExtra(ProviderAPI.RECEIVER_KEY, providerAPI_result_receiver); if(mProgressDialog != null) mProgressDialog.dismiss(); mProgressDialog = ProgressDialog.show(this, getResources().getString(R.string.authenticating_title), getResources().getString(R.string.authenticating_message), true); @@ -247,8 +249,8 @@ public class Dashboard extends Activity implements LogInDialog.LogInDialogInterf JSONObject provider_json; try { - provider_json = new JSONObject(preferences.getString(ConfigHelper.PROVIDER_KEY, "")); - parameters.putString(ConfigHelper.API_URL_KEY, provider_json.getString(ConfigHelper.API_URL_KEY) + "/" + provider_json.getString(ConfigHelper.API_VERSION_KEY)); + 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(); @@ -256,7 +258,7 @@ public class Dashboard extends Activity implements LogInDialog.LogInDialogInterf provider_API_command.setAction(ProviderAPI.LOG_OUT); provider_API_command.putExtra(ProviderAPI.PARAMETERS, parameters); - provider_API_command.putExtra(ConfigHelper.RECEIVER_KEY, providerAPI_result_receiver); + provider_API_command.putExtra(ProviderAPI.RECEIVER_KEY, providerAPI_result_receiver); if(mProgressDialog != null) mProgressDialog.dismiss(); mProgressDialog = ProgressDialog.show(this, getResources().getString(R.string.logout_title), getResources().getString(R.string.logout_message), true); @@ -269,7 +271,7 @@ public class Dashboard extends Activity implements LogInDialog.LogInDialogInterf */ public void logInDialog(View view, Bundle resultData) { FragmentTransaction fragment_transaction = getFragmentManager().beginTransaction(); - Fragment previous_log_in_dialog = getFragmentManager().findFragmentByTag(ConfigHelper.LOG_IN_DIALOG); + Fragment previous_log_in_dialog = getFragmentManager().findFragmentByTag(LogInDialog.TAG); if (previous_log_in_dialog != null) { fragment_transaction.remove(previous_log_in_dialog); } @@ -279,12 +281,12 @@ public class Dashboard extends Activity implements LogInDialog.LogInDialogInterf if(resultData != null && !resultData.isEmpty()) { Bundle user_message_bundle = new Bundle(); String user_message = resultData.getString(getResources().getString(R.string.user_message)); - String username = resultData.getString(ConfigHelper.USERNAME_KEY); + String username = resultData.getString(LogInDialog.USERNAME); user_message_bundle.putString(getResources().getString(R.string.user_message), user_message); - user_message_bundle.putString(ConfigHelper.USERNAME_KEY, username); + user_message_bundle.putString(LogInDialog.USERNAME, username); newFragment.setArguments(user_message_bundle); } - newFragment.show(fragment_transaction, ConfigHelper.LOG_IN_DIALOG); + newFragment.show(fragment_transaction, LogInDialog.TAG); } /** @@ -298,13 +300,13 @@ public class Dashboard extends Activity implements LogInDialog.LogInDialogInterf Intent provider_API_command = new Intent(this, ProviderAPI.class); Bundle parameters = new Bundle(); - parameters.putString(ConfigHelper.TYPE_OF_CERTIFICATE, ConfigHelper.AUTHED_CERTIFICATE); + 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); - provider_API_command.putExtra(ConfigHelper.RECEIVER_KEY, providerAPI_result_receiver); + provider_API_command.putExtra(ProviderAPI.RECEIVER_KEY, providerAPI_result_receiver); startService(provider_API_command); } @@ -312,8 +314,8 @@ public class Dashboard extends Activity implements LogInDialog.LogInDialogInterf @Override public void onReceiveResult(int resultCode, Bundle resultData) { if(resultCode == ProviderAPI.SRP_AUTHENTICATION_SUCCESSFUL){ - String session_id_cookie_key = resultData.getString(ConfigHelper.SESSION_ID_COOKIE_KEY); - String session_id_string = resultData.getString(ConfigHelper.SESSION_ID_KEY); + 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 = true; invalidateOptionsMenu(); diff --git a/src/se/leap/leapclient/EIP.java b/src/se/leap/leapclient/EIP.java index e0685c15..b0c22e50 100644 --- a/src/se/leap/leapclient/EIP.java +++ b/src/se/leap/leapclient/EIP.java @@ -62,6 +62,14 @@ public final class EIP extends IntentService { public final static String ACTION_UPDATE_EIP_SERVICE = "se.leap.leapclient.UPDATE_EIP_SERVICE"; public final static String ACTION_IS_EIP_RUNNING = "se.leap.leapclient.IS_RUNNING"; public final static String EIP_NOTIFICATION = "EIP_NOTIFICATION"; + public final static String ALLOWED_ANON = "allow_anonymous"; + public final static String CERTIFICATE = "certificate"; + public final static String PRIVATE_KEY = "private_key"; + public final static String KEY = "eip"; + public final static String PARSED_SERIAL = "eip_parsed_serial"; + 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"; private static Context context; private static ResultReceiver mReceiver; @@ -86,8 +94,8 @@ public final class EIP extends IntentService { context = getApplicationContext(); try { - eipDefinition = ConfigHelper.getJsonFromSharedPref(ConfigHelper.EIP_SERVICE_KEY); - parsedEipSerial = ConfigHelper.getIntFromSharedPref(ConfigHelper.EIP_PARSED_SERIAL); + eipDefinition = ConfigHelper.getJsonFromSharedPref(KEY); + parsedEipSerial = ConfigHelper.getIntFromSharedPref(PARSED_SERIAL); } catch (JSONException e) { // TODO Auto-generated catch block e.printStackTrace(); @@ -107,7 +115,7 @@ public final class EIP extends IntentService { @Override protected void onHandleIntent(Intent intent) { String action = intent.getAction(); - mReceiver = intent.getParcelableExtra(ConfigHelper.RECEIVER_TAG); + mReceiver = intent.getParcelableExtra(RECEIVER_TAG); if ( action == ACTION_IS_EIP_RUNNING ) this.isRunning(); @@ -150,7 +158,7 @@ public final class EIP extends IntentService { resultCode = (running) ? Activity.RESULT_CANCELED : Activity.RESULT_OK; Bundle resultData = new Bundle(); - resultData.putString(ConfigHelper.REQUEST_TAG, EIP_NOTIFICATION); + resultData.putString(REQUEST_TAG, EIP_NOTIFICATION); mReceiver.send(resultCode, resultData); mPending = null; @@ -163,7 +171,7 @@ public final class EIP extends IntentService { if (mReceiver != null){ Bundle resultData = new Bundle(); - resultData.putString(ConfigHelper.REQUEST_TAG, EIP_NOTIFICATION); + resultData.putString(REQUEST_TAG, EIP_NOTIFICATION); mReceiver.send(Activity.RESULT_CANCELED, resultData); } } @@ -181,7 +189,7 @@ public final class EIP extends IntentService { */ private void isRunning() { Bundle resultData = new Bundle(); - resultData.putString(ConfigHelper.REQUEST_TAG, ACTION_IS_EIP_RUNNING); + resultData.putString(REQUEST_TAG, ACTION_IS_EIP_RUNNING); int resultCode = Activity.RESULT_CANCELED; if (mBound) { resultCode = (mVpnService.isRunning()) ? Activity.RESULT_OK : Activity.RESULT_CANCELED; @@ -208,7 +216,7 @@ public final class EIP extends IntentService { intent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK); intent.putExtra(LaunchVPN.EXTRA_KEY, activeGateway.mVpnProfile.getUUID().toString() ); intent.putExtra(LaunchVPN.EXTRA_NAME, activeGateway.mVpnProfile.getName() ); - intent.putExtra(ConfigHelper.RECEIVER_TAG, mReceiver); + intent.putExtra(RECEIVER_TAG, mReceiver); startActivity(intent); mPending = ACTION_START_EIP; } @@ -225,7 +233,7 @@ public final class EIP extends IntentService { if (mReceiver != null){ Bundle resultData = new Bundle(); - resultData.putString(ConfigHelper.REQUEST_TAG, ACTION_STOP_EIP); + resultData.putString(REQUEST_TAG, ACTION_STOP_EIP); mReceiver.send(Activity.RESULT_OK, resultData); } } @@ -237,7 +245,7 @@ public final class EIP extends IntentService { */ private void updateEIPService() { try { - eipDefinition = ConfigHelper.getJsonFromSharedPref(ConfigHelper.EIP_SERVICE_KEY); + eipDefinition = ConfigHelper.getJsonFromSharedPref(EIP.KEY); } catch (JSONException e) { // TODO Auto-generated catch block e.printStackTrace(); @@ -294,7 +302,7 @@ public final class EIP extends IntentService { } } - ConfigHelper.saveSharedPref(ConfigHelper.EIP_PARSED_SERIAL, eipDefinition.optInt(ConfigHelper.API_RETURN_SERIAL_KEY)); + ConfigHelper.saveSharedPref(PARSED_SERIAL, eipDefinition.optInt(Provider.API_RETURN_SERIAL)); } /** diff --git a/src/se/leap/leapclient/EipServiceFragment.java b/src/se/leap/leapclient/EipServiceFragment.java index c18f83da..628572b4 100644 --- a/src/se/leap/leapclient/EipServiceFragment.java +++ b/src/se/leap/leapclient/EipServiceFragment.java @@ -159,7 +159,7 @@ public class EipServiceFragment extends Fragment implements StateListener, OnCli private void eipCommand(String action){ // TODO validate "action"...how do we get the list of intent-filters for a class via Android API? Intent vpnIntent = new Intent(action); - vpnIntent.putExtra(ConfigHelper.RECEIVER_TAG, mEIPReceiver); + vpnIntent.putExtra(EIP.RECEIVER_TAG, mEIPReceiver); getActivity().startService(vpnIntent); } @@ -214,7 +214,7 @@ public class EipServiceFragment extends Fragment implements StateListener, OnCli protected void onReceiveResult(int resultCode, Bundle resultData) { super.onReceiveResult(resultCode, resultData); - String request = resultData.getString(ConfigHelper.REQUEST_TAG); + String request = resultData.getString(EIP.REQUEST_TAG); boolean checked = false; if (request == EIP.ACTION_IS_EIP_RUNNING) { diff --git a/src/se/leap/leapclient/LeapHttpClient.java b/src/se/leap/leapclient/LeapHttpClient.java index ed926d28..5dca31e9 100644 --- a/src/se/leap/leapclient/LeapHttpClient.java +++ b/src/se/leap/leapclient/LeapHttpClient.java @@ -46,7 +46,7 @@ public class LeapHttpClient extends DefaultHttpClient { public static LeapHttpClient getInstance(Context context) { if(client == null) { client = new LeapHttpClient(context); - String cert_string = ConfigHelper.getStringFromSharedPref(ConfigHelper.MAIN_CERT_KEY); + String cert_string = ConfigHelper.getStringFromSharedPref(Provider.CA_CERT); if(cert_string != null) { ConfigHelper.addTrustedCertificate("provider_ca_certificate", cert_string); } diff --git a/src/se/leap/leapclient/LeapSRPSession.java b/src/se/leap/leapclient/LeapSRPSession.java index 9451c1be..fc30bd2b 100644 --- a/src/se/leap/leapclient/LeapSRPSession.java +++ b/src/se/leap/leapclient/LeapSRPSession.java @@ -34,6 +34,10 @@ import org.jboss.security.srp.SRPParameters; * */ public class LeapSRPSession { + + final public static String SALT = "salt"; + final public static String M1 = "m1"; + final public static String M2 = "m2"; private SRPParameters params; private String username; diff --git a/src/se/leap/leapclient/LogInDialog.java b/src/se/leap/leapclient/LogInDialog.java index 8e8bb65a..73833a13 100644 --- a/src/se/leap/leapclient/LogInDialog.java +++ b/src/se/leap/leapclient/LogInDialog.java @@ -38,7 +38,14 @@ import android.widget.TextView; * */ public class LogInDialog extends DialogFragment { - + + + 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"; + + public AlertDialog onCreateDialog(Bundle savedInstanceState) { AlertDialog.Builder builder = new AlertDialog.Builder(getActivity()); LayoutInflater inflater = getActivity().getLayoutInflater(); @@ -51,7 +58,7 @@ public class LogInDialog extends DialogFragment { final EditText username_field = (EditText)log_in_dialog_view.findViewById(R.id.username_entered); if(getArguments() != null && getArguments().containsKey(getResources().getString(R.string.user_message))) { - String username = getArguments().getString(ConfigHelper.USERNAME_KEY); + String username = getArguments().getString(USERNAME); username_field.setText(username); username_field.setHint(""); } diff --git a/src/se/leap/leapclient/NewProviderDialog.java b/src/se/leap/leapclient/NewProviderDialog.java index 0b9d8fd0..5cb16f7d 100644 --- a/src/se/leap/leapclient/NewProviderDialog.java +++ b/src/se/leap/leapclient/NewProviderDialog.java @@ -36,7 +36,9 @@ import android.widget.Toast; * */ public class NewProviderDialog extends DialogFragment { - + + final public static String TAG = "newProviderDialog"; + public interface NewProviderDialogInterface { public void saveAndSelectProvider(String url_provider, boolean danger_on); } diff --git a/src/se/leap/leapclient/Provider.java b/src/se/leap/leapclient/Provider.java index cdcd56c5..2846ea60 100644 --- a/src/se/leap/leapclient/Provider.java +++ b/src/se/leap/leapclient/Provider.java @@ -42,7 +42,21 @@ public final class Provider implements Serializable { private static SharedPreferences preferences = null; // Represents our Provider's provider.json private static JSONObject definition = null; - + + final public static String + API_URL = "api_uri", + API_VERSION = "api_version", + ALLOW_REGISTRATION = "allow_registration", + API_RETURN_SERIAL = "serial", + SERVICE = "service", + KEY = "provider", + CA_CERT = "ca_cert", + NAME = "name", + DESCRIPTION = "description", + DOMAIN = "domain", + MAIN_URL = "main_url", + DOT_JSON_URL = "provider_json_url" + ; // Array of what API versions we understand protected static final String[] API_VERSIONS = {"1"}; // I assume we might encounter arbitrary version "numbers" @@ -82,7 +96,7 @@ public final class Provider implements Serializable { //preferences = context.getgetPreferences(0); // 0 == MODE_PRIVATE, but we don't extend Android's classes... // Load SharedPreferences - preferences = activity.getSharedPreferences(ConfigHelper.PREFERENCES_KEY,Context.MODE_PRIVATE); + preferences = activity.getSharedPreferences(Dashboard.SHARED_PREFERENCES,Context.MODE_PRIVATE); // Inflate our provider.json data try { definition = new JSONObject( preferences.getString("provider", "") ); diff --git a/src/se/leap/leapclient/ProviderAPI.java b/src/se/leap/leapclient/ProviderAPI.java index 58dc8214..bc1602dc 100644 --- a/src/se/leap/leapclient/ProviderAPI.java +++ b/src/se/leap/leapclient/ProviderAPI.java @@ -89,7 +89,12 @@ public class ProviderAPI extends IntentService { SRP_AUTH = "srpAuth", LOG_OUT = "logOut", DOWNLOAD_CERTIFICATE = "downloadUserAuthedCertificate", - PARAMETERS = "parameters" + PARAMETERS = "parameters", + RESULT_KEY = "result", + RECEIVER_KEY = "receiver", + SESSION_ID_COOKIE_KEY = "session_id_cookie_key", + SESSION_ID_KEY = "session_id", + ERRORS = "errors" ; final public static int @@ -146,21 +151,21 @@ public class ProviderAPI extends IntentService { } } else if(action.equalsIgnoreCase(UPDATE_PROVIDER_DOTJSON)) { Bundle result = updateProviderDotJSON(parameters); - if(result.getBoolean(ConfigHelper.RESULT_KEY)) { + if(result.getBoolean(RESULT_KEY)) { receiver.send(CORRECTLY_UPDATED_PROVIDER_DOT_JSON, result); } else { receiver.send(INCORRECTLY_UPDATED_PROVIDER_DOT_JSON, Bundle.EMPTY); } } else if (action.equalsIgnoreCase(DOWNLOAD_NEW_PROVIDER_DOTJSON)) { Bundle result = downloadNewProviderDotJSON(parameters); - if(result.getBoolean(ConfigHelper.RESULT_KEY)) { + if(result.getBoolean(RESULT_KEY)) { receiver.send(CORRECTLY_UPDATED_PROVIDER_DOT_JSON, result); } else { receiver.send(INCORRECTLY_DOWNLOADED_JSON_FILES, Bundle.EMPTY); } } else if (action.equalsIgnoreCase(SRP_AUTH)) { Bundle session_id_bundle = authenticateBySRP(parameters); - if(session_id_bundle.getBoolean(ConfigHelper.RESULT_KEY)) { + if(session_id_bundle.getBoolean(RESULT_KEY)) { receiver.send(SRP_AUTHENTICATION_SUCCESSFUL, session_id_bundle); } else { receiver.send(SRP_AUTHENTICATION_FAILED, session_id_bundle); @@ -186,17 +191,17 @@ public class ProviderAPI extends IntentService { * @return true if eip-service.json was parsed as a JSON object correctly. */ private boolean downloadJsonFiles(Bundle task) { - String cert_url = task.getString(ConfigHelper.MAIN_CERT_KEY); - String eip_service_json_url = task.getString(ConfigHelper.EIP_SERVICE_KEY); - boolean danger_on = task.getBoolean(ConfigHelper.DANGER_ON); + String cert_url = task.getString(Provider.CA_CERT); + String eip_service_json_url = task.getString(EIP.KEY); + boolean danger_on = task.getBoolean(ProviderItem.DANGER_ON); try { String cert_string = downloadWithCommercialCA(cert_url, danger_on); X509Certificate certCert = ConfigHelper.parseX509CertificateFromString(cert_string); cert_string = Base64.encodeToString( certCert.getEncoded(), Base64.DEFAULT); - ConfigHelper.saveSharedPref(ConfigHelper.MAIN_CERT_KEY, "-----BEGIN CERTIFICATE-----\n"+cert_string+"-----END CERTIFICATE-----"); + ConfigHelper.saveSharedPref(Provider.CA_CERT, "-----BEGIN CERTIFICATE-----\n"+cert_string+"-----END CERTIFICATE-----"); String eip_service_string = downloadWithCommercialCA(eip_service_json_url, danger_on); - ConfigHelper.saveSharedPref(ConfigHelper.EIP_SERVICE_KEY, new JSONObject(eip_service_string)); + ConfigHelper.saveSharedPref(EIP.KEY, new JSONObject(eip_service_string)); return true; } catch (JSONException e) { @@ -212,15 +217,15 @@ public class ProviderAPI extends IntentService { * Starts the authentication process using SRP protocol. * * @param task containing: username, password and api url. - * @return a bundle with a boolean value mapped to a key named ConfigHelper.RESULT_KEY, and which is true if authentication was successful. + * @return a bundle with a boolean value mapped to a key named RESULT_KEY, and which is true if authentication was successful. */ private Bundle authenticateBySRP(Bundle task) { Bundle session_id_bundle = new Bundle(); - String username = (String) task.get(ConfigHelper.USERNAME_KEY); - String password = (String) task.get(ConfigHelper.PASSWORD_KEY); + String username = (String) task.get(LogInDialog.USERNAME); + String password = (String) task.get(LogInDialog.PASSWORD); if(wellFormedPassword(password)) { - String authentication_server = (String) task.get(ConfigHelper.API_URL_KEY); + String authentication_server = (String) task.get(Provider.API_URL); SRPParameters params = new SRPParameters(new BigInteger(ConfigHelper.NG_1024, 16).toByteArray(), ConfigHelper.G.toByteArray(), BigInteger.ZERO.toByteArray(), "SHA-256"); LeapSRPSession client = new LeapSRPSession(username, password, params); @@ -228,40 +233,38 @@ public class ProviderAPI extends IntentService { try { JSONObject saltAndB = sendAToSRPServer(authentication_server, username, new BigInteger(1, A).toString(16)); if(saltAndB.length() > 0) { - String salt = saltAndB.getString(ConfigHelper.SALT_KEY); + String salt = saltAndB.getString(LeapSRPSession.SALT); byte[] Bbytes = new BigInteger(saltAndB.getString("B"), 16).toByteArray(); byte[] M1 = client.response(new BigInteger(salt, 16).toByteArray(), Bbytes); JSONObject session_idAndM2 = sendM1ToSRPServer(authentication_server, username, M1); if(session_idAndM2.has("M2") && client.verify((byte[])session_idAndM2.get("M2"))) { - session_id_bundle.putBoolean(ConfigHelper.RESULT_KEY, true); - //session_id_bundle.putString(ConfigHelper.SESSION_ID_KEY, session_idAndM2.getString(ConfigHelper.SESSION_ID_KEY)); - //session_id_bundle.putString(ConfigHelper.SESSION_ID_COOKIE_KEY, session_idAndM2.getString(ConfigHelper.SESSION_ID_COOKIE_KEY)); + session_id_bundle.putBoolean(RESULT_KEY, true); } else { - session_id_bundle.putBoolean(ConfigHelper.RESULT_KEY, false); + session_id_bundle.putBoolean(RESULT_KEY, false); session_id_bundle.putString(getResources().getString(R.string.user_message), getResources().getString(R.string.error_bad_user_password_user_message)); - session_id_bundle.putString(ConfigHelper.USERNAME_KEY, username); + session_id_bundle.putString(LogInDialog.USERNAME, username); } } else { session_id_bundle.putString(getResources().getString(R.string.user_message), getResources().getString(R.string.error_bad_user_password_user_message)); - session_id_bundle.putString(ConfigHelper.USERNAME_KEY, username); - session_id_bundle.putBoolean(ConfigHelper.RESULT_KEY, false); + session_id_bundle.putString(LogInDialog.USERNAME, username); + session_id_bundle.putBoolean(RESULT_KEY, false); } } catch (ClientProtocolException e) { - session_id_bundle.putBoolean(ConfigHelper.RESULT_KEY, false); + session_id_bundle.putBoolean(RESULT_KEY, false); session_id_bundle.putString(getResources().getString(R.string.user_message), getResources().getString(R.string.error_client_http_user_message)); - session_id_bundle.putString(ConfigHelper.USERNAME_KEY, username); + session_id_bundle.putString(LogInDialog.USERNAME, username); } catch (IOException e) { - session_id_bundle.putBoolean(ConfigHelper.RESULT_KEY, false); + session_id_bundle.putBoolean(RESULT_KEY, false); session_id_bundle.putString(getResources().getString(R.string.user_message), getResources().getString(R.string.error_io_exception_user_message)); - session_id_bundle.putString(ConfigHelper.USERNAME_KEY, username); + session_id_bundle.putString(LogInDialog.USERNAME, username); } catch (JSONException e) { - session_id_bundle.putBoolean(ConfigHelper.RESULT_KEY, false); + session_id_bundle.putBoolean(RESULT_KEY, false); session_id_bundle.putString(getResources().getString(R.string.user_message), getResources().getString(R.string.error_json_exception_user_message)); - session_id_bundle.putString(ConfigHelper.USERNAME_KEY, username); + session_id_bundle.putString(LogInDialog.USERNAME, username); } catch (NoSuchAlgorithmException e) { - session_id_bundle.putBoolean(ConfigHelper.RESULT_KEY, false); + session_id_bundle.putBoolean(RESULT_KEY, false); session_id_bundle.putString(getResources().getString(R.string.user_message), getResources().getString(R.string.error_no_such_algorithm_exception_user_message)); - session_id_bundle.putString(ConfigHelper.USERNAME_KEY, username); + session_id_bundle.putString(LogInDialog.USERNAME, username); } catch (KeyManagementException e) { // TODO Auto-generated catch block e.printStackTrace(); @@ -273,9 +276,9 @@ public class ProviderAPI extends IntentService { e.printStackTrace(); } } else { - session_id_bundle.putBoolean(ConfigHelper.RESULT_KEY, false); + session_id_bundle.putBoolean(RESULT_KEY, false); session_id_bundle.putString(getResources().getString(R.string.user_message), getResources().getString(R.string.error_not_valid_password_user_message)); - session_id_bundle.putString(ConfigHelper.USERNAME_KEY, username); + session_id_bundle.putString(LogInDialog.USERNAME, username); } return session_id_bundle; @@ -337,11 +340,11 @@ public class ProviderAPI extends IntentService { JSONObject session_idAndM2 = new JSONObject(); if(json_response.length() > 0) { - byte[] M2_not_trimmed = new BigInteger(json_response.getString(ConfigHelper.M2_KEY), 16).toByteArray(); + byte[] M2_not_trimmed = new BigInteger(json_response.getString(LeapSRPSession.M2), 16).toByteArray(); /*Cookie session_id_cookie = LeapHttpClient.getInstance(getApplicationContext()).getCookieStore().getCookies().get(0); session_idAndM2.put(ConfigHelper.SESSION_ID_COOKIE_KEY, session_id_cookie.getName()); session_idAndM2.put(ConfigHelper.SESSION_ID_KEY, session_id_cookie.getValue());*/ - session_idAndM2.put(ConfigHelper.M2_KEY, ConfigHelper.trim(M2_not_trimmed)); + session_idAndM2.put(LeapSRPSession.M2, ConfigHelper.trim(M2_not_trimmed)); } return session_idAndM2; } @@ -383,7 +386,7 @@ public class ProviderAPI extends IntentService { urlConnection.disconnect(); Log.d("Error", error_response); json_response = new JSONObject(error_response); - if(!json_response.isNull(ConfigHelper.ERRORS_KEY) || json_response.has(ConfigHelper.ERRORS_KEY)) { + if(!json_response.isNull(ERRORS) || json_response.has(ERRORS)) { return new JSONObject(); } } @@ -416,30 +419,30 @@ public class ProviderAPI extends IntentService { /** * Downloads a provider.json from a given URL, adding a new provider using the given name. * @param task containing a boolean meaning if the provider is custom or not, another boolean meaning if the user completely trusts this provider, the provider name and its provider.json url. - * @return a bundle with a boolean value mapped to a key named ConfigHelper.RESULT_KEY, and which is true if the update was successful. + * @return a bundle with a boolean value mapped to a key named RESULT_KEY, and which is true if the update was successful. */ private Bundle updateProviderDotJSON(Bundle task) { Bundle result = new Bundle(); - boolean custom = task.getBoolean(ConfigHelper.CUSTOM); - boolean danger_on = task.getBoolean(ConfigHelper.DANGER_ON); - String provider_json_url = task.getString(ConfigHelper.PROVIDER_JSON_URL); - String provider_name = task.getString(ConfigHelper.PROVIDER_NAME); + boolean custom = task.getBoolean(ProviderItem.CUSTOM); + boolean danger_on = task.getBoolean(ProviderItem.DANGER_ON); + String provider_json_url = task.getString(Provider.DOT_JSON_URL); + String provider_name = task.getString(Provider.NAME); try { String provider_dot_json_string = downloadWithCommercialCA(provider_json_url, danger_on); if(provider_dot_json_string.isEmpty()) { - result.putBoolean(ConfigHelper.RESULT_KEY, false); + result.putBoolean(RESULT_KEY, false); } else { JSONObject provider_json = new JSONObject(provider_dot_json_string); - ConfigHelper.saveSharedPref(ConfigHelper.ALLOWED_ANON, provider_json.getJSONObject(ConfigHelper.SERVICE_KEY).getBoolean(ConfigHelper.ALLOWED_ANON)); + ConfigHelper.saveSharedPref(EIP.ALLOWED_ANON, provider_json.getJSONObject(Provider.SERVICE).getBoolean(EIP.ALLOWED_ANON)); //ProviderListContent.addItem(new ProviderItem(provider_name, provider_json_url, provider_json, custom, danger_on)); - result.putBoolean(ConfigHelper.RESULT_KEY, true); - result.putString(ConfigHelper.PROVIDER_KEY, provider_json.toString()); - result.putBoolean(ConfigHelper.DANGER_ON, danger_on); + result.putBoolean(RESULT_KEY, true); + result.putString(Provider.KEY, provider_json.toString()); + result.putBoolean(ProviderItem.DANGER_ON, danger_on); } } catch (JSONException e) { - result.putBoolean(ConfigHelper.RESULT_KEY, false); + result.putBoolean(RESULT_KEY, false); } return result; @@ -453,32 +456,32 @@ public class ProviderAPI extends IntentService { private Bundle downloadNewProviderDotJSON(Bundle task) { Bundle result = new Bundle(); boolean custom = true; - boolean danger_on = task.getBoolean(ConfigHelper.DANGER_ON); + boolean danger_on = task.getBoolean(ProviderItem.DANGER_ON); - String provider_main_url = (String) task.get(ConfigHelper.PROVIDER_MAIN_URL); + String provider_main_url = (String) task.get(Provider.MAIN_URL); String provider_name = provider_main_url.replaceFirst("http[s]?://", "").replaceFirst("\\/", "_"); String provider_json_url = guessProviderDotJsonURL(provider_main_url); String provider_json_string = downloadWithCommercialCA(provider_json_url, danger_on); try { if(provider_json_string.isEmpty()) { - result.putBoolean(ConfigHelper.RESULT_KEY, false); + result.putBoolean(RESULT_KEY, false); } else { JSONObject provider_json = new JSONObject(provider_json_string); - ConfigHelper.saveSharedPref(ConfigHelper.PROVIDER_KEY, provider_json); - ConfigHelper.saveSharedPref(ConfigHelper.DANGER_ON, danger_on); - ConfigHelper.saveSharedPref(ConfigHelper.ALLOWED_ANON, provider_json.getJSONObject(ConfigHelper.SERVICE_KEY).getBoolean(ConfigHelper.ALLOWED_ANON)); + ConfigHelper.saveSharedPref(Provider.KEY, provider_json); + ConfigHelper.saveSharedPref(ProviderItem.DANGER_ON, danger_on); + ConfigHelper.saveSharedPref(EIP.ALLOWED_ANON, provider_json.getJSONObject(Provider.SERVICE).getBoolean(EIP.ALLOWED_ANON)); ProviderItem added_provider = new ProviderItem(provider_name, provider_json_url, provider_json, custom, danger_on); ProviderListContent.addItem(added_provider); - result.putString(ConfigHelper.PROVIDER_ID, added_provider.getId()); - result.putBoolean(ConfigHelper.RESULT_KEY, true); - result.putString(ConfigHelper.PROVIDER_KEY, provider_json.toString()); - result.putBoolean(ConfigHelper.DANGER_ON, danger_on); + result.putString(Provider.NAME, added_provider.getName()); + result.putBoolean(RESULT_KEY, true); + result.putString(Provider.KEY, provider_json.toString()); + result.putBoolean(ProviderItem.DANGER_ON, danger_on); } } catch (JSONException e) { - result.putBoolean(ConfigHelper.RESULT_KEY, false); + result.putBoolean(RESULT_KEY, false); } return result; @@ -569,7 +572,7 @@ public class ProviderAPI extends IntentService { } private javax.net.ssl.SSLSocketFactory getProviderSSLSocketFactory() throws KeyStoreException, NoSuchAlgorithmException, CertificateException, IOException, KeyManagementException { - String provider_cert_string = ConfigHelper.getStringFromSharedPref(ConfigHelper.MAIN_CERT_KEY); + String provider_cert_string = ConfigHelper.getStringFromSharedPref(Provider.CA_CERT); java.security.cert.Certificate provider_certificate = ConfigHelper.parseX509CertificateFromString(provider_cert_string); @@ -660,7 +663,7 @@ public class ProviderAPI extends IntentService { */ private boolean logOut(Bundle task) { try { - String delete_url = task.getString(ConfigHelper.API_URL_KEY) + "/logout"; + String delete_url = task.getString(Provider.API_URL) + "/logout"; HttpsURLConnection urlConnection = (HttpsURLConnection)new URL(delete_url).openConnection(); urlConnection.setRequestMethod("DELETE"); @@ -703,30 +706,14 @@ public class ProviderAPI extends IntentService { * @return true if certificate was downloaded correctly, false if provider.json or danger_on flag are not present in SharedPreferences, or if the certificate url could not be parsed as a URI, or if there was an SSL error. */ private boolean getNewCert(Bundle task) { - //String type_of_certificate = task.getString(ConfigHelper.TYPE_OF_CERTIFICATE); + try { - JSONObject provider_json = ConfigHelper.getJsonFromSharedPref(ConfigHelper.PROVIDER_KEY); - URL provider_main_url = new URL(provider_json.getString(ConfigHelper.API_URL_KEY)); - String new_cert_string_url = provider_main_url.toString() + "/" + provider_json.getString(ConfigHelper.API_VERSION_KEY) + "/" + ConfigHelper.CERT_KEY; - - /*Cookie cookie = null; - if(type_of_certificate.equalsIgnoreCase(ConfigHelper.AUTHED_CERTIFICATE)) { - List list_cookies = LeapHttpClient.getInstance(getApplicationContext()).getCookieStore().getCookies(); - for(Cookie aux_cookie : list_cookies) { - if(aux_cookie.getName().equalsIgnoreCase(ConfigHelper.SESSION_ID_COOKIE_KEY)) { - cookie = aux_cookie; - break; - } - }*/ - //HttpCookie session_id_cookie = new HttpCookie(task.getString(ConfigHelper.SESSION_ID_COOKIE_KEY), task.getString(ConfigHelper.SESSION_ID_KEY)); - /*HttpCookie session_id_cookie = new HttpCookie(cookie.getName(), cookie.getValue()); - - CookieManager cookieManager = new CookieManager(); - cookieManager.getCookieStore().add(provider_main_url.toURI(), session_id_cookie); - CookieHandler.setDefault(cookieManager);*/ - //} - - boolean danger_on = ConfigHelper.getBoolFromSharedPref(ConfigHelper.DANGER_ON); + String type_of_certificate = task.getString(ConfigurationWizard.TYPE_OF_CERTIFICATE); + JSONObject provider_json = ConfigHelper.getJsonFromSharedPref(Provider.KEY); + URL provider_main_url = new URL(provider_json.getString(Provider.API_URL)); + String new_cert_string_url = provider_main_url.toString() + "/" + provider_json.getString(Provider.API_VERSION) + "/" + EIP.CERTIFICATE; + + boolean danger_on = ConfigHelper.getBoolFromSharedPref(ProviderItem.DANGER_ON); String cert_string = downloadWithCommercialCA(new_cert_string_url, danger_on); if(!cert_string.isEmpty()) { // API returns concatenated cert & key. Split them for OpenVPN options @@ -743,11 +730,11 @@ public class ProviderAPI extends IntentService { try { RSAPrivateKey keyCert = ConfigHelper.parseRsaKeyFromString(keyString); keyString = Base64.encodeToString( keyCert.getEncoded(), Base64.DEFAULT ); - ConfigHelper.saveSharedPref(ConfigHelper.KEY_KEY, "-----BEGIN RSA PRIVATE KEY-----\n"+keyString+"-----END RSA PRIVATE KEY-----"); + ConfigHelper.saveSharedPref(EIP.PRIVATE_KEY, "-----BEGIN RSA PRIVATE KEY-----\n"+keyString+"-----END RSA PRIVATE KEY-----"); X509Certificate certCert = ConfigHelper.parseX509CertificateFromString(certificateString); certificateString = Base64.encodeToString( certCert.getEncoded(), Base64.DEFAULT); - ConfigHelper.saveSharedPref(ConfigHelper.CERT_KEY, "-----BEGIN CERTIFICATE-----\n"+certificateString+"-----END CERTIFICATE-----"); + ConfigHelper.saveSharedPref(EIP.CERTIFICATE, "-----BEGIN CERTIFICATE-----\n"+certificateString+"-----END CERTIFICATE-----"); return true; } catch (CertificateException e) { diff --git a/src/se/leap/leapclient/ProviderDetailFragment.java b/src/se/leap/leapclient/ProviderDetailFragment.java index 600be58f..e7af140a 100644 --- a/src/se/leap/leapclient/ProviderDetailFragment.java +++ b/src/se/leap/leapclient/ProviderDetailFragment.java @@ -3,6 +3,8 @@ package se.leap.leapclient; import org.json.JSONException; import org.json.JSONObject; +import se.leap.leapclient.ProviderListContent.ProviderItem; + import android.app.Activity; import android.app.AlertDialog; import android.app.Dialog; @@ -14,6 +16,9 @@ import android.view.View; import android.widget.TextView; public class ProviderDetailFragment extends DialogFragment { + + final public static String TAG = "providerDetailFragment"; + @Override public Dialog onCreateDialog(Bundle savedInstanceState) { AlertDialog.Builder builder = new AlertDialog.Builder(getActivity()); @@ -22,14 +27,14 @@ public class ProviderDetailFragment extends DialogFragment { LayoutInflater inflater = getActivity().getLayoutInflater(); View provider_detail_view = inflater.inflate(R.layout.provider_detail_fragment, null); - JSONObject provider_json = ConfigHelper.getJsonFromSharedPref(ConfigHelper.PROVIDER_KEY); + JSONObject provider_json = ConfigHelper.getJsonFromSharedPref(Provider.KEY); final TextView domain = (TextView)provider_detail_view.findViewById(R.id.provider_detail_domain); - domain.setText(provider_json.getString(ConfigHelper.DOMAIN)); + domain.setText(provider_json.getString(Provider.DOMAIN)); final TextView name = (TextView)provider_detail_view.findViewById(R.id.provider_detail_name); - name.setText(provider_json.getJSONObject(ConfigHelper.NAME).getString("en")); + name.setText(provider_json.getJSONObject(Provider.NAME).getString("en")); final TextView description = (TextView)provider_detail_view.findViewById(R.id.provider_detail_description); - description.setText(provider_json.getJSONObject(ConfigHelper.DESCRIPTION).getString("en")); + description.setText(provider_json.getJSONObject(Provider.DESCRIPTION).getString("en")); builder.setView(provider_detail_view); builder.setTitle(R.string.provider_details_fragment_title); @@ -58,8 +63,8 @@ public class ProviderDetailFragment extends DialogFragment { private boolean anon_allowed(JSONObject provider_json) { try { - JSONObject service_description = provider_json.getJSONObject(ConfigHelper.SERVICE_KEY); - return service_description.has(ConfigHelper.ALLOWED_ANON) && service_description.getBoolean(ConfigHelper.ALLOWED_ANON); + JSONObject service_description = provider_json.getJSONObject(Provider.SERVICE); + return service_description.has(EIP.ALLOWED_ANON) && service_description.getBoolean(EIP.ALLOWED_ANON); } catch (JSONException e) { return false; } @@ -67,8 +72,8 @@ public class ProviderDetailFragment extends DialogFragment { private boolean registration_allowed(JSONObject provider_json) { try { - JSONObject service_description = provider_json.getJSONObject(ConfigHelper.SERVICE_KEY); - return service_description.has(ConfigHelper.ALLOW_REGISTRATION_KEY) && service_description.getBoolean(ConfigHelper.ALLOW_REGISTRATION_KEY); + JSONObject service_description = provider_json.getJSONObject(Provider.SERVICE); + return service_description.has(Provider.ALLOW_REGISTRATION) && service_description.getBoolean(Provider.ALLOW_REGISTRATION); } catch (JSONException e) { return false; } @@ -77,10 +82,10 @@ public class ProviderDetailFragment extends DialogFragment { @Override public void onCancel(DialogInterface dialog) { super.onCancel(dialog); - ConfigHelper.removeFromSharedPref(ConfigHelper.PROVIDER_KEY); - ConfigHelper.removeFromSharedPref(ConfigHelper.DANGER_ON); - ConfigHelper.removeFromSharedPref(ConfigHelper.ALLOWED_ANON); - ConfigHelper.removeFromSharedPref(ConfigHelper.EIP_SERVICE_KEY); + ConfigHelper.removeFromSharedPref(Provider.KEY); + ConfigHelper.removeFromSharedPref(ProviderItem.DANGER_ON); + ConfigHelper.removeFromSharedPref(EIP.ALLOWED_ANON); + ConfigHelper.removeFromSharedPref(EIP.KEY); } public static DialogFragment newInstance() { diff --git a/src/se/leap/leapclient/ProviderListContent.java b/src/se/leap/leapclient/ProviderListContent.java index 714ed5f4..6cd92430 100644 --- a/src/se/leap/leapclient/ProviderListContent.java +++ b/src/se/leap/leapclient/ProviderListContent.java @@ -52,7 +52,12 @@ public class ProviderListContent { /** * A provider item. */ - public static class ProviderItem { + public static class ProviderItem { + + + final public static String CUSTOM = "custom"; + final public static String DANGER_ON = "danger_on"; + public boolean custom = false; public String id; public String name; @@ -79,11 +84,11 @@ public class ProviderListContent { JSONObject file_contents = new JSONObject(urls_file_content); id = name; this.name = name; - provider_json_url = file_contents.getString(ConfigHelper.PROVIDER_JSON_URL); + provider_json_url = file_contents.getString(Provider.DOT_JSON_URL); domain = new URL(provider_json_url).getHost(); //provider_json_filename = file_contents.getString("assets_json_provider"); eip_service_json_url = file_contents.getString("json_eip_service"); - cert_json_url = file_contents.getString(ConfigHelper.CERT_KEY); + cert_json_url = file_contents.getString(EIP.CERTIFICATE); this.custom = custom; this.danger_on = danger_on; } catch (MalformedURLException e) { @@ -114,7 +119,7 @@ public class ProviderListContent { this.provider_json = provider_json; this.name = provider_json.getJSONObject("name").getString("en"); domain = new URL(provider_json_url).getHost(); - eip_service_json_url = provider_json.getString(ConfigHelper.API_URL_KEY) + "/" + provider_json.getString(ConfigHelper.API_VERSION_KEY) + "/" + ConfigHelper.EIP_SERVICE_API_PATH; + eip_service_json_url = provider_json.getString(Provider.API_URL) + "/" + provider_json.getString(Provider.API_VERSION) + "/" + EIP.SERVICE_API_PATH; cert_json_url = provider_json.getString("ca_cert_uri"); this.custom = custom; this.danger_on = danger_on; @@ -134,7 +139,7 @@ public class ProviderListContent { return name; } - public String getId() { + public String getName() { return id; } } diff --git a/src/se/leap/openvpn/LaunchVPN.java b/src/se/leap/openvpn/LaunchVPN.java index 1df6be96..73003c7e 100644 --- a/src/se/leap/openvpn/LaunchVPN.java +++ b/src/se/leap/openvpn/LaunchVPN.java @@ -106,7 +106,7 @@ public class LaunchVPN extends ListActivity implements OnItemClickListener { final String action = intent.getAction(); // If something wants feedback, they sent us a Receiver - mReceiver = intent.getParcelableExtra(ConfigHelper.RECEIVER_TAG); + mReceiver = intent.getParcelableExtra(EIP.RECEIVER_TAG); // If the intent is a request to create a shortcut, we'll do that and exit @@ -285,7 +285,7 @@ public class LaunchVPN extends ListActivity implements OnItemClickListener { // User does not want us to start, so we just vanish (well, now we tell our receiver, then vanish) Bundle resultData = new Bundle(); // For now, nothing else is calling, so this "request" string is good enough - resultData.putString(ConfigHelper.REQUEST_TAG, EIP.ACTION_START_EIP); + resultData.putString(EIP.REQUEST_TAG, EIP.ACTION_START_EIP); mReceiver.send(RESULT_CANCELED, resultData); finish(); } @@ -373,7 +373,7 @@ public class LaunchVPN extends ListActivity implements OnItemClickListener { // Tell whom-it-may-concern that we started VPN Bundle resultData = new Bundle(); // For now, nothing else is calling, so this "request" string is good enough - resultData.putString(ConfigHelper.REQUEST_TAG, EIP.ACTION_START_EIP); + resultData.putString(EIP.REQUEST_TAG, EIP.ACTION_START_EIP); mReceiver.send(RESULT_OK, resultData); finish(); diff --git a/src/se/leap/openvpn/VpnProfile.java b/src/se/leap/openvpn/VpnProfile.java index 2262f565..5752081a 100644 --- a/src/se/leap/openvpn/VpnProfile.java +++ b/src/se/leap/openvpn/VpnProfile.java @@ -22,6 +22,8 @@ import org.spongycastle.util.io.pem.PemObject; import org.spongycastle.util.io.pem.PemWriter; import se.leap.leapclient.ConfigHelper; +import se.leap.leapclient.EIP; +import se.leap.leapclient.Provider; import se.leap.leapclient.R; import android.content.Context; @@ -246,9 +248,9 @@ public class VpnProfile implements Serializable{ cfg+=insertFileData("cert",mClientCertFilename); */ // FIXME This is all we need...The whole switch statement can go... - cfg+="\n"+ConfigHelper.getStringFromSharedPref(ConfigHelper.MAIN_CERT_KEY)+"\n\n"; - cfg+="\n"+ConfigHelper.getStringFromSharedPref(ConfigHelper.KEY_KEY)+"\n\n"; - cfg+="\n"+ConfigHelper.getStringFromSharedPref(ConfigHelper.CERT_KEY)+"\n\n"; + cfg+="\n"+ConfigHelper.getStringFromSharedPref(Provider.CA_CERT)+"\n\n"; + cfg+="\n"+ConfigHelper.getStringFromSharedPref(EIP.PRIVATE_KEY)+"\n\n"; + cfg+="\n"+ConfigHelper.getStringFromSharedPref(EIP.CERTIFICATE)+"\n\n"; break; case VpnProfile.TYPE_USERPASS_PKCS12: -- cgit v1.2.3 From 4e21714544d3e7002fea884fabbd75b5ebc1d05f Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Parm=C3=A9nides=20GV?= Date: Mon, 30 Sep 2013 11:53:40 +0200 Subject: Erroneous CA cert download correctly handled. If there is an error while downloading CA cert on downloadJsonFiles, false is returned and progress dialog is dismissed. --- src/se/leap/leapclient/ConfigurationWizard.java | 1 + src/se/leap/leapclient/ProviderAPI.java | 1 + 2 files changed, 2 insertions(+) diff --git a/src/se/leap/leapclient/ConfigurationWizard.java b/src/se/leap/leapclient/ConfigurationWizard.java index 4a8158d6..dd9f4121 100644 --- a/src/se/leap/leapclient/ConfigurationWizard.java +++ b/src/se/leap/leapclient/ConfigurationWizard.java @@ -143,6 +143,7 @@ implements ProviderListFragment.Callbacks, NewProviderDialog.NewProviderDialogIn } else if(resultCode == ProviderAPI.INCORRECTLY_DOWNLOADED_JSON_FILES) { //Toast.makeText(getApplicationContext(), R.string.incorrectly_downloaded_json_files_message, Toast.LENGTH_LONG).show(); + mProgressDialog.dismiss(); setResult(RESULT_CANCELED, mConfigState); } else if(resultCode == ProviderAPI.CORRECTLY_DOWNLOADED_CERTIFICATE) { diff --git a/src/se/leap/leapclient/ProviderAPI.java b/src/se/leap/leapclient/ProviderAPI.java index bc1602dc..0935cd8d 100644 --- a/src/se/leap/leapclient/ProviderAPI.java +++ b/src/se/leap/leapclient/ProviderAPI.java @@ -196,6 +196,7 @@ public class ProviderAPI extends IntentService { boolean danger_on = task.getBoolean(ProviderItem.DANGER_ON); try { String cert_string = downloadWithCommercialCA(cert_url, danger_on); + if(cert_string.isEmpty()) return false; X509Certificate certCert = ConfigHelper.parseX509CertificateFromString(cert_string); cert_string = Base64.encodeToString( certCert.getEncoded(), Base64.DEFAULT); ConfigHelper.saveSharedPref(Provider.CA_CERT, "-----BEGIN CERTIFICATE-----\n"+cert_string+"-----END CERTIFICATE-----"); -- cgit v1.2.3 From 97b517f386cdecefff806d79ad29355b60636e96 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Parm=C3=A9nides=20GV?= Date: Mon, 30 Sep 2013 20:10:16 +0200 Subject: Fixed typo in EIP.certificate --- src/se/leap/leapclient/EIP.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/se/leap/leapclient/EIP.java b/src/se/leap/leapclient/EIP.java index b0c22e50..0a537b4d 100644 --- a/src/se/leap/leapclient/EIP.java +++ b/src/se/leap/leapclient/EIP.java @@ -63,7 +63,7 @@ public final class EIP extends IntentService { public final static String ACTION_IS_EIP_RUNNING = "se.leap.leapclient.IS_RUNNING"; public final static String EIP_NOTIFICATION = "EIP_NOTIFICATION"; public final static String ALLOWED_ANON = "allow_anonymous"; - public final static String CERTIFICATE = "certificate"; + public final static String CERTIFICATE = "cert"; public final static String PRIVATE_KEY = "private_key"; public final static String KEY = "eip"; public final static String PARSED_SERIAL = "eip_parsed_serial"; -- cgit v1.2.3 From 83f18ec709d71d843155a8df853b014e5a599c01 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Parm=C3=A9nides=20GV?= Date: Thu, 3 Oct 2013 10:18:18 +0200 Subject: Fixed M2 and M1 constants values. Logging in, it was returning a "Bad response from server" due to the malinterpretation of the received JSON. It was looking for a field named "m2", but it was "M2". --- src/se/leap/leapclient/LeapSRPSession.java | 4 ++-- src/se/leap/leapclient/ProviderAPI.java | 2 +- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/src/se/leap/leapclient/LeapSRPSession.java b/src/se/leap/leapclient/LeapSRPSession.java index fc30bd2b..5a78219b 100644 --- a/src/se/leap/leapclient/LeapSRPSession.java +++ b/src/se/leap/leapclient/LeapSRPSession.java @@ -36,8 +36,8 @@ import org.jboss.security.srp.SRPParameters; public class LeapSRPSession { final public static String SALT = "salt"; - final public static String M1 = "m1"; - final public static String M2 = "m2"; + final public static String M1 = "M1"; + final public static String M2 = "M2"; private SRPParameters params; private String username; diff --git a/src/se/leap/leapclient/ProviderAPI.java b/src/se/leap/leapclient/ProviderAPI.java index 0935cd8d..e7d329f8 100644 --- a/src/se/leap/leapclient/ProviderAPI.java +++ b/src/se/leap/leapclient/ProviderAPI.java @@ -238,7 +238,7 @@ public class ProviderAPI extends IntentService { byte[] Bbytes = new BigInteger(saltAndB.getString("B"), 16).toByteArray(); byte[] M1 = client.response(new BigInteger(salt, 16).toByteArray(), Bbytes); JSONObject session_idAndM2 = sendM1ToSRPServer(authentication_server, username, M1); - if(session_idAndM2.has("M2") && client.verify((byte[])session_idAndM2.get("M2"))) { + if(session_idAndM2.has(LeapSRPSession.M2) && client.verify((byte[])session_idAndM2.get(LeapSRPSession.M2))) { session_id_bundle.putBoolean(RESULT_KEY, true); } else { session_id_bundle.putBoolean(RESULT_KEY, false); -- cgit v1.2.3 From 37bb23c5549ffe690f65b1c04cf432bd3153bf04 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Parm=C3=A9nides=20GV?= Date: Wed, 14 Aug 2013 12:15:42 +0200 Subject: Login dialog requires username. I've also changed the way we notify that the password should have 8 characters at least, to make it consistent to the way we notify username is required. --- res/layout/log_in_dialog.xml | 4 ++-- res/values/strings.xml | 7 ++++--- src/se/leap/leapclient/Dashboard.java | 7 +------ src/se/leap/leapclient/LogInDialog.java | 26 ++++++++++++++++++++++---- src/se/leap/leapclient/ProviderAPI.java | 24 ++++++++++++++++++++---- 5 files changed, 49 insertions(+), 19 deletions(-) diff --git a/res/layout/log_in_dialog.xml b/res/layout/log_in_dialog.xml index 4c9fdbad..3a9eebb8 100644 --- a/res/layout/log_in_dialog.xml +++ b/res/layout/log_in_dialog.xml @@ -22,7 +22,7 @@ android:layout_marginRight="4dp" android:layout_marginTop="16dp" android:ems="10" - android:hint="@string/username_ask" + android:hint="@string/username_hint" android:inputType="textUri" > @@ -33,7 +33,7 @@ android:layout_width="match_parent" android:layout_height="wrap_content" android:ems="10" - android:hint="@string/password_ask" + android:hint="@string/password_hint" android:inputType="textPassword" /> \ No newline at end of file diff --git a/res/values/strings.xml b/res/values/strings.xml index 532d2379..a6afb71d 100755 --- a/res/values/strings.xml +++ b/res/values/strings.xml @@ -274,11 +274,12 @@ Name Description Use anonymously - Introduce your username - Enter your password + username + Please enter your username + password User message Not valid username and/or password. - Your password is not well-formed: it should have at least 8 characters. + It should have at least 8 characters. Try again: Client HTTP error Try again: I/O error Try again: Bad response from the server diff --git a/src/se/leap/leapclient/Dashboard.java b/src/se/leap/leapclient/Dashboard.java index 371663b7..19d33a12 100644 --- a/src/se/leap/leapclient/Dashboard.java +++ b/src/se/leap/leapclient/Dashboard.java @@ -279,12 +279,7 @@ public class Dashboard extends Activity implements LogInDialog.LogInDialogInterf DialogFragment newFragment = LogInDialog.newInstance(); if(resultData != null && !resultData.isEmpty()) { - Bundle user_message_bundle = new Bundle(); - String user_message = resultData.getString(getResources().getString(R.string.user_message)); - String username = resultData.getString(LogInDialog.USERNAME); - user_message_bundle.putString(getResources().getString(R.string.user_message), user_message); - user_message_bundle.putString(LogInDialog.USERNAME, username); - newFragment.setArguments(user_message_bundle); + newFragment.setArguments(resultData); } newFragment.show(fragment_transaction, LogInDialog.TAG); } diff --git a/src/se/leap/leapclient/LogInDialog.java b/src/se/leap/leapclient/LogInDialog.java index 73833a13..7dd1c732 100644 --- a/src/se/leap/leapclient/LogInDialog.java +++ b/src/se/leap/leapclient/LogInDialog.java @@ -17,13 +17,18 @@ package se.leap.leapclient; import se.leap.leapclient.R; +import android.R.color; import android.app.Activity; import android.app.AlertDialog; import android.app.DialogFragment; import android.content.DialogInterface; +import android.content.res.ColorStateList; import android.os.Bundle; +import android.provider.CalendarContract.Colors; import android.view.LayoutInflater; import android.view.View; +import android.view.animation.AlphaAnimation; +import android.view.animation.BounceInterpolator; import android.widget.EditText; import android.widget.TextView; @@ -44,6 +49,8 @@ public class LogInDialog extends DialogFragment { 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 AlertDialog onCreateDialog(Bundle savedInstanceState) { @@ -54,23 +61,34 @@ public class LogInDialog extends DialogFragment { final TextView user_message = (TextView)log_in_dialog_view.findViewById(R.id.user_message); if(getArguments() != null && getArguments().containsKey(getResources().getString(R.string.user_message))) { user_message.setText(getArguments().getString(getResources().getString(R.string.user_message))); - } else user_message.setVisibility(View.GONE); + } else { + user_message.setVisibility(View.GONE); + } final EditText username_field = (EditText)log_in_dialog_view.findViewById(R.id.username_entered); - if(getArguments() != null && getArguments().containsKey(getResources().getString(R.string.user_message))) { + if(getArguments() != null && getArguments().containsKey(USERNAME)) { String username = getArguments().getString(USERNAME); username_field.setText(username); - username_field.setHint(""); } + if (getArguments() != null && getArguments().containsKey(USERNAME_MISSING)) { + username_field.setError(getResources().getString(R.string.username_ask)); + } + final EditText password_field = (EditText)log_in_dialog_view.findViewById(R.id.password_entered); - if(!username_field.getText().toString().isEmpty() && password_field.isFocusable()) + if(!username_field.getText().toString().isEmpty() && password_field.isFocusable()) { password_field.requestFocus(); + } + if (getArguments() != null && getArguments().containsKey(PASSWORD_INVALID_LENGTH)) { + password_field.setError(getResources().getString(R.string.error_not_valid_password_user_message)); + } + builder.setView(log_in_dialog_view) .setPositiveButton(R.string.login_button, new DialogInterface.OnClickListener() { public void onClick(DialogInterface dialog, int id) { String username = username_field.getText().toString().trim(); String password = password_field.getText().toString().trim(); + dialog.dismiss(); interface_with_Dashboard.authenticate(username, password); } }) diff --git a/src/se/leap/leapclient/ProviderAPI.java b/src/se/leap/leapclient/ProviderAPI.java index e7d329f8..2170478b 100644 --- a/src/se/leap/leapclient/ProviderAPI.java +++ b/src/se/leap/leapclient/ProviderAPI.java @@ -225,7 +225,7 @@ public class ProviderAPI extends IntentService { String username = (String) task.get(LogInDialog.USERNAME); String password = (String) task.get(LogInDialog.PASSWORD); - if(wellFormedPassword(password)) { + if(validUserLoginData(username, password)) { String authentication_server = (String) task.get(Provider.API_URL); SRPParameters params = new SRPParameters(new BigInteger(ConfigHelper.NG_1024, 16).toByteArray(), ConfigHelper.G.toByteArray(), BigInteger.ZERO.toByteArray(), "SHA-256"); @@ -277,14 +277,30 @@ public class ProviderAPI extends IntentService { e.printStackTrace(); } } else { - session_id_bundle.putBoolean(RESULT_KEY, false); - session_id_bundle.putString(getResources().getString(R.string.user_message), getResources().getString(R.string.error_not_valid_password_user_message)); - session_id_bundle.putString(LogInDialog.USERNAME, username); + if(!wellFormedPassword(password)) { + session_id_bundle.putBoolean(RESULT_KEY, false); + session_id_bundle.putString(LogInDialog.USERNAME, username); + session_id_bundle.putBoolean(LogInDialog.PASSWORD_INVALID_LENGTH, true); + } + if(username.isEmpty()) { + session_id_bundle.putBoolean(RESULT_KEY, false); + session_id_bundle.putBoolean(LogInDialog.USERNAME_MISSING, true); + } } return session_id_bundle; } + /** + * Validates parameters entered by the user to log in + * @param entered_username + * @param entered_password + * @return true if both parameters are present and the entered password length is greater or equal to eight (8). + */ + private boolean validUserLoginData(String entered_username, String entered_password) { + return !(entered_username.isEmpty()) && wellFormedPassword(entered_password); + } + /** * Validates a password * @param entered_password -- cgit v1.2.3 From a2a38163202e53eea1328d7c20ec0e94b33f2fc6 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Parm=C3=A9nides=20GV?= Date: Thu, 10 Oct 2013 16:58:58 +0200 Subject: Refactored leapclient to bitmaskclient. I do not change the company (se.leap). All references within strings.xml point to "bitmask" instead of to "leap". --- AndroidManifest.xml | 16 +- debug.sh | 4 +- res/layout/basic_settings.xml | 2 +- res/values/strings.xml | 22 +- run.sh | 2 +- src/se/leap/bitmaskclient/AboutFragment.java | 60 ++ src/se/leap/bitmaskclient/ConfigHelper.java | 317 +++++++++ src/se/leap/bitmaskclient/ConfigurationWizard.java | 418 +++++++++++ src/se/leap/bitmaskclient/Dashboard.java | 354 ++++++++++ src/se/leap/bitmaskclient/EIP.java | 520 ++++++++++++++ src/se/leap/bitmaskclient/EipServiceFragment.java | 265 +++++++ src/se/leap/bitmaskclient/LeapHttpClient.java | 84 +++ src/se/leap/bitmaskclient/LeapSRPSession.java | 326 +++++++++ src/se/leap/bitmaskclient/LogInDialog.java | 139 ++++ src/se/leap/bitmaskclient/NewProviderDialog.java | 110 +++ src/se/leap/bitmaskclient/Provider.java | 208 ++++++ src/se/leap/bitmaskclient/ProviderAPI.java | 780 +++++++++++++++++++++ .../bitmaskclient/ProviderAPIResultReceiver.java | 56 ++ .../leap/bitmaskclient/ProviderDetailFragment.java | 114 +++ src/se/leap/bitmaskclient/ProviderListContent.java | 146 ++++ .../leap/bitmaskclient/ProviderListFragment.java | 192 +++++ src/se/leap/leapclient/AboutFragment.java | 60 -- src/se/leap/leapclient/ConfigHelper.java | 317 --------- src/se/leap/leapclient/ConfigurationWizard.java | 418 ----------- src/se/leap/leapclient/Dashboard.java | 353 ---------- src/se/leap/leapclient/EIP.java | 519 -------------- src/se/leap/leapclient/EipServiceFragment.java | 264 ------- src/se/leap/leapclient/LeapHttpClient.java | 84 --- src/se/leap/leapclient/LeapSRPSession.java | 326 --------- src/se/leap/leapclient/LogInDialog.java | 139 ---- src/se/leap/leapclient/NewProviderDialog.java | 110 --- src/se/leap/leapclient/Provider.java | 208 ------ src/se/leap/leapclient/ProviderAPI.java | 779 -------------------- .../leap/leapclient/ProviderAPIResultReceiver.java | 56 -- src/se/leap/leapclient/ProviderDetailFragment.java | 113 --- src/se/leap/leapclient/ProviderListContent.java | 146 ---- src/se/leap/leapclient/ProviderListFragment.java | 191 ----- src/se/leap/openvpn/ConfigConverter.java | 3 +- src/se/leap/openvpn/FaqFragment.java | 2 +- src/se/leap/openvpn/FileSelect.java | 3 +- src/se/leap/openvpn/FileSelectLayout.java | 2 +- src/se/leap/openvpn/FileSelectionFragment.java | 3 +- src/se/leap/openvpn/GeneralSettings.java | 3 +- src/se/leap/openvpn/InlineFileTab.java | 2 +- src/se/leap/openvpn/LaunchVPN.java | 6 +- src/se/leap/openvpn/LogWindow.java | 3 +- src/se/leap/openvpn/MainActivity.java | 3 +- src/se/leap/openvpn/NetworkSateReceiver.java | 2 +- src/se/leap/openvpn/OpenVPN.java | 3 +- src/se/leap/openvpn/OpenVPNThread.java | 3 +- src/se/leap/openvpn/OpenVpnManagementThread.java | 3 +- .../leap/openvpn/OpenVpnPreferencesFragment.java | 2 +- src/se/leap/openvpn/OpenVpnService.java | 4 +- src/se/leap/openvpn/ProxyDetection.java | 3 +- src/se/leap/openvpn/Settings_Authentication.java | 2 +- src/se/leap/openvpn/Settings_Basic.java | 4 +- src/se/leap/openvpn/Settings_IP.java | 2 +- src/se/leap/openvpn/Settings_Obscure.java | 2 +- src/se/leap/openvpn/Settings_Routing.java | 2 +- src/se/leap/openvpn/ShowConfigFragment.java | 2 +- src/se/leap/openvpn/VPNLaunchHelper.java | 3 +- src/se/leap/openvpn/VPNPreferences.java | 3 +- src/se/leap/openvpn/VPNProfileList.java | 3 +- src/se/leap/openvpn/VpnProfile.java | 10 +- 64 files changed, 4160 insertions(+), 4141 deletions(-) create mode 100644 src/se/leap/bitmaskclient/AboutFragment.java create mode 100644 src/se/leap/bitmaskclient/ConfigHelper.java create mode 100644 src/se/leap/bitmaskclient/ConfigurationWizard.java create mode 100644 src/se/leap/bitmaskclient/Dashboard.java create mode 100644 src/se/leap/bitmaskclient/EIP.java create mode 100644 src/se/leap/bitmaskclient/EipServiceFragment.java create mode 100644 src/se/leap/bitmaskclient/LeapHttpClient.java create mode 100644 src/se/leap/bitmaskclient/LeapSRPSession.java create mode 100644 src/se/leap/bitmaskclient/LogInDialog.java create mode 100644 src/se/leap/bitmaskclient/NewProviderDialog.java create mode 100644 src/se/leap/bitmaskclient/Provider.java create mode 100644 src/se/leap/bitmaskclient/ProviderAPI.java create mode 100644 src/se/leap/bitmaskclient/ProviderAPIResultReceiver.java create mode 100644 src/se/leap/bitmaskclient/ProviderDetailFragment.java create mode 100644 src/se/leap/bitmaskclient/ProviderListContent.java create mode 100644 src/se/leap/bitmaskclient/ProviderListFragment.java delete mode 100644 src/se/leap/leapclient/AboutFragment.java delete mode 100644 src/se/leap/leapclient/ConfigHelper.java delete mode 100644 src/se/leap/leapclient/ConfigurationWizard.java delete mode 100644 src/se/leap/leapclient/Dashboard.java delete mode 100644 src/se/leap/leapclient/EIP.java delete mode 100644 src/se/leap/leapclient/EipServiceFragment.java delete mode 100644 src/se/leap/leapclient/LeapHttpClient.java delete mode 100644 src/se/leap/leapclient/LeapSRPSession.java delete mode 100644 src/se/leap/leapclient/LogInDialog.java delete mode 100644 src/se/leap/leapclient/NewProviderDialog.java delete mode 100644 src/se/leap/leapclient/Provider.java delete mode 100644 src/se/leap/leapclient/ProviderAPI.java delete mode 100644 src/se/leap/leapclient/ProviderAPIResultReceiver.java delete mode 100644 src/se/leap/leapclient/ProviderDetailFragment.java delete mode 100644 src/se/leap/leapclient/ProviderListContent.java delete mode 100644 src/se/leap/leapclient/ProviderListFragment.java diff --git a/AndroidManifest.xml b/AndroidManifest.xml index 320d4fc4..2933a1ba 100644 --- a/AndroidManifest.xml +++ b/AndroidManifest.xml @@ -16,7 +16,7 @@ --> @@ -67,7 +67,7 @@ - + @@ -150,15 +150,15 @@ - + - - - + + + diff --git a/debug.sh b/debug.sh index 18679368..04e0fed0 100755 --- a/debug.sh +++ b/debug.sh @@ -25,9 +25,9 @@ wait_until_booted() { emulator -wipe-data @$avd_name & # If you want to test the app from scratch wait_until_booted adb install -r $PROJECT_FOLDER/bin/LEAP\ Android-debug.apk # Install the new version of the application -adb shell am start -D se.leap.leapclient/.Dashboard # Run app +adb shell am start -D se.leap.bitmaskclient/.Dashboard # Run app sleep 1 -pid=`adb shell ps | grep leap | awk '{print $2}'` # Identify the process id (pid) of the current leapclient process instance +pid=`adb shell ps | grep leap | awk '{print $2}'` # Identify the process id (pid) of the current bitmaskclient process instance echo forwarding tcp:$localport to jwdp:$pid adb forward tcp:$localport jdwp:$pid jdb -sourcepath $PROJECT_FOLDER/src/ -attach localhost:$localport diff --git a/res/layout/basic_settings.xml b/res/layout/basic_settings.xml index b71ae664..542de365 100644 --- a/res/layout/basic_settings.xml +++ b/res/layout/basic_settings.xml @@ -1,6 +1,6 @@ diff --git a/res/values/strings.xml b/res/values/strings.xml index a6afb71d..d2c57734 100755 --- a/res/values/strings.xml +++ b/res/values/strings.xml @@ -2,8 +2,8 @@ - LEAP for Android - LEAP + Bitmask for Android + Bitmask Server Address: Server Port: Location @@ -22,7 +22,7 @@ This program uses the following components; see the source code for full details on the licenses About Switch provider - About LEAP for Android + About Bitmask for Android List of all configured VPNs VPN Profiles Type @@ -113,7 +113,7 @@ %1$s %2$s Send log file Send - LEAP OpenVPN log file + Bitmask OpenVPN log file Copied log entry to clip board Tap Mode Tap Mode is not possible with the non root VPN API. Therefore this application cannot provide tap support @@ -256,13 +256,13 @@ Authentication failed Waiting for usable network Settings - LEAP Dashboard + Bitmask Dashboard Provider: No provider configured Access EIP connection settings Status unknown Encrypted Internet - Configure LEAP + Configure Bitmask Select new Provider Introduce new provider Save @@ -290,19 +290,19 @@ Configuration Error Configure Exit - There was an error configuring LEAP with your chosen provider.\n\nYou may choose to reconfigure, or exit and configure a provider upon next launch. - Configuring LEAP provider + There was an error configuring Bitmask with your chosen provider.\n\nYou may choose to reconfigure, or exit and configure a provider upon next launch. + Configuring Bitmask provider Downloading provider configuration Downloading service definitions Downloading authentication certificates Error parsing provider\'s responses! Success! - You have not entered a LEAP provider URL or it is unavailable + You have not entered a Bitmask provider URL or it is unavailable Your anon cert has been correctly downloaded Your anon cert was not downloaded Server is down. - It doesn\'t seem to be a LEAP provider. - This is not a trusted LEAP provider. + It doesn\'t seem to be a Bitmask provider. + This is not a trusted Bitmask provider. Authenticating Authenticating with entered login and password. Log out diff --git a/run.sh b/run.sh index b5a08612..08209db0 100755 --- a/run.sh +++ b/run.sh @@ -35,4 +35,4 @@ fi wait_until_booted adb install -r $PROJECT_FOLDER/bin/LEAP\ Android-debug.apk # Install the new version of the application -adb shell am start se.leap.leapclient/.Dashboard # Run app +adb shell am start se.leap.bitmaskclient/.Dashboard # Run app diff --git a/src/se/leap/bitmaskclient/AboutFragment.java b/src/se/leap/bitmaskclient/AboutFragment.java new file mode 100644 index 00000000..d751dc2f --- /dev/null +++ b/src/se/leap/bitmaskclient/AboutFragment.java @@ -0,0 +1,60 @@ +package se.leap.bitmaskclient; + +import android.app.Fragment; +import android.content.pm.PackageInfo; +import android.content.pm.PackageManager.NameNotFoundException; +import android.os.Bundle; +import android.text.Html; +import android.text.Spanned; +import android.text.method.LinkMovementMethod; +import android.view.LayoutInflater; +import android.view.View; +import android.view.ViewGroup; +import android.widget.TextView; +import se.leap.bitmaskclient.R; + +public class AboutFragment extends Fragment { + + final public static String TAG = "aboutFragment"; + + public static Fragment newInstance() { + AboutFragment provider_detail_fragment = new AboutFragment(); + return provider_detail_fragment; + } + + @Override + public void onCreate(Bundle savedInstanceState) { + super.onCreate(savedInstanceState); + + } + + @Override + public View onCreateView(LayoutInflater inflater, ViewGroup container, + Bundle savedInstanceState) { + View v= inflater.inflate(R.layout.about, container, false); + TextView ver = (TextView) v.findViewById(R.id.version); + + String version; + String name="Openvpn"; + try { + PackageInfo packageinfo = getActivity().getPackageManager().getPackageInfo(getActivity().getPackageName(), 0); + version = packageinfo.versionName; + name = getString(R.string.app); + } catch (NameNotFoundException e) { + version = "error fetching version"; + } + + + ver.setText(getString(R.string.version_info,name,version)); + + TextView translation = (TextView) v.findViewById(R.id.translation); + + // Don't print a text for myself + if ( getString(R.string.translationby).contains("Arne Schwabe")) + translation.setText(""); + else + translation.setText(R.string.translationby); + return v; + } + +} diff --git a/src/se/leap/bitmaskclient/ConfigHelper.java b/src/se/leap/bitmaskclient/ConfigHelper.java new file mode 100644 index 00000000..b916a9ac --- /dev/null +++ b/src/se/leap/bitmaskclient/ConfigHelper.java @@ -0,0 +1,317 @@ +/** + * 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 . + */ +package se.leap.bitmaskclient; + +import java.io.ByteArrayInputStream; +import java.io.IOException; +import java.math.BigInteger; +import java.io.InputStream; +import java.security.KeyFactory; +import java.security.KeyStore; +import java.security.KeyStoreException; +import java.security.NoSuchAlgorithmException; +import java.security.NoSuchProviderException; +import java.security.cert.CertificateException; +import java.security.cert.CertificateFactory; +import java.security.cert.X509Certificate; +import java.security.interfaces.RSAPrivateKey; +import java.security.spec.InvalidKeySpecException; +import java.security.spec.PKCS8EncodedKeySpec; + +import org.json.JSONException; +import org.json.JSONObject; + +import android.content.Context; +import android.content.SharedPreferences; +import android.util.Base64; + +/** + * Stores constants, and implements auxiliary methods used across all LEAP Android classes. + * + * @author parmegv + * @author MeanderingCode + * + */ +public class ConfigHelper { + + public static SharedPreferences shared_preferences; + private static KeyStore keystore_trusted; + + final public static String NG_1024 = + "eeaf0ab9adb38dd69c33f80afa8fc5e86072618775ff3c0b9ea2314c9c256576d674df7496ea81d3383b4813d692c6e0e0d5d8e250b98be48e495c1d6089dad15dc7d7b46154d6b6ce8ef4ad69b15d4982559b297bcf1885c529f566660e57ec68edbc3c05726cc02fd4cbf4976eaa9afd5138fe8376435b9fc61d2fc0eb06e3"; + final public static BigInteger G = new BigInteger("2"); + + + private static boolean checkSharedPrefs() { + try { + shared_preferences = Dashboard.getAppContext().getSharedPreferences(Dashboard.SHARED_PREFERENCES,Context.MODE_PRIVATE); + } catch (Exception e) { + return false; + } + + return true; + } + + /** + * Saves a JSON object into class scope Shared Preferences + * @param shared_preferences_key + * @param content + */ + public static void saveSharedPref(String shared_preferences_key, JSONObject content) { + + SharedPreferences.Editor shared_preferences_editor = shared_preferences + .edit(); + shared_preferences_editor.putString(shared_preferences_key, + content.toString()); + shared_preferences_editor.commit(); + } + + /** + * Saves a String object into class scope Shared Preferences + * @param shared_preferences_key + * @param content + */ + public static void saveSharedPref(String shared_preferences_key, String content) { + + SharedPreferences.Editor shared_preferences_editor = shared_preferences + .edit(); + shared_preferences_editor.putString(shared_preferences_key, + content); + shared_preferences_editor.commit(); + } + + /** + * Saves a boolean object into class scope Shared Preferences + * @param shared_preferences_key + * @param content + */ + public static void saveSharedPref(String shared_preferences_key, boolean content) { + + SharedPreferences.Editor shared_preferences_editor = shared_preferences + .edit(); + shared_preferences_editor.putBoolean(shared_preferences_key, content); + shared_preferences_editor.commit(); + } + + /** + * Saves an int into class scope Shared Preferences + * + * @param shared_preferences_key + * @param value + */ + protected static void saveSharedPref(String shared_preferences_key, int value) { + SharedPreferences.Editor shared_preferences_editor = shared_preferences.edit(); + shared_preferences_editor.putInt(shared_preferences_key, value).commit(); + } + + /** + * Gets String object from class scope Shared Preferences + * @param shared_preferences_key + * @return the string correspondent to the key parameter + */ + public static String getStringFromSharedPref(String shared_preferences_key) { + String content = null; + content = shared_preferences.getString(shared_preferences_key, ""); + return content; + } + + /** + * Gets JSON object from class scope Shared Preferences + * @param shared_preferences_key + * @return the JSON object correspondent to the key parameter + */ + public static JSONObject getJsonFromSharedPref(String shared_preferences_key) throws JSONException { + JSONObject content = null; + if ( checkSharedPrefs() ) { + String json_string = shared_preferences.getString(shared_preferences_key, ""); + content = new JSONObject(json_string); + } + + return content; + } + + /* + * This method defaults to false. + * If you use this method, be sure to fail-closed on false! + * TODO This is obviously less than ideal...solve it! + */ + public static boolean getBoolFromSharedPref(String shared_preferences_key) { + boolean value = false; + if ( checkSharedPrefs() ) { + value = shared_preferences.getBoolean(shared_preferences_key, false); + } + return value; + } + + /** + * Get an int from SharedPreferences + * + * @param shared_preferences_key Key to retrieve + * @return The value for the key or 0 + */ + protected static int getIntFromSharedPref(String shared_preferences_key) { + return shared_preferences.getInt(shared_preferences_key, 0); + } + + /* + * This method defaults to false. + * If you use this method, be sure to fail-closed on false! + * TODO This is obviously less than ideal...solve it! + */ + public static boolean removeFromSharedPref(String shared_preferences_key) { + SharedPreferences.Editor shared_preferences_editor = shared_preferences + .edit(); + shared_preferences_editor.remove(shared_preferences_key); + return shared_preferences_editor.commit(); + } + + /** + * Treat the input as the MSB representation of a number, + * and lop off leading zero elements. For efficiency, the + * input is simply returned if no leading zeroes are found. + * + * @param in array to be trimmed + */ + public static byte[] trim(byte[] in) { + if(in.length == 0 || in[0] != 0) + return in; + + int len = in.length; + int i = 1; + while(in[i] == 0 && i < len) + ++i; + byte[] ret = new byte[len - i]; + System.arraycopy(in, i, ret, 0, len - i); + return ret; + } + + /** + * Sets class scope Shared Preferences + * @param shared_preferences + */ + public static void setSharedPreferences( + SharedPreferences shared_preferences) { + ConfigHelper.shared_preferences = shared_preferences; + } + + public static X509Certificate parseX509CertificateFromString(String certificate_string) { + java.security.cert.Certificate certificate = null; + CertificateFactory cf; + try { + cf = CertificateFactory.getInstance("X.509"); + + certificate_string = certificate_string.replaceFirst("-----BEGIN CERTIFICATE-----", "").replaceFirst("-----END CERTIFICATE-----", "").trim(); + byte[] cert_bytes = Base64.decode(certificate_string, Base64.DEFAULT); + InputStream caInput = new ByteArrayInputStream(cert_bytes); + try { + certificate = cf.generateCertificate(caInput); + System.out.println("ca=" + ((X509Certificate) certificate).getSubjectDN()); + } finally { + caInput.close(); + } + } catch (CertificateException e) { + // TODO Auto-generated catch block + e.printStackTrace(); + } catch (IOException e) { + return null; + } + + return (X509Certificate) certificate; + } + + protected static RSAPrivateKey parseRsaKeyFromString(String RsaKeyString) { + RSAPrivateKey key = null; + try { + KeyFactory kf = KeyFactory.getInstance("RSA", "BC"); + + RsaKeyString = RsaKeyString.replaceFirst("-----BEGIN RSA PRIVATE KEY-----", "").replaceFirst("-----END RSA PRIVATE KEY-----", ""); + PKCS8EncodedKeySpec keySpec = new PKCS8EncodedKeySpec( Base64.decode(RsaKeyString, Base64.DEFAULT) ); + key = (RSAPrivateKey) kf.generatePrivate(keySpec); + } catch (InvalidKeySpecException e) { + // TODO Auto-generated catch block + e.printStackTrace(); + return null; + } catch (NoSuchAlgorithmException e) { + // TODO Auto-generated catch block + e.printStackTrace(); + return null; + } catch (NoSuchProviderException e) { + // TODO Auto-generated catch block + e.printStackTrace(); + return null; + } + + return key; + } + + /** + * Adds a new X509 certificate given its input stream and its provider name + * @param provider used to store the certificate in the keystore + * @param inputStream from which X509 certificate must be generated. + */ + public static void addTrustedCertificate(String provider, InputStream inputStream) { + CertificateFactory cf; + try { + cf = CertificateFactory.getInstance("X.509"); + X509Certificate cert = + (X509Certificate)cf.generateCertificate(inputStream); + keystore_trusted.setCertificateEntry(provider, cert); + } catch (CertificateException e) { + // TODO Auto-generated catch block + e.printStackTrace(); + } catch (KeyStoreException e) { + // TODO Auto-generated catch block + e.printStackTrace(); + } + } + + /** + * Adds a new X509 certificate given in its string from and using its provider name + * @param provider used to store the certificate in the keystore + * @param certificate + */ + public static void addTrustedCertificate(String provider, String certificate) { + + try { + X509Certificate cert = ConfigHelper.parseX509CertificateFromString(certificate); + if(keystore_trusted == null) { + keystore_trusted = KeyStore.getInstance("BKS"); + keystore_trusted.load(null); + } + keystore_trusted.setCertificateEntry(provider, cert); + } catch (KeyStoreException e) { + // TODO Auto-generated catch block + e.printStackTrace(); + } catch (NoSuchAlgorithmException e) { + // TODO Auto-generated catch block + e.printStackTrace(); + } catch (CertificateException e) { + // TODO Auto-generated catch block + e.printStackTrace(); + } catch (IOException e) { + // TODO Auto-generated catch block + e.printStackTrace(); + } + } + + /** + * @return class wide keystore + */ + public static KeyStore getKeystore() { + return keystore_trusted; + } +} diff --git a/src/se/leap/bitmaskclient/ConfigurationWizard.java b/src/se/leap/bitmaskclient/ConfigurationWizard.java new file mode 100644 index 00000000..bcb4fa9f --- /dev/null +++ b/src/se/leap/bitmaskclient/ConfigurationWizard.java @@ -0,0 +1,418 @@ +/** + * 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 . + */ + package se.leap.bitmaskclient; + +import java.io.IOException; +import java.util.Iterator; + +import org.json.JSONException; +import org.json.JSONObject; + +import se.leap.bitmaskclient.R; +import se.leap.bitmaskclient.ProviderAPIResultReceiver.Receiver; +import se.leap.bitmaskclient.ProviderListContent.ProviderItem; +import android.app.Activity; +import android.app.DialogFragment; +import android.app.Fragment; +import android.app.FragmentManager; +import android.app.FragmentTransaction; +import android.app.ProgressDialog; +import android.content.Intent; +import android.content.res.AssetManager; +import android.os.Bundle; +import android.os.Handler; +import android.view.Menu; +import android.view.MenuItem; +import android.view.View; + +/** + * Activity that builds and shows the list of known available providers. + * + * It also allows the user to enter custom providers with a button. + * + * @author parmegv + * + */ +public class ConfigurationWizard extends Activity +implements ProviderListFragment.Callbacks, NewProviderDialog.NewProviderDialogInterface, ProviderDetailFragment.ProviderDetailFragmentInterface, Receiver { + + private ProviderItem mSelectedProvider; + private ProgressDialog mProgressDialog; + private Intent mConfigState = new Intent(); + + final public static String TYPE_OF_CERTIFICATE = "type_of_certificate"; + final public static String ANON_CERTIFICATE = "anon_certificate"; + final public static String AUTHED_CERTIFICATE = "authed_certificate"; + + final protected static String PROVIDER_SET = "PROVIDER SET"; + final protected static String SERVICES_RETRIEVED = "SERVICES RETRIEVED"; + + public ProviderAPIResultReceiver providerAPI_result_receiver; + + @Override + protected void onCreate(Bundle savedInstanceState) { + super.onCreate(savedInstanceState); + + setContentView(R.layout.configuration_wizard_activity); + + providerAPI_result_receiver = new ProviderAPIResultReceiver(new Handler()); + providerAPI_result_receiver.setReceiver(this); + + ConfigHelper.setSharedPreferences(getSharedPreferences(Dashboard.SHARED_PREFERENCES, MODE_PRIVATE)); + + loadPreseededProviders(); + + // Only create our fragments if we're not restoring a saved instance + if ( savedInstanceState == null ){ + // TODO Some welcome screen? + // We will need better flow control when we have more Fragments (e.g. user auth) + ProviderListFragment providerList = new ProviderListFragment(); + + FragmentManager fragmentManager = getFragmentManager(); + fragmentManager.beginTransaction() + .add(R.id.configuration_wizard_layout, providerList, "providerlist") + .commit(); + } + + // TODO: If exposing deep links into your app, handle intents here. + } + + @Override + public void onReceiveResult(int resultCode, Bundle resultData) { + if(resultCode == ProviderAPI.CORRECTLY_UPDATED_PROVIDER_DOT_JSON) { + JSONObject provider_json; + try { + provider_json = new JSONObject(resultData.getString(Provider.KEY)); + boolean danger_on = resultData.getBoolean(ProviderItem.DANGER_ON); + ConfigHelper.saveSharedPref(Provider.KEY, provider_json); + ConfigHelper.saveSharedPref(ProviderItem.DANGER_ON, danger_on); + ConfigHelper.saveSharedPref(EIP.ALLOWED_ANON, provider_json.getJSONObject(Provider.SERVICE).getBoolean(EIP.ALLOWED_ANON)); + mConfigState.setAction(PROVIDER_SET); + + if(mProgressDialog != null) mProgressDialog.dismiss(); + mProgressDialog = ProgressDialog.show(this, getResources().getString(R.string.config_wait_title), getResources().getString(R.string.config_connecting_provider), true); + mProgressDialog.setMessage(getResources().getString(R.string.config_downloading_services)); + if(resultData.containsKey(Provider.NAME)) + mSelectedProvider = getProvider(resultData.getString(Provider.NAME)); + + ProviderListFragment providerList = new ProviderListFragment(); + + FragmentManager fragmentManager = getFragmentManager(); + fragmentManager.beginTransaction() + .replace(R.id.configuration_wizard_layout, providerList, "providerlist") + .commit(); + downloadJSONFiles(mSelectedProvider); + } catch (JSONException e) { + // TODO Auto-generated catch block + e.printStackTrace(); + + mProgressDialog.dismiss(); + //Toast.makeText(this, getResources().getString(R.string.config_error_parsing), Toast.LENGTH_LONG); + setResult(RESULT_CANCELED, mConfigState); + } + } + else if(resultCode == ProviderAPI.INCORRECTLY_UPDATED_PROVIDER_DOT_JSON) { + mProgressDialog.dismiss(); + setResult(RESULT_CANCELED, mConfigState); + } + else if(resultCode == ProviderAPI.CORRECTLY_DOWNLOADED_JSON_FILES) { + if (ConfigHelper.getBoolFromSharedPref(EIP.ALLOWED_ANON)){ + mProgressDialog.setMessage(getResources().getString(R.string.config_downloading_certificates)); + mConfigState.putExtra(SERVICES_RETRIEVED, true); + downloadAnonCert(); + } else { + mProgressDialog.dismiss(); + //Toast.makeText(getApplicationContext(), R.string.success, Toast.LENGTH_LONG).show(); + setResult(RESULT_OK); + finish(); + } + } + else if(resultCode == ProviderAPI.INCORRECTLY_DOWNLOADED_JSON_FILES) { + //Toast.makeText(getApplicationContext(), R.string.incorrectly_downloaded_json_files_message, Toast.LENGTH_LONG).show(); + mProgressDialog.dismiss(); + setResult(RESULT_CANCELED, mConfigState); + } + else if(resultCode == ProviderAPI.CORRECTLY_DOWNLOADED_CERTIFICATE) { + mProgressDialog.dismiss(); + setResult(RESULT_OK); + showProviderDetails(getCurrentFocus()); + } else if(resultCode == ProviderAPI.INCORRECTLY_DOWNLOADED_CERTIFICATE) { + mProgressDialog.dismiss(); + //Toast.makeText(getApplicationContext(), R.string.incorrectly_downloaded_certificate_message, Toast.LENGTH_LONG).show(); + setResult(RESULT_CANCELED, mConfigState); + } + } + + /** + * Callback method from {@link ProviderListFragment.Callbacks} + * indicating that the item with the given ID was selected. + */ + @Override + public void onItemSelected(String id) { + //TODO Code 2 pane view + ProviderItem selected_provider = getProvider(id); + mProgressDialog = ProgressDialog.show(this, getResources().getString(R.string.config_wait_title), getResources().getString(R.string.config_connecting_provider), true); + mSelectedProvider = selected_provider; + saveProviderJson(mSelectedProvider); + } + + @Override + public void onBackPressed() { + try { + if(ConfigHelper.getJsonFromSharedPref(Provider.KEY) == null || ConfigHelper.getJsonFromSharedPref(Provider.KEY).length() == 0) { + askDashboardToQuitApp(); + } else { + setResult(RESULT_OK); + } + } catch (JSONException e) { + askDashboardToQuitApp(); + } + super.onBackPressed(); + } + + private void askDashboardToQuitApp() { + Intent ask_quit = new Intent(); + ask_quit.putExtra(Dashboard.ACTION_QUIT, Dashboard.ACTION_QUIT); + setResult(RESULT_CANCELED, ask_quit); + } + + private ProviderItem getProvider(String id) { + Iterator providers_iterator = ProviderListContent.ITEMS.iterator(); + while(providers_iterator.hasNext()) { + ProviderItem provider = providers_iterator.next(); + if(provider.id.equalsIgnoreCase(id)) { + return provider; + } + } + return null; + } + + /** + * Loads providers data from url file contained in the project + * @return true if the file was read correctly + */ + private boolean loadPreseededProviders() { + boolean loaded_preseeded_providers = false; + AssetManager asset_manager = getAssets(); + String[] urls_filepaths = null; + try { + String url_files_folder = "urls"; + //TODO Put that folder in a better place (also inside the "for") + urls_filepaths = asset_manager.list(url_files_folder); + String provider_name = ""; + for(String url_filepath : urls_filepaths) + { + boolean custom = false; + provider_name = url_filepath.subSequence(0, url_filepath.indexOf(".")).toString(); + if(ProviderListContent.ITEMS.isEmpty()) //TODO I have to implement a way of checking if a provider new or is already present in that ITEMS list + ProviderListContent.addItem(new ProviderItem(provider_name, asset_manager.open(url_files_folder + "/" + url_filepath), custom, false)); + loaded_preseeded_providers = true; + } + } catch (IOException e) { + loaded_preseeded_providers = false; + } + + return loaded_preseeded_providers; + } + + /** + * Saves provider.json file associated with provider. + * + * If the provider is custom, the file has already been downloaded so we load it from memory. + * If not, the file is updated using the provider's URL. + * @param provider + */ + private void saveProviderJson(ProviderItem provider) { + JSONObject provider_json = new JSONObject(); + try { + if(!provider.custom) { + updateProviderDotJson(provider.name, provider.provider_json_url, provider.danger_on); + } else { + // FIXME!! We should we be updating our seeded providers list at ConfigurationWizard onStart() ? + // I think yes, but if so, where does this list live? leap.se, as it's the non-profit project for the software? + // If not, we should just be getting names/urls, and fetching the provider.json like in custom entries + provider_json = provider.provider_json; + ConfigHelper.saveSharedPref(Provider.KEY, provider_json); + ConfigHelper.saveSharedPref(EIP.ALLOWED_ANON, provider_json.getJSONObject(Provider.SERVICE).getBoolean(EIP.ALLOWED_ANON)); + ConfigHelper.saveSharedPref(ProviderItem.DANGER_ON, provider.danger_on); + + mProgressDialog.setMessage(getResources().getString(R.string.config_downloading_services)); + downloadJSONFiles(mSelectedProvider); + } + } catch (JSONException e) { + setResult(RESULT_CANCELED); + finish(); + } + } + + /** + * Asks ProviderAPI to download provider site's certificate and eip-service.json + * + * URLs are fetched from the provider parameter + * @param provider from which certificate and eip-service.json files are going to be downloaded + */ + private void downloadJSONFiles(ProviderItem provider) { + Intent provider_API_command = new Intent(this, ProviderAPI.class); + + Bundle parameters = new Bundle(); + + parameters.putString(Provider.KEY, provider.name); + parameters.putString(Provider.CA_CERT, provider.cert_json_url); + parameters.putString(EIP.KEY, provider.eip_service_json_url); + parameters.putBoolean(ProviderItem.DANGER_ON, provider.danger_on); + + provider_API_command.setAction(ProviderAPI.DOWNLOAD_JSON_FILES_BUNDLE_EXTRA); + provider_API_command.putExtra(ProviderAPI.PARAMETERS, parameters); + provider_API_command.putExtra(ProviderAPI.RECEIVER_KEY, providerAPI_result_receiver); + + startService(provider_API_command); + } + + /** + * Asks ProviderAPI to download an anonymous (anon) VPN certificate. + */ + private void downloadAnonCert() { + Intent provider_API_command = new Intent(this, ProviderAPI.class); + + Bundle parameters = new Bundle(); + + parameters.putString(TYPE_OF_CERTIFICATE, ANON_CERTIFICATE); + + provider_API_command.setAction(ProviderAPI.DOWNLOAD_CERTIFICATE); + provider_API_command.putExtra(ProviderAPI.PARAMETERS, parameters); + provider_API_command.putExtra(ProviderAPI.RECEIVER_KEY, providerAPI_result_receiver); + + startService(provider_API_command); + } + + /** + * Open the new provider dialog + * @param view from which the dialog is showed + */ + public void addAndSelectNewProvider(View view) { + FragmentTransaction fragment_transaction = getFragmentManager().beginTransaction(); + Fragment previous_new_provider_dialog = getFragmentManager().findFragmentByTag(NewProviderDialog.TAG); + if (previous_new_provider_dialog != null) { + fragment_transaction.remove(previous_new_provider_dialog); + } + fragment_transaction.addToBackStack(null); + + DialogFragment newFragment = NewProviderDialog.newInstance(); + newFragment.show(fragment_transaction, NewProviderDialog.TAG); + } + + /** + * Once selected a provider, this fragment offers the user to log in, + * use it anonymously (if possible) + * or cancel his/her election pressing the back button. + * @param view + */ + public void showProviderDetails(View view) { + FragmentTransaction fragment_transaction = getFragmentManager().beginTransaction(); + Fragment previous_provider_details_dialog = getFragmentManager().findFragmentByTag(ProviderDetailFragment.TAG); + if (previous_provider_details_dialog != null) { + fragment_transaction.remove(previous_provider_details_dialog); + } + fragment_transaction.addToBackStack(null); + + DialogFragment newFragment = ProviderDetailFragment.newInstance(); + newFragment.show(fragment_transaction, ProviderDetailFragment.TAG); + } + + @Override + public void saveAndSelectProvider(String provider_main_url, boolean danger_on) { + Intent provider_API_command = new Intent(this, ProviderAPI.class); + + Bundle parameters = new Bundle(); + parameters.putString(Provider.MAIN_URL, provider_main_url); + parameters.putBoolean(ProviderItem.DANGER_ON, danger_on); + + provider_API_command.setAction(ProviderAPI.DOWNLOAD_NEW_PROVIDER_DOTJSON); + provider_API_command.putExtra(ProviderAPI.PARAMETERS, parameters); + provider_API_command.putExtra(ProviderAPI.RECEIVER_KEY, providerAPI_result_receiver); + + startService(provider_API_command); + } + + /** + * Asks ProviderAPI to download a new provider.json file + * @param provider_name + * @param provider_json_url + * @param danger_on tells if HTTPS client should bypass certificate errors + */ + public void updateProviderDotJson(String provider_name, String provider_json_url, boolean danger_on) { + Intent provider_API_command = new Intent(this, ProviderAPI.class); + + Bundle parameters = new Bundle(); + parameters.putString(Provider.NAME, provider_name); + parameters.putString(Provider.DOT_JSON_URL, provider_json_url); + parameters.putBoolean(ProviderItem.DANGER_ON, danger_on); + + provider_API_command.setAction(ProviderAPI.UPDATE_PROVIDER_DOTJSON); + provider_API_command.putExtra(ProviderAPI.PARAMETERS, parameters); + provider_API_command.putExtra(ProviderAPI.RECEIVER_KEY, providerAPI_result_receiver); + + startService(provider_API_command); + } + + @Override + public boolean onCreateOptionsMenu(Menu menu) { + getMenuInflater().inflate(R.menu.configuration_wizard_activity, menu); + return true; + } + + @Override + public boolean onOptionsItemSelected(MenuItem item){ + switch (item.getItemId()){ + case R.id.about_leap: + showAboutFragment(getCurrentFocus()); + default: + return super.onOptionsItemSelected(item); + } + } + + /** + * Once selected a provider, this fragment offers the user to log in, + * use it anonymously (if possible) + * or cancel his/her election pressing the back button. + * @param view + */ + public void showAboutFragment(View view) { + FragmentTransaction fragment_transaction = getFragmentManager().beginTransaction(); + Fragment previous_about_fragment = getFragmentManager().findFragmentByTag(AboutFragment.TAG); + if (previous_about_fragment == null) { + fragment_transaction.addToBackStack(null); + + Fragment newFragment = AboutFragment.newInstance(); + fragment_transaction.replace(R.id.configuration_wizard_layout, newFragment, AboutFragment.TAG).commit(); + } + } + + @Override + public void login() { + Intent ask_login = new Intent(); + ask_login.putExtra(LogInDialog.VERB, LogInDialog.VERB); + setResult(RESULT_OK, ask_login); + finish(); + } + + @Override + public void use_anonymously() { + setResult(RESULT_OK); + finish(); + } +} diff --git a/src/se/leap/bitmaskclient/Dashboard.java b/src/se/leap/bitmaskclient/Dashboard.java new file mode 100644 index 00000000..97367e25 --- /dev/null +++ b/src/se/leap/bitmaskclient/Dashboard.java @@ -0,0 +1,354 @@ +/** + * 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 . + */ + package se.leap.bitmaskclient; + +import org.apache.http.cookie.Cookie; +import org.apache.http.impl.cookie.BasicClientCookie; +import org.json.JSONException; +import org.json.JSONObject; + +import se.leap.bitmaskclient.R; +import se.leap.bitmaskclient.ProviderAPIResultReceiver.Receiver; +import se.leap.openvpn.MainActivity; +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.app.ProgressDialog; +import android.content.Context; +import android.content.DialogInterface; +import android.content.Intent; +import android.content.SharedPreferences; +import android.os.Bundle; +import android.os.Handler; +import android.view.Menu; +import android.view.MenuItem; +import android.view.View; +import android.view.ViewGroup; +import android.widget.TextView; +import android.widget.Toast; + +/** + * The main user facing Activity of LEAP Android, consisting of status, controls, + * and access to preferences. + * + * @author Sean Leonard + */ +public class Dashboard extends Activity implements LogInDialog.LogInDialogInterface,Receiver { + + protected static final int CONFIGURE_LEAP = 0; + + private static final String TAG_EIP_FRAGMENT = "EIP_DASHBOARD_FRAGMENT"; + final public static String SHARED_PREFERENCES = "LEAPPreferences"; + final public static String ACTION_QUIT = "quit"; + + private ProgressDialog mProgressDialog; + + private static Context app; + private static SharedPreferences preferences; + private static Provider provider; + + private TextView providerNameTV; + + private boolean authed = false; + + public ProviderAPIResultReceiver providerAPI_result_receiver; + + @Override + protected void onCreate(Bundle savedInstanceState) { + super.onCreate(savedInstanceState); + + app = this; + + ConfigHelper.setSharedPreferences(getSharedPreferences(SHARED_PREFERENCES, MODE_PRIVATE)); + preferences = ConfigHelper.shared_preferences; + + if (ConfigHelper.getStringFromSharedPref(Provider.KEY).isEmpty()) + startActivityForResult(new Intent(this,ConfigurationWizard.class),CONFIGURE_LEAP); + else + buildDashboard(); + } + + @Override + protected void onActivityResult(int requestCode, int resultCode, Intent data){ + if ( requestCode == CONFIGURE_LEAP ) { + if ( resultCode == RESULT_OK ){ + startService( new Intent(EIP.ACTION_UPDATE_EIP_SERVICE) ); + buildDashboard(); + if(data != null && data.hasExtra(LogInDialog.VERB)) { + View view = ((ViewGroup)findViewById(android.R.id.content)).getChildAt(0); + logInDialog(view, Bundle.EMPTY); + } + } else if(resultCode == RESULT_CANCELED && data.hasExtra(ACTION_QUIT)) { + finish(); + } else + configErrorDialog(); + } + } + + /** + * Dialog shown when encountering a configuration error. Such errors require + * reconfiguring LEAP or aborting the application. + */ + private void configErrorDialog() { + AlertDialog.Builder alertBuilder = new AlertDialog.Builder(getAppContext()); + alertBuilder.setTitle(getResources().getString(R.string.setup_error_title)); + alertBuilder + .setMessage(getResources().getString(R.string.setup_error_text)) + .setCancelable(false) + .setPositiveButton(getResources().getString(R.string.setup_error_configure_button), new DialogInterface.OnClickListener() { + @Override + public void onClick(DialogInterface dialog, int which) { + startActivityForResult(new Intent(getAppContext(),ConfigurationWizard.class),CONFIGURE_LEAP); + } + }) + .setNegativeButton(getResources().getString(R.string.setup_error_close_button), new DialogInterface.OnClickListener() { + @Override + public void onClick(DialogInterface dialog, int which) { + SharedPreferences.Editor prefsEdit = getSharedPreferences(SHARED_PREFERENCES, MODE_PRIVATE).edit(); + prefsEdit.remove(Provider.KEY).commit(); + finish(); + } + }) + .show(); + } + + /** + * Inflates permanent UI elements of the View and contains logic for what + * service dependent UI elements to include. + */ + private void buildDashboard() { + provider = Provider.getInstance(); + provider.init( this ); + + setContentView(R.layout.client_dashboard); + + providerNameTV = (TextView) findViewById(R.id.providerName); + providerNameTV.setText(provider.getDomain()); + providerNameTV.setTextSize(28); + + FragmentManager fragMan = getFragmentManager(); + if ( provider.hasEIP()){ + EipServiceFragment eipFragment = new EipServiceFragment(); + fragMan.beginTransaction().replace(R.id.servicesCollection, eipFragment, TAG_EIP_FRAGMENT).commit(); + } + } + + @Override + public boolean onPrepareOptionsMenu(Menu menu) { + JSONObject provider_json; + try { + provider_json = ConfigHelper.getJsonFromSharedPref(Provider.KEY); + JSONObject service_description = provider_json.getJSONObject(Provider.SERVICE); + if(service_description.getBoolean(Provider.ALLOW_REGISTRATION)) { + if(authed) { + 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); + } + } + } catch (JSONException e) { + // TODO Auto-generated catch block + e.printStackTrace(); + } + return true; + } + + @Override + public boolean onCreateOptionsMenu(Menu menu) { + getMenuInflater().inflate(R.menu.client_dashboard, menu); + return true; + } + + @Override + public boolean onOptionsItemSelected(MenuItem item){ + Intent intent; + switch (item.getItemId()){ + case R.id.about_leap: + Fragment aboutFragment = new AboutFragment(); + FragmentTransaction trans = getFragmentManager().beginTransaction(); + trans.replace(R.id.dashboardLayout, aboutFragment); + trans.addToBackStack(null); + trans.commit(); + return true; + case R.id.legacy_interface: + intent = new Intent(this,MainActivity.class); + startActivity(intent); + return true; + case R.id.switch_provider: + startActivityForResult(new Intent(this,ConfigurationWizard.class),CONFIGURE_LEAP); + return true; + case R.id.login_button: + View view = ((ViewGroup)findViewById(android.R.id.content)).getChildAt(0); + logInDialog(view, Bundle.EMPTY); + return true; + case R.id.logout_button: + logOut(); + return true; + default: + return super.onOptionsItemSelected(item); + } + + } + + @Override + public void authenticate(String username, String password) { + 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(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(); + } + + provider_API_command.setAction(ProviderAPI.SRP_AUTH); + provider_API_command.putExtra(ProviderAPI.PARAMETERS, parameters); + provider_API_command.putExtra(ProviderAPI.RECEIVER_KEY, providerAPI_result_receiver); + + if(mProgressDialog != null) mProgressDialog.dismiss(); + mProgressDialog = ProgressDialog.show(this, getResources().getString(R.string.authenticating_title), getResources().getString(R.string.authenticating_message), true); + startService(provider_API_command); + } + + /** + * 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(mProgressDialog != null) mProgressDialog.dismiss(); + mProgressDialog = ProgressDialog.show(this, getResources().getString(R.string.logout_title), getResources().getString(R.string.logout_message), true); + startService(provider_API_command); + } + + /** + * Shows the log in dialog. + * @param view from which the dialog is created. + */ + public void logInDialog(View view, Bundle resultData) { + 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); + } + + /** + * 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*/) { + 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(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); + provider_API_command.putExtra(ProviderAPI.RECEIVER_KEY, providerAPI_result_receiver); + + startService(provider_API_command); + } + + @Override + public void onReceiveResult(int resultCode, Bundle resultData) { + 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 = true; + invalidateOptionsMenu(); + + //Cookie session_id = new BasicClientCookie(session_id_cookie_key, session_id_string); + downloadAuthedUserCertificate(/*session_id*/); + } else if(resultCode == ProviderAPI.SRP_AUTHENTICATION_FAILED) { + mProgressDialog.dismiss(); + logInDialog(getCurrentFocus(), resultData); + } else if(resultCode == ProviderAPI.LOGOUT_SUCCESSFUL) { + authed = false; + invalidateOptionsMenu(); + setResult(RESULT_OK); + mProgressDialog.dismiss(); + } else if(resultCode == ProviderAPI.LOGOUT_FAILED) { + setResult(RESULT_CANCELED); + mProgressDialog.dismiss(); + Toast.makeText(getApplicationContext(), R.string.log_out_failed_message, Toast.LENGTH_LONG).show(); + } else if(resultCode == ProviderAPI.CORRECTLY_DOWNLOADED_CERTIFICATE) { + setResult(RESULT_OK); + mProgressDialog.dismiss(); + Toast.makeText(getApplicationContext(), R.string.successful_authed_cert_downloaded_message, Toast.LENGTH_LONG).show(); + } else if(resultCode == ProviderAPI.INCORRECTLY_DOWNLOADED_CERTIFICATE) { + setResult(RESULT_CANCELED); + mProgressDialog.dismiss(); + Toast.makeText(getApplicationContext(), R.string.authed_cert_download_failed_message, Toast.LENGTH_LONG).show(); + } + } + + /** + * For retrieving the base application Context in classes that don't extend + * Android's Activity class + * + * @return Application Context as defined by this for Dashboard instance + */ + public static Context getAppContext() { + return app; + } + +} diff --git a/src/se/leap/bitmaskclient/EIP.java b/src/se/leap/bitmaskclient/EIP.java new file mode 100644 index 00000000..c643d501 --- /dev/null +++ b/src/se/leap/bitmaskclient/EIP.java @@ -0,0 +1,520 @@ +/** + * 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 . + */ + package se.leap.bitmaskclient; + +import java.util.Collection; +import java.util.HashMap; +import java.util.Iterator; +import java.util.NoSuchElementException; +import java.util.Vector; + +import org.json.JSONArray; +import org.json.JSONException; +import org.json.JSONObject; + +import se.leap.bitmaskclient.R; +import se.leap.openvpn.ConfigParser; +import se.leap.openvpn.ConfigParser.ConfigParseError; +import se.leap.openvpn.LaunchVPN; +import se.leap.openvpn.OpenVpnManagementThread; +import se.leap.openvpn.OpenVpnService; +import se.leap.openvpn.OpenVpnService.LocalBinder; +import se.leap.openvpn.ProfileManager; +import se.leap.openvpn.VpnProfile; + +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.os.Bundle; +import android.os.IBinder; +import android.os.ResultReceiver; +import android.util.Log; + +/** + * EIP is the abstract base class for interacting with and managing the Encrypted + * Internet Proxy connection. Connections are started, stopped, and queried through + * this IntentService. + * Contains logic for parsing eip-service.json from the provider, configuring and selecting + * gateways, and controlling {@link .openvpn.OpenVpnService} connections. + * + * @author Sean Leonard + */ +public final class EIP extends IntentService { + + public final static String ACTION_START_EIP = "se.leap.bitmaskclient.START_EIP"; + public final static String ACTION_STOP_EIP = "se.leap.bitmaskclient.STOP_EIP"; + public final static String ACTION_UPDATE_EIP_SERVICE = "se.leap.bitmaskclient.UPDATE_EIP_SERVICE"; + public final static String ACTION_IS_EIP_RUNNING = "se.leap.bitmaskclient.IS_RUNNING"; + public final static String EIP_NOTIFICATION = "EIP_NOTIFICATION"; + public final static String ALLOWED_ANON = "allow_anonymous"; + public final static String CERTIFICATE = "cert"; + public final static String PRIVATE_KEY = "private_key"; + public final static String KEY = "eip"; + public final static String PARSED_SERIAL = "eip_parsed_serial"; + 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"; + + private static Context context; + private static ResultReceiver mReceiver; + private static OpenVpnService mVpnService; + 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; + + public EIP(){ + super("LEAPEIP"); + } + + @Override + public void onCreate() { + super.onCreate(); + + context = getApplicationContext(); + + try { + eipDefinition = ConfigHelper.getJsonFromSharedPref(KEY); + parsedEipSerial = ConfigHelper.getIntFromSharedPref(PARSED_SERIAL); + } catch (JSONException e) { + // TODO Auto-generated catch block + e.printStackTrace(); + } + + this.retreiveVpnService(); + } + + @Override + public void onDestroy() { + unbindService(mVpnServiceConn); + mBound = false; + + super.onDestroy(); + } + + @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(); + } + + /** + * Sends an Intent to bind OpenVpnService. + * Used when OpenVpnService isn't bound but might be running. + */ + private void retreiveVpnService() { + Intent bindIntent = new Intent(this,OpenVpnService.class); + bindIntent.setAction(OpenVpnService.RETRIEVE_SERVICE); + bindService(bindIntent, mVpnServiceConn, 0); + } + + private static ServiceConnection mVpnServiceConn = new ServiceConnection() { + + @Override + public void onServiceConnected(ComponentName name, IBinder service) { + LocalBinder binder = (LocalBinder) service; + mVpnService = binder.getService(); + mBound = true; + + if (mReceiver != null && mPending != null) { + + boolean running = mVpnService.isRunning(); + int resultCode = Activity.RESULT_CANCELED; + + if (mPending.equals(ACTION_IS_EIP_RUNNING)) + resultCode = (running) ? Activity.RESULT_OK : Activity.RESULT_CANCELED; + if (mPending.equals(ACTION_START_EIP)) + resultCode = (running) ? Activity.RESULT_OK : Activity.RESULT_CANCELED; + else if (mPending.equals(ACTION_STOP_EIP)) + resultCode = (running) ? Activity.RESULT_CANCELED + : Activity.RESULT_OK; + Bundle resultData = new Bundle(); + resultData.putString(REQUEST_TAG, EIP_NOTIFICATION); + mReceiver.send(resultCode, resultData); + + mPending = null; + } + } + + @Override + public void onServiceDisconnected(ComponentName name) { + mBound = false; + + if (mReceiver != null){ + Bundle resultData = new Bundle(); + resultData.putString(REQUEST_TAG, EIP_NOTIFICATION); + mReceiver.send(Activity.RESULT_CANCELED, resultData); + } + } + + }; + + /** + * Attempts to determine if OpenVpnService has an established VPN connection + * through the bound ServiceConnection. If there is no bound service, this + * method will attempt to bind a running OpenVpnService and send + * Activity.RESULT_CANCELED to the ResultReceiver that made the + * request. + * Note: If the request to bind OpenVpnService is successful, the ResultReceiver + * will be notified in {@link onServiceConnected()} + */ + private void isRunning() { + Bundle resultData = new Bundle(); + resultData.putString(REQUEST_TAG, ACTION_IS_EIP_RUNNING); + int resultCode = Activity.RESULT_CANCELED; + if (mBound) { + resultCode = (mVpnService.isRunning()) ? Activity.RESULT_OK : Activity.RESULT_CANCELED; + } else { + mPending = ACTION_IS_EIP_RUNNING; + this.retreiveVpnService(); + } + + if (mReceiver != null){ + mReceiver.send(resultCode, resultData); + } + } + + /** + * Initiates an EIP connection by selecting a gateway and preparing and sending an + * Intent to {@link se.leap.openvpn.LaunchVPN} + */ + private void startEIP() { + if (activeGateway==null) + activeGateway = selectGateway(); + + Intent intent = new Intent(this,LaunchVPN.class); + intent.setAction(Intent.ACTION_MAIN); + intent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK); + intent.putExtra(LaunchVPN.EXTRA_KEY, activeGateway.mVpnProfile.getUUID().toString() ); + intent.putExtra(LaunchVPN.EXTRA_NAME, activeGateway.mVpnProfile.getName() ); + 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 (mBound) + mVpnService.onRevoke(); + else + OpenVpnManagementThread.stopOpenVPN(); + + if (mReceiver != null){ + Bundle resultData = new Bundle(); + resultData.putString(REQUEST_TAG, ACTION_STOP_EIP); + mReceiver.send(Activity.RESULT_OK, resultData); + } + } + + /** + * Loads eip-service.json from SharedPreferences and calls {@link updateGateways()} + * to parse gateway definitions. + * TODO Implement API call to refresh eip-service.json from the provider + */ + private void updateEIPService() { + try { + eipDefinition = ConfigHelper.getJsonFromSharedPref(EIP.KEY); + } catch (JSONException e) { + // TODO Auto-generated catch block + e.printStackTrace(); + } + if (eipDefinition.optInt("serial") > parsedEipSerial) + updateGateways(); + } + + /** + * Choose a gateway to connect to based on timezone from system locale data + * + * @return The gateway to connect to + */ + private OVPNGateway selectGateway() { + // TODO Implement gateway selection logic based on TZ or preferences + // TODO Implement search through gateways loaded from SharedPreferences + // TODO Remove String arg constructor in favor of findGatewayByName(String) + return new OVPNGateway("first"); + } + + /** + * Walk the list of gateways defined in eip-service.json and parse them into + * OVPNGateway objects. + * TODO Store the OVPNGateways (as Serializable) in SharedPreferences + */ + private void updateGateways(){ + JSONArray gatewaysDefined = null; + + try { + gatewaysDefined = eipDefinition.getJSONArray("gateways"); + } catch (JSONException e1) { + // TODO Auto-generated catch block + e1.printStackTrace(); + } + + for ( int i=0 ; i < gatewaysDefined.length(); i++ ){ + + JSONObject gw = null; + + try { + gw = gatewaysDefined.getJSONObject(i); + } catch (JSONException e) { + // TODO Auto-generated catch block + e.printStackTrace(); + } + + try { + if ( gw.getJSONObject("capabilities").getJSONArray("transport").toString().contains("openvpn") ){ + new OVPNGateway(gw); + } + } catch (JSONException e) { + // TODO Auto-generated catch block + e.printStackTrace(); + } + } + + ConfigHelper.saveSharedPref(PARSED_SERIAL, eipDefinition.optInt(Provider.API_RETURN_SERIAL)); + } + + /** + * OVPNGateway provides objects defining gateways and their options and metadata. + * Each instance contains a VpnProfile for OpenVPN specific data and member + * variables describing capabilities and location + * + * @author Sean Leonard + */ + private class OVPNGateway { + + private String TAG = "OVPNGateway"; + + private String mName; + private VpnProfile mVpnProfile; + private JSONObject mGateway; + private HashMap>> options = new HashMap>>(); + + + /** + * Attempts to retrieve a VpnProfile by name and build an OVPNGateway around it. + * FIXME This needs to become a findGatewayByName() method + * + * @param name The hostname of the gateway to inflate + */ + private OVPNGateway(String name){ + mName = name; + + this.loadVpnProfile(); + } + + private void loadVpnProfile() { + ProfileManager vpl = ProfileManager.getInstance(context); + + try { + if ( mName == "first" ) { + mName = vpl.getProfiles().iterator().next().mName; + } + + mVpnProfile = vpl.getProfileByName(mName); + + } catch (NoSuchElementException e) { + updateEIPService(); + this.loadVpnProfile(); // FIXME catch infinite loops + } catch (Exception e) { + // TODO Auto-generated catch block + e.printStackTrace(); + } + } + + /** + * Build a gateway object from a JSON OpenVPN gateway definition in eip-service.json + * and create a VpnProfile belonging to it. + * + * @param gateway The JSON OpenVPN gateway definition to parse + */ + protected OVPNGateway(JSONObject gateway){ + + mGateway = gateway; + + // Currently deletes VpnProfile for host, if there already is one, and builds new + ProfileManager vpl = ProfileManager.getInstance(context); + Collection profiles = vpl.getProfiles(); + for (Iterator it = profiles.iterator(); it.hasNext(); ){ + VpnProfile p = it.next(); + try { + if ( p.mName.contains( gateway.getString("host") ) ) + it.remove(); + vpl.removeProfile(context, p); + } catch (JSONException e) { + // TODO Auto-generated catch block + e.printStackTrace(); + } + } + + this.parseOptions(); + this.createVPNProfile(); + + setUniqueProfileName(vpl); + vpl.addProfile(mVpnProfile); + vpl.saveProfile(context, mVpnProfile); + vpl.saveProfileList(context); + } + + /** + * Attempts to create a unique profile name from the hostname of the gateway + * + * @param profileManager + */ + private void setUniqueProfileName(ProfileManager profileManager) { + int i=0; + + String newname; + try { + newname = mGateway.getString("host"); + while(profileManager.getProfileByName(newname)!=null) { + i++; + if(i==1) + newname = getString(R.string.converted_profile); + else + newname = getString(R.string.converted_profile_i,i); + } + + mVpnProfile.mName=newname; + } catch (JSONException e) { + // TODO Auto-generated catch block + Log.v(TAG,"Couldn't read gateway name for profile creation!"); + e.printStackTrace(); + } + } + + /** + * FIXME This method is really the outline of the refactoring needed in se.leap.openvpn.ConfigParser + */ + private void parseOptions(){ + + // FIXME move these to a common API (& version) definition place, like ProviderAPI or ConfigHelper + String common_options = "openvpn_configuration"; + String remote = "ip_address"; + String ports = "ports"; + String protos = "protocols"; + String capabilities = "capabilities"; + + Vector arg = new Vector(); + Vector> args = new Vector>(); + + try { + JSONObject def = (JSONObject) eipDefinition.get(common_options); + Iterator keys = def.keys(); + Vector> value = new Vector>(); + while ( keys.hasNext() ){ + String key = keys.next().toString(); + + arg.add(key); + for ( String word : def.getString(key).split(" ") ) + arg.add(word); + value.add( (Vector) arg.clone() ); + options.put(key, (Vector>) value.clone()); + + value.clear(); + arg.clear(); + } + } catch (JSONException e) { + // TODO Auto-generated catch block + e.printStackTrace(); + } + + try { + arg.add("remote"); + arg.add(mGateway.getString(remote)); + } catch (JSONException e) { + // TODO Auto-generated catch block + e.printStackTrace(); + } + args.add((Vector) arg.clone()); + options.put("remote", (Vector>) args.clone() ); + arg.clear(); + args.clear(); + + JSONArray protocolsJSON = null; + arg.add("proto"); + try { + protocolsJSON = mGateway.getJSONObject(capabilities).getJSONArray(protos); + } catch (JSONException e) { + // TODO Auto-generated catch block + e.printStackTrace(); + } + Vector protocols = new Vector(); + for ( int i=0; i) arg.clone()); + options.put("proto", (Vector>) args.clone()); + arg.clear(); + args.clear(); + + + String port = null; + arg.add("port"); + try { + port = mGateway.getJSONObject(capabilities).getJSONArray(ports).optString(0); + } catch (JSONException e) { + // TODO Auto-generated catch block + e.printStackTrace(); + } + arg.add(port); + args.add((Vector) arg.clone()); + options.put("port", (Vector>) args.clone()); + args.clear(); + arg.clear(); + } + + /** + * Create and attach the VpnProfile to our gateway object + */ + protected void createVPNProfile(){ + try { + ConfigParser cp = new ConfigParser(); + cp.setDefinition(options); + VpnProfile vp = cp.convertProfile(); + mVpnProfile = vp; + Log.v(TAG,"Created VPNProfile"); + } catch (ConfigParseError e) { + // FIXME We didn't get a VpnProfile! Error handling! and log level + Log.v(TAG,"Error createing VPNProfile"); + e.printStackTrace(); + } + } + } + +} diff --git a/src/se/leap/bitmaskclient/EipServiceFragment.java b/src/se/leap/bitmaskclient/EipServiceFragment.java new file mode 100644 index 00000000..daf446a5 --- /dev/null +++ b/src/se/leap/bitmaskclient/EipServiceFragment.java @@ -0,0 +1,265 @@ +package se.leap.bitmaskclient; + +import se.leap.bitmaskclient.R; +import se.leap.openvpn.LogWindow; +import se.leap.openvpn.OpenVPN; +import se.leap.openvpn.OpenVPN.StateListener; +import android.app.Activity; +import android.app.AlertDialog; +import android.app.Fragment; +import android.content.DialogInterface; +import android.content.Intent; +import android.os.Bundle; +import android.os.Handler; +import android.os.ResultReceiver; +import android.view.LayoutInflater; +import android.view.MotionEvent; +import android.view.View; +import android.view.View.OnClickListener; +import android.view.ViewGroup; +import android.widget.CompoundButton.OnCheckedChangeListener; +import android.widget.CompoundButton; +import android.widget.RelativeLayout; +import android.widget.Switch; +import android.widget.TextView; + +public class EipServiceFragment extends Fragment implements StateListener, OnClickListener, OnCheckedChangeListener { + + private static final String IS_EIP_PENDING = "is_eip_pending"; + + private View eipFragment; + private Switch eipSwitch; + private View eipDetail; + private TextView eipStatus; + + private boolean eipAutoSwitched = true; + + private boolean mEipStartPending = false; + + private EIPReceiver mEIPReceiver; + + @Override + public View onCreateView(LayoutInflater inflater, ViewGroup container, + Bundle savedInstanceState) { + + eipFragment = inflater.inflate(R.layout.eip_service_fragment, container, false); + + eipDetail = ((RelativeLayout) eipFragment.findViewById(R.id.eipDetail)); + eipDetail.setVisibility(View.VISIBLE); + + View eipSettings = eipFragment.findViewById(R.id.eipSettings); + eipSettings.setVisibility(View.GONE); // FIXME too! + + if (mEipStartPending) + eipFragment.findViewById(R.id.eipProgress).setVisibility(View.VISIBLE); + + eipStatus = (TextView) eipFragment.findViewById(R.id.eipStatus); + eipStatus.setOnClickListener(this); + + eipSwitch = (Switch) eipFragment.findViewById(R.id.eipSwitch); + eipSwitch.setOnTouchListener(new View.OnTouchListener() { + @Override + public boolean onTouch(View v, MotionEvent event) { + eipAutoSwitched = false; + return false; + } + }); + eipSwitch.setOnCheckedChangeListener(this); + + return eipFragment; + } + + @Override + public void onCreate(Bundle savedInstanceState) { + super.onCreate(savedInstanceState); + + mEIPReceiver = new EIPReceiver(new Handler()); + + if (savedInstanceState != null) + mEipStartPending = savedInstanceState.getBoolean(IS_EIP_PENDING); + } + + @Override + public void onResume() { + super.onResume(); + + OpenVPN.addStateListener(this); + } + + @Override + public void onPause() { + super.onPause(); + + OpenVPN.removeStateListener(this); + } + + @Override + public void onSaveInstanceState(Bundle outState) { + super.onSaveInstanceState(outState); + outState.putBoolean(IS_EIP_PENDING, mEipStartPending); + } + + @Override + public void onClick(View buttonView) { + if (buttonView.equals(eipStatus)) + showEIPLog(); + } + + /** + * Launches the se.leap.openvpn.LogWindow Activity showing detailed OpenVPN log + */ + public void showEIPLog(){ + Intent intent = new Intent(getActivity().getBaseContext(),LogWindow.class); + intent.addFlags(Intent.FLAG_ACTIVITY_REORDER_TO_FRONT); + startActivity(intent); + } + + @Override + public void onCheckedChanged(CompoundButton buttonView, boolean isChecked) { + if (buttonView.equals(eipSwitch) && !eipAutoSwitched){ + if (isChecked){ + mEipStartPending = true; + eipFragment.findViewById(R.id.eipProgress).setVisibility(View.VISIBLE); + ((TextView) eipFragment.findViewById(R.id.eipStatus)).setText(R.string.eip_status_start_pending); + eipCommand(EIP.ACTION_START_EIP); + } else { + if (mEipStartPending){ + AlertDialog.Builder alertBuilder = new AlertDialog.Builder(getActivity()); + alertBuilder.setTitle(getResources().getString(R.string.eip_cancel_connect_title)); + alertBuilder + .setMessage(getResources().getString(R.string.eip_cancel_connect_text)) + .setPositiveButton(getResources().getString(R.string.eip_cancel_connect_cancel), new DialogInterface.OnClickListener() { + @Override + public void onClick(DialogInterface dialog, int which) { + eipCommand(EIP.ACTION_STOP_EIP); + } + }) + .setNegativeButton(getResources().getString(R.string.eip_cancel_connect_false), new DialogInterface.OnClickListener() { + @Override + public void onClick(DialogInterface dialog, int which) { + eipAutoSwitched = true; + eipSwitch.setChecked(true); + eipAutoSwitched = false; + } + }) + .show(); + } else { + eipCommand(EIP.ACTION_STOP_EIP); + } + } + } + eipAutoSwitched = true; + } + + /** + * Send a command to EIP + * + * @param action A valid String constant from EIP class representing an Intent + * filter for the EIP class + */ + private void eipCommand(String action){ + // TODO validate "action"...how do we get the list of intent-filters for a class via Android API? + Intent vpnIntent = new Intent(action); + vpnIntent.putExtra(EIP.RECEIVER_TAG, mEIPReceiver); + getActivity().startService(vpnIntent); + } + + @Override + public void updateState(final String state, final String logmessage, final int localizedResId) { + // Note: "states" are not organized anywhere...collected state strings: + // NOPROCESS,NONETWORK,BYTECOUNT,AUTH_FAILED + some parsing thing ( WAIT(?),AUTH,GET_CONFIG,ASSIGN_IP,CONNECTED,SIGINT ) + getActivity().runOnUiThread(new Runnable() { + + @Override + public void run() { + if (eipStatus != null) { + boolean switchState = true; + String statusMessage = ""; + String prefix = getString(localizedResId); + if (state.equals("CONNECTED")){ + statusMessage = "Connection Secure"; + getActivity().findViewById(R.id.eipProgress).setVisibility(View.GONE); + mEipStartPending = false; + } else if (state.equals("BYTECOUNT")) { + statusMessage = logmessage; + } else if ( (state.equals("NOPROCESS") && !mEipStartPending ) || state.equals("EXITING")) { + statusMessage = "Not running! Connection not secure!"; + getActivity().findViewById(R.id.eipProgress).setVisibility(View.GONE); + mEipStartPending = false; + switchState = false; + } else { + statusMessage = prefix + logmessage; + } + + eipAutoSwitched = true; + eipSwitch.setChecked(switchState); + eipAutoSwitched = false; + eipStatus.setText(statusMessage); + } + } + }); + } + + /** + * Inner class for handling messages related to EIP status and control requests + * + * @author Sean Leonard + */ + protected class EIPReceiver extends ResultReceiver { + + protected EIPReceiver(Handler handler){ + super(handler); + } + + @Override + protected void onReceiveResult(int resultCode, Bundle resultData) { + super.onReceiveResult(resultCode, resultData); + + String request = resultData.getString(EIP.REQUEST_TAG); + boolean checked = false; + + if (request == EIP.ACTION_IS_EIP_RUNNING) { + switch (resultCode){ + case Activity.RESULT_OK: + checked = true; + break; + case Activity.RESULT_CANCELED: + checked = false; + break; + } + } else if (request == EIP.ACTION_START_EIP) { + switch (resultCode){ + case Activity.RESULT_OK: + checked = true; + break; + case Activity.RESULT_CANCELED: + checked = false; + eipFragment.findViewById(R.id.eipProgress).setVisibility(View.GONE); + break; + } + } else if (request == EIP.ACTION_STOP_EIP) { + switch (resultCode){ + case Activity.RESULT_OK: + checked = false; + break; + case Activity.RESULT_CANCELED: + checked = true; + break; + } + } else if (request == EIP.EIP_NOTIFICATION) { + switch (resultCode){ + case Activity.RESULT_OK: + checked = true; + break; + case Activity.RESULT_CANCELED: + checked = false; + break; + } + } + + eipAutoSwitched = true; + eipSwitch.setChecked(checked); + eipAutoSwitched = false; + } + } +} diff --git a/src/se/leap/bitmaskclient/LeapHttpClient.java b/src/se/leap/bitmaskclient/LeapHttpClient.java new file mode 100644 index 00000000..837da236 --- /dev/null +++ b/src/se/leap/bitmaskclient/LeapHttpClient.java @@ -0,0 +1,84 @@ +/** + * 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 . + */ + 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 { + final Context context; + + 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(Context context) { + if(client == null) { + client = new LeapHttpClient(context); + String cert_string = ConfigHelper.getStringFromSharedPref(Provider.CA_CERT); + 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); + } + } + + public LeapHttpClient(Context context) { + this.context = context; + } +} diff --git a/src/se/leap/bitmaskclient/LeapSRPSession.java b/src/se/leap/bitmaskclient/LeapSRPSession.java new file mode 100644 index 00000000..9260c81f --- /dev/null +++ b/src/se/leap/bitmaskclient/LeapSRPSession.java @@ -0,0 +1,326 @@ +/** + * 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 . + */ + package se.leap.bitmaskclient; + +import java.io.UnsupportedEncodingException; +import java.math.BigInteger; +import java.security.MessageDigest; +import java.security.NoSuchAlgorithmException; +import java.security.SecureRandom; +import java.util.Arrays; + +import org.jboss.security.srp.SRPParameters; + +/** + * Implements all SRP algorithm logic. + * + * It's derived from JBoss implementation, with adjustments to make it work with LEAP platform. + * + * @author parmegv + * + */ +public class LeapSRPSession { + + final public static String SALT = "salt"; + final public static String M1 = "M1"; + final public static String M2 = "M2"; + + private SRPParameters params; + private String username; + private String password; + private BigInteger N; + private byte[] N_bytes; + private BigInteger g; + private BigInteger x; + private BigInteger v; + private BigInteger a; + private BigInteger A; + private byte[] K; + private SecureRandom pseudoRng; + /** The M1 = H(H(N) xor H(g) | H(U) | s | A | B | K) hash */ + private MessageDigest clientHash; + /** The M2 = H(A | M | K) hash */ + private MessageDigest serverHash; + + 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) + { + this(username, password, params, null); + } + + /** 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 + @param abytes, the random exponent used in the A public key + */ + public LeapSRPSession(String username, String password, SRPParameters params, + byte[] abytes) { + this.params = params; + this.g = new BigInteger(1, params.g); + N_bytes = ConfigHelper.trim(params.N); + this.N = new BigInteger(1, N_bytes); + this.username = username; + this.password = password; + + try { + pseudoRng = SecureRandom.getInstance("SHA1PRNG"); + } catch (NoSuchAlgorithmException e) { + // TODO Auto-generated catch block + e.printStackTrace(); + } + + if( abytes != null ) { + A_LEN = 8*abytes.length; + /* TODO Why did they put this condition? + if( 8*abytes.length != A_LEN ) + throw new IllegalArgumentException("The abytes param must be " + +(A_LEN/8)+" in length, abytes.length="+abytes.length); + */ + this.a = new BigInteger(abytes); + } + else + A_LEN = 64; + + serverHash = newDigest(); + clientHash = newDigest(); + } + + /** + * Calculates the parameter x of the SRP-6a algorithm. + * @param username + * @param password + * @param salt the salt of the user + * @return x + */ + public byte[] calculatePasswordHash(String username, String password, byte[] salt) + { + //password = password.replaceAll("\\\\", "\\\\\\\\"); + // Calculate x = H(s | H(U | ':' | password)) + MessageDigest x_digest = newDigest(); + // Try to convert the username to a byte[] using ISO-8859-1 + byte[] user = null; + byte[] password_bytes = null; + byte[] colon = {}; + String encoding = "ISO-8859-1"; + try { + user = ConfigHelper.trim(username.getBytes(encoding)); + colon = ConfigHelper.trim(":".getBytes(encoding)); + password_bytes = ConfigHelper.trim(password.getBytes(encoding)); + } + catch(UnsupportedEncodingException e) { + // Use the default platform encoding + user = ConfigHelper.trim(username.getBytes()); + colon = ConfigHelper.trim(":".getBytes()); + password_bytes = ConfigHelper.trim(password.getBytes()); + } + + // Build the hash + x_digest.update(user); + x_digest.update(colon); + x_digest.update(password_bytes); + byte[] h = x_digest.digest(); + + x_digest.reset(); + x_digest.update(salt); + x_digest.update(h); + byte[] x_digest_bytes = x_digest.digest(); + + return x_digest_bytes; + } + + /** + * Calculates the parameter V of the SRP-6a algorithm. + * @param k_string constant k predefined by the SRP server implementation. + * @return the value of V + */ + private BigInteger calculateV(String k_string) { + BigInteger k = new BigInteger(k_string, 16); + BigInteger v = k.multiply(g.modPow(x, N)); // g^x % N + return v; + } + + /** + * Calculates the trimmed xor from two BigInteger numbers + * @param b1 the positive source to build first BigInteger + * @param b2 the positive source to build second BigInteger + * @param length + * @return + */ + public byte[] xor(byte[] b1, byte[] b2) + { + //TODO Check if length matters in the order, when b2 is smaller than b1 or viceversa + byte[] xor_digest = new BigInteger(1, b1).xor(new BigInteger(1, b2)).toByteArray(); + return ConfigHelper.trim(xor_digest); + } + + /** + * @returns The exponential residue (parameter A) to be sent to the server. + */ + public byte[] exponential() { + byte[] Abytes = null; + if(A == null) { + /* If the random component of A has not been specified use a random + number */ + if( a == null ) { + BigInteger one = BigInteger.ONE; + do { + a = new BigInteger(A_LEN, pseudoRng); + } while(a.compareTo(one) <= 0); + } + A = g.modPow(a, N); + Abytes = ConfigHelper.trim(A.toByteArray()); + } + return Abytes; + } + + /** + * Calculates the parameter M1, to be sent to the SRP server. + * It also updates hashes of client and server for further calculations in other methods. + * It uses a predefined k. + * @param salt_bytes + * @param Bbytes the parameter received from the server, in bytes + * @return the parameter M1 + * @throws NoSuchAlgorithmException + */ + public byte[] response(byte[] salt_bytes, byte[] Bbytes) throws NoSuchAlgorithmException { + // Calculate x = H(s | H(U | ':' | password)) + byte[] xb = calculatePasswordHash(username, password, ConfigHelper.trim(salt_bytes)); + this.x = new BigInteger(1, xb); + + // Calculate v = kg^x mod N + String k_string = "bf66c44a428916cad64aa7c679f3fd897ad4c375e9bbb4cbf2f5de241d618ef0"; + this.v = calculateV(k_string); + + // H(N) + byte[] digest_of_n = newDigest().digest(N_bytes); + + // H(g) + byte[] digest_of_g = newDigest().digest(params.g); + + // clientHash = H(N) xor H(g) + byte[] xor_digest = xor(digest_of_n, digest_of_g); + clientHash.update(xor_digest); + + // clientHash = H(N) xor H(g) | H(U) + byte[] username_digest = newDigest().digest(ConfigHelper.trim(username.getBytes())); + username_digest = ConfigHelper.trim(username_digest); + clientHash.update(username_digest); + + // clientHash = H(N) xor H(g) | H(U) | s + clientHash.update(ConfigHelper.trim(salt_bytes)); + + K = null; + + // clientHash = H(N) xor H(g) | H(U) | A + byte[] Abytes = ConfigHelper.trim(A.toByteArray()); + clientHash.update(Abytes); + + // clientHash = H(N) xor H(g) | H(U) | s | A | B + Bbytes = ConfigHelper.trim(Bbytes); + clientHash.update(Bbytes); + + // Calculate S = (B - kg^x) ^ (a + u * x) % N + BigInteger S = calculateS(Bbytes); + byte[] S_bytes = ConfigHelper.trim(S.toByteArray()); + + // K = SessionHash(S) + String hash_algorithm = params.hashAlgorithm; + MessageDigest sessionDigest = MessageDigest.getInstance(hash_algorithm); + K = ConfigHelper.trim(sessionDigest.digest(S_bytes)); + + // clientHash = H(N) xor H(g) | H(U) | A | B | K + clientHash.update(K); + + byte[] M1 = ConfigHelper.trim(clientHash.digest()); + + // serverHash = Astr + M + K + serverHash.update(Abytes); + serverHash.update(M1); + serverHash.update(K); + + return M1; + } + + /** + * It calculates the parameter S used by response() to obtain session hash K. + * @param Bbytes the parameter received from the server, in bytes + * @return the parameter S + */ + private BigInteger calculateS(byte[] Bbytes) { + byte[] Abytes = ConfigHelper.trim(A.toByteArray()); + Bbytes = ConfigHelper.trim(Bbytes); + byte[] u_bytes = getU(Abytes, Bbytes); + + BigInteger B = new BigInteger(1, Bbytes); + BigInteger u = new BigInteger(1, u_bytes); + + BigInteger B_minus_v = B.subtract(v); + BigInteger a_ux = a.add(u.multiply(x)); + BigInteger S = B_minus_v.modPow(a_ux, N); + return S; + } + + /** + * It calculates the parameter u used by calculateS to obtain S. + * @param Abytes the exponential residue sent to the server + * @param Bbytes the parameter received from the server, in bytes + * @return + */ + public byte[] getU(byte[] Abytes, byte[] Bbytes) { + MessageDigest u_digest = newDigest(); + u_digest.update(ConfigHelper.trim(Abytes)); + u_digest.update(ConfigHelper.trim(Bbytes)); + byte[] u_digest_bytes = u_digest.digest(); + return ConfigHelper.trim(new BigInteger(1, u_digest_bytes).toByteArray()); + } + + /** + * @param M2 The server's response to the client's challenge + * @returns True if and only if the server's response was correct. + */ + public boolean verify(byte[] M2) + { + // M2 = H(A | M1 | K) + M2 = ConfigHelper.trim(M2); + byte[] myM2 = ConfigHelper.trim(serverHash.digest()); + boolean valid = Arrays.equals(M2, myM2); + return valid; + } + + /** + * @return a new SHA-256 digest. + */ + public MessageDigest newDigest() + { + MessageDigest md = null; + try { + md = MessageDigest.getInstance("SHA-256"); + } catch (NoSuchAlgorithmException e) { + e.printStackTrace(); + } + return md; + } +} diff --git a/src/se/leap/bitmaskclient/LogInDialog.java b/src/se/leap/bitmaskclient/LogInDialog.java new file mode 100644 index 00000000..3651e9ba --- /dev/null +++ b/src/se/leap/bitmaskclient/LogInDialog.java @@ -0,0 +1,139 @@ +/** + * 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 . + */ + package se.leap.bitmaskclient; + +import se.leap.bitmaskclient.R; +import android.R.color; +import android.app.Activity; +import android.app.AlertDialog; +import android.app.DialogFragment; +import android.content.DialogInterface; +import android.content.res.ColorStateList; +import android.os.Bundle; +import android.provider.CalendarContract.Colors; +import android.view.LayoutInflater; +import android.view.View; +import android.view.animation.AlphaAnimation; +import android.view.animation.BounceInterpolator; +import android.widget.EditText; +import android.widget.TextView; + +/** + * Implements the log in dialog, currently without progress dialog. + * + * It returns to the previous fragment when finished, and sends username and password to the authenticate method. + * + * It also notifies the user if the password is not valid. + * + * @author parmegv + * + */ +public class LogInDialog extends DialogFragment { + + + 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"; + + + public AlertDialog onCreateDialog(Bundle savedInstanceState) { + AlertDialog.Builder builder = new AlertDialog.Builder(getActivity()); + LayoutInflater inflater = getActivity().getLayoutInflater(); + View log_in_dialog_view = inflater.inflate(R.layout.log_in_dialog, null); + + final TextView user_message = (TextView)log_in_dialog_view.findViewById(R.id.user_message); + if(getArguments() != null && getArguments().containsKey(getResources().getString(R.string.user_message))) { + user_message.setText(getArguments().getString(getResources().getString(R.string.user_message))); + } else { + user_message.setVisibility(View.GONE); + } + + final EditText username_field = (EditText)log_in_dialog_view.findViewById(R.id.username_entered); + if(getArguments() != null && getArguments().containsKey(USERNAME)) { + String username = getArguments().getString(USERNAME); + username_field.setText(username); + } + if (getArguments() != null && getArguments().containsKey(USERNAME_MISSING)) { + username_field.setError(getResources().getString(R.string.username_ask)); + } + + final EditText password_field = (EditText)log_in_dialog_view.findViewById(R.id.password_entered); + if(!username_field.getText().toString().isEmpty() && password_field.isFocusable()) { + password_field.requestFocus(); + } + if (getArguments() != null && getArguments().containsKey(PASSWORD_INVALID_LENGTH)) { + password_field.setError(getResources().getString(R.string.error_not_valid_password_user_message)); + } + + + builder.setView(log_in_dialog_view) + .setPositiveButton(R.string.login_button, new DialogInterface.OnClickListener() { + public void onClick(DialogInterface dialog, int id) { + String username = username_field.getText().toString().trim(); + String password = password_field.getText().toString().trim(); + dialog.dismiss(); + interface_with_Dashboard.authenticate(username, password); + } + }) + .setNegativeButton(R.string.cancel, new DialogInterface.OnClickListener() { + public void onClick(DialogInterface dialog, int id) { + dialog.cancel(); + } + }); + + return builder.create(); + } + + /** + * Interface used to communicate LogInDialog with Dashboard. + * + * @author parmegv + * + */ + public interface LogInDialogInterface { + /** + * Starts authentication process. + * @param username + * @param password + */ + public void authenticate(String username, String password); + } + + LogInDialogInterface interface_with_Dashboard; + + /** + * @return a new instance of this DialogFragment. + */ + public static DialogFragment newInstance() { + LogInDialog dialog_fragment = new LogInDialog(); + return dialog_fragment; + } + + @Override + public void onAttach(Activity activity) { + super.onAttach(activity); + try { + interface_with_Dashboard = (LogInDialogInterface) activity; + } catch (ClassCastException e) { + throw new ClassCastException(activity.toString() + + " must implement LogInDialogListener"); + } + } +} diff --git a/src/se/leap/bitmaskclient/NewProviderDialog.java b/src/se/leap/bitmaskclient/NewProviderDialog.java new file mode 100644 index 00000000..f77cb6d4 --- /dev/null +++ b/src/se/leap/bitmaskclient/NewProviderDialog.java @@ -0,0 +1,110 @@ +/** + * 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 . + */ + package se.leap.bitmaskclient; + +import se.leap.bitmaskclient.R; +import android.app.Activity; +import android.app.AlertDialog; +import android.app.Dialog; +import android.app.DialogFragment; +import android.content.DialogInterface; +import android.os.Bundle; +import android.view.LayoutInflater; +import android.view.View; +import android.widget.CheckBox; +import android.widget.EditText; +import android.widget.Toast; + +/** + * Implements the new custom provider dialog. + * + * @author parmegv + * + */ +public class NewProviderDialog extends DialogFragment { + + final public static String TAG = "newProviderDialog"; + + public interface NewProviderDialogInterface { + public void saveAndSelectProvider(String url_provider, boolean danger_on); + } + + NewProviderDialogInterface interface_with_ConfigurationWizard; + + /** + * @return a new instance of this DialogFragment. + */ + public static DialogFragment newInstance() { + NewProviderDialog dialog_fragment = new NewProviderDialog(); + return dialog_fragment; + } + + @Override + public void onAttach(Activity activity) { + super.onAttach(activity); + try { + interface_with_ConfigurationWizard = (NewProviderDialogInterface) activity; + } catch (ClassCastException e) { + throw new ClassCastException(activity.toString() + + " must implement NoticeDialogListener"); + } + } + + @Override + public Dialog onCreateDialog(Bundle savedInstanceState) { + AlertDialog.Builder builder = new AlertDialog.Builder(getActivity()); + LayoutInflater inflater = getActivity().getLayoutInflater(); + View new_provider_dialog_view = inflater.inflate(R.layout.new_provider_dialog, null); + final EditText url_input_field = (EditText)new_provider_dialog_view.findViewById(R.id.new_provider_url); + final CheckBox danger_checkbox = (CheckBox)new_provider_dialog_view.findViewById(R.id.danger_checkbox); + + builder.setView(new_provider_dialog_view) + .setMessage(R.string.introduce_new_provider) + .setPositiveButton(R.string.save, new DialogInterface.OnClickListener() { + public void onClick(DialogInterface dialog, int id) { + String entered_url = url_input_field.getText().toString().trim(); + if(!entered_url.startsWith("https://")) { + entered_url = "https://".concat(entered_url); + } + boolean danger_on = danger_checkbox.isChecked(); + if(validURL(entered_url)) { + interface_with_ConfigurationWizard.saveAndSelectProvider(entered_url, danger_on); + Toast.makeText(getActivity().getApplicationContext(), R.string.valid_url_entered, Toast.LENGTH_LONG).show(); + } else { + url_input_field.setText(""); + Toast.makeText(getActivity().getApplicationContext(), R.string.not_valid_url_entered, Toast.LENGTH_LONG).show(); + } + } + }) + .setNegativeButton(R.string.cancel, new DialogInterface.OnClickListener() { + public void onClick(DialogInterface dialog, int id) { + dialog.cancel(); + } + }); + // Create the AlertDialog object and return it + return builder.create(); + } + + /** + * Checks if the entered url is valid or not. + * @param entered_url + * @return true if it's not empty nor contains only the protocol. + */ + boolean validURL(String entered_url) { + return !entered_url.isEmpty() && entered_url.matches("http[s]?://.+") && !entered_url.replaceFirst("http[s]?://", "").isEmpty(); + } +} diff --git a/src/se/leap/bitmaskclient/Provider.java b/src/se/leap/bitmaskclient/Provider.java new file mode 100644 index 00000000..e462829f --- /dev/null +++ b/src/se/leap/bitmaskclient/Provider.java @@ -0,0 +1,208 @@ +/** + * 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 . + */ +package se.leap.bitmaskclient; + +import java.io.Serializable; +import java.util.Arrays; +import java.util.Locale; + +import org.json.JSONArray; +import org.json.JSONException; +import org.json.JSONObject; + +import android.content.Context; +import android.app.Activity; +import android.content.SharedPreferences; + +/** + * @author Sean Leonard + * + */ +public final class Provider implements Serializable { + + private static final long serialVersionUID = 6003835972151761353L; + + private static Provider instance = null; + + // We'll access our preferences here + private static SharedPreferences preferences = null; + // Represents our Provider's provider.json + private static JSONObject definition = null; + + final public static String + API_URL = "api_uri", + API_VERSION = "api_version", + ALLOW_REGISTRATION = "allow_registration", + API_RETURN_SERIAL = "serial", + SERVICE = "service", + KEY = "provider", + CA_CERT = "ca_cert", + NAME = "name", + DESCRIPTION = "description", + DOMAIN = "domain", + MAIN_URL = "main_url", + DOT_JSON_URL = "provider_json_url" + ; + + // Array of what API versions we understand + protected static final String[] API_VERSIONS = {"1"}; // I assume we might encounter arbitrary version "numbers" + // Some API pieces we want to know about + private static final String API_TERM_SERVICES = "services"; + private static final String API_TERM_NAME = "name"; + private static final String API_TERM_DOMAIN = "domain"; + private static final String API_TERM_DEFAULT_LANGUAGE = "default_language"; + protected static final String[] API_EIP_TYPES = {"openvpn"}; + + private static final String PREFS_EIP_NAME = null; + + + + // What, no individual fields?! We're going to gamble on org.json.JSONObject and JSONArray + // Supporting multiple API versions will probably break this paradigm, + // Forcing me to write a real constructor and rewrite getters/setters + // Also will refactor if i'm instantiating the same local variables all the time + + /** + * + */ + private Provider() {} + + protected static Provider getInstance(){ + if(instance==null){ + instance = new Provider(); + } + return instance; + } + + protected void init(Activity activity) { + + // Load our preferences from SharedPreferences + // If there's nothing there, we will end up returning a rather empty object + // to whoever called getInstance() and they can run the First Run Wizard + //preferences = context.getgetPreferences(0); // 0 == MODE_PRIVATE, but we don't extend Android's classes... + + // Load SharedPreferences + preferences = activity.getSharedPreferences(Dashboard.SHARED_PREFERENCES,Context.MODE_PRIVATE); + // Inflate our provider.json data + try { + definition = new JSONObject( preferences.getString("provider", "") ); + } catch (JSONException e) { + // TODO: handle exception + + // FIXME!! We want "real" data!! + } + } + + protected String getDomain(){ + String domain = "Null"; + try { + domain = definition.getString(API_TERM_DOMAIN); + } catch (JSONException e) { + domain = "Null"; + e.printStackTrace(); + } + return domain; + } + + protected String getName(){ + // Should we pass the locale in, or query the system here? + String lang = Locale.getDefault().getLanguage(); + String name = "Null"; // Should it actually /be/ null, for error conditions? + try { + name = definition.getJSONObject(API_TERM_NAME).getString(lang); + } catch (JSONException e) { + // TODO: Nesting try/catch blocks? Crazy + // Maybe you should actually handle exception? + try { + name = definition.getJSONObject(API_TERM_NAME).getString( definition.getString(API_TERM_DEFAULT_LANGUAGE) ); + } catch (JSONException e2) { + // TODO: Will you handle the exception already? + } + } + + return name; + } + + protected String getDescription(){ + String lang = Locale.getDefault().getLanguage(); + String desc = null; + try { + desc = definition.getJSONObject("description").getString(lang); + } catch (JSONException e) { + // TODO: handle exception!! + try { + desc = definition.getJSONObject("description").getString( definition.getString("default_language") ); + } catch (JSONException e2) { + // TODO: i can't believe you're doing it again! + } + } + + return desc; + } + + protected boolean hasEIP() { + JSONArray services = null; + try { + services = definition.getJSONArray(API_TERM_SERVICES); // returns ["openvpn"] + } catch (Exception e) { + // TODO: handle exception + } + for (int i=0;i. + */ + package se.leap.bitmaskclient; + +import java.io.DataOutputStream; +import java.io.FileNotFoundException; +import java.io.IOException; +import java.io.InputStream; +import java.io.UnsupportedEncodingException; +import java.math.BigInteger; +import java.net.CookieHandler; +import java.net.CookieManager; +import java.net.CookiePolicy; +import java.net.MalformedURLException; +import java.net.SocketTimeoutException; +import java.net.URL; +import java.net.URLConnection; +import java.net.URLEncoder; +import java.net.UnknownHostException; +import java.security.KeyManagementException; +import java.security.KeyStore; +import java.security.KeyStoreException; +import java.security.NoSuchAlgorithmException; +import java.security.SecureRandom; +import java.security.cert.CertificateException; +import java.security.cert.X509Certificate; +import java.security.interfaces.RSAPrivateKey; +import java.util.HashMap; +import java.util.Iterator; +import java.util.Map; +import java.util.Scanner; + +import javax.net.ssl.HostnameVerifier; +import javax.net.ssl.HttpsURLConnection; +import javax.net.ssl.KeyManager; +import javax.net.ssl.SSLContext; +import javax.net.ssl.SSLSession; +import javax.net.ssl.TrustManager; +import javax.net.ssl.TrustManagerFactory; +import javax.net.ssl.X509TrustManager; + +import org.apache.http.client.ClientProtocolException; +import org.jboss.security.srp.SRPParameters; +import org.json.JSONException; +import org.json.JSONObject; + +import se.leap.bitmaskclient.R; +import se.leap.bitmaskclient.ProviderListContent.ProviderItem; +import android.app.IntentService; +import android.content.Intent; +import android.os.Bundle; +import android.os.Handler; +import android.os.ResultReceiver; +import android.util.Base64; +import android.util.Log; +import android.widget.Toast; + +/** + * Implements HTTP api methods used to manage communications with the provider server. + * + * It's an IntentService because it downloads data from the Internet, so it operates in the background. + * + * @author parmegv + * @author MeanderingCode + * + */ +public class ProviderAPI extends IntentService { + + private Handler mHandler; + + final public static String + DOWNLOAD_JSON_FILES_BUNDLE_EXTRA = "downloadJSONFiles", + UPDATE_PROVIDER_DOTJSON = "updateProviderDotJSON", + DOWNLOAD_NEW_PROVIDER_DOTJSON = "downloadNewProviderDotJSON", + SRP_REGISTER = "srpRegister", + SRP_AUTH = "srpAuth", + LOG_OUT = "logOut", + DOWNLOAD_CERTIFICATE = "downloadUserAuthedCertificate", + PARAMETERS = "parameters", + RESULT_KEY = "result", + RECEIVER_KEY = "receiver", + SESSION_ID_COOKIE_KEY = "session_id_cookie_key", + SESSION_ID_KEY = "session_id", + ERRORS = "errors" + ; + + final public static int + CUSTOM_PROVIDER_ADDED = 0, + CORRECTLY_DOWNLOADED_JSON_FILES = 1, + INCORRECTLY_DOWNLOADED_JSON_FILES = 2, + SRP_AUTHENTICATION_SUCCESSFUL = 3, + SRP_AUTHENTICATION_FAILED = 4, + SRP_REGISTRATION_SUCCESSFUL = 5, + SRP_REGISTRATION_FAILED = 6, + LOGOUT_SUCCESSFUL = 7, + LOGOUT_FAILED = 8, + CORRECTLY_DOWNLOADED_CERTIFICATE = 9, + INCORRECTLY_DOWNLOADED_CERTIFICATE = 10, + CORRECTLY_UPDATED_PROVIDER_DOT_JSON = 11, + INCORRECTLY_UPDATED_PROVIDER_DOT_JSON = 12, + CORRECTLY_DOWNLOADED_ANON_CERTIFICATE = 13, + INCORRECTLY_DOWNLOADED_ANON_CERTIFICATE = 14 + ; + + public ProviderAPI() { + super("ProviderAPI"); + Log.v("ClassName", "Provider API"); + } + + @Override + public void onCreate() { + super.onCreate(); + mHandler = new Handler(); + CookieHandler.setDefault(new CookieManager(null, CookiePolicy.ACCEPT_ORIGINAL_SERVER) ); + } + + private void displayToast(final int toast_string_id) { + mHandler.post(new Runnable() { + + @Override + public void run() { + Toast.makeText(ProviderAPI.this, toast_string_id, Toast.LENGTH_LONG).show(); + } + }); + } + + @Override + protected void onHandleIntent(Intent command) { + final ResultReceiver receiver = command.getParcelableExtra("receiver"); + String action = command.getAction(); + Bundle parameters = command.getBundleExtra(PARAMETERS); + + if(action.equalsIgnoreCase(DOWNLOAD_JSON_FILES_BUNDLE_EXTRA)) { + if(!downloadJsonFiles(parameters)) { + receiver.send(INCORRECTLY_DOWNLOADED_JSON_FILES, Bundle.EMPTY); + } else { + receiver.send(CORRECTLY_DOWNLOADED_JSON_FILES, Bundle.EMPTY); + } + } else if(action.equalsIgnoreCase(UPDATE_PROVIDER_DOTJSON)) { + Bundle result = updateProviderDotJSON(parameters); + if(result.getBoolean(RESULT_KEY)) { + receiver.send(CORRECTLY_UPDATED_PROVIDER_DOT_JSON, result); + } else { + receiver.send(INCORRECTLY_UPDATED_PROVIDER_DOT_JSON, Bundle.EMPTY); + } + } else if (action.equalsIgnoreCase(DOWNLOAD_NEW_PROVIDER_DOTJSON)) { + Bundle result = downloadNewProviderDotJSON(parameters); + if(result.getBoolean(RESULT_KEY)) { + receiver.send(CORRECTLY_UPDATED_PROVIDER_DOT_JSON, result); + } else { + receiver.send(INCORRECTLY_DOWNLOADED_JSON_FILES, Bundle.EMPTY); + } + } else if (action.equalsIgnoreCase(SRP_AUTH)) { + Bundle session_id_bundle = authenticateBySRP(parameters); + if(session_id_bundle.getBoolean(RESULT_KEY)) { + receiver.send(SRP_AUTHENTICATION_SUCCESSFUL, session_id_bundle); + } else { + receiver.send(SRP_AUTHENTICATION_FAILED, session_id_bundle); + } + } else if (action.equalsIgnoreCase(LOG_OUT)) { + if(logOut(parameters)) { + receiver.send(LOGOUT_SUCCESSFUL, Bundle.EMPTY); + } else { + receiver.send(LOGOUT_FAILED, Bundle.EMPTY); + } + } else if (action.equalsIgnoreCase(DOWNLOAD_CERTIFICATE)) { + if(getNewCert(parameters)) { + receiver.send(CORRECTLY_DOWNLOADED_CERTIFICATE, Bundle.EMPTY); + } else { + receiver.send(INCORRECTLY_DOWNLOADED_CERTIFICATE, Bundle.EMPTY); + } + } + } + + /** + * Downloads the main cert and the eip-service.json files given through the task parameter + * @param task + * @return true if eip-service.json was parsed as a JSON object correctly. + */ + private boolean downloadJsonFiles(Bundle task) { + String cert_url = task.getString(Provider.CA_CERT); + String eip_service_json_url = task.getString(EIP.KEY); + boolean danger_on = task.getBoolean(ProviderItem.DANGER_ON); + try { + String cert_string = downloadWithCommercialCA(cert_url, danger_on); + if(cert_string.isEmpty()) return false; + X509Certificate certCert = ConfigHelper.parseX509CertificateFromString(cert_string); + cert_string = Base64.encodeToString( certCert.getEncoded(), Base64.DEFAULT); + ConfigHelper.saveSharedPref(Provider.CA_CERT, "-----BEGIN CERTIFICATE-----\n"+cert_string+"-----END CERTIFICATE-----"); + + String eip_service_string = downloadWithCommercialCA(eip_service_json_url, danger_on); + ConfigHelper.saveSharedPref(EIP.KEY, new JSONObject(eip_service_string)); + + return true; + } catch (JSONException e) { + return false; + } catch (CertificateException e) { + // TODO Auto-generated catch block + e.printStackTrace(); + return false; + } + } + + /** + * Starts the authentication process using SRP protocol. + * + * @param task containing: username, password and api url. + * @return a bundle with a boolean value mapped to a key named RESULT_KEY, and which is true if authentication was successful. + */ + private Bundle authenticateBySRP(Bundle task) { + Bundle session_id_bundle = new Bundle(); + + String username = (String) task.get(LogInDialog.USERNAME); + String password = (String) task.get(LogInDialog.PASSWORD); + if(validUserLoginData(username, password)) { + String authentication_server = (String) task.get(Provider.API_URL); + + SRPParameters params = new SRPParameters(new BigInteger(ConfigHelper.NG_1024, 16).toByteArray(), ConfigHelper.G.toByteArray(), BigInteger.ZERO.toByteArray(), "SHA-256"); + LeapSRPSession client = new LeapSRPSession(username, password, params); + byte[] A = client.exponential(); + try { + JSONObject saltAndB = sendAToSRPServer(authentication_server, username, new BigInteger(1, A).toString(16)); + if(saltAndB.length() > 0) { + String salt = saltAndB.getString(LeapSRPSession.SALT); + byte[] Bbytes = new BigInteger(saltAndB.getString("B"), 16).toByteArray(); + byte[] M1 = client.response(new BigInteger(salt, 16).toByteArray(), Bbytes); + JSONObject session_idAndM2 = sendM1ToSRPServer(authentication_server, username, M1); + if(session_idAndM2.has(LeapSRPSession.M2) && client.verify((byte[])session_idAndM2.get(LeapSRPSession.M2))) { + session_id_bundle.putBoolean(RESULT_KEY, true); + } else { + session_id_bundle.putBoolean(RESULT_KEY, false); + session_id_bundle.putString(getResources().getString(R.string.user_message), getResources().getString(R.string.error_bad_user_password_user_message)); + session_id_bundle.putString(LogInDialog.USERNAME, username); + } + } else { + session_id_bundle.putString(getResources().getString(R.string.user_message), getResources().getString(R.string.error_bad_user_password_user_message)); + session_id_bundle.putString(LogInDialog.USERNAME, username); + session_id_bundle.putBoolean(RESULT_KEY, false); + } + } catch (ClientProtocolException e) { + session_id_bundle.putBoolean(RESULT_KEY, false); + session_id_bundle.putString(getResources().getString(R.string.user_message), getResources().getString(R.string.error_client_http_user_message)); + session_id_bundle.putString(LogInDialog.USERNAME, username); + } catch (IOException e) { + session_id_bundle.putBoolean(RESULT_KEY, false); + session_id_bundle.putString(getResources().getString(R.string.user_message), getResources().getString(R.string.error_io_exception_user_message)); + session_id_bundle.putString(LogInDialog.USERNAME, username); + } catch (JSONException e) { + session_id_bundle.putBoolean(RESULT_KEY, false); + session_id_bundle.putString(getResources().getString(R.string.user_message), getResources().getString(R.string.error_json_exception_user_message)); + session_id_bundle.putString(LogInDialog.USERNAME, username); + } catch (NoSuchAlgorithmException e) { + session_id_bundle.putBoolean(RESULT_KEY, false); + session_id_bundle.putString(getResources().getString(R.string.user_message), getResources().getString(R.string.error_no_such_algorithm_exception_user_message)); + session_id_bundle.putString(LogInDialog.USERNAME, username); + } catch (KeyManagementException e) { + // TODO Auto-generated catch block + e.printStackTrace(); + } catch (KeyStoreException e) { + // TODO Auto-generated catch block + e.printStackTrace(); + } catch (CertificateException e) { + // TODO Auto-generated catch block + e.printStackTrace(); + } + } else { + if(!wellFormedPassword(password)) { + session_id_bundle.putBoolean(RESULT_KEY, false); + session_id_bundle.putString(LogInDialog.USERNAME, username); + session_id_bundle.putBoolean(LogInDialog.PASSWORD_INVALID_LENGTH, true); + } + if(username.isEmpty()) { + session_id_bundle.putBoolean(RESULT_KEY, false); + session_id_bundle.putBoolean(LogInDialog.USERNAME_MISSING, true); + } + } + + return session_id_bundle; + } + + /** + * Validates parameters entered by the user to log in + * @param entered_username + * @param entered_password + * @return true if both parameters are present and the entered password length is greater or equal to eight (8). + */ + private boolean validUserLoginData(String entered_username, String entered_password) { + return !(entered_username.isEmpty()) && wellFormedPassword(entered_password); + } + + /** + * Validates a password + * @param entered_password + * @return true if the entered password length is greater or equal to eight (8). + */ + private boolean wellFormedPassword(String entered_password) { + return entered_password.length() >= 8; + } + + /** + * Sends an HTTP POST request to the authentication server with the SRP Parameter A. + * @param server_url + * @param username + * @param clientA First SRP parameter sent + * @return response from authentication server + * @throws ClientProtocolException + * @throws IOException + * @throws JSONException + * @throws CertificateException + * @throws NoSuchAlgorithmException + * @throws KeyStoreException + * @throws KeyManagementException + */ + private JSONObject sendAToSRPServer(String server_url, String username, String clientA) throws ClientProtocolException, IOException, JSONException, KeyManagementException, KeyStoreException, NoSuchAlgorithmException, CertificateException { + Map parameters = new HashMap(); + parameters.put("login", username); + parameters.put("A", clientA); + return sendToServer(server_url + "/sessions.json", "POST", parameters); + + /*HttpPost post = new HttpPost(server_url + "/sessions.json" + "?" + "login=" + username + "&&" + "A=" + clientA); + return sendToServer(post);*/ + } + + /** + * Sends an HTTP PUT request to the authentication server with the SRP Parameter M1 (or simply M). + * @param server_url + * @param username + * @param m1 Second SRP parameter sent + * @return response from authentication server + * @throws ClientProtocolException + * @throws IOException + * @throws JSONException + * @throws CertificateException + * @throws NoSuchAlgorithmException + * @throws KeyStoreException + * @throws KeyManagementException + */ + private JSONObject sendM1ToSRPServer(String server_url, String username, byte[] m1) throws ClientProtocolException, IOException, JSONException, KeyManagementException, KeyStoreException, NoSuchAlgorithmException, CertificateException { + Map parameters = new HashMap(); + parameters.put("client_auth", new BigInteger(1, ConfigHelper.trim(m1)).toString(16)); + + //HttpPut put = new HttpPut(server_url + "/sessions/" + username +".json" + "?" + "client_auth" + "=" + new BigInteger(1, ConfigHelper.trim(m1)).toString(16)); + JSONObject json_response = sendToServer(server_url + "/sessions/" + username +".json", "PUT", parameters); + + JSONObject session_idAndM2 = new JSONObject(); + if(json_response.length() > 0) { + byte[] M2_not_trimmed = new BigInteger(json_response.getString(LeapSRPSession.M2), 16).toByteArray(); + /*Cookie session_id_cookie = LeapHttpClient.getInstance(getApplicationContext()).getCookieStore().getCookies().get(0); + session_idAndM2.put(ConfigHelper.SESSION_ID_COOKIE_KEY, session_id_cookie.getName()); + session_idAndM2.put(ConfigHelper.SESSION_ID_KEY, session_id_cookie.getValue());*/ + session_idAndM2.put(LeapSRPSession.M2, ConfigHelper.trim(M2_not_trimmed)); + } + return session_idAndM2; + } + + /** + * Executes an HTTP request expecting a JSON response. + * @param url + * @param request_method + * @param parameters + * @return response from authentication server + * @throws IOException + * @throws JSONException + * @throws MalformedURLException + * @throws CertificateException + * @throws NoSuchAlgorithmException + * @throws KeyStoreException + * @throws KeyManagementException + */ + private JSONObject sendToServer(String url, String request_method, Map parameters) throws JSONException, MalformedURLException, IOException, KeyManagementException, KeyStoreException, NoSuchAlgorithmException, CertificateException { + JSONObject json_response; + InputStream is = null; + HttpsURLConnection urlConnection = (HttpsURLConnection)new URL(url).openConnection(); + urlConnection.setRequestMethod(request_method); + urlConnection.setChunkedStreamingMode(0); + urlConnection.setSSLSocketFactory(getProviderSSLSocketFactory()); + try { + + DataOutputStream writer = new DataOutputStream(urlConnection.getOutputStream()); + writer.writeBytes(formatHttpParameters(parameters)); + writer.close(); + + is = urlConnection.getInputStream(); + String plain_response = new Scanner(is).useDelimiter("\\A").next(); + json_response = new JSONObject(plain_response); + } finally { + InputStream error_stream = urlConnection.getErrorStream(); + if(error_stream != null) { + String error_response = new Scanner(error_stream).useDelimiter("\\A").next(); + urlConnection.disconnect(); + Log.d("Error", error_response); + json_response = new JSONObject(error_response); + if(!json_response.isNull(ERRORS) || json_response.has(ERRORS)) { + return new JSONObject(); + } + } + } + + return json_response; + } + + private String formatHttpParameters(Map parameters) throws UnsupportedEncodingException { + StringBuilder result = new StringBuilder(); + boolean first = true; + + Iterator parameter_iterator = parameters.keySet().iterator(); + while(parameter_iterator.hasNext()) { + if(first) + first = false; + else + result.append("&&"); + + String key = parameter_iterator.next(); + String value = parameters.get(key); + + result.append(URLEncoder.encode(key, "UTF-8")); + result.append("="); + result.append(URLEncoder.encode(value, "UTF-8")); + } + + return result.toString(); + } + /** + * Downloads a provider.json from a given URL, adding a new provider using the given name. + * @param task containing a boolean meaning if the provider is custom or not, another boolean meaning if the user completely trusts this provider, the provider name and its provider.json url. + * @return a bundle with a boolean value mapped to a key named RESULT_KEY, and which is true if the update was successful. + */ + private Bundle updateProviderDotJSON(Bundle task) { + Bundle result = new Bundle(); + boolean custom = task.getBoolean(ProviderItem.CUSTOM); + boolean danger_on = task.getBoolean(ProviderItem.DANGER_ON); + String provider_json_url = task.getString(Provider.DOT_JSON_URL); + String provider_name = task.getString(Provider.NAME); + + try { + String provider_dot_json_string = downloadWithCommercialCA(provider_json_url, danger_on); + if(provider_dot_json_string.isEmpty()) { + result.putBoolean(RESULT_KEY, false); + } else { + JSONObject provider_json = new JSONObject(provider_dot_json_string); + ConfigHelper.saveSharedPref(EIP.ALLOWED_ANON, provider_json.getJSONObject(Provider.SERVICE).getBoolean(EIP.ALLOWED_ANON)); + + //ProviderListContent.addItem(new ProviderItem(provider_name, provider_json_url, provider_json, custom, danger_on)); + result.putBoolean(RESULT_KEY, true); + result.putString(Provider.KEY, provider_json.toString()); + result.putBoolean(ProviderItem.DANGER_ON, danger_on); + } + } catch (JSONException e) { + result.putBoolean(RESULT_KEY, false); + } + + return result; + } + + /** + * Downloads a custom provider provider.json file + * @param task containing a boolean meaning if the user completely trusts this provider, and the provider main url entered in the new custom provider dialog. + * @return true if provider.json file was successfully parsed as a JSON object. + */ + private Bundle downloadNewProviderDotJSON(Bundle task) { + Bundle result = new Bundle(); + boolean custom = true; + boolean danger_on = task.getBoolean(ProviderItem.DANGER_ON); + + String provider_main_url = (String) task.get(Provider.MAIN_URL); + String provider_name = provider_main_url.replaceFirst("http[s]?://", "").replaceFirst("\\/", "_"); + String provider_json_url = guessProviderDotJsonURL(provider_main_url); + + String provider_json_string = downloadWithCommercialCA(provider_json_url, danger_on); + try { + if(provider_json_string.isEmpty()) { + result.putBoolean(RESULT_KEY, false); + } else { + JSONObject provider_json = new JSONObject(provider_json_string); + + ConfigHelper.saveSharedPref(Provider.KEY, provider_json); + ConfigHelper.saveSharedPref(ProviderItem.DANGER_ON, danger_on); + ConfigHelper.saveSharedPref(EIP.ALLOWED_ANON, provider_json.getJSONObject(Provider.SERVICE).getBoolean(EIP.ALLOWED_ANON)); + ProviderItem added_provider = new ProviderItem(provider_name, provider_json_url, provider_json, custom, danger_on); + ProviderListContent.addItem(added_provider); + + result.putString(Provider.NAME, added_provider.getName()); + result.putBoolean(RESULT_KEY, true); + result.putString(Provider.KEY, provider_json.toString()); + result.putBoolean(ProviderItem.DANGER_ON, danger_on); + } + } catch (JSONException e) { + result.putBoolean(RESULT_KEY, false); + } + + return result; + } + + /** + * Tries to download the contents of the provided url using commercially validated CA certificate from chosen provider. + * + * If danger_on flag is true, SSL exceptions will be managed by futher methods that will try to use some bypass methods. + * @param string_url + * @param danger_on if the user completely trusts this provider + * @return + */ + private String downloadWithCommercialCA(String string_url, boolean danger_on) { + + String json_file_content = ""; + + URL provider_url = null; + int seconds_of_timeout = 1; + try { + provider_url = new URL(string_url); + URLConnection url_connection = provider_url.openConnection(); + url_connection.setConnectTimeout(seconds_of_timeout*1000); + json_file_content = new Scanner(url_connection.getInputStream()).useDelimiter("\\A").next(); + } catch (MalformedURLException e) { + displayToast(R.string.malformed_url); + } catch(SocketTimeoutException e) { + displayToast(R.string.server_is_down_message); + } catch (FileNotFoundException e) { + e.printStackTrace(); + displayToast(R.string.server_is_down_message); + } catch (IOException e) { + if(provider_url != null) { + json_file_content = downloadWithProviderCA(provider_url, danger_on); + } else { + displayToast(R.string.certificate_error); + } + } catch (Exception e) { + if(provider_url != null && danger_on) { + json_file_content = downloadWithProviderCA(provider_url, danger_on); + } + } + + return json_file_content; + } + + /** + * Tries to download the contents of the provided url using not commercially validated CA certificate from chosen provider. + * @param url + * @param danger_on true to download CA certificate in case it has not been downloaded. + * @return an empty string if it fails, the url content if not. + */ + private String downloadWithProviderCA(URL url, boolean danger_on) { + String json_file_content = ""; + + try { + // Tell the URLConnection to use a SocketFactory from our SSLContext + HttpsURLConnection urlConnection = + (HttpsURLConnection)url.openConnection(); + urlConnection.setSSLSocketFactory(getProviderSSLSocketFactory()); + json_file_content = new Scanner(urlConnection.getInputStream()).useDelimiter("\\A").next(); + } catch (CertificateException e) { + // TODO Auto-generated catch block + e.printStackTrace(); + } catch (UnknownHostException e) { + displayToast(R.string.server_is_down_message); + } catch (FileNotFoundException e) { + e.printStackTrace(); + displayToast(R.string.server_is_down_message); + } catch (IOException e) { + // The downloaded certificate doesn't validate our https connection. + if(danger_on) { + json_file_content = downloadWithoutCA(url); + } else { + displayToast(R.string.certificate_error); + } + } catch (KeyStoreException e) { + // TODO Auto-generated catch block + e.printStackTrace(); + } catch (NoSuchAlgorithmException e) { + // TODO Auto-generated catch block + e.printStackTrace(); + } catch (KeyManagementException e) { + // TODO Auto-generated catch block + e.printStackTrace(); + } + return json_file_content; + } + + private javax.net.ssl.SSLSocketFactory getProviderSSLSocketFactory() throws KeyStoreException, NoSuchAlgorithmException, CertificateException, IOException, KeyManagementException { + String provider_cert_string = ConfigHelper.getStringFromSharedPref(Provider.CA_CERT); + + java.security.cert.Certificate provider_certificate = ConfigHelper.parseX509CertificateFromString(provider_cert_string); + + // Create a KeyStore containing our trusted CAs + String keyStoreType = KeyStore.getDefaultType(); + KeyStore keyStore = KeyStore.getInstance(keyStoreType); + keyStore.load(null, null); + keyStore.setCertificateEntry("provider_ca_certificate", provider_certificate); + + // Create a TrustManager that trusts the CAs in our KeyStore + String tmfAlgorithm = TrustManagerFactory.getDefaultAlgorithm(); + TrustManagerFactory tmf = TrustManagerFactory.getInstance(tmfAlgorithm); + tmf.init(keyStore); + + // Create an SSLContext that uses our TrustManager + SSLContext context = SSLContext.getInstance("TLS"); + context.init(null, tmf.getTrustManagers(), null); + + return context.getSocketFactory(); + } + + /** + * Downloads the string that's in the url with any certificate. + */ + private String downloadWithoutCA(URL url) { + String string = ""; + try { + + HostnameVerifier hostnameVerifier = new HostnameVerifier() { + @Override + public boolean verify(String hostname, SSLSession session) { + return true; + } + }; + + class DefaultTrustManager implements X509TrustManager { + + @Override + public void checkClientTrusted(X509Certificate[] arg0, String arg1) throws CertificateException {} + + @Override + public void checkServerTrusted(X509Certificate[] arg0, String arg1) throws CertificateException {} + + @Override + public X509Certificate[] getAcceptedIssuers() { + return null; + } + } + + SSLContext context = SSLContext.getInstance("TLS"); + context.init(new KeyManager[0], new TrustManager[] {new DefaultTrustManager()}, new SecureRandom()); + + HttpsURLConnection urlConnection = (HttpsURLConnection)url.openConnection(); + urlConnection.setSSLSocketFactory(context.getSocketFactory()); + urlConnection.setHostnameVerifier(hostnameVerifier); + string = new Scanner(urlConnection.getInputStream()).useDelimiter("\\A").next(); + System.out.println("String ignoring certificate = " + string); + } catch (FileNotFoundException e) { + e.printStackTrace(); + displayToast(R.string.server_is_down_message); + } catch (IOException e) { + // The downloaded certificate doesn't validate our https connection. + e.printStackTrace(); + displayToast(R.string.certificate_error); + } catch (NoSuchAlgorithmException e) { + // TODO Auto-generated catch block + e.printStackTrace(); + } catch (KeyManagementException e) { + // TODO Auto-generated catch block + e.printStackTrace(); + } + return string; + } + + /** + * Tries to guess the provider.json url given the main provider url. + * @param provider_main_url + * @return the guessed provider.json url + */ + private String guessProviderDotJsonURL(String provider_main_url) { + return provider_main_url + "/provider.json"; + } + + /** + * Logs out from the api url retrieved from the task. + * @param task containing api url from which the user will log out + * @return true if there were no exceptions + */ + private boolean logOut(Bundle task) { + try { + String delete_url = task.getString(Provider.API_URL) + "/logout"; + + HttpsURLConnection urlConnection = (HttpsURLConnection)new URL(delete_url).openConnection(); + urlConnection.setRequestMethod("DELETE"); + urlConnection.setSSLSocketFactory(getProviderSSLSocketFactory()); + + int responseCode = urlConnection.getResponseCode(); + Log.d("logout", Integer.toString(responseCode)); + } catch (ClientProtocolException e) { + // TODO Auto-generated catch block + e.printStackTrace(); + return false; + } catch (IndexOutOfBoundsException e) { + // TODO Auto-generated catch block + e.printStackTrace(); + return false; + } catch (IOException e) { + // TODO Auto-generated catch block + e.printStackTrace(); + return false; + } catch (KeyManagementException e) { + // TODO Auto-generated catch block + e.printStackTrace(); + } catch (KeyStoreException e) { + // TODO Auto-generated catch block + e.printStackTrace(); + } catch (NoSuchAlgorithmException e) { + // TODO Auto-generated catch block + e.printStackTrace(); + } catch (CertificateException e) { + // TODO Auto-generated catch block + e.printStackTrace(); + } + return true; + } + + /** + * Downloads a new OpenVPN certificate, attaching authenticated cookie for authenticated certificate. + * + * @param task containing the type of the certificate to be downloaded + * @return true if certificate was downloaded correctly, false if provider.json or danger_on flag are not present in SharedPreferences, or if the certificate url could not be parsed as a URI, or if there was an SSL error. + */ + private boolean getNewCert(Bundle task) { + + try { + String type_of_certificate = task.getString(ConfigurationWizard.TYPE_OF_CERTIFICATE); + JSONObject provider_json = ConfigHelper.getJsonFromSharedPref(Provider.KEY); + URL provider_main_url = new URL(provider_json.getString(Provider.API_URL)); + String new_cert_string_url = provider_main_url.toString() + "/" + provider_json.getString(Provider.API_VERSION) + "/" + EIP.CERTIFICATE; + + boolean danger_on = ConfigHelper.getBoolFromSharedPref(ProviderItem.DANGER_ON); + String cert_string = downloadWithCommercialCA(new_cert_string_url, danger_on); + if(!cert_string.isEmpty()) { + // API returns concatenated cert & key. Split them for OpenVPN options + String certificateString = null, keyString = null; + String[] certAndKey = cert_string.split("(?<=-\n)"); + for (int i=0; i < certAndKey.length-1; i++){ + if ( certAndKey[i].contains("KEY") ) { + keyString = certAndKey[i++] + certAndKey[i]; + } + else if ( certAndKey[i].contains("CERTIFICATE") ) { + certificateString = certAndKey[i++] + certAndKey[i]; + } + } + try { + RSAPrivateKey keyCert = ConfigHelper.parseRsaKeyFromString(keyString); + keyString = Base64.encodeToString( keyCert.getEncoded(), Base64.DEFAULT ); + ConfigHelper.saveSharedPref(EIP.PRIVATE_KEY, "-----BEGIN RSA PRIVATE KEY-----\n"+keyString+"-----END RSA PRIVATE KEY-----"); + + X509Certificate certCert = ConfigHelper.parseX509CertificateFromString(certificateString); + certificateString = Base64.encodeToString( certCert.getEncoded(), Base64.DEFAULT); + ConfigHelper.saveSharedPref(EIP.CERTIFICATE, "-----BEGIN CERTIFICATE-----\n"+certificateString+"-----END CERTIFICATE-----"); + + return true; + } catch (CertificateException e) { + // TODO Auto-generated catch block + e.printStackTrace(); + return false; + } + } else { + return false; + } + } catch (IOException e) { + // TODO Auto-generated catch block + e.printStackTrace(); + return false; + } catch (JSONException e) { + // TODO Auto-generated catch block + e.printStackTrace(); + return false; + } /*catch (URISyntaxException e) { + // TODO Auto-generated catch block + e.printStackTrace(); + return false; + }*/ + } +} diff --git a/src/se/leap/bitmaskclient/ProviderAPIResultReceiver.java b/src/se/leap/bitmaskclient/ProviderAPIResultReceiver.java new file mode 100644 index 00000000..7b256124 --- /dev/null +++ b/src/se/leap/bitmaskclient/ProviderAPIResultReceiver.java @@ -0,0 +1,56 @@ +/** + * 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 . + */ + package se.leap.bitmaskclient; + +import android.os.Bundle; +import android.os.Handler; +import android.os.ResultReceiver; + +/** + * Implements the ResultReceiver needed by Activities using ProviderAPI to receive the results of its operations. + * @author parmegv + * + */ +public class ProviderAPIResultReceiver extends ResultReceiver { + private Receiver mReceiver; + + public ProviderAPIResultReceiver(Handler handler) { + super(handler); + // TODO Auto-generated constructor stub + } + + public void setReceiver(Receiver receiver) { + mReceiver = receiver; + } + + /** + * Interface to enable ProviderAPIResultReceiver to receive results from the ProviderAPI IntentService. + * @author parmegv + * + */ + public interface Receiver { + public void onReceiveResult(int resultCode, Bundle resultData); + } + + @Override + protected void onReceiveResult(int resultCode, Bundle resultData) { + if (mReceiver != null) { + mReceiver.onReceiveResult(resultCode, resultData); + } + } + +} diff --git a/src/se/leap/bitmaskclient/ProviderDetailFragment.java b/src/se/leap/bitmaskclient/ProviderDetailFragment.java new file mode 100644 index 00000000..4006a76c --- /dev/null +++ b/src/se/leap/bitmaskclient/ProviderDetailFragment.java @@ -0,0 +1,114 @@ +package se.leap.bitmaskclient; + +import org.json.JSONException; +import org.json.JSONObject; + +import se.leap.bitmaskclient.R; +import se.leap.bitmaskclient.ProviderListContent.ProviderItem; + +import android.app.Activity; +import android.app.AlertDialog; +import android.app.Dialog; +import android.app.DialogFragment; +import android.content.DialogInterface; +import android.os.Bundle; +import android.view.LayoutInflater; +import android.view.View; +import android.widget.TextView; + +public class ProviderDetailFragment extends DialogFragment { + + final public static String TAG = "providerDetailFragment"; + + @Override + public Dialog onCreateDialog(Bundle savedInstanceState) { + AlertDialog.Builder builder = new AlertDialog.Builder(getActivity()); + try { + + LayoutInflater inflater = getActivity().getLayoutInflater(); + View provider_detail_view = inflater.inflate(R.layout.provider_detail_fragment, null); + + JSONObject provider_json = ConfigHelper.getJsonFromSharedPref(Provider.KEY); + + final TextView domain = (TextView)provider_detail_view.findViewById(R.id.provider_detail_domain); + domain.setText(provider_json.getString(Provider.DOMAIN)); + final TextView name = (TextView)provider_detail_view.findViewById(R.id.provider_detail_name); + name.setText(provider_json.getJSONObject(Provider.NAME).getString("en")); + final TextView description = (TextView)provider_detail_view.findViewById(R.id.provider_detail_description); + description.setText(provider_json.getJSONObject(Provider.DESCRIPTION).getString("en")); + + builder.setView(provider_detail_view); + builder.setTitle(R.string.provider_details_fragment_title); + + if(anon_allowed(provider_json)) { + builder.setPositiveButton(R.string.use_anonymously_button, new DialogInterface.OnClickListener() { + public void onClick(DialogInterface dialog, int id) { + interface_with_configuration_wizard.use_anonymously(); + } + }); + } + + if(registration_allowed(provider_json)) { + builder.setNegativeButton(R.string.login_button, new DialogInterface.OnClickListener() { + public void onClick(DialogInterface dialog, int id) { + interface_with_configuration_wizard.login(); + } + }); + } + + return builder.create(); + } catch (JSONException e) { + return null; + } + } + + private boolean anon_allowed(JSONObject provider_json) { + try { + JSONObject service_description = provider_json.getJSONObject(Provider.SERVICE); + return service_description.has(EIP.ALLOWED_ANON) && service_description.getBoolean(EIP.ALLOWED_ANON); + } catch (JSONException e) { + return false; + } + } + + private boolean registration_allowed(JSONObject provider_json) { + try { + JSONObject service_description = provider_json.getJSONObject(Provider.SERVICE); + return service_description.has(Provider.ALLOW_REGISTRATION) && service_description.getBoolean(Provider.ALLOW_REGISTRATION); + } catch (JSONException e) { + return false; + } + } + + @Override + public void onCancel(DialogInterface dialog) { + super.onCancel(dialog); + ConfigHelper.removeFromSharedPref(Provider.KEY); + ConfigHelper.removeFromSharedPref(ProviderItem.DANGER_ON); + ConfigHelper.removeFromSharedPref(EIP.ALLOWED_ANON); + ConfigHelper.removeFromSharedPref(EIP.KEY); + } + + public static DialogFragment newInstance() { + ProviderDetailFragment provider_detail_fragment = new ProviderDetailFragment(); + return provider_detail_fragment; + } + + @Override + public void onAttach(Activity activity) { + super.onAttach(activity); + try { + interface_with_configuration_wizard = (ProviderDetailFragmentInterface) activity; + } catch (ClassCastException e) { + throw new ClassCastException(activity.toString() + + " must implement LogInDialogListener"); + } + } + + public interface ProviderDetailFragmentInterface { + public void login(); + public void use_anonymously(); + } + + ProviderDetailFragmentInterface interface_with_configuration_wizard; +} diff --git a/src/se/leap/bitmaskclient/ProviderListContent.java b/src/se/leap/bitmaskclient/ProviderListContent.java new file mode 100644 index 00000000..940a594d --- /dev/null +++ b/src/se/leap/bitmaskclient/ProviderListContent.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 . + */ + package se.leap.bitmaskclient; + +import java.io.IOException; +import java.io.InputStream; +import java.util.ArrayList; +import java.util.HashMap; +import java.util.List; +import java.util.Map; +import java.net.URL; +import java.net.MalformedURLException; + +import org.json.JSONException; +import org.json.JSONObject; + +/** + * Models the provider list shown in the ConfigurationWizard. + * + * @author parmegv + * + */ +public class ProviderListContent { + + public static List ITEMS = new ArrayList(); + + public static Map ITEM_MAP = new HashMap(); + + /** + * Adds a new provider item to the end of the items map, and to the items list. + * @param item + */ + public static void addItem(ProviderItem item) { + ITEMS.add(item); + ITEM_MAP.put(String.valueOf(ITEMS.size()), item); + } + + /** + * A provider item. + */ + public static class ProviderItem { + + + final public static String CUSTOM = "custom"; + final public static String DANGER_ON = "danger_on"; + + public boolean custom = false; + public String id; + public String name; + public String domain; + public String provider_json_url; + public JSONObject provider_json; + public String provider_json_filename; + public String eip_service_json_url; + public String cert_json_url; + public boolean danger_on = false; + + /** + * @param name of the provider + * @param urls_file_input_stream file input stream linking with the assets url file + * @param custom if it's a new provider entered by the user or not + * @param danger_on if the user trusts completely the new provider + */ + public ProviderItem(String name, InputStream urls_file_input_stream, boolean custom, boolean danger_on) { + + try { + byte[] urls_file_bytes = new byte[urls_file_input_stream.available()]; + urls_file_input_stream.read(urls_file_bytes); + String urls_file_content = new String(urls_file_bytes); + JSONObject file_contents = new JSONObject(urls_file_content); + id = name; + this.name = name; + provider_json_url = file_contents.getString(Provider.DOT_JSON_URL); + domain = new URL(provider_json_url).getHost(); + //provider_json_filename = file_contents.getString("assets_json_provider"); + eip_service_json_url = file_contents.getString("json_eip_service"); + cert_json_url = file_contents.getString(EIP.CERTIFICATE); + this.custom = custom; + this.danger_on = danger_on; + } catch (MalformedURLException e) { + // TODO Auto-generated catch block + e.printStackTrace(); + } catch (JSONException e) { + // TODO Auto-generated catch block + e.printStackTrace(); + } catch (IOException e) { + // TODO Auto-generated catch block + e.printStackTrace(); + } + } + + /** + * @param name of the provider + * @param provider_json_url used to download provider.json file of the provider + * @param provider_json already downloaded + * @param custom if it's a new provider entered by the user or not + * @param danger_on if the user trusts completely the new provider + */ + public ProviderItem(String name, String provider_json_url, JSONObject provider_json, boolean custom, boolean danger_on) { + + try { + id = name; + //this.name = name; + this.provider_json_url = provider_json_url; + this.provider_json = provider_json; + this.name = provider_json.getJSONObject("name").getString("en"); + domain = new URL(provider_json_url).getHost(); + eip_service_json_url = provider_json.getString(Provider.API_URL) + "/" + provider_json.getString(Provider.API_VERSION) + "/" + EIP.SERVICE_API_PATH; + cert_json_url = provider_json.getString("ca_cert_uri"); + this.custom = custom; + this.danger_on = danger_on; + if(custom) + provider_json_filename = name + "_provider.json".replaceFirst("__", "_"); + } catch (MalformedURLException e) { + // TODO Auto-generated catch block + e.printStackTrace(); + } catch (JSONException e) { + // TODO Auto-generated catch block + e.printStackTrace(); + } + } + + @Override + public String toString() { + return name; + } + + public String getName() { + return id; + } + } +} diff --git a/src/se/leap/bitmaskclient/ProviderListFragment.java b/src/se/leap/bitmaskclient/ProviderListFragment.java new file mode 100644 index 00000000..82c4bdc8 --- /dev/null +++ b/src/se/leap/bitmaskclient/ProviderListFragment.java @@ -0,0 +1,192 @@ +/** + * 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 . + */ + package se.leap.bitmaskclient; + +import se.leap.bitmaskclient.R; +import se.leap.bitmaskclient.ProviderListContent.ProviderItem; +import android.app.Activity; +import android.app.ListFragment; +import android.os.Bundle; +import android.view.LayoutInflater; +import android.view.View; +import android.view.ViewGroup; +import android.widget.ArrayAdapter; +import android.widget.ListView; +import android.content.Context; +import android.widget.TwoLineListItem; + +/** + * A list fragment representing a list of Providers. This fragment + * also supports tablet devices by allowing list items to be given an + * 'activated' state upon selection. This helps indicate which item is + * currently being viewed in a {@link DashboardFragment}. + *

+ * Activities containing this fragment MUST implement the {@link Callbacks} + * interface. + */ +public class ProviderListFragment extends ListFragment { + + private ArrayAdapter content_adapter; + + /** + * The serialization (saved instance state) Bundle key representing the + * activated item position. Only used on tablets. + */ + private static final String STATE_ACTIVATED_POSITION = "activated_position"; + + /** + * The fragment's current callback object, which is notified of list item + * clicks. + */ + private Callbacks mCallbacks = sDummyCallbacks; + + /** + * The current activated item position. Only used on tablets. + */ + private int mActivatedPosition = ListView.INVALID_POSITION; + + /** + * A callback interface that all activities containing this fragment must + * implement. This mechanism allows activities to be notified of item + * selections. + */ + public interface Callbacks { + /** + * Callback for when an item has been selected. + */ + public void onItemSelected(String id); + } + + /** + * A dummy implementation of the {@link Callbacks} interface that does + * nothing. Used only when this fragment is not attached to an activity. + */ + private static Callbacks sDummyCallbacks = new Callbacks() { + @Override + public void onItemSelected(String id) { + } + }; + + /** + * Mandatory empty constructor for the fragment manager to instantiate the + * fragment (e.g. upon screen orientation changes). + */ + public ProviderListFragment() { + } + + @Override + public void onCreate(Bundle savedInstanceState) { + super.onCreate(savedInstanceState); + content_adapter = new ArrayAdapter( + getActivity(), + android.R.layout.simple_list_item_activated_2, + ProviderListContent.ITEMS) { + @Override + public View getView(int position, View convertView, ViewGroup parent){ + TwoLineListItem row; + if (convertView == null) { + LayoutInflater inflater = (LayoutInflater)getActivity().getApplicationContext().getSystemService(Context.LAYOUT_INFLATER_SERVICE); + row = (TwoLineListItem)inflater.inflate(android.R.layout.simple_list_item_2, null); + } else { + row = (TwoLineListItem)convertView; + } + ProviderListContent.ProviderItem data = ProviderListContent.ITEMS.get(position); + row.getText1().setText(data.domain); + row.getText2().setText(data.name); + + return row; + } + }; + setListAdapter(content_adapter); + } + + @Override + public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle bundle) { + return inflater.inflate(R.layout.provider_list_fragment, container, false); + } + + @Override + public void onViewCreated(View view, Bundle savedInstanceState) { + super.onViewCreated(view, savedInstanceState); + + // Restore the previously serialized activated item position. + if (savedInstanceState != null + && savedInstanceState.containsKey(STATE_ACTIVATED_POSITION)) { + setActivatedPosition(savedInstanceState.getInt(STATE_ACTIVATED_POSITION)); + } + } + + @Override + public void onAttach(Activity activity) { + super.onAttach(activity); + + // Activities containing this fragment must implement its callbacks. + if (!(activity instanceof Callbacks)) { + throw new IllegalStateException("Activity must implement fragment's callbacks."); + } + + mCallbacks = (Callbacks) activity; + } + + @Override + public void onDetach() { + super.onDetach(); + + // Reset the active callbacks interface to the dummy implementation. + mCallbacks = sDummyCallbacks; + } + + @Override + public void onListItemClick(ListView listView, View view, int position, long id) { + super.onListItemClick(listView, view, position, id); + + // Notify the active callbacks interface (the activity, if the + // fragment is attached to one) that an item has been selected. + mCallbacks.onItemSelected(ProviderListContent.ITEMS.get(position).id); + } + + @Override + public void onSaveInstanceState(Bundle outState) { + super.onSaveInstanceState(outState); + if (mActivatedPosition != ListView.INVALID_POSITION) { + // Serialize and persist the activated item position. + outState.putInt(STATE_ACTIVATED_POSITION, mActivatedPosition); + } + } + + /** + * Turns on activate-on-click mode. When this mode is on, list items will be + * given the 'activated' state when touched. + */ + public void setActivateOnItemClick(boolean activateOnItemClick) { + // When setting CHOICE_MODE_SINGLE, ListView will automatically + // give items the 'activated' state when touched. + getListView().setChoiceMode(activateOnItemClick + ? ListView.CHOICE_MODE_SINGLE + : ListView.CHOICE_MODE_NONE); + } + + private void setActivatedPosition(int position) { + if (position == ListView.INVALID_POSITION) { + getListView().setItemChecked(mActivatedPosition, false); + } else { + getListView().setItemChecked(position, true); + } + + mActivatedPosition = position; + } +} diff --git a/src/se/leap/leapclient/AboutFragment.java b/src/se/leap/leapclient/AboutFragment.java deleted file mode 100644 index 97cfb584..00000000 --- a/src/se/leap/leapclient/AboutFragment.java +++ /dev/null @@ -1,60 +0,0 @@ -package se.leap.leapclient; - -import android.app.Fragment; -import android.content.pm.PackageInfo; -import android.content.pm.PackageManager.NameNotFoundException; -import android.os.Bundle; -import android.text.Html; -import android.text.Spanned; -import android.text.method.LinkMovementMethod; -import android.view.LayoutInflater; -import android.view.View; -import android.view.ViewGroup; -import android.widget.TextView; -import se.leap.leapclient.R; - -public class AboutFragment extends Fragment { - - final public static String TAG = "aboutFragment"; - - public static Fragment newInstance() { - AboutFragment provider_detail_fragment = new AboutFragment(); - return provider_detail_fragment; - } - - @Override - public void onCreate(Bundle savedInstanceState) { - super.onCreate(savedInstanceState); - - } - - @Override - public View onCreateView(LayoutInflater inflater, ViewGroup container, - Bundle savedInstanceState) { - View v= inflater.inflate(R.layout.about, container, false); - TextView ver = (TextView) v.findViewById(R.id.version); - - String version; - String name="Openvpn"; - try { - PackageInfo packageinfo = getActivity().getPackageManager().getPackageInfo(getActivity().getPackageName(), 0); - version = packageinfo.versionName; - name = getString(R.string.app); - } catch (NameNotFoundException e) { - version = "error fetching version"; - } - - - ver.setText(getString(R.string.version_info,name,version)); - - TextView translation = (TextView) v.findViewById(R.id.translation); - - // Don't print a text for myself - if ( getString(R.string.translationby).contains("Arne Schwabe")) - translation.setText(""); - else - translation.setText(R.string.translationby); - return v; - } - -} diff --git a/src/se/leap/leapclient/ConfigHelper.java b/src/se/leap/leapclient/ConfigHelper.java deleted file mode 100644 index 14b29787..00000000 --- a/src/se/leap/leapclient/ConfigHelper.java +++ /dev/null @@ -1,317 +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 . - */ -package se.leap.leapclient; - -import java.io.ByteArrayInputStream; -import java.io.IOException; -import java.math.BigInteger; -import java.io.InputStream; -import java.security.KeyFactory; -import java.security.KeyStore; -import java.security.KeyStoreException; -import java.security.NoSuchAlgorithmException; -import java.security.NoSuchProviderException; -import java.security.cert.CertificateException; -import java.security.cert.CertificateFactory; -import java.security.cert.X509Certificate; -import java.security.interfaces.RSAPrivateKey; -import java.security.spec.InvalidKeySpecException; -import java.security.spec.PKCS8EncodedKeySpec; - -import org.json.JSONException; -import org.json.JSONObject; - -import android.content.Context; -import android.content.SharedPreferences; -import android.util.Base64; - -/** - * Stores constants, and implements auxiliary methods used across all LEAP Android classes. - * - * @author parmegv - * @author MeanderingCode - * - */ -public class ConfigHelper { - - public static SharedPreferences shared_preferences; - private static KeyStore keystore_trusted; - - final public static String NG_1024 = - "eeaf0ab9adb38dd69c33f80afa8fc5e86072618775ff3c0b9ea2314c9c256576d674df7496ea81d3383b4813d692c6e0e0d5d8e250b98be48e495c1d6089dad15dc7d7b46154d6b6ce8ef4ad69b15d4982559b297bcf1885c529f566660e57ec68edbc3c05726cc02fd4cbf4976eaa9afd5138fe8376435b9fc61d2fc0eb06e3"; - final public static BigInteger G = new BigInteger("2"); - - - private static boolean checkSharedPrefs() { - try { - shared_preferences = Dashboard.getAppContext().getSharedPreferences(Dashboard.SHARED_PREFERENCES,Context.MODE_PRIVATE); - } catch (Exception e) { - return false; - } - - return true; - } - - /** - * Saves a JSON object into class scope Shared Preferences - * @param shared_preferences_key - * @param content - */ - public static void saveSharedPref(String shared_preferences_key, JSONObject content) { - - SharedPreferences.Editor shared_preferences_editor = shared_preferences - .edit(); - shared_preferences_editor.putString(shared_preferences_key, - content.toString()); - shared_preferences_editor.commit(); - } - - /** - * Saves a String object into class scope Shared Preferences - * @param shared_preferences_key - * @param content - */ - public static void saveSharedPref(String shared_preferences_key, String content) { - - SharedPreferences.Editor shared_preferences_editor = shared_preferences - .edit(); - shared_preferences_editor.putString(shared_preferences_key, - content); - shared_preferences_editor.commit(); - } - - /** - * Saves a boolean object into class scope Shared Preferences - * @param shared_preferences_key - * @param content - */ - public static void saveSharedPref(String shared_preferences_key, boolean content) { - - SharedPreferences.Editor shared_preferences_editor = shared_preferences - .edit(); - shared_preferences_editor.putBoolean(shared_preferences_key, content); - shared_preferences_editor.commit(); - } - - /** - * Saves an int into class scope Shared Preferences - * - * @param shared_preferences_key - * @param value - */ - protected static void saveSharedPref(String shared_preferences_key, int value) { - SharedPreferences.Editor shared_preferences_editor = shared_preferences.edit(); - shared_preferences_editor.putInt(shared_preferences_key, value).commit(); - } - - /** - * Gets String object from class scope Shared Preferences - * @param shared_preferences_key - * @return the string correspondent to the key parameter - */ - public static String getStringFromSharedPref(String shared_preferences_key) { - String content = null; - content = shared_preferences.getString(shared_preferences_key, ""); - return content; - } - - /** - * Gets JSON object from class scope Shared Preferences - * @param shared_preferences_key - * @return the JSON object correspondent to the key parameter - */ - public static JSONObject getJsonFromSharedPref(String shared_preferences_key) throws JSONException { - JSONObject content = null; - if ( checkSharedPrefs() ) { - String json_string = shared_preferences.getString(shared_preferences_key, ""); - content = new JSONObject(json_string); - } - - return content; - } - - /* - * This method defaults to false. - * If you use this method, be sure to fail-closed on false! - * TODO This is obviously less than ideal...solve it! - */ - public static boolean getBoolFromSharedPref(String shared_preferences_key) { - boolean value = false; - if ( checkSharedPrefs() ) { - value = shared_preferences.getBoolean(shared_preferences_key, false); - } - return value; - } - - /** - * Get an int from SharedPreferences - * - * @param shared_preferences_key Key to retrieve - * @return The value for the key or 0 - */ - protected static int getIntFromSharedPref(String shared_preferences_key) { - return shared_preferences.getInt(shared_preferences_key, 0); - } - - /* - * This method defaults to false. - * If you use this method, be sure to fail-closed on false! - * TODO This is obviously less than ideal...solve it! - */ - public static boolean removeFromSharedPref(String shared_preferences_key) { - SharedPreferences.Editor shared_preferences_editor = shared_preferences - .edit(); - shared_preferences_editor.remove(shared_preferences_key); - return shared_preferences_editor.commit(); - } - - /** - * Treat the input as the MSB representation of a number, - * and lop off leading zero elements. For efficiency, the - * input is simply returned if no leading zeroes are found. - * - * @param in array to be trimmed - */ - public static byte[] trim(byte[] in) { - if(in.length == 0 || in[0] != 0) - return in; - - int len = in.length; - int i = 1; - while(in[i] == 0 && i < len) - ++i; - byte[] ret = new byte[len - i]; - System.arraycopy(in, i, ret, 0, len - i); - return ret; - } - - /** - * Sets class scope Shared Preferences - * @param shared_preferences - */ - public static void setSharedPreferences( - SharedPreferences shared_preferences) { - ConfigHelper.shared_preferences = shared_preferences; - } - - public static X509Certificate parseX509CertificateFromString(String certificate_string) { - java.security.cert.Certificate certificate = null; - CertificateFactory cf; - try { - cf = CertificateFactory.getInstance("X.509"); - - certificate_string = certificate_string.replaceFirst("-----BEGIN CERTIFICATE-----", "").replaceFirst("-----END CERTIFICATE-----", "").trim(); - byte[] cert_bytes = Base64.decode(certificate_string, Base64.DEFAULT); - InputStream caInput = new ByteArrayInputStream(cert_bytes); - try { - certificate = cf.generateCertificate(caInput); - System.out.println("ca=" + ((X509Certificate) certificate).getSubjectDN()); - } finally { - caInput.close(); - } - } catch (CertificateException e) { - // TODO Auto-generated catch block - e.printStackTrace(); - } catch (IOException e) { - return null; - } - - return (X509Certificate) certificate; - } - - protected static RSAPrivateKey parseRsaKeyFromString(String RsaKeyString) { - RSAPrivateKey key = null; - try { - KeyFactory kf = KeyFactory.getInstance("RSA", "BC"); - - RsaKeyString = RsaKeyString.replaceFirst("-----BEGIN RSA PRIVATE KEY-----", "").replaceFirst("-----END RSA PRIVATE KEY-----", ""); - PKCS8EncodedKeySpec keySpec = new PKCS8EncodedKeySpec( Base64.decode(RsaKeyString, Base64.DEFAULT) ); - key = (RSAPrivateKey) kf.generatePrivate(keySpec); - } catch (InvalidKeySpecException e) { - // TODO Auto-generated catch block - e.printStackTrace(); - return null; - } catch (NoSuchAlgorithmException e) { - // TODO Auto-generated catch block - e.printStackTrace(); - return null; - } catch (NoSuchProviderException e) { - // TODO Auto-generated catch block - e.printStackTrace(); - return null; - } - - return key; - } - - /** - * Adds a new X509 certificate given its input stream and its provider name - * @param provider used to store the certificate in the keystore - * @param inputStream from which X509 certificate must be generated. - */ - public static void addTrustedCertificate(String provider, InputStream inputStream) { - CertificateFactory cf; - try { - cf = CertificateFactory.getInstance("X.509"); - X509Certificate cert = - (X509Certificate)cf.generateCertificate(inputStream); - keystore_trusted.setCertificateEntry(provider, cert); - } catch (CertificateException e) { - // TODO Auto-generated catch block - e.printStackTrace(); - } catch (KeyStoreException e) { - // TODO Auto-generated catch block - e.printStackTrace(); - } - } - - /** - * Adds a new X509 certificate given in its string from and using its provider name - * @param provider used to store the certificate in the keystore - * @param certificate - */ - public static void addTrustedCertificate(String provider, String certificate) { - - try { - X509Certificate cert = ConfigHelper.parseX509CertificateFromString(certificate); - if(keystore_trusted == null) { - keystore_trusted = KeyStore.getInstance("BKS"); - keystore_trusted.load(null); - } - keystore_trusted.setCertificateEntry(provider, cert); - } catch (KeyStoreException e) { - // TODO Auto-generated catch block - e.printStackTrace(); - } catch (NoSuchAlgorithmException e) { - // TODO Auto-generated catch block - e.printStackTrace(); - } catch (CertificateException e) { - // TODO Auto-generated catch block - e.printStackTrace(); - } catch (IOException e) { - // TODO Auto-generated catch block - e.printStackTrace(); - } - } - - /** - * @return class wide keystore - */ - public static KeyStore getKeystore() { - return keystore_trusted; - } -} diff --git a/src/se/leap/leapclient/ConfigurationWizard.java b/src/se/leap/leapclient/ConfigurationWizard.java deleted file mode 100644 index dd9f4121..00000000 --- a/src/se/leap/leapclient/ConfigurationWizard.java +++ /dev/null @@ -1,418 +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 . - */ - package se.leap.leapclient; - -import java.io.IOException; -import java.util.Iterator; - -import org.json.JSONException; -import org.json.JSONObject; - -import se.leap.leapclient.ProviderAPIResultReceiver.Receiver; -import se.leap.leapclient.ProviderListContent.ProviderItem; -import se.leap.leapclient.R; -import android.app.Activity; -import android.app.DialogFragment; -import android.app.Fragment; -import android.app.FragmentManager; -import android.app.FragmentTransaction; -import android.app.ProgressDialog; -import android.content.Intent; -import android.content.res.AssetManager; -import android.os.Bundle; -import android.os.Handler; -import android.view.Menu; -import android.view.MenuItem; -import android.view.View; - -/** - * Activity that builds and shows the list of known available providers. - * - * It also allows the user to enter custom providers with a button. - * - * @author parmegv - * - */ -public class ConfigurationWizard extends Activity -implements ProviderListFragment.Callbacks, NewProviderDialog.NewProviderDialogInterface, ProviderDetailFragment.ProviderDetailFragmentInterface, Receiver { - - private ProviderItem mSelectedProvider; - private ProgressDialog mProgressDialog; - private Intent mConfigState = new Intent(); - - final public static String TYPE_OF_CERTIFICATE = "type_of_certificate"; - final public static String ANON_CERTIFICATE = "anon_certificate"; - final public static String AUTHED_CERTIFICATE = "authed_certificate"; - - final protected static String PROVIDER_SET = "PROVIDER SET"; - final protected static String SERVICES_RETRIEVED = "SERVICES RETRIEVED"; - - public ProviderAPIResultReceiver providerAPI_result_receiver; - - @Override - protected void onCreate(Bundle savedInstanceState) { - super.onCreate(savedInstanceState); - - setContentView(R.layout.configuration_wizard_activity); - - providerAPI_result_receiver = new ProviderAPIResultReceiver(new Handler()); - providerAPI_result_receiver.setReceiver(this); - - ConfigHelper.setSharedPreferences(getSharedPreferences(Dashboard.SHARED_PREFERENCES, MODE_PRIVATE)); - - loadPreseededProviders(); - - // Only create our fragments if we're not restoring a saved instance - if ( savedInstanceState == null ){ - // TODO Some welcome screen? - // We will need better flow control when we have more Fragments (e.g. user auth) - ProviderListFragment providerList = new ProviderListFragment(); - - FragmentManager fragmentManager = getFragmentManager(); - fragmentManager.beginTransaction() - .add(R.id.configuration_wizard_layout, providerList, "providerlist") - .commit(); - } - - // TODO: If exposing deep links into your app, handle intents here. - } - - @Override - public void onReceiveResult(int resultCode, Bundle resultData) { - if(resultCode == ProviderAPI.CORRECTLY_UPDATED_PROVIDER_DOT_JSON) { - JSONObject provider_json; - try { - provider_json = new JSONObject(resultData.getString(Provider.KEY)); - boolean danger_on = resultData.getBoolean(ProviderItem.DANGER_ON); - ConfigHelper.saveSharedPref(Provider.KEY, provider_json); - ConfigHelper.saveSharedPref(ProviderItem.DANGER_ON, danger_on); - ConfigHelper.saveSharedPref(EIP.ALLOWED_ANON, provider_json.getJSONObject(Provider.SERVICE).getBoolean(EIP.ALLOWED_ANON)); - mConfigState.setAction(PROVIDER_SET); - - if(mProgressDialog != null) mProgressDialog.dismiss(); - mProgressDialog = ProgressDialog.show(this, getResources().getString(R.string.config_wait_title), getResources().getString(R.string.config_connecting_provider), true); - mProgressDialog.setMessage(getResources().getString(R.string.config_downloading_services)); - if(resultData.containsKey(Provider.NAME)) - mSelectedProvider = getProvider(resultData.getString(Provider.NAME)); - - ProviderListFragment providerList = new ProviderListFragment(); - - FragmentManager fragmentManager = getFragmentManager(); - fragmentManager.beginTransaction() - .replace(R.id.configuration_wizard_layout, providerList, "providerlist") - .commit(); - downloadJSONFiles(mSelectedProvider); - } catch (JSONException e) { - // TODO Auto-generated catch block - e.printStackTrace(); - - mProgressDialog.dismiss(); - //Toast.makeText(this, getResources().getString(R.string.config_error_parsing), Toast.LENGTH_LONG); - setResult(RESULT_CANCELED, mConfigState); - } - } - else if(resultCode == ProviderAPI.INCORRECTLY_UPDATED_PROVIDER_DOT_JSON) { - mProgressDialog.dismiss(); - setResult(RESULT_CANCELED, mConfigState); - } - else if(resultCode == ProviderAPI.CORRECTLY_DOWNLOADED_JSON_FILES) { - if (ConfigHelper.getBoolFromSharedPref(EIP.ALLOWED_ANON)){ - mProgressDialog.setMessage(getResources().getString(R.string.config_downloading_certificates)); - mConfigState.putExtra(SERVICES_RETRIEVED, true); - downloadAnonCert(); - } else { - mProgressDialog.dismiss(); - //Toast.makeText(getApplicationContext(), R.string.success, Toast.LENGTH_LONG).show(); - setResult(RESULT_OK); - finish(); - } - } - else if(resultCode == ProviderAPI.INCORRECTLY_DOWNLOADED_JSON_FILES) { - //Toast.makeText(getApplicationContext(), R.string.incorrectly_downloaded_json_files_message, Toast.LENGTH_LONG).show(); - mProgressDialog.dismiss(); - setResult(RESULT_CANCELED, mConfigState); - } - else if(resultCode == ProviderAPI.CORRECTLY_DOWNLOADED_CERTIFICATE) { - mProgressDialog.dismiss(); - setResult(RESULT_OK); - showProviderDetails(getCurrentFocus()); - } else if(resultCode == ProviderAPI.INCORRECTLY_DOWNLOADED_CERTIFICATE) { - mProgressDialog.dismiss(); - //Toast.makeText(getApplicationContext(), R.string.incorrectly_downloaded_certificate_message, Toast.LENGTH_LONG).show(); - setResult(RESULT_CANCELED, mConfigState); - } - } - - /** - * Callback method from {@link ProviderListFragment.Callbacks} - * indicating that the item with the given ID was selected. - */ - @Override - public void onItemSelected(String id) { - //TODO Code 2 pane view - ProviderItem selected_provider = getProvider(id); - mProgressDialog = ProgressDialog.show(this, getResources().getString(R.string.config_wait_title), getResources().getString(R.string.config_connecting_provider), true); - mSelectedProvider = selected_provider; - saveProviderJson(mSelectedProvider); - } - - @Override - public void onBackPressed() { - try { - if(ConfigHelper.getJsonFromSharedPref(Provider.KEY) == null || ConfigHelper.getJsonFromSharedPref(Provider.KEY).length() == 0) { - askDashboardToQuitApp(); - } else { - setResult(RESULT_OK); - } - } catch (JSONException e) { - askDashboardToQuitApp(); - } - super.onBackPressed(); - } - - private void askDashboardToQuitApp() { - Intent ask_quit = new Intent(); - ask_quit.putExtra(Dashboard.ACTION_QUIT, Dashboard.ACTION_QUIT); - setResult(RESULT_CANCELED, ask_quit); - } - - private ProviderItem getProvider(String id) { - Iterator providers_iterator = ProviderListContent.ITEMS.iterator(); - while(providers_iterator.hasNext()) { - ProviderItem provider = providers_iterator.next(); - if(provider.id.equalsIgnoreCase(id)) { - return provider; - } - } - return null; - } - - /** - * Loads providers data from url file contained in the project - * @return true if the file was read correctly - */ - private boolean loadPreseededProviders() { - boolean loaded_preseeded_providers = false; - AssetManager asset_manager = getAssets(); - String[] urls_filepaths = null; - try { - String url_files_folder = "urls"; - //TODO Put that folder in a better place (also inside the "for") - urls_filepaths = asset_manager.list(url_files_folder); - String provider_name = ""; - for(String url_filepath : urls_filepaths) - { - boolean custom = false; - provider_name = url_filepath.subSequence(0, url_filepath.indexOf(".")).toString(); - if(ProviderListContent.ITEMS.isEmpty()) //TODO I have to implement a way of checking if a provider new or is already present in that ITEMS list - ProviderListContent.addItem(new ProviderItem(provider_name, asset_manager.open(url_files_folder + "/" + url_filepath), custom, false)); - loaded_preseeded_providers = true; - } - } catch (IOException e) { - loaded_preseeded_providers = false; - } - - return loaded_preseeded_providers; - } - - /** - * Saves provider.json file associated with provider. - * - * If the provider is custom, the file has already been downloaded so we load it from memory. - * If not, the file is updated using the provider's URL. - * @param provider - */ - private void saveProviderJson(ProviderItem provider) { - JSONObject provider_json = new JSONObject(); - try { - if(!provider.custom) { - updateProviderDotJson(provider.name, provider.provider_json_url, provider.danger_on); - } else { - // FIXME!! We should we be updating our seeded providers list at ConfigurationWizard onStart() ? - // I think yes, but if so, where does this list live? leap.se, as it's the non-profit project for the software? - // If not, we should just be getting names/urls, and fetching the provider.json like in custom entries - provider_json = provider.provider_json; - ConfigHelper.saveSharedPref(Provider.KEY, provider_json); - ConfigHelper.saveSharedPref(EIP.ALLOWED_ANON, provider_json.getJSONObject(Provider.SERVICE).getBoolean(EIP.ALLOWED_ANON)); - ConfigHelper.saveSharedPref(ProviderItem.DANGER_ON, provider.danger_on); - - mProgressDialog.setMessage(getResources().getString(R.string.config_downloading_services)); - downloadJSONFiles(mSelectedProvider); - } - } catch (JSONException e) { - setResult(RESULT_CANCELED); - finish(); - } - } - - /** - * Asks ProviderAPI to download provider site's certificate and eip-service.json - * - * URLs are fetched from the provider parameter - * @param provider from which certificate and eip-service.json files are going to be downloaded - */ - private void downloadJSONFiles(ProviderItem provider) { - Intent provider_API_command = new Intent(this, ProviderAPI.class); - - Bundle parameters = new Bundle(); - - parameters.putString(Provider.KEY, provider.name); - parameters.putString(Provider.CA_CERT, provider.cert_json_url); - parameters.putString(EIP.KEY, provider.eip_service_json_url); - parameters.putBoolean(ProviderItem.DANGER_ON, provider.danger_on); - - provider_API_command.setAction(ProviderAPI.DOWNLOAD_JSON_FILES_BUNDLE_EXTRA); - provider_API_command.putExtra(ProviderAPI.PARAMETERS, parameters); - provider_API_command.putExtra(ProviderAPI.RECEIVER_KEY, providerAPI_result_receiver); - - startService(provider_API_command); - } - - /** - * Asks ProviderAPI to download an anonymous (anon) VPN certificate. - */ - private void downloadAnonCert() { - Intent provider_API_command = new Intent(this, ProviderAPI.class); - - Bundle parameters = new Bundle(); - - parameters.putString(TYPE_OF_CERTIFICATE, ANON_CERTIFICATE); - - provider_API_command.setAction(ProviderAPI.DOWNLOAD_CERTIFICATE); - provider_API_command.putExtra(ProviderAPI.PARAMETERS, parameters); - provider_API_command.putExtra(ProviderAPI.RECEIVER_KEY, providerAPI_result_receiver); - - startService(provider_API_command); - } - - /** - * Open the new provider dialog - * @param view from which the dialog is showed - */ - public void addAndSelectNewProvider(View view) { - FragmentTransaction fragment_transaction = getFragmentManager().beginTransaction(); - Fragment previous_new_provider_dialog = getFragmentManager().findFragmentByTag(NewProviderDialog.TAG); - if (previous_new_provider_dialog != null) { - fragment_transaction.remove(previous_new_provider_dialog); - } - fragment_transaction.addToBackStack(null); - - DialogFragment newFragment = NewProviderDialog.newInstance(); - newFragment.show(fragment_transaction, NewProviderDialog.TAG); - } - - /** - * Once selected a provider, this fragment offers the user to log in, - * use it anonymously (if possible) - * or cancel his/her election pressing the back button. - * @param view - */ - public void showProviderDetails(View view) { - FragmentTransaction fragment_transaction = getFragmentManager().beginTransaction(); - Fragment previous_provider_details_dialog = getFragmentManager().findFragmentByTag(ProviderDetailFragment.TAG); - if (previous_provider_details_dialog != null) { - fragment_transaction.remove(previous_provider_details_dialog); - } - fragment_transaction.addToBackStack(null); - - DialogFragment newFragment = ProviderDetailFragment.newInstance(); - newFragment.show(fragment_transaction, ProviderDetailFragment.TAG); - } - - @Override - public void saveAndSelectProvider(String provider_main_url, boolean danger_on) { - Intent provider_API_command = new Intent(this, ProviderAPI.class); - - Bundle parameters = new Bundle(); - parameters.putString(Provider.MAIN_URL, provider_main_url); - parameters.putBoolean(ProviderItem.DANGER_ON, danger_on); - - provider_API_command.setAction(ProviderAPI.DOWNLOAD_NEW_PROVIDER_DOTJSON); - provider_API_command.putExtra(ProviderAPI.PARAMETERS, parameters); - provider_API_command.putExtra(ProviderAPI.RECEIVER_KEY, providerAPI_result_receiver); - - startService(provider_API_command); - } - - /** - * Asks ProviderAPI to download a new provider.json file - * @param provider_name - * @param provider_json_url - * @param danger_on tells if HTTPS client should bypass certificate errors - */ - public void updateProviderDotJson(String provider_name, String provider_json_url, boolean danger_on) { - Intent provider_API_command = new Intent(this, ProviderAPI.class); - - Bundle parameters = new Bundle(); - parameters.putString(Provider.NAME, provider_name); - parameters.putString(Provider.DOT_JSON_URL, provider_json_url); - parameters.putBoolean(ProviderItem.DANGER_ON, danger_on); - - provider_API_command.setAction(ProviderAPI.UPDATE_PROVIDER_DOTJSON); - provider_API_command.putExtra(ProviderAPI.PARAMETERS, parameters); - provider_API_command.putExtra(ProviderAPI.RECEIVER_KEY, providerAPI_result_receiver); - - startService(provider_API_command); - } - - @Override - public boolean onCreateOptionsMenu(Menu menu) { - getMenuInflater().inflate(R.menu.configuration_wizard_activity, menu); - return true; - } - - @Override - public boolean onOptionsItemSelected(MenuItem item){ - switch (item.getItemId()){ - case R.id.about_leap: - showAboutFragment(getCurrentFocus()); - default: - return super.onOptionsItemSelected(item); - } - } - - /** - * Once selected a provider, this fragment offers the user to log in, - * use it anonymously (if possible) - * or cancel his/her election pressing the back button. - * @param view - */ - public void showAboutFragment(View view) { - FragmentTransaction fragment_transaction = getFragmentManager().beginTransaction(); - Fragment previous_about_fragment = getFragmentManager().findFragmentByTag(AboutFragment.TAG); - if (previous_about_fragment == null) { - fragment_transaction.addToBackStack(null); - - Fragment newFragment = AboutFragment.newInstance(); - fragment_transaction.replace(R.id.configuration_wizard_layout, newFragment, AboutFragment.TAG).commit(); - } - } - - @Override - public void login() { - Intent ask_login = new Intent(); - ask_login.putExtra(LogInDialog.VERB, LogInDialog.VERB); - setResult(RESULT_OK, ask_login); - finish(); - } - - @Override - public void use_anonymously() { - setResult(RESULT_OK); - finish(); - } -} diff --git a/src/se/leap/leapclient/Dashboard.java b/src/se/leap/leapclient/Dashboard.java deleted file mode 100644 index 19d33a12..00000000 --- a/src/se/leap/leapclient/Dashboard.java +++ /dev/null @@ -1,353 +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 . - */ - package se.leap.leapclient; - -import org.apache.http.cookie.Cookie; -import org.apache.http.impl.cookie.BasicClientCookie; -import org.json.JSONException; -import org.json.JSONObject; - -import se.leap.leapclient.ProviderAPIResultReceiver.Receiver; -import se.leap.openvpn.MainActivity; -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.app.ProgressDialog; -import android.content.Context; -import android.content.DialogInterface; -import android.content.Intent; -import android.content.SharedPreferences; -import android.os.Bundle; -import android.os.Handler; -import android.view.Menu; -import android.view.MenuItem; -import android.view.View; -import android.view.ViewGroup; -import android.widget.TextView; -import android.widget.Toast; - -/** - * The main user facing Activity of LEAP Android, consisting of status, controls, - * and access to preferences. - * - * @author Sean Leonard - */ -public class Dashboard extends Activity implements LogInDialog.LogInDialogInterface,Receiver { - - protected static final int CONFIGURE_LEAP = 0; - - private static final String TAG_EIP_FRAGMENT = "EIP_DASHBOARD_FRAGMENT"; - final public static String SHARED_PREFERENCES = "LEAPPreferences"; - final public static String ACTION_QUIT = "quit"; - - private ProgressDialog mProgressDialog; - - private static Context app; - private static SharedPreferences preferences; - private static Provider provider; - - private TextView providerNameTV; - - private boolean authed = false; - - public ProviderAPIResultReceiver providerAPI_result_receiver; - - @Override - protected void onCreate(Bundle savedInstanceState) { - super.onCreate(savedInstanceState); - - app = this; - - ConfigHelper.setSharedPreferences(getSharedPreferences(SHARED_PREFERENCES, MODE_PRIVATE)); - preferences = ConfigHelper.shared_preferences; - - if (ConfigHelper.getStringFromSharedPref(Provider.KEY).isEmpty()) - startActivityForResult(new Intent(this,ConfigurationWizard.class),CONFIGURE_LEAP); - else - buildDashboard(); - } - - @Override - protected void onActivityResult(int requestCode, int resultCode, Intent data){ - if ( requestCode == CONFIGURE_LEAP ) { - if ( resultCode == RESULT_OK ){ - startService( new Intent(EIP.ACTION_UPDATE_EIP_SERVICE) ); - buildDashboard(); - if(data != null && data.hasExtra(LogInDialog.VERB)) { - View view = ((ViewGroup)findViewById(android.R.id.content)).getChildAt(0); - logInDialog(view, Bundle.EMPTY); - } - } else if(resultCode == RESULT_CANCELED && data.hasExtra(ACTION_QUIT)) { - finish(); - } else - configErrorDialog(); - } - } - - /** - * Dialog shown when encountering a configuration error. Such errors require - * reconfiguring LEAP or aborting the application. - */ - private void configErrorDialog() { - AlertDialog.Builder alertBuilder = new AlertDialog.Builder(getAppContext()); - alertBuilder.setTitle(getResources().getString(R.string.setup_error_title)); - alertBuilder - .setMessage(getResources().getString(R.string.setup_error_text)) - .setCancelable(false) - .setPositiveButton(getResources().getString(R.string.setup_error_configure_button), new DialogInterface.OnClickListener() { - @Override - public void onClick(DialogInterface dialog, int which) { - startActivityForResult(new Intent(getAppContext(),ConfigurationWizard.class),CONFIGURE_LEAP); - } - }) - .setNegativeButton(getResources().getString(R.string.setup_error_close_button), new DialogInterface.OnClickListener() { - @Override - public void onClick(DialogInterface dialog, int which) { - SharedPreferences.Editor prefsEdit = getSharedPreferences(SHARED_PREFERENCES, MODE_PRIVATE).edit(); - prefsEdit.remove(Provider.KEY).commit(); - finish(); - } - }) - .show(); - } - - /** - * Inflates permanent UI elements of the View and contains logic for what - * service dependent UI elements to include. - */ - private void buildDashboard() { - provider = Provider.getInstance(); - provider.init( this ); - - setContentView(R.layout.client_dashboard); - - providerNameTV = (TextView) findViewById(R.id.providerName); - providerNameTV.setText(provider.getDomain()); - providerNameTV.setTextSize(28); - - FragmentManager fragMan = getFragmentManager(); - if ( provider.hasEIP()){ - EipServiceFragment eipFragment = new EipServiceFragment(); - fragMan.beginTransaction().replace(R.id.servicesCollection, eipFragment, TAG_EIP_FRAGMENT).commit(); - } - } - - @Override - public boolean onPrepareOptionsMenu(Menu menu) { - JSONObject provider_json; - try { - provider_json = ConfigHelper.getJsonFromSharedPref(Provider.KEY); - JSONObject service_description = provider_json.getJSONObject(Provider.SERVICE); - if(service_description.getBoolean(Provider.ALLOW_REGISTRATION)) { - if(authed) { - 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); - } - } - } catch (JSONException e) { - // TODO Auto-generated catch block - e.printStackTrace(); - } - return true; - } - - @Override - public boolean onCreateOptionsMenu(Menu menu) { - getMenuInflater().inflate(R.menu.client_dashboard, menu); - return true; - } - - @Override - public boolean onOptionsItemSelected(MenuItem item){ - Intent intent; - switch (item.getItemId()){ - case R.id.about_leap: - Fragment aboutFragment = new AboutFragment(); - FragmentTransaction trans = getFragmentManager().beginTransaction(); - trans.replace(R.id.dashboardLayout, aboutFragment); - trans.addToBackStack(null); - trans.commit(); - return true; - case R.id.legacy_interface: - intent = new Intent(this,MainActivity.class); - startActivity(intent); - return true; - case R.id.switch_provider: - startActivityForResult(new Intent(this,ConfigurationWizard.class),CONFIGURE_LEAP); - return true; - case R.id.login_button: - View view = ((ViewGroup)findViewById(android.R.id.content)).getChildAt(0); - logInDialog(view, Bundle.EMPTY); - return true; - case R.id.logout_button: - logOut(); - return true; - default: - return super.onOptionsItemSelected(item); - } - - } - - @Override - public void authenticate(String username, String password) { - 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(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(); - } - - provider_API_command.setAction(ProviderAPI.SRP_AUTH); - provider_API_command.putExtra(ProviderAPI.PARAMETERS, parameters); - provider_API_command.putExtra(ProviderAPI.RECEIVER_KEY, providerAPI_result_receiver); - - if(mProgressDialog != null) mProgressDialog.dismiss(); - mProgressDialog = ProgressDialog.show(this, getResources().getString(R.string.authenticating_title), getResources().getString(R.string.authenticating_message), true); - startService(provider_API_command); - } - - /** - * 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(mProgressDialog != null) mProgressDialog.dismiss(); - mProgressDialog = ProgressDialog.show(this, getResources().getString(R.string.logout_title), getResources().getString(R.string.logout_message), true); - startService(provider_API_command); - } - - /** - * Shows the log in dialog. - * @param view from which the dialog is created. - */ - public void logInDialog(View view, Bundle resultData) { - 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); - } - - /** - * 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*/) { - 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(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); - provider_API_command.putExtra(ProviderAPI.RECEIVER_KEY, providerAPI_result_receiver); - - startService(provider_API_command); - } - - @Override - public void onReceiveResult(int resultCode, Bundle resultData) { - 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 = true; - invalidateOptionsMenu(); - - //Cookie session_id = new BasicClientCookie(session_id_cookie_key, session_id_string); - downloadAuthedUserCertificate(/*session_id*/); - } else if(resultCode == ProviderAPI.SRP_AUTHENTICATION_FAILED) { - mProgressDialog.dismiss(); - logInDialog(getCurrentFocus(), resultData); - } else if(resultCode == ProviderAPI.LOGOUT_SUCCESSFUL) { - authed = false; - invalidateOptionsMenu(); - setResult(RESULT_OK); - mProgressDialog.dismiss(); - } else if(resultCode == ProviderAPI.LOGOUT_FAILED) { - setResult(RESULT_CANCELED); - mProgressDialog.dismiss(); - Toast.makeText(getApplicationContext(), R.string.log_out_failed_message, Toast.LENGTH_LONG).show(); - } else if(resultCode == ProviderAPI.CORRECTLY_DOWNLOADED_CERTIFICATE) { - setResult(RESULT_OK); - mProgressDialog.dismiss(); - Toast.makeText(getApplicationContext(), R.string.successful_authed_cert_downloaded_message, Toast.LENGTH_LONG).show(); - } else if(resultCode == ProviderAPI.INCORRECTLY_DOWNLOADED_CERTIFICATE) { - setResult(RESULT_CANCELED); - mProgressDialog.dismiss(); - Toast.makeText(getApplicationContext(), R.string.authed_cert_download_failed_message, Toast.LENGTH_LONG).show(); - } - } - - /** - * For retrieving the base application Context in classes that don't extend - * Android's Activity class - * - * @return Application Context as defined by this for Dashboard instance - */ - public static Context getAppContext() { - return app; - } - -} diff --git a/src/se/leap/leapclient/EIP.java b/src/se/leap/leapclient/EIP.java deleted file mode 100644 index 0a537b4d..00000000 --- a/src/se/leap/leapclient/EIP.java +++ /dev/null @@ -1,519 +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 . - */ - package se.leap.leapclient; - -import java.util.Collection; -import java.util.HashMap; -import java.util.Iterator; -import java.util.NoSuchElementException; -import java.util.Vector; - -import org.json.JSONArray; -import org.json.JSONException; -import org.json.JSONObject; - -import se.leap.openvpn.ConfigParser; -import se.leap.openvpn.ConfigParser.ConfigParseError; -import se.leap.openvpn.LaunchVPN; -import se.leap.openvpn.OpenVpnManagementThread; -import se.leap.openvpn.OpenVpnService; -import se.leap.openvpn.OpenVpnService.LocalBinder; -import se.leap.openvpn.ProfileManager; -import se.leap.openvpn.VpnProfile; - -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.os.Bundle; -import android.os.IBinder; -import android.os.ResultReceiver; -import android.util.Log; - -/** - * EIP is the abstract base class for interacting with and managing the Encrypted - * Internet Proxy connection. Connections are started, stopped, and queried through - * this IntentService. - * Contains logic for parsing eip-service.json from the provider, configuring and selecting - * gateways, and controlling {@link .openvpn.OpenVpnService} connections. - * - * @author Sean Leonard - */ -public final class EIP extends IntentService { - - public final static String ACTION_START_EIP = "se.leap.leapclient.START_EIP"; - public final static String ACTION_STOP_EIP = "se.leap.leapclient.STOP_EIP"; - public final static String ACTION_UPDATE_EIP_SERVICE = "se.leap.leapclient.UPDATE_EIP_SERVICE"; - public final static String ACTION_IS_EIP_RUNNING = "se.leap.leapclient.IS_RUNNING"; - public final static String EIP_NOTIFICATION = "EIP_NOTIFICATION"; - public final static String ALLOWED_ANON = "allow_anonymous"; - public final static String CERTIFICATE = "cert"; - public final static String PRIVATE_KEY = "private_key"; - public final static String KEY = "eip"; - public final static String PARSED_SERIAL = "eip_parsed_serial"; - 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"; - - private static Context context; - private static ResultReceiver mReceiver; - private static OpenVpnService mVpnService; - 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; - - public EIP(){ - super("LEAPEIP"); - } - - @Override - public void onCreate() { - super.onCreate(); - - context = getApplicationContext(); - - try { - eipDefinition = ConfigHelper.getJsonFromSharedPref(KEY); - parsedEipSerial = ConfigHelper.getIntFromSharedPref(PARSED_SERIAL); - } catch (JSONException e) { - // TODO Auto-generated catch block - e.printStackTrace(); - } - - this.retreiveVpnService(); - } - - @Override - public void onDestroy() { - unbindService(mVpnServiceConn); - mBound = false; - - super.onDestroy(); - } - - @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(); - } - - /** - * Sends an Intent to bind OpenVpnService. - * Used when OpenVpnService isn't bound but might be running. - */ - private void retreiveVpnService() { - Intent bindIntent = new Intent(this,OpenVpnService.class); - bindIntent.setAction(OpenVpnService.RETRIEVE_SERVICE); - bindService(bindIntent, mVpnServiceConn, 0); - } - - private static ServiceConnection mVpnServiceConn = new ServiceConnection() { - - @Override - public void onServiceConnected(ComponentName name, IBinder service) { - LocalBinder binder = (LocalBinder) service; - mVpnService = binder.getService(); - mBound = true; - - if (mReceiver != null && mPending != null) { - - boolean running = mVpnService.isRunning(); - int resultCode = Activity.RESULT_CANCELED; - - if (mPending.equals(ACTION_IS_EIP_RUNNING)) - resultCode = (running) ? Activity.RESULT_OK : Activity.RESULT_CANCELED; - if (mPending.equals(ACTION_START_EIP)) - resultCode = (running) ? Activity.RESULT_OK : Activity.RESULT_CANCELED; - else if (mPending.equals(ACTION_STOP_EIP)) - resultCode = (running) ? Activity.RESULT_CANCELED - : Activity.RESULT_OK; - Bundle resultData = new Bundle(); - resultData.putString(REQUEST_TAG, EIP_NOTIFICATION); - mReceiver.send(resultCode, resultData); - - mPending = null; - } - } - - @Override - public void onServiceDisconnected(ComponentName name) { - mBound = false; - - if (mReceiver != null){ - Bundle resultData = new Bundle(); - resultData.putString(REQUEST_TAG, EIP_NOTIFICATION); - mReceiver.send(Activity.RESULT_CANCELED, resultData); - } - } - - }; - - /** - * Attempts to determine if OpenVpnService has an established VPN connection - * through the bound ServiceConnection. If there is no bound service, this - * method will attempt to bind a running OpenVpnService and send - * Activity.RESULT_CANCELED to the ResultReceiver that made the - * request. - * Note: If the request to bind OpenVpnService is successful, the ResultReceiver - * will be notified in {@link onServiceConnected()} - */ - private void isRunning() { - Bundle resultData = new Bundle(); - resultData.putString(REQUEST_TAG, ACTION_IS_EIP_RUNNING); - int resultCode = Activity.RESULT_CANCELED; - if (mBound) { - resultCode = (mVpnService.isRunning()) ? Activity.RESULT_OK : Activity.RESULT_CANCELED; - } else { - mPending = ACTION_IS_EIP_RUNNING; - this.retreiveVpnService(); - } - - if (mReceiver != null){ - mReceiver.send(resultCode, resultData); - } - } - - /** - * Initiates an EIP connection by selecting a gateway and preparing and sending an - * Intent to {@link se.leap.openvpn.LaunchVPN} - */ - private void startEIP() { - if (activeGateway==null) - activeGateway = selectGateway(); - - Intent intent = new Intent(this,LaunchVPN.class); - intent.setAction(Intent.ACTION_MAIN); - intent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK); - intent.putExtra(LaunchVPN.EXTRA_KEY, activeGateway.mVpnProfile.getUUID().toString() ); - intent.putExtra(LaunchVPN.EXTRA_NAME, activeGateway.mVpnProfile.getName() ); - 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 (mBound) - mVpnService.onRevoke(); - else - OpenVpnManagementThread.stopOpenVPN(); - - if (mReceiver != null){ - Bundle resultData = new Bundle(); - resultData.putString(REQUEST_TAG, ACTION_STOP_EIP); - mReceiver.send(Activity.RESULT_OK, resultData); - } - } - - /** - * Loads eip-service.json from SharedPreferences and calls {@link updateGateways()} - * to parse gateway definitions. - * TODO Implement API call to refresh eip-service.json from the provider - */ - private void updateEIPService() { - try { - eipDefinition = ConfigHelper.getJsonFromSharedPref(EIP.KEY); - } catch (JSONException e) { - // TODO Auto-generated catch block - e.printStackTrace(); - } - if (eipDefinition.optInt("serial") > parsedEipSerial) - updateGateways(); - } - - /** - * Choose a gateway to connect to based on timezone from system locale data - * - * @return The gateway to connect to - */ - private OVPNGateway selectGateway() { - // TODO Implement gateway selection logic based on TZ or preferences - // TODO Implement search through gateways loaded from SharedPreferences - // TODO Remove String arg constructor in favor of findGatewayByName(String) - return new OVPNGateway("first"); - } - - /** - * Walk the list of gateways defined in eip-service.json and parse them into - * OVPNGateway objects. - * TODO Store the OVPNGateways (as Serializable) in SharedPreferences - */ - private void updateGateways(){ - JSONArray gatewaysDefined = null; - - try { - gatewaysDefined = eipDefinition.getJSONArray("gateways"); - } catch (JSONException e1) { - // TODO Auto-generated catch block - e1.printStackTrace(); - } - - for ( int i=0 ; i < gatewaysDefined.length(); i++ ){ - - JSONObject gw = null; - - try { - gw = gatewaysDefined.getJSONObject(i); - } catch (JSONException e) { - // TODO Auto-generated catch block - e.printStackTrace(); - } - - try { - if ( gw.getJSONObject("capabilities").getJSONArray("transport").toString().contains("openvpn") ){ - new OVPNGateway(gw); - } - } catch (JSONException e) { - // TODO Auto-generated catch block - e.printStackTrace(); - } - } - - ConfigHelper.saveSharedPref(PARSED_SERIAL, eipDefinition.optInt(Provider.API_RETURN_SERIAL)); - } - - /** - * OVPNGateway provides objects defining gateways and their options and metadata. - * Each instance contains a VpnProfile for OpenVPN specific data and member - * variables describing capabilities and location - * - * @author Sean Leonard - */ - private class OVPNGateway { - - private String TAG = "OVPNGateway"; - - private String mName; - private VpnProfile mVpnProfile; - private JSONObject mGateway; - private HashMap>> options = new HashMap>>(); - - - /** - * Attempts to retrieve a VpnProfile by name and build an OVPNGateway around it. - * FIXME This needs to become a findGatewayByName() method - * - * @param name The hostname of the gateway to inflate - */ - private OVPNGateway(String name){ - mName = name; - - this.loadVpnProfile(); - } - - private void loadVpnProfile() { - ProfileManager vpl = ProfileManager.getInstance(context); - - try { - if ( mName == "first" ) { - mName = vpl.getProfiles().iterator().next().mName; - } - - mVpnProfile = vpl.getProfileByName(mName); - - } catch (NoSuchElementException e) { - updateEIPService(); - this.loadVpnProfile(); // FIXME catch infinite loops - } catch (Exception e) { - // TODO Auto-generated catch block - e.printStackTrace(); - } - } - - /** - * Build a gateway object from a JSON OpenVPN gateway definition in eip-service.json - * and create a VpnProfile belonging to it. - * - * @param gateway The JSON OpenVPN gateway definition to parse - */ - protected OVPNGateway(JSONObject gateway){ - - mGateway = gateway; - - // Currently deletes VpnProfile for host, if there already is one, and builds new - ProfileManager vpl = ProfileManager.getInstance(context); - Collection profiles = vpl.getProfiles(); - for (Iterator it = profiles.iterator(); it.hasNext(); ){ - VpnProfile p = it.next(); - try { - if ( p.mName.contains( gateway.getString("host") ) ) - it.remove(); - vpl.removeProfile(context, p); - } catch (JSONException e) { - // TODO Auto-generated catch block - e.printStackTrace(); - } - } - - this.parseOptions(); - this.createVPNProfile(); - - setUniqueProfileName(vpl); - vpl.addProfile(mVpnProfile); - vpl.saveProfile(context, mVpnProfile); - vpl.saveProfileList(context); - } - - /** - * Attempts to create a unique profile name from the hostname of the gateway - * - * @param profileManager - */ - private void setUniqueProfileName(ProfileManager profileManager) { - int i=0; - - String newname; - try { - newname = mGateway.getString("host"); - while(profileManager.getProfileByName(newname)!=null) { - i++; - if(i==1) - newname = getString(R.string.converted_profile); - else - newname = getString(R.string.converted_profile_i,i); - } - - mVpnProfile.mName=newname; - } catch (JSONException e) { - // TODO Auto-generated catch block - Log.v(TAG,"Couldn't read gateway name for profile creation!"); - e.printStackTrace(); - } - } - - /** - * FIXME This method is really the outline of the refactoring needed in se.leap.openvpn.ConfigParser - */ - private void parseOptions(){ - - // FIXME move these to a common API (& version) definition place, like ProviderAPI or ConfigHelper - String common_options = "openvpn_configuration"; - String remote = "ip_address"; - String ports = "ports"; - String protos = "protocols"; - String capabilities = "capabilities"; - - Vector arg = new Vector(); - Vector> args = new Vector>(); - - try { - JSONObject def = (JSONObject) eipDefinition.get(common_options); - Iterator keys = def.keys(); - Vector> value = new Vector>(); - while ( keys.hasNext() ){ - String key = keys.next().toString(); - - arg.add(key); - for ( String word : def.getString(key).split(" ") ) - arg.add(word); - value.add( (Vector) arg.clone() ); - options.put(key, (Vector>) value.clone()); - - value.clear(); - arg.clear(); - } - } catch (JSONException e) { - // TODO Auto-generated catch block - e.printStackTrace(); - } - - try { - arg.add("remote"); - arg.add(mGateway.getString(remote)); - } catch (JSONException e) { - // TODO Auto-generated catch block - e.printStackTrace(); - } - args.add((Vector) arg.clone()); - options.put("remote", (Vector>) args.clone() ); - arg.clear(); - args.clear(); - - JSONArray protocolsJSON = null; - arg.add("proto"); - try { - protocolsJSON = mGateway.getJSONObject(capabilities).getJSONArray(protos); - } catch (JSONException e) { - // TODO Auto-generated catch block - e.printStackTrace(); - } - Vector protocols = new Vector(); - for ( int i=0; i) arg.clone()); - options.put("proto", (Vector>) args.clone()); - arg.clear(); - args.clear(); - - - String port = null; - arg.add("port"); - try { - port = mGateway.getJSONObject(capabilities).getJSONArray(ports).optString(0); - } catch (JSONException e) { - // TODO Auto-generated catch block - e.printStackTrace(); - } - arg.add(port); - args.add((Vector) arg.clone()); - options.put("port", (Vector>) args.clone()); - args.clear(); - arg.clear(); - } - - /** - * Create and attach the VpnProfile to our gateway object - */ - protected void createVPNProfile(){ - try { - ConfigParser cp = new ConfigParser(); - cp.setDefinition(options); - VpnProfile vp = cp.convertProfile(); - mVpnProfile = vp; - Log.v(TAG,"Created VPNProfile"); - } catch (ConfigParseError e) { - // FIXME We didn't get a VpnProfile! Error handling! and log level - Log.v(TAG,"Error createing VPNProfile"); - e.printStackTrace(); - } - } - } - -} diff --git a/src/se/leap/leapclient/EipServiceFragment.java b/src/se/leap/leapclient/EipServiceFragment.java deleted file mode 100644 index 628572b4..00000000 --- a/src/se/leap/leapclient/EipServiceFragment.java +++ /dev/null @@ -1,264 +0,0 @@ -package se.leap.leapclient; - -import se.leap.openvpn.LogWindow; -import se.leap.openvpn.OpenVPN; -import se.leap.openvpn.OpenVPN.StateListener; -import android.app.Activity; -import android.app.AlertDialog; -import android.app.Fragment; -import android.content.DialogInterface; -import android.content.Intent; -import android.os.Bundle; -import android.os.Handler; -import android.os.ResultReceiver; -import android.view.LayoutInflater; -import android.view.MotionEvent; -import android.view.View; -import android.view.View.OnClickListener; -import android.view.ViewGroup; -import android.widget.CompoundButton.OnCheckedChangeListener; -import android.widget.CompoundButton; -import android.widget.RelativeLayout; -import android.widget.Switch; -import android.widget.TextView; - -public class EipServiceFragment extends Fragment implements StateListener, OnClickListener, OnCheckedChangeListener { - - private static final String IS_EIP_PENDING = "is_eip_pending"; - - private View eipFragment; - private Switch eipSwitch; - private View eipDetail; - private TextView eipStatus; - - private boolean eipAutoSwitched = true; - - private boolean mEipStartPending = false; - - private EIPReceiver mEIPReceiver; - - @Override - public View onCreateView(LayoutInflater inflater, ViewGroup container, - Bundle savedInstanceState) { - - eipFragment = inflater.inflate(R.layout.eip_service_fragment, container, false); - - eipDetail = ((RelativeLayout) eipFragment.findViewById(R.id.eipDetail)); - eipDetail.setVisibility(View.VISIBLE); - - View eipSettings = eipFragment.findViewById(R.id.eipSettings); - eipSettings.setVisibility(View.GONE); // FIXME too! - - if (mEipStartPending) - eipFragment.findViewById(R.id.eipProgress).setVisibility(View.VISIBLE); - - eipStatus = (TextView) eipFragment.findViewById(R.id.eipStatus); - eipStatus.setOnClickListener(this); - - eipSwitch = (Switch) eipFragment.findViewById(R.id.eipSwitch); - eipSwitch.setOnTouchListener(new View.OnTouchListener() { - @Override - public boolean onTouch(View v, MotionEvent event) { - eipAutoSwitched = false; - return false; - } - }); - eipSwitch.setOnCheckedChangeListener(this); - - return eipFragment; - } - - @Override - public void onCreate(Bundle savedInstanceState) { - super.onCreate(savedInstanceState); - - mEIPReceiver = new EIPReceiver(new Handler()); - - if (savedInstanceState != null) - mEipStartPending = savedInstanceState.getBoolean(IS_EIP_PENDING); - } - - @Override - public void onResume() { - super.onResume(); - - OpenVPN.addStateListener(this); - } - - @Override - public void onPause() { - super.onPause(); - - OpenVPN.removeStateListener(this); - } - - @Override - public void onSaveInstanceState(Bundle outState) { - super.onSaveInstanceState(outState); - outState.putBoolean(IS_EIP_PENDING, mEipStartPending); - } - - @Override - public void onClick(View buttonView) { - if (buttonView.equals(eipStatus)) - showEIPLog(); - } - - /** - * Launches the se.leap.openvpn.LogWindow Activity showing detailed OpenVPN log - */ - public void showEIPLog(){ - Intent intent = new Intent(getActivity().getBaseContext(),LogWindow.class); - intent.addFlags(Intent.FLAG_ACTIVITY_REORDER_TO_FRONT); - startActivity(intent); - } - - @Override - public void onCheckedChanged(CompoundButton buttonView, boolean isChecked) { - if (buttonView.equals(eipSwitch) && !eipAutoSwitched){ - if (isChecked){ - mEipStartPending = true; - eipFragment.findViewById(R.id.eipProgress).setVisibility(View.VISIBLE); - ((TextView) eipFragment.findViewById(R.id.eipStatus)).setText(R.string.eip_status_start_pending); - eipCommand(EIP.ACTION_START_EIP); - } else { - if (mEipStartPending){ - AlertDialog.Builder alertBuilder = new AlertDialog.Builder(getActivity()); - alertBuilder.setTitle(getResources().getString(R.string.eip_cancel_connect_title)); - alertBuilder - .setMessage(getResources().getString(R.string.eip_cancel_connect_text)) - .setPositiveButton(getResources().getString(R.string.eip_cancel_connect_cancel), new DialogInterface.OnClickListener() { - @Override - public void onClick(DialogInterface dialog, int which) { - eipCommand(EIP.ACTION_STOP_EIP); - } - }) - .setNegativeButton(getResources().getString(R.string.eip_cancel_connect_false), new DialogInterface.OnClickListener() { - @Override - public void onClick(DialogInterface dialog, int which) { - eipAutoSwitched = true; - eipSwitch.setChecked(true); - eipAutoSwitched = false; - } - }) - .show(); - } else { - eipCommand(EIP.ACTION_STOP_EIP); - } - } - } - eipAutoSwitched = true; - } - - /** - * Send a command to EIP - * - * @param action A valid String constant from EIP class representing an Intent - * filter for the EIP class - */ - private void eipCommand(String action){ - // TODO validate "action"...how do we get the list of intent-filters for a class via Android API? - Intent vpnIntent = new Intent(action); - vpnIntent.putExtra(EIP.RECEIVER_TAG, mEIPReceiver); - getActivity().startService(vpnIntent); - } - - @Override - public void updateState(final String state, final String logmessage, final int localizedResId) { - // Note: "states" are not organized anywhere...collected state strings: - // NOPROCESS,NONETWORK,BYTECOUNT,AUTH_FAILED + some parsing thing ( WAIT(?),AUTH,GET_CONFIG,ASSIGN_IP,CONNECTED,SIGINT ) - getActivity().runOnUiThread(new Runnable() { - - @Override - public void run() { - if (eipStatus != null) { - boolean switchState = true; - String statusMessage = ""; - String prefix = getString(localizedResId); - if (state.equals("CONNECTED")){ - statusMessage = "Connection Secure"; - getActivity().findViewById(R.id.eipProgress).setVisibility(View.GONE); - mEipStartPending = false; - } else if (state.equals("BYTECOUNT")) { - statusMessage = logmessage; - } else if ( (state.equals("NOPROCESS") && !mEipStartPending ) || state.equals("EXITING")) { - statusMessage = "Not running! Connection not secure!"; - getActivity().findViewById(R.id.eipProgress).setVisibility(View.GONE); - mEipStartPending = false; - switchState = false; - } else { - statusMessage = prefix + logmessage; - } - - eipAutoSwitched = true; - eipSwitch.setChecked(switchState); - eipAutoSwitched = false; - eipStatus.setText(statusMessage); - } - } - }); - } - - /** - * Inner class for handling messages related to EIP status and control requests - * - * @author Sean Leonard - */ - protected class EIPReceiver extends ResultReceiver { - - protected EIPReceiver(Handler handler){ - super(handler); - } - - @Override - protected void onReceiveResult(int resultCode, Bundle resultData) { - super.onReceiveResult(resultCode, resultData); - - String request = resultData.getString(EIP.REQUEST_TAG); - boolean checked = false; - - if (request == EIP.ACTION_IS_EIP_RUNNING) { - switch (resultCode){ - case Activity.RESULT_OK: - checked = true; - break; - case Activity.RESULT_CANCELED: - checked = false; - break; - } - } else if (request == EIP.ACTION_START_EIP) { - switch (resultCode){ - case Activity.RESULT_OK: - checked = true; - break; - case Activity.RESULT_CANCELED: - checked = false; - eipFragment.findViewById(R.id.eipProgress).setVisibility(View.GONE); - break; - } - } else if (request == EIP.ACTION_STOP_EIP) { - switch (resultCode){ - case Activity.RESULT_OK: - checked = false; - break; - case Activity.RESULT_CANCELED: - checked = true; - break; - } - } else if (request == EIP.EIP_NOTIFICATION) { - switch (resultCode){ - case Activity.RESULT_OK: - checked = true; - break; - case Activity.RESULT_CANCELED: - checked = false; - break; - } - } - - eipAutoSwitched = true; - eipSwitch.setChecked(checked); - eipAutoSwitched = false; - } - } -} diff --git a/src/se/leap/leapclient/LeapHttpClient.java b/src/se/leap/leapclient/LeapHttpClient.java deleted file mode 100644 index 5dca31e9..00000000 --- a/src/se/leap/leapclient/LeapHttpClient.java +++ /dev/null @@ -1,84 +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 . - */ - package se.leap.leapclient; - -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 { - final Context context; - - 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(Context context) { - if(client == null) { - client = new LeapHttpClient(context); - String cert_string = ConfigHelper.getStringFromSharedPref(Provider.CA_CERT); - 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); - } - } - - public LeapHttpClient(Context context) { - this.context = context; - } -} diff --git a/src/se/leap/leapclient/LeapSRPSession.java b/src/se/leap/leapclient/LeapSRPSession.java deleted file mode 100644 index 5a78219b..00000000 --- a/src/se/leap/leapclient/LeapSRPSession.java +++ /dev/null @@ -1,326 +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 . - */ - package se.leap.leapclient; - -import java.io.UnsupportedEncodingException; -import java.math.BigInteger; -import java.security.MessageDigest; -import java.security.NoSuchAlgorithmException; -import java.security.SecureRandom; -import java.util.Arrays; - -import org.jboss.security.srp.SRPParameters; - -/** - * Implements all SRP algorithm logic. - * - * It's derived from JBoss implementation, with adjustments to make it work with LEAP platform. - * - * @author parmegv - * - */ -public class LeapSRPSession { - - final public static String SALT = "salt"; - final public static String M1 = "M1"; - final public static String M2 = "M2"; - - private SRPParameters params; - private String username; - private String password; - private BigInteger N; - private byte[] N_bytes; - private BigInteger g; - private BigInteger x; - private BigInteger v; - private BigInteger a; - private BigInteger A; - private byte[] K; - private SecureRandom pseudoRng; - /** The M1 = H(H(N) xor H(g) | H(U) | s | A | B | K) hash */ - private MessageDigest clientHash; - /** The M2 = H(A | M | K) hash */ - private MessageDigest serverHash; - - 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) - { - this(username, password, params, null); - } - - /** 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 - @param abytes, the random exponent used in the A public key - */ - public LeapSRPSession(String username, String password, SRPParameters params, - byte[] abytes) { - this.params = params; - this.g = new BigInteger(1, params.g); - N_bytes = ConfigHelper.trim(params.N); - this.N = new BigInteger(1, N_bytes); - this.username = username; - this.password = password; - - try { - pseudoRng = SecureRandom.getInstance("SHA1PRNG"); - } catch (NoSuchAlgorithmException e) { - // TODO Auto-generated catch block - e.printStackTrace(); - } - - if( abytes != null ) { - A_LEN = 8*abytes.length; - /* TODO Why did they put this condition? - if( 8*abytes.length != A_LEN ) - throw new IllegalArgumentException("The abytes param must be " - +(A_LEN/8)+" in length, abytes.length="+abytes.length); - */ - this.a = new BigInteger(abytes); - } - else - A_LEN = 64; - - serverHash = newDigest(); - clientHash = newDigest(); - } - - /** - * Calculates the parameter x of the SRP-6a algorithm. - * @param username - * @param password - * @param salt the salt of the user - * @return x - */ - public byte[] calculatePasswordHash(String username, String password, byte[] salt) - { - //password = password.replaceAll("\\\\", "\\\\\\\\"); - // Calculate x = H(s | H(U | ':' | password)) - MessageDigest x_digest = newDigest(); - // Try to convert the username to a byte[] using ISO-8859-1 - byte[] user = null; - byte[] password_bytes = null; - byte[] colon = {}; - String encoding = "ISO-8859-1"; - try { - user = ConfigHelper.trim(username.getBytes(encoding)); - colon = ConfigHelper.trim(":".getBytes(encoding)); - password_bytes = ConfigHelper.trim(password.getBytes(encoding)); - } - catch(UnsupportedEncodingException e) { - // Use the default platform encoding - user = ConfigHelper.trim(username.getBytes()); - colon = ConfigHelper.trim(":".getBytes()); - password_bytes = ConfigHelper.trim(password.getBytes()); - } - - // Build the hash - x_digest.update(user); - x_digest.update(colon); - x_digest.update(password_bytes); - byte[] h = x_digest.digest(); - - x_digest.reset(); - x_digest.update(salt); - x_digest.update(h); - byte[] x_digest_bytes = x_digest.digest(); - - return x_digest_bytes; - } - - /** - * Calculates the parameter V of the SRP-6a algorithm. - * @param k_string constant k predefined by the SRP server implementation. - * @return the value of V - */ - private BigInteger calculateV(String k_string) { - BigInteger k = new BigInteger(k_string, 16); - BigInteger v = k.multiply(g.modPow(x, N)); // g^x % N - return v; - } - - /** - * Calculates the trimmed xor from two BigInteger numbers - * @param b1 the positive source to build first BigInteger - * @param b2 the positive source to build second BigInteger - * @param length - * @return - */ - public byte[] xor(byte[] b1, byte[] b2) - { - //TODO Check if length matters in the order, when b2 is smaller than b1 or viceversa - byte[] xor_digest = new BigInteger(1, b1).xor(new BigInteger(1, b2)).toByteArray(); - return ConfigHelper.trim(xor_digest); - } - - /** - * @returns The exponential residue (parameter A) to be sent to the server. - */ - public byte[] exponential() { - byte[] Abytes = null; - if(A == null) { - /* If the random component of A has not been specified use a random - number */ - if( a == null ) { - BigInteger one = BigInteger.ONE; - do { - a = new BigInteger(A_LEN, pseudoRng); - } while(a.compareTo(one) <= 0); - } - A = g.modPow(a, N); - Abytes = ConfigHelper.trim(A.toByteArray()); - } - return Abytes; - } - - /** - * Calculates the parameter M1, to be sent to the SRP server. - * It also updates hashes of client and server for further calculations in other methods. - * It uses a predefined k. - * @param salt_bytes - * @param Bbytes the parameter received from the server, in bytes - * @return the parameter M1 - * @throws NoSuchAlgorithmException - */ - public byte[] response(byte[] salt_bytes, byte[] Bbytes) throws NoSuchAlgorithmException { - // Calculate x = H(s | H(U | ':' | password)) - byte[] xb = calculatePasswordHash(username, password, ConfigHelper.trim(salt_bytes)); - this.x = new BigInteger(1, xb); - - // Calculate v = kg^x mod N - String k_string = "bf66c44a428916cad64aa7c679f3fd897ad4c375e9bbb4cbf2f5de241d618ef0"; - this.v = calculateV(k_string); - - // H(N) - byte[] digest_of_n = newDigest().digest(N_bytes); - - // H(g) - byte[] digest_of_g = newDigest().digest(params.g); - - // clientHash = H(N) xor H(g) - byte[] xor_digest = xor(digest_of_n, digest_of_g); - clientHash.update(xor_digest); - - // clientHash = H(N) xor H(g) | H(U) - byte[] username_digest = newDigest().digest(ConfigHelper.trim(username.getBytes())); - username_digest = ConfigHelper.trim(username_digest); - clientHash.update(username_digest); - - // clientHash = H(N) xor H(g) | H(U) | s - clientHash.update(ConfigHelper.trim(salt_bytes)); - - K = null; - - // clientHash = H(N) xor H(g) | H(U) | A - byte[] Abytes = ConfigHelper.trim(A.toByteArray()); - clientHash.update(Abytes); - - // clientHash = H(N) xor H(g) | H(U) | s | A | B - Bbytes = ConfigHelper.trim(Bbytes); - clientHash.update(Bbytes); - - // Calculate S = (B - kg^x) ^ (a + u * x) % N - BigInteger S = calculateS(Bbytes); - byte[] S_bytes = ConfigHelper.trim(S.toByteArray()); - - // K = SessionHash(S) - String hash_algorithm = params.hashAlgorithm; - MessageDigest sessionDigest = MessageDigest.getInstance(hash_algorithm); - K = ConfigHelper.trim(sessionDigest.digest(S_bytes)); - - // clientHash = H(N) xor H(g) | H(U) | A | B | K - clientHash.update(K); - - byte[] M1 = ConfigHelper.trim(clientHash.digest()); - - // serverHash = Astr + M + K - serverHash.update(Abytes); - serverHash.update(M1); - serverHash.update(K); - - return M1; - } - - /** - * It calculates the parameter S used by response() to obtain session hash K. - * @param Bbytes the parameter received from the server, in bytes - * @return the parameter S - */ - private BigInteger calculateS(byte[] Bbytes) { - byte[] Abytes = ConfigHelper.trim(A.toByteArray()); - Bbytes = ConfigHelper.trim(Bbytes); - byte[] u_bytes = getU(Abytes, Bbytes); - - BigInteger B = new BigInteger(1, Bbytes); - BigInteger u = new BigInteger(1, u_bytes); - - BigInteger B_minus_v = B.subtract(v); - BigInteger a_ux = a.add(u.multiply(x)); - BigInteger S = B_minus_v.modPow(a_ux, N); - return S; - } - - /** - * It calculates the parameter u used by calculateS to obtain S. - * @param Abytes the exponential residue sent to the server - * @param Bbytes the parameter received from the server, in bytes - * @return - */ - public byte[] getU(byte[] Abytes, byte[] Bbytes) { - MessageDigest u_digest = newDigest(); - u_digest.update(ConfigHelper.trim(Abytes)); - u_digest.update(ConfigHelper.trim(Bbytes)); - byte[] u_digest_bytes = u_digest.digest(); - return ConfigHelper.trim(new BigInteger(1, u_digest_bytes).toByteArray()); - } - - /** - * @param M2 The server's response to the client's challenge - * @returns True if and only if the server's response was correct. - */ - public boolean verify(byte[] M2) - { - // M2 = H(A | M1 | K) - M2 = ConfigHelper.trim(M2); - byte[] myM2 = ConfigHelper.trim(serverHash.digest()); - boolean valid = Arrays.equals(M2, myM2); - return valid; - } - - /** - * @return a new SHA-256 digest. - */ - public MessageDigest newDigest() - { - MessageDigest md = null; - try { - md = MessageDigest.getInstance("SHA-256"); - } catch (NoSuchAlgorithmException e) { - e.printStackTrace(); - } - return md; - } -} diff --git a/src/se/leap/leapclient/LogInDialog.java b/src/se/leap/leapclient/LogInDialog.java deleted file mode 100644 index 7dd1c732..00000000 --- a/src/se/leap/leapclient/LogInDialog.java +++ /dev/null @@ -1,139 +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 . - */ - package se.leap.leapclient; - -import se.leap.leapclient.R; -import android.R.color; -import android.app.Activity; -import android.app.AlertDialog; -import android.app.DialogFragment; -import android.content.DialogInterface; -import android.content.res.ColorStateList; -import android.os.Bundle; -import android.provider.CalendarContract.Colors; -import android.view.LayoutInflater; -import android.view.View; -import android.view.animation.AlphaAnimation; -import android.view.animation.BounceInterpolator; -import android.widget.EditText; -import android.widget.TextView; - -/** - * Implements the log in dialog, currently without progress dialog. - * - * It returns to the previous fragment when finished, and sends username and password to the authenticate method. - * - * It also notifies the user if the password is not valid. - * - * @author parmegv - * - */ -public class LogInDialog extends DialogFragment { - - - 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"; - - - public AlertDialog onCreateDialog(Bundle savedInstanceState) { - AlertDialog.Builder builder = new AlertDialog.Builder(getActivity()); - LayoutInflater inflater = getActivity().getLayoutInflater(); - View log_in_dialog_view = inflater.inflate(R.layout.log_in_dialog, null); - - final TextView user_message = (TextView)log_in_dialog_view.findViewById(R.id.user_message); - if(getArguments() != null && getArguments().containsKey(getResources().getString(R.string.user_message))) { - user_message.setText(getArguments().getString(getResources().getString(R.string.user_message))); - } else { - user_message.setVisibility(View.GONE); - } - - final EditText username_field = (EditText)log_in_dialog_view.findViewById(R.id.username_entered); - if(getArguments() != null && getArguments().containsKey(USERNAME)) { - String username = getArguments().getString(USERNAME); - username_field.setText(username); - } - if (getArguments() != null && getArguments().containsKey(USERNAME_MISSING)) { - username_field.setError(getResources().getString(R.string.username_ask)); - } - - final EditText password_field = (EditText)log_in_dialog_view.findViewById(R.id.password_entered); - if(!username_field.getText().toString().isEmpty() && password_field.isFocusable()) { - password_field.requestFocus(); - } - if (getArguments() != null && getArguments().containsKey(PASSWORD_INVALID_LENGTH)) { - password_field.setError(getResources().getString(R.string.error_not_valid_password_user_message)); - } - - - builder.setView(log_in_dialog_view) - .setPositiveButton(R.string.login_button, new DialogInterface.OnClickListener() { - public void onClick(DialogInterface dialog, int id) { - String username = username_field.getText().toString().trim(); - String password = password_field.getText().toString().trim(); - dialog.dismiss(); - interface_with_Dashboard.authenticate(username, password); - } - }) - .setNegativeButton(R.string.cancel, new DialogInterface.OnClickListener() { - public void onClick(DialogInterface dialog, int id) { - dialog.cancel(); - } - }); - - return builder.create(); - } - - /** - * Interface used to communicate LogInDialog with Dashboard. - * - * @author parmegv - * - */ - public interface LogInDialogInterface { - /** - * Starts authentication process. - * @param username - * @param password - */ - public void authenticate(String username, String password); - } - - LogInDialogInterface interface_with_Dashboard; - - /** - * @return a new instance of this DialogFragment. - */ - public static DialogFragment newInstance() { - LogInDialog dialog_fragment = new LogInDialog(); - return dialog_fragment; - } - - @Override - public void onAttach(Activity activity) { - super.onAttach(activity); - try { - interface_with_Dashboard = (LogInDialogInterface) activity; - } catch (ClassCastException e) { - throw new ClassCastException(activity.toString() - + " must implement LogInDialogListener"); - } - } -} diff --git a/src/se/leap/leapclient/NewProviderDialog.java b/src/se/leap/leapclient/NewProviderDialog.java deleted file mode 100644 index 5cb16f7d..00000000 --- a/src/se/leap/leapclient/NewProviderDialog.java +++ /dev/null @@ -1,110 +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 . - */ - package se.leap.leapclient; - -import se.leap.leapclient.R; -import android.app.Activity; -import android.app.AlertDialog; -import android.app.Dialog; -import android.app.DialogFragment; -import android.content.DialogInterface; -import android.os.Bundle; -import android.view.LayoutInflater; -import android.view.View; -import android.widget.CheckBox; -import android.widget.EditText; -import android.widget.Toast; - -/** - * Implements the new custom provider dialog. - * - * @author parmegv - * - */ -public class NewProviderDialog extends DialogFragment { - - final public static String TAG = "newProviderDialog"; - - public interface NewProviderDialogInterface { - public void saveAndSelectProvider(String url_provider, boolean danger_on); - } - - NewProviderDialogInterface interface_with_ConfigurationWizard; - - /** - * @return a new instance of this DialogFragment. - */ - public static DialogFragment newInstance() { - NewProviderDialog dialog_fragment = new NewProviderDialog(); - return dialog_fragment; - } - - @Override - public void onAttach(Activity activity) { - super.onAttach(activity); - try { - interface_with_ConfigurationWizard = (NewProviderDialogInterface) activity; - } catch (ClassCastException e) { - throw new ClassCastException(activity.toString() - + " must implement NoticeDialogListener"); - } - } - - @Override - public Dialog onCreateDialog(Bundle savedInstanceState) { - AlertDialog.Builder builder = new AlertDialog.Builder(getActivity()); - LayoutInflater inflater = getActivity().getLayoutInflater(); - View new_provider_dialog_view = inflater.inflate(R.layout.new_provider_dialog, null); - final EditText url_input_field = (EditText)new_provider_dialog_view.findViewById(R.id.new_provider_url); - final CheckBox danger_checkbox = (CheckBox)new_provider_dialog_view.findViewById(R.id.danger_checkbox); - - builder.setView(new_provider_dialog_view) - .setMessage(R.string.introduce_new_provider) - .setPositiveButton(R.string.save, new DialogInterface.OnClickListener() { - public void onClick(DialogInterface dialog, int id) { - String entered_url = url_input_field.getText().toString().trim(); - if(!entered_url.startsWith("https://")) { - entered_url = "https://".concat(entered_url); - } - boolean danger_on = danger_checkbox.isChecked(); - if(validURL(entered_url)) { - interface_with_ConfigurationWizard.saveAndSelectProvider(entered_url, danger_on); - Toast.makeText(getActivity().getApplicationContext(), R.string.valid_url_entered, Toast.LENGTH_LONG).show(); - } else { - url_input_field.setText(""); - Toast.makeText(getActivity().getApplicationContext(), R.string.not_valid_url_entered, Toast.LENGTH_LONG).show(); - } - } - }) - .setNegativeButton(R.string.cancel, new DialogInterface.OnClickListener() { - public void onClick(DialogInterface dialog, int id) { - dialog.cancel(); - } - }); - // Create the AlertDialog object and return it - return builder.create(); - } - - /** - * Checks if the entered url is valid or not. - * @param entered_url - * @return true if it's not empty nor contains only the protocol. - */ - boolean validURL(String entered_url) { - return !entered_url.isEmpty() && entered_url.matches("http[s]?://.+") && !entered_url.replaceFirst("http[s]?://", "").isEmpty(); - } -} diff --git a/src/se/leap/leapclient/Provider.java b/src/se/leap/leapclient/Provider.java deleted file mode 100644 index 2846ea60..00000000 --- a/src/se/leap/leapclient/Provider.java +++ /dev/null @@ -1,208 +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 . - */ -package se.leap.leapclient; - -import java.io.Serializable; -import java.util.Arrays; -import java.util.Locale; - -import org.json.JSONArray; -import org.json.JSONException; -import org.json.JSONObject; - -import android.content.Context; -import android.app.Activity; -import android.content.SharedPreferences; - -/** - * @author Sean Leonard - * - */ -public final class Provider implements Serializable { - - private static final long serialVersionUID = 6003835972151761353L; - - private static Provider instance = null; - - // We'll access our preferences here - private static SharedPreferences preferences = null; - // Represents our Provider's provider.json - private static JSONObject definition = null; - - final public static String - API_URL = "api_uri", - API_VERSION = "api_version", - ALLOW_REGISTRATION = "allow_registration", - API_RETURN_SERIAL = "serial", - SERVICE = "service", - KEY = "provider", - CA_CERT = "ca_cert", - NAME = "name", - DESCRIPTION = "description", - DOMAIN = "domain", - MAIN_URL = "main_url", - DOT_JSON_URL = "provider_json_url" - ; - - // Array of what API versions we understand - protected static final String[] API_VERSIONS = {"1"}; // I assume we might encounter arbitrary version "numbers" - // Some API pieces we want to know about - private static final String API_TERM_SERVICES = "services"; - private static final String API_TERM_NAME = "name"; - private static final String API_TERM_DOMAIN = "domain"; - private static final String API_TERM_DEFAULT_LANGUAGE = "default_language"; - protected static final String[] API_EIP_TYPES = {"openvpn"}; - - private static final String PREFS_EIP_NAME = null; - - - - // What, no individual fields?! We're going to gamble on org.json.JSONObject and JSONArray - // Supporting multiple API versions will probably break this paradigm, - // Forcing me to write a real constructor and rewrite getters/setters - // Also will refactor if i'm instantiating the same local variables all the time - - /** - * - */ - private Provider() {} - - protected static Provider getInstance(){ - if(instance==null){ - instance = new Provider(); - } - return instance; - } - - protected void init(Activity activity) { - - // Load our preferences from SharedPreferences - // If there's nothing there, we will end up returning a rather empty object - // to whoever called getInstance() and they can run the First Run Wizard - //preferences = context.getgetPreferences(0); // 0 == MODE_PRIVATE, but we don't extend Android's classes... - - // Load SharedPreferences - preferences = activity.getSharedPreferences(Dashboard.SHARED_PREFERENCES,Context.MODE_PRIVATE); - // Inflate our provider.json data - try { - definition = new JSONObject( preferences.getString("provider", "") ); - } catch (JSONException e) { - // TODO: handle exception - - // FIXME!! We want "real" data!! - } - } - - protected String getDomain(){ - String domain = "Null"; - try { - domain = definition.getString(API_TERM_DOMAIN); - } catch (JSONException e) { - domain = "Null"; - e.printStackTrace(); - } - return domain; - } - - protected String getName(){ - // Should we pass the locale in, or query the system here? - String lang = Locale.getDefault().getLanguage(); - String name = "Null"; // Should it actually /be/ null, for error conditions? - try { - name = definition.getJSONObject(API_TERM_NAME).getString(lang); - } catch (JSONException e) { - // TODO: Nesting try/catch blocks? Crazy - // Maybe you should actually handle exception? - try { - name = definition.getJSONObject(API_TERM_NAME).getString( definition.getString(API_TERM_DEFAULT_LANGUAGE) ); - } catch (JSONException e2) { - // TODO: Will you handle the exception already? - } - } - - return name; - } - - protected String getDescription(){ - String lang = Locale.getDefault().getLanguage(); - String desc = null; - try { - desc = definition.getJSONObject("description").getString(lang); - } catch (JSONException e) { - // TODO: handle exception!! - try { - desc = definition.getJSONObject("description").getString( definition.getString("default_language") ); - } catch (JSONException e2) { - // TODO: i can't believe you're doing it again! - } - } - - return desc; - } - - protected boolean hasEIP() { - JSONArray services = null; - try { - services = definition.getJSONArray(API_TERM_SERVICES); // returns ["openvpn"] - } catch (Exception e) { - // TODO: handle exception - } - for (int i=0;i. - */ - package se.leap.leapclient; - -import java.io.DataOutputStream; -import java.io.FileNotFoundException; -import java.io.IOException; -import java.io.InputStream; -import java.io.UnsupportedEncodingException; -import java.math.BigInteger; -import java.net.CookieHandler; -import java.net.CookieManager; -import java.net.CookiePolicy; -import java.net.MalformedURLException; -import java.net.SocketTimeoutException; -import java.net.URL; -import java.net.URLConnection; -import java.net.URLEncoder; -import java.net.UnknownHostException; -import java.security.KeyManagementException; -import java.security.KeyStore; -import java.security.KeyStoreException; -import java.security.NoSuchAlgorithmException; -import java.security.SecureRandom; -import java.security.cert.CertificateException; -import java.security.cert.X509Certificate; -import java.security.interfaces.RSAPrivateKey; -import java.util.HashMap; -import java.util.Iterator; -import java.util.Map; -import java.util.Scanner; - -import javax.net.ssl.HostnameVerifier; -import javax.net.ssl.HttpsURLConnection; -import javax.net.ssl.KeyManager; -import javax.net.ssl.SSLContext; -import javax.net.ssl.SSLSession; -import javax.net.ssl.TrustManager; -import javax.net.ssl.TrustManagerFactory; -import javax.net.ssl.X509TrustManager; - -import org.apache.http.client.ClientProtocolException; -import org.jboss.security.srp.SRPParameters; -import org.json.JSONException; -import org.json.JSONObject; - -import se.leap.leapclient.ProviderListContent.ProviderItem; -import android.app.IntentService; -import android.content.Intent; -import android.os.Bundle; -import android.os.Handler; -import android.os.ResultReceiver; -import android.util.Base64; -import android.util.Log; -import android.widget.Toast; - -/** - * Implements HTTP api methods used to manage communications with the provider server. - * - * It's an IntentService because it downloads data from the Internet, so it operates in the background. - * - * @author parmegv - * @author MeanderingCode - * - */ -public class ProviderAPI extends IntentService { - - private Handler mHandler; - - final public static String - DOWNLOAD_JSON_FILES_BUNDLE_EXTRA = "downloadJSONFiles", - UPDATE_PROVIDER_DOTJSON = "updateProviderDotJSON", - DOWNLOAD_NEW_PROVIDER_DOTJSON = "downloadNewProviderDotJSON", - SRP_REGISTER = "srpRegister", - SRP_AUTH = "srpAuth", - LOG_OUT = "logOut", - DOWNLOAD_CERTIFICATE = "downloadUserAuthedCertificate", - PARAMETERS = "parameters", - RESULT_KEY = "result", - RECEIVER_KEY = "receiver", - SESSION_ID_COOKIE_KEY = "session_id_cookie_key", - SESSION_ID_KEY = "session_id", - ERRORS = "errors" - ; - - final public static int - CUSTOM_PROVIDER_ADDED = 0, - CORRECTLY_DOWNLOADED_JSON_FILES = 1, - INCORRECTLY_DOWNLOADED_JSON_FILES = 2, - SRP_AUTHENTICATION_SUCCESSFUL = 3, - SRP_AUTHENTICATION_FAILED = 4, - SRP_REGISTRATION_SUCCESSFUL = 5, - SRP_REGISTRATION_FAILED = 6, - LOGOUT_SUCCESSFUL = 7, - LOGOUT_FAILED = 8, - CORRECTLY_DOWNLOADED_CERTIFICATE = 9, - INCORRECTLY_DOWNLOADED_CERTIFICATE = 10, - CORRECTLY_UPDATED_PROVIDER_DOT_JSON = 11, - INCORRECTLY_UPDATED_PROVIDER_DOT_JSON = 12, - CORRECTLY_DOWNLOADED_ANON_CERTIFICATE = 13, - INCORRECTLY_DOWNLOADED_ANON_CERTIFICATE = 14 - ; - - public ProviderAPI() { - super("ProviderAPI"); - Log.v("ClassName", "Provider API"); - } - - @Override - public void onCreate() { - super.onCreate(); - mHandler = new Handler(); - CookieHandler.setDefault(new CookieManager(null, CookiePolicy.ACCEPT_ORIGINAL_SERVER) ); - } - - private void displayToast(final int toast_string_id) { - mHandler.post(new Runnable() { - - @Override - public void run() { - Toast.makeText(ProviderAPI.this, toast_string_id, Toast.LENGTH_LONG).show(); - } - }); - } - - @Override - protected void onHandleIntent(Intent command) { - final ResultReceiver receiver = command.getParcelableExtra("receiver"); - String action = command.getAction(); - Bundle parameters = command.getBundleExtra(PARAMETERS); - - if(action.equalsIgnoreCase(DOWNLOAD_JSON_FILES_BUNDLE_EXTRA)) { - if(!downloadJsonFiles(parameters)) { - receiver.send(INCORRECTLY_DOWNLOADED_JSON_FILES, Bundle.EMPTY); - } else { - receiver.send(CORRECTLY_DOWNLOADED_JSON_FILES, Bundle.EMPTY); - } - } else if(action.equalsIgnoreCase(UPDATE_PROVIDER_DOTJSON)) { - Bundle result = updateProviderDotJSON(parameters); - if(result.getBoolean(RESULT_KEY)) { - receiver.send(CORRECTLY_UPDATED_PROVIDER_DOT_JSON, result); - } else { - receiver.send(INCORRECTLY_UPDATED_PROVIDER_DOT_JSON, Bundle.EMPTY); - } - } else if (action.equalsIgnoreCase(DOWNLOAD_NEW_PROVIDER_DOTJSON)) { - Bundle result = downloadNewProviderDotJSON(parameters); - if(result.getBoolean(RESULT_KEY)) { - receiver.send(CORRECTLY_UPDATED_PROVIDER_DOT_JSON, result); - } else { - receiver.send(INCORRECTLY_DOWNLOADED_JSON_FILES, Bundle.EMPTY); - } - } else if (action.equalsIgnoreCase(SRP_AUTH)) { - Bundle session_id_bundle = authenticateBySRP(parameters); - if(session_id_bundle.getBoolean(RESULT_KEY)) { - receiver.send(SRP_AUTHENTICATION_SUCCESSFUL, session_id_bundle); - } else { - receiver.send(SRP_AUTHENTICATION_FAILED, session_id_bundle); - } - } else if (action.equalsIgnoreCase(LOG_OUT)) { - if(logOut(parameters)) { - receiver.send(LOGOUT_SUCCESSFUL, Bundle.EMPTY); - } else { - receiver.send(LOGOUT_FAILED, Bundle.EMPTY); - } - } else if (action.equalsIgnoreCase(DOWNLOAD_CERTIFICATE)) { - if(getNewCert(parameters)) { - receiver.send(CORRECTLY_DOWNLOADED_CERTIFICATE, Bundle.EMPTY); - } else { - receiver.send(INCORRECTLY_DOWNLOADED_CERTIFICATE, Bundle.EMPTY); - } - } - } - - /** - * Downloads the main cert and the eip-service.json files given through the task parameter - * @param task - * @return true if eip-service.json was parsed as a JSON object correctly. - */ - private boolean downloadJsonFiles(Bundle task) { - String cert_url = task.getString(Provider.CA_CERT); - String eip_service_json_url = task.getString(EIP.KEY); - boolean danger_on = task.getBoolean(ProviderItem.DANGER_ON); - try { - String cert_string = downloadWithCommercialCA(cert_url, danger_on); - if(cert_string.isEmpty()) return false; - X509Certificate certCert = ConfigHelper.parseX509CertificateFromString(cert_string); - cert_string = Base64.encodeToString( certCert.getEncoded(), Base64.DEFAULT); - ConfigHelper.saveSharedPref(Provider.CA_CERT, "-----BEGIN CERTIFICATE-----\n"+cert_string+"-----END CERTIFICATE-----"); - - String eip_service_string = downloadWithCommercialCA(eip_service_json_url, danger_on); - ConfigHelper.saveSharedPref(EIP.KEY, new JSONObject(eip_service_string)); - - return true; - } catch (JSONException e) { - return false; - } catch (CertificateException e) { - // TODO Auto-generated catch block - e.printStackTrace(); - return false; - } - } - - /** - * Starts the authentication process using SRP protocol. - * - * @param task containing: username, password and api url. - * @return a bundle with a boolean value mapped to a key named RESULT_KEY, and which is true if authentication was successful. - */ - private Bundle authenticateBySRP(Bundle task) { - Bundle session_id_bundle = new Bundle(); - - String username = (String) task.get(LogInDialog.USERNAME); - String password = (String) task.get(LogInDialog.PASSWORD); - if(validUserLoginData(username, password)) { - String authentication_server = (String) task.get(Provider.API_URL); - - SRPParameters params = new SRPParameters(new BigInteger(ConfigHelper.NG_1024, 16).toByteArray(), ConfigHelper.G.toByteArray(), BigInteger.ZERO.toByteArray(), "SHA-256"); - LeapSRPSession client = new LeapSRPSession(username, password, params); - byte[] A = client.exponential(); - try { - JSONObject saltAndB = sendAToSRPServer(authentication_server, username, new BigInteger(1, A).toString(16)); - if(saltAndB.length() > 0) { - String salt = saltAndB.getString(LeapSRPSession.SALT); - byte[] Bbytes = new BigInteger(saltAndB.getString("B"), 16).toByteArray(); - byte[] M1 = client.response(new BigInteger(salt, 16).toByteArray(), Bbytes); - JSONObject session_idAndM2 = sendM1ToSRPServer(authentication_server, username, M1); - if(session_idAndM2.has(LeapSRPSession.M2) && client.verify((byte[])session_idAndM2.get(LeapSRPSession.M2))) { - session_id_bundle.putBoolean(RESULT_KEY, true); - } else { - session_id_bundle.putBoolean(RESULT_KEY, false); - session_id_bundle.putString(getResources().getString(R.string.user_message), getResources().getString(R.string.error_bad_user_password_user_message)); - session_id_bundle.putString(LogInDialog.USERNAME, username); - } - } else { - session_id_bundle.putString(getResources().getString(R.string.user_message), getResources().getString(R.string.error_bad_user_password_user_message)); - session_id_bundle.putString(LogInDialog.USERNAME, username); - session_id_bundle.putBoolean(RESULT_KEY, false); - } - } catch (ClientProtocolException e) { - session_id_bundle.putBoolean(RESULT_KEY, false); - session_id_bundle.putString(getResources().getString(R.string.user_message), getResources().getString(R.string.error_client_http_user_message)); - session_id_bundle.putString(LogInDialog.USERNAME, username); - } catch (IOException e) { - session_id_bundle.putBoolean(RESULT_KEY, false); - session_id_bundle.putString(getResources().getString(R.string.user_message), getResources().getString(R.string.error_io_exception_user_message)); - session_id_bundle.putString(LogInDialog.USERNAME, username); - } catch (JSONException e) { - session_id_bundle.putBoolean(RESULT_KEY, false); - session_id_bundle.putString(getResources().getString(R.string.user_message), getResources().getString(R.string.error_json_exception_user_message)); - session_id_bundle.putString(LogInDialog.USERNAME, username); - } catch (NoSuchAlgorithmException e) { - session_id_bundle.putBoolean(RESULT_KEY, false); - session_id_bundle.putString(getResources().getString(R.string.user_message), getResources().getString(R.string.error_no_such_algorithm_exception_user_message)); - session_id_bundle.putString(LogInDialog.USERNAME, username); - } catch (KeyManagementException e) { - // TODO Auto-generated catch block - e.printStackTrace(); - } catch (KeyStoreException e) { - // TODO Auto-generated catch block - e.printStackTrace(); - } catch (CertificateException e) { - // TODO Auto-generated catch block - e.printStackTrace(); - } - } else { - if(!wellFormedPassword(password)) { - session_id_bundle.putBoolean(RESULT_KEY, false); - session_id_bundle.putString(LogInDialog.USERNAME, username); - session_id_bundle.putBoolean(LogInDialog.PASSWORD_INVALID_LENGTH, true); - } - if(username.isEmpty()) { - session_id_bundle.putBoolean(RESULT_KEY, false); - session_id_bundle.putBoolean(LogInDialog.USERNAME_MISSING, true); - } - } - - return session_id_bundle; - } - - /** - * Validates parameters entered by the user to log in - * @param entered_username - * @param entered_password - * @return true if both parameters are present and the entered password length is greater or equal to eight (8). - */ - private boolean validUserLoginData(String entered_username, String entered_password) { - return !(entered_username.isEmpty()) && wellFormedPassword(entered_password); - } - - /** - * Validates a password - * @param entered_password - * @return true if the entered password length is greater or equal to eight (8). - */ - private boolean wellFormedPassword(String entered_password) { - return entered_password.length() >= 8; - } - - /** - * Sends an HTTP POST request to the authentication server with the SRP Parameter A. - * @param server_url - * @param username - * @param clientA First SRP parameter sent - * @return response from authentication server - * @throws ClientProtocolException - * @throws IOException - * @throws JSONException - * @throws CertificateException - * @throws NoSuchAlgorithmException - * @throws KeyStoreException - * @throws KeyManagementException - */ - private JSONObject sendAToSRPServer(String server_url, String username, String clientA) throws ClientProtocolException, IOException, JSONException, KeyManagementException, KeyStoreException, NoSuchAlgorithmException, CertificateException { - Map parameters = new HashMap(); - parameters.put("login", username); - parameters.put("A", clientA); - return sendToServer(server_url + "/sessions.json", "POST", parameters); - - /*HttpPost post = new HttpPost(server_url + "/sessions.json" + "?" + "login=" + username + "&&" + "A=" + clientA); - return sendToServer(post);*/ - } - - /** - * Sends an HTTP PUT request to the authentication server with the SRP Parameter M1 (or simply M). - * @param server_url - * @param username - * @param m1 Second SRP parameter sent - * @return response from authentication server - * @throws ClientProtocolException - * @throws IOException - * @throws JSONException - * @throws CertificateException - * @throws NoSuchAlgorithmException - * @throws KeyStoreException - * @throws KeyManagementException - */ - private JSONObject sendM1ToSRPServer(String server_url, String username, byte[] m1) throws ClientProtocolException, IOException, JSONException, KeyManagementException, KeyStoreException, NoSuchAlgorithmException, CertificateException { - Map parameters = new HashMap(); - parameters.put("client_auth", new BigInteger(1, ConfigHelper.trim(m1)).toString(16)); - - //HttpPut put = new HttpPut(server_url + "/sessions/" + username +".json" + "?" + "client_auth" + "=" + new BigInteger(1, ConfigHelper.trim(m1)).toString(16)); - JSONObject json_response = sendToServer(server_url + "/sessions/" + username +".json", "PUT", parameters); - - JSONObject session_idAndM2 = new JSONObject(); - if(json_response.length() > 0) { - byte[] M2_not_trimmed = new BigInteger(json_response.getString(LeapSRPSession.M2), 16).toByteArray(); - /*Cookie session_id_cookie = LeapHttpClient.getInstance(getApplicationContext()).getCookieStore().getCookies().get(0); - session_idAndM2.put(ConfigHelper.SESSION_ID_COOKIE_KEY, session_id_cookie.getName()); - session_idAndM2.put(ConfigHelper.SESSION_ID_KEY, session_id_cookie.getValue());*/ - session_idAndM2.put(LeapSRPSession.M2, ConfigHelper.trim(M2_not_trimmed)); - } - return session_idAndM2; - } - - /** - * Executes an HTTP request expecting a JSON response. - * @param url - * @param request_method - * @param parameters - * @return response from authentication server - * @throws IOException - * @throws JSONException - * @throws MalformedURLException - * @throws CertificateException - * @throws NoSuchAlgorithmException - * @throws KeyStoreException - * @throws KeyManagementException - */ - private JSONObject sendToServer(String url, String request_method, Map parameters) throws JSONException, MalformedURLException, IOException, KeyManagementException, KeyStoreException, NoSuchAlgorithmException, CertificateException { - JSONObject json_response; - InputStream is = null; - HttpsURLConnection urlConnection = (HttpsURLConnection)new URL(url).openConnection(); - urlConnection.setRequestMethod(request_method); - urlConnection.setChunkedStreamingMode(0); - urlConnection.setSSLSocketFactory(getProviderSSLSocketFactory()); - try { - - DataOutputStream writer = new DataOutputStream(urlConnection.getOutputStream()); - writer.writeBytes(formatHttpParameters(parameters)); - writer.close(); - - is = urlConnection.getInputStream(); - String plain_response = new Scanner(is).useDelimiter("\\A").next(); - json_response = new JSONObject(plain_response); - } finally { - InputStream error_stream = urlConnection.getErrorStream(); - if(error_stream != null) { - String error_response = new Scanner(error_stream).useDelimiter("\\A").next(); - urlConnection.disconnect(); - Log.d("Error", error_response); - json_response = new JSONObject(error_response); - if(!json_response.isNull(ERRORS) || json_response.has(ERRORS)) { - return new JSONObject(); - } - } - } - - return json_response; - } - - private String formatHttpParameters(Map parameters) throws UnsupportedEncodingException { - StringBuilder result = new StringBuilder(); - boolean first = true; - - Iterator parameter_iterator = parameters.keySet().iterator(); - while(parameter_iterator.hasNext()) { - if(first) - first = false; - else - result.append("&&"); - - String key = parameter_iterator.next(); - String value = parameters.get(key); - - result.append(URLEncoder.encode(key, "UTF-8")); - result.append("="); - result.append(URLEncoder.encode(value, "UTF-8")); - } - - return result.toString(); - } - /** - * Downloads a provider.json from a given URL, adding a new provider using the given name. - * @param task containing a boolean meaning if the provider is custom or not, another boolean meaning if the user completely trusts this provider, the provider name and its provider.json url. - * @return a bundle with a boolean value mapped to a key named RESULT_KEY, and which is true if the update was successful. - */ - private Bundle updateProviderDotJSON(Bundle task) { - Bundle result = new Bundle(); - boolean custom = task.getBoolean(ProviderItem.CUSTOM); - boolean danger_on = task.getBoolean(ProviderItem.DANGER_ON); - String provider_json_url = task.getString(Provider.DOT_JSON_URL); - String provider_name = task.getString(Provider.NAME); - - try { - String provider_dot_json_string = downloadWithCommercialCA(provider_json_url, danger_on); - if(provider_dot_json_string.isEmpty()) { - result.putBoolean(RESULT_KEY, false); - } else { - JSONObject provider_json = new JSONObject(provider_dot_json_string); - ConfigHelper.saveSharedPref(EIP.ALLOWED_ANON, provider_json.getJSONObject(Provider.SERVICE).getBoolean(EIP.ALLOWED_ANON)); - - //ProviderListContent.addItem(new ProviderItem(provider_name, provider_json_url, provider_json, custom, danger_on)); - result.putBoolean(RESULT_KEY, true); - result.putString(Provider.KEY, provider_json.toString()); - result.putBoolean(ProviderItem.DANGER_ON, danger_on); - } - } catch (JSONException e) { - result.putBoolean(RESULT_KEY, false); - } - - return result; - } - - /** - * Downloads a custom provider provider.json file - * @param task containing a boolean meaning if the user completely trusts this provider, and the provider main url entered in the new custom provider dialog. - * @return true if provider.json file was successfully parsed as a JSON object. - */ - private Bundle downloadNewProviderDotJSON(Bundle task) { - Bundle result = new Bundle(); - boolean custom = true; - boolean danger_on = task.getBoolean(ProviderItem.DANGER_ON); - - String provider_main_url = (String) task.get(Provider.MAIN_URL); - String provider_name = provider_main_url.replaceFirst("http[s]?://", "").replaceFirst("\\/", "_"); - String provider_json_url = guessProviderDotJsonURL(provider_main_url); - - String provider_json_string = downloadWithCommercialCA(provider_json_url, danger_on); - try { - if(provider_json_string.isEmpty()) { - result.putBoolean(RESULT_KEY, false); - } else { - JSONObject provider_json = new JSONObject(provider_json_string); - - ConfigHelper.saveSharedPref(Provider.KEY, provider_json); - ConfigHelper.saveSharedPref(ProviderItem.DANGER_ON, danger_on); - ConfigHelper.saveSharedPref(EIP.ALLOWED_ANON, provider_json.getJSONObject(Provider.SERVICE).getBoolean(EIP.ALLOWED_ANON)); - ProviderItem added_provider = new ProviderItem(provider_name, provider_json_url, provider_json, custom, danger_on); - ProviderListContent.addItem(added_provider); - - result.putString(Provider.NAME, added_provider.getName()); - result.putBoolean(RESULT_KEY, true); - result.putString(Provider.KEY, provider_json.toString()); - result.putBoolean(ProviderItem.DANGER_ON, danger_on); - } - } catch (JSONException e) { - result.putBoolean(RESULT_KEY, false); - } - - return result; - } - - /** - * Tries to download the contents of the provided url using commercially validated CA certificate from chosen provider. - * - * If danger_on flag is true, SSL exceptions will be managed by futher methods that will try to use some bypass methods. - * @param string_url - * @param danger_on if the user completely trusts this provider - * @return - */ - private String downloadWithCommercialCA(String string_url, boolean danger_on) { - - String json_file_content = ""; - - URL provider_url = null; - int seconds_of_timeout = 1; - try { - provider_url = new URL(string_url); - URLConnection url_connection = provider_url.openConnection(); - url_connection.setConnectTimeout(seconds_of_timeout*1000); - json_file_content = new Scanner(url_connection.getInputStream()).useDelimiter("\\A").next(); - } catch (MalformedURLException e) { - displayToast(R.string.malformed_url); - } catch(SocketTimeoutException e) { - displayToast(R.string.server_is_down_message); - } catch (FileNotFoundException e) { - e.printStackTrace(); - displayToast(R.string.server_is_down_message); - } catch (IOException e) { - if(provider_url != null) { - json_file_content = downloadWithProviderCA(provider_url, danger_on); - } else { - displayToast(R.string.certificate_error); - } - } catch (Exception e) { - if(provider_url != null && danger_on) { - json_file_content = downloadWithProviderCA(provider_url, danger_on); - } - } - - return json_file_content; - } - - /** - * Tries to download the contents of the provided url using not commercially validated CA certificate from chosen provider. - * @param url - * @param danger_on true to download CA certificate in case it has not been downloaded. - * @return an empty string if it fails, the url content if not. - */ - private String downloadWithProviderCA(URL url, boolean danger_on) { - String json_file_content = ""; - - try { - // Tell the URLConnection to use a SocketFactory from our SSLContext - HttpsURLConnection urlConnection = - (HttpsURLConnection)url.openConnection(); - urlConnection.setSSLSocketFactory(getProviderSSLSocketFactory()); - json_file_content = new Scanner(urlConnection.getInputStream()).useDelimiter("\\A").next(); - } catch (CertificateException e) { - // TODO Auto-generated catch block - e.printStackTrace(); - } catch (UnknownHostException e) { - displayToast(R.string.server_is_down_message); - } catch (FileNotFoundException e) { - e.printStackTrace(); - displayToast(R.string.server_is_down_message); - } catch (IOException e) { - // The downloaded certificate doesn't validate our https connection. - if(danger_on) { - json_file_content = downloadWithoutCA(url); - } else { - displayToast(R.string.certificate_error); - } - } catch (KeyStoreException e) { - // TODO Auto-generated catch block - e.printStackTrace(); - } catch (NoSuchAlgorithmException e) { - // TODO Auto-generated catch block - e.printStackTrace(); - } catch (KeyManagementException e) { - // TODO Auto-generated catch block - e.printStackTrace(); - } - return json_file_content; - } - - private javax.net.ssl.SSLSocketFactory getProviderSSLSocketFactory() throws KeyStoreException, NoSuchAlgorithmException, CertificateException, IOException, KeyManagementException { - String provider_cert_string = ConfigHelper.getStringFromSharedPref(Provider.CA_CERT); - - java.security.cert.Certificate provider_certificate = ConfigHelper.parseX509CertificateFromString(provider_cert_string); - - // Create a KeyStore containing our trusted CAs - String keyStoreType = KeyStore.getDefaultType(); - KeyStore keyStore = KeyStore.getInstance(keyStoreType); - keyStore.load(null, null); - keyStore.setCertificateEntry("provider_ca_certificate", provider_certificate); - - // Create a TrustManager that trusts the CAs in our KeyStore - String tmfAlgorithm = TrustManagerFactory.getDefaultAlgorithm(); - TrustManagerFactory tmf = TrustManagerFactory.getInstance(tmfAlgorithm); - tmf.init(keyStore); - - // Create an SSLContext that uses our TrustManager - SSLContext context = SSLContext.getInstance("TLS"); - context.init(null, tmf.getTrustManagers(), null); - - return context.getSocketFactory(); - } - - /** - * Downloads the string that's in the url with any certificate. - */ - private String downloadWithoutCA(URL url) { - String string = ""; - try { - - HostnameVerifier hostnameVerifier = new HostnameVerifier() { - @Override - public boolean verify(String hostname, SSLSession session) { - return true; - } - }; - - class DefaultTrustManager implements X509TrustManager { - - @Override - public void checkClientTrusted(X509Certificate[] arg0, String arg1) throws CertificateException {} - - @Override - public void checkServerTrusted(X509Certificate[] arg0, String arg1) throws CertificateException {} - - @Override - public X509Certificate[] getAcceptedIssuers() { - return null; - } - } - - SSLContext context = SSLContext.getInstance("TLS"); - context.init(new KeyManager[0], new TrustManager[] {new DefaultTrustManager()}, new SecureRandom()); - - HttpsURLConnection urlConnection = (HttpsURLConnection)url.openConnection(); - urlConnection.setSSLSocketFactory(context.getSocketFactory()); - urlConnection.setHostnameVerifier(hostnameVerifier); - string = new Scanner(urlConnection.getInputStream()).useDelimiter("\\A").next(); - System.out.println("String ignoring certificate = " + string); - } catch (FileNotFoundException e) { - e.printStackTrace(); - displayToast(R.string.server_is_down_message); - } catch (IOException e) { - // The downloaded certificate doesn't validate our https connection. - e.printStackTrace(); - displayToast(R.string.certificate_error); - } catch (NoSuchAlgorithmException e) { - // TODO Auto-generated catch block - e.printStackTrace(); - } catch (KeyManagementException e) { - // TODO Auto-generated catch block - e.printStackTrace(); - } - return string; - } - - /** - * Tries to guess the provider.json url given the main provider url. - * @param provider_main_url - * @return the guessed provider.json url - */ - private String guessProviderDotJsonURL(String provider_main_url) { - return provider_main_url + "/provider.json"; - } - - /** - * Logs out from the api url retrieved from the task. - * @param task containing api url from which the user will log out - * @return true if there were no exceptions - */ - private boolean logOut(Bundle task) { - try { - String delete_url = task.getString(Provider.API_URL) + "/logout"; - - HttpsURLConnection urlConnection = (HttpsURLConnection)new URL(delete_url).openConnection(); - urlConnection.setRequestMethod("DELETE"); - urlConnection.setSSLSocketFactory(getProviderSSLSocketFactory()); - - int responseCode = urlConnection.getResponseCode(); - Log.d("logout", Integer.toString(responseCode)); - } catch (ClientProtocolException e) { - // TODO Auto-generated catch block - e.printStackTrace(); - return false; - } catch (IndexOutOfBoundsException e) { - // TODO Auto-generated catch block - e.printStackTrace(); - return false; - } catch (IOException e) { - // TODO Auto-generated catch block - e.printStackTrace(); - return false; - } catch (KeyManagementException e) { - // TODO Auto-generated catch block - e.printStackTrace(); - } catch (KeyStoreException e) { - // TODO Auto-generated catch block - e.printStackTrace(); - } catch (NoSuchAlgorithmException e) { - // TODO Auto-generated catch block - e.printStackTrace(); - } catch (CertificateException e) { - // TODO Auto-generated catch block - e.printStackTrace(); - } - return true; - } - - /** - * Downloads a new OpenVPN certificate, attaching authenticated cookie for authenticated certificate. - * - * @param task containing the type of the certificate to be downloaded - * @return true if certificate was downloaded correctly, false if provider.json or danger_on flag are not present in SharedPreferences, or if the certificate url could not be parsed as a URI, or if there was an SSL error. - */ - private boolean getNewCert(Bundle task) { - - try { - String type_of_certificate = task.getString(ConfigurationWizard.TYPE_OF_CERTIFICATE); - JSONObject provider_json = ConfigHelper.getJsonFromSharedPref(Provider.KEY); - URL provider_main_url = new URL(provider_json.getString(Provider.API_URL)); - String new_cert_string_url = provider_main_url.toString() + "/" + provider_json.getString(Provider.API_VERSION) + "/" + EIP.CERTIFICATE; - - boolean danger_on = ConfigHelper.getBoolFromSharedPref(ProviderItem.DANGER_ON); - String cert_string = downloadWithCommercialCA(new_cert_string_url, danger_on); - if(!cert_string.isEmpty()) { - // API returns concatenated cert & key. Split them for OpenVPN options - String certificateString = null, keyString = null; - String[] certAndKey = cert_string.split("(?<=-\n)"); - for (int i=0; i < certAndKey.length-1; i++){ - if ( certAndKey[i].contains("KEY") ) { - keyString = certAndKey[i++] + certAndKey[i]; - } - else if ( certAndKey[i].contains("CERTIFICATE") ) { - certificateString = certAndKey[i++] + certAndKey[i]; - } - } - try { - RSAPrivateKey keyCert = ConfigHelper.parseRsaKeyFromString(keyString); - keyString = Base64.encodeToString( keyCert.getEncoded(), Base64.DEFAULT ); - ConfigHelper.saveSharedPref(EIP.PRIVATE_KEY, "-----BEGIN RSA PRIVATE KEY-----\n"+keyString+"-----END RSA PRIVATE KEY-----"); - - X509Certificate certCert = ConfigHelper.parseX509CertificateFromString(certificateString); - certificateString = Base64.encodeToString( certCert.getEncoded(), Base64.DEFAULT); - ConfigHelper.saveSharedPref(EIP.CERTIFICATE, "-----BEGIN CERTIFICATE-----\n"+certificateString+"-----END CERTIFICATE-----"); - - return true; - } catch (CertificateException e) { - // TODO Auto-generated catch block - e.printStackTrace(); - return false; - } - } else { - return false; - } - } catch (IOException e) { - // TODO Auto-generated catch block - e.printStackTrace(); - return false; - } catch (JSONException e) { - // TODO Auto-generated catch block - e.printStackTrace(); - return false; - } /*catch (URISyntaxException e) { - // TODO Auto-generated catch block - e.printStackTrace(); - return false; - }*/ - } -} diff --git a/src/se/leap/leapclient/ProviderAPIResultReceiver.java b/src/se/leap/leapclient/ProviderAPIResultReceiver.java deleted file mode 100644 index d82484c8..00000000 --- a/src/se/leap/leapclient/ProviderAPIResultReceiver.java +++ /dev/null @@ -1,56 +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 . - */ - package se.leap.leapclient; - -import android.os.Bundle; -import android.os.Handler; -import android.os.ResultReceiver; - -/** - * Implements the ResultReceiver needed by Activities using ProviderAPI to receive the results of its operations. - * @author parmegv - * - */ -public class ProviderAPIResultReceiver extends ResultReceiver { - private Receiver mReceiver; - - public ProviderAPIResultReceiver(Handler handler) { - super(handler); - // TODO Auto-generated constructor stub - } - - public void setReceiver(Receiver receiver) { - mReceiver = receiver; - } - - /** - * Interface to enable ProviderAPIResultReceiver to receive results from the ProviderAPI IntentService. - * @author parmegv - * - */ - public interface Receiver { - public void onReceiveResult(int resultCode, Bundle resultData); - } - - @Override - protected void onReceiveResult(int resultCode, Bundle resultData) { - if (mReceiver != null) { - mReceiver.onReceiveResult(resultCode, resultData); - } - } - -} diff --git a/src/se/leap/leapclient/ProviderDetailFragment.java b/src/se/leap/leapclient/ProviderDetailFragment.java deleted file mode 100644 index e7af140a..00000000 --- a/src/se/leap/leapclient/ProviderDetailFragment.java +++ /dev/null @@ -1,113 +0,0 @@ -package se.leap.leapclient; - -import org.json.JSONException; -import org.json.JSONObject; - -import se.leap.leapclient.ProviderListContent.ProviderItem; - -import android.app.Activity; -import android.app.AlertDialog; -import android.app.Dialog; -import android.app.DialogFragment; -import android.content.DialogInterface; -import android.os.Bundle; -import android.view.LayoutInflater; -import android.view.View; -import android.widget.TextView; - -public class ProviderDetailFragment extends DialogFragment { - - final public static String TAG = "providerDetailFragment"; - - @Override - public Dialog onCreateDialog(Bundle savedInstanceState) { - AlertDialog.Builder builder = new AlertDialog.Builder(getActivity()); - try { - - LayoutInflater inflater = getActivity().getLayoutInflater(); - View provider_detail_view = inflater.inflate(R.layout.provider_detail_fragment, null); - - JSONObject provider_json = ConfigHelper.getJsonFromSharedPref(Provider.KEY); - - final TextView domain = (TextView)provider_detail_view.findViewById(R.id.provider_detail_domain); - domain.setText(provider_json.getString(Provider.DOMAIN)); - final TextView name = (TextView)provider_detail_view.findViewById(R.id.provider_detail_name); - name.setText(provider_json.getJSONObject(Provider.NAME).getString("en")); - final TextView description = (TextView)provider_detail_view.findViewById(R.id.provider_detail_description); - description.setText(provider_json.getJSONObject(Provider.DESCRIPTION).getString("en")); - - builder.setView(provider_detail_view); - builder.setTitle(R.string.provider_details_fragment_title); - - if(anon_allowed(provider_json)) { - builder.setPositiveButton(R.string.use_anonymously_button, new DialogInterface.OnClickListener() { - public void onClick(DialogInterface dialog, int id) { - interface_with_configuration_wizard.use_anonymously(); - } - }); - } - - if(registration_allowed(provider_json)) { - builder.setNegativeButton(R.string.login_button, new DialogInterface.OnClickListener() { - public void onClick(DialogInterface dialog, int id) { - interface_with_configuration_wizard.login(); - } - }); - } - - return builder.create(); - } catch (JSONException e) { - return null; - } - } - - private boolean anon_allowed(JSONObject provider_json) { - try { - JSONObject service_description = provider_json.getJSONObject(Provider.SERVICE); - return service_description.has(EIP.ALLOWED_ANON) && service_description.getBoolean(EIP.ALLOWED_ANON); - } catch (JSONException e) { - return false; - } - } - - private boolean registration_allowed(JSONObject provider_json) { - try { - JSONObject service_description = provider_json.getJSONObject(Provider.SERVICE); - return service_description.has(Provider.ALLOW_REGISTRATION) && service_description.getBoolean(Provider.ALLOW_REGISTRATION); - } catch (JSONException e) { - return false; - } - } - - @Override - public void onCancel(DialogInterface dialog) { - super.onCancel(dialog); - ConfigHelper.removeFromSharedPref(Provider.KEY); - ConfigHelper.removeFromSharedPref(ProviderItem.DANGER_ON); - ConfigHelper.removeFromSharedPref(EIP.ALLOWED_ANON); - ConfigHelper.removeFromSharedPref(EIP.KEY); - } - - public static DialogFragment newInstance() { - ProviderDetailFragment provider_detail_fragment = new ProviderDetailFragment(); - return provider_detail_fragment; - } - - @Override - public void onAttach(Activity activity) { - super.onAttach(activity); - try { - interface_with_configuration_wizard = (ProviderDetailFragmentInterface) activity; - } catch (ClassCastException e) { - throw new ClassCastException(activity.toString() - + " must implement LogInDialogListener"); - } - } - - public interface ProviderDetailFragmentInterface { - public void login(); - public void use_anonymously(); - } - - ProviderDetailFragmentInterface interface_with_configuration_wizard; -} diff --git a/src/se/leap/leapclient/ProviderListContent.java b/src/se/leap/leapclient/ProviderListContent.java deleted file mode 100644 index 6cd92430..00000000 --- a/src/se/leap/leapclient/ProviderListContent.java +++ /dev/null @@ -1,146 +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 . - */ - package se.leap.leapclient; - -import java.io.IOException; -import java.io.InputStream; -import java.util.ArrayList; -import java.util.HashMap; -import java.util.List; -import java.util.Map; -import java.net.URL; -import java.net.MalformedURLException; - -import org.json.JSONException; -import org.json.JSONObject; - -/** - * Models the provider list shown in the ConfigurationWizard. - * - * @author parmegv - * - */ -public class ProviderListContent { - - public static List ITEMS = new ArrayList(); - - public static Map ITEM_MAP = new HashMap(); - - /** - * Adds a new provider item to the end of the items map, and to the items list. - * @param item - */ - public static void addItem(ProviderItem item) { - ITEMS.add(item); - ITEM_MAP.put(String.valueOf(ITEMS.size()), item); - } - - /** - * A provider item. - */ - public static class ProviderItem { - - - final public static String CUSTOM = "custom"; - final public static String DANGER_ON = "danger_on"; - - public boolean custom = false; - public String id; - public String name; - public String domain; - public String provider_json_url; - public JSONObject provider_json; - public String provider_json_filename; - public String eip_service_json_url; - public String cert_json_url; - public boolean danger_on = false; - - /** - * @param name of the provider - * @param urls_file_input_stream file input stream linking with the assets url file - * @param custom if it's a new provider entered by the user or not - * @param danger_on if the user trusts completely the new provider - */ - public ProviderItem(String name, InputStream urls_file_input_stream, boolean custom, boolean danger_on) { - - try { - byte[] urls_file_bytes = new byte[urls_file_input_stream.available()]; - urls_file_input_stream.read(urls_file_bytes); - String urls_file_content = new String(urls_file_bytes); - JSONObject file_contents = new JSONObject(urls_file_content); - id = name; - this.name = name; - provider_json_url = file_contents.getString(Provider.DOT_JSON_URL); - domain = new URL(provider_json_url).getHost(); - //provider_json_filename = file_contents.getString("assets_json_provider"); - eip_service_json_url = file_contents.getString("json_eip_service"); - cert_json_url = file_contents.getString(EIP.CERTIFICATE); - this.custom = custom; - this.danger_on = danger_on; - } catch (MalformedURLException e) { - // TODO Auto-generated catch block - e.printStackTrace(); - } catch (JSONException e) { - // TODO Auto-generated catch block - e.printStackTrace(); - } catch (IOException e) { - // TODO Auto-generated catch block - e.printStackTrace(); - } - } - - /** - * @param name of the provider - * @param provider_json_url used to download provider.json file of the provider - * @param provider_json already downloaded - * @param custom if it's a new provider entered by the user or not - * @param danger_on if the user trusts completely the new provider - */ - public ProviderItem(String name, String provider_json_url, JSONObject provider_json, boolean custom, boolean danger_on) { - - try { - id = name; - //this.name = name; - this.provider_json_url = provider_json_url; - this.provider_json = provider_json; - this.name = provider_json.getJSONObject("name").getString("en"); - domain = new URL(provider_json_url).getHost(); - eip_service_json_url = provider_json.getString(Provider.API_URL) + "/" + provider_json.getString(Provider.API_VERSION) + "/" + EIP.SERVICE_API_PATH; - cert_json_url = provider_json.getString("ca_cert_uri"); - this.custom = custom; - this.danger_on = danger_on; - if(custom) - provider_json_filename = name + "_provider.json".replaceFirst("__", "_"); - } catch (MalformedURLException e) { - // TODO Auto-generated catch block - e.printStackTrace(); - } catch (JSONException e) { - // TODO Auto-generated catch block - e.printStackTrace(); - } - } - - @Override - public String toString() { - return name; - } - - public String getName() { - return id; - } - } -} diff --git a/src/se/leap/leapclient/ProviderListFragment.java b/src/se/leap/leapclient/ProviderListFragment.java deleted file mode 100644 index 2fca20e2..00000000 --- a/src/se/leap/leapclient/ProviderListFragment.java +++ /dev/null @@ -1,191 +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 . - */ - package se.leap.leapclient; - -import se.leap.leapclient.ProviderListContent.ProviderItem; -import android.app.Activity; -import android.app.ListFragment; -import android.os.Bundle; -import android.view.LayoutInflater; -import android.view.View; -import android.view.ViewGroup; -import android.widget.ArrayAdapter; -import android.widget.ListView; -import android.content.Context; -import android.widget.TwoLineListItem; - -/** - * A list fragment representing a list of Providers. This fragment - * also supports tablet devices by allowing list items to be given an - * 'activated' state upon selection. This helps indicate which item is - * currently being viewed in a {@link DashboardFragment}. - *

- * Activities containing this fragment MUST implement the {@link Callbacks} - * interface. - */ -public class ProviderListFragment extends ListFragment { - - private ArrayAdapter content_adapter; - - /** - * The serialization (saved instance state) Bundle key representing the - * activated item position. Only used on tablets. - */ - private static final String STATE_ACTIVATED_POSITION = "activated_position"; - - /** - * The fragment's current callback object, which is notified of list item - * clicks. - */ - private Callbacks mCallbacks = sDummyCallbacks; - - /** - * The current activated item position. Only used on tablets. - */ - private int mActivatedPosition = ListView.INVALID_POSITION; - - /** - * A callback interface that all activities containing this fragment must - * implement. This mechanism allows activities to be notified of item - * selections. - */ - public interface Callbacks { - /** - * Callback for when an item has been selected. - */ - public void onItemSelected(String id); - } - - /** - * A dummy implementation of the {@link Callbacks} interface that does - * nothing. Used only when this fragment is not attached to an activity. - */ - private static Callbacks sDummyCallbacks = new Callbacks() { - @Override - public void onItemSelected(String id) { - } - }; - - /** - * Mandatory empty constructor for the fragment manager to instantiate the - * fragment (e.g. upon screen orientation changes). - */ - public ProviderListFragment() { - } - - @Override - public void onCreate(Bundle savedInstanceState) { - super.onCreate(savedInstanceState); - content_adapter = new ArrayAdapter( - getActivity(), - android.R.layout.simple_list_item_activated_2, - ProviderListContent.ITEMS) { - @Override - public View getView(int position, View convertView, ViewGroup parent){ - TwoLineListItem row; - if (convertView == null) { - LayoutInflater inflater = (LayoutInflater)getActivity().getApplicationContext().getSystemService(Context.LAYOUT_INFLATER_SERVICE); - row = (TwoLineListItem)inflater.inflate(android.R.layout.simple_list_item_2, null); - } else { - row = (TwoLineListItem)convertView; - } - ProviderListContent.ProviderItem data = ProviderListContent.ITEMS.get(position); - row.getText1().setText(data.domain); - row.getText2().setText(data.name); - - return row; - } - }; - setListAdapter(content_adapter); - } - - @Override - public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle bundle) { - return inflater.inflate(R.layout.provider_list_fragment, container, false); - } - - @Override - public void onViewCreated(View view, Bundle savedInstanceState) { - super.onViewCreated(view, savedInstanceState); - - // Restore the previously serialized activated item position. - if (savedInstanceState != null - && savedInstanceState.containsKey(STATE_ACTIVATED_POSITION)) { - setActivatedPosition(savedInstanceState.getInt(STATE_ACTIVATED_POSITION)); - } - } - - @Override - public void onAttach(Activity activity) { - super.onAttach(activity); - - // Activities containing this fragment must implement its callbacks. - if (!(activity instanceof Callbacks)) { - throw new IllegalStateException("Activity must implement fragment's callbacks."); - } - - mCallbacks = (Callbacks) activity; - } - - @Override - public void onDetach() { - super.onDetach(); - - // Reset the active callbacks interface to the dummy implementation. - mCallbacks = sDummyCallbacks; - } - - @Override - public void onListItemClick(ListView listView, View view, int position, long id) { - super.onListItemClick(listView, view, position, id); - - // Notify the active callbacks interface (the activity, if the - // fragment is attached to one) that an item has been selected. - mCallbacks.onItemSelected(ProviderListContent.ITEMS.get(position).id); - } - - @Override - public void onSaveInstanceState(Bundle outState) { - super.onSaveInstanceState(outState); - if (mActivatedPosition != ListView.INVALID_POSITION) { - // Serialize and persist the activated item position. - outState.putInt(STATE_ACTIVATED_POSITION, mActivatedPosition); - } - } - - /** - * Turns on activate-on-click mode. When this mode is on, list items will be - * given the 'activated' state when touched. - */ - public void setActivateOnItemClick(boolean activateOnItemClick) { - // When setting CHOICE_MODE_SINGLE, ListView will automatically - // give items the 'activated' state when touched. - getListView().setChoiceMode(activateOnItemClick - ? ListView.CHOICE_MODE_SINGLE - : ListView.CHOICE_MODE_NONE); - } - - private void setActivatedPosition(int position) { - if (position == ListView.INVALID_POSITION) { - getListView().setItemChecked(mActivatedPosition, false); - } else { - getListView().setItemChecked(position, true); - } - - mActivatedPosition = position; - } -} diff --git a/src/se/leap/openvpn/ConfigConverter.java b/src/se/leap/openvpn/ConfigConverter.java index 8b5f316d..3c6bf91e 100644 --- a/src/se/leap/openvpn/ConfigConverter.java +++ b/src/se/leap/openvpn/ConfigConverter.java @@ -9,7 +9,8 @@ import java.io.InputStream; import java.io.InputStreamReader; import java.util.List; import java.util.Vector; -import se.leap.leapclient.R; + +import se.leap.bitmaskclient.R; import android.app.Activity; import android.app.AlertDialog; diff --git a/src/se/leap/openvpn/FaqFragment.java b/src/se/leap/openvpn/FaqFragment.java index 2b9f02eb..dc498087 100644 --- a/src/se/leap/openvpn/FaqFragment.java +++ b/src/se/leap/openvpn/FaqFragment.java @@ -8,7 +8,7 @@ import android.view.LayoutInflater; import android.view.View; import android.view.ViewGroup; import android.widget.TextView; -import se.leap.leapclient.R; +import se.leap.bitmaskclient.R; public class FaqFragment extends Fragment { diff --git a/src/se/leap/openvpn/FileSelect.java b/src/se/leap/openvpn/FileSelect.java index 4abf6c31..4b88e7a7 100644 --- a/src/se/leap/openvpn/FileSelect.java +++ b/src/se/leap/openvpn/FileSelect.java @@ -6,7 +6,8 @@ import java.io.FileInputStream; import java.io.FileNotFoundException; import java.io.IOException; import java.io.InputStream; -import se.leap.leapclient.R; + +import se.leap.bitmaskclient.R; import android.app.ActionBar; import android.app.ActionBar.Tab; diff --git a/src/se/leap/openvpn/FileSelectLayout.java b/src/se/leap/openvpn/FileSelectLayout.java index 2ca4490d..ec5f3636 100644 --- a/src/se/leap/openvpn/FileSelectLayout.java +++ b/src/se/leap/openvpn/FileSelectLayout.java @@ -10,7 +10,7 @@ import android.view.View.OnClickListener; import android.widget.Button; import android.widget.LinearLayout; import android.widget.TextView; -import se.leap.leapclient.R; +import se.leap.bitmaskclient.R; public class FileSelectLayout extends LinearLayout implements OnClickListener { diff --git a/src/se/leap/openvpn/FileSelectionFragment.java b/src/se/leap/openvpn/FileSelectionFragment.java index 5bc981fe..80cb2c62 100644 --- a/src/se/leap/openvpn/FileSelectionFragment.java +++ b/src/se/leap/openvpn/FileSelectionFragment.java @@ -5,7 +5,8 @@ import java.util.ArrayList; import java.util.HashMap; import java.util.List; import java.util.TreeMap; -import se.leap.leapclient.R; + +import se.leap.bitmaskclient.R; import android.app.AlertDialog; import android.app.ListFragment; diff --git a/src/se/leap/openvpn/GeneralSettings.java b/src/se/leap/openvpn/GeneralSettings.java index 34657914..93e4818e 100644 --- a/src/se/leap/openvpn/GeneralSettings.java +++ b/src/se/leap/openvpn/GeneralSettings.java @@ -1,6 +1,7 @@ package se.leap.openvpn; import java.io.File; -import se.leap.leapclient.R; + +import se.leap.bitmaskclient.R; import android.os.Bundle; import android.preference.Preference; diff --git a/src/se/leap/openvpn/InlineFileTab.java b/src/se/leap/openvpn/InlineFileTab.java index 40995ceb..9e8041c0 100644 --- a/src/se/leap/openvpn/InlineFileTab.java +++ b/src/se/leap/openvpn/InlineFileTab.java @@ -9,7 +9,7 @@ import android.view.MenuItem; import android.view.View; import android.view.ViewGroup; import android.widget.EditText; -import se.leap.leapclient.R; +import se.leap.bitmaskclient.R; public class InlineFileTab extends Fragment { diff --git a/src/se/leap/openvpn/LaunchVPN.java b/src/se/leap/openvpn/LaunchVPN.java index 73003c7e..89f2d372 100644 --- a/src/se/leap/openvpn/LaunchVPN.java +++ b/src/se/leap/openvpn/LaunchVPN.java @@ -20,9 +20,9 @@ import java.io.IOException; import java.util.Collection; import java.util.Vector; -import se.leap.leapclient.ConfigHelper; -import se.leap.leapclient.EIP; -import se.leap.leapclient.R; +import se.leap.bitmaskclient.ConfigHelper; +import se.leap.bitmaskclient.EIP; +import se.leap.bitmaskclient.R; import android.app.Activity; import android.app.AlertDialog; diff --git a/src/se/leap/openvpn/LogWindow.java b/src/se/leap/openvpn/LogWindow.java index abd1acd6..c3ce8424 100644 --- a/src/se/leap/openvpn/LogWindow.java +++ b/src/se/leap/openvpn/LogWindow.java @@ -1,7 +1,8 @@ package se.leap.openvpn; import java.util.Vector; -import se.leap.leapclient.R; + +import se.leap.bitmaskclient.R; import android.app.AlertDialog; import android.app.AlertDialog.Builder; diff --git a/src/se/leap/openvpn/MainActivity.java b/src/se/leap/openvpn/MainActivity.java index d33fd832..0a769b4d 100644 --- a/src/se/leap/openvpn/MainActivity.java +++ b/src/se/leap/openvpn/MainActivity.java @@ -1,7 +1,8 @@ package se.leap.openvpn; import java.util.List; -import se.leap.leapclient.R; + +import se.leap.bitmaskclient.R; import android.content.Intent; import android.preference.PreferenceActivity; diff --git a/src/se/leap/openvpn/NetworkSateReceiver.java b/src/se/leap/openvpn/NetworkSateReceiver.java index 301803b6..777402b4 100644 --- a/src/se/leap/openvpn/NetworkSateReceiver.java +++ b/src/se/leap/openvpn/NetworkSateReceiver.java @@ -8,7 +8,7 @@ import android.net.ConnectivityManager; import android.net.NetworkInfo; import android.net.NetworkInfo.State; import android.preference.PreferenceManager; -import se.leap.leapclient.R; +import se.leap.bitmaskclient.R; public class NetworkSateReceiver extends BroadcastReceiver { private int lastNetwork=-1; diff --git a/src/se/leap/openvpn/OpenVPN.java b/src/se/leap/openvpn/OpenVPN.java index 3ffc47cb..c6055abd 100644 --- a/src/se/leap/openvpn/OpenVPN.java +++ b/src/se/leap/openvpn/OpenVPN.java @@ -3,7 +3,8 @@ package se.leap.openvpn; import java.util.LinkedList; import java.util.Locale; import java.util.Vector; -import se.leap.leapclient.R; + +import se.leap.bitmaskclient.R; import android.content.Context; diff --git a/src/se/leap/openvpn/OpenVPNThread.java b/src/se/leap/openvpn/OpenVPNThread.java index 3f9a0d91..0c383ab0 100644 --- a/src/se/leap/openvpn/OpenVPNThread.java +++ b/src/se/leap/openvpn/OpenVPNThread.java @@ -7,7 +7,8 @@ import java.io.IOException; import java.io.InputStream; import java.io.InputStreamReader; import java.util.LinkedList; -import se.leap.leapclient.R; + +import se.leap.bitmaskclient.R; import android.util.Log; import se.leap.openvpn.OpenVPN.LogItem; diff --git a/src/se/leap/openvpn/OpenVpnManagementThread.java b/src/se/leap/openvpn/OpenVpnManagementThread.java index 43d4f701..028c6ec7 100644 --- a/src/se/leap/openvpn/OpenVpnManagementThread.java +++ b/src/se/leap/openvpn/OpenVpnManagementThread.java @@ -17,7 +17,8 @@ import javax.crypto.BadPaddingException; import javax.crypto.Cipher; import javax.crypto.IllegalBlockSizeException; import javax.crypto.NoSuchPaddingException; -import se.leap.leapclient.R; + +import se.leap.bitmaskclient.R; import android.content.SharedPreferences; import android.net.LocalServerSocket; diff --git a/src/se/leap/openvpn/OpenVpnPreferencesFragment.java b/src/se/leap/openvpn/OpenVpnPreferencesFragment.java index 31746332..190a48fe 100644 --- a/src/se/leap/openvpn/OpenVpnPreferencesFragment.java +++ b/src/se/leap/openvpn/OpenVpnPreferencesFragment.java @@ -2,7 +2,7 @@ package se.leap.openvpn; import android.os.Bundle; import android.preference.PreferenceFragment; -import se.leap.leapclient.R; +import se.leap.bitmaskclient.R; public abstract class OpenVpnPreferencesFragment extends PreferenceFragment { diff --git a/src/se/leap/openvpn/OpenVpnService.java b/src/se/leap/openvpn/OpenVpnService.java index 47f9ca44..bec7dcee 100644 --- a/src/se/leap/openvpn/OpenVpnService.java +++ b/src/se/leap/openvpn/OpenVpnService.java @@ -5,8 +5,8 @@ import java.lang.reflect.InvocationTargetException; import java.lang.reflect.Method; import java.util.Vector; -import se.leap.leapclient.Dashboard; -import se.leap.leapclient.R; +import se.leap.bitmaskclient.Dashboard; +import se.leap.bitmaskclient.R; import android.annotation.TargetApi; import android.app.Notification; diff --git a/src/se/leap/openvpn/ProxyDetection.java b/src/se/leap/openvpn/ProxyDetection.java index 7114857d..c7b3d196 100644 --- a/src/se/leap/openvpn/ProxyDetection.java +++ b/src/se/leap/openvpn/ProxyDetection.java @@ -8,7 +8,8 @@ import java.net.SocketAddress; import java.net.URISyntaxException; import java.net.URL; import java.util.List; -import se.leap.leapclient.R; + +import se.leap.bitmaskclient.R; public class ProxyDetection { static SocketAddress detectProxy(VpnProfile vp) { diff --git a/src/se/leap/openvpn/Settings_Authentication.java b/src/se/leap/openvpn/Settings_Authentication.java index 00f4c08a..7824d790 100644 --- a/src/se/leap/openvpn/Settings_Authentication.java +++ b/src/se/leap/openvpn/Settings_Authentication.java @@ -11,7 +11,7 @@ import android.preference.Preference; import android.preference.Preference.OnPreferenceChangeListener; import android.preference.Preference.OnPreferenceClickListener; import android.preference.SwitchPreference; -import se.leap.leapclient.R; +import se.leap.bitmaskclient.R; public class Settings_Authentication extends OpenVpnPreferencesFragment implements OnPreferenceChangeListener, OnPreferenceClickListener { diff --git a/src/se/leap/openvpn/Settings_Basic.java b/src/se/leap/openvpn/Settings_Basic.java index f3510da9..014c71a1 100644 --- a/src/se/leap/openvpn/Settings_Basic.java +++ b/src/se/leap/openvpn/Settings_Basic.java @@ -39,8 +39,8 @@ import android.widget.EditText; import android.widget.Spinner; import android.widget.TextView; import android.widget.ToggleButton; -import se.leap.leapclient.R.id; -import se.leap.leapclient.R; +import se.leap.bitmaskclient.R; +import se.leap.bitmaskclient.R.id; public class Settings_Basic extends Fragment implements View.OnClickListener, OnItemSelectedListener, Callback { private static final int CHOOSE_FILE_OFFSET = 1000; diff --git a/src/se/leap/openvpn/Settings_IP.java b/src/se/leap/openvpn/Settings_IP.java index df2efb40..bb605937 100644 --- a/src/se/leap/openvpn/Settings_IP.java +++ b/src/se/leap/openvpn/Settings_IP.java @@ -6,7 +6,7 @@ import android.preference.Preference; import android.preference.Preference.OnPreferenceChangeListener; import android.preference.PreferenceManager; import android.preference.SwitchPreference; -import se.leap.leapclient.R; +import se.leap.bitmaskclient.R; public class Settings_IP extends OpenVpnPreferencesFragment implements OnPreferenceChangeListener { private EditTextPreference mIPv4; diff --git a/src/se/leap/openvpn/Settings_Obscure.java b/src/se/leap/openvpn/Settings_Obscure.java index ffbce971..6ba98606 100644 --- a/src/se/leap/openvpn/Settings_Obscure.java +++ b/src/se/leap/openvpn/Settings_Obscure.java @@ -6,7 +6,7 @@ import android.preference.EditTextPreference; import android.preference.ListPreference; import android.preference.Preference; import android.preference.Preference.OnPreferenceChangeListener; -import se.leap.leapclient.R; +import se.leap.bitmaskclient.R; public class Settings_Obscure extends OpenVpnPreferencesFragment implements OnPreferenceChangeListener { private CheckBoxPreference mUseRandomHostName; diff --git a/src/se/leap/openvpn/Settings_Routing.java b/src/se/leap/openvpn/Settings_Routing.java index 48c09ff0..3cbdac0f 100644 --- a/src/se/leap/openvpn/Settings_Routing.java +++ b/src/se/leap/openvpn/Settings_Routing.java @@ -4,7 +4,7 @@ import android.preference.CheckBoxPreference; import android.preference.EditTextPreference; import android.preference.Preference; import android.preference.Preference.OnPreferenceChangeListener; -import se.leap.leapclient.R; +import se.leap.bitmaskclient.R; public class Settings_Routing extends OpenVpnPreferencesFragment implements OnPreferenceChangeListener { diff --git a/src/se/leap/openvpn/ShowConfigFragment.java b/src/se/leap/openvpn/ShowConfigFragment.java index 9bce67a6..194f87d4 100644 --- a/src/se/leap/openvpn/ShowConfigFragment.java +++ b/src/se/leap/openvpn/ShowConfigFragment.java @@ -10,7 +10,7 @@ import android.view.MenuItem; import android.view.View; import android.view.ViewGroup; import android.widget.TextView; -import se.leap.leapclient.R; +import se.leap.bitmaskclient.R; public class ShowConfigFragment extends Fragment { diff --git a/src/se/leap/openvpn/VPNLaunchHelper.java b/src/se/leap/openvpn/VPNLaunchHelper.java index 59303748..418cf7e9 100644 --- a/src/se/leap/openvpn/VPNLaunchHelper.java +++ b/src/se/leap/openvpn/VPNLaunchHelper.java @@ -4,7 +4,8 @@ import java.io.File; import java.io.FileOutputStream; import java.io.IOException; import java.io.InputStream; -import se.leap.leapclient.R; + +import se.leap.bitmaskclient.R; import android.content.Context; import android.content.Intent; diff --git a/src/se/leap/openvpn/VPNPreferences.java b/src/se/leap/openvpn/VPNPreferences.java index 81d854ce..e3052050 100644 --- a/src/se/leap/openvpn/VPNPreferences.java +++ b/src/se/leap/openvpn/VPNPreferences.java @@ -1,7 +1,8 @@ package se.leap.openvpn; import java.util.List; -import se.leap.leapclient.R; + +import se.leap.bitmaskclient.R; import android.app.AlertDialog; import android.content.DialogInterface; diff --git a/src/se/leap/openvpn/VPNProfileList.java b/src/se/leap/openvpn/VPNProfileList.java index a7132c9e..0ef611df 100644 --- a/src/se/leap/openvpn/VPNProfileList.java +++ b/src/se/leap/openvpn/VPNProfileList.java @@ -3,7 +3,8 @@ package se.leap.openvpn; import java.util.Collection; import java.util.Comparator; import java.util.TreeSet; -import se.leap.leapclient.R; + +import se.leap.bitmaskclient.R; import android.app.Activity; import android.app.AlertDialog; diff --git a/src/se/leap/openvpn/VpnProfile.java b/src/se/leap/openvpn/VpnProfile.java index 5752081a..8eebb763 100644 --- a/src/se/leap/openvpn/VpnProfile.java +++ b/src/se/leap/openvpn/VpnProfile.java @@ -21,10 +21,10 @@ import java.util.Vector; import org.spongycastle.util.io.pem.PemObject; import org.spongycastle.util.io.pem.PemWriter; -import se.leap.leapclient.ConfigHelper; -import se.leap.leapclient.EIP; -import se.leap.leapclient.Provider; -import se.leap.leapclient.R; +import se.leap.bitmaskclient.ConfigHelper; +import se.leap.bitmaskclient.EIP; +import se.leap.bitmaskclient.Provider; +import se.leap.bitmaskclient.R; import android.content.Context; import android.content.Intent; @@ -50,7 +50,7 @@ public class VpnProfile implements Serializable{ public static final int TYPE_USERPASS_KEYSTORE = 7; // Don't change this, not all parts of the program use this constant - public static final String EXTRA_PROFILEUUID = "se.leap.leapclient.profileUUID"; // TODO this feels wrong. See Issue #1494 + public static final String EXTRA_PROFILEUUID = "se.leap.bitmaskclient.profileUUID"; // TODO this feels wrong. See Issue #1494 public static final String INLINE_TAG = "[[INLINE]]"; private static final String OVPNCONFIGFILE = "android.conf"; -- cgit v1.2.3 From 413b0c9d35527a9b16e1d3b1f4cf466be9fac6c4 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Parm=C3=A9nides=20GV?= Date: Thu, 10 Oct 2013 17:08:20 +0200 Subject: Project name changed to "bitmask_android". --- .project | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.project b/.project index 6c5495ad..3fb41079 100644 --- a/.project +++ b/.project @@ -1,6 +1,6 @@ - leap_android + bitmask_android -- cgit v1.2.3 From 0a24acb85b585b6ccd985fe58e2a831a20b51fa7 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Parm=C3=A9nides=20GV?= Date: Thu, 10 Oct 2013 17:13:13 +0200 Subject: Changed some documentation and scripts. --- README.txt | 12 ++++++------ build.xml | 2 +- compile.sh | 2 +- run.sh | 2 +- 4 files changed, 9 insertions(+), 9 deletions(-) diff --git a/README.txt b/README.txt index 7d57a6e3..c7dd933b 100644 --- a/README.txt +++ b/README.txt @@ -17,7 +17,7 @@ Instructions to compile Postconditions -------------- -1. $PROJECT_LOCATION/leap_android/bin/LEAP Android-debug.apk exists +1. $PROJECT_LOCATION/leap_android/bin/Bitmask Android-debug.apk exists Running on the emulator ========================= @@ -26,7 +26,7 @@ Preconditions ----------------- 1. Android SDK is installed, and its tools are in the PATH. -2. leap_android has been compiled. +2. Bitmask Android has been compiled. 3. An avd exists in ~/.android/avd/ (if you do not have one, follow instructions from http://developer.android.com/tools/devices/managing-avds-cmdline.html) Instructions to run on the emulator @@ -38,7 +38,7 @@ Instructions to run on the emulator Postconditions -------------- -1. LEAP Android is running. +1. Bitmask Android is running. Debugging from console ====================== @@ -47,7 +47,7 @@ Preconditions ----------------- 1. Android SDK is installed, and its tools are in the PATH. -2. leap_android has been compiled. +2. Bitmask Android has been compiled. 3. An avd exists in ~/.android/avd/ (if you do not have one, follow instructions from http://developer.android.com/tools/devices/managing-avds-cmdline.html). 4. jdb is installed (this program is part of OpenJDK 7) @@ -60,6 +60,6 @@ Instructions to debug from the console Postconditions -------------- -1. LEAP Android is running. -2. LEAP Android does not show the message "Application LEAP for Android (process se.leap.leapclient) is waiting for the debugger to attach". +1. Bitmask Android is running. +2. Bitmask Android does not show the message "Application Bitmask for Android (process se.leap.bitmaskclient) is waiting for the debugger to attach". 3. You are in a jdb debuggin session. diff --git a/build.xml b/build.xml index 538f2eee..56cf179f 100644 --- a/build.xml +++ b/build.xml @@ -1,5 +1,5 @@ - +