From 77c76fc1c856f73e1b6d072dbe27242fd707b586 Mon Sep 17 00:00:00 2001 From: Sean Leonard Date: Wed, 30 Jan 2013 22:22:49 -0700 Subject: Empty Provider.java file --- src/se/leap/leapclient/Provider.java | 0 1 file changed, 0 insertions(+), 0 deletions(-) create mode 100644 src/se/leap/leapclient/Provider.java (limited to 'src/se/leap/leapclient') diff --git a/src/se/leap/leapclient/Provider.java b/src/se/leap/leapclient/Provider.java new file mode 100644 index 00000000..e69de29b -- cgit v1.2.3 From 026ba24b0b3e3c47ce31cad4822e0c4beae1cd5e Mon Sep 17 00:00:00 2001 From: Sean Leonard Date: Wed, 30 Jan 2013 22:27:26 -0700 Subject: Provider class filled up quick ;) Resolves #1520 --- src/se/leap/leapclient/Provider.java | 162 +++++++++++++++++++++++++++++++++++ 1 file changed, 162 insertions(+) (limited to 'src/se/leap/leapclient') diff --git a/src/se/leap/leapclient/Provider.java b/src/se/leap/leapclient/Provider.java index e69de29b..a25909bf 100644 --- a/src/se/leap/leapclient/Provider.java +++ b/src/se/leap/leapclient/Provider.java @@ -0,0 +1,162 @@ +/** + * + */ +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.SharedPreferences; + +/** + * @author Sean Leonard + * + */ +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; + + + // 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_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(SharedPreferences preferences) { + + // 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... + + // Inflate our provider.json data + try { + definition = new JSONObject( preferences.getString("provider", "") ); + } catch (JSONException e) { + // TODO: handle exception + + // FIXME!! We want "real" data!! + } + } + + protected static Provider getInstance(SharedPreferences preferences){ + if(instance==null){ + instance = new Provider(preferences); + } + return instance; + } + + 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; + } + + public 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 Date: Wed, 30 Jan 2013 22:39:33 -0700 Subject: Empty Dashboard.java --- src/se/leap/leapclient/Dashboard.java | 0 1 file changed, 0 insertions(+), 0 deletions(-) create mode 100644 src/se/leap/leapclient/Dashboard.java (limited to 'src/se/leap/leapclient') diff --git a/src/se/leap/leapclient/Dashboard.java b/src/se/leap/leapclient/Dashboard.java new file mode 100644 index 00000000..e69de29b -- cgit v1.2.3 From c849913fba3f5b692309570415f85e9bdb8cceeb Mon Sep 17 00:00:00 2001 From: Sean Leonard Date: Wed, 30 Jan 2013 22:54:56 -0700 Subject: Beginnings of a Dashboard Activity Matching layout and menu XML And don't forget strings --- src/se/leap/leapclient/Dashboard.java | 71 +++++++++++++++++++++++++++++++++++ 1 file changed, 71 insertions(+) (limited to 'src/se/leap/leapclient') diff --git a/src/se/leap/leapclient/Dashboard.java b/src/se/leap/leapclient/Dashboard.java index e69de29b..50c267b3 100644 --- a/src/se/leap/leapclient/Dashboard.java +++ b/src/se/leap/leapclient/Dashboard.java @@ -0,0 +1,71 @@ +package se.leap.leapclient; + +import java.io.BufferedReader; +import java.io.IOException; +import java.io.InputStreamReader; + +import se.leap.openvpn.AboutFragment; +import se.leap.openvpn.MainActivity; +import android.app.Activity; +import android.app.Fragment; +import android.app.FragmentTransaction; +import android.content.Intent; +import android.content.SharedPreferences; +import android.content.res.AssetManager; +import android.os.Bundle; +import android.view.Menu; +import android.view.MenuItem; +import android.view.View; +import android.view.ViewStub; +import android.widget.CompoundButton; +import android.widget.Switch; +import android.widget.TextView; + +public class Dashboard extends Activity { + + private static SharedPreferences preferences; + private static Provider provider; + + private TextView providerNameTV; + private TextView eipTypeTV; + + @Override + protected void onCreate(Bundle savedInstanceState) { + super.onCreate(savedInstanceState); + setContentView(R.layout.client_dashboard); + + preferences = getPreferences(MODE_PRIVATE); + + // Get our provider + provider = Provider.getInstance(preferences); + + // Set provider name in textview + providerNameTV = (TextView) findViewById(R.id.providerName); + providerNameTV.setText(provider.getName()); + providerNameTV.setTextSize(28); // TODO maybe to some calculating, or a marquee? + } + + @Override + public boolean onCreateOptionsMenu(Menu menu) { + // Inflate the menu; this adds items to the action bar if it is present. + getMenuInflater().inflate(R.menu.client_dashboard, menu); + return true; + } + + @Override + public boolean onOptionsItemSelected(MenuItem item){ + Intent intent; + // Handle item selection + switch (item.getItemId()){ + case R.id.legacy_interface: + // TODO call se.leap.openvpn.MainActivity + intent = new Intent(this,MainActivity.class); + startActivity(intent); + return true; + default: + return super.onOptionsItemSelected(item); + } + + } + +} -- cgit v1.2.3 From 4bcb53cff01cb13530e1011fb6d5ac105be1ba25 Mon Sep 17 00:00:00 2001 From: Sean Leonard Date: Wed, 30 Jan 2013 23:10:26 -0700 Subject: Put some About love in the menu Needs attention, as the AboutFragment does not fill the layout You can still see providerLine Creates Issue #1592 --- src/se/leap/leapclient/Dashboard.java | 11 +++++++++++ 1 file changed, 11 insertions(+) (limited to 'src/se/leap/leapclient') diff --git a/src/se/leap/leapclient/Dashboard.java b/src/se/leap/leapclient/Dashboard.java index 50c267b3..3e8f35a4 100644 --- a/src/se/leap/leapclient/Dashboard.java +++ b/src/se/leap/leapclient/Dashboard.java @@ -57,6 +57,17 @@ public class Dashboard extends Activity { Intent intent; // Handle item selection switch (item.getItemId()){ + case R.id.about_leap: + // TODO move se.leap.openvpn.AboutFragment into our package + Fragment aboutFragment = new AboutFragment(); + FragmentTransaction trans = getFragmentManager().beginTransaction(); + trans.replace(R.id.dashboardLayout, aboutFragment); + trans.addToBackStack(null); + trans.commit(); + + //intent = new Intent(this,AboutFragment.class); + //startActivity(intent); + return true; case R.id.legacy_interface: // TODO call se.leap.openvpn.MainActivity intent = new Intent(this,MainActivity.class); -- cgit v1.2.3 From fea68f17a1a69bc3710e1b1b743e0d0ded95234a Mon Sep 17 00:00:00 2001 From: Sean Leonard Date: Wed, 30 Jan 2013 23:23:13 -0700 Subject: FIXME!! Here there be dragons. Of the "fake data seeded by seedy functions" variety, And there shady json files...Creates Issue #1593 --- src/se/leap/leapclient/Dashboard.java | 51 +++++++++++++++++++++++++++++++++++ 1 file changed, 51 insertions(+) (limited to 'src/se/leap/leapclient') diff --git a/src/se/leap/leapclient/Dashboard.java b/src/se/leap/leapclient/Dashboard.java index 3e8f35a4..cc215be9 100644 --- a/src/se/leap/leapclient/Dashboard.java +++ b/src/se/leap/leapclient/Dashboard.java @@ -36,6 +36,10 @@ public class Dashboard extends Activity { preferences = getPreferences(MODE_PRIVATE); + // FIXME provider data!! get parmegv's work so we can stop (or lessen) faking it + if ( !preferences.contains("provider") ) + fixmePrefsFaker(preferences); + // Get our provider provider = Provider.getInstance(preferences); @@ -45,6 +49,53 @@ public class Dashboard extends Activity { providerNameTV.setTextSize(28); // TODO maybe to some calculating, or a marquee? } + // FIXME!! We don't want you around here once we have something /real/ going on + private void fixmePrefsFaker(SharedPreferences fakeit) { + SharedPreferences.Editor fakes = fakeit.edit(); + + AssetManager am = getAssets(); + BufferedReader prov = null; + try { + prov = new BufferedReader(new InputStreamReader(am.open("providers/bitmask.net_provider.json"))); + } catch (IOException e) { + // TODO Auto-generated catch block + e.printStackTrace(); + } + BufferedReader serv = null; + try { + serv = new BufferedReader(new InputStreamReader(am.open("providers/bitmask.net_eip-service.json"))); + } catch (IOException e) { + // TODO Auto-generated catch block + e.printStackTrace(); + } + StringBuilder provider = new StringBuilder(); + StringBuilder eip = new StringBuilder(); + + String line; + try { + while ((line = prov.readLine()) != null){ + provider.append(line); + } + } catch (IOException e) { + // TODO Auto-generated catch block + e.printStackTrace(); + } + String providerjson = provider.toString(); + try { + while ((line = serv.readLine()) != null){ + eip.append(line); + } + } catch (IOException e) { + // TODO Auto-generated catch block + e.printStackTrace(); + } + String eipjson = eip.toString(); + + fakes.putString("provider", providerjson); + fakes.putString("eip", eipjson); + fakes.commit(); + } + @Override public boolean onCreateOptionsMenu(Menu menu) { // Inflate the menu; this adds items to the action bar if it is present. -- cgit v1.2.3 From b6e47ac59c3e853b23d4392eec33bbeb2f068f17 Mon Sep 17 00:00:00 2001 From: Sean Leonard Date: Wed, 30 Jan 2013 23:35:42 -0700 Subject: Add EIP Service item in Dashboard --- src/se/leap/leapclient/Dashboard.java | 33 +++++++++++++++++++++++++++++++++ 1 file changed, 33 insertions(+) (limited to 'src/se/leap/leapclient') diff --git a/src/se/leap/leapclient/Dashboard.java b/src/se/leap/leapclient/Dashboard.java index cc215be9..5835acb8 100644 --- a/src/se/leap/leapclient/Dashboard.java +++ b/src/se/leap/leapclient/Dashboard.java @@ -47,6 +47,10 @@ public class Dashboard extends Activity { providerNameTV = (TextView) findViewById(R.id.providerName); providerNameTV.setText(provider.getName()); providerNameTV.setTextSize(28); // TODO maybe to some calculating, or a marquee? + + // TODO Inflate layout fragments for provider's services + if ( provider.hasEIP() ) + serviceItemEIP(); } // FIXME!! We don't want you around here once we have something /real/ going on @@ -96,6 +100,35 @@ public class Dashboard extends Activity { fakes.commit(); } + private void serviceItemEIP() { + // FIXME Provider service (eip/openvpn) + View eipOverview = ((ViewStub) findViewById(R.id.eipOverviewStub)).inflate(); + + // Set our EIP type title + eipTypeTV = (TextView) findViewById(R.id.eipType); + eipTypeTV.setText(provider.getEIPType()); + + // TODO Bind our switch to run our EIP + // What happens when our VPN stops running? does it call the listener? + Switch eipSwitch = (Switch) findViewById(R.id.eipSwitch); + eipSwitch.setOnCheckedChangeListener(new CompoundButton.OnCheckedChangeListener() { + @Override + public void onCheckedChanged(CompoundButton buttonView, boolean isChecked) { + if ( isChecked ){ + //TODO startVPN(); + } else { + //TODO stopVPN(); + } + } + }); + + //TODO write our info into the view fragment that will expand with details and a settings button + // TODO set eip overview subview + // TODO make eip type clickable, show subview + // TODO attach vpn status feedback to eip overview view + // TODO attach settings button to something + } + @Override public boolean onCreateOptionsMenu(Menu menu) { // Inflate the menu; this adds items to the action bar if it is present. -- cgit v1.2.3 From d21e8390e90437f0d053374f8e304ca3f592beb9 Mon Sep 17 00:00:00 2001 From: Sean Leonard Date: Wed, 30 Jan 2013 23:37:33 -0700 Subject: More fun with EIP item entry. Added parts to expand listing for quick info and settings access --- src/se/leap/leapclient/Dashboard.java | 5 +++++ 1 file changed, 5 insertions(+) (limited to 'src/se/leap/leapclient') diff --git a/src/se/leap/leapclient/Dashboard.java b/src/se/leap/leapclient/Dashboard.java index 5835acb8..7d0b5e0f 100644 --- a/src/se/leap/leapclient/Dashboard.java +++ b/src/se/leap/leapclient/Dashboard.java @@ -163,4 +163,9 @@ public class Dashboard extends Activity { } + @SuppressWarnings("unused") + private void toggleOverview() { + // TODO Expand the one line overview item to show some details + } + } -- cgit v1.2.3 From 92c32b0b96938009af55ed28920472f22a4614ee Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Parm=C3=A9nides=20GV?= Date: Thu, 31 Jan 2013 22:12:21 +0100 Subject: Problems with downloaded file, the emulator cannot find the file downloaded. Seen http://code.google.com/p/android/issues/detail?id=18462 and decided to look for another solution. First solution thought (and going to be the next test): HTTP Get request :) --- src/se/leap/leapclient/Dashboard.java | 4 +- src/se/leap/leapclient/ProviderAPI.java | 15 ++ src/se/leap/leapclient/ProviderListActivity.java | 187 +++++++++++++++++++++++ src/se/leap/leapclient/ProviderListContent.java | 77 ++++++++++ src/se/leap/leapclient/ProviderListFragment.java | 150 ++++++++++++++++++ 5 files changed, 431 insertions(+), 2 deletions(-) create mode 100644 src/se/leap/leapclient/ProviderAPI.java create mode 100644 src/se/leap/leapclient/ProviderListActivity.java create mode 100644 src/se/leap/leapclient/ProviderListContent.java create mode 100644 src/se/leap/leapclient/ProviderListFragment.java (limited to 'src/se/leap/leapclient') diff --git a/src/se/leap/leapclient/Dashboard.java b/src/se/leap/leapclient/Dashboard.java index 7d0b5e0f..84ddab27 100644 --- a/src/se/leap/leapclient/Dashboard.java +++ b/src/se/leap/leapclient/Dashboard.java @@ -37,8 +37,8 @@ public class Dashboard extends Activity { preferences = getPreferences(MODE_PRIVATE); // FIXME provider data!! get parmegv's work so we can stop (or lessen) faking it - if ( !preferences.contains("provider") ) - fixmePrefsFaker(preferences); + if (preferences.contains("provider") ) + startActivity(new Intent(this, ProviderListActivity.class)); // Get our provider provider = Provider.getInstance(preferences); diff --git a/src/se/leap/leapclient/ProviderAPI.java b/src/se/leap/leapclient/ProviderAPI.java new file mode 100644 index 00000000..6d52e44f --- /dev/null +++ b/src/se/leap/leapclient/ProviderAPI.java @@ -0,0 +1,15 @@ +package se.leap.leapclient; + +import android.app.Service; +import android.content.Intent; +import android.os.IBinder; + +public class ProviderAPI extends Service { + + @Override + public IBinder onBind(Intent arg0) { + // TODO Auto-generated method stub + return null; + } + +} diff --git a/src/se/leap/leapclient/ProviderListActivity.java b/src/se/leap/leapclient/ProviderListActivity.java new file mode 100644 index 00000000..4964a1fd --- /dev/null +++ b/src/se/leap/leapclient/ProviderListActivity.java @@ -0,0 +1,187 @@ +package se.leap.leapclient; + +import java.io.File; +import java.io.IOException; +import java.util.ArrayList; +import java.util.Iterator; + +import se.leap.leapclient.ProviderListContent; +import se.leap.leapclient.ProviderListContent.ProviderItem; +import android.app.DownloadManager; +import android.content.Context; +import android.content.Intent; +import android.content.SharedPreferences; +import android.content.res.AssetManager; +import android.net.Uri; +import android.os.Build; +import android.os.Bundle; +import android.os.Environment; +import android.support.v4.app.FragmentActivity; + + +/** + * An activity representing a list of Providers. This activity + * has different presentations for handset and tablet-size devices. On + * handsets, the activity presents a list of items, which when touched, + * lead to a {@link DashboardActivity} representing + * item details. On tablets, the activity presents the list of items and + * item details side-by-side using two vertical panes. + *

+ * The activity makes heavy use of fragments. The list of items is a + * {@link ProviderListFragment} and the item details + * (if present) is a {@link DashboardFragment}. + *

+ * This activity also implements the required + * {@link ProviderListFragment.Callbacks} interface + * to listen for item selections. + */ +public class ProviderListActivity extends FragmentActivity + implements ProviderListFragment.Callbacks { + + /** + * Whether or not the activity is in two-pane mode, i.e. running on a tablet + * device. + */ + private boolean mTwoPane; + + private static SharedPreferences preferences; + + @Override + protected void onCreate(Bundle savedInstanceState) { + super.onCreate(savedInstanceState); + setContentView(R.layout.activity_provider_list); + + preferences = getPreferences(MODE_PRIVATE); + + loadPreseededProviders(); + + // TODO: If exposing deep links into your app, handle intents here. + } + + private void loadPreseededProviders() { + 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) + { + 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))); + } + } catch (IOException e) { + // TODO Auto-generated catch block + e.printStackTrace(); + } + } + + /** + * Callback method from {@link ProviderListFragment.Callbacks} + * indicating that the item with the given ID was selected. + */ + @Override + public void onItemSelected(String id) { + if (mTwoPane) { + + } else { + // In single-pane mode, simply start the detail activity + // for the selected item ID. + + Iterator preseeded_providers_iterator = ProviderListContent.ITEMS.iterator(); + while(preseeded_providers_iterator.hasNext()) + { + ProviderItem current_provider_item = preseeded_providers_iterator.next(); + if(current_provider_item.id.equalsIgnoreCase(id)) + { + ArrayList downloaded_files = downloadFiles(current_provider_item); + try { + parseToSharedPrefs(downloaded_files); + } catch (IOException e) { + // TODO Auto-generated catch block + e.printStackTrace(); + } + } + } + + Intent dashboardIntent = new Intent(this, Dashboard.class); + startActivity(dashboardIntent); + } + } + + private void parseToSharedPrefs(ArrayList downloaded_files) throws IOException { + SharedPreferences.Editor sharedPreferencesEditor = preferences.edit(); + + for(int i = 0; i < downloaded_files.size(); i++) + { + String type_and_filename = downloaded_files.get(i); + String filename = type_and_filename.substring(type_and_filename.indexOf(":")+1, type_and_filename.length()); + + String file_contents = readFileAsString(filename, null); + + if(downloaded_files.get(i).startsWith("provider:")) + sharedPreferencesEditor.putString("provider", file_contents); + else if(downloaded_files.get(i).startsWith("provider:")) + sharedPreferencesEditor.putString("eip", file_contents); + + sharedPreferencesEditor.commit(); + } + } + + public static String readFileAsString(String fileName, String charsetName) + throws java.io.IOException { + java.io.InputStream is = new java.io.FileInputStream(fileName); + try { + final int bufsize = 4096; + int available = is.available(); + byte data[] = new byte[available < bufsize ? bufsize : available]; + int used = 0; + while (true) { + if (data.length - used < bufsize) { + byte newData[] = new byte[data.length << 1]; + System.arraycopy(data, 0, newData, 0, used); + data = newData; + } + int got = is.read(data, used, data.length - used); + if (got <= 0) + break; + used += got; + } + return charsetName != null ? new String(data, 0, used, charsetName) + : new String(data, 0, used); + } finally { + is.close(); + } + } + + private ArrayList downloadFiles(ProviderItem current_provider_item) { + ArrayList paths_to_downloaded_files = new ArrayList(); + + paths_to_downloaded_files.add(downloadProviderJSON("provider_json", current_provider_item.provider_json_url, Environment.DIRECTORY_DOWNLOADS, current_provider_item.name + "_provider.json")); + paths_to_downloaded_files.add(downloadProviderJSON("eip_service_json", current_provider_item.eip_service_json_url, Environment.DIRECTORY_DOWNLOADS, current_provider_item.name + "_eip-service.json")); + + return paths_to_downloaded_files; + } + + private String downloadProviderJSON(String type, String json_url, String target_directory, String filename) { + + DownloadManager.Request request = new DownloadManager.Request(Uri.parse(json_url)); + request.setDescription("Downloading JSON file"); + request.setTitle("JSON file"); + // in order for this if to run, you must use the android 3.2 to compile your app + if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.HONEYCOMB) { + request.allowScanningByMediaScanner(); + request.setNotificationVisibility(DownloadManager.Request.VISIBILITY_VISIBLE_NOTIFY_COMPLETED); + } + //request.setDestinationInExternalPublicDir(Environment.DIRECTORY_DOWNLOADS, current_provider_item.name + "_provider.json"); + request.setDestinationInExternalPublicDir(target_directory, filename); + + // get download service and enqueue file + DownloadManager manager = (DownloadManager) getSystemService(Context.DOWNLOAD_SERVICE); + manager.enqueue(request); + return type + ":" + target_directory + "/" + filename; + + } +} diff --git a/src/se/leap/leapclient/ProviderListContent.java b/src/se/leap/leapclient/ProviderListContent.java new file mode 100644 index 00000000..1fe60159 --- /dev/null +++ b/src/se/leap/leapclient/ProviderListContent.java @@ -0,0 +1,77 @@ +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 org.json.JSONException; +import org.json.JSONObject; + + +public class ProviderListContent { + + /** + * An array of sample (dummy) items. + */ + public static List ITEMS = new ArrayList(); + + /** + * A map of sample (dummy) items, by ID. + */ + public static Map ITEM_MAP = new HashMap(); + + static { + //addItem(new ProviderItem("1", "bitmask", "https://bitmask.net/provider.json", "https://api.bitmask.net:4430/1/config/eip-service.json")); + } + + public static void addItem(ProviderItem item) { + ITEMS.add(item); + ITEM_MAP.put(String.valueOf(ITEMS.size()), item); + } + + /** + * A dummy item representing a piece of content. + */ + public static class ProviderItem { + public String id; + public String name; + public String provider_json_url; + public String eip_service_json_url; + + + public ProviderItem(String id, String name, String provider_json_url, String eip_service_json_url) { + this.id = id; + this.name = name; + this.provider_json_url = provider_json_url; + this.eip_service_json_url = eip_service_json_url; + } + + public ProviderItem(String name, InputStream urls_file_input_stream) { + + 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 = (String) file_contents.get("json_provider"); + eip_service_json_url = (String) file_contents.get("json_eip_service"); + } catch (JSONException e) { + // TODO Auto-generated catch block + e.printStackTrace(); + } catch (IOException e) { + // TODO Auto-generated catch block + e.printStackTrace(); + } + } + + @Override + public String toString() { + return name; + } + } +} diff --git a/src/se/leap/leapclient/ProviderListFragment.java b/src/se/leap/leapclient/ProviderListFragment.java new file mode 100644 index 00000000..717a65c1 --- /dev/null +++ b/src/se/leap/leapclient/ProviderListFragment.java @@ -0,0 +1,150 @@ +package se.leap.leapclient; + +import android.app.Activity; +import android.os.Bundle; +import android.support.v4.app.ListFragment; +import android.view.View; +import android.widget.ArrayAdapter; +import android.widget.ListView; + +import se.leap.leapclient.ProviderListContent; + +/** + * 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 { + + /** + * 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); + + setListAdapter(new ArrayAdapter( + getActivity(), + android.R.layout.simple_list_item_activated_1, + android.R.id.text1, + ProviderListContent.ITEMS)); + } + + @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; + } +} -- cgit v1.2.3 From 7b9e22e765a1e5eda05ad121684e63c20ff5f049 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Parm=C3=A9nides=20GV?= Date: Fri, 1 Feb 2013 00:13:09 +0100 Subject: I have a handshake failing within an HTTP connection in order to get the eip-service.json file. provider.json downloads and parses itself OK to SharedPreferences. It also does not link OK to the Dashboard, I do not know how to do it properly and I'm so tired (eyes hurting). Beginning with security things :) Happy to have gotten around DownloadManager problem with a simple HTTP connection. --- src/se/leap/leapclient/Dashboard.java | 3 +- src/se/leap/leapclient/ProviderAPI.java | 64 +++++++++++++++-- src/se/leap/leapclient/ProviderListActivity.java | 89 +++++------------------- 3 files changed, 77 insertions(+), 79 deletions(-) (limited to 'src/se/leap/leapclient') diff --git a/src/se/leap/leapclient/Dashboard.java b/src/se/leap/leapclient/Dashboard.java index 84ddab27..f81c37a7 100644 --- a/src/se/leap/leapclient/Dashboard.java +++ b/src/se/leap/leapclient/Dashboard.java @@ -37,7 +37,8 @@ public class Dashboard extends Activity { preferences = getPreferences(MODE_PRIVATE); // FIXME provider data!! get parmegv's work so we can stop (or lessen) faking it - if (preferences.contains("provider") ) + //TODO In my emulator, I always get that contains TRUE. Don't know why, but I've been testing without the "!". + if (!preferences.contains("provider") ) startActivity(new Intent(this, ProviderListActivity.class)); // Get our provider diff --git a/src/se/leap/leapclient/ProviderAPI.java b/src/se/leap/leapclient/ProviderAPI.java index 6d52e44f..aefb87fc 100644 --- a/src/se/leap/leapclient/ProviderAPI.java +++ b/src/se/leap/leapclient/ProviderAPI.java @@ -1,15 +1,67 @@ package se.leap.leapclient; -import android.app.Service; +import java.io.BufferedInputStream; +import java.io.IOException; +import java.io.InputStream; +import java.net.HttpURLConnection; +import java.net.URL; +import java.util.Scanner; + +import android.app.IntentService; import android.content.Intent; -import android.os.IBinder; +import android.content.SharedPreferences; +import android.os.Bundle; +import android.util.Log; + +public class ProviderAPI extends IntentService { -public class ProviderAPI extends Service { + public ProviderAPI() { + super("ProviderAPI"); + Log.v("ClassName", "Provider API"); + // TODO Auto-generated constructor stub + } @Override - public IBinder onBind(Intent arg0) { - // TODO Auto-generated method stub - return null; + protected void onHandleIntent(Intent task_for) { + Bundle task ; + System.out.println("onHandleIntent called"); + if(!(task = task_for.getBundleExtra("downloadJSONFiles")).isEmpty()) + { + String provider_key = "provider"; + String eip_service_key = "eip"; + String provider_json_url = (String) task.get(provider_key); + String eip_service_json_url = (String) task.get(eip_service_key); + try { + getAndParseSharedPref(provider_key, provider_json_url); + getAndParseSharedPref(eip_service_key, eip_service_json_url); + } catch (IOException e) { + // TODO Auto-generated catch block + e.printStackTrace(); + } + } + } + + private void getAndParseSharedPref(String shared_preferences_key, + String json_url) throws IOException { + URL url = new URL(json_url); + HttpURLConnection urlConnection = (HttpURLConnection) url + .openConnection(); + try { + InputStream in = new BufferedInputStream( + urlConnection.getInputStream()); + String json_file_content = new Scanner(in).useDelimiter("\\A") + .next(); + + SharedPreferences.Editor shared_preferences_editor = ProviderListActivity.shared_preferences + .edit(); + shared_preferences_editor.putString(shared_preferences_key, + json_file_content); + shared_preferences_editor.commit(); + System.out.println("Shared preferences updated: " + ProviderListActivity.shared_preferences.getString(shared_preferences_key, "Default")); + } finally { + urlConnection.disconnect(); + } + } } diff --git a/src/se/leap/leapclient/ProviderListActivity.java b/src/se/leap/leapclient/ProviderListActivity.java index 4964a1fd..9e5796da 100644 --- a/src/se/leap/leapclient/ProviderListActivity.java +++ b/src/se/leap/leapclient/ProviderListActivity.java @@ -1,9 +1,15 @@ package se.leap.leapclient; +import java.io.BufferedInputStream; import java.io.File; import java.io.IOException; +import java.io.InputStream; +import java.net.HttpURLConnection; +import java.net.MalformedURLException; +import java.net.URL; import java.util.ArrayList; import java.util.Iterator; +import java.util.Scanner; import se.leap.leapclient.ProviderListContent; import se.leap.leapclient.ProviderListContent.ProviderItem; @@ -44,14 +50,14 @@ public class ProviderListActivity extends FragmentActivity */ private boolean mTwoPane; - private static SharedPreferences preferences; + static SharedPreferences shared_preferences; @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_provider_list); - preferences = getPreferences(MODE_PRIVATE); + shared_preferences = getPreferences(MODE_PRIVATE); loadPreseededProviders(); @@ -96,9 +102,8 @@ public class ProviderListActivity extends FragmentActivity ProviderItem current_provider_item = preseeded_providers_iterator.next(); if(current_provider_item.id.equalsIgnoreCase(id)) { - ArrayList downloaded_files = downloadFiles(current_provider_item); try { - parseToSharedPrefs(downloaded_files); + downloadJSONFiles(current_provider_item); } catch (IOException e) { // TODO Auto-generated catch block e.printStackTrace(); @@ -111,77 +116,17 @@ public class ProviderListActivity extends FragmentActivity } } - private void parseToSharedPrefs(ArrayList downloaded_files) throws IOException { - SharedPreferences.Editor sharedPreferencesEditor = preferences.edit(); + private void downloadJSONFiles(ProviderItem current_provider_item) throws IOException { + Intent provider_API_command = new Intent(this, ProviderAPI.class); - for(int i = 0; i < downloaded_files.size(); i++) - { - String type_and_filename = downloaded_files.get(i); - String filename = type_and_filename.substring(type_and_filename.indexOf(":")+1, type_and_filename.length()); - - String file_contents = readFileAsString(filename, null); - - if(downloaded_files.get(i).startsWith("provider:")) - sharedPreferencesEditor.putString("provider", file_contents); - else if(downloaded_files.get(i).startsWith("provider:")) - sharedPreferencesEditor.putString("eip", file_contents); - - sharedPreferencesEditor.commit(); - } - } - - public static String readFileAsString(String fileName, String charsetName) - throws java.io.IOException { - java.io.InputStream is = new java.io.FileInputStream(fileName); - try { - final int bufsize = 4096; - int available = is.available(); - byte data[] = new byte[available < bufsize ? bufsize : available]; - int used = 0; - while (true) { - if (data.length - used < bufsize) { - byte newData[] = new byte[data.length << 1]; - System.arraycopy(data, 0, newData, 0, used); - data = newData; - } - int got = is.read(data, used, data.length - used); - if (got <= 0) - break; - used += got; - } - return charsetName != null ? new String(data, 0, used, charsetName) - : new String(data, 0, used); - } finally { - is.close(); - } - } - - private ArrayList downloadFiles(ProviderItem current_provider_item) { - ArrayList paths_to_downloaded_files = new ArrayList(); + Bundle method_and_parameters = new Bundle(); + method_and_parameters.putString("method", "getAndParseSharedPref"); + method_and_parameters.putString("provider", current_provider_item.provider_json_url); + method_and_parameters.putString("eip", current_provider_item.eip_service_json_url); - paths_to_downloaded_files.add(downloadProviderJSON("provider_json", current_provider_item.provider_json_url, Environment.DIRECTORY_DOWNLOADS, current_provider_item.name + "_provider.json")); - paths_to_downloaded_files.add(downloadProviderJSON("eip_service_json", current_provider_item.eip_service_json_url, Environment.DIRECTORY_DOWNLOADS, current_provider_item.name + "_eip-service.json")); + provider_API_command.putExtra("downloadJSONFiles", method_and_parameters); - return paths_to_downloaded_files; - } - - private String downloadProviderJSON(String type, String json_url, String target_directory, String filename) { - - DownloadManager.Request request = new DownloadManager.Request(Uri.parse(json_url)); - request.setDescription("Downloading JSON file"); - request.setTitle("JSON file"); - // in order for this if to run, you must use the android 3.2 to compile your app - if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.HONEYCOMB) { - request.allowScanningByMediaScanner(); - request.setNotificationVisibility(DownloadManager.Request.VISIBILITY_VISIBLE_NOTIFY_COMPLETED); - } - //request.setDestinationInExternalPublicDir(Environment.DIRECTORY_DOWNLOADS, current_provider_item.name + "_provider.json"); - request.setDestinationInExternalPublicDir(target_directory, filename); - - // get download service and enqueue file - DownloadManager manager = (DownloadManager) getSystemService(Context.DOWNLOAD_SERVICE); - manager.enqueue(request); - return type + ":" + target_directory + "/" + filename; + startService(provider_API_command); } } -- cgit v1.2.3 From d2bd18ef560d95974117604af899b3a9fcc16dab Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Parm=C3=A9nides=20GV?= Date: Mon, 4 Feb 2013 16:35:28 +0100 Subject: Created ConfigHelper with static information such as sharedprefs keys, the saveSharedPrefs method and an unimplemented rescueFromJSONException. Next step: managing HttpsURLConnection for the CertPathValidatorException. --- src/se/leap/leapclient/ConfigHelper.java | 32 ++++++++++++++ src/se/leap/leapclient/Dashboard.java | 3 +- src/se/leap/leapclient/ProviderAPI.java | 55 +++++++++++++----------- src/se/leap/leapclient/ProviderListActivity.java | 3 +- 4 files changed, 64 insertions(+), 29 deletions(-) create mode 100644 src/se/leap/leapclient/ConfigHelper.java (limited to 'src/se/leap/leapclient') diff --git a/src/se/leap/leapclient/ConfigHelper.java b/src/se/leap/leapclient/ConfigHelper.java new file mode 100644 index 00000000..174ff79f --- /dev/null +++ b/src/se/leap/leapclient/ConfigHelper.java @@ -0,0 +1,32 @@ +package se.leap.leapclient; + +import org.json.JSONException; +import org.json.JSONObject; + +import android.content.SharedPreferences; + +public class ConfigHelper { + + final static String downloadJsonFilesBundleExtra = "downloadJSONFiles"; + final static String provider_key = "provider"; + final static String eip_service_key = "eip"; + + static void saveSharedPref(String shared_preferences_key, + JSONObject content) { + + SharedPreferences.Editor shared_preferences_editor = ProviderListActivity.shared_preferences + .edit(); + shared_preferences_editor.putString(shared_preferences_key, + content.toString()); + shared_preferences_editor.commit(); + System.out.println("Shared preferences updated: " + + ProviderListActivity.shared_preferences.getString( + shared_preferences_key, "Default")); + + } + + static void rescueJSONException(JSONException e) { + // TODO Auto-generated catch block + e.printStackTrace(); + } +} diff --git a/src/se/leap/leapclient/Dashboard.java b/src/se/leap/leapclient/Dashboard.java index f81c37a7..84ddab27 100644 --- a/src/se/leap/leapclient/Dashboard.java +++ b/src/se/leap/leapclient/Dashboard.java @@ -37,8 +37,7 @@ public class Dashboard extends Activity { preferences = getPreferences(MODE_PRIVATE); // FIXME provider data!! get parmegv's work so we can stop (or lessen) faking it - //TODO In my emulator, I always get that contains TRUE. Don't know why, but I've been testing without the "!". - if (!preferences.contains("provider") ) + if (preferences.contains("provider") ) startActivity(new Intent(this, ProviderListActivity.class)); // Get our provider diff --git a/src/se/leap/leapclient/ProviderAPI.java b/src/se/leap/leapclient/ProviderAPI.java index aefb87fc..40638180 100644 --- a/src/se/leap/leapclient/ProviderAPI.java +++ b/src/se/leap/leapclient/ProviderAPI.java @@ -5,11 +5,16 @@ import java.io.IOException; import java.io.InputStream; import java.net.HttpURLConnection; import java.net.URL; +import java.net.URLConnection; import java.util.Scanner; +import javax.net.ssl.HttpsURLConnection; + +import org.json.JSONException; +import org.json.JSONObject; + import android.app.IntentService; import android.content.Intent; -import android.content.SharedPreferences; import android.os.Bundle; import android.util.Log; @@ -23,45 +28,45 @@ public class ProviderAPI extends IntentService { @Override protected void onHandleIntent(Intent task_for) { - Bundle task ; + Bundle task; System.out.println("onHandleIntent called"); - if(!(task = task_for.getBundleExtra("downloadJSONFiles")).isEmpty()) - { - String provider_key = "provider"; - String eip_service_key = "eip"; - String provider_json_url = (String) task.get(provider_key); - String eip_service_json_url = (String) task.get(eip_service_key); + if (!(task = task_for.getBundleExtra(ConfigHelper.downloadJsonFilesBundleExtra)).isEmpty()) { + String provider_json_url = (String) task.get(ConfigHelper.provider_key); + String eip_service_json_url = (String) task.get(ConfigHelper.eip_service_key); try { - getAndParseSharedPref(provider_key, provider_json_url); - getAndParseSharedPref(eip_service_key, eip_service_json_url); + JSONObject provider_json = getFromProvider(provider_json_url); + ConfigHelper.saveSharedPref(ConfigHelper.provider_key, provider_json); + JSONObject eip_service_json = getFromProvider(eip_service_json_url); + ConfigHelper.saveSharedPref(ConfigHelper.eip_service_key, eip_service_json); } catch (IOException e) { // TODO Auto-generated catch block e.printStackTrace(); + } catch (JSONException e) { + ConfigHelper.rescueJSONException(e); } } } - private void getAndParseSharedPref(String shared_preferences_key, - String json_url) throws IOException { + private JSONObject getFromProvider(String json_url) throws IOException, JSONException { URL url = new URL(json_url); - HttpURLConnection urlConnection = (HttpURLConnection) url - .openConnection(); + String json_file_content = ""; + URLConnection urlConnection = null; + + if (url.getProtocol().equalsIgnoreCase("https")) { + urlConnection = (HttpsURLConnection) url.openConnection(); + } else if (url.getProtocol().equalsIgnoreCase("http")) { + urlConnection = (HttpURLConnection) url.openConnection(); + } + try { InputStream in = new BufferedInputStream( urlConnection.getInputStream()); - String json_file_content = new Scanner(in).useDelimiter("\\A") - .next(); - - SharedPreferences.Editor shared_preferences_editor = ProviderListActivity.shared_preferences - .edit(); - shared_preferences_editor.putString(shared_preferences_key, - json_file_content); - shared_preferences_editor.commit(); - System.out.println("Shared preferences updated: " + ProviderListActivity.shared_preferences.getString(shared_preferences_key, "Default")); + json_file_content = new Scanner(in).useDelimiter("\\A").next(); } finally { - urlConnection.disconnect(); + ((HttpURLConnection) urlConnection).disconnect(); } - + + return new JSONObject(json_file_content); } } diff --git a/src/se/leap/leapclient/ProviderListActivity.java b/src/se/leap/leapclient/ProviderListActivity.java index 9e5796da..088b464d 100644 --- a/src/se/leap/leapclient/ProviderListActivity.java +++ b/src/se/leap/leapclient/ProviderListActivity.java @@ -120,11 +120,10 @@ public class ProviderListActivity extends FragmentActivity Intent provider_API_command = new Intent(this, ProviderAPI.class); Bundle method_and_parameters = new Bundle(); - method_and_parameters.putString("method", "getAndParseSharedPref"); method_and_parameters.putString("provider", current_provider_item.provider_json_url); method_and_parameters.putString("eip", current_provider_item.eip_service_json_url); - provider_API_command.putExtra("downloadJSONFiles", method_and_parameters); + provider_API_command.putExtra(ConfigHelper.downloadJsonFilesBundleExtra, method_and_parameters); startService(provider_API_command); -- cgit v1.2.3 From 3bab2278ccd8d960e6f8f92f939c81b13832b23a Mon Sep 17 00:00:00 2001 From: Sean Leonard Date: Mon, 4 Feb 2013 09:40:16 -0700 Subject: Fix testing conditional looking for saved prefs that made it into last commit --- src/se/leap/leapclient/Dashboard.java | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) (limited to 'src/se/leap/leapclient') diff --git a/src/se/leap/leapclient/Dashboard.java b/src/se/leap/leapclient/Dashboard.java index 84ddab27..7bb71c1e 100644 --- a/src/se/leap/leapclient/Dashboard.java +++ b/src/se/leap/leapclient/Dashboard.java @@ -36,8 +36,8 @@ public class Dashboard extends Activity { preferences = getPreferences(MODE_PRIVATE); - // FIXME provider data!! get parmegv's work so we can stop (or lessen) faking it - if (preferences.contains("provider") ) + // FIXME We need to StartActivityForResult and move the rest to buildDashboard (called in "else" and onActivityResult) + if ( !preferences.contains("provider") ) startActivity(new Intent(this, ProviderListActivity.class)); // Get our provider -- cgit v1.2.3 From 8ab36864e2a393df077073f8618a4fc55c307522 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Parm=C3=A9nides=20GV?= Date: Mon, 4 Feb 2013 18:44:38 +0100 Subject: Secure HTTP working with certificates downloaded from api.bitmask.net and bitmask.net. Both prefs are downloaded and parsed to SharedPreferences. --- src/se/leap/leapclient/ConfigHelper.java | 1 + src/se/leap/leapclient/LeapHttpClient.java | 58 ++++++++++++++++++++++++++++++ src/se/leap/leapclient/ProviderAPI.java | 35 +++++++----------- 3 files changed, 72 insertions(+), 22 deletions(-) create mode 100644 src/se/leap/leapclient/LeapHttpClient.java (limited to 'src/se/leap/leapclient') diff --git a/src/se/leap/leapclient/ConfigHelper.java b/src/se/leap/leapclient/ConfigHelper.java index 174ff79f..9b857b0d 100644 --- a/src/se/leap/leapclient/ConfigHelper.java +++ b/src/se/leap/leapclient/ConfigHelper.java @@ -1,5 +1,6 @@ package se.leap.leapclient; + import org.json.JSONException; import org.json.JSONObject; diff --git a/src/se/leap/leapclient/LeapHttpClient.java b/src/se/leap/leapclient/LeapHttpClient.java new file mode 100644 index 00000000..41cb7879 --- /dev/null +++ b/src/se/leap/leapclient/LeapHttpClient.java @@ -0,0 +1,58 @@ +package se.leap.leapclient; + +import java.io.InputStream; +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; + +public class LeapHttpClient extends DefaultHttpClient { + final Context context; + + public LeapHttpClient(Context context) { + this.context = context; + } + + @Override + protected ClientConnectionManager createClientConnectionManager() { + SchemeRegistry registry = new SchemeRegistry(); + registry.register(new Scheme("http", PlainSocketFactory.getSocketFactory(), 80)); + // Register for port 443 our SSLSocketFactory with our keystore + // to the ConnectionManager + registry.register(new Scheme("https", newSslSocketFactory(), 443)); + return new SingleClientConnManager(getParams(), registry); + } + + private SSLSocketFactory newSslSocketFactory() { + try { + // Get an instance of the Bouncy Castle KeyStore format + KeyStore trusted = KeyStore.getInstance("BKS"); + // Get the raw resource, which contains the keystore with + // your trusted certificates (root and any intermediate certs) + InputStream in = context.getResources().openRawResource(R.raw.leapkeystore); + try { + // Initialize the keystore with the provided trusted certificates + // Also provide the password of the keystore + trusted.load(in, "uer92jf".toCharArray()); + } finally { + in.close(); + } + // Pass the keystore to the SSLSocketFactory. The factory is responsible + // for the verification of the server certificate. + SSLSocketFactory sf = new SSLSocketFactory(trusted); + // Hostname verification from certificate + // http://hc.apache.org/httpcomponents-client-ga/tutorial/html/connmgmt.html#d4e506 + sf.setHostnameVerifier(SSLSocketFactory.STRICT_HOSTNAME_VERIFIER); + return sf; + } catch (Exception e) { + throw new AssertionError(e); + } + } +} diff --git a/src/se/leap/leapclient/ProviderAPI.java b/src/se/leap/leapclient/ProviderAPI.java index 40638180..d487ebe3 100644 --- a/src/se/leap/leapclient/ProviderAPI.java +++ b/src/se/leap/leapclient/ProviderAPI.java @@ -1,15 +1,12 @@ package se.leap.leapclient; -import java.io.BufferedInputStream; import java.io.IOException; -import java.io.InputStream; -import java.net.HttpURLConnection; -import java.net.URL; -import java.net.URLConnection; import java.util.Scanner; -import javax.net.ssl.HttpsURLConnection; - +import org.apache.http.HttpEntity; +import org.apache.http.HttpResponse; +import org.apache.http.client.methods.HttpGet; +import org.apache.http.impl.client.DefaultHttpClient; import org.json.JSONException; import org.json.JSONObject; @@ -48,23 +45,17 @@ public class ProviderAPI extends IntentService { } private JSONObject getFromProvider(String json_url) throws IOException, JSONException { - URL url = new URL(json_url); + String json_file_content = ""; - URLConnection urlConnection = null; - if (url.getProtocol().equalsIgnoreCase("https")) { - urlConnection = (HttpsURLConnection) url.openConnection(); - } else if (url.getProtocol().equalsIgnoreCase("http")) { - urlConnection = (HttpURLConnection) url.openConnection(); - } - - try { - InputStream in = new BufferedInputStream( - urlConnection.getInputStream()); - json_file_content = new Scanner(in).useDelimiter("\\A").next(); - } finally { - ((HttpURLConnection) urlConnection).disconnect(); - } + DefaultHttpClient client = new LeapHttpClient(getApplicationContext()); + HttpGet get = new HttpGet(json_url); + // Execute the GET call and obtain the response + HttpResponse getResponse = client.execute(get); + HttpEntity responseEntity = getResponse.getEntity(); + + json_file_content = new Scanner(responseEntity.getContent()).useDelimiter("\\A").next(); + return new JSONObject(json_file_content); } -- cgit v1.2.3 From 4567c97e526154394874b971a29f66c9ca22e6f2 Mon Sep 17 00:00:00 2001 From: Sean Leonard Date: Tue, 5 Feb 2013 10:35:36 -0700 Subject: Move Dashboard view building code into a function so it does not run when we have no config (createed NullPointerExceptions) --- src/se/leap/leapclient/Dashboard.java | 33 +++++++++++++++++++-------------- 1 file changed, 19 insertions(+), 14 deletions(-) (limited to 'src/se/leap/leapclient') diff --git a/src/se/leap/leapclient/Dashboard.java b/src/se/leap/leapclient/Dashboard.java index 7bb71c1e..a7e84eef 100644 --- a/src/se/leap/leapclient/Dashboard.java +++ b/src/se/leap/leapclient/Dashboard.java @@ -36,21 +36,12 @@ public class Dashboard extends Activity { preferences = getPreferences(MODE_PRIVATE); - // FIXME We need to StartActivityForResult and move the rest to buildDashboard (called in "else" and onActivityResult) - if ( !preferences.contains("provider") ) + // Check if we have preferences, run configuration wizard if not + // TODO We should do a better check for config that this! + if (!preferences.contains("provider") ) startActivity(new Intent(this, ProviderListActivity.class)); - - // Get our provider - provider = Provider.getInstance(preferences); - - // Set provider name in textview - providerNameTV = (TextView) findViewById(R.id.providerName); - providerNameTV.setText(provider.getName()); - providerNameTV.setTextSize(28); // TODO maybe to some calculating, or a marquee? - - // TODO Inflate layout fragments for provider's services - if ( provider.hasEIP() ) - serviceItemEIP(); + else + buildDashboard(); } // FIXME!! We don't want you around here once we have something /real/ going on @@ -99,6 +90,20 @@ public class Dashboard extends Activity { fakes.putString("eip", eipjson); fakes.commit(); } + + private void buildDashboard() { + // Get our provider + provider = Provider.getInstance(preferences); + + // Set provider name in textview + providerNameTV = (TextView) findViewById(R.id.providerName); + providerNameTV.setText(provider.getName()); + providerNameTV.setTextSize(28); // TODO maybe to some calculating, or a marquee? + + // TODO Inflate layout fragments for provider's services + if ( provider.hasEIP() ) + serviceItemEIP(); + } private void serviceItemEIP() { // FIXME Provider service (eip/openvpn) -- cgit v1.2.3 From 2045c946b0f67c0415909bb1e459ac00af1359b9 Mon Sep 17 00:00:00 2001 From: Sean Leonard Date: Tue, 5 Feb 2013 11:05:16 -0700 Subject: Remove function to push data into preferences (it was for testing before we had ProviderList stuff) --- src/se/leap/leapclient/Dashboard.java | 46 ----------------------------------- 1 file changed, 46 deletions(-) (limited to 'src/se/leap/leapclient') diff --git a/src/se/leap/leapclient/Dashboard.java b/src/se/leap/leapclient/Dashboard.java index a7e84eef..3f32bde3 100644 --- a/src/se/leap/leapclient/Dashboard.java +++ b/src/se/leap/leapclient/Dashboard.java @@ -44,52 +44,6 @@ public class Dashboard extends Activity { buildDashboard(); } - // FIXME!! We don't want you around here once we have something /real/ going on - private void fixmePrefsFaker(SharedPreferences fakeit) { - SharedPreferences.Editor fakes = fakeit.edit(); - - AssetManager am = getAssets(); - BufferedReader prov = null; - try { - prov = new BufferedReader(new InputStreamReader(am.open("providers/bitmask.net_provider.json"))); - } catch (IOException e) { - // TODO Auto-generated catch block - e.printStackTrace(); - } - BufferedReader serv = null; - try { - serv = new BufferedReader(new InputStreamReader(am.open("providers/bitmask.net_eip-service.json"))); - } catch (IOException e) { - // TODO Auto-generated catch block - e.printStackTrace(); - } - StringBuilder provider = new StringBuilder(); - StringBuilder eip = new StringBuilder(); - - String line; - try { - while ((line = prov.readLine()) != null){ - provider.append(line); - } - } catch (IOException e) { - // TODO Auto-generated catch block - e.printStackTrace(); - } - String providerjson = provider.toString(); - try { - while ((line = serv.readLine()) != null){ - eip.append(line); - } - } catch (IOException e) { - // TODO Auto-generated catch block - e.printStackTrace(); - } - String eipjson = eip.toString(); - - fakes.putString("provider", providerjson); - fakes.putString("eip", eipjson); - fakes.commit(); - } private void buildDashboard() { // Get our provider -- cgit v1.2.3 From 1d5f1c320ee67cfadd62aeef056a043bee75096d Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Parm=C3=A9nides=20GV?= Date: Tue, 5 Feb 2013 20:46:33 +0100 Subject: Simplified certificates and urls: only 1 certificate, and no :443 port in eip. Downloads certificate and eip from web, and loads provider from assets. KeyStore not created with latest version of BouncyCastle. Looking forward to file a bug and look for a solution. --- src/se/leap/leapclient/ConfigHelper.java | 11 ++++++----- src/se/leap/leapclient/Dashboard.java | 5 +++-- src/se/leap/leapclient/LeapHttpClient.java | 2 +- src/se/leap/leapclient/ProviderAPI.java | 21 +++++++++++++------- src/se/leap/leapclient/ProviderListActivity.java | 25 ++++++++++++++++++++++-- src/se/leap/leapclient/ProviderListContent.java | 7 ++++++- 6 files changed, 53 insertions(+), 18 deletions(-) (limited to 'src/se/leap/leapclient') diff --git a/src/se/leap/leapclient/ConfigHelper.java b/src/se/leap/leapclient/ConfigHelper.java index 9b857b0d..be848db0 100644 --- a/src/se/leap/leapclient/ConfigHelper.java +++ b/src/se/leap/leapclient/ConfigHelper.java @@ -10,20 +10,21 @@ public class ConfigHelper { final static String downloadJsonFilesBundleExtra = "downloadJSONFiles"; final static String provider_key = "provider"; + final static String cert_key = "cert"; final static String eip_service_key = "eip"; - static void saveSharedPref(String shared_preferences_key, - JSONObject content) { - + static void saveSharedPref(String shared_preferences_key, JSONObject content) { + SharedPreferences.Editor shared_preferences_editor = ProviderListActivity.shared_preferences .edit(); shared_preferences_editor.putString(shared_preferences_key, content.toString()); shared_preferences_editor.commit(); - System.out.println("Shared preferences updated: " + System.out.println("Shared preferences updated: key = " + + shared_preferences_key + + " Content = " + ProviderListActivity.shared_preferences.getString( shared_preferences_key, "Default")); - } static void rescueJSONException(JSONException e) { diff --git a/src/se/leap/leapclient/Dashboard.java b/src/se/leap/leapclient/Dashboard.java index 7bb71c1e..02bc704c 100644 --- a/src/se/leap/leapclient/Dashboard.java +++ b/src/se/leap/leapclient/Dashboard.java @@ -37,9 +37,10 @@ public class Dashboard extends Activity { preferences = getPreferences(MODE_PRIVATE); // FIXME We need to StartActivityForResult and move the rest to buildDashboard (called in "else" and onActivityResult) - if ( !preferences.contains("provider") ) + if ( !preferences.contains("provider") ) { startActivity(new Intent(this, ProviderListActivity.class)); - + } + // Get our provider provider = Provider.getInstance(preferences); diff --git a/src/se/leap/leapclient/LeapHttpClient.java b/src/se/leap/leapclient/LeapHttpClient.java index 41cb7879..9e1a541b 100644 --- a/src/se/leap/leapclient/LeapHttpClient.java +++ b/src/se/leap/leapclient/LeapHttpClient.java @@ -49,7 +49,7 @@ public class LeapHttpClient extends DefaultHttpClient { SSLSocketFactory sf = new SSLSocketFactory(trusted); // Hostname verification from certificate // http://hc.apache.org/httpcomponents-client-ga/tutorial/html/connmgmt.html#d4e506 - sf.setHostnameVerifier(SSLSocketFactory.STRICT_HOSTNAME_VERIFIER); + sf.setHostnameVerifier(SSLSocketFactory.ALLOW_ALL_HOSTNAME_VERIFIER); return sf; } catch (Exception e) { throw new AssertionError(e); diff --git a/src/se/leap/leapclient/ProviderAPI.java b/src/se/leap/leapclient/ProviderAPI.java index d487ebe3..33f7fd74 100644 --- a/src/se/leap/leapclient/ProviderAPI.java +++ b/src/se/leap/leapclient/ProviderAPI.java @@ -5,6 +5,7 @@ import java.util.Scanner; import org.apache.http.HttpEntity; import org.apache.http.HttpResponse; +import org.apache.http.client.ClientProtocolException; import org.apache.http.client.methods.HttpGet; import org.apache.http.impl.client.DefaultHttpClient; import org.json.JSONException; @@ -28,35 +29,41 @@ public class ProviderAPI extends IntentService { Bundle task; System.out.println("onHandleIntent called"); if (!(task = task_for.getBundleExtra(ConfigHelper.downloadJsonFilesBundleExtra)).isEmpty()) { - String provider_json_url = (String) task.get(ConfigHelper.provider_key); + String cert_url = (String) task.get(ConfigHelper.cert_key); String eip_service_json_url = (String) task.get(ConfigHelper.eip_service_key); try { - JSONObject provider_json = getFromProvider(provider_json_url); - ConfigHelper.saveSharedPref(ConfigHelper.provider_key, provider_json); - JSONObject eip_service_json = getFromProvider(eip_service_json_url); + String cert_string = getStringFromProvider(cert_url); + JSONObject cert_json = new JSONObject("{ \"certificate\" : \"" + cert_string + "\"}"); + ConfigHelper.saveSharedPref(ConfigHelper.cert_key, cert_json); + JSONObject eip_service_json = getJSONFromProvider(eip_service_json_url); ConfigHelper.saveSharedPref(ConfigHelper.eip_service_key, eip_service_json); } catch (IOException e) { // TODO Auto-generated catch block e.printStackTrace(); } catch (JSONException e) { ConfigHelper.rescueJSONException(e); + } catch(Exception e) { + e.printStackTrace(); } } } - private JSONObject getFromProvider(String json_url) throws IOException, JSONException { + private String getStringFromProvider(String string_url) throws IOException { String json_file_content = ""; DefaultHttpClient client = new LeapHttpClient(getApplicationContext()); - HttpGet get = new HttpGet(json_url); + HttpGet get = new HttpGet(string_url); // Execute the GET call and obtain the response HttpResponse getResponse = client.execute(get); HttpEntity responseEntity = getResponse.getEntity(); json_file_content = new Scanner(responseEntity.getContent()).useDelimiter("\\A").next(); - + return json_file_content; + } + private JSONObject getJSONFromProvider(String json_url) throws IOException, JSONException { + String json_file_content = getStringFromProvider(json_url); return new JSONObject(json_file_content); } diff --git a/src/se/leap/leapclient/ProviderListActivity.java b/src/se/leap/leapclient/ProviderListActivity.java index 088b464d..808c12ce 100644 --- a/src/se/leap/leapclient/ProviderListActivity.java +++ b/src/se/leap/leapclient/ProviderListActivity.java @@ -1,9 +1,11 @@ package se.leap.leapclient; import java.io.BufferedInputStream; +import java.io.BufferedReader; import java.io.File; import java.io.IOException; import java.io.InputStream; +import java.io.InputStreamReader; import java.net.HttpURLConnection; import java.net.MalformedURLException; import java.net.URL; @@ -11,6 +13,9 @@ import java.util.ArrayList; import java.util.Iterator; import java.util.Scanner; +import org.json.JSONException; +import org.json.JSONObject; + import se.leap.leapclient.ProviderListContent; import se.leap.leapclient.ProviderListContent.ProviderItem; import android.app.DownloadManager; @@ -103,6 +108,7 @@ public class ProviderListActivity extends FragmentActivity if(current_provider_item.id.equalsIgnoreCase(id)) { try { + processAssetsFiles(current_provider_item); downloadJSONFiles(current_provider_item); } catch (IOException e) { // TODO Auto-generated catch block @@ -116,12 +122,27 @@ public class ProviderListActivity extends FragmentActivity } } + private void processAssetsFiles(ProviderItem current_provider_item) { + AssetManager assets_manager = getAssets(); + JSONObject provider_json = new JSONObject(); + try { + String provider_contents = new Scanner(new InputStreamReader(assets_manager.open(current_provider_item.provider_json_assets))).useDelimiter("\\A").next(); + provider_json = new JSONObject(provider_contents); + } catch (IOException e) { + // TODO Auto-generated catch block + e.printStackTrace(); + } catch (JSONException e) { + ConfigHelper.rescueJSONException(e); + } + ConfigHelper.saveSharedPref(ConfigHelper.provider_key, provider_json); + } + private void downloadJSONFiles(ProviderItem current_provider_item) throws IOException { Intent provider_API_command = new Intent(this, ProviderAPI.class); Bundle method_and_parameters = new Bundle(); - method_and_parameters.putString("provider", current_provider_item.provider_json_url); - method_and_parameters.putString("eip", current_provider_item.eip_service_json_url); + method_and_parameters.putString(ConfigHelper.cert_key, current_provider_item.cert_json_url); + method_and_parameters.putString(ConfigHelper.eip_service_key, current_provider_item.eip_service_json_url); provider_API_command.putExtra(ConfigHelper.downloadJsonFilesBundleExtra, method_and_parameters); diff --git a/src/se/leap/leapclient/ProviderListContent.java b/src/se/leap/leapclient/ProviderListContent.java index 1fe60159..bf8bfa87 100644 --- a/src/se/leap/leapclient/ProviderListContent.java +++ b/src/se/leap/leapclient/ProviderListContent.java @@ -39,14 +39,17 @@ public class ProviderListContent { public String id; public String name; public String provider_json_url; + public String provider_json_assets; public String eip_service_json_url; + public String cert_json_url; - public ProviderItem(String id, String name, String provider_json_url, String eip_service_json_url) { + public ProviderItem(String id, String name, String provider_json_url, String eip_service_json_url, String cert_json_url) { this.id = id; this.name = name; this.provider_json_url = provider_json_url; this.eip_service_json_url = eip_service_json_url; + this.cert_json_url = cert_json_url; } public ProviderItem(String name, InputStream urls_file_input_stream) { @@ -59,7 +62,9 @@ public class ProviderListContent { id = name; this.name = name; provider_json_url = (String) file_contents.get("json_provider"); + provider_json_assets = (String) file_contents.get("assets_json_provider"); eip_service_json_url = (String) file_contents.get("json_eip_service"); + cert_json_url = (String) file_contents.get("cert"); } catch (JSONException e) { // TODO Auto-generated catch block e.printStackTrace(); -- cgit v1.2.3 From 2fecc0d022e2d3022572c21f14605ee917f71cff Mon Sep 17 00:00:00 2001 From: Sean Leonard Date: Tue, 5 Feb 2013 17:30:16 -0700 Subject: Change access modifiers of some functions in Provider.class from public to protected --- src/se/leap/leapclient/Provider.java | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) (limited to 'src/se/leap/leapclient') diff --git a/src/se/leap/leapclient/Provider.java b/src/se/leap/leapclient/Provider.java index a25909bf..b5e81c9d 100644 --- a/src/se/leap/leapclient/Provider.java +++ b/src/se/leap/leapclient/Provider.java @@ -109,7 +109,7 @@ final class Provider implements Serializable { return desc; } - public boolean hasEIP() { + protected boolean hasEIP() { JSONArray services = null; try { services = definition.getJSONArray(API_TERM_SERVICES); // returns ["openvpn"] @@ -128,7 +128,7 @@ final class Provider implements Serializable { return false; } - public String getEIPType() { + protected String getEIPType() { // FIXME!!!!! We won't always be providing /only/ OpenVPN, will we? // This will have to hook into some saved choice of EIP transport if ( instance.hasEIP() ) @@ -137,7 +137,7 @@ final class Provider implements Serializable { return null; } - public JSONObject getEIP() { + protected JSONObject getEIP() { // FIXME!!!!! We won't always be providing /only/ OpenVPN, will we? // This will have to hook into some saved choice of EIP transport, cluster, gateway // with possible "choose at random" preference -- cgit v1.2.3 From b4fddc796c11a4da7a81b044857d82d516531095 Mon Sep 17 00:00:00 2001 From: Sean Leonard Date: Tue, 5 Feb 2013 17:31:01 -0700 Subject: Comments regarding TODOs for changes to ProviderListActivity --- src/se/leap/leapclient/ProviderListActivity.java | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) (limited to 'src/se/leap/leapclient') diff --git a/src/se/leap/leapclient/ProviderListActivity.java b/src/se/leap/leapclient/ProviderListActivity.java index 808c12ce..3b1d78e2 100644 --- a/src/se/leap/leapclient/ProviderListActivity.java +++ b/src/se/leap/leapclient/ProviderListActivity.java @@ -96,7 +96,7 @@ public class ProviderListActivity extends FragmentActivity @Override public void onItemSelected(String id) { if (mTwoPane) { - + // TODO Hmmm...is this how we should do this? What if it /is/ two pane? } else { // In single-pane mode, simply start the detail activity // for the selected item ID. @@ -109,6 +109,7 @@ public class ProviderListActivity extends FragmentActivity { try { processAssetsFiles(current_provider_item); + // TODO ask Provider class to save provider.json, setResult(OK), finish() to ConfigurationWizard downloadJSONFiles(current_provider_item); } catch (IOException e) { // TODO Auto-generated catch block -- cgit v1.2.3 From 72fd6621a988fcc25d1fa93b977cb7d0a88c96d6 Mon Sep 17 00:00:00 2001 From: Sean Leonard Date: Tue, 5 Feb 2013 17:51:24 -0700 Subject: Clean up unused imports --- src/se/leap/leapclient/Dashboard.java | 5 ----- src/se/leap/leapclient/ProviderAPI.java | 1 - src/se/leap/leapclient/ProviderListActivity.java | 14 -------------- 3 files changed, 20 deletions(-) (limited to 'src/se/leap/leapclient') diff --git a/src/se/leap/leapclient/Dashboard.java b/src/se/leap/leapclient/Dashboard.java index 3f32bde3..c3c6a07f 100644 --- a/src/se/leap/leapclient/Dashboard.java +++ b/src/se/leap/leapclient/Dashboard.java @@ -1,9 +1,5 @@ package se.leap.leapclient; -import java.io.BufferedReader; -import java.io.IOException; -import java.io.InputStreamReader; - import se.leap.openvpn.AboutFragment; import se.leap.openvpn.MainActivity; import android.app.Activity; @@ -11,7 +7,6 @@ import android.app.Fragment; import android.app.FragmentTransaction; import android.content.Intent; import android.content.SharedPreferences; -import android.content.res.AssetManager; import android.os.Bundle; import android.view.Menu; import android.view.MenuItem; diff --git a/src/se/leap/leapclient/ProviderAPI.java b/src/se/leap/leapclient/ProviderAPI.java index 33f7fd74..5a8f9572 100644 --- a/src/se/leap/leapclient/ProviderAPI.java +++ b/src/se/leap/leapclient/ProviderAPI.java @@ -5,7 +5,6 @@ import java.util.Scanner; import org.apache.http.HttpEntity; import org.apache.http.HttpResponse; -import org.apache.http.client.ClientProtocolException; import org.apache.http.client.methods.HttpGet; import org.apache.http.impl.client.DefaultHttpClient; import org.json.JSONException; diff --git a/src/se/leap/leapclient/ProviderListActivity.java b/src/se/leap/leapclient/ProviderListActivity.java index 3b1d78e2..972e2bf0 100644 --- a/src/se/leap/leapclient/ProviderListActivity.java +++ b/src/se/leap/leapclient/ProviderListActivity.java @@ -1,32 +1,18 @@ package se.leap.leapclient; -import java.io.BufferedInputStream; -import java.io.BufferedReader; -import java.io.File; import java.io.IOException; -import java.io.InputStream; import java.io.InputStreamReader; -import java.net.HttpURLConnection; -import java.net.MalformedURLException; -import java.net.URL; -import java.util.ArrayList; import java.util.Iterator; import java.util.Scanner; import org.json.JSONException; import org.json.JSONObject; -import se.leap.leapclient.ProviderListContent; import se.leap.leapclient.ProviderListContent.ProviderItem; -import android.app.DownloadManager; -import android.content.Context; import android.content.Intent; import android.content.SharedPreferences; import android.content.res.AssetManager; -import android.net.Uri; -import android.os.Build; import android.os.Bundle; -import android.os.Environment; import android.support.v4.app.FragmentActivity; -- cgit v1.2.3 From 6e0142a335eafe8a9b0e41b0e968038c0aeabd11 Mon Sep 17 00:00:00 2001 From: Sean Leonard Date: Thu, 7 Feb 2013 01:33:03 -0700 Subject: Refactor ProviderListActivity.class into ConfigurationWizard.class, Moves towards our wizard flow; Addresses #1497 #1500 --- src/se/leap/leapclient/ConfigHelper.java | 4 +- src/se/leap/leapclient/ConfigurationWizard.java | 153 +++++++++++++++++++++++ src/se/leap/leapclient/ProviderListActivity.java | 139 -------------------- src/se/leap/leapclient/ProviderListFragment.java | 4 +- 4 files changed, 156 insertions(+), 144 deletions(-) create mode 100644 src/se/leap/leapclient/ConfigurationWizard.java delete mode 100644 src/se/leap/leapclient/ProviderListActivity.java (limited to 'src/se/leap/leapclient') diff --git a/src/se/leap/leapclient/ConfigHelper.java b/src/se/leap/leapclient/ConfigHelper.java index be848db0..b2baed67 100644 --- a/src/se/leap/leapclient/ConfigHelper.java +++ b/src/se/leap/leapclient/ConfigHelper.java @@ -15,7 +15,7 @@ public class ConfigHelper { static void saveSharedPref(String shared_preferences_key, JSONObject content) { - SharedPreferences.Editor shared_preferences_editor = ProviderListActivity.shared_preferences + SharedPreferences.Editor shared_preferences_editor = ConfigurationWizard.shared_preferences .edit(); shared_preferences_editor.putString(shared_preferences_key, content.toString()); @@ -23,7 +23,7 @@ public class ConfigHelper { System.out.println("Shared preferences updated: key = " + shared_preferences_key + " Content = " - + ProviderListActivity.shared_preferences.getString( + + ConfigurationWizard.shared_preferences.getString( shared_preferences_key, "Default")); } diff --git a/src/se/leap/leapclient/ConfigurationWizard.java b/src/se/leap/leapclient/ConfigurationWizard.java new file mode 100644 index 00000000..6a7bd10c --- /dev/null +++ b/src/se/leap/leapclient/ConfigurationWizard.java @@ -0,0 +1,153 @@ +package se.leap.leapclient; + +import java.io.IOException; +import java.io.InputStreamReader; +import java.util.Iterator; +import java.util.Scanner; + +import org.json.JSONException; +import org.json.JSONObject; + +import se.leap.leapclient.ProviderListContent.ProviderItem; +import android.app.Activity; +import android.app.FragmentManager; +import android.content.Intent; +import android.content.SharedPreferences; +import android.content.res.AssetManager; +import android.os.Bundle; + + +/** + * An activity representing a list of Providers. This activity + * has different presentations for handset and tablet-size devices. On + * handsets, the activity presents a list of items, which when touched, + * lead to a {@link DashboardActivity} representing + * item details. On tablets, the activity presents the list of items and + * item details side-by-side using two vertical panes. + *

+ * The activity makes heavy use of fragments. The list of items is a + * {@link ProviderListFragment} and the item details + * (if present) is a {@link DashboardFragment}. + *

+ * This activity also implements the required + * {@link ProviderListFragment.Callbacks} interface + * to listen for item selections. + */ +public class ConfigurationWizard extends Activity + implements ProviderListFragment.Callbacks { + + /** + * Whether or not the activity is in two-pane mode, i.e. running on a tablet + * device. + */ + private boolean mTwoPane; + + static SharedPreferences shared_preferences; + + @Override + protected void onCreate(Bundle savedInstanceState) { + super.onCreate(savedInstanceState); + + setContentView(R.layout.activity_configuration_wizard); + + shared_preferences = getSharedPreferences(ConfigHelper.PREFERENCES_KEY,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. + } + + private void loadPreseededProviders() { + 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) + { + 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))); + } + } catch (IOException e) { + // TODO Auto-generated catch block + e.printStackTrace(); + } + } + + /** + * Callback method from {@link ProviderListFragment.Callbacks} + * indicating that the item with the given ID was selected. + */ + @Override + public void onItemSelected(String id) { + if (mTwoPane) { + // TODO Hmmm...is this how we should do this? What if it /is/ two pane? + } else { + // In single-pane mode, simply start the detail activity + // for the selected item ID. + + Iterator preseeded_providers_iterator = ProviderListContent.ITEMS.iterator(); + while(preseeded_providers_iterator.hasNext()) + { + ProviderItem current_provider_item = preseeded_providers_iterator.next(); + if(current_provider_item.id.equalsIgnoreCase(id)) + { + try { + processAssetsFiles(current_provider_item); + // TODO ask Provider class to save provider.json, setResult(OK), finish() to ConfigurationWizard + downloadJSONFiles(current_provider_item); + } catch (IOException e) { + // TODO Auto-generated catch block + e.printStackTrace(); + } + } + } + + Intent dashboardIntent = new Intent(this, Dashboard.class); + startActivity(dashboardIntent); + } + } + + private void processAssetsFiles(ProviderItem current_provider_item) { + AssetManager assets_manager = getAssets(); + JSONObject provider_json = new JSONObject(); + try { + String provider_contents = new Scanner(new InputStreamReader(assets_manager.open(current_provider_item.provider_json_assets))).useDelimiter("\\A").next(); + provider_json = new JSONObject(provider_contents); + } catch (IOException e) { + // TODO Auto-generated catch block + e.printStackTrace(); + } catch (JSONException e) { + ConfigHelper.rescueJSONException(e); + } + ConfigHelper.saveSharedPref(ConfigHelper.provider_key, provider_json); + } + + private void downloadJSONFiles(ProviderItem current_provider_item) throws IOException { + Intent provider_API_command = new Intent(this, ProviderAPI.class); + + Bundle method_and_parameters = new Bundle(); + method_and_parameters.putString(ConfigHelper.cert_key, current_provider_item.cert_json_url); + method_and_parameters.putString(ConfigHelper.eip_service_key, current_provider_item.eip_service_json_url); + + provider_API_command.putExtra(ConfigHelper.downloadJsonFilesBundleExtra, method_and_parameters); + + startService(provider_API_command); + + } +} diff --git a/src/se/leap/leapclient/ProviderListActivity.java b/src/se/leap/leapclient/ProviderListActivity.java deleted file mode 100644 index 972e2bf0..00000000 --- a/src/se/leap/leapclient/ProviderListActivity.java +++ /dev/null @@ -1,139 +0,0 @@ -package se.leap.leapclient; - -import java.io.IOException; -import java.io.InputStreamReader; -import java.util.Iterator; -import java.util.Scanner; - -import org.json.JSONException; -import org.json.JSONObject; - -import se.leap.leapclient.ProviderListContent.ProviderItem; -import android.content.Intent; -import android.content.SharedPreferences; -import android.content.res.AssetManager; -import android.os.Bundle; -import android.support.v4.app.FragmentActivity; - - -/** - * An activity representing a list of Providers. This activity - * has different presentations for handset and tablet-size devices. On - * handsets, the activity presents a list of items, which when touched, - * lead to a {@link DashboardActivity} representing - * item details. On tablets, the activity presents the list of items and - * item details side-by-side using two vertical panes. - *

- * The activity makes heavy use of fragments. The list of items is a - * {@link ProviderListFragment} and the item details - * (if present) is a {@link DashboardFragment}. - *

- * This activity also implements the required - * {@link ProviderListFragment.Callbacks} interface - * to listen for item selections. - */ -public class ProviderListActivity extends FragmentActivity - implements ProviderListFragment.Callbacks { - - /** - * Whether or not the activity is in two-pane mode, i.e. running on a tablet - * device. - */ - private boolean mTwoPane; - - static SharedPreferences shared_preferences; - - @Override - protected void onCreate(Bundle savedInstanceState) { - super.onCreate(savedInstanceState); - setContentView(R.layout.activity_provider_list); - - shared_preferences = getPreferences(MODE_PRIVATE); - - loadPreseededProviders(); - - // TODO: If exposing deep links into your app, handle intents here. - } - - private void loadPreseededProviders() { - 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) - { - 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))); - } - } catch (IOException e) { - // TODO Auto-generated catch block - e.printStackTrace(); - } - } - - /** - * Callback method from {@link ProviderListFragment.Callbacks} - * indicating that the item with the given ID was selected. - */ - @Override - public void onItemSelected(String id) { - if (mTwoPane) { - // TODO Hmmm...is this how we should do this? What if it /is/ two pane? - } else { - // In single-pane mode, simply start the detail activity - // for the selected item ID. - - Iterator preseeded_providers_iterator = ProviderListContent.ITEMS.iterator(); - while(preseeded_providers_iterator.hasNext()) - { - ProviderItem current_provider_item = preseeded_providers_iterator.next(); - if(current_provider_item.id.equalsIgnoreCase(id)) - { - try { - processAssetsFiles(current_provider_item); - // TODO ask Provider class to save provider.json, setResult(OK), finish() to ConfigurationWizard - downloadJSONFiles(current_provider_item); - } catch (IOException e) { - // TODO Auto-generated catch block - e.printStackTrace(); - } - } - } - - Intent dashboardIntent = new Intent(this, Dashboard.class); - startActivity(dashboardIntent); - } - } - - private void processAssetsFiles(ProviderItem current_provider_item) { - AssetManager assets_manager = getAssets(); - JSONObject provider_json = new JSONObject(); - try { - String provider_contents = new Scanner(new InputStreamReader(assets_manager.open(current_provider_item.provider_json_assets))).useDelimiter("\\A").next(); - provider_json = new JSONObject(provider_contents); - } catch (IOException e) { - // TODO Auto-generated catch block - e.printStackTrace(); - } catch (JSONException e) { - ConfigHelper.rescueJSONException(e); - } - ConfigHelper.saveSharedPref(ConfigHelper.provider_key, provider_json); - } - - private void downloadJSONFiles(ProviderItem current_provider_item) throws IOException { - Intent provider_API_command = new Intent(this, ProviderAPI.class); - - Bundle method_and_parameters = new Bundle(); - method_and_parameters.putString(ConfigHelper.cert_key, current_provider_item.cert_json_url); - method_and_parameters.putString(ConfigHelper.eip_service_key, current_provider_item.eip_service_json_url); - - provider_API_command.putExtra(ConfigHelper.downloadJsonFilesBundleExtra, method_and_parameters); - - startService(provider_API_command); - - } -} diff --git a/src/se/leap/leapclient/ProviderListFragment.java b/src/se/leap/leapclient/ProviderListFragment.java index 717a65c1..d83a7bc1 100644 --- a/src/se/leap/leapclient/ProviderListFragment.java +++ b/src/se/leap/leapclient/ProviderListFragment.java @@ -1,14 +1,12 @@ package se.leap.leapclient; import android.app.Activity; +import android.app.ListFragment; import android.os.Bundle; -import android.support.v4.app.ListFragment; import android.view.View; import android.widget.ArrayAdapter; import android.widget.ListView; -import se.leap.leapclient.ProviderListContent; - /** * A list fragment representing a list of Providers. This fragment * also supports tablet devices by allowing list items to be given an -- cgit v1.2.3 From c107e15a1ca7707a7c2351a3c31f3dbd9f156b73 Mon Sep 17 00:00:00 2001 From: Sean Leonard Date: Thu, 7 Feb 2013 01:34:49 -0700 Subject: Rearrange singleton Provider.class pattern, Fix isolated SharedPreferences silos --- src/se/leap/leapclient/ConfigHelper.java | 1 + src/se/leap/leapclient/Dashboard.java | 5 +++-- src/se/leap/leapclient/Provider.java | 21 +++++++++++++-------- 3 files changed, 17 insertions(+), 10 deletions(-) (limited to 'src/se/leap/leapclient') diff --git a/src/se/leap/leapclient/ConfigHelper.java b/src/se/leap/leapclient/ConfigHelper.java index b2baed67..eded2504 100644 --- a/src/se/leap/leapclient/ConfigHelper.java +++ b/src/se/leap/leapclient/ConfigHelper.java @@ -12,6 +12,7 @@ public class ConfigHelper { final static String provider_key = "provider"; final static String cert_key = "cert"; final static String eip_service_key = "eip"; + public static final String PREFERENCES_KEY = "LEAPPreferences"; static void saveSharedPref(String shared_preferences_key, JSONObject content) { diff --git a/src/se/leap/leapclient/Dashboard.java b/src/se/leap/leapclient/Dashboard.java index c3c6a07f..b6110aac 100644 --- a/src/se/leap/leapclient/Dashboard.java +++ b/src/se/leap/leapclient/Dashboard.java @@ -29,7 +29,7 @@ public class Dashboard extends Activity { super.onCreate(savedInstanceState); setContentView(R.layout.client_dashboard); - preferences = getPreferences(MODE_PRIVATE); + preferences = getSharedPreferences(ConfigHelper.PREFERENCES_KEY,MODE_PRIVATE); // Check if we have preferences, run configuration wizard if not // TODO We should do a better check for config that this! @@ -42,7 +42,8 @@ public class Dashboard extends Activity { private void buildDashboard() { // Get our provider - provider = Provider.getInstance(preferences); + provider = Provider.getInstance(); + provider.init( this ); // Set provider name in textview providerNameTV = (TextView) findViewById(R.id.providerName); diff --git a/src/se/leap/leapclient/Provider.java b/src/se/leap/leapclient/Provider.java index b5e81c9d..4235acfd 100644 --- a/src/se/leap/leapclient/Provider.java +++ b/src/se/leap/leapclient/Provider.java @@ -11,6 +11,7 @@ import org.json.JSONArray; import org.json.JSONException; import org.json.JSONObject; +import android.app.Activity; import android.content.SharedPreferences; /** @@ -49,13 +50,24 @@ final class Provider implements Serializable { /** * */ - private Provider(SharedPreferences preferences) { + 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(ConfigHelper.PREFERENCES_KEY,0); // We don't get MODE_PRIVATE by importing SharedPreferences; i guess it's in Activity? // Inflate our provider.json data try { definition = new JSONObject( preferences.getString("provider", "") ); @@ -66,13 +78,6 @@ final class Provider implements Serializable { } } - protected static Provider getInstance(SharedPreferences preferences){ - if(instance==null){ - instance = new Provider(preferences); - } - return instance; - } - protected String getName(){ // Should we pass the locale in, or query the system here? String lang = Locale.getDefault().getLanguage(); -- cgit v1.2.3 From baaf0fec8894513768f0ba3406a9dfe2d7ad2775 Mon Sep 17 00:00:00 2001 From: Sean Leonard Date: Thu, 7 Feb 2013 01:36:14 -0700 Subject: Change in Dashboard to startActivityForResult() ConfigurationWizard --- src/se/leap/leapclient/ConfigurationWizard.java | 6 ++++-- src/se/leap/leapclient/Dashboard.java | 20 ++++++++++++++++++-- 2 files changed, 22 insertions(+), 4 deletions(-) (limited to 'src/se/leap/leapclient') diff --git a/src/se/leap/leapclient/ConfigurationWizard.java b/src/se/leap/leapclient/ConfigurationWizard.java index 6a7bd10c..f759b37e 100644 --- a/src/se/leap/leapclient/ConfigurationWizard.java +++ b/src/se/leap/leapclient/ConfigurationWizard.java @@ -118,8 +118,10 @@ public class ConfigurationWizard extends Activity } } - Intent dashboardIntent = new Intent(this, Dashboard.class); - startActivity(dashboardIntent); + // FIXME!! We're going to have more Fragments and listeners, flow control? + // TODO There is no testing done to know if we're okay... + setResult(RESULT_OK); + finish(); } } diff --git a/src/se/leap/leapclient/Dashboard.java b/src/se/leap/leapclient/Dashboard.java index b6110aac..dce99b1e 100644 --- a/src/se/leap/leapclient/Dashboard.java +++ b/src/se/leap/leapclient/Dashboard.java @@ -18,6 +18,8 @@ import android.widget.TextView; public class Dashboard extends Activity { + protected static final int CONFIGURE_LEAP = 0; + private static SharedPreferences preferences; private static Provider provider; @@ -34,11 +36,25 @@ public class Dashboard extends Activity { // Check if we have preferences, run configuration wizard if not // TODO We should do a better check for config that this! if (!preferences.contains("provider") ) - startActivity(new Intent(this, ProviderListActivity.class)); + 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 ){ + // Configuration done, get our preferences again + preferences = getSharedPreferences(ConfigHelper.PREFERENCES_KEY,MODE_PRIVATE); + + buildDashboard(); + } else { + // Something went wrong... TODO figure out what + // TODO Error dialog + } + } + } private void buildDashboard() { // Get our provider -- cgit v1.2.3 From e3acc71aaedfcf97b2adee907b6587e3c1eadf48 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Parm=C3=A9nides=20GV?= Date: Thu, 7 Feb 2013 21:25:58 +0100 Subject: Button not working from ConfigurationWizard. Trying to test cancel button from created new dialog. --- src/se/leap/leapclient/ConfigurationWizard.java | 18 ++++++++++++++ src/se/leap/leapclient/NewProviderDialog.java | 32 +++++++++++++++++++++++++ 2 files changed, 50 insertions(+) create mode 100644 src/se/leap/leapclient/NewProviderDialog.java (limited to 'src/se/leap/leapclient') diff --git a/src/se/leap/leapclient/ConfigurationWizard.java b/src/se/leap/leapclient/ConfigurationWizard.java index f759b37e..86de817c 100644 --- a/src/se/leap/leapclient/ConfigurationWizard.java +++ b/src/se/leap/leapclient/ConfigurationWizard.java @@ -10,11 +10,15 @@ import org.json.JSONObject; import se.leap.leapclient.ProviderListContent.ProviderItem; import android.app.Activity; +import android.app.DialogFragment; +import android.app.Fragment; import android.app.FragmentManager; +import android.app.FragmentTransaction; import android.content.Intent; import android.content.SharedPreferences; import android.content.res.AssetManager; import android.os.Bundle; +import android.view.View; /** @@ -41,6 +45,8 @@ public class ConfigurationWizard extends Activity * device. */ private boolean mTwoPane; + + private int mStackLevel; static SharedPreferences shared_preferences; @@ -152,4 +158,16 @@ public class ConfigurationWizard extends Activity startService(provider_API_command); } + + public void addNewProvider(View view) { + FragmentTransaction fragment_transaction = getFragmentManager().beginTransaction(); + Fragment previous_new_provider_dialog = getFragmentManager().findFragmentByTag("newProviderDialog"); + 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"); + } } diff --git a/src/se/leap/leapclient/NewProviderDialog.java b/src/se/leap/leapclient/NewProviderDialog.java new file mode 100644 index 00000000..fd6d4619 --- /dev/null +++ b/src/se/leap/leapclient/NewProviderDialog.java @@ -0,0 +1,32 @@ +package se.leap.leapclient; + +import android.app.AlertDialog; +import android.app.Dialog; +import android.app.DialogFragment; +import android.content.DialogInterface; +import android.os.Bundle; + +public class NewProviderDialog extends DialogFragment { + public Dialog onCreateDialog(Bundle savedInstanceState) { + AlertDialog.Builder builder = new AlertDialog.Builder(getActivity()); + builder.setMessage(R.string.introduce_new_provider) + .setPositiveButton(R.string.save, new DialogInterface.OnClickListener() { + public void onClick(DialogInterface dialog, int id) { + // Save provider + } + }) + .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(); + } + + public static DialogFragment newInstance() { + NewProviderDialog dialog_fragment = new NewProviderDialog(); + return dialog_fragment; + } + +} -- cgit v1.2.3 From 8db161017f55a710bd91aa14fe9c1b24d4efdeab Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Parm=C3=A9nides=20GV?= Date: Mon, 11 Feb 2013 17:32:19 +0100 Subject: The newProviderButton gets user to the DialogFragment correctly. The problem in the previous commit was that I had to modify the fragment layout, instead of that of the Activity. I learnt how to obtain and modify it from here: https://developer.android.com/reference/android/app/ListFragment.html --- src/se/leap/leapclient/ProviderListFragment.java | 13 ++++++++++++- 1 file changed, 12 insertions(+), 1 deletion(-) (limited to 'src/se/leap/leapclient') diff --git a/src/se/leap/leapclient/ProviderListFragment.java b/src/se/leap/leapclient/ProviderListFragment.java index d83a7bc1..bde3baac 100644 --- a/src/se/leap/leapclient/ProviderListFragment.java +++ b/src/se/leap/leapclient/ProviderListFragment.java @@ -1,9 +1,14 @@ package se.leap.leapclient; import android.app.Activity; +import android.app.DialogFragment; +import android.app.Fragment; +import android.app.FragmentTransaction; 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; @@ -63,7 +68,7 @@ public class ProviderListFragment extends ListFragment { */ public ProviderListFragment() { } - + @Override public void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); @@ -73,8 +78,14 @@ public class ProviderListFragment extends ListFragment { android.R.layout.simple_list_item_activated_1, android.R.id.text1, ProviderListContent.ITEMS)); + } + @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); -- cgit v1.2.3 From 162afa5bfa6485f3aacb3f60e9c92fa0c3bfa7a7 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Parm=C3=A9nides=20GV?= Date: Mon, 11 Feb 2013 20:28:59 +0100 Subject: Gets provider.json from custom url (assuming the file is at the root of the website, just as bitmask.net/provider.json), and writes it to a file in ~/leap_android. Next steps: parse that file and download eip-service and cert. --- src/se/leap/leapclient/ConfigHelper.java | 32 ++++++++++- src/se/leap/leapclient/ConfigurationWizard.java | 15 +++++- src/se/leap/leapclient/NewProviderDialog.java | 72 +++++++++++++++++++------ src/se/leap/leapclient/ProviderAPI.java | 21 +++++++- 4 files changed, 122 insertions(+), 18 deletions(-) (limited to 'src/se/leap/leapclient') diff --git a/src/se/leap/leapclient/ConfigHelper.java b/src/se/leap/leapclient/ConfigHelper.java index eded2504..c724a31c 100644 --- a/src/se/leap/leapclient/ConfigHelper.java +++ b/src/se/leap/leapclient/ConfigHelper.java @@ -1,18 +1,28 @@ package se.leap.leapclient; +import java.io.BufferedWriter; +import java.io.File; +import java.io.FileWriter; +import java.io.IOException; + import org.json.JSONException; import org.json.JSONObject; import android.content.SharedPreferences; +import android.os.Environment; +import android.util.Log; public class ConfigHelper { final static String downloadJsonFilesBundleExtra = "downloadJSONFiles"; + final static String downloadNewProviderDotJSON = "downloadNewProviderDotJSON"; final static String provider_key = "provider"; final static String cert_key = "cert"; final static String eip_service_key = "eip"; public static final String PREFERENCES_KEY = "LEAPPreferences"; + public static final String user_directory = "leap_android"; + public static String provider_key_url = "provider_main_url"; static void saveSharedPref(String shared_preferences_key, JSONObject content) { @@ -27,9 +37,29 @@ public class ConfigHelper { + ConfigurationWizard.shared_preferences.getString( shared_preferences_key, "Default")); } - + static void rescueJSONException(JSONException e) { // TODO Auto-generated catch block e.printStackTrace(); } + + static void saveFile(String filename, String content) { + File root = Environment.getExternalStorageDirectory(); + File outDir = new File(root.getAbsolutePath() + File.separator + user_directory); + if (!outDir.isDirectory()) { + outDir.mkdir(); + } + try { + if (!outDir.isDirectory()) { + throw new IOException( + "Unable to create directory " + user_directory + ". Maybe the SD card is mounted?"); + } + File outputFile = new File(outDir, filename); + BufferedWriter writer = new BufferedWriter(new FileWriter(outputFile)); + writer.write(content); + writer.close(); + } catch (IOException e) { + Log.w("leap_android", e.getMessage(), e); + } + } } diff --git a/src/se/leap/leapclient/ConfigurationWizard.java b/src/se/leap/leapclient/ConfigurationWizard.java index 86de817c..39ada310 100644 --- a/src/se/leap/leapclient/ConfigurationWizard.java +++ b/src/se/leap/leapclient/ConfigurationWizard.java @@ -8,6 +8,7 @@ import java.util.Scanner; import org.json.JSONException; import org.json.JSONObject; +import se.leap.leapclient.NewProviderDialog.NewProviderDialogInterface; import se.leap.leapclient.ProviderListContent.ProviderItem; import android.app.Activity; import android.app.DialogFragment; @@ -38,7 +39,7 @@ import android.view.View; * to listen for item selections. */ public class ConfigurationWizard extends Activity - implements ProviderListFragment.Callbacks { + implements ProviderListFragment.Callbacks, NewProviderDialog.NewProviderDialogInterface{ /** * Whether or not the activity is in two-pane mode, i.e. running on a tablet @@ -170,4 +171,16 @@ public class ConfigurationWizard extends Activity DialogFragment newFragment = NewProviderDialog.newInstance(); newFragment.show(fragment_transaction, "newProviderDialog"); } + + @Override + public void saveProvider(String provider_url) { + Intent provider_API_command = new Intent(this, ProviderAPI.class); + + Bundle method_and_parameters = new Bundle(); + method_and_parameters.putString(ConfigHelper.provider_key_url, provider_url); + + provider_API_command.putExtra(ConfigHelper.downloadNewProviderDotJSON, method_and_parameters); + + startService(provider_API_command); + } } diff --git a/src/se/leap/leapclient/NewProviderDialog.java b/src/se/leap/leapclient/NewProviderDialog.java index fd6d4619..09e7453a 100644 --- a/src/se/leap/leapclient/NewProviderDialog.java +++ b/src/se/leap/leapclient/NewProviderDialog.java @@ -1,32 +1,74 @@ package se.leap.leapclient; +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.view.ViewGroup; +import android.webkit.WebView.FindListener; +import android.widget.EditText; +import android.widget.Toast; public class NewProviderDialog extends DialogFragment { - public Dialog onCreateDialog(Bundle savedInstanceState) { - AlertDialog.Builder builder = new AlertDialog.Builder(getActivity()); - builder.setMessage(R.string.introduce_new_provider) - .setPositiveButton(R.string.save, new DialogInterface.OnClickListener() { - public void onClick(DialogInterface dialog, int id) { - // Save provider - } - }) - .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(); + + public interface NewProviderDialogInterface { + public void saveProvider(String url_provider); } + NewProviderDialogInterface interface_with_ConfigurationWizard; + public static DialogFragment newInstance() { NewProviderDialog dialog_fragment = new NewProviderDialog(); return dialog_fragment; } + + @Override + public void onAttach(Activity activity) { + super.onAttach(activity); + // Verify that the host activity implements the callback interface + try { + // Instantiate the NoticeDialogListener so we can send events to the host + interface_with_ConfigurationWizard = (NewProviderDialogInterface) activity; + } catch (ClassCastException e) { + // The activity doesn't implement the interface, throw exception + throw new ClassCastException(activity.toString() + + " must implement NoticeDialogListener"); + } + } + 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); + 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(validURL(entered_url)) { + interface_with_ConfigurationWizard.saveProvider(entered_url); + Toast.makeText(getActivity().getApplicationContext(), "Valid URL", Toast.LENGTH_LONG).show(); + } else { + url_input_field.setText(""); + Toast.makeText(getActivity().getApplicationContext(), "Not valid URL", 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(); + } + + 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/ProviderAPI.java b/src/se/leap/leapclient/ProviderAPI.java index 5a8f9572..c21e17a4 100644 --- a/src/se/leap/leapclient/ProviderAPI.java +++ b/src/se/leap/leapclient/ProviderAPI.java @@ -27,7 +27,7 @@ public class ProviderAPI extends IntentService { protected void onHandleIntent(Intent task_for) { Bundle task; System.out.println("onHandleIntent called"); - if (!(task = task_for.getBundleExtra(ConfigHelper.downloadJsonFilesBundleExtra)).isEmpty()) { + if((task = task_for.getBundleExtra(ConfigHelper.downloadJsonFilesBundleExtra)) != null) { String cert_url = (String) task.get(ConfigHelper.cert_key); String eip_service_json_url = (String) task.get(ConfigHelper.eip_service_key); try { @@ -45,6 +45,25 @@ public class ProviderAPI extends IntentService { e.printStackTrace(); } } + else if ((task = task_for.getBundleExtra(ConfigHelper.downloadNewProviderDotJSON)) != null) { + String provider_main_url = (String) task.get(ConfigHelper.provider_key_url); + String provider_json_url = guessURL(provider_main_url); + try { + JSONObject provider_json = getJSONFromProvider(provider_json_url); + String filename = provider_json_url.replaceFirst("http[s]?://", "").replaceFirst("\\/", "_") + "_provider.json".replaceFirst("__", "_"); + ConfigHelper.saveFile(filename, provider_json.toString()); + } catch (IOException e) { + // TODO Auto-generated catch block + e.printStackTrace(); + } catch (JSONException e) { + // TODO Auto-generated catch block + e.printStackTrace(); + } + } + } + + private String guessURL(String provider_main_url) { + return provider_main_url + "/provider.json"; } private String getStringFromProvider(String string_url) throws IOException { -- cgit v1.2.3 From c01aa98a1d43ae0d6b56f0d13a8782dbb6a3e35e Mon Sep 17 00:00:00 2001 From: parmegv Date: Tue, 12 Feb 2013 19:33:19 +0100 Subject: New custom provider dialog effectively adds the new provider to the ProviderListFragment, and then the user can choose it. --- src/se/leap/leapclient/ConfigHelper.java | 29 ++++++++++++++---- src/se/leap/leapclient/ConfigurationWizard.java | 34 +++++++++++++++++----- src/se/leap/leapclient/ProviderAPI.java | 13 +++++++-- .../leap/leapclient/ProviderAPIResultReceiver.java | 30 +++++++++++++++++++ src/se/leap/leapclient/ProviderListContent.java | 27 +++++++++++++++-- src/se/leap/leapclient/ProviderListFragment.java | 10 ++++--- 6 files changed, 121 insertions(+), 22 deletions(-) create mode 100644 src/se/leap/leapclient/ProviderAPIResultReceiver.java (limited to 'src/se/leap/leapclient') diff --git a/src/se/leap/leapclient/ConfigHelper.java b/src/se/leap/leapclient/ConfigHelper.java index c724a31c..5301209c 100644 --- a/src/se/leap/leapclient/ConfigHelper.java +++ b/src/se/leap/leapclient/ConfigHelper.java @@ -3,8 +3,11 @@ package se.leap.leapclient; import java.io.BufferedWriter; import java.io.File; +import java.io.FileInputStream; +import java.io.FileNotFoundException; import java.io.FileWriter; import java.io.IOException; +import java.io.InputStream; import org.json.JSONException; import org.json.JSONObject; @@ -23,6 +26,9 @@ public class ConfigHelper { public static final String PREFERENCES_KEY = "LEAPPreferences"; public static final String user_directory = "leap_android"; public static String provider_key_url = "provider_main_url"; + final public static String eip_service_api_path = "/config/eip-service.json"; + + final public static int CUSTOM_PROVIDER_ADDED = 0; static void saveSharedPref(String shared_preferences_key, JSONObject content) { @@ -45,16 +51,16 @@ public class ConfigHelper { static void saveFile(String filename, String content) { File root = Environment.getExternalStorageDirectory(); - File outDir = new File(root.getAbsolutePath() + File.separator + user_directory); - if (!outDir.isDirectory()) { - outDir.mkdir(); + File leap_dir = new File(root.getAbsolutePath() + File.separator + user_directory); + if (!leap_dir.isDirectory()) { + leap_dir.mkdir(); } try { - if (!outDir.isDirectory()) { + if (!leap_dir.isDirectory()) { throw new IOException( "Unable to create directory " + user_directory + ". Maybe the SD card is mounted?"); } - File outputFile = new File(outDir, filename); + File outputFile = new File(leap_dir, filename); BufferedWriter writer = new BufferedWriter(new FileWriter(outputFile)); writer.write(content); writer.close(); @@ -62,4 +68,17 @@ public class ConfigHelper { Log.w("leap_android", e.getMessage(), e); } } + + 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; + } } diff --git a/src/se/leap/leapclient/ConfigurationWizard.java b/src/se/leap/leapclient/ConfigurationWizard.java index 39ada310..422f9968 100644 --- a/src/se/leap/leapclient/ConfigurationWizard.java +++ b/src/se/leap/leapclient/ConfigurationWizard.java @@ -8,7 +8,7 @@ import java.util.Scanner; import org.json.JSONException; import org.json.JSONObject; -import se.leap.leapclient.NewProviderDialog.NewProviderDialogInterface; +import se.leap.leapclient.ProviderAPIResultReceiver.Receiver; import se.leap.leapclient.ProviderListContent.ProviderItem; import android.app.Activity; import android.app.DialogFragment; @@ -19,6 +19,7 @@ import android.content.Intent; import android.content.SharedPreferences; import android.content.res.AssetManager; import android.os.Bundle; +import android.os.Handler; import android.view.View; @@ -39,18 +40,19 @@ import android.view.View; * to listen for item selections. */ public class ConfigurationWizard extends Activity - implements ProviderListFragment.Callbacks, NewProviderDialog.NewProviderDialogInterface{ + implements ProviderListFragment.Callbacks, NewProviderDialog.NewProviderDialogInterface, Receiver { + /** * Whether or not the activity is in two-pane mode, i.e. running on a tablet * device. */ private boolean mTwoPane; - - private int mStackLevel; static SharedPreferences shared_preferences; + public ProviderAPIResultReceiver providerAPI_result_receiver; + @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); @@ -86,9 +88,10 @@ public class ConfigurationWizard extends Activity 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))); + ProviderListContent.addItem(new ProviderItem(provider_name, asset_manager.open(url_files_folder + "/" + url_filepath), custom)); } } catch (IOException e) { // TODO Auto-generated catch block @@ -115,7 +118,8 @@ public class ConfigurationWizard extends Activity if(current_provider_item.id.equalsIgnoreCase(id)) { try { - processAssetsFiles(current_provider_item); + if(current_provider_item.custom) + processAssetsFiles(current_provider_item); // TODO ask Provider class to save provider.json, setResult(OK), finish() to ConfigurationWizard downloadJSONFiles(current_provider_item); } catch (IOException e) { @@ -174,13 +178,29 @@ public class ConfigurationWizard extends Activity @Override public void saveProvider(String provider_url) { + providerAPI_result_receiver = new ProviderAPIResultReceiver(new Handler()); + providerAPI_result_receiver.setReceiver(this); + Intent provider_API_command = new Intent(this, ProviderAPI.class); Bundle method_and_parameters = new Bundle(); method_and_parameters.putString(ConfigHelper.provider_key_url, provider_url); provider_API_command.putExtra(ConfigHelper.downloadNewProviderDotJSON, method_and_parameters); - + provider_API_command.putExtra("receiver", providerAPI_result_receiver); startService(provider_API_command); } + + @Override + public void onReceiveResult(int resultCode, Bundle resultData) { + // TODO Auto-generated method stub + if(resultCode == ConfigHelper.CUSTOM_PROVIDER_ADDED){ + ProviderListFragment providerList = new ProviderListFragment(); + + FragmentManager fragmentManager = getFragmentManager(); + fragmentManager.beginTransaction() + .replace(R.id.configuration_wizard_layout, providerList, "providerlist") + .commit(); + } + } } diff --git a/src/se/leap/leapclient/ProviderAPI.java b/src/se/leap/leapclient/ProviderAPI.java index c21e17a4..583eea06 100644 --- a/src/se/leap/leapclient/ProviderAPI.java +++ b/src/se/leap/leapclient/ProviderAPI.java @@ -10,13 +10,16 @@ import org.apache.http.impl.client.DefaultHttpClient; 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.ResultReceiver; import android.util.Log; public class ProviderAPI extends IntentService { - + public ProviderAPI() { super("ProviderAPI"); Log.v("ClassName", "Provider API"); @@ -25,6 +28,7 @@ public class ProviderAPI extends IntentService { @Override protected void onHandleIntent(Intent task_for) { + final ResultReceiver receiver = task_for.getParcelableExtra("receiver"); Bundle task; System.out.println("onHandleIntent called"); if((task = task_for.getBundleExtra(ConfigHelper.downloadJsonFilesBundleExtra)) != null) { @@ -46,12 +50,16 @@ public class ProviderAPI extends IntentService { } } else if ((task = task_for.getBundleExtra(ConfigHelper.downloadNewProviderDotJSON)) != null) { + boolean custom = true; String provider_main_url = (String) task.get(ConfigHelper.provider_key_url); + String provider_name = provider_main_url.replaceFirst("http[s]?://", "").replaceFirst("\\/", "_"); String provider_json_url = guessURL(provider_main_url); try { JSONObject provider_json = getJSONFromProvider(provider_json_url); - String filename = provider_json_url.replaceFirst("http[s]?://", "").replaceFirst("\\/", "_") + "_provider.json".replaceFirst("__", "_"); + String filename = provider_name + "_provider.json".replaceFirst("__", "_"); ConfigHelper.saveFile(filename, provider_json.toString()); + ProviderListContent.addItem(new ProviderItem(provider_name, ConfigHelper.openFileInputStream(filename), custom)); + receiver.send(ConfigHelper.CUSTOM_PROVIDER_ADDED, Bundle.EMPTY); } catch (IOException e) { // TODO Auto-generated catch block e.printStackTrace(); @@ -84,5 +92,4 @@ public class ProviderAPI extends IntentService { String json_file_content = getStringFromProvider(json_url); return new JSONObject(json_file_content); } - } diff --git a/src/se/leap/leapclient/ProviderAPIResultReceiver.java b/src/se/leap/leapclient/ProviderAPIResultReceiver.java new file mode 100644 index 00000000..a6a8d9d8 --- /dev/null +++ b/src/se/leap/leapclient/ProviderAPIResultReceiver.java @@ -0,0 +1,30 @@ +package se.leap.leapclient; + +import android.os.Bundle; +import android.os.Handler; +import android.os.ResultReceiver; + +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; + } + + 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/ProviderListContent.java b/src/se/leap/leapclient/ProviderListContent.java index bf8bfa87..5fe206eb 100644 --- a/src/se/leap/leapclient/ProviderListContent.java +++ b/src/se/leap/leapclient/ProviderListContent.java @@ -1,5 +1,6 @@ package se.leap.leapclient; +import java.io.FileInputStream; import java.io.IOException; import java.io.InputStream; import java.util.ArrayList; @@ -35,7 +36,8 @@ public class ProviderListContent { /** * A dummy item representing a piece of content. */ - public static class ProviderItem { + public static class ProviderItem { + public boolean custom = false; public String id; public String name; public String provider_json_url; @@ -43,7 +45,6 @@ public class ProviderListContent { public String eip_service_json_url; public String cert_json_url; - public ProviderItem(String id, String name, String provider_json_url, String eip_service_json_url, String cert_json_url) { this.id = id; this.name = name; @@ -52,7 +53,7 @@ public class ProviderListContent { this.cert_json_url = cert_json_url; } - public ProviderItem(String name, InputStream urls_file_input_stream) { + public ProviderItem(String name, InputStream urls_file_input_stream, boolean custom) { try { byte[] urls_file_bytes = new byte[urls_file_input_stream.available()]; @@ -74,6 +75,26 @@ public class ProviderListContent { } } + public ProviderItem(String name, FileInputStream provider_json, boolean custom) { + + try { + byte[] urls_file_bytes = new byte[provider_json.available()]; + provider_json.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; + eip_service_json_url = (String) file_contents.get("api_uri") + ConfigHelper.eip_service_api_path; + cert_json_url = (String) file_contents.get("ca_cert_uri"); + } catch (JSONException e) { + // TODO Auto-generated catch block + e.printStackTrace(); + } catch (IOException e) { + // TODO Auto-generated catch block + e.printStackTrace(); + } + } + @Override public String toString() { return name; diff --git a/src/se/leap/leapclient/ProviderListFragment.java b/src/se/leap/leapclient/ProviderListFragment.java index bde3baac..4316e9f3 100644 --- a/src/se/leap/leapclient/ProviderListFragment.java +++ b/src/se/leap/leapclient/ProviderListFragment.java @@ -1,5 +1,6 @@ package se.leap.leapclient; +import se.leap.leapclient.ProviderListContent.ProviderItem; import android.app.Activity; import android.app.DialogFragment; import android.app.Fragment; @@ -23,6 +24,8 @@ import android.widget.ListView; */ 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. @@ -72,13 +75,12 @@ public class ProviderListFragment extends ListFragment { @Override public void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); - - setListAdapter(new ArrayAdapter( + content_adapter = new ArrayAdapter( getActivity(), android.R.layout.simple_list_item_activated_1, android.R.id.text1, - ProviderListContent.ITEMS)); - + ProviderListContent.ITEMS); + setListAdapter(content_adapter); } @Override -- cgit v1.2.3 From 0222df37d072fd6529dfe2cce1f857834ccbd02e Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Parm=C3=A9nides=20GV?= Date: Wed, 13 Feb 2013 20:40:58 +0100 Subject: Solves Issue #1757. The problem was that ProviderItem.custom was not being set by the constructor, and when using this variable from ConfigurationWizard to get providers.json from http or from assets file. --- src/se/leap/leapclient/ConfigurationWizard.java | 2 +- src/se/leap/leapclient/ProviderListContent.java | 2 ++ 2 files changed, 3 insertions(+), 1 deletion(-) (limited to 'src/se/leap/leapclient') diff --git a/src/se/leap/leapclient/ConfigurationWizard.java b/src/se/leap/leapclient/ConfigurationWizard.java index 422f9968..e252fa6b 100644 --- a/src/se/leap/leapclient/ConfigurationWizard.java +++ b/src/se/leap/leapclient/ConfigurationWizard.java @@ -118,7 +118,7 @@ public class ConfigurationWizard extends Activity if(current_provider_item.id.equalsIgnoreCase(id)) { try { - if(current_provider_item.custom) + if(!current_provider_item.custom) processAssetsFiles(current_provider_item); // TODO ask Provider class to save provider.json, setResult(OK), finish() to ConfigurationWizard downloadJSONFiles(current_provider_item); diff --git a/src/se/leap/leapclient/ProviderListContent.java b/src/se/leap/leapclient/ProviderListContent.java index 5fe206eb..d475d368 100644 --- a/src/se/leap/leapclient/ProviderListContent.java +++ b/src/se/leap/leapclient/ProviderListContent.java @@ -66,6 +66,7 @@ public class ProviderListContent { provider_json_assets = (String) file_contents.get("assets_json_provider"); eip_service_json_url = (String) file_contents.get("json_eip_service"); cert_json_url = (String) file_contents.get("cert"); + this.custom = custom; } catch (JSONException e) { // TODO Auto-generated catch block e.printStackTrace(); @@ -86,6 +87,7 @@ public class ProviderListContent { this.name = name; eip_service_json_url = (String) file_contents.get("api_uri") + ConfigHelper.eip_service_api_path; cert_json_url = (String) file_contents.get("ca_cert_uri"); + this.custom = custom; } catch (JSONException e) { // TODO Auto-generated catch block e.printStackTrace(); -- cgit v1.2.3 From 1868e180e8f56c310a52f4ed399dc9e34284957e Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Parm=C3=A9nides=20GV?= Date: Thu, 21 Feb 2013 18:49:59 +0100 Subject: Started SRP authentication. Using NG_1024 with g = 2, and SHA256 digest. Next steps: Implement async communication with the server to receive salt, send A and receive B. --- src/se/leap/leapclient/ConfigHelper.java | 8 ++++++++ src/se/leap/leapclient/ProviderAPI.java | 24 ++++++++++++++++++++++++ 2 files changed, 32 insertions(+) (limited to 'src/se/leap/leapclient') diff --git a/src/se/leap/leapclient/ConfigHelper.java b/src/se/leap/leapclient/ConfigHelper.java index 5301209c..533a426f 100644 --- a/src/se/leap/leapclient/ConfigHelper.java +++ b/src/se/leap/leapclient/ConfigHelper.java @@ -8,6 +8,7 @@ import java.io.FileNotFoundException; import java.io.FileWriter; import java.io.IOException; import java.io.InputStream; +import java.math.BigInteger; import org.json.JSONException; import org.json.JSONObject; @@ -20,14 +21,21 @@ public class ConfigHelper { final static String downloadJsonFilesBundleExtra = "downloadJSONFiles"; final static String downloadNewProviderDotJSON = "downloadNewProviderDotJSON"; + final static String srpAuth = "srpAuth"; final static String provider_key = "provider"; final static String cert_key = "cert"; final static String eip_service_key = "eip"; public static final String PREFERENCES_KEY = "LEAPPreferences"; public static final String user_directory = "leap_android"; public static String provider_key_url = "provider_main_url"; + final public static String username_key = "username"; + final public static String password_key = "password"; final public static String eip_service_api_path = "/config/eip-service.json"; + final public static String NG_1024 = + "EEAF0AB9ADB38DD69C33F80AFA8FC5E86072618775FF3C0B9EA2314C9C256576D674DF7496EA81D3383B4813D692C6E0E0D5D8E250B98BE48E495C1D6089DAD15DC7D7B46154D6B6CE8EF4AD69B15D4982559B297BCF1885C529F566660E57EC68EDBC3C05726CC02FD4CBF4976EAA9AFD5138FE8376435B9FC61D2FC0EB06E3"; + final public static BigInteger g = BigInteger.valueOf(2); + final public static int CUSTOM_PROVIDER_ADDED = 0; static void saveSharedPref(String shared_preferences_key, JSONObject content) { diff --git a/src/se/leap/leapclient/ProviderAPI.java b/src/se/leap/leapclient/ProviderAPI.java index 583eea06..e83e9e6e 100644 --- a/src/se/leap/leapclient/ProviderAPI.java +++ b/src/se/leap/leapclient/ProviderAPI.java @@ -1,8 +1,13 @@ package se.leap.leapclient; import java.io.IOException; +import java.math.BigInteger; +import java.security.SecureRandom; import java.util.Scanner; +import org.bouncycastle.crypto.agreement.srp.SRP6Client; +import org.bouncycastle.crypto.digests.SHA256Digest; +import org.bouncycastle.jcajce.provider.digest.Whirlpool.Digest; import org.apache.http.HttpEntity; import org.apache.http.HttpResponse; import org.apache.http.client.methods.HttpGet; @@ -68,6 +73,25 @@ public class ProviderAPI extends IntentService { e.printStackTrace(); } } + else if ((task = task_for.getBundleExtra(ConfigHelper.srpAuth)) != null) { + String username = (String) task.get(ConfigHelper.username_key); + String password = (String) task.get(ConfigHelper.password_key); + SRP6Client srp_client = new SRP6Client(); + srp_client.init(new BigInteger(ConfigHelper.NG_1024, 16), ConfigHelper.g, new SHA256Digest(), new SecureRandom()); + // Receive salt from server + String salt = getSaltFromSRPServer(); + BigInteger A = srp_client.generateClientCredentials(salt.getBytes(), username.getBytes(), password.getBytes()); + //Send A to the server. Doing a http response with cookies? + //Receive server generated serverB + //S = calculateSecret(BigInteger serverB) + //K = H(S) + //Now the two parties have a shared, strong session key K. To complete authentication, they need to prove to each other that their keys match. + } + } + + private String getSaltFromSRPServer() { + // TODO Auto-generated method stub + return null; } private String guessURL(String provider_main_url) { -- cgit v1.2.3 From 5964b1ffec270b99cdbc962cd0c4aefa2c5fcb4d Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Parm=C3=A9nides=20GV?= Date: Mon, 25 Feb 2013 21:30:42 +0100 Subject: Finished first implementation of SRP. Next step: get cookies understood, how do I get server's sent parameters? --- src/se/leap/leapclient/ConfigHelper.java | 1 + src/se/leap/leapclient/ProviderAPI.java | 154 +++++++++++++++++++++++++++++-- 2 files changed, 147 insertions(+), 8 deletions(-) (limited to 'src/se/leap/leapclient') diff --git a/src/se/leap/leapclient/ConfigHelper.java b/src/se/leap/leapclient/ConfigHelper.java index 533a426f..7649fcae 100644 --- a/src/se/leap/leapclient/ConfigHelper.java +++ b/src/se/leap/leapclient/ConfigHelper.java @@ -28,6 +28,7 @@ public class ConfigHelper { public static final String PREFERENCES_KEY = "LEAPPreferences"; public static final String user_directory = "leap_android"; public static String provider_key_url = "provider_main_url"; + final public static String srp_server_url_key = "srp_server_url"; final public static String username_key = "username"; final public static String password_key = "password"; final public static String eip_service_api_path = "/config/eip-service.json"; diff --git a/src/se/leap/leapclient/ProviderAPI.java b/src/se/leap/leapclient/ProviderAPI.java index e83e9e6e..39bb50ec 100644 --- a/src/se/leap/leapclient/ProviderAPI.java +++ b/src/se/leap/leapclient/ProviderAPI.java @@ -2,15 +2,25 @@ package se.leap.leapclient; import java.io.IOException; import java.math.BigInteger; +import java.nio.ByteBuffer; +import java.security.MessageDigest; +import java.security.NoSuchAlgorithmException; import java.security.SecureRandom; +import java.util.List; +import java.util.Random; import java.util.Scanner; +import org.bouncycastle.crypto.CryptoException; import org.bouncycastle.crypto.agreement.srp.SRP6Client; import org.bouncycastle.crypto.digests.SHA256Digest; +import org.bouncycastle.crypto.prng.RandomGenerator; import org.bouncycastle.jcajce.provider.digest.Whirlpool.Digest; import org.apache.http.HttpEntity; import org.apache.http.HttpResponse; +import org.apache.http.client.ClientProtocolException; import org.apache.http.client.methods.HttpGet; +import org.apache.http.client.methods.HttpPost; +import org.apache.http.cookie.Cookie; import org.apache.http.impl.client.DefaultHttpClient; import org.json.JSONException; import org.json.JSONObject; @@ -76,22 +86,150 @@ public class ProviderAPI extends IntentService { else if ((task = task_for.getBundleExtra(ConfigHelper.srpAuth)) != null) { String username = (String) task.get(ConfigHelper.username_key); String password = (String) task.get(ConfigHelper.password_key); + String authentication_server = (String) task.get(ConfigHelper.srp_server_url_key); SRP6Client srp_client = new SRP6Client(); srp_client.init(new BigInteger(ConfigHelper.NG_1024, 16), ConfigHelper.g, new SHA256Digest(), new SecureRandom()); // Receive salt from server - String salt = getSaltFromSRPServer(); - BigInteger A = srp_client.generateClientCredentials(salt.getBytes(), username.getBytes(), password.getBytes()); + Random random_number_generator = new Random(); + int salt = random_number_generator.nextInt(Integer.valueOf(ConfigHelper.NG_1024)); + byte[] salt_in_bytes = ByteBuffer.allocate(4).putInt(salt).array(); + BigInteger clientA = srp_client.generateClientCredentials(salt_in_bytes, username.getBytes(), password.getBytes()); //Send A to the server. Doing a http response with cookies? //Receive server generated serverB - //S = calculateSecret(BigInteger serverB) - //K = H(S) - //Now the two parties have a shared, strong session key K. To complete authentication, they need to prove to each other that their keys match. + try { + BigInteger serverB = sendParameterToSRPServer(authentication_server, "A", clientA); + BigInteger s = srp_client.calculateSecret(serverB); + MessageDigest digest_of_S = MessageDigest.getInstance("SHA-256"); + digest_of_S.update(s.toByteArray(), 0, s.toByteArray().length); + BigInteger k = new BigInteger(digest_of_S.digest()); + BigInteger m1 = generateM1(k, clientA, serverB, salt, username); + BigInteger m2 = sendParameterToSRPServer(authentication_server, "M1", m1); + sendM1(m2, k, clientA, serverB, salt, username); + boolean verified = verifyM2(m2, k, clientA, serverB, salt, username); + if(!verified) { + + } + } catch (ClientProtocolException e) { + // TODO Auto-generated catch block + e.printStackTrace(); + } catch (IOException e) { + // TODO Auto-generated catch block + // From sendAToSRPServer or from sendM1ToSRPServer + e.printStackTrace(); + } catch (CryptoException e) { + // TODO Auto-generated catch block + // From calculateSecret + e.printStackTrace(); + } catch (NoSuchAlgorithmException e) { + // TODO Auto-generated catch block + // From MessageDigest.getInstance + e.printStackTrace(); + } } } + + private void sendM1(BigInteger m2, BigInteger k, BigInteger clientA, + BigInteger serverB, int salt, String username) throws NoSuchAlgorithmException { + BigInteger M1 = generateM1(k, clientA, serverB, salt, username); + + } - private String getSaltFromSRPServer() { - // TODO Auto-generated method stub - return null; + private BigInteger generateM1(BigInteger K, BigInteger clientA, BigInteger serverB, int salt, String username) throws NoSuchAlgorithmException { + /* https://github.com/leapcode/srp_js/blob/master/src/srp_session.js + var hashN = SHA256(hex2a(N.toString(16))) + var hashG = SHA256(hex2a(g.toString(16))) + var hexString = hexXor(hashN, hashG); + hexString += SHA256(I); + hexString += salt; + hexString += Astr; + hexString += Bstr; + hexString += K + M = SHA256(hex2a(hexString)); + //M2 = H(A, M, K) + M2 = SHA256(hex2a(Astr + M + K)); + */ + MessageDigest digest_of_N = MessageDigest.getInstance("SHA-256"); + digest_of_N.update(ConfigHelper.NG_1024.getBytes()); + String digest_of_N_as_string = new String(digest_of_N.digest()); + + MessageDigest digest_of_G = MessageDigest.getInstance("SHA-256"); + digest_of_G.update(ConfigHelper.g.toByteArray()); + String digest_of_G_as_string = new String(digest_of_G.digest()); + + String xor_n_and_g = hexXor(digest_of_N_as_string, digest_of_G_as_string); + + MessageDigest digest_of_username = MessageDigest.getInstance("SHA-256"); + digest_of_username.update(username.getBytes()); + String digest_of_username_as_string = new String(digest_of_username.digest()); + + MessageDigest my_M1 = MessageDigest.getInstance("SHA-256"); + String m1_source_string = xor_n_and_g + digest_of_username_as_string + clientA.toString() + serverB.toString() + K.toString(); + + my_M1.update(m1_source_string.getBytes()); + + return new BigInteger(my_M1.digest()); + } + + private boolean verifyM2(BigInteger M2, BigInteger K, BigInteger clientA, BigInteger serverB, int salt, String username) throws NoSuchAlgorithmException { + /* https://github.com/leapcode/srp_js/blob/master/src/srp_session.js + var hashN = SHA256(hex2a(N.toString(16))) + var hashG = SHA256(hex2a(g.toString(16))) + var hexString = hexXor(hashN, hashG); + hexString += SHA256(I); + hexString += salt; + hexString += Astr; + hexString += Bstr; + hexString += K + M = SHA256(hex2a(hexString)); + //M2 = H(A, M, K) + M2 = SHA256(hex2a(Astr + M + K)); + */ + MessageDigest digest_of_N = MessageDigest.getInstance("SHA-256"); + digest_of_N.update(ConfigHelper.NG_1024.getBytes()); + String digest_of_N_as_string = new String(digest_of_N.digest()); + + MessageDigest digest_of_G = MessageDigest.getInstance("SHA-256"); + digest_of_G.update(ConfigHelper.g.toByteArray()); + String digest_of_G_as_string = new String(digest_of_G.digest()); + + String xor_n_and_g = hexXor(digest_of_N_as_string, digest_of_G_as_string); + + MessageDigest digest_of_username = MessageDigest.getInstance("SHA-256"); + digest_of_username.update(username.getBytes()); + String digest_of_username_as_string = new String(digest_of_username.digest()); + + MessageDigest my_M1 = MessageDigest.getInstance("SHA-256"); + String m1_source_string = xor_n_and_g + digest_of_username_as_string + clientA.toString() + serverB.toString() + K.toString(); + my_M1.update(m1_source_string.getBytes()); + + MessageDigest my_own_M2 = MessageDigest.getInstance("SHA-256"); + String m2_source_string = clientA.toString() + new String(my_M1.digest()) + K.toString(); + + my_own_M2.update(m2_source_string.getBytes()); + + return M2 == new BigInteger(my_own_M2.digest()); + } + + + private String hexXor(String a, String b) { + String str = ""; + for (int i = 0; i < a.length(); i += 2) { + int xor = Integer.parseInt(a.substring(i, 2), 16) ^ Integer.parseInt(b.substring(i, 2), 16); + String xor_string = String.valueOf(Integer.valueOf(String.valueOf(xor), 16)); + str += (xor_string.length() == 1) ? ("0" + xor) : xor_string; + } + return str; + } + + private BigInteger sendParameterToSRPServer(String server_url, String parameter_name, BigInteger parameter) throws ClientProtocolException, IOException { + DefaultHttpClient client = new LeapHttpClient(getApplicationContext()); + String parameter_chain = parameter_name + "=" + parameter.toString(); + HttpPost post = new HttpPost(server_url + "?" + parameter_chain); + // TODO Look for how our srp server sends the serverB (as a cookie?) and how to fetch it from response. + HttpResponse getResponse = client.execute(post); + HttpEntity responseEntity = getResponse.getEntity(); + List cookies = client.getCookieStore().getCookies(); + return BigInteger.valueOf((Long.valueOf(cookies.get(0).getValue()))); } private String guessURL(String provider_main_url) { -- cgit v1.2.3 From 36a185ef45678ce2a897d7dda1392b0e147ae336 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Parm=C3=A9nides=20GV?= Date: Wed, 27 Feb 2013 17:31:26 +0100 Subject: Added bouncycastle lib with libs folder. --- src/se/leap/leapclient/ProviderAPI.java | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) (limited to 'src/se/leap/leapclient') diff --git a/src/se/leap/leapclient/ProviderAPI.java b/src/se/leap/leapclient/ProviderAPI.java index 39bb50ec..96544159 100644 --- a/src/se/leap/leapclient/ProviderAPI.java +++ b/src/se/leap/leapclient/ProviderAPI.java @@ -84,9 +84,9 @@ public class ProviderAPI extends IntentService { } } else if ((task = task_for.getBundleExtra(ConfigHelper.srpAuth)) != null) { - String username = (String) task.get(ConfigHelper.username_key); - String password = (String) task.get(ConfigHelper.password_key); - String authentication_server = (String) task.get(ConfigHelper.srp_server_url_key); + String username = "username";//(String) task.get(ConfigHelper.username_key); + String password = "password";//(String) task.get(ConfigHelper.password_key); + String authentication_server = "localhost:3000";//(String) task.get(ConfigHelper.srp_server_url_key); SRP6Client srp_client = new SRP6Client(); srp_client.init(new BigInteger(ConfigHelper.NG_1024, 16), ConfigHelper.g, new SHA256Digest(), new SecureRandom()); // Receive salt from server -- cgit v1.2.3 From 018eb179f820b09d2e65c5ede1d4a867957bbce4 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Parm=C3=A9nides=20GV?= Date: Thu, 28 Feb 2013 16:56:51 +0100 Subject: Now, ProviderAPI sends result to ConfigurationWizard. Refactored downloadJsonFiles in ProviderAPI, new method from block in the intent identification. --- src/se/leap/leapclient/ConfigHelper.java | 4 ++- src/se/leap/leapclient/ConfigurationWizard.java | 9 ++++- src/se/leap/leapclient/ProviderAPI.java | 44 ++++++++++++++++--------- 3 files changed, 39 insertions(+), 18 deletions(-) (limited to 'src/se/leap/leapclient') diff --git a/src/se/leap/leapclient/ConfigHelper.java b/src/se/leap/leapclient/ConfigHelper.java index 7649fcae..c9810519 100644 --- a/src/se/leap/leapclient/ConfigHelper.java +++ b/src/se/leap/leapclient/ConfigHelper.java @@ -37,7 +37,9 @@ public class ConfigHelper { "EEAF0AB9ADB38DD69C33F80AFA8FC5E86072618775FF3C0B9EA2314C9C256576D674DF7496EA81D3383B4813D692C6E0E0D5D8E250B98BE48E495C1D6089DAD15DC7D7B46154D6B6CE8EF4AD69B15D4982559B297BCF1885C529F566660E57EC68EDBC3C05726CC02FD4CBF4976EAA9AFD5138FE8376435B9FC61D2FC0EB06E3"; final public static BigInteger g = BigInteger.valueOf(2); - final public static int CUSTOM_PROVIDER_ADDED = 0; + final public static int CUSTOM_PROVIDER_ADDED = 0; + final public static int CORRECTLY_DOWNLOADED_JSON_FILES = 0; + final public static int INCORRECTLY_DOWNLOADED_JSON_FILES = 0; static void saveSharedPref(String shared_preferences_key, JSONObject content) { diff --git a/src/se/leap/leapclient/ConfigurationWizard.java b/src/se/leap/leapclient/ConfigurationWizard.java index e252fa6b..e41eb5cf 100644 --- a/src/se/leap/leapclient/ConfigurationWizard.java +++ b/src/se/leap/leapclient/ConfigurationWizard.java @@ -159,6 +159,7 @@ public class ConfigurationWizard extends Activity method_and_parameters.putString(ConfigHelper.eip_service_key, current_provider_item.eip_service_json_url); provider_API_command.putExtra(ConfigHelper.downloadJsonFilesBundleExtra, method_and_parameters); + provider_API_command.putExtra("receiver", providerAPI_result_receiver); startService(provider_API_command); @@ -188,12 +189,12 @@ public class ConfigurationWizard extends Activity provider_API_command.putExtra(ConfigHelper.downloadNewProviderDotJSON, method_and_parameters); provider_API_command.putExtra("receiver", providerAPI_result_receiver); + startService(provider_API_command); } @Override public void onReceiveResult(int resultCode, Bundle resultData) { - // TODO Auto-generated method stub if(resultCode == ConfigHelper.CUSTOM_PROVIDER_ADDED){ ProviderListFragment providerList = new ProviderListFragment(); @@ -202,5 +203,11 @@ public class ConfigurationWizard extends Activity .replace(R.id.configuration_wizard_layout, providerList, "providerlist") .commit(); } + else if(resultCode == ConfigHelper.INCORRECTLY_DOWNLOADED_JSON_FILES) { + // TODO Show error + } + else if(resultCode == ConfigHelper.CORRECTLY_DOWNLOADED_JSON_FILES) { + // TODO Show nothing? Show success? + } } } diff --git a/src/se/leap/leapclient/ProviderAPI.java b/src/se/leap/leapclient/ProviderAPI.java index 96544159..19404c2b 100644 --- a/src/se/leap/leapclient/ProviderAPI.java +++ b/src/se/leap/leapclient/ProviderAPI.java @@ -44,25 +44,14 @@ public class ProviderAPI extends IntentService { @Override protected void onHandleIntent(Intent task_for) { final ResultReceiver receiver = task_for.getParcelableExtra("receiver"); + Bundle task; System.out.println("onHandleIntent called"); if((task = task_for.getBundleExtra(ConfigHelper.downloadJsonFilesBundleExtra)) != null) { - String cert_url = (String) task.get(ConfigHelper.cert_key); - String eip_service_json_url = (String) task.get(ConfigHelper.eip_service_key); - try { - String cert_string = getStringFromProvider(cert_url); - JSONObject cert_json = new JSONObject("{ \"certificate\" : \"" + cert_string + "\"}"); - ConfigHelper.saveSharedPref(ConfigHelper.cert_key, cert_json); - JSONObject eip_service_json = getJSONFromProvider(eip_service_json_url); - ConfigHelper.saveSharedPref(ConfigHelper.eip_service_key, eip_service_json); - } catch (IOException e) { - // TODO Auto-generated catch block - e.printStackTrace(); - } catch (JSONException e) { - ConfigHelper.rescueJSONException(e); - } catch(Exception e) { - e.printStackTrace(); - } + if(!downloadJsonFiles(task)) + 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.downloadNewProviderDotJSON)) != null) { boolean custom = true; @@ -128,6 +117,29 @@ public class ProviderAPI extends IntentService { } } + private boolean downloadJsonFiles(Bundle task) { + String cert_url = (String) task.get(ConfigHelper.cert_key); + String eip_service_json_url = (String) task.get(ConfigHelper.eip_service_key); + try { + String cert_string = getStringFromProvider(cert_url); + JSONObject cert_json = new JSONObject("{ \"certificate\" : \"" + cert_string + "\"}"); + ConfigHelper.saveSharedPref(ConfigHelper.cert_key, cert_json); + JSONObject eip_service_json = getJSONFromProvider(eip_service_json_url); + ConfigHelper.saveSharedPref(ConfigHelper.eip_service_key, eip_service_json); + return true; + } catch (IOException e) { + // TODO Auto-generated catch block + e.printStackTrace(); + return false; + } catch (JSONException e) { + ConfigHelper.rescueJSONException(e); + return false; + } catch(Exception e) { + e.printStackTrace(); + return false; + } + } + private void sendM1(BigInteger m2, BigInteger k, BigInteger clientA, BigInteger serverB, int salt, String username) throws NoSuchAlgorithmException { BigInteger M1 = generateM1(k, clientA, serverB, salt, username); -- cgit v1.2.3 From 5b9e20dca5f70289a2fcdfaa9f45fabd28887726 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Parm=C3=A9nides=20GV?= Date: Tue, 5 Mar 2013 21:13:27 +0100 Subject: Registering method from ProviderAPI implemented and tested. M1 is not OK, because errors (with null description, awkward) are received from posting M1 to the server instead of M2. Next step: purge user database from leap_webapp and start testing again. --- src/se/leap/leapclient/ConfigHelper.java | 24 ++- src/se/leap/leapclient/ConfigurationWizard.java | 4 - src/se/leap/leapclient/ProviderAPI.java | 261 +++++++++++++++++------- 3 files changed, 205 insertions(+), 84 deletions(-) (limited to 'src/se/leap/leapclient') diff --git a/src/se/leap/leapclient/ConfigHelper.java b/src/se/leap/leapclient/ConfigHelper.java index c9810519..41364e96 100644 --- a/src/se/leap/leapclient/ConfigHelper.java +++ b/src/se/leap/leapclient/ConfigHelper.java @@ -7,7 +7,6 @@ import java.io.FileInputStream; import java.io.FileNotFoundException; import java.io.FileWriter; import java.io.IOException; -import java.io.InputStream; import java.math.BigInteger; import org.json.JSONException; @@ -18,10 +17,14 @@ import android.os.Environment; import android.util.Log; public class ConfigHelper { + + public static SharedPreferences shared_preferences; final static String downloadJsonFilesBundleExtra = "downloadJSONFiles"; final static String downloadNewProviderDotJSON = "downloadNewProviderDotJSON"; - final static String srpAuth = "srpAuth"; + public static final String srpRegister = "srpRegister"; + final public static String srpAuth = "srpAuth"; + final public static String resultKey = "result"; final static String provider_key = "provider"; final static String cert_key = "cert"; final static String eip_service_key = "eip"; @@ -38,12 +41,16 @@ public class ConfigHelper { final public static BigInteger g = BigInteger.valueOf(2); final public static int CUSTOM_PROVIDER_ADDED = 0; - final public static int CORRECTLY_DOWNLOADED_JSON_FILES = 0; - final public static int INCORRECTLY_DOWNLOADED_JSON_FILES = 0; + final public static int CORRECTLY_DOWNLOADED_JSON_FILES = 1; + final public static int INCORRECTLY_DOWNLOADED_JSON_FILES = 2; + final public static int SRP_AUTHENTICATION_SUCCESSFUL = 3; + final public static int SRP_AUTHENTICATION_FAILED = 4; + public static final int SRP_REGISTRATION_SUCCESSFUL = 5; + public static final int SRP_REGISTRATION_FAILED = 6; static void saveSharedPref(String shared_preferences_key, JSONObject content) { - SharedPreferences.Editor shared_preferences_editor = ConfigurationWizard.shared_preferences + SharedPreferences.Editor shared_preferences_editor = shared_preferences .edit(); shared_preferences_editor.putString(shared_preferences_key, content.toString()); @@ -51,7 +58,7 @@ public class ConfigHelper { System.out.println("Shared preferences updated: key = " + shared_preferences_key + " Content = " - + ConfigurationWizard.shared_preferences.getString( + + shared_preferences.getString( shared_preferences_key, "Default")); } @@ -92,4 +99,9 @@ public class ConfigHelper { } return input_stream; } + + public static void setSharedPreferences( + SharedPreferences shared_preferences) { + ConfigHelper.shared_preferences = shared_preferences; + } } diff --git a/src/se/leap/leapclient/ConfigurationWizard.java b/src/se/leap/leapclient/ConfigurationWizard.java index e41eb5cf..33ff31fe 100644 --- a/src/se/leap/leapclient/ConfigurationWizard.java +++ b/src/se/leap/leapclient/ConfigurationWizard.java @@ -48,8 +48,6 @@ public class ConfigurationWizard extends Activity * device. */ private boolean mTwoPane; - - static SharedPreferences shared_preferences; public ProviderAPIResultReceiver providerAPI_result_receiver; @@ -59,8 +57,6 @@ public class ConfigurationWizard extends Activity setContentView(R.layout.activity_configuration_wizard); - shared_preferences = getSharedPreferences(ConfigHelper.PREFERENCES_KEY,MODE_PRIVATE); - loadPreseededProviders(); // Only create our fragments if we're not restoring a saved instance diff --git a/src/se/leap/leapclient/ProviderAPI.java b/src/se/leap/leapclient/ProviderAPI.java index 19404c2b..41612d16 100644 --- a/src/se/leap/leapclient/ProviderAPI.java +++ b/src/se/leap/leapclient/ProviderAPI.java @@ -12,6 +12,7 @@ import java.util.Scanner; import org.bouncycastle.crypto.CryptoException; import org.bouncycastle.crypto.agreement.srp.SRP6Client; +import org.bouncycastle.crypto.agreement.srp.SRP6VerifierGenerator; import org.bouncycastle.crypto.digests.SHA256Digest; import org.bouncycastle.crypto.prng.RandomGenerator; import org.bouncycastle.jcajce.provider.digest.Whirlpool.Digest; @@ -29,6 +30,7 @@ import se.leap.leapclient.ProviderListContent.ProviderItem; import android.app.IntentService; import android.content.Intent; +import android.content.SharedPreferences; import android.os.Bundle; import android.os.ResultReceiver; import android.util.Log; @@ -38,7 +40,6 @@ public class ProviderAPI extends IntentService { public ProviderAPI() { super("ProviderAPI"); Log.v("ClassName", "Provider API"); - // TODO Auto-generated constructor stub } @Override @@ -72,51 +73,20 @@ public class ProviderAPI extends IntentService { e.printStackTrace(); } } + else if ((task = task_for.getBundleExtra(ConfigHelper.srpRegister)) != null) { + if(!registerWithSRP(task)) + receiver.send(ConfigHelper.SRP_REGISTRATION_FAILED, Bundle.EMPTY); + else + receiver.send(ConfigHelper.SRP_REGISTRATION_SUCCESSFUL, Bundle.EMPTY); + } else if ((task = task_for.getBundleExtra(ConfigHelper.srpAuth)) != null) { - String username = "username";//(String) task.get(ConfigHelper.username_key); - String password = "password";//(String) task.get(ConfigHelper.password_key); - String authentication_server = "localhost:3000";//(String) task.get(ConfigHelper.srp_server_url_key); - SRP6Client srp_client = new SRP6Client(); - srp_client.init(new BigInteger(ConfigHelper.NG_1024, 16), ConfigHelper.g, new SHA256Digest(), new SecureRandom()); - // Receive salt from server - Random random_number_generator = new Random(); - int salt = random_number_generator.nextInt(Integer.valueOf(ConfigHelper.NG_1024)); - byte[] salt_in_bytes = ByteBuffer.allocate(4).putInt(salt).array(); - BigInteger clientA = srp_client.generateClientCredentials(salt_in_bytes, username.getBytes(), password.getBytes()); - //Send A to the server. Doing a http response with cookies? - //Receive server generated serverB - try { - BigInteger serverB = sendParameterToSRPServer(authentication_server, "A", clientA); - BigInteger s = srp_client.calculateSecret(serverB); - MessageDigest digest_of_S = MessageDigest.getInstance("SHA-256"); - digest_of_S.update(s.toByteArray(), 0, s.toByteArray().length); - BigInteger k = new BigInteger(digest_of_S.digest()); - BigInteger m1 = generateM1(k, clientA, serverB, salt, username); - BigInteger m2 = sendParameterToSRPServer(authentication_server, "M1", m1); - sendM1(m2, k, clientA, serverB, salt, username); - boolean verified = verifyM2(m2, k, clientA, serverB, salt, username); - if(!verified) { - - } - } catch (ClientProtocolException e) { - // TODO Auto-generated catch block - e.printStackTrace(); - } catch (IOException e) { - // TODO Auto-generated catch block - // From sendAToSRPServer or from sendM1ToSRPServer - e.printStackTrace(); - } catch (CryptoException e) { - // TODO Auto-generated catch block - // From calculateSecret - e.printStackTrace(); - } catch (NoSuchAlgorithmException e) { - // TODO Auto-generated catch block - // From MessageDigest.getInstance - e.printStackTrace(); - } + if(!authenticateBySRP(task)) + receiver.send(ConfigHelper.SRP_AUTHENTICATION_FAILED, Bundle.EMPTY); + else + receiver.send(ConfigHelper.SRP_AUTHENTICATION_SUCCESSFUL, Bundle.EMPTY); } } - + private boolean downloadJsonFiles(Bundle task) { String cert_url = (String) task.get(ConfigHelper.cert_key); String eip_service_json_url = (String) task.get(ConfigHelper.eip_service_key); @@ -140,13 +110,115 @@ public class ProviderAPI extends IntentService { } } - private void sendM1(BigInteger m2, BigInteger k, BigInteger clientA, - BigInteger serverB, int salt, String username) throws NoSuchAlgorithmException { - BigInteger M1 = generateM1(k, clientA, serverB, salt, username); + private boolean registerWithSRP(Bundle task) { + String username = (String) task.get(ConfigHelper.username_key); + String password = (String) task.get(ConfigHelper.password_key); + String authentication_server = (String) task.get(ConfigHelper.srp_server_url_key); + + BigInteger ng_1024 = new BigInteger(ConfigHelper.NG_1024, 16); + BigInteger salt = ng_1024.probablePrime(1024, null); + byte[] salt_in_bytes = salt.toByteArray(); + SRP6VerifierGenerator verifier_generator = new SRP6VerifierGenerator(); + verifier_generator.init(ng_1024, ConfigHelper.g, new SHA256Digest()); + BigInteger verifier = verifier_generator.generateVerifier(salt_in_bytes, username.getBytes(), password.getBytes()); + + return sendRegisterMessage(authentication_server, salt.toString(16), verifier.toString(), username); } + + private boolean sendRegisterMessage(String server_url, String password_salt, String password_verifier, String login) { + DefaultHttpClient client = new LeapHttpClient(getApplicationContext()); + String parameter_chain = "user[password_salt]" + "=" + password_salt + "&" + "user[password_verifier]" + "=" + password_verifier + "&" + "user[login]" + "=" + login; + HttpPost post = new HttpPost(server_url + "/users.json" + "?" + parameter_chain); - private BigInteger generateM1(BigInteger K, BigInteger clientA, BigInteger serverB, int salt, String username) throws NoSuchAlgorithmException { + HttpResponse getResponse; + try { + getResponse = client.execute(post); + HttpEntity responseEntity = getResponse.getEntity(); + String plain_response = new Scanner(responseEntity.getContent()).useDelimiter("\\A").next(); + JSONObject json_response = new JSONObject(plain_response); + if(!json_response.getString("errors").isEmpty()) { + return false; + } + else if(json_response.getString("password_salt").equalsIgnoreCase(password_salt) && json_response.getString("login").equalsIgnoreCase(login)) + return true; + } catch (ClientProtocolException e) { + // TODO Auto-generated catch block + e.printStackTrace(); + 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; + } + + return false; + } + + private boolean authenticateBySRP(Bundle task) { + String username = (String) task.get(ConfigHelper.username_key); + String password = (String) task.get(ConfigHelper.password_key); + String authentication_server = (String) task.get(ConfigHelper.srp_server_url_key); + SRP6Client srp_client = new SRP6Client(); + srp_client.init(new BigInteger(ConfigHelper.NG_1024, 16), ConfigHelper.g, new SHA256Digest(), new SecureRandom()); + // Receive salt from server + Random random_number_generator = new Random(); + BigInteger ng_1024 = new BigInteger(ConfigHelper.NG_1024, 16); + byte[] salt_in_bytes = ng_1024.probablePrime(1024, null).toByteArray(); + //int salt = random_number_generator.nextInt(Integer.parseInt(ConfigHelper.NG_1024, 16)); + //byte[] salt_in_bytes = ByteBuffer.allocate(4).putInt(salt).array(); + BigInteger clientA = srp_client.generateClientCredentials(salt_in_bytes, username.getBytes(), password.getBytes()); + //Send A to the server. Doing a http response with cookies? + //Receive server generated serverB + try { + BigInteger serverB = sendAToSRPServer(authentication_server, username, clientA); + if(serverB == BigInteger.ZERO) + return false; // TODO Show error: error trying to start authentication with provider + BigInteger s = srp_client.calculateSecret(serverB); + MessageDigest digest_of_S = MessageDigest.getInstance("SHA-256"); + digest_of_S.update(s.toByteArray(), 0, s.toByteArray().length); + BigInteger k = new BigInteger(digest_of_S.digest()); + BigInteger m1 = generateM1(k, clientA, serverB, username); + BigInteger m2 = sendM1ToSRPServer(authentication_server, "M1", m1); + if(m2 == BigInteger.ZERO) + return false; // TODO Show error: error in M1 + boolean verified = verifyM2(m2, k, clientA, serverB, username); + return verified; // TODO If false, Username or password are not correct -> Show a warning and get back to login fragment + } catch (ClientProtocolException e) { + // TODO Auto-generated catch block + e.printStackTrace(); + return false; + } catch (IOException e) { + // TODO Auto-generated catch block + // From sendAToSRPServer or from sendM1ToSRPServer + e.printStackTrace(); + return false; + } catch (CryptoException e) { + // TODO Auto-generated catch block + // From calculateSecret + e.printStackTrace(); + return false; + } catch (NoSuchAlgorithmException e) { + // TODO Auto-generated catch block + // From MessageDigest.getInstance + e.printStackTrace(); + return false; + } catch (NumberFormatException e) { + // TODO Auto-generated catch block + e.printStackTrace(); + return false; + } catch (JSONException e) { + // TODO Auto-generated catch block + e.printStackTrace(); + return false; + } + } + + private BigInteger generateM1(BigInteger K, BigInteger clientA, BigInteger serverB, String username) throws NoSuchAlgorithmException { /* https://github.com/leapcode/srp_js/blob/master/src/srp_session.js var hashN = SHA256(hex2a(N.toString(16))) var hashG = SHA256(hex2a(g.toString(16))) @@ -160,29 +232,21 @@ public class ProviderAPI extends IntentService { //M2 = H(A, M, K) M2 = SHA256(hex2a(Astr + M + K)); */ - MessageDigest digest_of_N = MessageDigest.getInstance("SHA-256"); - digest_of_N.update(ConfigHelper.NG_1024.getBytes()); - String digest_of_N_as_string = new String(digest_of_N.digest()); + String digest_of_N_as_string = new BigInteger(MessageDigest.getInstance("SHA-256").digest(ConfigHelper.NG_1024.getBytes())).toString(16); - MessageDigest digest_of_G = MessageDigest.getInstance("SHA-256"); - digest_of_G.update(ConfigHelper.g.toByteArray()); - String digest_of_G_as_string = new String(digest_of_G.digest()); + String digest_of_G_as_string = new BigInteger(1, MessageDigest.getInstance("SHA-256").digest(ConfigHelper.g.toString(16).getBytes())).toString(16); + //String digest_of_G_as_string = new BigInteger(MessageDigest.getInstance("SHA-256").digest(ConfigHelper.g.toByteArray())).toString(16); String xor_n_and_g = hexXor(digest_of_N_as_string, digest_of_G_as_string); - MessageDigest digest_of_username = MessageDigest.getInstance("SHA-256"); - digest_of_username.update(username.getBytes()); - String digest_of_username_as_string = new String(digest_of_username.digest()); + String digest_of_username_as_string = new BigInteger(MessageDigest.getInstance("SHA-256").digest(username.getBytes())).toString(16); - MessageDigest my_M1 = MessageDigest.getInstance("SHA-256"); - String m1_source_string = xor_n_and_g + digest_of_username_as_string + clientA.toString() + serverB.toString() + K.toString(); + String m1_source_string = xor_n_and_g + digest_of_username_as_string + clientA.toString(16) + serverB.toString(16) + K.toString(16); - my_M1.update(m1_source_string.getBytes()); - - return new BigInteger(my_M1.digest()); + return new BigInteger(1, MessageDigest.getInstance("SHA-256").digest(m1_source_string.getBytes())); } - private boolean verifyM2(BigInteger M2, BigInteger K, BigInteger clientA, BigInteger serverB, int salt, String username) throws NoSuchAlgorithmException { + private boolean verifyM2(BigInteger M2, BigInteger K, BigInteger clientA, BigInteger serverB, String username) throws NoSuchAlgorithmException { /* https://github.com/leapcode/srp_js/blob/master/src/srp_session.js var hashN = SHA256(hex2a(N.toString(16))) var hashG = SHA256(hex2a(g.toString(16))) @@ -198,50 +262,99 @@ public class ProviderAPI extends IntentService { */ MessageDigest digest_of_N = MessageDigest.getInstance("SHA-256"); digest_of_N.update(ConfigHelper.NG_1024.getBytes()); - String digest_of_N_as_string = new String(digest_of_N.digest()); + String digest_of_N_as_string = new BigInteger(digest_of_N.digest()).toString(); MessageDigest digest_of_G = MessageDigest.getInstance("SHA-256"); digest_of_G.update(ConfigHelper.g.toByteArray()); - String digest_of_G_as_string = new String(digest_of_G.digest()); + String digest_of_G_as_string = new BigInteger(digest_of_G.digest()).toString(); String xor_n_and_g = hexXor(digest_of_N_as_string, digest_of_G_as_string); MessageDigest digest_of_username = MessageDigest.getInstance("SHA-256"); digest_of_username.update(username.getBytes()); - String digest_of_username_as_string = new String(digest_of_username.digest()); + String digest_of_username_as_string = new BigInteger(digest_of_username.digest()).toString(); MessageDigest my_M1 = MessageDigest.getInstance("SHA-256"); String m1_source_string = xor_n_and_g + digest_of_username_as_string + clientA.toString() + serverB.toString() + K.toString(); my_M1.update(m1_source_string.getBytes()); MessageDigest my_own_M2 = MessageDigest.getInstance("SHA-256"); - String m2_source_string = clientA.toString() + new String(my_M1.digest()) + K.toString(); + String m2_source_string = clientA.toString() + new BigInteger(my_M1.digest()).toString() + K.toString(); my_own_M2.update(m2_source_string.getBytes()); return M2 == new BigInteger(my_own_M2.digest()); } - - private String hexXor(String a, String b) { + private String hexXor(String a, String b) { String str = ""; for (int i = 0; i < a.length(); i += 2) { - int xor = Integer.parseInt(a.substring(i, 2), 16) ^ Integer.parseInt(b.substring(i, 2), 16); + int xor = Integer.parseInt(a.substring(i, 2 + i), 16) ^ Integer.parseInt(b.substring(i, 2 + i), 16); String xor_string = String.valueOf(Integer.valueOf(String.valueOf(xor), 16)); str += (xor_string.length() == 1) ? ("0" + xor) : xor_string; } - return str; + return stringToHex(str); } + + private String stringToHex(String base) + { + StringBuffer buffer = new StringBuffer(); + int intValue; + for(int x = 0; x < base.length(); x++) + { + int cursor = 0; + intValue = base.charAt(x); + String binaryChar = new String(Integer.toBinaryString(base.charAt(x))); + for(int i = 0; i < binaryChar.length(); i++) + { + if(binaryChar.charAt(i) == '1') + { + cursor += 1; + } + } + if((cursor % 2) > 0) + { + intValue += 128; + } + buffer.append(Integer.toHexString(intValue) + ""); + } + return buffer.toString().toUpperCase(); +} - private BigInteger sendParameterToSRPServer(String server_url, String parameter_name, BigInteger parameter) throws ClientProtocolException, IOException { + private BigInteger sendAToSRPServer(String server_url, String username, BigInteger clientA) throws ClientProtocolException, IOException, NumberFormatException, JSONException { + DefaultHttpClient client = new LeapHttpClient(getApplicationContext()); + String parameter_chain = "A" + "=" + clientA.toString() + "&" + "login" + "=" + username; + HttpPost post = new HttpPost(server_url + "/sessions.json" + "?" + parameter_chain); + + HttpResponse getResponse = client.execute(post); + 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("errors")) { + return BigInteger.ZERO; + } + List cookies = client.getCookieStore().getCookies(); + if(!cookies.isEmpty()) { + String session_id = cookies.get(0).getValue(); + } + return new BigInteger(json_response.getString("B"), 16); + } + private BigInteger sendM1ToSRPServer(String server_url, String parameter_name, BigInteger parameter) throws ClientProtocolException, IOException, JSONException { DefaultHttpClient client = new LeapHttpClient(getApplicationContext()); String parameter_chain = parameter_name + "=" + parameter.toString(); - HttpPost post = new HttpPost(server_url + "?" + parameter_chain); - // TODO Look for how our srp server sends the serverB (as a cookie?) and how to fetch it from response. + HttpPost post = new HttpPost(server_url + "/sessions.json" + "?" + parameter_chain); + HttpResponse getResponse = client.execute(post); 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("errors") || json_response.has("errors")) { + return BigInteger.ZERO; + } + List cookies = client.getCookieStore().getCookies(); - return BigInteger.valueOf((Long.valueOf(cookies.get(0).getValue()))); + String session_id = cookies.get(0).getValue(); + return new BigInteger(json_response.getString("M2"), 16); } private String guessURL(String provider_main_url) { -- cgit v1.2.3 From 34400de64dcf68a451b5a1bf1dbea52a49bb24eb Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Parm=C3=A9nides=20GV?= Date: Thu, 7 Mar 2013 19:56:23 +0100 Subject: Changed POST by PUT in the sendM1 method. Cleaned some code, pending the M2 one (testing with M1). --- src/se/leap/leapclient/ConfigHelper.java | 2 +- src/se/leap/leapclient/ProviderAPI.java | 110 ++++++++++++++----------------- 2 files changed, 51 insertions(+), 61 deletions(-) (limited to 'src/se/leap/leapclient') diff --git a/src/se/leap/leapclient/ConfigHelper.java b/src/se/leap/leapclient/ConfigHelper.java index 41364e96..b263c532 100644 --- a/src/se/leap/leapclient/ConfigHelper.java +++ b/src/se/leap/leapclient/ConfigHelper.java @@ -37,7 +37,7 @@ public class ConfigHelper { final public static String eip_service_api_path = "/config/eip-service.json"; final public static String NG_1024 = - "EEAF0AB9ADB38DD69C33F80AFA8FC5E86072618775FF3C0B9EA2314C9C256576D674DF7496EA81D3383B4813D692C6E0E0D5D8E250B98BE48E495C1D6089DAD15DC7D7B46154D6B6CE8EF4AD69B15D4982559B297BCF1885C529F566660E57EC68EDBC3C05726CC02FD4CBF4976EAA9AFD5138FE8376435B9FC61D2FC0EB06E3"; + "eeaf0ab9adb38dd69c33f80afa8fc5e86072618775ff3c0b9ea2314c9c256576d674df7496ea81d3383b4813d692c6e0e0d5d8e250b98be48e495c1d6089dad15dc7d7b46154d6b6ce8ef4ad69b15d4982559b297bcf1885c529f566660e57ec68edbc3c05726cc02fd4cbf4976eaa9afd5138fe8376435b9fc61d2fc0eb06e3"; final public static BigInteger g = BigInteger.valueOf(2); final public static int CUSTOM_PROVIDER_ADDED = 0; diff --git a/src/se/leap/leapclient/ProviderAPI.java b/src/se/leap/leapclient/ProviderAPI.java index 41612d16..e2af08e3 100644 --- a/src/se/leap/leapclient/ProviderAPI.java +++ b/src/se/leap/leapclient/ProviderAPI.java @@ -21,6 +21,7 @@ import org.apache.http.HttpResponse; import org.apache.http.client.ClientProtocolException; import org.apache.http.client.methods.HttpGet; import org.apache.http.client.methods.HttpPost; +import org.apache.http.client.methods.HttpPut; import org.apache.http.cookie.Cookie; import org.apache.http.impl.client.DefaultHttpClient; import org.json.JSONException; @@ -123,7 +124,7 @@ public class ProviderAPI extends IntentService { verifier_generator.init(ng_1024, ConfigHelper.g, new SHA256Digest()); BigInteger verifier = verifier_generator.generateVerifier(salt_in_bytes, username.getBytes(), password.getBytes()); - return sendRegisterMessage(authentication_server, salt.toString(16), verifier.toString(), username); + return sendRegisterMessage(authentication_server, salt.toString(16), verifier.toString(16), username); } private boolean sendRegisterMessage(String server_url, String password_salt, String password_verifier, String login) { @@ -137,10 +138,11 @@ public class ProviderAPI extends IntentService { HttpEntity responseEntity = getResponse.getEntity(); String plain_response = new Scanner(responseEntity.getContent()).useDelimiter("\\A").next(); JSONObject json_response = new JSONObject(plain_response); - if(!json_response.getString("errors").isEmpty()) { + if(!json_response.isNull("errors") || json_response.has("errors")) { return false; } - else if(json_response.getString("password_salt").equalsIgnoreCase(password_salt) && json_response.getString("login").equalsIgnoreCase(login)) + //else if(json_response.getString("password_salt").equalsIgnoreCase(password_salt) && json_response.getString("login").equalsIgnoreCase(login)) + else if(json_response.getBoolean("ok") && json_response.getString("login").equalsIgnoreCase(login)) return true; } catch (ClientProtocolException e) { // TODO Auto-generated catch block @@ -163,30 +165,31 @@ public class ProviderAPI extends IntentService { String username = (String) task.get(ConfigHelper.username_key); String password = (String) task.get(ConfigHelper.password_key); String authentication_server = (String) task.get(ConfigHelper.srp_server_url_key); + SRP6Client srp_client = new SRP6Client(); - srp_client.init(new BigInteger(ConfigHelper.NG_1024, 16), ConfigHelper.g, new SHA256Digest(), new SecureRandom()); - // Receive salt from server - Random random_number_generator = new Random(); - BigInteger ng_1024 = new BigInteger(ConfigHelper.NG_1024, 16); - byte[] salt_in_bytes = ng_1024.probablePrime(1024, null).toByteArray(); - //int salt = random_number_generator.nextInt(Integer.parseInt(ConfigHelper.NG_1024, 16)); - //byte[] salt_in_bytes = ByteBuffer.allocate(4).putInt(salt).array(); - BigInteger clientA = srp_client.generateClientCredentials(salt_in_bytes, username.getBytes(), password.getBytes()); - //Send A to the server. Doing a http response with cookies? - //Receive server generated serverB + BigInteger n = new BigInteger(ConfigHelper.NG_1024, 16); + srp_client.init(n, ConfigHelper.g, new SHA256Digest(), new SecureRandom()); + + BigInteger salt = BigInteger.probablePrime(1024, null); + BigInteger clientA = srp_client.generateClientCredentials(salt.toByteArray(), username.getBytes(), password.getBytes()); try { BigInteger serverB = sendAToSRPServer(authentication_server, username, clientA); if(serverB == BigInteger.ZERO) return false; // TODO Show error: error trying to start authentication with provider + BigInteger s = srp_client.calculateSecret(serverB); - MessageDigest digest_of_S = MessageDigest.getInstance("SHA-256"); - digest_of_S.update(s.toByteArray(), 0, s.toByteArray().length); - BigInteger k = new BigInteger(digest_of_S.digest()); - BigInteger m1 = generateM1(k, clientA, serverB, username); - BigInteger m2 = sendM1ToSRPServer(authentication_server, "M1", m1); + + BigInteger k = new BigInteger(1, MessageDigest.getInstance("SHA-256").digest(s.toByteArray())); + + BigInteger m1 = generateM1(k, salt, clientA, serverB, username); + + BigInteger m2 = sendM1ToSRPServer(authentication_server, username, m1); + if(m2 == BigInteger.ZERO) return false; // TODO Show error: error in M1 + boolean verified = verifyM2(m2, k, clientA, serverB, username); + return verified; // TODO If false, Username or password are not correct -> Show a warning and get back to login fragment } catch (ClientProtocolException e) { // TODO Auto-generated catch block @@ -218,30 +221,35 @@ public class ProviderAPI extends IntentService { } } - private BigInteger generateM1(BigInteger K, BigInteger clientA, BigInteger serverB, String username) throws NoSuchAlgorithmException { - /* https://github.com/leapcode/srp_js/blob/master/src/srp_session.js - var hashN = SHA256(hex2a(N.toString(16))) - var hashG = SHA256(hex2a(g.toString(16))) - var hexString = hexXor(hashN, hashG); - hexString += SHA256(I); - hexString += salt; - hexString += Astr; - hexString += Bstr; - hexString += K - M = SHA256(hex2a(hexString)); - //M2 = H(A, M, K) - M2 = SHA256(hex2a(Astr + M + K)); - */ + private BigInteger sendAToSRPServer(String server_url, String username, BigInteger clientA) throws ClientProtocolException, IOException, NumberFormatException, JSONException { + DefaultHttpClient client = new LeapHttpClient(getApplicationContext()); + String parameter_chain = "A" + "=" + clientA.toString(16) + "&" + "login" + "=" + username; + HttpPost post = new HttpPost(server_url + "/sessions.json" + "?" + parameter_chain); + + HttpResponse getResponse = client.execute(post); + 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("errors") || json_response.has("errors")) { + return BigInteger.ZERO; + } + List cookies = client.getCookieStore().getCookies(); + if(!cookies.isEmpty()) { + String session_id = cookies.get(0).getValue(); + } + return new BigInteger(json_response.getString("B"), 16); + } + + public BigInteger generateM1(BigInteger K, BigInteger salt, BigInteger clientA, BigInteger serverB, String username) throws NoSuchAlgorithmException { String digest_of_N_as_string = new BigInteger(MessageDigest.getInstance("SHA-256").digest(ConfigHelper.NG_1024.getBytes())).toString(16); - + String digest_of_G_as_string = new BigInteger(1, MessageDigest.getInstance("SHA-256").digest(ConfigHelper.g.toString(16).getBytes())).toString(16); - //String digest_of_G_as_string = new BigInteger(MessageDigest.getInstance("SHA-256").digest(ConfigHelper.g.toByteArray())).toString(16); - + String xor_n_and_g = hexXor(digest_of_N_as_string, digest_of_G_as_string); - + String digest_of_username_as_string = new BigInteger(MessageDigest.getInstance("SHA-256").digest(username.getBytes())).toString(16); - String m1_source_string = xor_n_and_g + digest_of_username_as_string + clientA.toString(16) + serverB.toString(16) + K.toString(16); + String m1_source_string = xor_n_and_g + digest_of_username_as_string + salt.toString(16) + clientA.toString(16) + serverB.toString(16) + K.toString(16); return new BigInteger(1, MessageDigest.getInstance("SHA-256").digest(m1_source_string.getBytes())); } @@ -318,33 +326,15 @@ public class ProviderAPI extends IntentService { } buffer.append(Integer.toHexString(intValue) + ""); } - return buffer.toString().toUpperCase(); + return buffer.toString(); } - private BigInteger sendAToSRPServer(String server_url, String username, BigInteger clientA) throws ClientProtocolException, IOException, NumberFormatException, JSONException { + private BigInteger sendM1ToSRPServer(String server_url, String username, BigInteger m1) throws ClientProtocolException, IOException, JSONException { DefaultHttpClient client = new LeapHttpClient(getApplicationContext()); - String parameter_chain = "A" + "=" + clientA.toString() + "&" + "login" + "=" + username; - HttpPost post = new HttpPost(server_url + "/sessions.json" + "?" + parameter_chain); - - HttpResponse getResponse = client.execute(post); - 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("errors")) { - return BigInteger.ZERO; - } - List cookies = client.getCookieStore().getCookies(); - if(!cookies.isEmpty()) { - String session_id = cookies.get(0).getValue(); - } - return new BigInteger(json_response.getString("B"), 16); - } - private BigInteger sendM1ToSRPServer(String server_url, String parameter_name, BigInteger parameter) throws ClientProtocolException, IOException, JSONException { - DefaultHttpClient client = new LeapHttpClient(getApplicationContext()); - String parameter_chain = parameter_name + "=" + parameter.toString(); - HttpPost post = new HttpPost(server_url + "/sessions.json" + "?" + parameter_chain); + String parameter_chain = "client_auth" + "=" + m1.toString(16); + HttpPut put = new HttpPut(server_url + "/sessions/" + username +".json" + "?" + parameter_chain); - HttpResponse getResponse = client.execute(post); + HttpResponse getResponse = client.execute(put); HttpEntity responseEntity = getResponse.getEntity(); String plain_response = new Scanner(responseEntity.getContent()).useDelimiter("\\A").next(); JSONObject json_response = new JSONObject(plain_response); -- cgit v1.2.3 From 86856f497377aa0c9b39551a2df013b915be21ce Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Parm=C3=A9nides=20GV?= Date: Tue, 12 Mar 2013 18:23:11 +0100 Subject: Gonna try jboss srp implementation, because if I implement myself one we will have to audit it. --- src/se/leap/leapclient/ProviderAPI.java | 23 ++++++++++++++++++++--- 1 file changed, 20 insertions(+), 3 deletions(-) (limited to 'src/se/leap/leapclient') diff --git a/src/se/leap/leapclient/ProviderAPI.java b/src/se/leap/leapclient/ProviderAPI.java index e2af08e3..591bdc9f 100644 --- a/src/se/leap/leapclient/ProviderAPI.java +++ b/src/se/leap/leapclient/ProviderAPI.java @@ -171,9 +171,12 @@ public class ProviderAPI extends IntentService { srp_client.init(n, ConfigHelper.g, new SHA256Digest(), new SecureRandom()); BigInteger salt = BigInteger.probablePrime(1024, null); - BigInteger clientA = srp_client.generateClientCredentials(salt.toByteArray(), username.getBytes(), password.getBytes()); + + BigInteger clientA = srp_client.generateClientCredentials(salt.toString(16).getBytes(), username.getBytes(), password.getBytes()); + try { BigInteger serverB = sendAToSRPServer(authentication_server, username, clientA); + if(serverB == BigInteger.ZERO) return false; // TODO Show error: error trying to start authentication with provider @@ -241,7 +244,7 @@ public class ProviderAPI extends IntentService { } public BigInteger generateM1(BigInteger K, BigInteger salt, BigInteger clientA, BigInteger serverB, String username) throws NoSuchAlgorithmException { - String digest_of_N_as_string = new BigInteger(MessageDigest.getInstance("SHA-256").digest(ConfigHelper.NG_1024.getBytes())).toString(16); + String digest_of_N_as_string = new BigInteger(1, MessageDigest.getInstance("SHA-256").digest(hex2ascii(ConfigHelper.NG_1024).getBytes())).toString(16); String digest_of_G_as_string = new BigInteger(1, MessageDigest.getInstance("SHA-256").digest(ConfigHelper.g.toString(16).getBytes())).toString(16); @@ -297,7 +300,11 @@ public class ProviderAPI extends IntentService { private String hexXor(String a, String b) { String str = ""; for (int i = 0; i < a.length(); i += 2) { - int xor = Integer.parseInt(a.substring(i, 2 + i), 16) ^ Integer.parseInt(b.substring(i, 2 + i), 16); + int xor = 0; + if(a.length() > i + 2) + xor = Integer.parseInt(a.substring(i, 2 + i), 16) ^ Integer.parseInt(b.substring(i, 2 + i), 16); + else + xor = Integer.parseInt(a.substring(i, 1 + i), 16) ^ Integer.parseInt(b.substring(i, 1 + i), 16); String xor_string = String.valueOf(Integer.valueOf(String.valueOf(xor), 16)); str += (xor_string.length() == 1) ? ("0" + xor) : xor_string; } @@ -328,6 +335,16 @@ public class ProviderAPI extends IntentService { } return buffer.toString(); } + + private String hex2ascii(String hex) { + StringBuilder output = new StringBuilder(); + for (int i = 0; i < hex.length(); i+=2) { + String str = hex.substring(i, i+2); + output.append((char)Integer.parseInt(str, 16)); + } + String debug = output.toString(); + return output.toString(); + } private BigInteger sendM1ToSRPServer(String server_url, String username, BigInteger m1) throws ClientProtocolException, IOException, JSONException { DefaultHttpClient client = new LeapHttpClient(getApplicationContext()); -- cgit v1.2.3 From 49747e858649fa7ed68e4a038d5602ec2bae6df5 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Parm=C3=A9nides=20GV?= Date: Tue, 12 Mar 2013 19:14:10 +0100 Subject: Error using CryptoUtil.calculatePasswordHash. Going to hit some bugs before continuing with this work. --- src/se/leap/leapclient/ProviderAPI.java | 65 +++++++++++++++++++++++++++++++++ 1 file changed, 65 insertions(+) (limited to 'src/se/leap/leapclient') diff --git a/src/se/leap/leapclient/ProviderAPI.java b/src/se/leap/leapclient/ProviderAPI.java index 591bdc9f..b20e30b1 100644 --- a/src/se/leap/leapclient/ProviderAPI.java +++ b/src/se/leap/leapclient/ProviderAPI.java @@ -24,6 +24,9 @@ import org.apache.http.client.methods.HttpPost; import org.apache.http.client.methods.HttpPut; import org.apache.http.cookie.Cookie; import org.apache.http.impl.client.DefaultHttpClient; +import org.jboss.security.srp.SRPClientSession; +import org.jboss.security.srp.SRPConf.SRPParams; +import org.jboss.security.srp.SRPParameters; import org.json.JSONException; import org.json.JSONObject; @@ -166,6 +169,30 @@ public class ProviderAPI extends IntentService { String password = (String) task.get(ConfigHelper.password_key); String authentication_server = (String) task.get(ConfigHelper.srp_server_url_key); + SRPParameters params = new SRPParameters(ConfigHelper.NG_1024.getBytes(), "2".getBytes(), null); + SRPClientSession client = new SRPClientSession(username, password.toCharArray(), params); + byte[] A = client.exponential(); + try { + byte[] B = sendAToSRPServer(authentication_server, username, A); + byte[] M1 = client.response(B); + byte[] M2 = sendM1ToSRPServer(authentication_server, username, M1); + if( client.verify(M2) == false ) + throw new SecurityException("Failed to validate server reply"); + return true; + } catch (ClientProtocolException e1) { + // TODO Auto-generated catch block + e1.printStackTrace(); + } catch (IOException e1) { + // TODO Auto-generated catch block + e1.printStackTrace(); + } catch (JSONException e1) { + // TODO Auto-generated catch block + e1.printStackTrace(); + } catch (NoSuchAlgorithmException e) { + // TODO Auto-generated catch block + e.printStackTrace(); + } + SRP6Client srp_client = new SRP6Client(); BigInteger n = new BigInteger(ConfigHelper.NG_1024, 16); srp_client.init(n, ConfigHelper.g, new SHA256Digest(), new SecureRandom()); @@ -242,6 +269,25 @@ public class ProviderAPI extends IntentService { } return new BigInteger(json_response.getString("B"), 16); } + + private byte[] sendAToSRPServer(String server_url, String username, byte[] clientA) throws ClientProtocolException, IOException, JSONException { + DefaultHttpClient client = new LeapHttpClient(getApplicationContext()); + String parameter_chain = "A" + "=" + new String(clientA) + "&" + "login" + "=" + username; + HttpPost post = new HttpPost(server_url + "/sessions.json" + "?" + parameter_chain); + + HttpResponse getResponse = client.execute(post); + 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("errors") || json_response.has("errors")) { + return new byte[0]; + } + List cookies = client.getCookieStore().getCookies(); + if(!cookies.isEmpty()) { + String session_id = cookies.get(0).getValue(); + } + return json_response.getString("B").getBytes(); + } public BigInteger generateM1(BigInteger K, BigInteger salt, BigInteger clientA, BigInteger serverB, String username) throws NoSuchAlgorithmException { String digest_of_N_as_string = new BigInteger(1, MessageDigest.getInstance("SHA-256").digest(hex2ascii(ConfigHelper.NG_1024).getBytes())).toString(16); @@ -364,6 +410,25 @@ public class ProviderAPI extends IntentService { return new BigInteger(json_response.getString("M2"), 16); } + private byte[] sendM1ToSRPServer(String server_url, String username, byte[] m1) throws ClientProtocolException, IOException, JSONException { + DefaultHttpClient client = new LeapHttpClient(getApplicationContext()); + String parameter_chain = "client_auth" + "=" + new String(m1); + HttpPut put = new HttpPut(server_url + "/sessions/" + username +".json" + "?" + parameter_chain); + + HttpResponse getResponse = client.execute(put); + 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("errors") || json_response.has("errors")) { + return new byte[0]; + } + + List cookies = client.getCookieStore().getCookies(); + String session_id = cookies.get(0).getValue(); + + return json_response.getString("M2").getBytes(); + } + private String guessURL(String provider_main_url) { return provider_main_url + "/provider.json"; } -- cgit v1.2.3 From 929fa9a3b7621e0a956ed8d7beffb87ed7f16249 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Parm=C3=A9nides=20GV?= Date: Wed, 13 Mar 2013 21:01:53 +0100 Subject: ConfigurationWizard sets provider.json correctly for Dashboard once a custom provider is selected. Tested using https://bitmask.net as url for custom provider. --- src/se/leap/leapclient/ConfigHelper.java | 15 +++++++++++--- src/se/leap/leapclient/ConfigurationWizard.java | 26 +++++++++++++++---------- src/se/leap/leapclient/ProviderAPI.java | 8 ++++++++ src/se/leap/leapclient/ProviderListContent.java | 6 ++++-- 4 files changed, 40 insertions(+), 15 deletions(-) (limited to 'src/se/leap/leapclient') diff --git a/src/se/leap/leapclient/ConfigHelper.java b/src/se/leap/leapclient/ConfigHelper.java index 5301209c..f5800a0e 100644 --- a/src/se/leap/leapclient/ConfigHelper.java +++ b/src/se/leap/leapclient/ConfigHelper.java @@ -17,6 +17,8 @@ import android.os.Environment; import android.util.Log; public class ConfigHelper { + + public static SharedPreferences shared_preferences; final static String downloadJsonFilesBundleExtra = "downloadJSONFiles"; final static String downloadNewProviderDotJSON = "downloadNewProviderDotJSON"; @@ -28,11 +30,13 @@ public class ConfigHelper { public static String provider_key_url = "provider_main_url"; final public static String eip_service_api_path = "/config/eip-service.json"; - final public static int CUSTOM_PROVIDER_ADDED = 0; + final public static int CUSTOM_PROVIDER_ADDED = 0; + final public static int CORRECTLY_DOWNLOADED_JSON_FILES = 1; + final public static int INCORRECTLY_DOWNLOADED_JSON_FILES = 2; static void saveSharedPref(String shared_preferences_key, JSONObject content) { - SharedPreferences.Editor shared_preferences_editor = ConfigurationWizard.shared_preferences + SharedPreferences.Editor shared_preferences_editor = shared_preferences .edit(); shared_preferences_editor.putString(shared_preferences_key, content.toString()); @@ -40,7 +44,7 @@ public class ConfigHelper { System.out.println("Shared preferences updated: key = " + shared_preferences_key + " Content = " - + ConfigurationWizard.shared_preferences.getString( + + shared_preferences.getString( shared_preferences_key, "Default")); } @@ -81,4 +85,9 @@ public class ConfigHelper { } return input_stream; } + + public static void setSharedPreferences( + SharedPreferences shared_preferences) { + ConfigHelper.shared_preferences = shared_preferences; + } } diff --git a/src/se/leap/leapclient/ConfigurationWizard.java b/src/se/leap/leapclient/ConfigurationWizard.java index e252fa6b..dcefb271 100644 --- a/src/se/leap/leapclient/ConfigurationWizard.java +++ b/src/se/leap/leapclient/ConfigurationWizard.java @@ -59,7 +59,7 @@ public class ConfigurationWizard extends Activity setContentView(R.layout.activity_configuration_wizard); - shared_preferences = getSharedPreferences(ConfigHelper.PREFERENCES_KEY,MODE_PRIVATE); + ConfigHelper.setSharedPreferences(getSharedPreferences(ConfigHelper.PREFERENCES_KEY,MODE_PRIVATE)); loadPreseededProviders(); @@ -118,10 +118,9 @@ public class ConfigurationWizard extends Activity if(current_provider_item.id.equalsIgnoreCase(id)) { try { - if(!current_provider_item.custom) - processAssetsFiles(current_provider_item); - // TODO ask Provider class to save provider.json, setResult(OK), finish() to ConfigurationWizard - downloadJSONFiles(current_provider_item); + saveProviderJson(current_provider_item); + downloadJSONFiles(current_provider_item); + } catch (IOException e) { // TODO Auto-generated catch block e.printStackTrace(); @@ -136,11 +135,15 @@ public class ConfigurationWizard extends Activity } } - private void processAssetsFiles(ProviderItem current_provider_item) { + private void saveProviderJson(ProviderItem current_provider_item) { AssetManager assets_manager = getAssets(); JSONObject provider_json = new JSONObject(); try { - String provider_contents = new Scanner(new InputStreamReader(assets_manager.open(current_provider_item.provider_json_assets))).useDelimiter("\\A").next(); + String provider_contents = ""; + if(!current_provider_item.custom) + provider_contents = new Scanner(new InputStreamReader(assets_manager.open(current_provider_item.provider_json_filename))).useDelimiter("\\A").next(); + else + provider_contents = new Scanner(ConfigHelper.openFileInputStream(current_provider_item.provider_json_filename)).useDelimiter("\\A").next(); provider_json = new JSONObject(provider_contents); } catch (IOException e) { // TODO Auto-generated catch block @@ -152,16 +155,20 @@ public class ConfigurationWizard extends Activity } private void downloadJSONFiles(ProviderItem current_provider_item) throws IOException { + providerAPI_result_receiver = new ProviderAPIResultReceiver(new Handler()); + providerAPI_result_receiver.setReceiver(this); + Intent provider_API_command = new Intent(this, ProviderAPI.class); Bundle method_and_parameters = new Bundle(); + + method_and_parameters.putString(ConfigHelper.provider_key, current_provider_item.name); method_and_parameters.putString(ConfigHelper.cert_key, current_provider_item.cert_json_url); method_and_parameters.putString(ConfigHelper.eip_service_key, current_provider_item.eip_service_json_url); provider_API_command.putExtra(ConfigHelper.downloadJsonFilesBundleExtra, method_and_parameters); - + provider_API_command.putExtra("receiver", providerAPI_result_receiver); startService(provider_API_command); - } public void addNewProvider(View view) { @@ -193,7 +200,6 @@ public class ConfigurationWizard extends Activity @Override public void onReceiveResult(int resultCode, Bundle resultData) { - // TODO Auto-generated method stub if(resultCode == ConfigHelper.CUSTOM_PROVIDER_ADDED){ ProviderListFragment providerList = new ProviderListFragment(); diff --git a/src/se/leap/leapclient/ProviderAPI.java b/src/se/leap/leapclient/ProviderAPI.java index 583eea06..1dc7c9f6 100644 --- a/src/se/leap/leapclient/ProviderAPI.java +++ b/src/se/leap/leapclient/ProviderAPI.java @@ -32,21 +32,28 @@ public class ProviderAPI extends IntentService { Bundle task; System.out.println("onHandleIntent called"); if((task = task_for.getBundleExtra(ConfigHelper.downloadJsonFilesBundleExtra)) != null) { + String provider_name = (String) task.get(ConfigHelper.provider_key); String cert_url = (String) task.get(ConfigHelper.cert_key); String eip_service_json_url = (String) task.get(ConfigHelper.eip_service_key); try { + JSONObject provider_json = new JSONObject("{ \"provider\" : \"" + provider_name + "\"}"); + ConfigHelper.saveSharedPref(ConfigHelper.provider_key, provider_json); String cert_string = getStringFromProvider(cert_url); JSONObject cert_json = new JSONObject("{ \"certificate\" : \"" + cert_string + "\"}"); ConfigHelper.saveSharedPref(ConfigHelper.cert_key, cert_json); JSONObject eip_service_json = getJSONFromProvider(eip_service_json_url); ConfigHelper.saveSharedPref(ConfigHelper.eip_service_key, eip_service_json); + receiver.send(ConfigHelper.CORRECTLY_DOWNLOADED_JSON_FILES, Bundle.EMPTY); } catch (IOException e) { // TODO Auto-generated catch block e.printStackTrace(); + receiver.send(ConfigHelper.INCORRECTLY_DOWNLOADED_JSON_FILES, Bundle.EMPTY); } catch (JSONException e) { ConfigHelper.rescueJSONException(e); + receiver.send(ConfigHelper.INCORRECTLY_DOWNLOADED_JSON_FILES, Bundle.EMPTY); } catch(Exception e) { e.printStackTrace(); + receiver.send(ConfigHelper.INCORRECTLY_DOWNLOADED_JSON_FILES, Bundle.EMPTY); } } else if ((task = task_for.getBundleExtra(ConfigHelper.downloadNewProviderDotJSON)) != null) { @@ -58,6 +65,7 @@ public class ProviderAPI extends IntentService { JSONObject provider_json = getJSONFromProvider(provider_json_url); String filename = provider_name + "_provider.json".replaceFirst("__", "_"); ConfigHelper.saveFile(filename, provider_json.toString()); + ProviderListContent.addItem(new ProviderItem(provider_name, ConfigHelper.openFileInputStream(filename), custom)); receiver.send(ConfigHelper.CUSTOM_PROVIDER_ADDED, Bundle.EMPTY); } catch (IOException e) { diff --git a/src/se/leap/leapclient/ProviderListContent.java b/src/se/leap/leapclient/ProviderListContent.java index d475d368..dd227bfd 100644 --- a/src/se/leap/leapclient/ProviderListContent.java +++ b/src/se/leap/leapclient/ProviderListContent.java @@ -41,7 +41,7 @@ public class ProviderListContent { public String id; public String name; public String provider_json_url; - public String provider_json_assets; + public String provider_json_filename; public String eip_service_json_url; public String cert_json_url; @@ -63,7 +63,7 @@ public class ProviderListContent { id = name; this.name = name; provider_json_url = (String) file_contents.get("json_provider"); - provider_json_assets = (String) file_contents.get("assets_json_provider"); + provider_json_filename = (String) file_contents.get("assets_json_provider"); eip_service_json_url = (String) file_contents.get("json_eip_service"); cert_json_url = (String) file_contents.get("cert"); this.custom = custom; @@ -88,6 +88,8 @@ public class ProviderListContent { eip_service_json_url = (String) file_contents.get("api_uri") + ConfigHelper.eip_service_api_path; cert_json_url = (String) file_contents.get("ca_cert_uri"); this.custom = custom; + if(custom) + provider_json_filename = name + "_provider.json".replaceFirst("__", "_"); } catch (JSONException e) { // TODO Auto-generated catch block e.printStackTrace(); -- cgit v1.2.3 From 203c8caca5a305b90fd0e69c965e503afe979354 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Parm=C3=A9nides=20GV?= Date: Thu, 14 Mar 2013 19:53:31 +0100 Subject: After downloading provider.json successfully, ConfigurationWizard now can download eip-service.json and ca.crt without having the latter as a predefined trusted certificate. It does not ask anything about trusting the new certificate as far as selecting a custom provider means that the user trusts that url. Next step: make provider.json also downloadable from https address using ca.cert not trusted. --- src/se/leap/leapclient/ConfigHelper.java | 70 +++++++++++++++++++++++++ src/se/leap/leapclient/ConfigurationWizard.java | 6 +++ src/se/leap/leapclient/LeapHttpClient.java | 15 ++---- src/se/leap/leapclient/ProviderAPI.java | 13 +++-- 4 files changed, 90 insertions(+), 14 deletions(-) (limited to 'src/se/leap/leapclient') diff --git a/src/se/leap/leapclient/ConfigHelper.java b/src/se/leap/leapclient/ConfigHelper.java index f5800a0e..b6526691 100644 --- a/src/se/leap/leapclient/ConfigHelper.java +++ b/src/se/leap/leapclient/ConfigHelper.java @@ -8,6 +8,12 @@ import java.io.FileNotFoundException; import java.io.FileWriter; import java.io.IOException; import java.io.InputStream; +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 org.json.JSONException; import org.json.JSONObject; @@ -19,6 +25,7 @@ import android.util.Log; public class ConfigHelper { public static SharedPreferences shared_preferences; + private static KeyStore keystore_trusted; final static String downloadJsonFilesBundleExtra = "downloadJSONFiles"; final static String downloadNewProviderDotJSON = "downloadNewProviderDotJSON"; @@ -90,4 +97,67 @@ public class ConfigHelper { SharedPreferences shared_preferences) { ConfigHelper.shared_preferences = shared_preferences; } + + 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(); + } + } + + public static void addTrustedCertificate(String provider, String certificate) { + String filename_to_save = provider + "_certificate.cer"; + saveFile(filename_to_save, certificate); + CertificateFactory cf; + try { + cf = CertificateFactory.getInstance("X.509"); + X509Certificate cert = + (X509Certificate)cf.generateCertificate(openFileInputStream(filename_to_save)); + 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(); + } + } + + public static KeyStore getKeystore() { + return keystore_trusted; + } + + public static void getNewKeystore(InputStream leap_keystore) { + try { + keystore_trusted = KeyStore.getInstance("BKS"); + try { + // Initialize the keystore with the provided trusted certificates + // Also provide the password of the keystore + keystore_trusted.load(leap_keystore, "uer92jf".toCharArray()); + } finally { + leap_keystore.close(); + } + } 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(); + } + } } diff --git a/src/se/leap/leapclient/ConfigurationWizard.java b/src/se/leap/leapclient/ConfigurationWizard.java index dcefb271..69e13f19 100644 --- a/src/se/leap/leapclient/ConfigurationWizard.java +++ b/src/se/leap/leapclient/ConfigurationWizard.java @@ -1,6 +1,7 @@ package se.leap.leapclient; import java.io.IOException; +import java.io.InputStream; import java.io.InputStreamReader; import java.util.Iterator; import java.util.Scanner; @@ -63,6 +64,11 @@ public class ConfigurationWizard extends Activity loadPreseededProviders(); + if(ConfigHelper.getKeystore() == null) { + InputStream keystore_input_stream = getResources().openRawResource(R.raw.leapkeystore); + ConfigHelper.getNewKeystore(keystore_input_stream); + } + // Only create our fragments if we're not restoring a saved instance if ( savedInstanceState == null ){ // TODO Some welcome screen? diff --git a/src/se/leap/leapclient/LeapHttpClient.java b/src/se/leap/leapclient/LeapHttpClient.java index 9e1a541b..9ee0a95e 100644 --- a/src/se/leap/leapclient/LeapHttpClient.java +++ b/src/se/leap/leapclient/LeapHttpClient.java @@ -33,23 +33,16 @@ public class LeapHttpClient extends DefaultHttpClient { private SSLSocketFactory newSslSocketFactory() { try { // Get an instance of the Bouncy Castle KeyStore format - KeyStore trusted = KeyStore.getInstance("BKS"); - // Get the raw resource, which contains the keystore with - // your trusted certificates (root and any intermediate certs) - InputStream in = context.getResources().openRawResource(R.raw.leapkeystore); - try { - // Initialize the keystore with the provided trusted certificates - // Also provide the password of the keystore - trusted.load(in, "uer92jf".toCharArray()); - } finally { - in.close(); - } + KeyStore trusted = ConfigHelper.getKeystore(); + // Pass the keystore to the SSLSocketFactory. The factory is responsible // for the verification of the server certificate. SSLSocketFactory sf = new SSLSocketFactory(trusted); + // Hostname verification from certificate // http://hc.apache.org/httpcomponents-client-ga/tutorial/html/connmgmt.html#d4e506 sf.setHostnameVerifier(SSLSocketFactory.ALLOW_ALL_HOSTNAME_VERIFIER); + return sf; } catch (Exception e) { throw new AssertionError(e); diff --git a/src/se/leap/leapclient/ProviderAPI.java b/src/se/leap/leapclient/ProviderAPI.java index 1dc7c9f6..01cbd01c 100644 --- a/src/se/leap/leapclient/ProviderAPI.java +++ b/src/se/leap/leapclient/ProviderAPI.java @@ -1,6 +1,9 @@ package se.leap.leapclient; import java.io.IOException; +import java.net.URL; +import java.security.Provider; +import java.security.Security; import java.util.Scanner; import org.apache.http.HttpEntity; @@ -38,14 +41,18 @@ public class ProviderAPI extends IntentService { try { JSONObject provider_json = new JSONObject("{ \"provider\" : \"" + provider_name + "\"}"); ConfigHelper.saveSharedPref(ConfigHelper.provider_key, provider_json); - String cert_string = getStringFromProvider(cert_url); + + /*String cert_string = getStringFromProvider(cert_url); JSONObject cert_json = new JSONObject("{ \"certificate\" : \"" + cert_string + "\"}"); ConfigHelper.saveSharedPref(ConfigHelper.cert_key, cert_json); + ConfigHelper.addTrustedCertificate(provider_name, cert_string);*/ + URL cacert = new URL(cert_url); + ConfigHelper.addTrustedCertificate(provider_name, cacert.openStream()); JSONObject eip_service_json = getJSONFromProvider(eip_service_json_url); ConfigHelper.saveSharedPref(ConfigHelper.eip_service_key, eip_service_json); receiver.send(ConfigHelper.CORRECTLY_DOWNLOADED_JSON_FILES, Bundle.EMPTY); } catch (IOException e) { - // TODO Auto-generated catch block + // TODO It could happen that an https site used a certificate not trusted. e.printStackTrace(); receiver.send(ConfigHelper.INCORRECTLY_DOWNLOADED_JSON_FILES, Bundle.EMPTY); } catch (JSONException e) { @@ -69,7 +76,7 @@ public class ProviderAPI extends IntentService { ProviderListContent.addItem(new ProviderItem(provider_name, ConfigHelper.openFileInputStream(filename), custom)); receiver.send(ConfigHelper.CUSTOM_PROVIDER_ADDED, Bundle.EMPTY); } catch (IOException e) { - // TODO Auto-generated catch block + // TODO It could happen that an https site used a certificate not trusted. e.printStackTrace(); } catch (JSONException e) { // TODO Auto-generated catch block -- cgit v1.2.3 From f4f454d53b881563d82f392545fb17ef9283c5e3 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Parm=C3=A9nides=20GV?= Date: Mon, 18 Mar 2013 11:13:54 +0100 Subject: If ca.crt from new provider is not trusted, we can download it without problems assuming user wanted to trust it since s/he entered by him/herself the URL. Next step: refactor a bit, to make code more beautiful. --- src/se/leap/leapclient/ConfigHelper.java | 3 ++- src/se/leap/leapclient/ProviderAPI.java | 29 +++++++++++++++++++++++------ 2 files changed, 25 insertions(+), 7 deletions(-) (limited to 'src/se/leap/leapclient') diff --git a/src/se/leap/leapclient/ConfigHelper.java b/src/se/leap/leapclient/ConfigHelper.java index b6526691..8a0e2b45 100644 --- a/src/se/leap/leapclient/ConfigHelper.java +++ b/src/se/leap/leapclient/ConfigHelper.java @@ -142,7 +142,8 @@ public class ConfigHelper { try { // Initialize the keystore with the provided trusted certificates // Also provide the password of the keystore - keystore_trusted.load(leap_keystore, "uer92jf".toCharArray()); + //keystore_trusted.load(leap_keystore, "uer92jf".toCharArray()); + keystore_trusted.load(null, null); } finally { leap_keystore.close(); } diff --git a/src/se/leap/leapclient/ProviderAPI.java b/src/se/leap/leapclient/ProviderAPI.java index 01cbd01c..db5301e9 100644 --- a/src/se/leap/leapclient/ProviderAPI.java +++ b/src/se/leap/leapclient/ProviderAPI.java @@ -1,6 +1,7 @@ package se.leap.leapclient; import java.io.IOException; +import java.net.MalformedURLException; import java.net.URL; import java.security.Provider; import java.security.Security; @@ -68,20 +69,36 @@ public class ProviderAPI extends IntentService { String provider_main_url = (String) task.get(ConfigHelper.provider_key_url); String provider_name = provider_main_url.replaceFirst("http[s]?://", "").replaceFirst("\\/", "_"); String provider_json_url = guessURL(provider_main_url); + JSONObject provider_json = null; try { - JSONObject provider_json = getJSONFromProvider(provider_json_url); - String filename = provider_name + "_provider.json".replaceFirst("__", "_"); - ConfigHelper.saveFile(filename, provider_json.toString()); - - ProviderListContent.addItem(new ProviderItem(provider_name, ConfigHelper.openFileInputStream(filename), custom)); - receiver.send(ConfigHelper.CUSTOM_PROVIDER_ADDED, Bundle.EMPTY); + provider_json = getJSONFromProvider(provider_json_url); } catch (IOException e) { // TODO It could happen that an https site used a certificate not trusted. + try { + URL provider_url = new URL(provider_json_url); + String provider_json_string = new Scanner(provider_url.openStream()).useDelimiter("\\A").next(); + provider_json = new JSONObject(provider_json_string); + } catch (MalformedURLException e1) { + // TODO Auto-generated catch block + e1.printStackTrace(); + } catch (IOException e1) { + // TODO Auto-generated catch block + e1.printStackTrace(); + } catch (JSONException e1) { + // TODO Auto-generated catch block + e1.printStackTrace(); + } + e.printStackTrace(); } catch (JSONException e) { // TODO Auto-generated catch block e.printStackTrace(); } + String filename = provider_name + "_provider.json".replaceFirst("__", "_"); + ConfigHelper.saveFile(filename, provider_json.toString()); + + ProviderListContent.addItem(new ProviderItem(provider_name, ConfigHelper.openFileInputStream(filename), custom)); + receiver.send(ConfigHelper.CUSTOM_PROVIDER_ADDED, Bundle.EMPTY); } } -- cgit v1.2.3 From 1fcb255170a2be35eecc5645a7b1757101b844f6 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Parm=C3=A9nides=20GV?= Date: Mon, 18 Mar 2013 12:00:47 +0100 Subject: Refactored ProviderAPI code. ConfigurationWizard works without problem for both new and preseeded providers. I've added flow control for the activity to finish when all files have been downloaded, managing errors with setResult(RESULT_CANCELED). --- src/se/leap/leapclient/ConfigurationWizard.java | 14 +-- src/se/leap/leapclient/ProviderAPI.java | 135 ++++++++++++++---------- 2 files changed, 86 insertions(+), 63 deletions(-) (limited to 'src/se/leap/leapclient') diff --git a/src/se/leap/leapclient/ConfigurationWizard.java b/src/se/leap/leapclient/ConfigurationWizard.java index 69e13f19..90e74e51 100644 --- a/src/se/leap/leapclient/ConfigurationWizard.java +++ b/src/se/leap/leapclient/ConfigurationWizard.java @@ -126,18 +126,12 @@ public class ConfigurationWizard extends Activity try { saveProviderJson(current_provider_item); downloadJSONFiles(current_provider_item); - } catch (IOException e) { // TODO Auto-generated catch block e.printStackTrace(); } } } - - // FIXME!! We're going to have more Fragments and listeners, flow control? - // TODO There is no testing done to know if we're okay... - setResult(RESULT_OK); - finish(); } } @@ -214,5 +208,13 @@ public class ConfigurationWizard extends Activity .replace(R.id.configuration_wizard_layout, providerList, "providerlist") .commit(); } + else if(resultCode == ConfigHelper.CORRECTLY_DOWNLOADED_JSON_FILES) { + setResult(RESULT_OK); + finish(); + } + else if(resultCode == ConfigHelper.INCORRECTLY_DOWNLOADED_JSON_FILES) { + setResult(RESULT_CANCELED); + finish(); + } } } diff --git a/src/se/leap/leapclient/ProviderAPI.java b/src/se/leap/leapclient/ProviderAPI.java index db5301e9..afbf1c01 100644 --- a/src/se/leap/leapclient/ProviderAPI.java +++ b/src/se/leap/leapclient/ProviderAPI.java @@ -34,72 +34,93 @@ public class ProviderAPI extends IntentService { protected void onHandleIntent(Intent task_for) { final ResultReceiver receiver = task_for.getParcelableExtra("receiver"); Bundle task; - System.out.println("onHandleIntent called"); if((task = task_for.getBundleExtra(ConfigHelper.downloadJsonFilesBundleExtra)) != null) { - String provider_name = (String) task.get(ConfigHelper.provider_key); - String cert_url = (String) task.get(ConfigHelper.cert_key); - String eip_service_json_url = (String) task.get(ConfigHelper.eip_service_key); - try { - JSONObject provider_json = new JSONObject("{ \"provider\" : \"" + provider_name + "\"}"); - ConfigHelper.saveSharedPref(ConfigHelper.provider_key, provider_json); - - /*String cert_string = getStringFromProvider(cert_url); - JSONObject cert_json = new JSONObject("{ \"certificate\" : \"" + cert_string + "\"}"); - ConfigHelper.saveSharedPref(ConfigHelper.cert_key, cert_json); - ConfigHelper.addTrustedCertificate(provider_name, cert_string);*/ - URL cacert = new URL(cert_url); - ConfigHelper.addTrustedCertificate(provider_name, cacert.openStream()); - JSONObject eip_service_json = getJSONFromProvider(eip_service_json_url); - ConfigHelper.saveSharedPref(ConfigHelper.eip_service_key, eip_service_json); + if(downloadJsonFilesBundleExtra(task)) receiver.send(ConfigHelper.CORRECTLY_DOWNLOADED_JSON_FILES, Bundle.EMPTY); - } catch (IOException e) { - // TODO It could happen that an https site used a certificate not trusted. - e.printStackTrace(); + else receiver.send(ConfigHelper.INCORRECTLY_DOWNLOADED_JSON_FILES, Bundle.EMPTY); - } catch (JSONException e) { - ConfigHelper.rescueJSONException(e); - receiver.send(ConfigHelper.INCORRECTLY_DOWNLOADED_JSON_FILES, Bundle.EMPTY); - } catch(Exception e) { - e.printStackTrace(); - receiver.send(ConfigHelper.INCORRECTLY_DOWNLOADED_JSON_FILES, Bundle.EMPTY); - } } else if ((task = task_for.getBundleExtra(ConfigHelper.downloadNewProviderDotJSON)) != null) { - boolean custom = true; - String provider_main_url = (String) task.get(ConfigHelper.provider_key_url); - String provider_name = provider_main_url.replaceFirst("http[s]?://", "").replaceFirst("\\/", "_"); - String provider_json_url = guessURL(provider_main_url); - JSONObject provider_json = null; - try { - provider_json = getJSONFromProvider(provider_json_url); - } catch (IOException e) { - // TODO It could happen that an https site used a certificate not trusted. - try { - URL provider_url = new URL(provider_json_url); - String provider_json_string = new Scanner(provider_url.openStream()).useDelimiter("\\A").next(); - provider_json = new JSONObject(provider_json_string); - } catch (MalformedURLException e1) { - // TODO Auto-generated catch block - e1.printStackTrace(); - } catch (IOException e1) { - // TODO Auto-generated catch block - e1.printStackTrace(); - } catch (JSONException e1) { - // TODO Auto-generated catch block - e1.printStackTrace(); - } - - e.printStackTrace(); - } catch (JSONException e) { - // TODO Auto-generated catch block - e.printStackTrace(); - } + if(downloadNewProviderDotJSON(task)) + receiver.send(ConfigHelper.CUSTOM_PROVIDER_ADDED, Bundle.EMPTY); + else + receiver.send(ConfigHelper.INCORRECTLY_DOWNLOADED_JSON_FILES, Bundle.EMPTY); + } + } + + private boolean downloadNewProviderDotJSON(Bundle task) { + boolean custom = true; + String provider_main_url = (String) task.get(ConfigHelper.provider_key_url); + String provider_name = provider_main_url.replaceFirst("http[s]?://", "").replaceFirst("\\/", "_"); + String provider_json_url = guessURL(provider_main_url); + JSONObject provider_json = null; + try { + provider_json = getJSONFromProvider(provider_json_url); + } catch (IOException e) { + // It could happen that an https site used a certificate not trusted. + provider_json = downloadNewProviderDotJsonWithoutCert(provider_json_url); + } catch (JSONException e) { + // TODO Auto-generated catch block + e.printStackTrace(); + return false; + } + + if(provider_json == null) { + return false; + } else { String filename = provider_name + "_provider.json".replaceFirst("__", "_"); ConfigHelper.saveFile(filename, provider_json.toString()); + + ProviderListContent.addItem(new ProviderItem(provider_name, ConfigHelper.openFileInputStream(filename), custom)); + return true; + } + } + + private boolean downloadJsonFilesBundleExtra(Bundle task) { + String provider_name = (String) task.get(ConfigHelper.provider_key); + String cert_url = (String) task.get(ConfigHelper.cert_key); + String eip_service_json_url = (String) task.get(ConfigHelper.eip_service_key); + try { + //JSONObject provider_json = new JSONObject("{ \"provider\" : \"" + provider_name + "\"}"); + //ConfigHelper.saveSharedPref(ConfigHelper.provider_key, provider_json); - ProviderListContent.addItem(new ProviderItem(provider_name, ConfigHelper.openFileInputStream(filename), custom)); - receiver.send(ConfigHelper.CUSTOM_PROVIDER_ADDED, Bundle.EMPTY); + /*String cert_string = getStringFromProvider(cert_url); + JSONObject cert_json = new JSONObject("{ \"certificate\" : \"" + cert_string + "\"}"); + ConfigHelper.saveSharedPref(ConfigHelper.cert_key, cert_json); + ConfigHelper.addTrustedCertificate(provider_name, cert_string);*/ + URL cacert = new URL(cert_url); + ConfigHelper.addTrustedCertificate(provider_name, cacert.openStream()); + JSONObject eip_service_json = getJSONFromProvider(eip_service_json_url); + ConfigHelper.saveSharedPref(ConfigHelper.eip_service_key, eip_service_json); + return true; + } catch (IOException e) { + // It could happen that an https site used a certificate not trusted: solved above using URL + e.printStackTrace(); + return false; + } catch (JSONException e) { + ConfigHelper.rescueJSONException(e); + return false; + } catch(Exception e) { + e.printStackTrace(); + return false; + } + } + + private JSONObject downloadNewProviderDotJsonWithoutCert( + String provider_json_url) { + JSONObject provider_json = null; + try { + URL provider_url = new URL(provider_json_url); + String provider_json_string = new Scanner(provider_url.openStream()).useDelimiter("\\A").next(); + provider_json = new JSONObject(provider_json_string); + } catch (MalformedURLException e1) { + e1.printStackTrace(); + } catch (IOException e1) { + e1.printStackTrace(); + } catch (JSONException e1) { + e1.printStackTrace(); } + return provider_json; } private String guessURL(String provider_main_url) { -- cgit v1.2.3 From e99b19c279abddc1cfb30a12b48f37a8e37a82a2 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Parm=C3=A9nides=20GV?= Date: Mon, 18 Mar 2013 12:11:16 +0100 Subject: Loads bks file from assets. --- src/se/leap/leapclient/ConfigHelper.java | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) (limited to 'src/se/leap/leapclient') diff --git a/src/se/leap/leapclient/ConfigHelper.java b/src/se/leap/leapclient/ConfigHelper.java index 8a0e2b45..5d89e491 100644 --- a/src/se/leap/leapclient/ConfigHelper.java +++ b/src/se/leap/leapclient/ConfigHelper.java @@ -142,8 +142,8 @@ public class ConfigHelper { try { // Initialize the keystore with the provided trusted certificates // Also provide the password of the keystore - //keystore_trusted.load(leap_keystore, "uer92jf".toCharArray()); - keystore_trusted.load(null, null); + keystore_trusted.load(leap_keystore, "uer92jf".toCharArray()); + //keystore_trusted.load(null, null); } finally { leap_keystore.close(); } -- cgit v1.2.3 From 57ab546646e3e2814be547dd4666ca2de4548597 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Parm=C3=A9nides=20GV?= Date: Tue, 19 Mar 2013 16:29:09 +0100 Subject: Trying to find a jar from JBoss to use their SRP implementation. Imports errors because of classes not yet found. --- src/se/leap/leapclient/ProviderAPI.java | 3 --- 1 file changed, 3 deletions(-) (limited to 'src/se/leap/leapclient') diff --git a/src/se/leap/leapclient/ProviderAPI.java b/src/se/leap/leapclient/ProviderAPI.java index b20e30b1..eb3afcfa 100644 --- a/src/se/leap/leapclient/ProviderAPI.java +++ b/src/se/leap/leapclient/ProviderAPI.java @@ -24,9 +24,6 @@ import org.apache.http.client.methods.HttpPost; import org.apache.http.client.methods.HttpPut; import org.apache.http.cookie.Cookie; import org.apache.http.impl.client.DefaultHttpClient; -import org.jboss.security.srp.SRPClientSession; -import org.jboss.security.srp.SRPConf.SRPParams; -import org.jboss.security.srp.SRPParameters; import org.json.JSONException; import org.json.JSONObject; -- cgit v1.2.3 From b48c3f63bfbdb0c01950cbd47c41a560afaf4fe2 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Parm=C3=A9nides=20GV?= Date: Tue, 19 Mar 2013 17:39:53 +0100 Subject: The new certificate added by ConfigHelper.addTrustedCertificate did not used the provider alias, but a predefined (I forgot removing quotes from argument) string. --- src/se/leap/leapclient/ConfigHelper.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'src/se/leap/leapclient') diff --git a/src/se/leap/leapclient/ConfigHelper.java b/src/se/leap/leapclient/ConfigHelper.java index 5d89e491..35aec885 100644 --- a/src/se/leap/leapclient/ConfigHelper.java +++ b/src/se/leap/leapclient/ConfigHelper.java @@ -104,7 +104,7 @@ public class ConfigHelper { cf = CertificateFactory.getInstance("X.509"); X509Certificate cert = (X509Certificate)cf.generateCertificate(inputStream); - keystore_trusted.setCertificateEntry("provider", cert); + keystore_trusted.setCertificateEntry(provider, cert); } catch (CertificateException e) { // TODO Auto-generated catch block e.printStackTrace(); -- cgit v1.2.3 From 5f66e5765f52aab1907939018e40578e939dbc5f Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Parm=C3=A9nides=20GV?= Date: Wed, 20 Mar 2013 17:35:39 +0100 Subject: Ready to use with Android JellyBean (api 16) --- src/se/leap/leapclient/ConfigHelper.java | 2 +- src/se/leap/leapclient/NewProviderDialog.java | 2 -- 2 files changed, 1 insertion(+), 3 deletions(-) (limited to 'src/se/leap/leapclient') diff --git a/src/se/leap/leapclient/ConfigHelper.java b/src/se/leap/leapclient/ConfigHelper.java index 35aec885..c2f6c413 100644 --- a/src/se/leap/leapclient/ConfigHelper.java +++ b/src/se/leap/leapclient/ConfigHelper.java @@ -122,7 +122,7 @@ public class ConfigHelper { cf = CertificateFactory.getInstance("X.509"); X509Certificate cert = (X509Certificate)cf.generateCertificate(openFileInputStream(filename_to_save)); - keystore_trusted.setCertificateEntry("provider", cert); + keystore_trusted.setCertificateEntry(provider, cert); } catch (CertificateException e) { // TODO Auto-generated catch block e.printStackTrace(); diff --git a/src/se/leap/leapclient/NewProviderDialog.java b/src/se/leap/leapclient/NewProviderDialog.java index 09e7453a..52453485 100644 --- a/src/se/leap/leapclient/NewProviderDialog.java +++ b/src/se/leap/leapclient/NewProviderDialog.java @@ -8,8 +8,6 @@ import android.content.DialogInterface; import android.os.Bundle; import android.view.LayoutInflater; import android.view.View; -import android.view.ViewGroup; -import android.webkit.WebView.FindListener; import android.widget.EditText; import android.widget.Toast; -- cgit v1.2.3 From 54ad71d09d6cb61fad62d1376cd7b3bf237e16f9 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Parm=C3=A9nides=20GV?= Date: Fri, 29 Mar 2013 16:30:39 +0100 Subject: Tried to implement SRP with JBoss: discarded because it needs RMI to get the salt, and because of our messageflow I cannot obtain it before starting Authentication. That's why on line 132 from ProviderAPI I tried to get a new SRPClientSession using the newly obtained salt, but of course it fails since A cannot be restored from previous initialization. Next step: try with srpforjava. Next next step: if srpforjava does not work for us, use lower level methods to implement our own http srp flow. --- src/se/leap/leapclient/ProviderAPI.java | 270 +++++--------------------------- 1 file changed, 35 insertions(+), 235 deletions(-) (limited to 'src/se/leap/leapclient') diff --git a/src/se/leap/leapclient/ProviderAPI.java b/src/se/leap/leapclient/ProviderAPI.java index eb3afcfa..aa1ce305 100644 --- a/src/se/leap/leapclient/ProviderAPI.java +++ b/src/se/leap/leapclient/ProviderAPI.java @@ -2,20 +2,11 @@ package se.leap.leapclient; import java.io.IOException; import java.math.BigInteger; -import java.nio.ByteBuffer; -import java.security.MessageDigest; import java.security.NoSuchAlgorithmException; -import java.security.SecureRandom; +import java.util.ArrayList; import java.util.List; -import java.util.Random; import java.util.Scanner; -import org.bouncycastle.crypto.CryptoException; -import org.bouncycastle.crypto.agreement.srp.SRP6Client; -import org.bouncycastle.crypto.agreement.srp.SRP6VerifierGenerator; -import org.bouncycastle.crypto.digests.SHA256Digest; -import org.bouncycastle.crypto.prng.RandomGenerator; -import org.bouncycastle.jcajce.provider.digest.Whirlpool.Digest; import org.apache.http.HttpEntity; import org.apache.http.HttpResponse; import org.apache.http.client.ClientProtocolException; @@ -24,6 +15,9 @@ import org.apache.http.client.methods.HttpPost; import org.apache.http.client.methods.HttpPut; import org.apache.http.cookie.Cookie; import org.apache.http.impl.client.DefaultHttpClient; +import org.jboss.security.srp.SRPClientSession; +import org.jboss.security.srp.SRPParameters; +import org.jboss.security.srp.SRPServerInterface; import org.json.JSONException; import org.json.JSONObject; @@ -31,7 +25,6 @@ import se.leap.leapclient.ProviderListContent.ProviderItem; import android.app.IntentService; import android.content.Intent; -import android.content.SharedPreferences; import android.os.Bundle; import android.os.ResultReceiver; import android.util.Log; @@ -120,44 +113,6 @@ public class ProviderAPI extends IntentService { BigInteger salt = ng_1024.probablePrime(1024, null); byte[] salt_in_bytes = salt.toByteArray(); - SRP6VerifierGenerator verifier_generator = new SRP6VerifierGenerator(); - verifier_generator.init(ng_1024, ConfigHelper.g, new SHA256Digest()); - BigInteger verifier = verifier_generator.generateVerifier(salt_in_bytes, username.getBytes(), password.getBytes()); - - return sendRegisterMessage(authentication_server, salt.toString(16), verifier.toString(16), username); - } - - private boolean sendRegisterMessage(String server_url, String password_salt, String password_verifier, String login) { - DefaultHttpClient client = new LeapHttpClient(getApplicationContext()); - String parameter_chain = "user[password_salt]" + "=" + password_salt + "&" + "user[password_verifier]" + "=" + password_verifier + "&" + "user[login]" + "=" + login; - HttpPost post = new HttpPost(server_url + "/users.json" + "?" + parameter_chain); - - HttpResponse getResponse; - try { - getResponse = client.execute(post); - 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("errors") || json_response.has("errors")) { - return false; - } - //else if(json_response.getString("password_salt").equalsIgnoreCase(password_salt) && json_response.getString("login").equalsIgnoreCase(login)) - else if(json_response.getBoolean("ok") && json_response.getString("login").equalsIgnoreCase(login)) - return true; - } catch (ClientProtocolException e) { - // TODO Auto-generated catch block - e.printStackTrace(); - 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; - } - return false; } @@ -165,12 +120,17 @@ public class ProviderAPI extends IntentService { String username = (String) task.get(ConfigHelper.username_key); String password = (String) task.get(ConfigHelper.password_key); String authentication_server = (String) task.get(ConfigHelper.srp_server_url_key); - - SRPParameters params = new SRPParameters(ConfigHelper.NG_1024.getBytes(), "2".getBytes(), null); + + SRPParameters params = new SRPParameters(ConfigHelper.NG_1024.getBytes(), "2".getBytes(), "salt".getBytes(), "SHA-256"); SRPClientSession client = new SRPClientSession(username, password.toCharArray(), params); byte[] A = client.exponential(); try { - byte[] B = sendAToSRPServer(authentication_server, username, A); + JSONObject saltAndB = sendAToSRPServer(authentication_server, username, getHexString(A)); + byte[] B = saltAndB.getString("B").getBytes(); + String salt = saltAndB.getString("salt"); + params = new SRPParameters(ConfigHelper.NG_1024.getBytes(), "2".getBytes(), salt.getBytes(), "SHA-256"); + client = new SRPClientSession(username, password.toCharArray(), params); + client.exponential(); byte[] M1 = client.response(B); byte[] M2 = sendM1ToSRPServer(authentication_server, username, M1); if( client.verify(M2) == false ) @@ -179,78 +139,39 @@ public class ProviderAPI extends IntentService { } catch (ClientProtocolException e1) { // TODO Auto-generated catch block e1.printStackTrace(); + return false; } catch (IOException e1) { // TODO Auto-generated catch block e1.printStackTrace(); + return false; } catch (JSONException e1) { // TODO Auto-generated catch block e1.printStackTrace(); - } catch (NoSuchAlgorithmException e) { - // TODO Auto-generated catch block - e.printStackTrace(); - } - - SRP6Client srp_client = new SRP6Client(); - BigInteger n = new BigInteger(ConfigHelper.NG_1024, 16); - srp_client.init(n, ConfigHelper.g, new SHA256Digest(), new SecureRandom()); - - BigInteger salt = BigInteger.probablePrime(1024, null); - - BigInteger clientA = srp_client.generateClientCredentials(salt.toString(16).getBytes(), username.getBytes(), password.getBytes()); - - try { - BigInteger serverB = sendAToSRPServer(authentication_server, username, clientA); - - if(serverB == BigInteger.ZERO) - return false; // TODO Show error: error trying to start authentication with provider - - BigInteger s = srp_client.calculateSecret(serverB); - - BigInteger k = new BigInteger(1, MessageDigest.getInstance("SHA-256").digest(s.toByteArray())); - - BigInteger m1 = generateM1(k, salt, clientA, serverB, username); - - BigInteger m2 = sendM1ToSRPServer(authentication_server, username, m1); - - if(m2 == BigInteger.ZERO) - return false; // TODO Show error: error in M1 - - boolean verified = verifyM2(m2, k, clientA, serverB, username); - - return verified; // TODO If false, Username or password are not correct -> Show a warning and get back to login fragment - } catch (ClientProtocolException e) { - // TODO Auto-generated catch block - e.printStackTrace(); - return false; - } catch (IOException e) { - // TODO Auto-generated catch block - // From sendAToSRPServer or from sendM1ToSRPServer - e.printStackTrace(); - return false; - } catch (CryptoException e) { - // TODO Auto-generated catch block - // From calculateSecret - e.printStackTrace(); return false; } catch (NoSuchAlgorithmException e) { - // TODO Auto-generated catch block - // From MessageDigest.getInstance - e.printStackTrace(); - return false; - } catch (NumberFormatException e) { - // TODO Auto-generated catch block - e.printStackTrace(); - return false; - } catch (JSONException e) { // TODO Auto-generated catch block e.printStackTrace(); return false; } } + + public static String getHexString(byte[] b) { + String result = ""; + StringBuffer sb = new StringBuffer(); + for (byte tmp : b) { + sb.append(Integer.toHexString((int) (tmp & 0xff))); + } + return sb.toString(); +// for (int i=0; i < b.length; i++) { +// result += +// Integer.toString( ( b[i] & 0xff ) + 0x100, 16).substring( 1 ); +// } +// return result; + } - private BigInteger sendAToSRPServer(String server_url, String username, BigInteger clientA) throws ClientProtocolException, IOException, NumberFormatException, JSONException { + private JSONObject sendAToSRPServer(String server_url, String username, String clientA) throws ClientProtocolException, IOException, JSONException { DefaultHttpClient client = new LeapHttpClient(getApplicationContext()); - String parameter_chain = "A" + "=" + clientA.toString(16) + "&" + "login" + "=" + username; + String parameter_chain = "A" + "=" + clientA + "&" + "login" + "=" + username; HttpPost post = new HttpPost(server_url + "/sessions.json" + "?" + parameter_chain); HttpResponse getResponse = client.execute(post); @@ -258,18 +179,18 @@ public class ProviderAPI extends IntentService { String plain_response = new Scanner(responseEntity.getContent()).useDelimiter("\\A").next(); JSONObject json_response = new JSONObject(plain_response); if(!json_response.isNull("errors") || json_response.has("errors")) { - return BigInteger.ZERO; + return new JSONObject(); } List cookies = client.getCookieStore().getCookies(); if(!cookies.isEmpty()) { String session_id = cookies.get(0).getValue(); } - return new BigInteger(json_response.getString("B"), 16); + return json_response; } - + private byte[] sendAToSRPServer(String server_url, String username, byte[] clientA) throws ClientProtocolException, IOException, JSONException { DefaultHttpClient client = new LeapHttpClient(getApplicationContext()); - String parameter_chain = "A" + "=" + new String(clientA) + "&" + "login" + "=" + username; + String parameter_chain = "A" + "=" + getHexString(clientA) + "&" + "login" + "=" + username; HttpPost post = new HttpPost(server_url + "/sessions.json" + "?" + parameter_chain); HttpResponse getResponse = client.execute(post); @@ -286,130 +207,9 @@ public class ProviderAPI extends IntentService { return json_response.getString("B").getBytes(); } - public BigInteger generateM1(BigInteger K, BigInteger salt, BigInteger clientA, BigInteger serverB, String username) throws NoSuchAlgorithmException { - String digest_of_N_as_string = new BigInteger(1, MessageDigest.getInstance("SHA-256").digest(hex2ascii(ConfigHelper.NG_1024).getBytes())).toString(16); - - String digest_of_G_as_string = new BigInteger(1, MessageDigest.getInstance("SHA-256").digest(ConfigHelper.g.toString(16).getBytes())).toString(16); - - String xor_n_and_g = hexXor(digest_of_N_as_string, digest_of_G_as_string); - - String digest_of_username_as_string = new BigInteger(MessageDigest.getInstance("SHA-256").digest(username.getBytes())).toString(16); - - String m1_source_string = xor_n_and_g + digest_of_username_as_string + salt.toString(16) + clientA.toString(16) + serverB.toString(16) + K.toString(16); - - return new BigInteger(1, MessageDigest.getInstance("SHA-256").digest(m1_source_string.getBytes())); - } - - private boolean verifyM2(BigInteger M2, BigInteger K, BigInteger clientA, BigInteger serverB, String username) throws NoSuchAlgorithmException { - /* https://github.com/leapcode/srp_js/blob/master/src/srp_session.js - var hashN = SHA256(hex2a(N.toString(16))) - var hashG = SHA256(hex2a(g.toString(16))) - var hexString = hexXor(hashN, hashG); - hexString += SHA256(I); - hexString += salt; - hexString += Astr; - hexString += Bstr; - hexString += K - M = SHA256(hex2a(hexString)); - //M2 = H(A, M, K) - M2 = SHA256(hex2a(Astr + M + K)); - */ - MessageDigest digest_of_N = MessageDigest.getInstance("SHA-256"); - digest_of_N.update(ConfigHelper.NG_1024.getBytes()); - String digest_of_N_as_string = new BigInteger(digest_of_N.digest()).toString(); - - MessageDigest digest_of_G = MessageDigest.getInstance("SHA-256"); - digest_of_G.update(ConfigHelper.g.toByteArray()); - String digest_of_G_as_string = new BigInteger(digest_of_G.digest()).toString(); - - String xor_n_and_g = hexXor(digest_of_N_as_string, digest_of_G_as_string); - - MessageDigest digest_of_username = MessageDigest.getInstance("SHA-256"); - digest_of_username.update(username.getBytes()); - String digest_of_username_as_string = new BigInteger(digest_of_username.digest()).toString(); - - MessageDigest my_M1 = MessageDigest.getInstance("SHA-256"); - String m1_source_string = xor_n_and_g + digest_of_username_as_string + clientA.toString() + serverB.toString() + K.toString(); - my_M1.update(m1_source_string.getBytes()); - - MessageDigest my_own_M2 = MessageDigest.getInstance("SHA-256"); - String m2_source_string = clientA.toString() + new BigInteger(my_M1.digest()).toString() + K.toString(); - - my_own_M2.update(m2_source_string.getBytes()); - - return M2 == new BigInteger(my_own_M2.digest()); - } - - private String hexXor(String a, String b) { - String str = ""; - for (int i = 0; i < a.length(); i += 2) { - int xor = 0; - if(a.length() > i + 2) - xor = Integer.parseInt(a.substring(i, 2 + i), 16) ^ Integer.parseInt(b.substring(i, 2 + i), 16); - else - xor = Integer.parseInt(a.substring(i, 1 + i), 16) ^ Integer.parseInt(b.substring(i, 1 + i), 16); - String xor_string = String.valueOf(Integer.valueOf(String.valueOf(xor), 16)); - str += (xor_string.length() == 1) ? ("0" + xor) : xor_string; - } - return stringToHex(str); - } - - private String stringToHex(String base) - { - StringBuffer buffer = new StringBuffer(); - int intValue; - for(int x = 0; x < base.length(); x++) - { - int cursor = 0; - intValue = base.charAt(x); - String binaryChar = new String(Integer.toBinaryString(base.charAt(x))); - for(int i = 0; i < binaryChar.length(); i++) - { - if(binaryChar.charAt(i) == '1') - { - cursor += 1; - } - } - if((cursor % 2) > 0) - { - intValue += 128; - } - buffer.append(Integer.toHexString(intValue) + ""); - } - return buffer.toString(); -} - - private String hex2ascii(String hex) { - StringBuilder output = new StringBuilder(); - for (int i = 0; i < hex.length(); i+=2) { - String str = hex.substring(i, i+2); - output.append((char)Integer.parseInt(str, 16)); - } - String debug = output.toString(); - return output.toString(); - } - - private BigInteger sendM1ToSRPServer(String server_url, String username, BigInteger m1) throws ClientProtocolException, IOException, JSONException { - DefaultHttpClient client = new LeapHttpClient(getApplicationContext()); - String parameter_chain = "client_auth" + "=" + m1.toString(16); - HttpPut put = new HttpPut(server_url + "/sessions/" + username +".json" + "?" + parameter_chain); - - HttpResponse getResponse = client.execute(put); - 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("errors") || json_response.has("errors")) { - return BigInteger.ZERO; - } - - List cookies = client.getCookieStore().getCookies(); - String session_id = cookies.get(0).getValue(); - return new BigInteger(json_response.getString("M2"), 16); - } - private byte[] sendM1ToSRPServer(String server_url, String username, byte[] m1) throws ClientProtocolException, IOException, JSONException { DefaultHttpClient client = new LeapHttpClient(getApplicationContext()); - String parameter_chain = "client_auth" + "=" + new String(m1); + String parameter_chain = "client_auth" + "=" + getHexString(m1); HttpPut put = new HttpPut(server_url + "/sessions/" + username +".json" + "?" + parameter_chain); HttpResponse getResponse = client.execute(put); -- cgit v1.2.3 From 7af9519591ea481718b4f903b97463250cc5f116 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Parm=C3=A9nides=20GV?= Date: Sat, 30 Mar 2013 11:20:07 +0100 Subject: Trial for srpforjava: it does not work since it implements SRP-6, and not SRP-6a. That means, for example, that M1 is calculated differently from what we need. --- src/se/leap/leapclient/ProviderAPI.java | 31 ++++++++++++++----------------- 1 file changed, 14 insertions(+), 17 deletions(-) (limited to 'src/se/leap/leapclient') diff --git a/src/se/leap/leapclient/ProviderAPI.java b/src/se/leap/leapclient/ProviderAPI.java index aa1ce305..b8d6a765 100644 --- a/src/se/leap/leapclient/ProviderAPI.java +++ b/src/se/leap/leapclient/ProviderAPI.java @@ -15,12 +15,13 @@ import org.apache.http.client.methods.HttpPost; import org.apache.http.client.methods.HttpPut; import org.apache.http.cookie.Cookie; import org.apache.http.impl.client.DefaultHttpClient; -import org.jboss.security.srp.SRPClientSession; -import org.jboss.security.srp.SRPParameters; -import org.jboss.security.srp.SRPServerInterface; import org.json.JSONException; import org.json.JSONObject; +import com.jordanzimmerman.SRPClientSession; +import com.jordanzimmerman.SRPConstants; +import com.jordanzimmerman.SRPFactory; + import se.leap.leapclient.ProviderListContent.ProviderItem; import android.app.IntentService; @@ -121,20 +122,20 @@ public class ProviderAPI extends IntentService { String password = (String) task.get(ConfigHelper.password_key); String authentication_server = (String) task.get(ConfigHelper.srp_server_url_key); - SRPParameters params = new SRPParameters(ConfigHelper.NG_1024.getBytes(), "2".getBytes(), "salt".getBytes(), "SHA-256"); - SRPClientSession client = new SRPClientSession(username, password.toCharArray(), params); - byte[] A = client.exponential(); + SRPConstants constants = new SRPConstants(new BigInteger(ConfigHelper.NG_1024, 16), ConfigHelper.g); + SRPFactory factory = SRPFactory.getInstance(constants); + SRPClientSession session = factory.newClientSession(password.getBytes()); + session.setSalt_s(new BigInteger("1")); + byte[] A = session.getPublicKey_A().toString(16).getBytes(); try { JSONObject saltAndB = sendAToSRPServer(authentication_server, username, getHexString(A)); - byte[] B = saltAndB.getString("B").getBytes(); + String B = saltAndB.getString("B"); String salt = saltAndB.getString("salt"); - params = new SRPParameters(ConfigHelper.NG_1024.getBytes(), "2".getBytes(), salt.getBytes(), "SHA-256"); - client = new SRPClientSession(username, password.toCharArray(), params); - client.exponential(); - byte[] M1 = client.response(B); + session.setSalt_s(new BigInteger(salt, 16)); + session.setServerPublicKey_B(new BigInteger(B, 16)); + byte[] M1 = session.getEvidenceValue_M1().toString(16).getBytes(); byte[] M2 = sendM1ToSRPServer(authentication_server, username, M1); - if( client.verify(M2) == false ) - throw new SecurityException("Failed to validate server reply"); + session.validateServerEvidenceValue_M2(new BigInteger(getHexString(M2), 16)); return true; } catch (ClientProtocolException e1) { // TODO Auto-generated catch block @@ -148,10 +149,6 @@ public class ProviderAPI extends IntentService { // TODO Auto-generated catch block e1.printStackTrace(); return false; - } catch (NoSuchAlgorithmException e) { - // TODO Auto-generated catch block - e.printStackTrace(); - return false; } } -- cgit v1.2.3 From 3e9a68fcc6c16be69abfa27d5fd3a2cbfc620bb0 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Parm=C3=A9nides=20GV?= Date: Wed, 3 Apr 2013 19:34:40 +0200 Subject: Fixed bug #2146 => A calculation is now fine. Next step: fix M1 calculation, since right now (using tests) response() method is not doing OK. Added new SRPSession modifying response() method from JBoss SRP implementation. Added hosts-for-android-emulator. Use with the following commands to be able to test on api.lvh.me: adb shell mount -o rw,remount -t yaffs2 /dev/block/mtdblock3 /system adb push ~/workspace/leap_android/hosts-for-android-emulator /system/etc/hosts --- src/se/leap/leapclient/LeapHttpClient.java | 8 ++ src/se/leap/leapclient/LeapSRPSession.java | 193 +++++++++++++++++++++++++++++ src/se/leap/leapclient/ProviderAPI.java | 99 ++++++--------- 3 files changed, 240 insertions(+), 60 deletions(-) create mode 100644 src/se/leap/leapclient/LeapSRPSession.java (limited to 'src/se/leap/leapclient') diff --git a/src/se/leap/leapclient/LeapHttpClient.java b/src/se/leap/leapclient/LeapHttpClient.java index 9e1a541b..fd6db745 100644 --- a/src/se/leap/leapclient/LeapHttpClient.java +++ b/src/se/leap/leapclient/LeapHttpClient.java @@ -15,6 +15,8 @@ import android.content.Context; public class LeapHttpClient extends DefaultHttpClient { final Context context; + + private static LeapHttpClient client; public LeapHttpClient(Context context) { this.context = context; @@ -55,4 +57,10 @@ public class LeapHttpClient extends DefaultHttpClient { throw new AssertionError(e); } } + + public static LeapHttpClient getInstance(Context context) { + if(client == null) + client = new LeapHttpClient(context); + return client; + } } diff --git a/src/se/leap/leapclient/LeapSRPSession.java b/src/se/leap/leapclient/LeapSRPSession.java new file mode 100644 index 00000000..1d1f0c9d --- /dev/null +++ b/src/se/leap/leapclient/LeapSRPSession.java @@ -0,0 +1,193 @@ +package se.leap.leapclient; + +import java.math.BigInteger; +import java.security.MessageDigest; +import java.security.NoSuchAlgorithmException; +import java.util.Arrays; + +import org.jboss.security.Util; +import org.jboss.security.srp.SRPClientSession; +import org.jboss.security.srp.SRPParameters; +import org.jboss.security.srp.SRPPermission; + +public class LeapSRPSession { + + private SRPParameters params; + private BigInteger N; + private BigInteger g; + private BigInteger x; + private BigInteger v; + private byte[] s; + private BigInteger a; + private BigInteger A; + private byte[] K; + /** 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, char[] 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. This must be + 8 bytes in length. + */ + public LeapSRPSession(String username, char[] password, SRPParameters params, + byte[] abytes) + { + try + { + // Initialize the secure random number and message digests + Util.init(); + } + catch(NoSuchAlgorithmException e) + { + } + this.params = params; + this.g = new BigInteger(1, params.g); + this.N = new BigInteger(1, params.N); + 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); + } + + // Calculate x = H(s | H(U | ':' | password)) + byte[] xb = Util.calculatePasswordHash(username, password, params.s); + this.x = new BigInteger(1, xb); + this.v = g.modPow(x, N); // g^x % N + + serverHash = Util.newDigest(); + clientHash = Util.newDigest(); + // H(N) + byte[] hn = Util.newDigest().digest(params.N); + // H(g) + byte[] hg = Util.newDigest().digest(params.g); + // clientHash = H(N) xor H(g) + byte[] hxg = Util.xor(hn, hg, 20); + clientHash.update(hxg); + // clientHash = H(N) xor H(g) | H(U) + clientHash.update(Util.newDigest().digest(username.getBytes())); + // clientHash = H(N) xor H(g) | H(U) | s + clientHash.update(params.s); + K = null; + } + + /** + * @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, Util.getPRNG()); + } while(a.compareTo(one) <= 0); + } + A = g.modPow(a, N); + Abytes = Util.trim(A.toByteArray()); + // clientHash = H(N) xor H(g) | H(U) | A + clientHash.update(Abytes); + // serverHash = A + serverHash.update(Abytes); + } + return Abytes; + } + + public byte[] response(byte[] Bbytes) throws NoSuchAlgorithmException { + // clientHash = H(N) xor H(g) | H(U) | s | A | B + clientHash.update(Bbytes); + + /* + var B = new BigInteger(ephemeral, 16); + var Bstr = ephemeral; + // u = H(A,B) + var u = new BigInteger(SHA256(hex2a(Astr + Bstr)), 16); + // x = H(s, H(I:p)) + var x = this.calcX(salt); + //S = (B - kg^x) ^ (a + ux) + var kgx = k.multiply(g.modPow(x, N)); + var aux = a.add(u.multiply(x)); + S = B.subtract(kgx).modPow(aux, N); + K = SHA256(hex2a(S.toString(16))); + */ + byte[] hA = Util.newDigest().digest(A.toByteArray()); + MessageDigest u_digest = Util.newDigest(); + u_digest.update(A.toByteArray()); + u_digest.update(Bbytes); + clientHash.update(u_digest.digest()); + byte[] ub = new BigInteger(clientHash.digest()).toByteArray(); + // Calculate S = (B - g^x) ^ (a + u * x) % N + BigInteger B = new BigInteger(1, Bbytes); + if( B.compareTo(v) < 0 ) + B = B.add(N); + BigInteger u = new BigInteger(1, ub); + BigInteger B_v = B.subtract(v); + BigInteger a_ux = a.add(u.multiply(x)); + BigInteger S = B_v.modPow(a_ux, N); + // K = SessionHash(S) + MessageDigest sessionDigest = MessageDigest.getInstance(params.hashAlgorithm); + K = sessionDigest.digest(S.toByteArray()); + // clientHash = H(N) xor H(g) | H(U) | A | B | K + clientHash.update(K); + byte[] M1 = clientHash.digest(); + return M1; + } + + + /** + * @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) + byte[] myM2 = serverHash.digest(); + boolean valid = Arrays.equals(M2, myM2); + return valid; + } + + /** Returns the negotiated session K, K = SHA_Interleave(S) + @return the private session K byte[] + @throws SecurityException - if the current thread does not have an + getSessionKey SRPPermission. + */ + public byte[] getSessionKey() throws SecurityException + { + SecurityManager sm = System.getSecurityManager(); + if( sm != null ) + { + SRPPermission p = new SRPPermission("getSessionKey"); + sm.checkPermission(p); + } + return K; + } + +} diff --git a/src/se/leap/leapclient/ProviderAPI.java b/src/se/leap/leapclient/ProviderAPI.java index b8d6a765..ea1410ad 100644 --- a/src/se/leap/leapclient/ProviderAPI.java +++ b/src/se/leap/leapclient/ProviderAPI.java @@ -3,7 +3,6 @@ package se.leap.leapclient; import java.io.IOException; import java.math.BigInteger; import java.security.NoSuchAlgorithmException; -import java.util.ArrayList; import java.util.List; import java.util.Scanner; @@ -13,15 +12,16 @@ import org.apache.http.client.ClientProtocolException; import org.apache.http.client.methods.HttpGet; import org.apache.http.client.methods.HttpPost; import org.apache.http.client.methods.HttpPut; +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.SRPClientSession; +import org.jboss.security.srp.SRPParameters; import org.json.JSONException; import org.json.JSONObject; -import com.jordanzimmerman.SRPClientSession; -import com.jordanzimmerman.SRPConstants; -import com.jordanzimmerman.SRPFactory; - import se.leap.leapclient.ProviderListContent.ProviderItem; import android.app.IntentService; @@ -121,22 +121,31 @@ public class ProviderAPI extends IntentService { String username = (String) task.get(ConfigHelper.username_key); String password = (String) task.get(ConfigHelper.password_key); String authentication_server = (String) task.get(ConfigHelper.srp_server_url_key); + + String salt = "abcd"; - SRPConstants constants = new SRPConstants(new BigInteger(ConfigHelper.NG_1024, 16), ConfigHelper.g); - SRPFactory factory = SRPFactory.getInstance(constants); - SRPClientSession session = factory.newClientSession(password.getBytes()); - session.setSalt_s(new BigInteger("1")); - byte[] A = session.getPublicKey_A().toString(16).getBytes(); + SRPParameters params = new SRPParameters(new BigInteger(ConfigHelper.NG_1024, 16).toByteArray(), new BigInteger("2").toByteArray(), new BigInteger(salt, 16).toByteArray(), "SHA-256"); + //SRPClientSession client = new SRPClientSession(username, password.toCharArray(), params); + LeapSRPSession client = new LeapSRPSession(username, password.toCharArray(), params); + byte[] A = client.exponential(); try { - JSONObject saltAndB = sendAToSRPServer(authentication_server, username, getHexString(A)); - String B = saltAndB.getString("B"); - String salt = saltAndB.getString("salt"); - session.setSalt_s(new BigInteger(salt, 16)); - session.setServerPublicKey_B(new BigInteger(B, 16)); - byte[] M1 = session.getEvidenceValue_M1().toString(16).getBytes(); - byte[] M2 = sendM1ToSRPServer(authentication_server, username, M1); - session.validateServerEvidenceValue_M2(new BigInteger(getHexString(M2), 16)); - return true; + JSONObject saltAndB = sendAToSRPServer(authentication_server, username, new BigInteger(A).toString(16)); + if(saltAndB.length() > 0) { + byte[] B = saltAndB.getString("B").getBytes(); + salt = saltAndB.getString("salt"); + params = new SRPParameters(new BigInteger(ConfigHelper.NG_1024, 16).toByteArray(), new BigInteger("2").toByteArray(), new BigInteger(salt, 16).toByteArray(), "SHA-256"); + //client = new SRPClientSession(username, password.toCharArray(), params); + client = new LeapSRPSession(username, password.toCharArray(), params); + A = client.exponential(); + saltAndB = sendAToSRPServer(authentication_server, username, new BigInteger(A).toString(16)); + String Bhex = saltAndB.getString("B"); + byte[] M1 = client.response(new BigInteger(Bhex, 16).toByteArray()); + byte[] M2 = sendM1ToSRPServer(authentication_server, username, M1); + if( client.verify(M2) == false ) + throw new SecurityException("Failed to validate server reply"); + return true; + } + else return false; } catch (ClientProtocolException e1) { // TODO Auto-generated catch block e1.printStackTrace(); @@ -149,25 +158,15 @@ public class ProviderAPI extends IntentService { // TODO Auto-generated catch block e1.printStackTrace(); return false; + } catch (NoSuchAlgorithmException e) { + // TODO Auto-generated catch block + e.printStackTrace(); + return false; } } - - public static String getHexString(byte[] b) { - String result = ""; - StringBuffer sb = new StringBuffer(); - for (byte tmp : b) { - sb.append(Integer.toHexString((int) (tmp & 0xff))); - } - return sb.toString(); -// for (int i=0; i < b.length; i++) { -// result += -// Integer.toString( ( b[i] & 0xff ) + 0x100, 16).substring( 1 ); -// } -// return result; - } private JSONObject sendAToSRPServer(String server_url, String username, String clientA) throws ClientProtocolException, IOException, JSONException { - DefaultHttpClient client = new LeapHttpClient(getApplicationContext()); + DefaultHttpClient client = LeapHttpClient.getInstance(getApplicationContext()); String parameter_chain = "A" + "=" + clientA + "&" + "login" + "=" + username; HttpPost post = new HttpPost(server_url + "/sessions.json" + "?" + parameter_chain); @@ -185,31 +184,14 @@ public class ProviderAPI extends IntentService { return json_response; } - private byte[] sendAToSRPServer(String server_url, String username, byte[] clientA) throws ClientProtocolException, IOException, JSONException { - DefaultHttpClient client = new LeapHttpClient(getApplicationContext()); - String parameter_chain = "A" + "=" + getHexString(clientA) + "&" + "login" + "=" + username; - HttpPost post = new HttpPost(server_url + "/sessions.json" + "?" + parameter_chain); - - HttpResponse getResponse = client.execute(post); - 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("errors") || json_response.has("errors")) { - return new byte[0]; - } - List cookies = client.getCookieStore().getCookies(); - if(!cookies.isEmpty()) { - String session_id = cookies.get(0).getValue(); - } - return json_response.getString("B").getBytes(); - } - private byte[] sendM1ToSRPServer(String server_url, String username, byte[] m1) throws ClientProtocolException, IOException, JSONException { - DefaultHttpClient client = new LeapHttpClient(getApplicationContext()); - String parameter_chain = "client_auth" + "=" + getHexString(m1); + DefaultHttpClient client = LeapHttpClient.getInstance(getApplicationContext()); + String parameter_chain = "client_auth" + "=" + new BigInteger(m1).toString(16); HttpPut put = new HttpPut(server_url + "/sessions/" + username +".json" + "?" + parameter_chain); + HttpContext localContext = new BasicHttpContext(); + localContext.setAttribute(ClientContext.COOKIE_STORE, client.getCookieStore()); - HttpResponse getResponse = client.execute(put); + HttpResponse getResponse = client.execute(put, localContext); HttpEntity responseEntity = getResponse.getEntity(); String plain_response = new Scanner(responseEntity.getContent()).useDelimiter("\\A").next(); JSONObject json_response = new JSONObject(plain_response); @@ -217,9 +199,6 @@ public class ProviderAPI extends IntentService { return new byte[0]; } - List cookies = client.getCookieStore().getCookies(); - String session_id = cookies.get(0).getValue(); - return json_response.getString("M2").getBytes(); } @@ -231,7 +210,7 @@ public class ProviderAPI extends IntentService { String json_file_content = ""; - DefaultHttpClient client = new LeapHttpClient(getApplicationContext()); + DefaultHttpClient client = LeapHttpClient.getInstance(getApplicationContext()); HttpGet get = new HttpGet(string_url); // Execute the GET call and obtain the response HttpResponse getResponse = client.execute(get); -- cgit v1.2.3 From bfee299e998143c801b231060fd5fdb5eb7204b2 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Parm=C3=A9nides=20GV?= Date: Mon, 8 Apr 2013 17:12:23 +0200 Subject: Xor method fixed. I use BigInteger Java one. Next step: understand why SHA-256 digest from NG_1024 is not equals to the one leap_web is calculating. --- src/se/leap/leapclient/ConfigHelper.java | 2 +- src/se/leap/leapclient/LeapSRPSession.java | 126 +++++++++++++++++++++-------- 2 files changed, 94 insertions(+), 34 deletions(-) (limited to 'src/se/leap/leapclient') diff --git a/src/se/leap/leapclient/ConfigHelper.java b/src/se/leap/leapclient/ConfigHelper.java index b263c532..52365762 100644 --- a/src/se/leap/leapclient/ConfigHelper.java +++ b/src/se/leap/leapclient/ConfigHelper.java @@ -36,7 +36,7 @@ public class ConfigHelper { final public static String password_key = "password"; final public static String eip_service_api_path = "/config/eip-service.json"; - final public static String NG_1024 = + final public static String NG_1024 = "eeaf0ab9adb38dd69c33f80afa8fc5e86072618775ff3c0b9ea2314c9c256576d674df7496ea81d3383b4813d692c6e0e0d5d8e250b98be48e495c1d6089dad15dc7d7b46154d6b6ce8ef4ad69b15d4982559b297bcf1885c529f566660e57ec68edbc3c05726cc02fd4cbf4976eaa9afd5138fe8376435b9fc61d2fc0eb06e3"; final public static BigInteger g = BigInteger.valueOf(2); diff --git a/src/se/leap/leapclient/LeapSRPSession.java b/src/se/leap/leapclient/LeapSRPSession.java index 1d1f0c9d..f81e1637 100644 --- a/src/se/leap/leapclient/LeapSRPSession.java +++ b/src/se/leap/leapclient/LeapSRPSession.java @@ -1,5 +1,6 @@ package se.leap.leapclient; +import java.io.UnsupportedEncodingException; import java.math.BigInteger; import java.security.MessageDigest; import java.security.NoSuchAlgorithmException; @@ -61,33 +62,36 @@ public class LeapSRPSession { this.params = params; this.g = new BigInteger(1, params.g); this.N = new BigInteger(1, params.N); - if( abytes != null ) - { + 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); + */ + this.a = new BigInteger(abytes); } // Calculate x = H(s | H(U | ':' | password)) - byte[] xb = Util.calculatePasswordHash(username, password, params.s); + byte[] xb = calculatePasswordHash(username, password, params.s); this.x = new BigInteger(1, xb); - this.v = g.modPow(x, N); // g^x % N - serverHash = Util.newDigest(); - clientHash = Util.newDigest(); + // Calculate v = kg^x mod N + BigInteger k = new BigInteger("bf66c44a428916cad64aa7c679f3fd897ad4c375e9bbb4cbf2f5de241d618ef0", 16); + this.v = k.multiply(g.modPow(x, N)); // g^x % N + + serverHash = newDigest(); + clientHash = newDigest(); + // H(N) - byte[] hn = Util.newDigest().digest(params.N); + byte[] hn = newDigest().digest(params.N); // H(g) - byte[] hg = Util.newDigest().digest(params.g); + byte[] hg = newDigest().digest(params.g); // clientHash = H(N) xor H(g) - byte[] hxg = Util.xor(hn, hg, 20); + byte[] hxg = xor(hn, hg, hg.length); clientHash.update(hxg); // clientHash = H(N) xor H(g) | H(U) - clientHash.update(Util.newDigest().digest(username.getBytes())); + clientHash.update(newDigest().digest(username.getBytes())); // clientHash = H(N) xor H(g) | H(U) | s clientHash.update(params.s); K = null; @@ -96,23 +100,20 @@ public class LeapSRPSession { /** * @returns The exponential residue (parameter A) to be sent to the server. */ - public byte[] exponential() - { + public byte[] exponential() { byte[] Abytes = null; - if(A == null) - { + if(A == null) { /* If the random component of A has not been specified use a random number */ - if( a == null ) - { + if( a == null ) { BigInteger one = BigInteger.ONE; - do - { + do { a = new BigInteger(A_LEN, Util.getPRNG()); } while(a.compareTo(one) <= 0); } A = g.modPow(a, N); - Abytes = Util.trim(A.toByteArray()); + //Abytes = Util.trim(A.toByteArray()); + Abytes = A.toByteArray(); // clientHash = H(N) xor H(g) | H(U) | A clientHash.update(Abytes); // serverHash = A @@ -138,16 +139,9 @@ public class LeapSRPSession { S = B.subtract(kgx).modPow(aux, N); K = SHA256(hex2a(S.toString(16))); */ - byte[] hA = Util.newDigest().digest(A.toByteArray()); - MessageDigest u_digest = Util.newDigest(); - u_digest.update(A.toByteArray()); - u_digest.update(Bbytes); - clientHash.update(u_digest.digest()); - byte[] ub = new BigInteger(clientHash.digest()).toByteArray(); - // Calculate S = (B - g^x) ^ (a + u * x) % N + byte[] ub = getU(A.toByteArray(), Bbytes); + // Calculate S = (B - kg^x) ^ (a + u * x) % N BigInteger B = new BigInteger(1, Bbytes); - if( B.compareTo(v) < 0 ) - B = B.add(N); BigInteger u = new BigInteger(1, ub); BigInteger B_v = B.subtract(v); BigInteger a_ux = a.add(u.multiply(x)); @@ -160,9 +154,16 @@ public class LeapSRPSession { byte[] M1 = clientHash.digest(); return M1; } - - - /** + + + public byte[] getU(byte[] Abytes, byte[] Bbytes) { + MessageDigest u_digest = Util.newDigest(); + u_digest.update(Abytes); + u_digest.update(Bbytes); + return new BigInteger(1, u_digest.digest()).toByteArray(); + } + + /** * @param M2 The server's response to the client's challenge * @returns True if and only if the server's response was correct. */ @@ -190,4 +191,63 @@ public class LeapSRPSession { return K; } + public MessageDigest newDigest() + { + MessageDigest md = null; + try { + md = MessageDigest.getInstance("SHA256"); + } catch (NoSuchAlgorithmException e) { + e.printStackTrace(); + } + return md; + } + + public byte[] calculatePasswordHash(String username, char[] password, + byte[] salt) + { + // Calculate x = H(s | H(U | ':' | password)) + MessageDigest xd = newDigest(); + // Try to convert the username to a byte[] using UTF-8 + byte[] user = null; + byte[] colon = {}; + try { + user = username.getBytes("UTF-8"); + colon = ":".getBytes("UTF-8"); + } + catch(UnsupportedEncodingException e) { + // Use the default platform encoding + user = username.getBytes(); + colon = ":".getBytes(); + } + byte[] passBytes = new byte[2*password.length]; + int passBytesLength = 0; + for(int p = 0; p < password.length; p ++) { + int c = (password[p] & 0x00FFFF); + // The low byte of the char + byte b0 = (byte) (c & 0x0000FF); + // The high byte of the char + byte b1 = (byte) ((c & 0x00FF00) >> 8); + passBytes[passBytesLength ++] = b0; + // Only encode the high byte if c is a multi-byte char + if( c > 255 ) + passBytes[passBytesLength ++] = b1; + } + + // Build the hash + xd.update(user); + xd.update(colon); + xd.update(passBytes, 0, passBytesLength); + byte[] h = xd.digest(); + xd.reset(); + xd.update(salt); + xd.update(h); + byte[] xb = xd.digest(); + return xb; + } + + public byte[] xor(byte[] b1, byte[] b2, int length) + { + //TODO Check if length matters in the order, when b2 is smaller than b1 or viceversa + return new BigInteger(b1).xor(new BigInteger(b2)).toByteArray(); + } } -- cgit v1.2.3 From 47e489f521c1f69c357880234a8aa8b5408595aa Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Parm=C3=A9nides=20GV?= Date: Mon, 8 Apr 2013 20:48:17 +0200 Subject: Done constructor of LeapSRPSession: it's OK. Next step: fix response() calculations. --- src/se/leap/leapclient/LeapSRPSession.java | 16 +++++++++------- 1 file changed, 9 insertions(+), 7 deletions(-) (limited to 'src/se/leap/leapclient') diff --git a/src/se/leap/leapclient/LeapSRPSession.java b/src/se/leap/leapclient/LeapSRPSession.java index f81e1637..e5860dd8 100644 --- a/src/se/leap/leapclient/LeapSRPSession.java +++ b/src/se/leap/leapclient/LeapSRPSession.java @@ -61,7 +61,8 @@ public class LeapSRPSession { } this.params = params; this.g = new BigInteger(1, params.g); - this.N = new BigInteger(1, params.N); + byte[] N_trimmed = Util.trim(params.N); + this.N = new BigInteger(1, N_trimmed); if( abytes != null ) { A_LEN = 8*abytes.length; /* TODO Why did they put this condition? @@ -84,14 +85,15 @@ public class LeapSRPSession { clientHash = newDigest(); // H(N) - byte[] hn = newDigest().digest(params.N); + byte[] hn = newDigest().digest(N_trimmed); // H(g) byte[] hg = newDigest().digest(params.g); // clientHash = H(N) xor H(g) byte[] hxg = xor(hn, hg, hg.length); clientHash.update(hxg); // clientHash = H(N) xor H(g) | H(U) - clientHash.update(newDigest().digest(username.getBytes())); + byte[] username_digest = newDigest().digest(username.getBytes()); + clientHash.update(username_digest); // clientHash = H(N) xor H(g) | H(U) | s clientHash.update(params.s); K = null; @@ -124,7 +126,7 @@ public class LeapSRPSession { public byte[] response(byte[] Bbytes) throws NoSuchAlgorithmException { // clientHash = H(N) xor H(g) | H(U) | s | A | B - clientHash.update(Bbytes); + clientHash.update(Util.trim(Bbytes)); /* var B = new BigInteger(ephemeral, 16); @@ -157,7 +159,7 @@ public class LeapSRPSession { public byte[] getU(byte[] Abytes, byte[] Bbytes) { - MessageDigest u_digest = Util.newDigest(); + MessageDigest u_digest = newDigest(); u_digest.update(Abytes); u_digest.update(Bbytes); return new BigInteger(1, u_digest.digest()).toByteArray(); @@ -195,7 +197,7 @@ public class LeapSRPSession { { MessageDigest md = null; try { - md = MessageDigest.getInstance("SHA256"); + md = MessageDigest.getInstance("SHA-256"); } catch (NoSuchAlgorithmException e) { e.printStackTrace(); } @@ -248,6 +250,6 @@ public class LeapSRPSession { public byte[] xor(byte[] b1, byte[] b2, int length) { //TODO Check if length matters in the order, when b2 is smaller than b1 or viceversa - return new BigInteger(b1).xor(new BigInteger(b2)).toByteArray(); + return new BigInteger(1, b1).xor(new BigInteger(1, b2)).toByteArray(); } } -- cgit v1.2.3 From 1026d9779ff1cdca200cf60ad0de1292475d16f7 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Parm=C3=A9nides=20GV?= Date: Tue, 9 Apr 2013 19:21:16 +0200 Subject: Response should be correct, as far as different calculations individually are. But in reality it's not. Tried to fix final hash putting a trim in every byte array, but it did not work. Next step: check the final hash, looking for padding issues. --- src/se/leap/leapclient/LeapSRPSession.java | 435 +++++++++++++++-------------- 1 file changed, 219 insertions(+), 216 deletions(-) (limited to 'src/se/leap/leapclient') diff --git a/src/se/leap/leapclient/LeapSRPSession.java b/src/se/leap/leapclient/LeapSRPSession.java index e5860dd8..3dacce9c 100644 --- a/src/se/leap/leapclient/LeapSRPSession.java +++ b/src/se/leap/leapclient/LeapSRPSession.java @@ -12,244 +12,247 @@ import org.jboss.security.srp.SRPParameters; import org.jboss.security.srp.SRPPermission; public class LeapSRPSession { - + private SRPParameters params; - private BigInteger N; - private BigInteger g; - private BigInteger x; - private BigInteger v; - private byte[] s; - private BigInteger a; - private BigInteger A; - private byte[] K; - /** 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 + private BigInteger N; + private BigInteger g; + private BigInteger x; + private BigInteger v; + private byte[] s; + private BigInteger a; + private BigInteger A; + private byte[] K; + /** 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, char[] password, SRPParameters params) - { - this(username, password, params, null); - } + */ + public LeapSRPSession(String username, char[] password, SRPParameters params) + { + this(username, password, params, null); + } - /** Creates a new SRP server session object from the username, password + /** 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. This must be 8 bytes in length. - */ - public LeapSRPSession(String username, char[] password, SRPParameters params, - byte[] abytes) - { - try - { - // Initialize the secure random number and message digests - Util.init(); - } - catch(NoSuchAlgorithmException e) - { - } - this.params = params; - this.g = new BigInteger(1, params.g); - byte[] N_trimmed = Util.trim(params.N); - this.N = new BigInteger(1, N_trimmed); - if( abytes != null ) { - A_LEN = 8*abytes.length; - /* TODO Why did they put this condition? + */ + public LeapSRPSession(String username, char[] password, SRPParameters params, + byte[] abytes) + { + try + { + // Initialize the secure random number and message digests + Util.init(); + } + catch(NoSuchAlgorithmException e) + { + } + this.params = params; + this.g = new BigInteger(1, params.g); + byte[] N_bytes = Util.trim(params.N); + this.N = new BigInteger(1, N_bytes); + 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); - } - - // Calculate x = H(s | H(U | ':' | password)) - byte[] xb = calculatePasswordHash(username, password, params.s); - this.x = new BigInteger(1, xb); - - // Calculate v = kg^x mod N - BigInteger k = new BigInteger("bf66c44a428916cad64aa7c679f3fd897ad4c375e9bbb4cbf2f5de241d618ef0", 16); - this.v = k.multiply(g.modPow(x, N)); // g^x % N - - serverHash = newDigest(); - clientHash = newDigest(); - - // H(N) - byte[] hn = newDigest().digest(N_trimmed); - // H(g) - byte[] hg = newDigest().digest(params.g); - // clientHash = H(N) xor H(g) - byte[] hxg = xor(hn, hg, hg.length); - clientHash.update(hxg); - // clientHash = H(N) xor H(g) | H(U) - byte[] username_digest = newDigest().digest(username.getBytes()); - clientHash.update(username_digest); - // clientHash = H(N) xor H(g) | H(U) | s - clientHash.update(params.s); - K = null; - } - - /** - * @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, Util.getPRNG()); - } while(a.compareTo(one) <= 0); - } - A = g.modPow(a, N); - //Abytes = Util.trim(A.toByteArray()); - Abytes = A.toByteArray(); - // clientHash = H(N) xor H(g) | H(U) | A - clientHash.update(Abytes); - // serverHash = A - serverHash.update(Abytes); - } - return Abytes; - } - - public byte[] response(byte[] Bbytes) throws NoSuchAlgorithmException { - // clientHash = H(N) xor H(g) | H(U) | s | A | B - clientHash.update(Util.trim(Bbytes)); - - /* - var B = new BigInteger(ephemeral, 16); - var Bstr = ephemeral; - // u = H(A,B) - var u = new BigInteger(SHA256(hex2a(Astr + Bstr)), 16); - // x = H(s, H(I:p)) - var x = this.calcX(salt); - //S = (B - kg^x) ^ (a + ux) - var kgx = k.multiply(g.modPow(x, N)); - var aux = a.add(u.multiply(x)); - S = B.subtract(kgx).modPow(aux, N); - K = SHA256(hex2a(S.toString(16))); - */ - byte[] ub = getU(A.toByteArray(), Bbytes); - // Calculate S = (B - kg^x) ^ (a + u * x) % N - BigInteger B = new BigInteger(1, Bbytes); - BigInteger u = new BigInteger(1, ub); - BigInteger B_v = B.subtract(v); - BigInteger a_ux = a.add(u.multiply(x)); - BigInteger S = B_v.modPow(a_ux, N); - // K = SessionHash(S) - MessageDigest sessionDigest = MessageDigest.getInstance(params.hashAlgorithm); - K = sessionDigest.digest(S.toByteArray()); - // clientHash = H(N) xor H(g) | H(U) | A | B | K - clientHash.update(K); - byte[] M1 = clientHash.digest(); - return M1; + */ + this.a = new BigInteger(abytes); } + // Calculate x = H(s | H(U | ':' | password)) + byte[] xb = calculatePasswordHash(username, password, params.s); + //xb = Util.trim(xb); + this.x = new BigInteger(1, xb); + + // Calculate v = kg^x mod N + this.v = calculateV(); - public byte[] getU(byte[] Abytes, byte[] Bbytes) { - MessageDigest u_digest = newDigest(); - u_digest.update(Abytes); - u_digest.update(Bbytes); - return new BigInteger(1, u_digest.digest()).toByteArray(); + serverHash = newDigest(); + clientHash = newDigest(); + + // H(N) + byte[] hn = newDigest().digest(N_bytes); + // H(g) + byte[] hg = newDigest().digest(params.g); + // clientHash = H(N) xor H(g) + byte[] hxg = xor(hn, hg, hg.length); + //hxg = Util.trim(hxg); + clientHash.update(hxg); + // clientHash = H(N) xor H(g) | H(U) + byte[] username_bytes = username.getBytes(); + byte[] username_digest = newDigest().digest(username_bytes); + clientHash.update(username_digest); + // clientHash = H(N) xor H(g) | H(U) | s + byte[] salt_bytes = params.s; + clientHash.update(salt_bytes); + K = null; + } + + private BigInteger calculateV() { + BigInteger k = new BigInteger("bf66c44a428916cad64aa7c679f3fd897ad4c375e9bbb4cbf2f5de241d618ef0", 16); + return k.multiply(g.modPow(x, N)); // g^x % N + } + + /** + * @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, Util.getPRNG()); + } while(a.compareTo(one) <= 0); + } + A = g.modPow(a, N); + Abytes = A.toByteArray(); + //Abytes = Util.trim(Abytes); + // clientHash = H(N) xor H(g) | H(U) | A + clientHash.update(Abytes); + // serverHash = A + serverHash.update(Abytes); } + return Abytes; + } + + public byte[] response(byte[] Bbytes) throws NoSuchAlgorithmException { + // clientHash = H(N) xor H(g) | H(U) | s | A | B + //Bbytes = Util.trim(Bbytes); + clientHash.update(Bbytes); + // Calculate S = (B - kg^x) ^ (a + u * x) % N + BigInteger S = calculateS(Bbytes); + byte[] S_bytes = S.toByteArray(); + //S_bytes = Util.trim(S_bytes); + // K = SessionHash(S) + String hash_algorithm = params.hashAlgorithm; + MessageDigest sessionDigest = MessageDigest.getInstance(hash_algorithm); + K = sessionDigest.digest(S_bytes); + // clientHash = H(N) xor H(g) | H(U) | A | B | K + clientHash.update(K); + byte[] M1 = clientHash.digest(); + return M1; + } + + + private BigInteger calculateS(byte[] Bbytes) { + byte[] ub = getU(A.toByteArray(), Bbytes); + BigInteger B = new BigInteger(1, Bbytes); + BigInteger u = new BigInteger(1, ub); + BigInteger B_v = B.subtract(v); + BigInteger a_ux = a.add(u.multiply(x)); + BigInteger S = B_v.modPow(a_ux, N); + + return S; + } + + public byte[] getU(byte[] Abytes, byte[] Bbytes) { + MessageDigest u_digest = newDigest(); + u_digest.update(Util.trim(Abytes)); + u_digest.update(Util.trim(Bbytes)); + return new BigInteger(1, u_digest.digest()).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) - byte[] myM2 = serverHash.digest(); - boolean valid = Arrays.equals(M2, myM2); - return valid; - } - - /** Returns the negotiated session K, K = SHA_Interleave(S) + * @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) + byte[] myM2 = serverHash.digest(); + boolean valid = Arrays.equals(M2, myM2); + return valid; + } + + /** Returns the negotiated session K, K = SHA_Interleave(S) @return the private session K byte[] @throws SecurityException - if the current thread does not have an getSessionKey SRPPermission. - */ - public byte[] getSessionKey() throws SecurityException - { - SecurityManager sm = System.getSecurityManager(); - if( sm != null ) - { - SRPPermission p = new SRPPermission("getSessionKey"); - sm.checkPermission(p); - } - return K; - } - - public MessageDigest newDigest() - { - MessageDigest md = null; - try { - md = MessageDigest.getInstance("SHA-256"); - } catch (NoSuchAlgorithmException e) { - e.printStackTrace(); - } - return md; - } - - public byte[] calculatePasswordHash(String username, char[] password, - byte[] salt) - { - // Calculate x = H(s | H(U | ':' | password)) - MessageDigest xd = newDigest(); - // Try to convert the username to a byte[] using UTF-8 - byte[] user = null; - byte[] colon = {}; - try { - user = username.getBytes("UTF-8"); - colon = ":".getBytes("UTF-8"); - } - catch(UnsupportedEncodingException e) { - // Use the default platform encoding - user = username.getBytes(); - colon = ":".getBytes(); - } - byte[] passBytes = new byte[2*password.length]; - int passBytesLength = 0; - for(int p = 0; p < password.length; p ++) { - int c = (password[p] & 0x00FFFF); - // The low byte of the char - byte b0 = (byte) (c & 0x0000FF); - // The high byte of the char - byte b1 = (byte) ((c & 0x00FF00) >> 8); - passBytes[passBytesLength ++] = b0; - // Only encode the high byte if c is a multi-byte char - if( c > 255 ) - passBytes[passBytesLength ++] = b1; - } - - // Build the hash - xd.update(user); - xd.update(colon); - xd.update(passBytes, 0, passBytesLength); - byte[] h = xd.digest(); - xd.reset(); - xd.update(salt); - xd.update(h); - byte[] xb = xd.digest(); - return xb; - } - - public byte[] xor(byte[] b1, byte[] b2, int length) - { - //TODO Check if length matters in the order, when b2 is smaller than b1 or viceversa - return new BigInteger(1, b1).xor(new BigInteger(1, b2)).toByteArray(); - } + */ + public byte[] getSessionKey() throws SecurityException + { + SecurityManager sm = System.getSecurityManager(); + if( sm != null ) + { + SRPPermission p = new SRPPermission("getSessionKey"); + sm.checkPermission(p); + } + return K; + } + + public MessageDigest newDigest() + { + MessageDigest md = null; + try { + md = MessageDigest.getInstance("SHA-256"); + } catch (NoSuchAlgorithmException e) { + e.printStackTrace(); + } + return md; + } + + public byte[] calculatePasswordHash(String username, char[] password, byte[] salt) + { + // Calculate x = H(s | H(U | ':' | password)) + MessageDigest xd = newDigest(); + // Try to convert the username to a byte[] using UTF-8 + byte[] user = null; + byte[] colon = {}; + try { + user = username.getBytes("UTF-8"); + colon = ":".getBytes("UTF-8"); + } + catch(UnsupportedEncodingException e) { + // Use the default platform encoding + user = username.getBytes(); + colon = ":".getBytes(); + } + byte[] passBytes = new byte[2*password.length]; + int passBytesLength = 0; + for(int p = 0; p < password.length; p ++) { + int c = (password[p] & 0x00FFFF); + // The low byte of the char + byte b0 = (byte) (c & 0x0000FF); + // The high byte of the char + byte b1 = (byte) ((c & 0x00FF00) >> 8); + passBytes[passBytesLength ++] = b0; + // Only encode the high byte if c is a multi-byte char + if( c > 255 ) + passBytes[passBytesLength ++] = b1; + } + + // Build the hash + xd.update(user); + xd.update(colon); + xd.update(passBytes, 0, passBytesLength); + byte[] h = xd.digest(); + xd.reset(); + xd.update(salt); + xd.update(h); + byte[] xb = xd.digest(); + return xb; + } + + public byte[] xor(byte[] b1, byte[] b2, int length) + { + //TODO Check if length matters in the order, when b2 is smaller than b1 or viceversa + return new BigInteger(1, b1).xor(new BigInteger(1, b2)).toByteArray(); + } } -- cgit v1.2.3 From 90ff9cc39faeb5a85ce56175dd64eaec6e4004c7 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Parm=C3=A9nides=20GV?= Date: Wed, 10 Apr 2013 18:24:50 +0200 Subject: LeapSRPSession response() method is working for the three different tests I've written for it. Next step: verify() --- src/se/leap/leapclient/LeapSRPSession.java | 27 ++++++++++++++++++--------- 1 file changed, 18 insertions(+), 9 deletions(-) (limited to 'src/se/leap/leapclient') diff --git a/src/se/leap/leapclient/LeapSRPSession.java b/src/se/leap/leapclient/LeapSRPSession.java index 3dacce9c..c0d2d0f9 100644 --- a/src/se/leap/leapclient/LeapSRPSession.java +++ b/src/se/leap/leapclient/LeapSRPSession.java @@ -90,15 +90,18 @@ public class LeapSRPSession { byte[] hg = newDigest().digest(params.g); // clientHash = H(N) xor H(g) byte[] hxg = xor(hn, hg, hg.length); - //hxg = Util.trim(hxg); - clientHash.update(hxg); + String hxg_string = new BigInteger(1, hxg).toString(16); + hxg = Util.trim(hxg); + clientHash.update(hxg); // OK // clientHash = H(N) xor H(g) | H(U) byte[] username_bytes = username.getBytes(); byte[] username_digest = newDigest().digest(username_bytes); - clientHash.update(username_digest); + String username_digest_string = new BigInteger(1, username_digest).toString(16); + clientHash.update(username_digest); // OK // clientHash = H(N) xor H(g) | H(U) | s byte[] salt_bytes = params.s; - clientHash.update(salt_bytes); + String salt_string = new BigInteger(1, salt_bytes).toString(16); + clientHash.update(salt_bytes); // OK K = null; } @@ -123,9 +126,10 @@ public class LeapSRPSession { } A = g.modPow(a, N); Abytes = A.toByteArray(); - //Abytes = Util.trim(Abytes); + String Abytes_string = new BigInteger(1, Abytes).toString(16); + Abytes = Util.trim(Abytes); // clientHash = H(N) xor H(g) | H(U) | A - clientHash.update(Abytes); + clientHash.update(Abytes); // Begins with 0: second case // serverHash = A serverHash.update(Abytes); } @@ -134,16 +138,21 @@ public class LeapSRPSession { public byte[] response(byte[] Bbytes) throws NoSuchAlgorithmException { // clientHash = H(N) xor H(g) | H(U) | s | A | B - //Bbytes = Util.trim(Bbytes); - clientHash.update(Bbytes); + Bbytes = Util.trim(Bbytes); // Begins with 0: first case, second case + String Abytes_string = new BigInteger(1, Bbytes).toString(16); + clientHash.update(Bbytes); // OK // Calculate S = (B - kg^x) ^ (a + u * x) % N BigInteger S = calculateS(Bbytes); byte[] S_bytes = S.toByteArray(); - //S_bytes = Util.trim(S_bytes); + S_bytes = Util.trim(S_bytes); // Begins with 0: first case + String S_bytes_string = new BigInteger(1, S_bytes).toString(16); // K = SessionHash(S) String hash_algorithm = params.hashAlgorithm; MessageDigest sessionDigest = MessageDigest.getInstance(hash_algorithm); K = sessionDigest.digest(S_bytes); + //K = Util.trim(K); + String K_bytes_string = new BigInteger(1, K).toString(16); + // clientHash = H(N) xor H(g) | H(U) | A | B | K clientHash.update(K); byte[] M1 = clientHash.digest(); -- cgit v1.2.3 From 3140e730378a0a506224d8cb8e1678647238a425 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Parm=C3=A9nides=20GV?= Date: Wed, 10 Apr 2013 21:43:56 +0200 Subject: Some more trims added. It passes a lot of tests from the test project (not included here, still to decide if push it publicly). Next steps: make code beautiful, Android GUI SRP and real communication server, and add even more tests (in my spare time, just to check with more users). --- src/se/leap/leapclient/LeapSRPSession.java | 30 +++++++++++++++++++++++------- 1 file changed, 23 insertions(+), 7 deletions(-) (limited to 'src/se/leap/leapclient') diff --git a/src/se/leap/leapclient/LeapSRPSession.java b/src/se/leap/leapclient/LeapSRPSession.java index c0d2d0f9..cecceed6 100644 --- a/src/se/leap/leapclient/LeapSRPSession.java +++ b/src/se/leap/leapclient/LeapSRPSession.java @@ -63,6 +63,7 @@ public class LeapSRPSession { this.g = new BigInteger(1, params.g); byte[] N_bytes = Util.trim(params.N); this.N = new BigInteger(1, N_bytes); + if( abytes != null ) { A_LEN = 8*abytes.length; /* TODO Why did they put this condition? @@ -74,12 +75,15 @@ public class LeapSRPSession { } // Calculate x = H(s | H(U | ':' | password)) - byte[] xb = calculatePasswordHash(username, password, params.s); - //xb = Util.trim(xb); + byte[] salt_bytes = params.s; + salt_bytes = Util.trim(salt_bytes); + byte[] xb = calculatePasswordHash(username, password, salt_bytes); + xb = Util.trim(xb); this.x = new BigInteger(1, xb); // Calculate v = kg^x mod N this.v = calculateV(); + String v_string = v.toString(16); serverHash = newDigest(); clientHash = newDigest(); @@ -95,11 +99,12 @@ public class LeapSRPSession { clientHash.update(hxg); // OK // clientHash = H(N) xor H(g) | H(U) byte[] username_bytes = username.getBytes(); + username_bytes = Util.trim(username_bytes); byte[] username_digest = newDigest().digest(username_bytes); + username_digest = Util.trim(username_digest); String username_digest_string = new BigInteger(1, username_digest).toString(16); clientHash.update(username_digest); // OK // clientHash = H(N) xor H(g) | H(U) | s - byte[] salt_bytes = params.s; String salt_string = new BigInteger(1, salt_bytes).toString(16); clientHash.update(salt_bytes); // OK K = null; @@ -139,7 +144,7 @@ public class LeapSRPSession { public byte[] response(byte[] Bbytes) throws NoSuchAlgorithmException { // clientHash = H(N) xor H(g) | H(U) | s | A | B Bbytes = Util.trim(Bbytes); // Begins with 0: first case, second case - String Abytes_string = new BigInteger(1, Bbytes).toString(16); + String Bbytes_string = new BigInteger(1, Bbytes).toString(16); clientHash.update(Bbytes); // OK // Calculate S = (B - kg^x) ^ (a + u * x) % N BigInteger S = calculateS(Bbytes); @@ -156,16 +161,24 @@ public class LeapSRPSession { // clientHash = H(N) xor H(g) | H(U) | A | B | K clientHash.update(K); byte[] M1 = clientHash.digest(); + // serverHash = Astr + M + K + serverHash.update(M1); + serverHash.update(K); return M1; } private BigInteger calculateS(byte[] Bbytes) { - byte[] ub = getU(A.toByteArray(), Bbytes); + byte[] Abytes = Util.trim(A.toByteArray()); + byte[] ub = getU(Abytes, Bbytes); + //ub = Util.trim(ub); + BigInteger B = new BigInteger(1, Bbytes); BigInteger u = new BigInteger(1, ub); + String u_string = u.toString(16); BigInteger B_v = B.subtract(v); BigInteger a_ux = a.add(u.multiply(x)); + String a_ux_string = a_ux.toString(16); BigInteger S = B_v.modPow(a_ux, N); return S; @@ -173,8 +186,8 @@ public class LeapSRPSession { public byte[] getU(byte[] Abytes, byte[] Bbytes) { MessageDigest u_digest = newDigest(); - u_digest.update(Util.trim(Abytes)); - u_digest.update(Util.trim(Bbytes)); + u_digest.update(Abytes); + u_digest.update(Bbytes); return new BigInteger(1, u_digest.digest()).toByteArray(); } @@ -233,6 +246,8 @@ public class LeapSRPSession { user = username.getBytes(); colon = ":".getBytes(); } + user = Util.trim(user); + colon = Util.trim(colon); byte[] passBytes = new byte[2*password.length]; int passBytesLength = 0; for(int p = 0; p < password.length; p ++) { @@ -252,6 +267,7 @@ public class LeapSRPSession { xd.update(colon); xd.update(passBytes, 0, passBytesLength); byte[] h = xd.digest(); + //h = Util.trim(h); xd.reset(); xd.update(salt); xd.update(h); -- cgit v1.2.3 From 60e5f181c1a9f4f1851aafd059971ba5d05748f3 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Parm=C3=A9nides=20GV?= Date: Thu, 11 Apr 2013 18:15:19 +0200 Subject: Made LeapSRPSession more beautiful, put javadoc and commented lines of strings used to check everything's fine manually. --- src/se/leap/leapclient/LeapSRPSession.java | 236 ++++++++++++++++------------- 1 file changed, 134 insertions(+), 102 deletions(-) (limited to 'src/se/leap/leapclient') diff --git a/src/se/leap/leapclient/LeapSRPSession.java b/src/se/leap/leapclient/LeapSRPSession.java index cecceed6..abdf6b2c 100644 --- a/src/se/leap/leapclient/LeapSRPSession.java +++ b/src/se/leap/leapclient/LeapSRPSession.java @@ -18,7 +18,6 @@ public class LeapSRPSession { private BigInteger g; private BigInteger x; private BigInteger v; - private byte[] s; private BigInteger a; private BigInteger A; private byte[] K; @@ -49,16 +48,14 @@ public class LeapSRPSession { 8 bytes in length. */ public LeapSRPSession(String username, char[] password, SRPParameters params, - byte[] abytes) - { - try - { + byte[] abytes) { + try { // Initialize the secure random number and message digests Util.init(); } - catch(NoSuchAlgorithmException e) - { + catch(NoSuchAlgorithmException e) { } + this.params = params; this.g = new BigInteger(1, params.g); byte[] N_bytes = Util.trim(params.N); @@ -75,46 +72,113 @@ public class LeapSRPSession { } // Calculate x = H(s | H(U | ':' | password)) - byte[] salt_bytes = params.s; - salt_bytes = Util.trim(salt_bytes); + byte[] salt_bytes = Util.trim(params.s); byte[] xb = calculatePasswordHash(username, password, salt_bytes); - xb = Util.trim(xb); this.x = new BigInteger(1, xb); // Calculate v = kg^x mod N - this.v = calculateV(); - String v_string = v.toString(16); + String k_string = "bf66c44a428916cad64aa7c679f3fd897ad4c375e9bbb4cbf2f5de241d618ef0"; + this.v = calculateV(k_string); + //String v_string = v.toString(16); serverHash = newDigest(); clientHash = newDigest(); // H(N) - byte[] hn = newDigest().digest(N_bytes); + byte[] digest_of_n = newDigest().digest(N_bytes); + // H(g) - byte[] hg = newDigest().digest(params.g); + byte[] digest_of_g = newDigest().digest(params.g); + // clientHash = H(N) xor H(g) - byte[] hxg = xor(hn, hg, hg.length); - String hxg_string = new BigInteger(1, hxg).toString(16); - hxg = Util.trim(hxg); - clientHash.update(hxg); // OK + byte[] xor_digest = xor(digest_of_n, digest_of_g, digest_of_g.length); + //String hxg_string = new BigInteger(1, xor_digest).toString(16); + clientHash.update(xor_digest); + // clientHash = H(N) xor H(g) | H(U) - byte[] username_bytes = username.getBytes(); - username_bytes = Util.trim(username_bytes); - byte[] username_digest = newDigest().digest(username_bytes); + byte[] username_digest = newDigest().digest(Util.trim(username.getBytes())); username_digest = Util.trim(username_digest); - String username_digest_string = new BigInteger(1, username_digest).toString(16); - clientHash.update(username_digest); // OK + //String username_digest_string = new BigInteger(1, username_digest).toString(16); + clientHash.update(username_digest); + // clientHash = H(N) xor H(g) | H(U) | s - String salt_string = new BigInteger(1, salt_bytes).toString(16); - clientHash.update(salt_bytes); // OK + //String salt_string = new BigInteger(1, salt_bytes).toString(16); + clientHash.update(salt_bytes); + K = null; } - private BigInteger calculateV() { - BigInteger k = new BigInteger("bf66c44a428916cad64aa7c679f3fd897ad4c375e9bbb4cbf2f5de241d618ef0", 16); + /** + * 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, char[] password, byte[] salt) + { + // Calculate x = H(s | H(U | ':' | password)) + MessageDigest x_digest = newDigest(); + + // Try to convert the username to a byte[] using UTF-8 + byte[] user = null; + byte[] colon = {}; + try { + user = Util.trim(username.getBytes("UTF-8")); + colon = Util.trim(":".getBytes("UTF-8")); + } + catch(UnsupportedEncodingException e) { + // Use the default platform encoding + user = Util.trim(username.getBytes()); + colon = Util.trim(":".getBytes()); + } + + byte[] passBytes = new byte[2*password.length]; + int passBytesLength = 0; + for(int p = 0; p < password.length; p++) { + int c = (password[p] & 0x00FFFF); + // The low byte of the char + byte b0 = (byte) (c & 0x0000FF); + // The high byte of the char + byte b1 = (byte) ((c & 0x00FF00) >> 8); + passBytes[passBytesLength ++] = b0; + // Only encode the high byte if c is a multi-byte char + if( c > 255 ) + passBytes[passBytesLength ++] = b1; + } + + // Build the hash + x_digest.update(user); + x_digest.update(colon); + x_digest.update(passBytes, 0, passBytesLength); + byte[] h = x_digest.digest(); + //h = Util.trim(h); + + x_digest.reset(); + x_digest.update(salt); + x_digest.update(h); + byte[] x_digest_bytes = Util.trim(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); return k.multiply(g.modPow(x, N)); // g^x % N } + public byte[] xor(byte[] b1, byte[] b2, int length) + { + //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 Util.trim(xor_digest); + } + /** * @returns The exponential residue (parameter A) to be sent to the server. */ @@ -130,60 +194,81 @@ public class LeapSRPSession { } while(a.compareTo(one) <= 0); } A = g.modPow(a, N); - Abytes = A.toByteArray(); - String Abytes_string = new BigInteger(1, Abytes).toString(16); - Abytes = Util.trim(Abytes); + Abytes = Util.trim(A.toByteArray()); + //String Abytes_string = new BigInteger(1, Abytes).toString(16); + // clientHash = H(N) xor H(g) | H(U) | A - clientHash.update(Abytes); // Begins with 0: second case + clientHash.update(Abytes); + // serverHash = A serverHash.update(Abytes); } 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. + * @param Bbytes the parameter received from the server, in bytes + * @return the parameter M1 + * @throws NoSuchAlgorithmException + */ public byte[] response(byte[] Bbytes) throws NoSuchAlgorithmException { // clientHash = H(N) xor H(g) | H(U) | s | A | B - Bbytes = Util.trim(Bbytes); // Begins with 0: first case, second case - String Bbytes_string = new BigInteger(1, Bbytes).toString(16); - clientHash.update(Bbytes); // OK + Bbytes = Util.trim(Bbytes); + //String Bbytes_string = new BigInteger(1, Bbytes).toString(16); + clientHash.update(Bbytes); + // Calculate S = (B - kg^x) ^ (a + u * x) % N BigInteger S = calculateS(Bbytes); - byte[] S_bytes = S.toByteArray(); - S_bytes = Util.trim(S_bytes); // Begins with 0: first case - String S_bytes_string = new BigInteger(1, S_bytes).toString(16); + byte[] S_bytes = Util.trim(S.toByteArray()); + //String S_bytes_string = new BigInteger(1, S_bytes).toString(16); + // K = SessionHash(S) String hash_algorithm = params.hashAlgorithm; MessageDigest sessionDigest = MessageDigest.getInstance(hash_algorithm); K = sessionDigest.digest(S_bytes); //K = Util.trim(K); - String K_bytes_string = new BigInteger(1, K).toString(16); + //String K_bytes_string = new BigInteger(1, K).toString(16); // clientHash = H(N) xor H(g) | H(U) | A | B | K clientHash.update(K); byte[] M1 = clientHash.digest(); + // serverHash = Astr + M + K 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 = Util.trim(A.toByteArray()); - byte[] ub = getU(Abytes, Bbytes); + byte[] u_bytes = getU(Abytes, Bbytes); //ub = Util.trim(ub); BigInteger B = new BigInteger(1, Bbytes); - BigInteger u = new BigInteger(1, ub); - String u_string = u.toString(16); - BigInteger B_v = B.subtract(v); + BigInteger u = new BigInteger(1, u_bytes); + //String u_string = u.toString(16); + + BigInteger B_minus_v = B.subtract(v); BigInteger a_ux = a.add(u.multiply(x)); - String a_ux_string = a_ux.toString(16); - BigInteger S = B_v.modPow(a_ux, N); + //String a_ux_string = a_ux.toString(16); + 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(Abytes); @@ -210,15 +295,13 @@ public class LeapSRPSession { */ public byte[] getSessionKey() throws SecurityException { - SecurityManager sm = System.getSecurityManager(); - if( sm != null ) - { - SRPPermission p = new SRPPermission("getSessionKey"); - sm.checkPermission(p); - } return K; } + + /** + * @return a new SHA-256 digest. + */ public MessageDigest newDigest() { MessageDigest md = null; @@ -229,55 +312,4 @@ public class LeapSRPSession { } return md; } - - public byte[] calculatePasswordHash(String username, char[] password, byte[] salt) - { - // Calculate x = H(s | H(U | ':' | password)) - MessageDigest xd = newDigest(); - // Try to convert the username to a byte[] using UTF-8 - byte[] user = null; - byte[] colon = {}; - try { - user = username.getBytes("UTF-8"); - colon = ":".getBytes("UTF-8"); - } - catch(UnsupportedEncodingException e) { - // Use the default platform encoding - user = username.getBytes(); - colon = ":".getBytes(); - } - user = Util.trim(user); - colon = Util.trim(colon); - byte[] passBytes = new byte[2*password.length]; - int passBytesLength = 0; - for(int p = 0; p < password.length; p ++) { - int c = (password[p] & 0x00FFFF); - // The low byte of the char - byte b0 = (byte) (c & 0x0000FF); - // The high byte of the char - byte b1 = (byte) ((c & 0x00FF00) >> 8); - passBytes[passBytesLength ++] = b0; - // Only encode the high byte if c is a multi-byte char - if( c > 255 ) - passBytes[passBytesLength ++] = b1; - } - - // Build the hash - xd.update(user); - xd.update(colon); - xd.update(passBytes, 0, passBytesLength); - byte[] h = xd.digest(); - //h = Util.trim(h); - xd.reset(); - xd.update(salt); - xd.update(h); - byte[] xb = xd.digest(); - return xb; - } - - public byte[] xor(byte[] b1, byte[] b2, int length) - { - //TODO Check if length matters in the order, when b2 is smaller than b1 or viceversa - return new BigInteger(1, b1).xor(new BigInteger(1, b2)).toByteArray(); - } } -- cgit v1.2.3 From c3d73145c746419d23ec1a337b62506c4ef70fcf Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Parm=C3=A9nides=20GV?= Date: Mon, 15 Apr 2013 17:52:19 +0200 Subject: Added one "else if" that I missed during merge. Next step: understand why ca.cert from bitmask is not being downloaded correctly. --- src/se/leap/leapclient/ConfigurationWizard.java | 3 +-- src/se/leap/leapclient/LeapHttpClient.java | 1 - src/se/leap/leapclient/ProviderAPI.java | 2 ++ 3 files changed, 3 insertions(+), 3 deletions(-) (limited to 'src/se/leap/leapclient') diff --git a/src/se/leap/leapclient/ConfigurationWizard.java b/src/se/leap/leapclient/ConfigurationWizard.java index 5b93cbbe..a61acfaa 100644 --- a/src/se/leap/leapclient/ConfigurationWizard.java +++ b/src/se/leap/leapclient/ConfigurationWizard.java @@ -17,7 +17,6 @@ import android.app.Fragment; import android.app.FragmentManager; import android.app.FragmentTransaction; import android.content.Intent; -import android.content.SharedPreferences; import android.content.res.AssetManager; import android.os.Bundle; import android.os.Handler; @@ -58,7 +57,7 @@ public class ConfigurationWizard extends Activity setContentView(R.layout.activity_configuration_wizard); - ConfigHelper.setSharedPreferences(getSharedPreferences(ConfigHelper.PREFERENCES_KEY,MODE_PRIVATE)); + ConfigHelper.setSharedPreferences(getSharedPreferences(ConfigHelper.PREFERENCES_KEY, MODE_PRIVATE)); loadPreseededProviders(); diff --git a/src/se/leap/leapclient/LeapHttpClient.java b/src/se/leap/leapclient/LeapHttpClient.java index 51b76b2c..d1908c34 100644 --- a/src/se/leap/leapclient/LeapHttpClient.java +++ b/src/se/leap/leapclient/LeapHttpClient.java @@ -1,6 +1,5 @@ package se.leap.leapclient; -import java.io.InputStream; import java.security.KeyStore; import org.apache.http.conn.ClientConnectionManager; diff --git a/src/se/leap/leapclient/ProviderAPI.java b/src/se/leap/leapclient/ProviderAPI.java index 6b09eb9d..ec131aaa 100644 --- a/src/se/leap/leapclient/ProviderAPI.java +++ b/src/se/leap/leapclient/ProviderAPI.java @@ -48,6 +48,8 @@ public class ProviderAPI extends IntentService { 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.downloadNewProviderDotJSON)) != null) { if(downloadJsonFilesBundleExtra(task)) receiver.send(ConfigHelper.CORRECTLY_DOWNLOADED_JSON_FILES, Bundle.EMPTY); else -- cgit v1.2.3 From 418264e2a78371d133b510122f5ac3c9bd940764 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Parm=C3=A9nides=20GV?= Date: Mon, 15 Apr 2013 20:20:58 +0200 Subject: Fixed bug 2231. New provider dialog works OK. --- src/se/leap/leapclient/ConfigHelper.java | 9 ++++++++- src/se/leap/leapclient/ConfigurationWizard.java | 4 ++-- src/se/leap/leapclient/ProviderAPI.java | 11 +++++++---- 3 files changed, 17 insertions(+), 7 deletions(-) (limited to 'src/se/leap/leapclient') diff --git a/src/se/leap/leapclient/ConfigHelper.java b/src/se/leap/leapclient/ConfigHelper.java index 11401df5..7476c89a 100644 --- a/src/se/leap/leapclient/ConfigHelper.java +++ b/src/se/leap/leapclient/ConfigHelper.java @@ -38,7 +38,7 @@ public class ConfigHelper { final static String eip_service_key = "eip"; public static final String PREFERENCES_KEY = "LEAPPreferences"; public static final String user_directory = "leap_android"; - public static String provider_key_url = "provider_main_url"; + public static String provider_main_url = "provider_main_url"; final public static String srp_server_url_key = "srp_server_url"; final public static String username_key = "username"; final public static String password_key = "password"; @@ -176,4 +176,11 @@ public class ConfigHelper { e.printStackTrace(); } } + + public static int getSrpAuthenticationFailed() { + return SRP_AUTHENTICATION_FAILED; + }static String extractProviderName(String provider_main_url) { + + return null; + } } diff --git a/src/se/leap/leapclient/ConfigurationWizard.java b/src/se/leap/leapclient/ConfigurationWizard.java index a61acfaa..4fbba1df 100644 --- a/src/se/leap/leapclient/ConfigurationWizard.java +++ b/src/se/leap/leapclient/ConfigurationWizard.java @@ -182,14 +182,14 @@ public class ConfigurationWizard extends Activity } @Override - public void saveProvider(String provider_url) { + public void saveProvider(String provider_main_url) { providerAPI_result_receiver = new ProviderAPIResultReceiver(new Handler()); providerAPI_result_receiver.setReceiver(this); Intent provider_API_command = new Intent(this, ProviderAPI.class); Bundle method_and_parameters = new Bundle(); - method_and_parameters.putString(ConfigHelper.provider_key_url, provider_url); + method_and_parameters.putString(ConfigHelper.provider_main_url, provider_main_url); provider_API_command.putExtra(ConfigHelper.downloadNewProviderDotJSON, method_and_parameters); provider_API_command.putExtra("receiver", providerAPI_result_receiver); diff --git a/src/se/leap/leapclient/ProviderAPI.java b/src/se/leap/leapclient/ProviderAPI.java index ec131aaa..07452a44 100644 --- a/src/se/leap/leapclient/ProviderAPI.java +++ b/src/se/leap/leapclient/ProviderAPI.java @@ -50,7 +50,7 @@ public class ProviderAPI extends IntentService { receiver.send(ConfigHelper.CORRECTLY_DOWNLOADED_JSON_FILES, Bundle.EMPTY); } else if ((task = task_for.getBundleExtra(ConfigHelper.downloadNewProviderDotJSON)) != null) { - if(downloadJsonFilesBundleExtra(task)) + if(downloadNewProviderDotJSON(task)) receiver.send(ConfigHelper.CORRECTLY_DOWNLOADED_JSON_FILES, Bundle.EMPTY); else receiver.send(ConfigHelper.INCORRECTLY_DOWNLOADED_JSON_FILES, Bundle.EMPTY); @@ -179,7 +179,7 @@ public class ProviderAPI extends IntentService { private boolean downloadNewProviderDotJSON(Bundle task) { boolean custom = true; - String provider_main_url = (String) task.get(ConfigHelper.provider_key_url); + String provider_main_url = (String) task.get(ConfigHelper.provider_main_url); String provider_name = provider_main_url.replaceFirst("http[s]?://", "").replaceFirst("\\/", "_"); String provider_json_url = guessURL(provider_main_url); JSONObject provider_json = null; @@ -199,6 +199,7 @@ public class ProviderAPI extends IntentService { } else { String filename = provider_name + "_provider.json".replaceFirst("__", "_"); ConfigHelper.saveFile(filename, provider_json.toString()); + ConfigHelper.saveSharedPref(ConfigHelper.provider_key, provider_json); ProviderListContent.addItem(new ProviderItem(provider_name, ConfigHelper.openFileInputStream(filename), custom)); return true; @@ -206,7 +207,9 @@ public class ProviderAPI extends IntentService { } private boolean downloadJsonFilesBundleExtra(Bundle task) { - String provider_name = (String) task.get(ConfigHelper.provider_key); + //TODO task only contains provider main url -> we need to infer cert_url, provider_name and eip_service_json_url from that. + String provider_main_url = (String) task.get(ConfigHelper.provider_main_url); + String provider_name = ConfigHelper.extractProviderName(provider_main_url); String cert_url = (String) task.get(ConfigHelper.cert_key); String eip_service_json_url = (String) task.get(ConfigHelper.eip_service_key); try { @@ -223,7 +226,7 @@ public class ProviderAPI extends IntentService { ConfigHelper.saveSharedPref(ConfigHelper.eip_service_key, eip_service_json); return true; } catch (IOException e) { - // It could happen that an https site used a certificate not trusted: solved above using URL + //TODO It could happen when the url is not valid. e.printStackTrace(); return false; } catch (JSONException e) { -- cgit v1.2.3 From fbfdf86a1df28ccf8f1854c2e2a4c7b3135d50ae Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Parm=C3=A9nides=20GV?= Date: Tue, 16 Apr 2013 18:14:47 +0200 Subject: Fixed bug #2225 (https://leap.se/code/issues/2225) --- src/se/leap/leapclient/ConfigurationWizard.java | 3 ++- src/se/leap/leapclient/NewProviderDialog.java | 4 ++-- src/se/leap/leapclient/ProviderAPI.java | 3 +++ 3 files changed, 7 insertions(+), 3 deletions(-) (limited to 'src/se/leap/leapclient') diff --git a/src/se/leap/leapclient/ConfigurationWizard.java b/src/se/leap/leapclient/ConfigurationWizard.java index 4fbba1df..0d445227 100644 --- a/src/se/leap/leapclient/ConfigurationWizard.java +++ b/src/se/leap/leapclient/ConfigurationWizard.java @@ -21,6 +21,7 @@ import android.content.res.AssetManager; import android.os.Bundle; import android.os.Handler; import android.view.View; +import android.widget.Toast; /** @@ -213,7 +214,7 @@ public class ConfigurationWizard extends Activity } else if(resultCode == ConfigHelper.INCORRECTLY_DOWNLOADED_JSON_FILES) { setResult(RESULT_CANCELED); - finish(); + Toast.makeText(getApplicationContext(), "You have not entered a LEAP provider URL", Toast.LENGTH_LONG).show(); } } } diff --git a/src/se/leap/leapclient/NewProviderDialog.java b/src/se/leap/leapclient/NewProviderDialog.java index 52453485..88e4711c 100644 --- a/src/se/leap/leapclient/NewProviderDialog.java +++ b/src/se/leap/leapclient/NewProviderDialog.java @@ -50,10 +50,10 @@ public class NewProviderDialog extends DialogFragment { String entered_url = url_input_field.getText().toString().trim(); if(validURL(entered_url)) { interface_with_ConfigurationWizard.saveProvider(entered_url); - Toast.makeText(getActivity().getApplicationContext(), "Valid URL", Toast.LENGTH_LONG).show(); + Toast.makeText(getActivity().getApplicationContext(), "It seems your URL is well formed", Toast.LENGTH_LONG).show(); } else { url_input_field.setText(""); - Toast.makeText(getActivity().getApplicationContext(), "Not valid URL", Toast.LENGTH_LONG).show(); + Toast.makeText(getActivity().getApplicationContext(), "It seems your URL is not well formed", Toast.LENGTH_LONG).show(); } } }) diff --git a/src/se/leap/leapclient/ProviderAPI.java b/src/se/leap/leapclient/ProviderAPI.java index 07452a44..4ffd2762 100644 --- a/src/se/leap/leapclient/ProviderAPI.java +++ b/src/se/leap/leapclient/ProviderAPI.java @@ -6,6 +6,7 @@ import java.security.NoSuchAlgorithmException; import java.util.List; import java.net.MalformedURLException; import java.net.URL; +import java.net.UnknownHostException; import java.util.Scanner; import org.apache.http.HttpEntity; @@ -247,6 +248,8 @@ public class ProviderAPI extends IntentService { provider_json = new JSONObject(provider_json_string); } catch (MalformedURLException e1) { e1.printStackTrace(); + } catch (UnknownHostException e1) { + e1.printStackTrace(); } catch (IOException e1) { e1.printStackTrace(); } catch (JSONException e1) { -- cgit v1.2.3 From 8e47afc7f4f85b80d59d253378681cb85ec54d5c Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Parm=C3=A9nides=20GV?= Date: Tue, 16 Apr 2013 20:12:13 +0200 Subject: Made SRP working with ProviderAPI methods more frequently than not in localhost, but I cannot succeed in api.bitmask.net with my personal account. Next step: add tests from api.bitmask.net. --- src/se/leap/leapclient/LeapSRPSession.java | 2 ++ src/se/leap/leapclient/ProviderAPI.java | 22 +++++++++++++++------- 2 files changed, 17 insertions(+), 7 deletions(-) (limited to 'src/se/leap/leapclient') diff --git a/src/se/leap/leapclient/LeapSRPSession.java b/src/se/leap/leapclient/LeapSRPSession.java index abdf6b2c..6fc8b2b1 100644 --- a/src/se/leap/leapclient/LeapSRPSession.java +++ b/src/se/leap/leapclient/LeapSRPSession.java @@ -70,6 +70,8 @@ public class LeapSRPSession { */ this.a = new BigInteger(abytes); } + else + A_LEN = 64; // Calculate x = H(s | H(U | ':' | password)) byte[] salt_bytes = Util.trim(params.s); diff --git a/src/se/leap/leapclient/ProviderAPI.java b/src/se/leap/leapclient/ProviderAPI.java index 4ffd2762..5113ebc1 100644 --- a/src/se/leap/leapclient/ProviderAPI.java +++ b/src/se/leap/leapclient/ProviderAPI.java @@ -20,6 +20,7 @@ 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.Util; import org.jboss.security.srp.SRPParameters; import org.json.JSONException; import org.json.JSONObject; @@ -56,6 +57,12 @@ public class ProviderAPI extends IntentService { else receiver.send(ConfigHelper.INCORRECTLY_DOWNLOADED_JSON_FILES, Bundle.EMPTY); } + else if ((task = task_for.getBundleExtra(ConfigHelper.srpAuth)) != null) { + if(authenticateBySRP(task)) + receiver.send(ConfigHelper.SRP_AUTHENTICATION_SUCCESSFUL, Bundle.EMPTY); + else + receiver.send(ConfigHelper.SRP_AUTHENTICATION_FAILED, Bundle.EMPTY); + } } private boolean downloadJsonFiles(Bundle task) { @@ -105,17 +112,16 @@ public class ProviderAPI extends IntentService { LeapSRPSession client = new LeapSRPSession(username, password.toCharArray(), params); byte[] A = client.exponential(); try { - JSONObject saltAndB = sendAToSRPServer(authentication_server, username, new BigInteger(A).toString(16)); + JSONObject saltAndB = sendAToSRPServer(authentication_server, username, new BigInteger(1, A).toString(16)); if(saltAndB.length() > 0) { byte[] B = saltAndB.getString("B").getBytes(); salt = saltAndB.getString("salt"); params = new SRPParameters(new BigInteger(ConfigHelper.NG_1024, 16).toByteArray(), new BigInteger("2").toByteArray(), new BigInteger(salt, 16).toByteArray(), "SHA-256"); - //client = new SRPClientSession(username, password.toCharArray(), params); client = new LeapSRPSession(username, password.toCharArray(), params); A = client.exponential(); - saltAndB = sendAToSRPServer(authentication_server, username, new BigInteger(A).toString(16)); - String Bhex = saltAndB.getString("B"); - byte[] M1 = client.response(new BigInteger(Bhex, 16).toByteArray()); + saltAndB = sendAToSRPServer(authentication_server, username, new BigInteger(1, A).toString(16)); + byte[] Bbytes = new BigInteger(saltAndB.getString("B"), 16).toByteArray(); + byte[] M1 = client.response(Bbytes); byte[] M2 = sendM1ToSRPServer(authentication_server, username, M1); if( client.verify(M2) == false ) throw new SecurityException("Failed to validate server reply"); @@ -162,7 +168,7 @@ public class ProviderAPI extends IntentService { private byte[] sendM1ToSRPServer(String server_url, String username, byte[] m1) throws ClientProtocolException, IOException, JSONException { DefaultHttpClient client = LeapHttpClient.getInstance(getApplicationContext()); - String parameter_chain = "client_auth" + "=" + new BigInteger(m1).toString(16); + String parameter_chain = "client_auth" + "=" + new BigInteger(1, Util.trim(m1)).toString(16); HttpPut put = new HttpPut(server_url + "/sessions/" + username +".json" + "?" + parameter_chain); HttpContext localContext = new BasicHttpContext(); localContext.setAttribute(ClientContext.COOKIE_STORE, client.getCookieStore()); @@ -175,7 +181,9 @@ public class ProviderAPI extends IntentService { return new byte[0]; } - return json_response.getString("M2").getBytes(); + byte[] M2_not_trimmed = new BigInteger(json_response.getString("M2"), 16).toByteArray(); + return Util.trim(M2_not_trimmed); + //return M2_not_trimmed; } private boolean downloadNewProviderDotJSON(Bundle task) { -- cgit v1.2.3 From f9b9827ec1975cb01e83826f0ad77542e514b21f Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Parm=C3=A9nides=20GV?= Date: Wed, 17 Apr 2013 21:17:22 +0200 Subject: This commit contains: - SRP algorithm improved (validate method uses trim, and some other trims have been added). - Refactored calculatePasswordHash, so that it receives a String instead of a char array, and now it is capable of escaping "\" correctly. - A 1000*2 successful logins, with a new test that performs 1000 trials for 2 different username/password/server trios. Next step: think about how the user is going to trigger the log in fragment. --- src/se/leap/leapclient/LeapSRPSession.java | 36 +++++++++++++++++------------- src/se/leap/leapclient/ProviderAPI.java | 6 ++--- 2 files changed, 23 insertions(+), 19 deletions(-) (limited to 'src/se/leap/leapclient') diff --git a/src/se/leap/leapclient/LeapSRPSession.java b/src/se/leap/leapclient/LeapSRPSession.java index 6fc8b2b1..d266cd7f 100644 --- a/src/se/leap/leapclient/LeapSRPSession.java +++ b/src/se/leap/leapclient/LeapSRPSession.java @@ -34,7 +34,7 @@ public class LeapSRPSession { @param password, the user clear text password @param params, the SRP parameters for the session */ - public LeapSRPSession(String username, char[] password, SRPParameters params) + public LeapSRPSession(String username, String password, SRPParameters params) { this(username, password, params, null); } @@ -47,7 +47,7 @@ public class LeapSRPSession { @param abytes, the random exponent used in the A public key. This must be 8 bytes in length. */ - public LeapSRPSession(String username, char[] password, SRPParameters params, + public LeapSRPSession(String username, String password, SRPParameters params, byte[] abytes) { try { // Initialize the secure random number and message digests @@ -117,11 +117,11 @@ public class LeapSRPSession { * @param salt the salt of the user * @return x */ - public byte[] calculatePasswordHash(String username, char[] password, byte[] salt) + 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 UTF-8 byte[] user = null; byte[] colon = {}; @@ -135,10 +135,10 @@ public class LeapSRPSession { colon = Util.trim(":".getBytes()); } - byte[] passBytes = new byte[2*password.length]; + byte[] passBytes = new byte[2*password.toCharArray().length]; int passBytesLength = 0; - for(int p = 0; p < password.length; p++) { - int c = (password[p] & 0x00FFFF); + for(int p = 0; p < password.toCharArray().length; p++) { + int c = (password.toCharArray()[p] & 0x00FFFF); // The low byte of the char byte b0 = (byte) (c & 0x0000FF); // The high byte of the char @@ -159,7 +159,7 @@ public class LeapSRPSession { x_digest.reset(); x_digest.update(salt); x_digest.update(h); - byte[] x_digest_bytes = Util.trim(x_digest.digest()); + byte[] x_digest_bytes = x_digest.digest(); return x_digest_bytes; } @@ -171,7 +171,8 @@ public class LeapSRPSession { */ private BigInteger calculateV(String k_string) { BigInteger k = new BigInteger(k_string, 16); - return k.multiply(g.modPow(x, N)); // g^x % N + BigInteger v = k.multiply(g.modPow(x, N)); // g^x % N + return v; } public byte[] xor(byte[] b1, byte[] b2, int length) @@ -229,13 +230,13 @@ public class LeapSRPSession { // K = SessionHash(S) String hash_algorithm = params.hashAlgorithm; MessageDigest sessionDigest = MessageDigest.getInstance(hash_algorithm); - K = sessionDigest.digest(S_bytes); + K = Util.trim(sessionDigest.digest(S_bytes)); //K = Util.trim(K); //String K_bytes_string = new BigInteger(1, K).toString(16); // clientHash = H(N) xor H(g) | H(U) | A | B | K clientHash.update(K); - byte[] M1 = clientHash.digest(); + byte[] M1 = Util.trim(clientHash.digest()); // serverHash = Astr + M + K serverHash.update(M1); @@ -250,10 +251,11 @@ public class LeapSRPSession { */ private BigInteger calculateS(byte[] Bbytes) { byte[] Abytes = Util.trim(A.toByteArray()); + Bbytes = Util.trim(Bbytes); byte[] u_bytes = getU(Abytes, Bbytes); - //ub = Util.trim(ub); BigInteger B = new BigInteger(1, Bbytes); + //String Bstring = B.toString(16); BigInteger u = new BigInteger(1, u_bytes); //String u_string = u.toString(16); @@ -273,9 +275,10 @@ public class LeapSRPSession { */ public byte[] getU(byte[] Abytes, byte[] Bbytes) { MessageDigest u_digest = newDigest(); - u_digest.update(Abytes); - u_digest.update(Bbytes); - return new BigInteger(1, u_digest.digest()).toByteArray(); + u_digest.update(Util.trim(Abytes)); + u_digest.update(Util.trim(Bbytes)); + byte[] u_digest_bytes = u_digest.digest();//Util.trim(u_digest.digest()); + return Util.trim(new BigInteger(1, u_digest_bytes).toByteArray()); } /** @@ -285,7 +288,8 @@ public class LeapSRPSession { public boolean verify(byte[] M2) { // M2 = H(A | M1 | K) - byte[] myM2 = serverHash.digest(); + M2 = Util.trim(M2); + byte[] myM2 = Util.trim(serverHash.digest()); boolean valid = Arrays.equals(M2, myM2); return valid; } diff --git a/src/se/leap/leapclient/ProviderAPI.java b/src/se/leap/leapclient/ProviderAPI.java index 5113ebc1..55686f70 100644 --- a/src/se/leap/leapclient/ProviderAPI.java +++ b/src/se/leap/leapclient/ProviderAPI.java @@ -109,7 +109,7 @@ public class ProviderAPI extends IntentService { SRPParameters params = new SRPParameters(new BigInteger(ConfigHelper.NG_1024, 16).toByteArray(), new BigInteger("2").toByteArray(), new BigInteger(salt, 16).toByteArray(), "SHA-256"); //SRPClientSession client = new SRPClientSession(username, password.toCharArray(), params); - LeapSRPSession client = new LeapSRPSession(username, password.toCharArray(), params); + LeapSRPSession client = new LeapSRPSession(username, password, params); byte[] A = client.exponential(); try { JSONObject saltAndB = sendAToSRPServer(authentication_server, username, new BigInteger(1, A).toString(16)); @@ -117,14 +117,14 @@ public class ProviderAPI extends IntentService { byte[] B = saltAndB.getString("B").getBytes(); salt = saltAndB.getString("salt"); params = new SRPParameters(new BigInteger(ConfigHelper.NG_1024, 16).toByteArray(), new BigInteger("2").toByteArray(), new BigInteger(salt, 16).toByteArray(), "SHA-256"); - client = new LeapSRPSession(username, password.toCharArray(), params); + client = new LeapSRPSession(username, password, params); A = client.exponential(); saltAndB = sendAToSRPServer(authentication_server, username, new BigInteger(1, A).toString(16)); byte[] Bbytes = new BigInteger(saltAndB.getString("B"), 16).toByteArray(); byte[] M1 = client.response(Bbytes); byte[] M2 = sendM1ToSRPServer(authentication_server, username, M1); if( client.verify(M2) == false ) - throw new SecurityException("Failed to validate server reply"); + throw new SecurityException("Failed to validate server reply: M2 = " + new BigInteger(1, M2).toString(16)); return true; } else return false; -- cgit v1.2.3 From 5c05094401d6ed3c69ab8f64e47278973bc87425 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Parm=C3=A9nides=20GV?= Date: Thu, 18 Apr 2013 21:56:06 +0200 Subject: Coded logout method, and tested. --- src/se/leap/leapclient/ConfigHelper.java | 7 ++-- src/se/leap/leapclient/ProviderAPI.java | 60 +++++++++++++++----------------- 2 files changed, 33 insertions(+), 34 deletions(-) (limited to 'src/se/leap/leapclient') diff --git a/src/se/leap/leapclient/ConfigHelper.java b/src/se/leap/leapclient/ConfigHelper.java index 7476c89a..8f38cbeb 100644 --- a/src/se/leap/leapclient/ConfigHelper.java +++ b/src/se/leap/leapclient/ConfigHelper.java @@ -32,6 +32,7 @@ public class ConfigHelper { final static String downloadNewProviderDotJSON = "downloadNewProviderDotJSON"; public static final String srpRegister = "srpRegister"; final public static String srpAuth = "srpAuth"; + public static String logOut = "logOut"; final public static String resultKey = "result"; final static String provider_key = "provider"; final static String cert_key = "cert"; @@ -53,8 +54,10 @@ public class ConfigHelper { final public static int INCORRECTLY_DOWNLOADED_JSON_FILES = 2; final public static int SRP_AUTHENTICATION_SUCCESSFUL = 3; final public static int SRP_AUTHENTICATION_FAILED = 4; - public static final int SRP_REGISTRATION_SUCCESSFUL = 5; - public static final int SRP_REGISTRATION_FAILED = 6; + final public static int SRP_REGISTRATION_SUCCESSFUL = 5; + final public static int SRP_REGISTRATION_FAILED = 6; + final public static int LOGOUT_SUCCESSFUL = 7; + final public static int LOGOUT_FAILED = 8; static void saveSharedPref(String shared_preferences_key, JSONObject content) { diff --git a/src/se/leap/leapclient/ProviderAPI.java b/src/se/leap/leapclient/ProviderAPI.java index 55686f70..d47e3b65 100644 --- a/src/se/leap/leapclient/ProviderAPI.java +++ b/src/se/leap/leapclient/ProviderAPI.java @@ -12,6 +12,7 @@ import java.util.Scanner; 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.HttpGet; import org.apache.http.client.methods.HttpPost; import org.apache.http.client.methods.HttpPut; @@ -63,6 +64,12 @@ public class ProviderAPI extends IntentService { else receiver.send(ConfigHelper.SRP_AUTHENTICATION_FAILED, Bundle.EMPTY); } + else if ((task = task_for.getBundleExtra(ConfigHelper.logOut)) != null) { + if(logOut(task)) + receiver.send(ConfigHelper.LOGOUT_SUCCESSFUL, Bundle.EMPTY); + else + receiver.send(ConfigHelper.LOGOUT_FAILED, Bundle.EMPTY); + } } private boolean downloadJsonFiles(Bundle task) { @@ -215,38 +222,6 @@ public class ProviderAPI extends IntentService { } } - private boolean downloadJsonFilesBundleExtra(Bundle task) { - //TODO task only contains provider main url -> we need to infer cert_url, provider_name and eip_service_json_url from that. - String provider_main_url = (String) task.get(ConfigHelper.provider_main_url); - String provider_name = ConfigHelper.extractProviderName(provider_main_url); - String cert_url = (String) task.get(ConfigHelper.cert_key); - String eip_service_json_url = (String) task.get(ConfigHelper.eip_service_key); - try { - //JSONObject provider_json = new JSONObject("{ \"provider\" : \"" + provider_name + "\"}"); - //ConfigHelper.saveSharedPref(ConfigHelper.provider_key, provider_json); - - /*String cert_string = getStringFromProvider(cert_url); - JSONObject cert_json = new JSONObject("{ \"certificate\" : \"" + cert_string + "\"}"); - ConfigHelper.saveSharedPref(ConfigHelper.cert_key, cert_json); - ConfigHelper.addTrustedCertificate(provider_name, cert_string);*/ - URL cacert = new URL(cert_url); - ConfigHelper.addTrustedCertificate(provider_name, cacert.openStream()); - JSONObject eip_service_json = getJSONFromProvider(eip_service_json_url); - ConfigHelper.saveSharedPref(ConfigHelper.eip_service_key, eip_service_json); - return true; - } catch (IOException e) { - //TODO It could happen when the url is not valid. - e.printStackTrace(); - return false; - } catch (JSONException e) { - ConfigHelper.rescueJSONException(e); - return false; - } catch(Exception e) { - e.printStackTrace(); - return false; - } - } - private JSONObject downloadNewProviderDotJsonWithoutCert( String provider_json_url) { JSONObject provider_json = null; @@ -284,8 +259,29 @@ public class ProviderAPI extends IntentService { return json_file_content; } + private JSONObject getJSONFromProvider(String json_url) throws IOException, JSONException { String json_file_content = getStringFromProvider(json_url); return new JSONObject(json_file_content); } + + 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(); + String delete_url = task.getString(ConfigHelper.srp_server_url_key) + "/logout" + "?authenticity_token=" + client.getCookieStore().getCookies().get(session_id_index).getValue(); + HttpDelete delete = new HttpDelete(delete_url); + try { + HttpResponse getResponse = client.execute(delete); + HttpEntity responseEntity = getResponse.getEntity(); + responseEntity.consumeContent(); + } catch (ClientProtocolException e) { + // TODO Auto-generated catch block + e.printStackTrace(); + } catch (IOException e) { + // TODO Auto-generated catch block + e.printStackTrace(); + } + return true; + } } -- cgit v1.2.3 From 75728462433b19567710f54a9d4767681b10be95 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Parm=C3=A9nides=20GV?= Date: Mon, 22 Apr 2013 18:07:07 +0200 Subject: Coded dialog (now there is a button in the Dashboard), time to test. I need to implement bypass for dev.bitmask.net, because bitmask.net is down. --- src/se/leap/leapclient/ConfigHelper.java | 7 ++- src/se/leap/leapclient/ConfigurationWizard.java | 4 +- src/se/leap/leapclient/Dashboard.java | 64 +++++++++++++++++++++- src/se/leap/leapclient/LogInDialog.java | 73 +++++++++++++++++++++++++ src/se/leap/leapclient/ProviderAPI.java | 8 +-- 5 files changed, 147 insertions(+), 9 deletions(-) create mode 100644 src/se/leap/leapclient/LogInDialog.java (limited to 'src/se/leap/leapclient') diff --git a/src/se/leap/leapclient/ConfigHelper.java b/src/se/leap/leapclient/ConfigHelper.java index 8f38cbeb..de14eed6 100644 --- a/src/se/leap/leapclient/ConfigHelper.java +++ b/src/se/leap/leapclient/ConfigHelper.java @@ -30,8 +30,11 @@ public class ConfigHelper { final static String downloadJsonFilesBundleExtra = "downloadJSONFiles"; final static String downloadNewProviderDotJSON = "downloadNewProviderDotJSON"; - public static final String srpRegister = "srpRegister"; + final public static String logInDialog = "logInDialog"; + final public static String newProviderDialog = "logInDialog"; + final public static String srpRegister = "srpRegister"; final public static String srpAuth = "srpAuth"; + public static String logIn = "logIn"; public static String logOut = "logOut"; final public static String resultKey = "result"; final static String provider_key = "provider"; @@ -40,7 +43,7 @@ public class ConfigHelper { public static final String PREFERENCES_KEY = "LEAPPreferences"; public static final String user_directory = "leap_android"; public static String provider_main_url = "provider_main_url"; - final public static String srp_server_url_key = "srp_server_url"; + final public static String api_url_key = "srp_server_url"; final public static String username_key = "username"; final public static String password_key = "password"; final public static String eip_service_api_path = "/config/eip-service.json"; diff --git a/src/se/leap/leapclient/ConfigurationWizard.java b/src/se/leap/leapclient/ConfigurationWizard.java index 0d445227..417752e2 100644 --- a/src/se/leap/leapclient/ConfigurationWizard.java +++ b/src/se/leap/leapclient/ConfigurationWizard.java @@ -172,14 +172,14 @@ public class ConfigurationWizard extends Activity public void addNewProvider(View view) { FragmentTransaction fragment_transaction = getFragmentManager().beginTransaction(); - Fragment previous_new_provider_dialog = getFragmentManager().findFragmentByTag("newProviderDialog"); + Fragment previous_new_provider_dialog = getFragmentManager().findFragmentByTag(ConfigHelper.newProviderDialog); 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"); + newFragment.show(fragment_transaction, ConfigHelper.newProviderDialog); } @Override diff --git a/src/se/leap/leapclient/Dashboard.java b/src/se/leap/leapclient/Dashboard.java index dce99b1e..815df18f 100644 --- a/src/se/leap/leapclient/Dashboard.java +++ b/src/se/leap/leapclient/Dashboard.java @@ -1,13 +1,20 @@ package se.leap.leapclient; +import org.json.JSONException; +import org.json.JSONObject; + +import se.leap.leapclient.ProviderAPIResultReceiver.Receiver; import se.leap.openvpn.AboutFragment; import se.leap.openvpn.MainActivity; import android.app.Activity; +import android.app.DialogFragment; import android.app.Fragment; +import android.app.FragmentManager; import android.app.FragmentTransaction; 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; @@ -16,7 +23,7 @@ import android.widget.CompoundButton; import android.widget.Switch; import android.widget.TextView; -public class Dashboard extends Activity { +public class Dashboard extends Activity implements LogInDialog.LogInDialogInterface, Receiver { protected static final int CONFIGURE_LEAP = 0; @@ -26,6 +33,8 @@ public class Dashboard extends Activity { private TextView providerNameTV; private TextView eipTypeTV; + public ProviderAPIResultReceiver providerAPI_result_receiver; + @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); @@ -127,6 +136,9 @@ public class Dashboard extends Activity { // TODO call se.leap.openvpn.MainActivity intent = new Intent(this,MainActivity.class); startActivity(intent); + return true; + case R.id.login_button: + return true; default: return super.onOptionsItemSelected(item); @@ -139,4 +151,54 @@ public class Dashboard extends Activity { // TODO Expand the one line overview item to show some details } + @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 method_and_parameters = new Bundle(); + method_and_parameters.putString(ConfigHelper.username_key, username); + method_and_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)); + } catch (JSONException e) { + // TODO Auto-generated catch block + e.printStackTrace(); + } + + provider_API_command.putExtra(ConfigHelper.srpAuth, method_and_parameters); + provider_API_command.putExtra("receiver", providerAPI_result_receiver); + + startService(provider_API_command); + } + + public void logInDialog(View view) { + FragmentTransaction fragment_transaction = getFragmentManager().beginTransaction(); + Fragment previous_log_in_dialog = getFragmentManager().findFragmentByTag(ConfigHelper.logInDialog); + if (previous_log_in_dialog != null) { + fragment_transaction.remove(previous_log_in_dialog); + } + fragment_transaction.addToBackStack(null); + + DialogFragment newFragment = LogInDialog.newInstance(); + newFragment.show(fragment_transaction, ConfigHelper.logInDialog); + } + + @Override + public void onReceiveResult(int resultCode, Bundle resultData) { + if(resultCode == ConfigHelper.SRP_AUTHENTICATION_SUCCESSFUL){ + setResult(RESULT_OK); + //TODO What should we do know? + } + else if(resultCode == ConfigHelper.SRP_AUTHENTICATION_FAILED) { + setResult(RESULT_CANCELED); + finish(); + } + } + } diff --git a/src/se/leap/leapclient/LogInDialog.java b/src/se/leap/leapclient/LogInDialog.java new file mode 100644 index 00000000..b9583d8a --- /dev/null +++ b/src/se/leap/leapclient/LogInDialog.java @@ -0,0 +1,73 @@ +package se.leap.leapclient; + +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.EditText; +import android.widget.Toast; + +public class LogInDialog extends DialogFragment { + + public interface LogInDialogInterface { + public void authenticate(String username, String password); + } + + LogInDialogInterface interface_with_ConfigurationWizard; + + public static DialogFragment newInstance() { + LogInDialog dialog_fragment = new LogInDialog(); + return dialog_fragment; + } + + @Override + public void onAttach(Activity activity) { + super.onAttach(activity); + // Verify that the host activity implements the callback interface + try { + // Instantiate the NoticeDialogListener so we can send events to the host + interface_with_ConfigurationWizard = (LogInDialogInterface) activity; + } catch (ClassCastException e) { + // The activity doesn't implement the interface, throw exception + throw new ClassCastException(activity.toString() + + " must implement NoticeDialogListener"); + } + } + + public Dialog 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 EditText username_field = (EditText)log_in_dialog_view.findViewById(R.id.username_entered); + final EditText password_field = (EditText)log_in_dialog_view.findViewById(R.id.password_entered); + builder.setView(log_in_dialog_view) + .setPositiveButton(R.string.log_in_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(); + if(validPassword(password)) { + interface_with_ConfigurationWizard.authenticate(username, password); + Toast.makeText(getActivity().getApplicationContext(), "It seems your URL is well formed", Toast.LENGTH_LONG).show(); + } else { + password_field.setText(""); + Toast.makeText(getActivity().getApplicationContext(), "It seems your URL is not well formed", 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(); + } + + boolean validPassword(String entered_password) { + return !(entered_password.length() > 8); + } +} diff --git a/src/se/leap/leapclient/ProviderAPI.java b/src/se/leap/leapclient/ProviderAPI.java index d47e3b65..0b114e38 100644 --- a/src/se/leap/leapclient/ProviderAPI.java +++ b/src/se/leap/leapclient/ProviderAPI.java @@ -83,7 +83,7 @@ public class ProviderAPI extends IntentService { ConfigHelper.saveSharedPref(ConfigHelper.eip_service_key, eip_service_json); return true; } catch (IOException e) { - // TODO Auto-generated catch block + // TODO e.printStackTrace(); return false; } catch (JSONException e) { @@ -98,7 +98,7 @@ public class ProviderAPI extends IntentService { private boolean registerWithSRP(Bundle task) { String username = (String) task.get(ConfigHelper.username_key); String password = (String) task.get(ConfigHelper.password_key); - String authentication_server = (String) task.get(ConfigHelper.srp_server_url_key); + String authentication_server = (String) task.get(ConfigHelper.api_url_key); BigInteger ng_1024 = new BigInteger(ConfigHelper.NG_1024, 16); BigInteger salt = ng_1024.probablePrime(1024, null); @@ -110,7 +110,7 @@ public class ProviderAPI extends IntentService { private boolean authenticateBySRP(Bundle task) { String username = (String) task.get(ConfigHelper.username_key); String password = (String) task.get(ConfigHelper.password_key); - String authentication_server = (String) task.get(ConfigHelper.srp_server_url_key); + String authentication_server = (String) task.get(ConfigHelper.api_url_key); String salt = "abcd"; @@ -269,7 +269,7 @@ public class ProviderAPI extends IntentService { 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(); - String delete_url = task.getString(ConfigHelper.srp_server_url_key) + "/logout" + "?authenticity_token=" + client.getCookieStore().getCookies().get(session_id_index).getValue(); + String delete_url = task.getString(ConfigHelper.api_url_key) + "/logout" + "?authenticity_token=" + client.getCookieStore().getCookies().get(session_id_index).getValue(); HttpDelete delete = new HttpDelete(delete_url); try { HttpResponse getResponse = client.execute(delete); -- cgit v1.2.3 From bfe2263d6b73159a4f929bc7b1fdeb724c88e8de Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Parm=C3=A9nides=20GV?= Date: Mon, 22 Apr 2013 20:17:43 +0200 Subject: Added danger mode: we can bypass dev.bitmask.net hostname io exception. --- src/se/leap/leapclient/ConfigHelper.java | 3 +- src/se/leap/leapclient/ConfigurationWizard.java | 3 +- src/se/leap/leapclient/Dashboard.java | 4 +- src/se/leap/leapclient/LogInDialog.java | 8 ++-- src/se/leap/leapclient/NewProviderDialog.java | 8 +++- src/se/leap/leapclient/ProviderAPI.java | 50 ++++++++++++++++++++++++- 6 files changed, 65 insertions(+), 11 deletions(-) (limited to 'src/se/leap/leapclient') diff --git a/src/se/leap/leapclient/ConfigHelper.java b/src/se/leap/leapclient/ConfigHelper.java index de14eed6..78c71cc4 100644 --- a/src/se/leap/leapclient/ConfigHelper.java +++ b/src/se/leap/leapclient/ConfigHelper.java @@ -42,7 +42,8 @@ public class ConfigHelper { final static String eip_service_key = "eip"; public static final String PREFERENCES_KEY = "LEAPPreferences"; public static final String user_directory = "leap_android"; - public static String provider_main_url = "provider_main_url"; + final public static String provider_main_url = "provider_main_url"; + final public static String danger_on = "danger_on"; final public static String api_url_key = "srp_server_url"; final public static String username_key = "username"; final public static String password_key = "password"; diff --git a/src/se/leap/leapclient/ConfigurationWizard.java b/src/se/leap/leapclient/ConfigurationWizard.java index 417752e2..9edaa288 100644 --- a/src/se/leap/leapclient/ConfigurationWizard.java +++ b/src/se/leap/leapclient/ConfigurationWizard.java @@ -183,7 +183,7 @@ public class ConfigurationWizard extends Activity } @Override - public void saveProvider(String provider_main_url) { + public void saveProvider(String provider_main_url, boolean danger_on) { providerAPI_result_receiver = new ProviderAPIResultReceiver(new Handler()); providerAPI_result_receiver.setReceiver(this); @@ -193,6 +193,7 @@ public class ConfigurationWizard extends Activity method_and_parameters.putString(ConfigHelper.provider_main_url, provider_main_url); provider_API_command.putExtra(ConfigHelper.downloadNewProviderDotJSON, method_and_parameters); + provider_API_command.putExtra(ConfigHelper.danger_on, danger_on); provider_API_command.putExtra("receiver", providerAPI_result_receiver); startService(provider_API_command); diff --git a/src/se/leap/leapclient/Dashboard.java b/src/se/leap/leapclient/Dashboard.java index 815df18f..a169c9d4 100644 --- a/src/se/leap/leapclient/Dashboard.java +++ b/src/se/leap/leapclient/Dashboard.java @@ -18,6 +18,7 @@ import android.os.Handler; import android.view.Menu; import android.view.MenuItem; import android.view.View; +import android.view.ViewGroup; import android.view.ViewStub; import android.widget.CompoundButton; import android.widget.Switch; @@ -138,7 +139,8 @@ public class Dashboard extends Activity implements LogInDialog.LogInDialogInterf startActivity(intent); return true; case R.id.login_button: - + View view = ((ViewGroup)findViewById(android.R.id.content)).getChildAt(0); + logInDialog(view); return true; default: return super.onOptionsItemSelected(item); diff --git a/src/se/leap/leapclient/LogInDialog.java b/src/se/leap/leapclient/LogInDialog.java index b9583d8a..61526c69 100644 --- a/src/se/leap/leapclient/LogInDialog.java +++ b/src/se/leap/leapclient/LogInDialog.java @@ -17,7 +17,7 @@ public class LogInDialog extends DialogFragment { public void authenticate(String username, String password); } - LogInDialogInterface interface_with_ConfigurationWizard; + LogInDialogInterface interface_with_Dashboard; public static DialogFragment newInstance() { LogInDialog dialog_fragment = new LogInDialog(); @@ -30,7 +30,7 @@ public class LogInDialog extends DialogFragment { // Verify that the host activity implements the callback interface try { // Instantiate the NoticeDialogListener so we can send events to the host - interface_with_ConfigurationWizard = (LogInDialogInterface) activity; + interface_with_Dashboard = (LogInDialogInterface) activity; } catch (ClassCastException e) { // The activity doesn't implement the interface, throw exception throw new ClassCastException(activity.toString() @@ -50,7 +50,7 @@ public class LogInDialog extends DialogFragment { String username = username_field.getText().toString().trim(); String password = password_field.getText().toString().trim(); if(validPassword(password)) { - interface_with_ConfigurationWizard.authenticate(username, password); + interface_with_Dashboard.authenticate(username, password); Toast.makeText(getActivity().getApplicationContext(), "It seems your URL is well formed", Toast.LENGTH_LONG).show(); } else { password_field.setText(""); @@ -68,6 +68,6 @@ public class LogInDialog extends DialogFragment { } boolean validPassword(String entered_password) { - return !(entered_password.length() > 8); + return entered_password.length() > 8; } } diff --git a/src/se/leap/leapclient/NewProviderDialog.java b/src/se/leap/leapclient/NewProviderDialog.java index 88e4711c..61018463 100644 --- a/src/se/leap/leapclient/NewProviderDialog.java +++ b/src/se/leap/leapclient/NewProviderDialog.java @@ -8,13 +8,14 @@ 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; public class NewProviderDialog extends DialogFragment { public interface NewProviderDialogInterface { - public void saveProvider(String url_provider); + public void saveProvider(String url_provider, boolean danger_on); } NewProviderDialogInterface interface_with_ConfigurationWizard; @@ -43,13 +44,16 @@ public class NewProviderDialog extends DialogFragment { 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(); + boolean danger_on = danger_checkbox.isChecked(); if(validURL(entered_url)) { - interface_with_ConfigurationWizard.saveProvider(entered_url); + interface_with_ConfigurationWizard.saveProvider(entered_url, danger_on); Toast.makeText(getActivity().getApplicationContext(), "It seems your URL is well formed", Toast.LENGTH_LONG).show(); } else { url_input_field.setText(""); diff --git a/src/se/leap/leapclient/ProviderAPI.java b/src/se/leap/leapclient/ProviderAPI.java index 0b114e38..63db18e1 100644 --- a/src/se/leap/leapclient/ProviderAPI.java +++ b/src/se/leap/leapclient/ProviderAPI.java @@ -9,6 +9,10 @@ import java.net.URL; import java.net.UnknownHostException; import java.util.Scanner; +import javax.net.ssl.HostnameVerifier; +import javax.net.ssl.HttpsURLConnection; +import javax.net.ssl.SSLSession; + import org.apache.http.HttpEntity; import org.apache.http.HttpResponse; import org.apache.http.client.ClientProtocolException; @@ -195,6 +199,8 @@ public class ProviderAPI extends IntentService { private boolean downloadNewProviderDotJSON(Bundle task) { boolean custom = true; + boolean danger_on = ((Boolean)task.get(ConfigHelper.danger_on)).booleanValue(); + String provider_main_url = (String) task.get(ConfigHelper.provider_main_url); String provider_name = provider_main_url.replaceFirst("http[s]?://", "").replaceFirst("\\/", "_"); String provider_json_url = guessURL(provider_main_url); @@ -203,7 +209,7 @@ public class ProviderAPI extends IntentService { provider_json = getJSONFromProvider(provider_json_url); } catch (IOException e) { // It could happen that an https site used a certificate not trusted. - provider_json = downloadNewProviderDotJsonWithoutCert(provider_json_url); + provider_json = downloadNewProviderDotJsonWithoutCert(provider_json_url, danger_on); } catch (JSONException e) { // TODO Auto-generated catch block e.printStackTrace(); @@ -223,7 +229,7 @@ public class ProviderAPI extends IntentService { } private JSONObject downloadNewProviderDotJsonWithoutCert( - String provider_json_url) { + String provider_json_url, boolean danger_on) { JSONObject provider_json = null; try { URL provider_url = new URL(provider_json_url); @@ -234,6 +240,12 @@ public class ProviderAPI extends IntentService { } catch (UnknownHostException e1) { e1.printStackTrace(); } catch (IOException e1) { + if(danger_on) { + provider_json = downloadNewProviderDotJsonWithoutValidate(provider_json_url); + } + else { + //TODO Show error message advising to check the checkbox if the url is completely trusted. + } e1.printStackTrace(); } catch (JSONException e1) { e1.printStackTrace(); @@ -241,6 +253,40 @@ public class ProviderAPI extends IntentService { return provider_json; } + private JSONObject downloadNewProviderDotJsonWithoutValidate( + String provider_json_url) { + JSONObject provider_json = null; + HostnameVerifier hostnameVerifier = new HostnameVerifier() { + @Override + public boolean verify(String hostname, SSLSession session) { + HostnameVerifier hostname_verifier = + HttpsURLConnection.getDefaultHostnameVerifier(); + return hostname_verifier.verify("", session); + } + }; + + // Tell the URLConnection to use our HostnameVerifier + try { + URL url = new URL(provider_json_url); + HttpsURLConnection urlConnection = + (HttpsURLConnection)url.openConnection(); + urlConnection.setHostnameVerifier(hostnameVerifier); + String provider_json_string = new Scanner(url.openStream()).useDelimiter("\\A").next(); + provider_json = new JSONObject(provider_json_string); + } catch (MalformedURLException e) { + // TODO Auto-generated catch block + e.printStackTrace(); + } catch (IOException e) { + // TODO Auto-generated catch block + e.printStackTrace(); + } catch (JSONException e) { + // TODO Auto-generated catch block + e.printStackTrace(); + } + return provider_json; + + } + private String guessURL(String provider_main_url) { return provider_main_url + "/provider.json"; } -- cgit v1.2.3 From 69389ee7db23ce7182b21da08d227d88d6cfdc46 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Parm=C3=A9nides=20GV?= Date: Wed, 24 Apr 2013 20:01:28 +0200 Subject: "Trust completely" checkbox saves that trust for the new provider entered, so that if in the future the client tries to log in or whatever, it can use the certificate downloaded when added. Log in dialog works ok, showing a toast when authentication fails (by this time, I have not managed to get a correct login due to dev.bitmask.net problems). dev.bitmask.net works perfectly, via adding it as a new provider (MeanderingCode, this is for you ;) ). All GET requests are done by default Android URL class, which means that certificates trusted by Android are also trusted by us. If there are problems when logging in due to certificates, the app is able to use only the certificate associated to the provider in the moment it was selected as the chosen provider. --- src/se/leap/leapclient/ConfigHelper.java | 21 ++- src/se/leap/leapclient/ConfigurationWizard.java | 5 +- src/se/leap/leapclient/Dashboard.java | 4 +- src/se/leap/leapclient/LogInDialog.java | 2 +- src/se/leap/leapclient/ProviderAPI.java | 193 +++++++++++++++--------- src/se/leap/leapclient/ProviderListContent.java | 16 +- 6 files changed, 160 insertions(+), 81 deletions(-) (limited to 'src/se/leap/leapclient') diff --git a/src/se/leap/leapclient/ConfigHelper.java b/src/se/leap/leapclient/ConfigHelper.java index 78c71cc4..7c52629b 100644 --- a/src/se/leap/leapclient/ConfigHelper.java +++ b/src/se/leap/leapclient/ConfigHelper.java @@ -16,6 +16,7 @@ import java.security.cert.CertificateException; import java.security.cert.CertificateFactory; import java.security.cert.X509Certificate; +import org.json.JSONArray; import org.json.JSONException; import org.json.JSONObject; @@ -44,7 +45,7 @@ public class ConfigHelper { public static final String user_directory = "leap_android"; final public static String provider_main_url = "provider_main_url"; final public static String danger_on = "danger_on"; - final public static String api_url_key = "srp_server_url"; + final public static String api_url_key = "api_uri"; final public static String username_key = "username"; final public static String password_key = "password"; final public static String eip_service_api_path = "/config/eip-service.json"; @@ -63,6 +64,20 @@ public class ConfigHelper { final public static int LOGOUT_SUCCESSFUL = 7; final public static int LOGOUT_FAILED = 8; + static String getStringFromSharedPref(String shared_preferences_key) { + String value = ""; + String content = shared_preferences.getString(shared_preferences_key, ""); + try { + JSONObject json_object = new JSONObject(content); + JSONArray names = json_object.names(); + String key = names.getString(0); + value = json_object.getString(key); + } catch (JSONException e) { + value = content; + } + return value; + } + static void saveSharedPref(String shared_preferences_key, JSONObject content) { SharedPreferences.Editor shared_preferences_editor = shared_preferences @@ -164,8 +179,8 @@ public class ConfigHelper { try { // Initialize the keystore with the provided trusted certificates // Also provide the password of the keystore - keystore_trusted.load(leap_keystore, "uer92jf".toCharArray()); - //keystore_trusted.load(null, null); + //keystore_trusted.load(leap_keystore, "uer92jf".toCharArray()); + keystore_trusted.load(null, null); } finally { leap_keystore.close(); } diff --git a/src/se/leap/leapclient/ConfigurationWizard.java b/src/se/leap/leapclient/ConfigurationWizard.java index 9edaa288..3d165211 100644 --- a/src/se/leap/leapclient/ConfigurationWizard.java +++ b/src/se/leap/leapclient/ConfigurationWizard.java @@ -95,7 +95,7 @@ public class ConfigurationWizard extends Activity 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)); + ProviderListContent.addItem(new ProviderItem(provider_name, asset_manager.open(url_files_folder + "/" + url_filepath), custom, true)); // By default, it trusts the provider } } catch (IOException e) { // TODO Auto-generated catch block @@ -163,6 +163,7 @@ public class ConfigurationWizard extends Activity method_and_parameters.putString(ConfigHelper.provider_key, current_provider_item.name); method_and_parameters.putString(ConfigHelper.cert_key, current_provider_item.cert_json_url); method_and_parameters.putString(ConfigHelper.eip_service_key, current_provider_item.eip_service_json_url); + method_and_parameters.putBoolean(ConfigHelper.danger_on, current_provider_item.danger_on); provider_API_command.putExtra(ConfigHelper.downloadJsonFilesBundleExtra, method_and_parameters); provider_API_command.putExtra("receiver", providerAPI_result_receiver); @@ -191,9 +192,9 @@ public class ConfigurationWizard extends Activity 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); provider_API_command.putExtra(ConfigHelper.downloadNewProviderDotJSON, method_and_parameters); - provider_API_command.putExtra(ConfigHelper.danger_on, danger_on); provider_API_command.putExtra("receiver", providerAPI_result_receiver); startService(provider_API_command); diff --git a/src/se/leap/leapclient/Dashboard.java b/src/se/leap/leapclient/Dashboard.java index a169c9d4..577092bb 100644 --- a/src/se/leap/leapclient/Dashboard.java +++ b/src/se/leap/leapclient/Dashboard.java @@ -23,6 +23,7 @@ import android.view.ViewStub; import android.widget.CompoundButton; import android.widget.Switch; import android.widget.TextView; +import android.widget.Toast; public class Dashboard extends Activity implements LogInDialog.LogInDialogInterface, Receiver { @@ -195,11 +196,12 @@ public class Dashboard extends Activity implements LogInDialog.LogInDialogInterf public void onReceiveResult(int resultCode, Bundle resultData) { if(resultCode == ConfigHelper.SRP_AUTHENTICATION_SUCCESSFUL){ setResult(RESULT_OK); + Toast.makeText(getApplicationContext(), "Authentication succeeded", Toast.LENGTH_LONG).show(); //TODO What should we do know? } else if(resultCode == ConfigHelper.SRP_AUTHENTICATION_FAILED) { setResult(RESULT_CANCELED); - finish(); + Toast.makeText(getApplicationContext(), "Authentication failed", Toast.LENGTH_LONG).show(); } } diff --git a/src/se/leap/leapclient/LogInDialog.java b/src/se/leap/leapclient/LogInDialog.java index 61526c69..74db92ea 100644 --- a/src/se/leap/leapclient/LogInDialog.java +++ b/src/se/leap/leapclient/LogInDialog.java @@ -68,6 +68,6 @@ public class LogInDialog extends DialogFragment { } boolean validPassword(String entered_password) { - return entered_password.length() > 8; + return entered_password.length() > 4; } } diff --git a/src/se/leap/leapclient/ProviderAPI.java b/src/se/leap/leapclient/ProviderAPI.java index 63db18e1..04185eda 100644 --- a/src/se/leap/leapclient/ProviderAPI.java +++ b/src/se/leap/leapclient/ProviderAPI.java @@ -1,17 +1,26 @@ package se.leap.leapclient; +import java.io.ByteArrayInputStream; 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.util.List; import java.net.MalformedURLException; import java.net.URL; -import java.net.UnknownHostException; import java.util.Scanner; import javax.net.ssl.HostnameVerifier; import javax.net.ssl.HttpsURLConnection; +import javax.net.ssl.SSLContext; import javax.net.ssl.SSLSession; +import javax.net.ssl.TrustManagerFactory; import org.apache.http.HttpEntity; import org.apache.http.HttpResponse; @@ -36,6 +45,7 @@ import android.app.IntentService; import android.content.Intent; import android.os.Bundle; import android.os.ResultReceiver; +import android.util.Base64; import android.util.Log; public class ProviderAPI extends IntentService { @@ -58,7 +68,7 @@ public class ProviderAPI extends IntentService { } else if ((task = task_for.getBundleExtra(ConfigHelper.downloadNewProviderDotJSON)) != null) { if(downloadNewProviderDotJSON(task)) - receiver.send(ConfigHelper.CORRECTLY_DOWNLOADED_JSON_FILES, Bundle.EMPTY); + receiver.send(ConfigHelper.CUSTOM_PROVIDER_ADDED, Bundle.EMPTY); else receiver.send(ConfigHelper.INCORRECTLY_DOWNLOADED_JSON_FILES, Bundle.EMPTY); } @@ -77,25 +87,21 @@ public class ProviderAPI extends IntentService { } private boolean downloadJsonFiles(Bundle task) { - String cert_url = (String) task.get(ConfigHelper.cert_key); - String eip_service_json_url = (String) task.get(ConfigHelper.eip_service_key); + String provider_name = task.getString(ConfigHelper.provider_key); + String cert_url = task.getString(ConfigHelper.cert_key); + 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); + String cert_string = getStringFromProvider(cert_url, danger_on); + ConfigHelper.addTrustedCertificate(provider_name, cert_string); JSONObject cert_json = new JSONObject("{ \"certificate\" : \"" + cert_string + "\"}"); ConfigHelper.saveSharedPref(ConfigHelper.cert_key, cert_json); - JSONObject eip_service_json = getJSONFromProvider(eip_service_json_url); + JSONObject eip_service_json = getJSONFromProvider(eip_service_json_url, danger_on); ConfigHelper.saveSharedPref(ConfigHelper.eip_service_key, eip_service_json); return true; - } catch (IOException e) { - // TODO - e.printStackTrace(); - return false; } catch (JSONException e) { ConfigHelper.rescueJSONException(e); return false; - } catch(Exception e) { - e.printStackTrace(); - return false; } } @@ -135,7 +141,8 @@ public class ProviderAPI extends IntentService { byte[] M1 = client.response(Bbytes); byte[] M2 = sendM1ToSRPServer(authentication_server, username, M1); if( client.verify(M2) == false ) - throw new SecurityException("Failed to validate server reply: M2 = " + new BigInteger(1, M2).toString(16)); + //throw new SecurityException("Failed to validate server reply: M2 = " + new BigInteger(1, M2).toString(16)); + return false; return true; } else return false; @@ -199,17 +206,14 @@ public class ProviderAPI extends IntentService { private boolean downloadNewProviderDotJSON(Bundle task) { boolean custom = true; - boolean danger_on = ((Boolean)task.get(ConfigHelper.danger_on)).booleanValue(); + boolean danger_on = task.getBoolean(ConfigHelper.danger_on); String provider_main_url = (String) task.get(ConfigHelper.provider_main_url); String provider_name = provider_main_url.replaceFirst("http[s]?://", "").replaceFirst("\\/", "_"); String provider_json_url = guessURL(provider_main_url); JSONObject provider_json = null; try { - provider_json = getJSONFromProvider(provider_json_url); - } catch (IOException e) { - // It could happen that an https site used a certificate not trusted. - provider_json = downloadNewProviderDotJsonWithoutCert(provider_json_url, danger_on); + provider_json = getJSONFromProvider(provider_json_url, danger_on); } catch (JSONException e) { // TODO Auto-generated catch block e.printStackTrace(); @@ -223,75 +227,128 @@ public class ProviderAPI extends IntentService { ConfigHelper.saveFile(filename, provider_json.toString()); ConfigHelper.saveSharedPref(ConfigHelper.provider_key, provider_json); - ProviderListContent.addItem(new ProviderItem(provider_name, ConfigHelper.openFileInputStream(filename), custom)); + ProviderListContent.addItem(new ProviderItem(provider_name, provider_json_url, ConfigHelper.openFileInputStream(filename), custom, danger_on)); return true; } } - private JSONObject downloadNewProviderDotJsonWithoutCert( - String provider_json_url, boolean danger_on) { - JSONObject provider_json = null; - try { - URL provider_url = new URL(provider_json_url); - String provider_json_string = new Scanner(provider_url.openStream()).useDelimiter("\\A").next(); - provider_json = new JSONObject(provider_json_string); - } catch (MalformedURLException e1) { - e1.printStackTrace(); - } catch (UnknownHostException e1) { - e1.printStackTrace(); - } catch (IOException e1) { - if(danger_on) { - provider_json = downloadNewProviderDotJsonWithoutValidate(provider_json_url); - } - else { - //TODO Show error message advising to check the checkbox if the url is completely trusted. - } - e1.printStackTrace(); - } catch (JSONException e1) { - e1.printStackTrace(); - } - return provider_json; - } - - private JSONObject downloadNewProviderDotJsonWithoutValidate( - String provider_json_url) { - JSONObject provider_json = null; + private String getStringFromProviderWithoutValidate( + URL provider_json_url) { + + String json_string = ""; HostnameVerifier hostnameVerifier = new HostnameVerifier() { - @Override - public boolean verify(String hostname, SSLSession session) { - HostnameVerifier hostname_verifier = - HttpsURLConnection.getDefaultHostnameVerifier(); - return hostname_verifier.verify("", session); - } + @Override + public boolean verify(String hostname, SSLSession session) { + return true; + } }; // Tell the URLConnection to use our HostnameVerifier try { - URL url = new URL(provider_json_url); HttpsURLConnection urlConnection = - (HttpsURLConnection)url.openConnection(); - urlConnection.setHostnameVerifier(hostnameVerifier); - String provider_json_string = new Scanner(url.openStream()).useDelimiter("\\A").next(); - provider_json = new JSONObject(provider_json_string); + (HttpsURLConnection)provider_json_url.openConnection(); + urlConnection.setHostnameVerifier(hostnameVerifier); + json_string = new Scanner(urlConnection.getInputStream()).useDelimiter("\\A").next(); } catch (MalformedURLException e) { // TODO Auto-generated catch block e.printStackTrace(); } catch (IOException e) { // TODO Auto-generated catch block - e.printStackTrace(); - } catch (JSONException e) { - // TODO Auto-generated catch block - e.printStackTrace(); + json_string = getStringFromProviderWithCACertAdded(provider_json_url); + //e.printStackTrace(); } - return provider_json; - + return json_string; } private String guessURL(String provider_main_url) { return provider_main_url + "/provider.json"; } + + private String getStringFromProvider(String string_url, boolean danger_on) { + + String json_file_content = ""; + + URL provider_url = null; + try { + provider_url = new URL(string_url); + json_file_content = new Scanner(provider_url.openStream()).useDelimiter("\\A").next(); + } catch (MalformedURLException e) { + // TODO Auto-generated catch block + e.printStackTrace(); + } catch (IOException e) { + // TODO SSLHandshakeException + // This means that we have not added ca.crt to the trusted certificates. + if(provider_url != null && danger_on) { + json_file_content = getStringFromProviderWithoutValidate(provider_url); + } + //json_file_content = downloadStringFromProviderWithCACertAdded(string_url); + e.printStackTrace(); + } + + return json_file_content; + } + + private String getStringFromProviderWithCACertAdded(URL url) { + String json_file_content = ""; + + // Load CAs from an InputStream + // (could be from a resource or ByteArrayInputStream or ...) + CertificateFactory cf; + try { + cf = CertificateFactory.getInstance("X.509"); + + String cert_string = ConfigHelper.getStringFromSharedPref(ConfigHelper.cert_key); + cert_string = cert_string.replaceFirst("-----BEGIN CERTIFICATE-----", "").replaceFirst("-----END CERTIFICATE-----", "").trim(); + byte[] cert_bytes = Base64.decode(cert_string, Base64.DEFAULT); + InputStream caInput = new ByteArrayInputStream(cert_bytes); + java.security.cert.Certificate ca; + try { + ca = cf.generateCertificate(caInput); + System.out.println("ca=" + ((X509Certificate) ca).getSubjectDN()); + } finally { + caInput.close(); + } + + // Create a KeyStore containing our trusted CAs + String keyStoreType = KeyStore.getDefaultType(); + KeyStore keyStore = KeyStore.getInstance(keyStoreType); + keyStore.load(null, null); + keyStore.setCertificateEntry("ca", ca); + + // 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()); + json_file_content = new Scanner(urlConnection.getInputStream()).useDelimiter("\\A").next(); + } catch (CertificateException e) { + // TODO Auto-generated catch block + e.printStackTrace(); + } catch (IOException 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 (KeyManagementException e) { + // TODO Auto-generated catch block + e.printStackTrace(); + } + return json_file_content; + } - private String getStringFromProvider(String string_url) throws IOException { + private String getStringFromProvider_2(String string_url) throws IOException { String json_file_content = ""; @@ -306,8 +363,8 @@ public class ProviderAPI extends IntentService { return json_file_content; } - private JSONObject getJSONFromProvider(String json_url) throws IOException, JSONException { - String json_file_content = getStringFromProvider(json_url); + 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); } diff --git a/src/se/leap/leapclient/ProviderListContent.java b/src/se/leap/leapclient/ProviderListContent.java index dd227bfd..9ed7e9bf 100644 --- a/src/se/leap/leapclient/ProviderListContent.java +++ b/src/se/leap/leapclient/ProviderListContent.java @@ -44,6 +44,7 @@ public class ProviderListContent { public String provider_json_filename; public String eip_service_json_url; public String cert_json_url; + public boolean danger_on = false; public ProviderItem(String id, String name, String provider_json_url, String eip_service_json_url, String cert_json_url) { this.id = id; @@ -53,7 +54,7 @@ public class ProviderListContent { this.cert_json_url = cert_json_url; } - public ProviderItem(String name, InputStream urls_file_input_stream, boolean custom) { + 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()]; @@ -62,11 +63,12 @@ public class ProviderListContent { JSONObject file_contents = new JSONObject(urls_file_content); id = name; this.name = name; - provider_json_url = (String) file_contents.get("json_provider"); - provider_json_filename = (String) file_contents.get("assets_json_provider"); - eip_service_json_url = (String) file_contents.get("json_eip_service"); - cert_json_url = (String) file_contents.get("cert"); + provider_json_url = file_contents.getString("json_provider"); + 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("cert"); this.custom = custom; + this.danger_on = danger_on; } catch (JSONException e) { // TODO Auto-generated catch block e.printStackTrace(); @@ -76,7 +78,7 @@ public class ProviderListContent { } } - public ProviderItem(String name, FileInputStream provider_json, boolean custom) { + public ProviderItem(String name, String provider_json_url, FileInputStream provider_json, boolean custom, boolean danger_on) { try { byte[] urls_file_bytes = new byte[provider_json.available()]; @@ -85,9 +87,11 @@ public class ProviderListContent { JSONObject file_contents = new JSONObject(urls_file_content); id = name; this.name = name; + this.provider_json_url = provider_json_url; eip_service_json_url = (String) file_contents.get("api_uri") + ConfigHelper.eip_service_api_path; cert_json_url = (String) file_contents.get("ca_cert_uri"); this.custom = custom; + this.danger_on = danger_on; if(custom) provider_json_filename = name + "_provider.json".replaceFirst("__", "_"); } catch (JSONException e) { -- cgit v1.2.3 From 09493a9dec5fb235d5c4914eb8f8142e3312e246 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Parm=C3=A9nides=20GV?= Date: Mon, 29 Apr 2013 21:32:10 +0200 Subject: Changed the message shown when checking if the password is valid or not. Refactored LeapSRPSession so that there is no need to send A twice. --- src/se/leap/leapclient/LeapSRPSession.java | 94 ++++++++++++++++-------------- src/se/leap/leapclient/LogInDialog.java | 4 +- src/se/leap/leapclient/ProviderAPI.java | 8 +-- 3 files changed, 57 insertions(+), 49 deletions(-) (limited to 'src/se/leap/leapclient') diff --git a/src/se/leap/leapclient/LeapSRPSession.java b/src/se/leap/leapclient/LeapSRPSession.java index d266cd7f..f9037de9 100644 --- a/src/se/leap/leapclient/LeapSRPSession.java +++ b/src/se/leap/leapclient/LeapSRPSession.java @@ -14,7 +14,10 @@ import org.jboss.security.srp.SRPPermission; public class LeapSRPSession { 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; @@ -58,9 +61,11 @@ public class LeapSRPSession { this.params = params; this.g = new BigInteger(1, params.g); - byte[] N_bytes = Util.trim(params.N); + N_bytes = Util.trim(params.N); this.N = new BigInteger(1, N_bytes); - + this.username = username; + this.password = password; + if( abytes != null ) { A_LEN = 8*abytes.length; /* TODO Why did they put this condition? @@ -73,41 +78,8 @@ public class LeapSRPSession { else A_LEN = 64; - // Calculate x = H(s | H(U | ':' | password)) - byte[] salt_bytes = Util.trim(params.s); - byte[] xb = calculatePasswordHash(username, password, salt_bytes); - this.x = new BigInteger(1, xb); - - // Calculate v = kg^x mod N - String k_string = "bf66c44a428916cad64aa7c679f3fd897ad4c375e9bbb4cbf2f5de241d618ef0"; - this.v = calculateV(k_string); - //String v_string = v.toString(16); - serverHash = newDigest(); clientHash = newDigest(); - - // 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, digest_of_g.length); - //String hxg_string = new BigInteger(1, xor_digest).toString(16); - clientHash.update(xor_digest); - - // clientHash = H(N) xor H(g) | H(U) - byte[] username_digest = newDigest().digest(Util.trim(username.getBytes())); - username_digest = Util.trim(username_digest); - //String username_digest_string = new BigInteger(1, username_digest).toString(16); - clientHash.update(username_digest); - - // clientHash = H(N) xor H(g) | H(U) | s - //String salt_string = new BigInteger(1, salt_bytes).toString(16); - clientHash.update(salt_bytes); - - K = null; } /** @@ -198,13 +170,6 @@ public class LeapSRPSession { } A = g.modPow(a, N); Abytes = Util.trim(A.toByteArray()); - //String Abytes_string = new BigInteger(1, Abytes).toString(16); - - // clientHash = H(N) xor H(g) | H(U) | A - clientHash.update(Abytes); - - // serverHash = A - serverHash.update(Abytes); } return Abytes; } @@ -213,10 +178,52 @@ public class LeapSRPSession { * 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. * @param Bbytes the parameter received from the server, in bytes + * @param bs * @return the parameter M1 * @throws NoSuchAlgorithmException */ - public byte[] response(byte[] Bbytes) throws NoSuchAlgorithmException { + public byte[] response(byte[] salt_bytes, byte[] Bbytes) throws NoSuchAlgorithmException { + // Calculate x = H(s | H(U | ':' | password)) + byte[] xb = calculatePasswordHash(username, password, salt_bytes); + this.x = new BigInteger(1, xb); + + // Calculate v = kg^x mod N + String k_string = "bf66c44a428916cad64aa7c679f3fd897ad4c375e9bbb4cbf2f5de241d618ef0"; + this.v = calculateV(k_string); + //String v_string = v.toString(16); + + + // 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, digest_of_g.length); + //String hxg_string = new BigInteger(1, xor_digest).toString(16); + clientHash.update(xor_digest); + + // clientHash = H(N) xor H(g) | H(U) + byte[] username_digest = newDigest().digest(Util.trim(username.getBytes())); + username_digest = Util.trim(username_digest); + //String username_digest_string = new BigInteger(1, username_digest).toString(16); + clientHash.update(username_digest); + + // clientHash = H(N) xor H(g) | H(U) | s + //String salt_string = new BigInteger(1, salt_bytes).toString(16); + clientHash.update(Util.trim(salt_bytes)); + + K = null; + + // clientHash = H(N) xor H(g) | H(U) | s | A | B + + byte[] Abytes = Util.trim(A.toByteArray()); + //String Abytes_string = new BigInteger(1, Abytes).toString(16); + + // clientHash = H(N) xor H(g) | H(U) | A + clientHash.update(Abytes); + // clientHash = H(N) xor H(g) | H(U) | s | A | B Bbytes = Util.trim(Bbytes); //String Bbytes_string = new BigInteger(1, Bbytes).toString(16); @@ -239,6 +246,7 @@ public class LeapSRPSession { byte[] M1 = Util.trim(clientHash.digest()); // serverHash = Astr + M + K + serverHash.update(Abytes); serverHash.update(M1); serverHash.update(K); return M1; diff --git a/src/se/leap/leapclient/LogInDialog.java b/src/se/leap/leapclient/LogInDialog.java index 74db92ea..30984db6 100644 --- a/src/se/leap/leapclient/LogInDialog.java +++ b/src/se/leap/leapclient/LogInDialog.java @@ -51,10 +51,10 @@ public class LogInDialog extends DialogFragment { String password = password_field.getText().toString().trim(); if(validPassword(password)) { interface_with_Dashboard.authenticate(username, password); - Toast.makeText(getActivity().getApplicationContext(), "It seems your URL is well formed", Toast.LENGTH_LONG).show(); + Toast.makeText(getActivity().getApplicationContext(), "Your password is valid", Toast.LENGTH_LONG).show(); } else { password_field.setText(""); - Toast.makeText(getActivity().getApplicationContext(), "It seems your URL is not well formed", Toast.LENGTH_LONG).show(); + Toast.makeText(getActivity().getApplicationContext(), "Your password is not valid: it should have at least 8 characters", Toast.LENGTH_LONG).show(); } } }) diff --git a/src/se/leap/leapclient/ProviderAPI.java b/src/se/leap/leapclient/ProviderAPI.java index 04185eda..66eb3e60 100644 --- a/src/se/leap/leapclient/ProviderAPI.java +++ b/src/se/leap/leapclient/ProviderAPI.java @@ -131,14 +131,14 @@ public class ProviderAPI extends IntentService { try { JSONObject saltAndB = sendAToSRPServer(authentication_server, username, new BigInteger(1, A).toString(16)); if(saltAndB.length() > 0) { - byte[] B = saltAndB.getString("B").getBytes(); - salt = saltAndB.getString("salt"); + /*byte[] B = saltAndB.getString("B").getBytes(); params = new SRPParameters(new BigInteger(ConfigHelper.NG_1024, 16).toByteArray(), new BigInteger("2").toByteArray(), new BigInteger(salt, 16).toByteArray(), "SHA-256"); client = new LeapSRPSession(username, password, params); A = client.exponential(); - saltAndB = sendAToSRPServer(authentication_server, username, new BigInteger(1, A).toString(16)); + saltAndB = sendAToSRPServer(authentication_server, username, new BigInteger(1, A).toString(16));*/ + salt = saltAndB.getString("salt"); byte[] Bbytes = new BigInteger(saltAndB.getString("B"), 16).toByteArray(); - byte[] M1 = client.response(Bbytes); + byte[] M1 = client.response(new BigInteger(salt, 16).toByteArray(), Bbytes); byte[] M2 = sendM1ToSRPServer(authentication_server, username, M1); if( client.verify(M2) == false ) //throw new SecurityException("Failed to validate server reply: M2 = " + new BigInteger(1, M2).toString(16)); -- cgit v1.2.3 From ff3d469a9549e3670e097fc0e49c043c84e7b7d4 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Parm=C3=A9nides=20GV?= Date: Wed, 1 May 2013 18:41:05 +0200 Subject: If the app is restarted with a custom provider selected, the client can request a log in without certificates problems. I've removed the addition of the certificate when downloaded eip-service.json, because I already do that in LeapHttpClient. Solves issue 2367: https://leap.se/code/issues/2367 --- src/se/leap/leapclient/ConfigHelper.java | 16 ++++++++++++---- src/se/leap/leapclient/Dashboard.java | 4 +++- src/se/leap/leapclient/LeapHttpClient.java | 7 ++++++- src/se/leap/leapclient/ProviderAPI.java | 8 ++++++-- src/se/leap/leapclient/ProviderListContent.java | 2 +- 5 files changed, 28 insertions(+), 9 deletions(-) (limited to 'src/se/leap/leapclient') diff --git a/src/se/leap/leapclient/ConfigHelper.java b/src/se/leap/leapclient/ConfigHelper.java index 7c52629b..76845228 100644 --- a/src/se/leap/leapclient/ConfigHelper.java +++ b/src/se/leap/leapclient/ConfigHelper.java @@ -48,7 +48,7 @@ public class ConfigHelper { final public static String api_url_key = "api_uri"; final public static String username_key = "username"; final public static String password_key = "password"; - final public static String eip_service_api_path = "/config/eip-service.json"; + final public static String eip_service_api_path = "config/eip-service.json"; final public static String NG_1024 = "eeaf0ab9adb38dd69c33f80afa8fc5e86072618775ff3c0b9ea2314c9c256576d674df7496ea81d3383b4813d692c6e0e0d5d8e250b98be48e495c1d6089dad15dc7d7b46154d6b6ce8ef4ad69b15d4982559b297bcf1885c529f566660e57ec68edbc3c05726cc02fd4cbf4976eaa9afd5138fe8376435b9fc61d2fc0eb06e3"; @@ -159,6 +159,9 @@ public class ConfigHelper { cf = CertificateFactory.getInstance("X.509"); X509Certificate cert = (X509Certificate)cf.generateCertificate(openFileInputStream(filename_to_save)); + if(keystore_trusted == null) { + getNewKeystore(null); + } keystore_trusted.setCertificateEntry(provider, cert); } catch (CertificateException e) { // TODO Auto-generated catch block @@ -179,10 +182,15 @@ public class ConfigHelper { try { // Initialize the keystore with the provided trusted certificates // Also provide the password of the keystore - //keystore_trusted.load(leap_keystore, "uer92jf".toCharArray()); - keystore_trusted.load(null, null); + if(leap_keystore != null) { + //keystore_trusted.load(leap_keystore, "uer92jf".toCharArray()); + keystore_trusted.load(null, null); + } else { + keystore_trusted.load(null, null); + } } finally { - leap_keystore.close(); + if(leap_keystore != null) + leap_keystore.close(); } } catch (KeyStoreException e) { // TODO Auto-generated catch block diff --git a/src/se/leap/leapclient/Dashboard.java b/src/se/leap/leapclient/Dashboard.java index 577092bb..a68c048b 100644 --- a/src/se/leap/leapclient/Dashboard.java +++ b/src/se/leap/leapclient/Dashboard.java @@ -43,7 +43,9 @@ public class Dashboard extends Activity implements LogInDialog.LogInDialogInterf setContentView(R.layout.client_dashboard); preferences = getSharedPreferences(ConfigHelper.PREFERENCES_KEY,MODE_PRIVATE); - + if(ConfigHelper.shared_preferences == null) + ConfigHelper.setSharedPreferences(preferences); + // Check if we have preferences, run configuration wizard if not // TODO We should do a better check for config that this! if (!preferences.contains("provider") ) diff --git a/src/se/leap/leapclient/LeapHttpClient.java b/src/se/leap/leapclient/LeapHttpClient.java index d1908c34..f9119823 100644 --- a/src/se/leap/leapclient/LeapHttpClient.java +++ b/src/se/leap/leapclient/LeapHttpClient.java @@ -51,8 +51,13 @@ public class LeapHttpClient extends DefaultHttpClient { } public static LeapHttpClient getInstance(Context context) { - if(client == null) + if(client == null) { client = new LeapHttpClient(context); + String cert_string = ConfigHelper.getStringFromSharedPref(ConfigHelper.cert_key); + if(!cert_string.isEmpty()) { + ConfigHelper.addTrustedCertificate("recovered_certificate", cert_string); + } + } return client; } } diff --git a/src/se/leap/leapclient/ProviderAPI.java b/src/se/leap/leapclient/ProviderAPI.java index 66eb3e60..4a288787 100644 --- a/src/se/leap/leapclient/ProviderAPI.java +++ b/src/se/leap/leapclient/ProviderAPI.java @@ -93,7 +93,7 @@ public class ProviderAPI extends IntentService { boolean danger_on = task.getBoolean(ConfigHelper.danger_on); try { String cert_string = getStringFromProvider(cert_url, danger_on); - ConfigHelper.addTrustedCertificate(provider_name, cert_string); + //ConfigHelper.addTrustedCertificate(provider_name, cert_string); JSONObject cert_json = new JSONObject("{ \"certificate\" : \"" + cert_string + "\"}"); ConfigHelper.saveSharedPref(ConfigHelper.cert_key, cert_json); JSONObject eip_service_json = getJSONFromProvider(eip_service_json_url, danger_on); @@ -177,9 +177,11 @@ public class ProviderAPI extends IntentService { if(!json_response.isNull("errors") || json_response.has("errors")) { return new JSONObject(); } + + String session_id = ""; List cookies = client.getCookieStore().getCookies(); if(!cookies.isEmpty()) { - String session_id = cookies.get(0).getValue(); + session_id = cookies.get(0).getValue(); } return json_response; } @@ -190,6 +192,8 @@ public class ProviderAPI extends IntentService { HttpPut put = new HttpPut(server_url + "/sessions/" + username +".json" + "?" + parameter_chain); HttpContext localContext = new BasicHttpContext(); localContext.setAttribute(ClientContext.COOKIE_STORE, client.getCookieStore()); + String session_id = client.getCookieStore().getCookies().get(0).getValue(); + int number_of_cookies = client.getCookieStore().getCookies().size(); HttpResponse getResponse = client.execute(put, localContext); HttpEntity responseEntity = getResponse.getEntity(); diff --git a/src/se/leap/leapclient/ProviderListContent.java b/src/se/leap/leapclient/ProviderListContent.java index 9ed7e9bf..8cc349c2 100644 --- a/src/se/leap/leapclient/ProviderListContent.java +++ b/src/se/leap/leapclient/ProviderListContent.java @@ -88,7 +88,7 @@ public class ProviderListContent { id = name; this.name = name; this.provider_json_url = provider_json_url; - eip_service_json_url = (String) file_contents.get("api_uri") + ConfigHelper.eip_service_api_path; + eip_service_json_url = file_contents.getString("api_uri") + "/" + file_contents.getString("api_version") + "/" + ConfigHelper.eip_service_api_path; cert_json_url = (String) file_contents.get("ca_cert_uri"); this.custom = custom; this.danger_on = danger_on; -- cgit v1.2.3 From a16605fd16a87faa5fa530288e01f0d7c7c7bf98 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Parm=C3=A9nides=20GV?= Date: Wed, 1 May 2013 19:01:16 +0200 Subject: Logging in successfully to dev.bitmask.net :) The problem was that I needed to append the api_version to the api_uri. I was doing well in tests because I hardcoded the api urls, but in production code I was getting from provider.json only api_url and not api_version. --- src/se/leap/leapclient/ConfigHelper.java | 1 + src/se/leap/leapclient/Dashboard.java | 2 +- 2 files changed, 2 insertions(+), 1 deletion(-) (limited to 'src/se/leap/leapclient') diff --git a/src/se/leap/leapclient/ConfigHelper.java b/src/se/leap/leapclient/ConfigHelper.java index 76845228..72d966b8 100644 --- a/src/se/leap/leapclient/ConfigHelper.java +++ b/src/se/leap/leapclient/ConfigHelper.java @@ -37,6 +37,7 @@ public class ConfigHelper { final public static String srpAuth = "srpAuth"; public static String logIn = "logIn"; public static String logOut = "logOut"; + public static String api_version_key = "api_version"; final public static String resultKey = "result"; final static String provider_key = "provider"; final static String cert_key = "cert"; diff --git a/src/se/leap/leapclient/Dashboard.java b/src/se/leap/leapclient/Dashboard.java index a68c048b..67e33e77 100644 --- a/src/se/leap/leapclient/Dashboard.java +++ b/src/se/leap/leapclient/Dashboard.java @@ -170,7 +170,7 @@ public class Dashboard extends Activity implements LogInDialog.LogInDialogInterf 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)); + method_and_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(); -- cgit v1.2.3 From 0cb5d9470127e280d2d955effd32b82e533d9de3 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Parm=C3=A9nides=20GV?= Date: Tue, 7 May 2013 16:10:20 +0200 Subject: Ready to create a new branch for the download of the new user auth'ed certificate. Next step in this branch: detect what the selected provider support in terms of authenticated/anon users, and show login/logout methods consecuently. --- src/se/leap/leapclient/Dashboard.java | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) (limited to 'src/se/leap/leapclient') diff --git a/src/se/leap/leapclient/Dashboard.java b/src/se/leap/leapclient/Dashboard.java index 67e33e77..04445023 100644 --- a/src/se/leap/leapclient/Dashboard.java +++ b/src/se/leap/leapclient/Dashboard.java @@ -199,7 +199,8 @@ public class Dashboard extends Activity implements LogInDialog.LogInDialogInterf if(resultCode == ConfigHelper.SRP_AUTHENTICATION_SUCCESSFUL){ setResult(RESULT_OK); Toast.makeText(getApplicationContext(), "Authentication succeeded", Toast.LENGTH_LONG).show(); - //TODO What should we do know? + //TODO Download certificate requesting /1/cert with session_id cookie + } else if(resultCode == ConfigHelper.SRP_AUTHENTICATION_FAILED) { setResult(RESULT_CANCELED); -- cgit v1.2.3 From fb5e26c2ff4f95dd826a3ce3545865ac4388b711 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Parm=C3=A9nides=20GV?= Date: Wed, 8 May 2013 18:23:10 +0200 Subject: After loggin in successfully, the new client certificate is downloaded. It is stored in SharedPrefs, with ConfigHelper.cert_key (="cert") key. --- src/se/leap/leapclient/ConfigHelper.java | 27 +++-- src/se/leap/leapclient/ConfigurationWizard.java | 8 +- src/se/leap/leapclient/Dashboard.java | 31 ++++- src/se/leap/leapclient/LeapHttpClient.java | 17 ++- src/se/leap/leapclient/ProviderAPI.java | 146 ++++++++++++++++-------- 5 files changed, 170 insertions(+), 59 deletions(-) (limited to 'src/se/leap/leapclient') diff --git a/src/se/leap/leapclient/ConfigHelper.java b/src/se/leap/leapclient/ConfigHelper.java index 72d966b8..98761b61 100644 --- a/src/se/leap/leapclient/ConfigHelper.java +++ b/src/se/leap/leapclient/ConfigHelper.java @@ -37,11 +37,15 @@ public class ConfigHelper { final public static String srpAuth = "srpAuth"; public static String logIn = "logIn"; public static String logOut = "logOut"; + public static String downloadUserAuthedCertificate = "downloadUserAuthedCertificate"; public static String api_version_key = "api_version"; final public static String resultKey = "result"; final static String provider_key = "provider"; + final static String main_cert_key = "main_cert"; final static String cert_key = "cert"; final static String eip_service_key = "eip"; + final static String session_id_cookie_key = "session_id_cookie_key"; + final static String session_id_key = "session_id"; public static final String PREFERENCES_KEY = "LEAPPreferences"; public static final String user_directory = "leap_android"; final public static String provider_main_url = "provider_main_url"; @@ -64,17 +68,23 @@ public class ConfigHelper { final public static int SRP_REGISTRATION_FAILED = 6; final public static int LOGOUT_SUCCESSFUL = 7; final public static int LOGOUT_FAILED = 8; + final public static int CORRECTLY_DOWNLOADED_AUTHED_USER_CERTIFICATE = 9; + final public static int INCORRECTLY_DOWNLOADED_AUTHED_USER_CERTIFICATE = 10; static String getStringFromSharedPref(String shared_preferences_key) { String value = ""; - String content = shared_preferences.getString(shared_preferences_key, ""); - try { - JSONObject json_object = new JSONObject(content); - JSONArray names = json_object.names(); - String key = names.getString(0); - value = json_object.getString(key); - } catch (JSONException e) { - value = content; + //TODO This is not OK -> when reading provider.json it only shows "open" + if(shared_preferences != null) { + String content = shared_preferences.getString(shared_preferences_key, ""); + try { + JSONObject json_object = new JSONObject(content); + value = json_object.toString(); + /*JSONArray names = json_object.names(); + String key = names.getString(0); + value = json_object.getString(key);*/ + } catch (JSONException e) { + value = content; + } } return value; } @@ -184,6 +194,7 @@ public class ConfigHelper { // Initialize the keystore with the provided trusted certificates // Also provide the password of the keystore if(leap_keystore != null) { + InputStream android_default_keystore; //keystore_trusted.load(leap_keystore, "uer92jf".toCharArray()); keystore_trusted.load(null, null); } else { diff --git a/src/se/leap/leapclient/ConfigurationWizard.java b/src/se/leap/leapclient/ConfigurationWizard.java index 3d165211..a50a8e62 100644 --- a/src/se/leap/leapclient/ConfigurationWizard.java +++ b/src/se/leap/leapclient/ConfigurationWizard.java @@ -150,6 +150,12 @@ public class ConfigurationWizard extends Activity ConfigHelper.rescueJSONException(e); } ConfigHelper.saveSharedPref(ConfigHelper.provider_key, provider_json); + try { + ConfigHelper.saveSharedPref(ConfigHelper.danger_on, new JSONObject().put(ConfigHelper.danger_on, current_provider_item.danger_on)); + } catch (JSONException e) { + // TODO Auto-generated catch block + e.printStackTrace(); + } } private void downloadJSONFiles(ProviderItem current_provider_item) throws IOException { @@ -161,7 +167,7 @@ public class ConfigurationWizard extends Activity Bundle method_and_parameters = new Bundle(); method_and_parameters.putString(ConfigHelper.provider_key, current_provider_item.name); - method_and_parameters.putString(ConfigHelper.cert_key, current_provider_item.cert_json_url); + method_and_parameters.putString(ConfigHelper.main_cert_key, current_provider_item.cert_json_url); method_and_parameters.putString(ConfigHelper.eip_service_key, current_provider_item.eip_service_json_url); method_and_parameters.putBoolean(ConfigHelper.danger_on, current_provider_item.danger_on); diff --git a/src/se/leap/leapclient/Dashboard.java b/src/se/leap/leapclient/Dashboard.java index 04445023..dbee9c48 100644 --- a/src/se/leap/leapclient/Dashboard.java +++ b/src/se/leap/leapclient/Dashboard.java @@ -1,5 +1,7 @@ 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; @@ -194,18 +196,45 @@ public class Dashboard extends Activity implements LogInDialog.LogInDialogInterf newFragment.show(fragment_transaction, ConfigHelper.logInDialog); } + 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 method_and_parameters = new Bundle(); + method_and_parameters.putString(ConfigHelper.session_id_cookie_key, session_id.getName()); + method_and_parameters.putString(ConfigHelper.session_id_key, session_id.getValue()); + + provider_API_command.putExtra(ConfigHelper.downloadUserAuthedCertificate, method_and_parameters); + provider_API_command.putExtra("receiver", providerAPI_result_receiver); + + startService(provider_API_command); + } + @Override public void onReceiveResult(int resultCode, Bundle resultData) { if(resultCode == ConfigHelper.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); Toast.makeText(getApplicationContext(), "Authentication succeeded", Toast.LENGTH_LONG).show(); //TODO Download certificate requesting /1/cert with session_id cookie - + Cookie session_id = new BasicClientCookie(session_id_cookie_key, session_id_string); + downloadAuthedUserCertificate(session_id); } else if(resultCode == ConfigHelper.SRP_AUTHENTICATION_FAILED) { setResult(RESULT_CANCELED); Toast.makeText(getApplicationContext(), "Authentication failed", Toast.LENGTH_LONG).show(); } + else if(resultCode == ConfigHelper.CORRECTLY_DOWNLOADED_AUTHED_USER_CERTIFICATE) { + setResult(RESULT_CANCELED); + Toast.makeText(getApplicationContext(), "Your own cert has been correctly downloaded", Toast.LENGTH_LONG).show(); + } + else if(resultCode == ConfigHelper.INCORRECTLY_DOWNLOADED_AUTHED_USER_CERTIFICATE) { + setResult(RESULT_CANCELED); + Toast.makeText(getApplicationContext(), "Your own cert has incorrectly been downloaded", Toast.LENGTH_LONG).show(); + } } } diff --git a/src/se/leap/leapclient/LeapHttpClient.java b/src/se/leap/leapclient/LeapHttpClient.java index f9119823..4de7ae08 100644 --- a/src/se/leap/leapclient/LeapHttpClient.java +++ b/src/se/leap/leapclient/LeapHttpClient.java @@ -9,6 +9,8 @@ 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 org.json.JSONException; +import org.json.JSONObject; import android.content.Context; @@ -49,13 +51,20 @@ public class LeapHttpClient extends DefaultHttpClient { throw new AssertionError(e); } } - + public static LeapHttpClient getInstance(Context context) { if(client == null) { client = new LeapHttpClient(context); - String cert_string = ConfigHelper.getStringFromSharedPref(ConfigHelper.cert_key); - if(!cert_string.isEmpty()) { - ConfigHelper.addTrustedCertificate("recovered_certificate", cert_string); + String cert_json_string = ConfigHelper.getStringFromSharedPref(ConfigHelper.main_cert_key); + String cert_string; + try { + cert_string = new JSONObject(cert_json_string).getString(ConfigHelper.main_cert_key); + if(!cert_string.isEmpty()) { + ConfigHelper.addTrustedCertificate("recovered_certificate", cert_string); + } + } catch (JSONException e) { + // TODO Auto-generated catch block + e.printStackTrace(); } } return client; diff --git a/src/se/leap/leapclient/ProviderAPI.java b/src/se/leap/leapclient/ProviderAPI.java index 4a288787..bdfd6207 100644 --- a/src/se/leap/leapclient/ProviderAPI.java +++ b/src/se/leap/leapclient/ProviderAPI.java @@ -12,7 +12,12 @@ import java.security.cert.CertificateException; import java.security.cert.CertificateFactory; import java.security.cert.X509Certificate; import java.util.List; +import java.net.CookieHandler; +import java.net.CookieManager; +import java.net.HttpCookie; +import java.net.HttpURLConnection; import java.net.MalformedURLException; +import java.net.URISyntaxException; import java.net.URL; import java.util.Scanner; @@ -25,13 +30,16 @@ import javax.net.ssl.TrustManagerFactory; import org.apache.http.HttpEntity; import org.apache.http.HttpResponse; import org.apache.http.client.ClientProtocolException; +import org.apache.http.client.CookieStore; import org.apache.http.client.methods.HttpDelete; import org.apache.http.client.methods.HttpGet; import org.apache.http.client.methods.HttpPost; import org.apache.http.client.methods.HttpPut; import org.apache.http.client.protocol.ClientContext; import org.apache.http.cookie.Cookie; +import org.apache.http.impl.client.BasicCookieStore; import org.apache.http.impl.client.DefaultHttpClient; +import org.apache.http.impl.cookie.BasicClientCookie; import org.apache.http.protocol.BasicHttpContext; import org.apache.http.protocol.HttpContext; import org.jboss.security.Util; @@ -73,10 +81,20 @@ public class ProviderAPI extends IntentService { receiver.send(ConfigHelper.INCORRECTLY_DOWNLOADED_JSON_FILES, Bundle.EMPTY); } else if ((task = task_for.getBundleExtra(ConfigHelper.srpAuth)) != null) { - if(authenticateBySRP(task)) - receiver.send(ConfigHelper.SRP_AUTHENTICATION_SUCCESSFUL, Bundle.EMPTY); - else - receiver.send(ConfigHelper.SRP_AUTHENTICATION_FAILED, Bundle.EMPTY); + try { + JSONObject session_idAndResult = authenticateBySRP(task); + if(session_idAndResult.getBoolean(ConfigHelper.resultKey)) { + Bundle session_id_bundle = new Bundle(); + session_id_bundle.putString(ConfigHelper.session_id_cookie_key, session_idAndResult.getString(ConfigHelper.session_id_cookie_key)); + session_id_bundle.putString(ConfigHelper.session_id_key, session_idAndResult.getString(ConfigHelper.session_id_key)); + receiver.send(ConfigHelper.SRP_AUTHENTICATION_SUCCESSFUL, session_id_bundle); + } else { + receiver.send(ConfigHelper.SRP_AUTHENTICATION_FAILED, Bundle.EMPTY); + } + } catch (JSONException e) { + // TODO Auto-generated catch block + e.printStackTrace(); + } } else if ((task = task_for.getBundleExtra(ConfigHelper.logOut)) != null) { if(logOut(task)) @@ -84,18 +102,24 @@ public class ProviderAPI extends IntentService { else receiver.send(ConfigHelper.LOGOUT_FAILED, Bundle.EMPTY); } + else if ((task = task_for.getBundleExtra(ConfigHelper.downloadUserAuthedCertificate)) != null) { + if(getNewCert(task)) + receiver.send(ConfigHelper.CORRECTLY_DOWNLOADED_AUTHED_USER_CERTIFICATE, Bundle.EMPTY); + else + receiver.send(ConfigHelper.INCORRECTLY_DOWNLOADED_AUTHED_USER_CERTIFICATE, Bundle.EMPTY); + } } private boolean downloadJsonFiles(Bundle task) { - String provider_name = task.getString(ConfigHelper.provider_key); - String cert_url = task.getString(ConfigHelper.cert_key); + //String provider_name = task.getString(ConfigHelper.provider_key); + 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); try { String cert_string = getStringFromProvider(cert_url, danger_on); //ConfigHelper.addTrustedCertificate(provider_name, cert_string); - JSONObject cert_json = new JSONObject("{ \"certificate\" : \"" + cert_string + "\"}"); - ConfigHelper.saveSharedPref(ConfigHelper.cert_key, cert_json); + JSONObject cert_json = new JSONObject().put(ConfigHelper.main_cert_key, cert_string); + ConfigHelper.saveSharedPref(ConfigHelper.main_cert_key, cert_json); JSONObject eip_service_json = getJSONFromProvider(eip_service_json_url, danger_on); ConfigHelper.saveSharedPref(ConfigHelper.eip_service_key, eip_service_json); return true; @@ -117,7 +141,9 @@ public class ProviderAPI extends IntentService { return false; } - private boolean authenticateBySRP(Bundle task) { + private JSONObject authenticateBySRP(Bundle task) { + JSONObject successfulAndsession_id = new JSONObject(); + String username = (String) task.get(ConfigHelper.username_key); String password = (String) task.get(ConfigHelper.password_key); String authentication_server = (String) task.get(ConfigHelper.api_url_key); @@ -131,38 +157,36 @@ public class ProviderAPI extends IntentService { try { JSONObject saltAndB = sendAToSRPServer(authentication_server, username, new BigInteger(1, A).toString(16)); if(saltAndB.length() > 0) { - /*byte[] B = saltAndB.getString("B").getBytes(); - params = new SRPParameters(new BigInteger(ConfigHelper.NG_1024, 16).toByteArray(), new BigInteger("2").toByteArray(), new BigInteger(salt, 16).toByteArray(), "SHA-256"); - client = new LeapSRPSession(username, password, params); - A = client.exponential(); - saltAndB = sendAToSRPServer(authentication_server, username, new BigInteger(1, A).toString(16));*/ salt = saltAndB.getString("salt"); byte[] Bbytes = new BigInteger(saltAndB.getString("B"), 16).toByteArray(); byte[] M1 = client.response(new BigInteger(salt, 16).toByteArray(), Bbytes); - byte[] M2 = sendM1ToSRPServer(authentication_server, username, M1); - if( client.verify(M2) == false ) + //byte[] M2 = sendM1ToSRPServer(authentication_server, username, M1); + JSONObject session_idAndM2 = sendM1ToSRPServer(authentication_server, username, M1); + if( client.verify((byte[])session_idAndM2.get("M2")) == false ) { //throw new SecurityException("Failed to validate server reply: M2 = " + new BigInteger(1, M2).toString(16)); - return false; - return true; + successfulAndsession_id.put(ConfigHelper.resultKey, false); + return successfulAndsession_id; + } else { + successfulAndsession_id.put(ConfigHelper.resultKey, true); + successfulAndsession_id.put(ConfigHelper.session_id_key, session_idAndM2.getString(ConfigHelper.session_id_key)); + successfulAndsession_id.put(ConfigHelper.session_id_cookie_key, session_idAndM2.getString(ConfigHelper.session_id_cookie_key)); + return successfulAndsession_id; + } } - else return false; } catch (ClientProtocolException e1) { // TODO Auto-generated catch block e1.printStackTrace(); - return false; } catch (IOException e1) { // TODO Auto-generated catch block e1.printStackTrace(); - return false; } catch (JSONException e1) { // TODO Auto-generated catch block e1.printStackTrace(); - return false; } catch (NoSuchAlgorithmException e) { // TODO Auto-generated catch block e.printStackTrace(); - return false; } + return successfulAndsession_id; } private JSONObject sendAToSRPServer(String server_url, String username, String clientA) throws ClientProtocolException, IOException, JSONException { @@ -186,7 +210,8 @@ public class ProviderAPI extends IntentService { return json_response; } - private byte[] sendM1ToSRPServer(String server_url, String username, byte[] m1) throws ClientProtocolException, IOException, JSONException { + private JSONObject sendM1ToSRPServer(String server_url, String username, byte[] m1) throws ClientProtocolException, IOException, JSONException { + JSONObject session_idAndM2 = new JSONObject(); DefaultHttpClient client = LeapHttpClient.getInstance(getApplicationContext()); String parameter_chain = "client_auth" + "=" + new BigInteger(1, Util.trim(m1)).toString(16); HttpPut put = new HttpPut(server_url + "/sessions/" + username +".json" + "?" + parameter_chain); @@ -200,12 +225,15 @@ public class ProviderAPI extends IntentService { String plain_response = new Scanner(responseEntity.getContent()).useDelimiter("\\A").next(); JSONObject json_response = new JSONObject(plain_response); if(!json_response.isNull("errors") || json_response.has("errors")) { - return new byte[0]; + return session_idAndM2; } - + + number_of_cookies = client.getCookieStore().getCookies().size(); byte[] M2_not_trimmed = new BigInteger(json_response.getString("M2"), 16).toByteArray(); - return Util.trim(M2_not_trimmed); - //return M2_not_trimmed; + session_idAndM2.put(ConfigHelper.session_id_cookie_key, client.getCookieStore().getCookies().get(0).getName()); + session_idAndM2.put(ConfigHelper.session_id_key, client.getCookieStore().getCookies().get(0).getValue()); + session_idAndM2.put("M2", Util.trim(M2_not_trimmed)); + return session_idAndM2; } private boolean downloadNewProviderDotJSON(Bundle task) { @@ -229,7 +257,7 @@ public class ProviderAPI extends IntentService { } else { String filename = provider_name + "_provider.json".replaceFirst("__", "_"); ConfigHelper.saveFile(filename, provider_json.toString()); - ConfigHelper.saveSharedPref(ConfigHelper.provider_key, provider_json); + //ConfigHelper.saveSharedPref(ConfigHelper.provider_key, provider_json); ProviderListContent.addItem(new ProviderItem(provider_name, provider_json_url, ConfigHelper.openFileInputStream(filename), custom, danger_on)); return true; @@ -301,7 +329,8 @@ public class ProviderAPI extends IntentService { try { cf = CertificateFactory.getInstance("X.509"); - String cert_string = ConfigHelper.getStringFromSharedPref(ConfigHelper.cert_key); + String cert_json_string = ConfigHelper.getStringFromSharedPref(ConfigHelper.main_cert_key); + String cert_string = new JSONObject(cert_json_string).getString(ConfigHelper.main_cert_key); cert_string = cert_string.replaceFirst("-----BEGIN CERTIFICATE-----", "").replaceFirst("-----END CERTIFICATE-----", "").trim(); byte[] cert_bytes = Base64.decode(cert_string, Base64.DEFAULT); InputStream caInput = new ByteArrayInputStream(cert_bytes); @@ -348,24 +377,12 @@ public class ProviderAPI extends IntentService { } catch (KeyManagementException e) { // TODO Auto-generated catch block e.printStackTrace(); + } catch (JSONException e) { + // TODO Auto-generated catch block + e.printStackTrace(); } return json_file_content; } - - private String getStringFromProvider_2(String string_url) throws IOException { - - String json_file_content = ""; - - DefaultHttpClient client = LeapHttpClient.getInstance(getApplicationContext()); - HttpGet get = new HttpGet(string_url); - // Execute the GET call and obtain the response - HttpResponse getResponse = client.execute(get); - HttpEntity responseEntity = getResponse.getEntity(); - - json_file_content = new Scanner(responseEntity.getContent()).useDelimiter("\\A").next(); - - return json_file_content; - } private JSONObject getJSONFromProvider(String json_url, boolean danger_on) throws JSONException { String json_file_content = getStringFromProvider(json_url, danger_on); @@ -391,4 +408,43 @@ public class ProviderAPI extends IntentService { } return true; } + + private boolean getNewCert(Bundle task) { + String provider_json_string = ConfigHelper.getStringFromSharedPref(ConfigHelper.provider_key); + HttpCookie session_id_cookie = new HttpCookie(task.getString(ConfigHelper.session_id_cookie_key), task.getString(ConfigHelper.session_id_key)); + + try { + JSONObject provider_json = new JSONObject(provider_json_string); + URL provider_main_url = new URL(provider_json.getString(ConfigHelper.api_url_key).replace("api.", "")); + String new_cert_string_url = provider_main_url.getProtocol() + "://" + provider_main_url.getHost() + "/" + provider_json.getString(ConfigHelper.api_version_key) + "/" + ConfigHelper.cert_key; + + CookieManager cookieManager = new CookieManager(); + cookieManager.getCookieStore().add(provider_main_url.toURI(), session_id_cookie); + CookieHandler.setDefault(cookieManager); + + String danger_on_json_string = ConfigHelper.getStringFromSharedPref(ConfigHelper.danger_on); + boolean danger_on = new JSONObject(danger_on_json_string).getBoolean(ConfigHelper.danger_on); + String cert_string = getStringFromProvider(new_cert_string_url, danger_on); + if(!cert_string.isEmpty()) { + JSONObject cert_json = new JSONObject().put(ConfigHelper.cert_key, cert_string); + ConfigHelper.saveSharedPref(ConfigHelper.cert_key, cert_json); + return true; + } 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 true; + } } -- cgit v1.2.3 From 84a11bb1620d2b9080992427c847b58007f2304a Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Parm=C3=A9nides=20GV?= Date: Thu, 9 May 2013 17:29:38 +0200 Subject: Log in and Log out options are shown only if allow registration is true. Allow registration is present in provider.json. Provider.json is downloaded from both preseeded and custom providers. Authentication success or fail is notified correctly to the user. --- src/se/leap/leapclient/ConfigHelper.java | 14 +++- src/se/leap/leapclient/ConfigurationWizard.java | 78 ++++++++++++++------- src/se/leap/leapclient/Dashboard.java | 62 ++++++++++++++--- src/se/leap/leapclient/ProviderAPI.java | 90 +++++++++++++++++++++---- src/se/leap/leapclient/ProviderListContent.java | 5 +- 5 files changed, 202 insertions(+), 47 deletions(-) (limited to 'src/se/leap/leapclient') diff --git a/src/se/leap/leapclient/ConfigHelper.java b/src/se/leap/leapclient/ConfigHelper.java index 98761b61..0dab26f4 100644 --- a/src/se/leap/leapclient/ConfigHelper.java +++ b/src/se/leap/leapclient/ConfigHelper.java @@ -16,7 +16,6 @@ import java.security.cert.CertificateException; import java.security.cert.CertificateFactory; import java.security.cert.X509Certificate; -import org.json.JSONArray; import org.json.JSONException; import org.json.JSONObject; @@ -30,6 +29,7 @@ public class ConfigHelper { private static KeyStore keystore_trusted; final static String downloadJsonFilesBundleExtra = "downloadJSONFiles"; + final static String updateProviderDotJSON = "updateProviderDotJSON"; final static String downloadNewProviderDotJSON = "downloadNewProviderDotJSON"; final public static String logInDialog = "logInDialog"; final public static String newProviderDialog = "logInDialog"; @@ -41,6 +41,7 @@ public class ConfigHelper { public static String api_version_key = "api_version"; final public static String resultKey = "result"; final static String provider_key = "provider"; + final static String service_key = "service"; final static String main_cert_key = "main_cert"; final static String cert_key = "cert"; final static String eip_service_key = "eip"; @@ -48,11 +49,15 @@ public class ConfigHelper { final static String session_id_key = "session_id"; public static final String PREFERENCES_KEY = "LEAPPreferences"; public static final String user_directory = "leap_android"; + final public static String provider_name = "provider_name"; final public static String provider_main_url = "provider_main_url"; + final public static String provider_json_url = "provider_json_url"; + final public static String custom = "custom"; final public static String danger_on = "danger_on"; final public static String api_url_key = "api_uri"; final public static String username_key = "username"; final public static String password_key = "password"; + final public static String allow_registration_key = "allow_registration"; final public static String eip_service_api_path = "config/eip-service.json"; final public static String NG_1024 = @@ -70,6 +75,8 @@ public class ConfigHelper { final public static int LOGOUT_FAILED = 8; final public static int CORRECTLY_DOWNLOADED_AUTHED_USER_CERTIFICATE = 9; final public static int INCORRECTLY_DOWNLOADED_AUTHED_USER_CERTIFICATE = 10; + final public static int CORRECTLY_UPDATED_PROVIDER_DOT_JSON = 11; + final public static int INCORRECTLY_UPDATED_PROVIDER_DOT_JSON = 12; static String getStringFromSharedPref(String shared_preferences_key) { String value = ""; @@ -194,7 +201,6 @@ public class ConfigHelper { // Initialize the keystore with the provided trusted certificates // Also provide the password of the keystore if(leap_keystore != null) { - InputStream android_default_keystore; //keystore_trusted.load(leap_keystore, "uer92jf".toCharArray()); keystore_trusted.load(null, null); } else { @@ -221,7 +227,9 @@ public class ConfigHelper { public static int getSrpAuthenticationFailed() { return SRP_AUTHENTICATION_FAILED; - }static String extractProviderName(String provider_main_url) { + } + + static String extractProviderName(String provider_main_url) { return null; } diff --git a/src/se/leap/leapclient/ConfigurationWizard.java b/src/se/leap/leapclient/ConfigurationWizard.java index a50a8e62..ba17f9bb 100644 --- a/src/se/leap/leapclient/ConfigurationWizard.java +++ b/src/se/leap/leapclient/ConfigurationWizard.java @@ -3,6 +3,7 @@ package se.leap.leapclient; import java.io.IOException; import java.io.InputStream; import java.io.InputStreamReader; +import java.net.URL; import java.util.Iterator; import java.util.Scanner; @@ -133,29 +134,27 @@ public class ConfigurationWizard extends Activity } } - private void saveProviderJson(ProviderItem current_provider_item) { - AssetManager assets_manager = getAssets(); - JSONObject provider_json = new JSONObject(); - try { - String provider_contents = ""; - if(!current_provider_item.custom) - provider_contents = new Scanner(new InputStreamReader(assets_manager.open(current_provider_item.provider_json_filename))).useDelimiter("\\A").next(); - else - provider_contents = new Scanner(ConfigHelper.openFileInputStream(current_provider_item.provider_json_filename)).useDelimiter("\\A").next(); - provider_json = new JSONObject(provider_contents); - } catch (IOException e) { - // TODO Auto-generated catch block - e.printStackTrace(); - } catch (JSONException e) { - ConfigHelper.rescueJSONException(e); - } - ConfigHelper.saveSharedPref(ConfigHelper.provider_key, provider_json); - try { - ConfigHelper.saveSharedPref(ConfigHelper.danger_on, new JSONObject().put(ConfigHelper.danger_on, current_provider_item.danger_on)); - } catch (JSONException e) { - // TODO Auto-generated catch block - e.printStackTrace(); - } + private void saveProviderJson(ProviderItem current_provider_item) { + JSONObject provider_json = new JSONObject(); + try { + String provider_contents = ""; + if(!current_provider_item.custom) { + //provider_contents = new Scanner(new InputStreamReader(assets_manager.open(current_provider_item.provider_json_filename))).useDelimiter("\\A").next(); + updateProviderDotJson(current_provider_item.name, current_provider_item.provider_json_url, current_provider_item.danger_on); + } else { + provider_contents = new Scanner(ConfigHelper.openFileInputStream(current_provider_item.provider_json_filename)).useDelimiter("\\A").next(); + provider_json = new JSONObject(provider_contents); + ConfigHelper.saveSharedPref(ConfigHelper.provider_key, provider_json); + try { + ConfigHelper.saveSharedPref(ConfigHelper.danger_on, new JSONObject().put(ConfigHelper.danger_on, current_provider_item.danger_on)); + } catch (JSONException e) { + // TODO Auto-generated catch block + e.printStackTrace(); + } + } + } catch (JSONException e) { + ConfigHelper.rescueJSONException(e); + } } private void downloadJSONFiles(ProviderItem current_provider_item) throws IOException { @@ -205,6 +204,23 @@ public class ConfigurationWizard extends Activity startService(provider_API_command); } + + public void updateProviderDotJson(String provider_name, String provider_json_url, boolean danger_on) { + providerAPI_result_receiver = new ProviderAPIResultReceiver(new Handler()); + providerAPI_result_receiver.setReceiver(this); + + 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); + + provider_API_command.putExtra(ConfigHelper.updateProviderDotJSON, method_and_parameters); + provider_API_command.putExtra("receiver", providerAPI_result_receiver); + + startService(provider_API_command); + } @Override public void onReceiveResult(int resultCode, Bundle resultData) { @@ -224,5 +240,21 @@ public class ConfigurationWizard extends Activity setResult(RESULT_CANCELED); Toast.makeText(getApplicationContext(), "You have not entered a LEAP provider URL", Toast.LENGTH_LONG).show(); } + else if(resultCode == ConfigHelper.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, new JSONObject().put(ConfigHelper.danger_on, danger_on)); + } catch (JSONException e) { + // TODO Auto-generated catch block + e.printStackTrace(); + } + } + else if(resultCode == ConfigHelper.INCORRECTLY_UPDATED_PROVIDER_DOT_JSON) { + Toast.makeText(getApplicationContext(), "Install a new version of this app.", Toast.LENGTH_LONG).show(); + } + } } diff --git a/src/se/leap/leapclient/Dashboard.java b/src/se/leap/leapclient/Dashboard.java index dbee9c48..c8cbc5a3 100644 --- a/src/se/leap/leapclient/Dashboard.java +++ b/src/se/leap/leapclient/Dashboard.java @@ -11,7 +11,6 @@ import se.leap.openvpn.MainActivity; import android.app.Activity; import android.app.DialogFragment; import android.app.Fragment; -import android.app.FragmentManager; import android.app.FragmentTransaction; import android.content.Intent; import android.content.SharedPreferences; @@ -115,6 +114,25 @@ public class Dashboard extends Activity implements LogInDialog.LogInDialogInterf // TODO attach settings button to something } + @Override + public boolean onPrepareOptionsMenu(Menu menu) { + String provider_json_string = ConfigHelper.getStringFromSharedPref(ConfigHelper.provider_key); + try { + JSONObject provider_json = new JSONObject(provider_json_string); + JSONObject service_description = provider_json.getJSONObject(ConfigHelper.service_key); + if(service_description.getBoolean(ConfigHelper.allow_registration_key)) { + menu.findItem(R.id.login_button).setVisible(true); + menu.findItem(R.id.logout_button).setVisible(true); + return true; + } + } catch (JSONException e) { + menu.findItem(R.id.login_button).setVisible(false); + menu.findItem(R.id.logout_button).setVisible(false); + return false; + } + return false; + } + @Override public boolean onCreateOptionsMenu(Menu menu) { // Inflate the menu; this adds items to the action bar if it is present. @@ -147,6 +165,9 @@ public class Dashboard extends Activity implements LogInDialog.LogInDialogInterf View view = ((ViewGroup)findViewById(android.R.id.content)).getChildAt(0); logInDialog(view); return true; + case R.id.logout_button: + logOut(); + return true; default: return super.onOptionsItemSelected(item); } @@ -184,6 +205,28 @@ public class Dashboard extends Activity implements LogInDialog.LogInDialogInterf startService(provider_API_command); } + 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 method_and_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)); + } catch (JSONException e) { + // TODO Auto-generated catch block + e.printStackTrace(); + } + + provider_API_command.putExtra(ConfigHelper.logOut, method_and_parameters); + provider_API_command.putExtra("receiver", providerAPI_result_receiver); + + startService(provider_API_command); + } + public void logInDialog(View view) { FragmentTransaction fragment_transaction = getFragmentManager().beginTransaction(); Fragment previous_log_in_dialog = getFragmentManager().findFragmentByTag(ConfigHelper.logInDialog); @@ -219,19 +262,22 @@ public class Dashboard extends Activity implements LogInDialog.LogInDialogInterf String session_id_string = resultData.getString(ConfigHelper.session_id_key); setResult(RESULT_OK); Toast.makeText(getApplicationContext(), "Authentication succeeded", Toast.LENGTH_LONG).show(); - //TODO Download certificate requesting /1/cert with session_id cookie + 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 == ConfigHelper.SRP_AUTHENTICATION_FAILED) { setResult(RESULT_CANCELED); Toast.makeText(getApplicationContext(), "Authentication failed", Toast.LENGTH_LONG).show(); - } - else if(resultCode == ConfigHelper.CORRECTLY_DOWNLOADED_AUTHED_USER_CERTIFICATE) { + } else if(resultCode == ConfigHelper.LOGOUT_SUCCESSFUL) { + setResult(RESULT_OK); + Toast.makeText(getApplicationContext(), "Logged out", Toast.LENGTH_LONG).show(); + } else if(resultCode == ConfigHelper.LOGOUT_FAILED) { + setResult(RESULT_CANCELED); + Toast.makeText(getApplicationContext(), "Didn't logged out", Toast.LENGTH_LONG).show(); + } else if(resultCode == ConfigHelper.CORRECTLY_DOWNLOADED_AUTHED_USER_CERTIFICATE) { setResult(RESULT_CANCELED); Toast.makeText(getApplicationContext(), "Your own cert has been correctly downloaded", Toast.LENGTH_LONG).show(); - } - else if(resultCode == ConfigHelper.INCORRECTLY_DOWNLOADED_AUTHED_USER_CERTIFICATE) { + } else if(resultCode == ConfigHelper.INCORRECTLY_DOWNLOADED_AUTHED_USER_CERTIFICATE) { setResult(RESULT_CANCELED); Toast.makeText(getApplicationContext(), "Your own cert has incorrectly been downloaded", Toast.LENGTH_LONG).show(); } diff --git a/src/se/leap/leapclient/ProviderAPI.java b/src/se/leap/leapclient/ProviderAPI.java index bdfd6207..b44c9971 100644 --- a/src/se/leap/leapclient/ProviderAPI.java +++ b/src/se/leap/leapclient/ProviderAPI.java @@ -15,7 +15,6 @@ import java.util.List; import java.net.CookieHandler; import java.net.CookieManager; import java.net.HttpCookie; -import java.net.HttpURLConnection; import java.net.MalformedURLException; import java.net.URISyntaxException; import java.net.URL; @@ -30,16 +29,12 @@ import javax.net.ssl.TrustManagerFactory; import org.apache.http.HttpEntity; import org.apache.http.HttpResponse; import org.apache.http.client.ClientProtocolException; -import org.apache.http.client.CookieStore; import org.apache.http.client.methods.HttpDelete; -import org.apache.http.client.methods.HttpGet; import org.apache.http.client.methods.HttpPost; import org.apache.http.client.methods.HttpPut; import org.apache.http.client.protocol.ClientContext; import org.apache.http.cookie.Cookie; -import org.apache.http.impl.client.BasicCookieStore; import org.apache.http.impl.client.DefaultHttpClient; -import org.apache.http.impl.cookie.BasicClientCookie; import org.apache.http.protocol.BasicHttpContext; import org.apache.http.protocol.HttpContext; import org.jboss.security.Util; @@ -74,6 +69,24 @@ public class ProviderAPI extends IntentService { else receiver.send(ConfigHelper.CORRECTLY_DOWNLOADED_JSON_FILES, Bundle.EMPTY); } + else if ((task = task_for.getBundleExtra(ConfigHelper.updateProviderDotJSON)) != null) { + JSONObject result = updateProviderDotJSON(task); + boolean successful; + try { + successful = result.getBoolean(ConfigHelper.resultKey); + if(successful) { + Bundle provider_dot_json_and_danger_on = new Bundle(); + provider_dot_json_and_danger_on.putBoolean(ConfigHelper.danger_on, result.getBoolean(ConfigHelper.danger_on)); + provider_dot_json_and_danger_on.putString(ConfigHelper.provider_key, result.getJSONObject(ConfigHelper.provider_key).toString()); + receiver.send(ConfigHelper.CORRECTLY_UPDATED_PROVIDER_DOT_JSON, provider_dot_json_and_danger_on); + } else { + receiver.send(ConfigHelper.INCORRECTLY_UPDATED_PROVIDER_DOT_JSON, Bundle.EMPTY); + } + } catch (JSONException e) { + // TODO Auto-generated catch block + e.printStackTrace(); + } + } else if ((task = task_for.getBundleExtra(ConfigHelper.downloadNewProviderDotJSON)) != null) { if(downloadNewProviderDotJSON(task)) receiver.send(ConfigHelper.CUSTOM_PROVIDER_ADDED, Bundle.EMPTY); @@ -172,6 +185,9 @@ public class ProviderAPI extends IntentService { successfulAndsession_id.put(ConfigHelper.session_id_cookie_key, session_idAndM2.getString(ConfigHelper.session_id_cookie_key)); return successfulAndsession_id; } + } else { + successfulAndsession_id.put(ConfigHelper.resultKey, false); + return successfulAndsession_id; } } catch (ClientProtocolException e1) { // TODO Auto-generated catch block @@ -236,6 +252,50 @@ public class ProviderAPI extends IntentService { return session_idAndM2; } + private JSONObject updateProviderDotJSON(Bundle task) { + JSONObject result = new JSONObject(); + 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); + + JSONObject provider_json = null; + try { + provider_json = getJSONFromProvider(provider_json_url, danger_on); + } catch (JSONException e) { + // TODO Auto-generated catch block + e.printStackTrace(); + try { + return result.put(ConfigHelper.resultKey, false); + } catch (JSONException e1) { + // TODO Auto-generated catch block + e1.printStackTrace(); + } + } + + if(provider_json == null) { + try { + return result.put(ConfigHelper.resultKey, false); + } catch (JSONException e) { + // TODO Auto-generated catch block + e.printStackTrace(); + } + } else { + String filename = provider_name + "_provider.json".replaceFirst("__", "_"); + ConfigHelper.saveFile(filename, provider_json.toString()); + //ConfigHelper.saveSharedPref(ConfigHelper.provider_key, provider_json); + + ProviderListContent.addItem(new ProviderItem(provider_name, provider_json_url, filename, custom, danger_on)); + try { + return result.put(ConfigHelper.resultKey, true).put(ConfigHelper.provider_key, provider_json).put(ConfigHelper.danger_on, danger_on); + } catch (JSONException e) { + // TODO Auto-generated catch block + e.printStackTrace(); + } + } + return result; + } + private boolean downloadNewProviderDotJSON(Bundle task) { boolean custom = true; boolean danger_on = task.getBoolean(ConfigHelper.danger_on); @@ -259,7 +319,7 @@ public class ProviderAPI extends IntentService { ConfigHelper.saveFile(filename, provider_json.toString()); //ConfigHelper.saveSharedPref(ConfigHelper.provider_key, provider_json); - ProviderListContent.addItem(new ProviderItem(provider_name, provider_json_url, ConfigHelper.openFileInputStream(filename), custom, danger_on)); + ProviderListContent.addItem(new ProviderItem(provider_name, provider_json_url, filename, custom, danger_on)); return true; } } @@ -291,10 +351,6 @@ public class ProviderAPI extends IntentService { } return json_string; } - - private String guessURL(String provider_main_url) { - return provider_main_url + "/provider.json"; - } private String getStringFromProvider(String string_url, boolean danger_on) { @@ -388,23 +444,33 @@ public class ProviderAPI extends IntentService { String json_file_content = getStringFromProvider(json_url, danger_on); return new JSONObject(json_file_content); } + + private String guessURL(String provider_main_url) { + return provider_main_url + "/provider.json"; + } 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(); - String delete_url = task.getString(ConfigHelper.api_url_key) + "/logout" + "?authenticity_token=" + client.getCookieStore().getCookies().get(session_id_index).getValue(); - HttpDelete delete = new HttpDelete(delete_url); try { + String delete_url = task.getString(ConfigHelper.api_url_key) + "/logout" + "?authenticity_token=" + client.getCookieStore().getCookies().get(session_id_index).getValue(); + HttpDelete delete = new HttpDelete(delete_url); HttpResponse getResponse = client.execute(delete); HttpEntity responseEntity = getResponse.getEntity(); responseEntity.consumeContent(); } 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; } return true; } diff --git a/src/se/leap/leapclient/ProviderListContent.java b/src/se/leap/leapclient/ProviderListContent.java index 8cc349c2..d4bb6a9a 100644 --- a/src/se/leap/leapclient/ProviderListContent.java +++ b/src/se/leap/leapclient/ProviderListContent.java @@ -78,8 +78,10 @@ public class ProviderListContent { } } - public ProviderItem(String name, String provider_json_url, FileInputStream provider_json, boolean custom, boolean danger_on) { + public ProviderItem(String name, String provider_json_url, String provider_json_filename, boolean custom, boolean danger_on) { + + FileInputStream provider_json = ConfigHelper.openFileInputStream(provider_json_filename); try { byte[] urls_file_bytes = new byte[provider_json.available()]; provider_json.read(urls_file_bytes); @@ -88,6 +90,7 @@ public class ProviderListContent { id = name; this.name = name; this.provider_json_url = provider_json_url; + this.provider_json_filename = provider_json_filename; eip_service_json_url = file_contents.getString("api_uri") + "/" + file_contents.getString("api_version") + "/" + ConfigHelper.eip_service_api_path; cert_json_url = (String) file_contents.get("ca_cert_uri"); this.custom = custom; -- cgit v1.2.3 From 80a8106afc8956008beb9d1ed9396f1d695d5b7b Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Parm=C3=A9nides=20GV?= Date: Mon, 13 May 2013 20:39:34 +0200 Subject: A bit more clean. I've upper cased ConfigHelper constants. I've created a new method in ConfigHelper, to send requests to a server, that it's used when sending A and M1. --- src/se/leap/leapclient/ConfigHelper.java | 185 ++++++--------- src/se/leap/leapclient/ConfigurationWizard.java | 210 ++++++++--------- src/se/leap/leapclient/Dashboard.java | 40 ++-- src/se/leap/leapclient/LeapHttpClient.java | 96 ++++---- src/se/leap/leapclient/LeapSRPSession.java | 39 +--- src/se/leap/leapclient/LogInDialog.java | 67 +++--- src/se/leap/leapclient/NewProviderDialog.java | 7 +- src/se/leap/leapclient/Provider.java | 2 +- src/se/leap/leapclient/ProviderAPI.java | 289 +++++++++--------------- src/se/leap/leapclient/ProviderListContent.java | 2 +- 10 files changed, 391 insertions(+), 546 deletions(-) (limited to 'src/se/leap/leapclient') diff --git a/src/se/leap/leapclient/ConfigHelper.java b/src/se/leap/leapclient/ConfigHelper.java index 0dab26f4..5d44f004 100644 --- a/src/se/leap/leapclient/ConfigHelper.java +++ b/src/se/leap/leapclient/ConfigHelper.java @@ -1,6 +1,5 @@ package se.leap.leapclient; - import java.io.BufferedWriter; import java.io.File; import java.io.FileInputStream; @@ -28,103 +27,94 @@ public class ConfigHelper { public static SharedPreferences shared_preferences; private static KeyStore keystore_trusted; - final static String downloadJsonFilesBundleExtra = "downloadJSONFiles"; - final static String updateProviderDotJSON = "updateProviderDotJSON"; - final static String downloadNewProviderDotJSON = "downloadNewProviderDotJSON"; - final public static String logInDialog = "logInDialog"; - final public static String newProviderDialog = "logInDialog"; - final public static String srpRegister = "srpRegister"; - final public static String srpAuth = "srpAuth"; - public static String logIn = "logIn"; - public static String logOut = "logOut"; - public static String downloadUserAuthedCertificate = "downloadUserAuthedCertificate"; - public static String api_version_key = "api_version"; - final public static String resultKey = "result"; - final static String provider_key = "provider"; - final static String service_key = "service"; - final static String main_cert_key = "main_cert"; - final static String cert_key = "cert"; - final static String eip_service_key = "eip"; - final static String session_id_cookie_key = "session_id_cookie_key"; - final static String session_id_key = "session_id"; - public static final String PREFERENCES_KEY = "LEAPPreferences"; - public static final String user_directory = "leap_android"; - final public static String provider_name = "provider_name"; - final public static String provider_main_url = "provider_main_url"; - final public static String provider_json_url = "provider_json_url"; - final public static String custom = "custom"; - final public static String danger_on = "danger_on"; - final public static String api_url_key = "api_uri"; - final public static String username_key = "username"; - final public static String password_key = "password"; - final public static String allow_registration_key = "allow_registration"; - final public static String eip_service_api_path = "config/eip-service.json"; + final public static String + 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", + LOG_IN = "logIn", + LOG_OUT = "logOut", + DOWNLOAD_USER_AUTHED_CERTIFICATE = "downloadUserAuthedCertificate", + API_VERSION_KEY = "api_version", + RESULT_KEY = "result", + PROVIDER_KEY = "provider", + SERVICE_KEY = "service", + MAIN_CERT_KEY = "main_cert", + CERT_KEY = "cert", + EIP_SERVICE_KEY = "eip", + SALT_KEY = "salt", + SESSION_ID_COOKIE_KEY = "session_id_cookie_key", + SESSION_ID_KEY = "session_id", + PREFERENCES_KEY = "LEAPPreferences", + USER_DIRECTORY = "leap_android", + PROVIDER_NAME = "provider_name", + 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" + ; - final public static String NG_1024 = - "eeaf0ab9adb38dd69c33f80afa8fc5e86072618775ff3c0b9ea2314c9c256576d674df7496ea81d3383b4813d692c6e0e0d5d8e250b98be48e495c1d6089dad15dc7d7b46154d6b6ce8ef4ad69b15d4982559b297bcf1885c529f566660e57ec68edbc3c05726cc02fd4cbf4976eaa9afd5138fe8376435b9fc61d2fc0eb06e3"; - final public static BigInteger g = BigInteger.valueOf(2); + 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_AUTHED_USER_CERTIFICATE = 9, + INCORRECTLY_DOWNLOADED_AUTHED_USER_CERTIFICATE = 10, + CORRECTLY_UPDATED_PROVIDER_DOT_JSON = 11, + INCORRECTLY_UPDATED_PROVIDER_DOT_JSON = 12 + ; - final public static int CUSTOM_PROVIDER_ADDED = 0; - final public static int CORRECTLY_DOWNLOADED_JSON_FILES = 1; - final public static int INCORRECTLY_DOWNLOADED_JSON_FILES = 2; - final public static int SRP_AUTHENTICATION_SUCCESSFUL = 3; - final public static int SRP_AUTHENTICATION_FAILED = 4; - final public static int SRP_REGISTRATION_SUCCESSFUL = 5; - final public static int SRP_REGISTRATION_FAILED = 6; - final public static int LOGOUT_SUCCESSFUL = 7; - final public static int LOGOUT_FAILED = 8; - final public static int CORRECTLY_DOWNLOADED_AUTHED_USER_CERTIFICATE = 9; - final public static int INCORRECTLY_DOWNLOADED_AUTHED_USER_CERTIFICATE = 10; - final public static int CORRECTLY_UPDATED_PROVIDER_DOT_JSON = 11; - final public static int INCORRECTLY_UPDATED_PROVIDER_DOT_JSON = 12; + 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(); + } - static String getStringFromSharedPref(String shared_preferences_key) { + public static String getStringFromSharedPref(String shared_preferences_key) { String value = ""; - //TODO This is not OK -> when reading provider.json it only shows "open" if(shared_preferences != null) { String content = shared_preferences.getString(shared_preferences_key, ""); try { JSONObject json_object = new JSONObject(content); value = json_object.toString(); - /*JSONArray names = json_object.names(); - String key = names.getString(0); - value = json_object.getString(key);*/ } catch (JSONException e) { value = content; } } return value; } - - 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(); - System.out.println("Shared preferences updated: key = " - + shared_preferences_key - + " Content = " - + shared_preferences.getString( - shared_preferences_key, "Default")); - } - static void rescueJSONException(JSONException e) { - // TODO Auto-generated catch block - e.printStackTrace(); - } - - static void saveFile(String filename, String content) { + public static void saveFile(String filename, String content) { File root = Environment.getExternalStorageDirectory(); - File leap_dir = new File(root.getAbsolutePath() + File.separator + user_directory); + File leap_dir = new File(root.getAbsolutePath() + File.separator + USER_DIRECTORY); if (!leap_dir.isDirectory()) { leap_dir.mkdir(); } try { if (!leap_dir.isDirectory()) { throw new IOException( - "Unable to create directory " + user_directory + ". Maybe the SD card is mounted?"); + "Unable to create directory " + USER_DIRECTORY + ". Maybe the SD card is mounted?"); } File outputFile = new File(leap_dir, filename); BufferedWriter writer = new BufferedWriter(new FileWriter(outputFile)); @@ -135,10 +125,10 @@ public class ConfigHelper { } } - static FileInputStream openFileInputStream(String filename) { + 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); + File leap_dir = new File(root.getAbsolutePath() + File.separator + USER_DIRECTORY); try { input_stream = new FileInputStream(leap_dir + File.separator + filename); } catch (FileNotFoundException e) { @@ -178,7 +168,8 @@ public class ConfigHelper { X509Certificate cert = (X509Certificate)cf.generateCertificate(openFileInputStream(filename_to_save)); if(keystore_trusted == null) { - getNewKeystore(null); + keystore_trusted = KeyStore.getInstance("BKS"); + keystore_trusted.load(null); } keystore_trusted.setCertificateEntry(provider, cert); } catch (CertificateException e) { @@ -187,50 +178,16 @@ public class ConfigHelper { } catch (KeyStoreException e) { // TODO Auto-generated catch block e.printStackTrace(); - } - } - - public static KeyStore getKeystore() { - return keystore_trusted; - } - - public static void getNewKeystore(InputStream leap_keystore) { - try { - keystore_trusted = KeyStore.getInstance("BKS"); - try { - // Initialize the keystore with the provided trusted certificates - // Also provide the password of the keystore - if(leap_keystore != null) { - //keystore_trusted.load(leap_keystore, "uer92jf".toCharArray()); - keystore_trusted.load(null, null); - } else { - keystore_trusted.load(null, null); - } - } finally { - if(leap_keystore != null) - leap_keystore.close(); - } - } 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(); } } - - public static int getSrpAuthenticationFailed() { - return SRP_AUTHENTICATION_FAILED; - } - static String extractProviderName(String provider_main_url) { - - return null; + public static KeyStore getKeystore() { + return keystore_trusted; } } diff --git a/src/se/leap/leapclient/ConfigurationWizard.java b/src/se/leap/leapclient/ConfigurationWizard.java index ba17f9bb..78ac0462 100644 --- a/src/se/leap/leapclient/ConfigurationWizard.java +++ b/src/se/leap/leapclient/ConfigurationWizard.java @@ -1,9 +1,6 @@ package se.leap.leapclient; import java.io.IOException; -import java.io.InputStream; -import java.io.InputStreamReader; -import java.net.URL; import java.util.Iterator; import java.util.Scanner; @@ -12,6 +9,9 @@ import org.json.JSONObject; import se.leap.leapclient.ProviderAPIResultReceiver.Receiver; import se.leap.leapclient.ProviderListContent.ProviderItem; +import se.leap.leapclient.R; +import se.leap.leapclient.R.id; +import se.leap.leapclient.R.layout; import android.app.Activity; import android.app.DialogFragment; import android.app.Fragment; @@ -24,23 +24,6 @@ import android.os.Handler; import android.view.View; import android.widget.Toast; - -/** - * An activity representing a list of Providers. This activity - * has different presentations for handset and tablet-size devices. On - * handsets, the activity presents a list of items, which when touched, - * lead to a {@link DashboardActivity} representing - * item details. On tablets, the activity presents the list of items and - * item details side-by-side using two vertical panes. - *

- * The activity makes heavy use of fragments. The list of items is a - * {@link ProviderListFragment} and the item details - * (if present) is a {@link DashboardFragment}. - *

- * This activity also implements the required - * {@link ProviderListFragment.Callbacks} interface - * to listen for item selections. - */ public class ConfigurationWizard extends Activity implements ProviderListFragment.Callbacks, NewProviderDialog.NewProviderDialogInterface, Receiver { @@ -63,11 +46,6 @@ public class ConfigurationWizard extends Activity loadPreseededProviders(); - if(ConfigHelper.getKeystore() == null) { - InputStream keystore_input_stream = getResources().openRawResource(R.raw.leapkeystore); - ConfigHelper.getNewKeystore(keystore_input_stream); - } - // Only create our fragments if we're not restoring a saved instance if ( savedInstanceState == null ){ // TODO Some welcome screen? @@ -83,7 +61,67 @@ public class ConfigurationWizard extends Activity // TODO: If exposing deep links into your app, handle intents here. } - private void loadPreseededProviders() { + @Override + public void onReceiveResult(int resultCode, Bundle resultData) { + if(resultCode == ConfigHelper.CUSTOM_PROVIDER_ADDED){ + ProviderListFragment providerList = new ProviderListFragment(); + + FragmentManager fragmentManager = getFragmentManager(); + fragmentManager.beginTransaction() + .replace(R.id.configuration_wizard_layout, providerList, "providerlist") + .commit(); + } + else if(resultCode == ConfigHelper.CORRECTLY_DOWNLOADED_JSON_FILES) { + setResult(RESULT_OK); + finish(); + } + else if(resultCode == ConfigHelper.INCORRECTLY_DOWNLOADED_JSON_FILES) { + setResult(RESULT_CANCELED); + Toast.makeText(getApplicationContext(), "You have not entered a LEAP provider URL or it is unavailable", Toast.LENGTH_LONG).show(); + } + else if(resultCode == ConfigHelper.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, new JSONObject().put(ConfigHelper.DANGER_ON, danger_on)); + } catch (JSONException e) { + // TODO Auto-generated catch block + e.printStackTrace(); + } + } + else if(resultCode == ConfigHelper.INCORRECTLY_UPDATED_PROVIDER_DOT_JSON) { + Toast.makeText(getApplicationContext(), "Install a new version of this app.", Toast.LENGTH_LONG).show(); + } + } + + /** + * 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 + Iterator preseeded_providers_iterator = ProviderListContent.ITEMS.iterator(); + while(preseeded_providers_iterator.hasNext()) + { + ProviderItem current_provider_item = preseeded_providers_iterator.next(); + if(current_provider_item.id.equalsIgnoreCase(id)) + { + try { + saveProviderJson(current_provider_item); + downloadJSONFiles(current_provider_item); + } catch (IOException e) { + // TODO Auto-generated catch block + e.printStackTrace(); + } + } + } + } + + private boolean loadPreseededProviders() { + boolean loaded_preseeded_providers = false; AssetManager asset_manager = getAssets(); String[] urls_filepaths = null; try { @@ -97,65 +135,33 @@ public class ConfigurationWizard extends Activity 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 + loaded_preseeded_providers = true; } } catch (IOException e) { - // TODO Auto-generated catch block - e.printStackTrace(); - } + loaded_preseeded_providers = false; + } + + return loaded_preseeded_providers; } - /** - * Callback method from {@link ProviderListFragment.Callbacks} - * indicating that the item with the given ID was selected. - */ - @Override - public void onItemSelected(String id) { - if (mTwoPane) { - // TODO Hmmm...is this how we should do this? What if it /is/ two pane? - } else { - // In single-pane mode, simply start the detail activity - // for the selected item ID. - - Iterator preseeded_providers_iterator = ProviderListContent.ITEMS.iterator(); - while(preseeded_providers_iterator.hasNext()) - { - ProviderItem current_provider_item = preseeded_providers_iterator.next(); - if(current_provider_item.id.equalsIgnoreCase(id)) - { - try { - saveProviderJson(current_provider_item); - downloadJSONFiles(current_provider_item); - } catch (IOException e) { - // TODO Auto-generated catch block - e.printStackTrace(); - } - } - } - } - } - - private void saveProviderJson(ProviderItem current_provider_item) { + private boolean saveProviderJson(ProviderItem current_provider_item) { JSONObject provider_json = new JSONObject(); try { String provider_contents = ""; if(!current_provider_item.custom) { - //provider_contents = new Scanner(new InputStreamReader(assets_manager.open(current_provider_item.provider_json_filename))).useDelimiter("\\A").next(); updateProviderDotJson(current_provider_item.name, current_provider_item.provider_json_url, current_provider_item.danger_on); + return true; } else { provider_contents = new Scanner(ConfigHelper.openFileInputStream(current_provider_item.provider_json_filename)).useDelimiter("\\A").next(); provider_json = new JSONObject(provider_contents); - ConfigHelper.saveSharedPref(ConfigHelper.provider_key, provider_json); - try { - ConfigHelper.saveSharedPref(ConfigHelper.danger_on, new JSONObject().put(ConfigHelper.danger_on, current_provider_item.danger_on)); - } catch (JSONException e) { - // TODO Auto-generated catch block - e.printStackTrace(); - } + ConfigHelper.saveSharedPref(ConfigHelper.PROVIDER_KEY, provider_json); + ConfigHelper.saveSharedPref(ConfigHelper.DANGER_ON, new JSONObject().put(ConfigHelper.DANGER_ON, current_provider_item.danger_on)); + return true; } } catch (JSONException e) { - ConfigHelper.rescueJSONException(e); + return false; } - } + } private void downloadJSONFiles(ProviderItem current_provider_item) throws IOException { providerAPI_result_receiver = new ProviderAPIResultReceiver(new Handler()); @@ -165,12 +171,12 @@ public class ConfigurationWizard extends Activity Bundle method_and_parameters = new Bundle(); - method_and_parameters.putString(ConfigHelper.provider_key, current_provider_item.name); - method_and_parameters.putString(ConfigHelper.main_cert_key, current_provider_item.cert_json_url); - method_and_parameters.putString(ConfigHelper.eip_service_key, current_provider_item.eip_service_json_url); - method_and_parameters.putBoolean(ConfigHelper.danger_on, current_provider_item.danger_on); + method_and_parameters.putString(ConfigHelper.PROVIDER_KEY, current_provider_item.name); + method_and_parameters.putString(ConfigHelper.MAIN_CERT_KEY, current_provider_item.cert_json_url); + method_and_parameters.putString(ConfigHelper.EIP_SERVICE_KEY, current_provider_item.eip_service_json_url); + method_and_parameters.putBoolean(ConfigHelper.DANGER_ON, current_provider_item.danger_on); - provider_API_command.putExtra(ConfigHelper.downloadJsonFilesBundleExtra, method_and_parameters); + provider_API_command.putExtra(ConfigHelper.DOWNLOAD_JSON_FILES_BUNDLE_EXTRA, method_and_parameters); provider_API_command.putExtra("receiver", providerAPI_result_receiver); startService(provider_API_command); @@ -178,14 +184,14 @@ public class ConfigurationWizard extends Activity public void addNewProvider(View view) { FragmentTransaction fragment_transaction = getFragmentManager().beginTransaction(); - Fragment previous_new_provider_dialog = getFragmentManager().findFragmentByTag(ConfigHelper.newProviderDialog); + Fragment previous_new_provider_dialog = getFragmentManager().findFragmentByTag(ConfigHelper.NEW_PROVIDER_DIALOG); 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.newProviderDialog); + newFragment.show(fragment_transaction, ConfigHelper.NEW_PROVIDER_DIALOG); } @Override @@ -196,10 +202,10 @@ public class ConfigurationWizard extends Activity 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); + method_and_parameters.putString(ConfigHelper.PROVIDER_MAIN_URL, provider_main_url); + method_and_parameters.putBoolean(ConfigHelper.DANGER_ON, danger_on); - provider_API_command.putExtra(ConfigHelper.downloadNewProviderDotJSON, method_and_parameters); + provider_API_command.putExtra(ConfigHelper.DOWNLOAD_NEW_PROVIDER_DOTJSON, method_and_parameters); provider_API_command.putExtra("receiver", providerAPI_result_receiver); startService(provider_API_command); @@ -212,49 +218,13 @@ public class ConfigurationWizard extends Activity 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); + 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); - provider_API_command.putExtra(ConfigHelper.updateProviderDotJSON, method_and_parameters); + provider_API_command.putExtra(ConfigHelper.UPDATE_PROVIDER_DOTJSON, method_and_parameters); provider_API_command.putExtra("receiver", providerAPI_result_receiver); startService(provider_API_command); } - - @Override - public void onReceiveResult(int resultCode, Bundle resultData) { - if(resultCode == ConfigHelper.CUSTOM_PROVIDER_ADDED){ - ProviderListFragment providerList = new ProviderListFragment(); - - FragmentManager fragmentManager = getFragmentManager(); - fragmentManager.beginTransaction() - .replace(R.id.configuration_wizard_layout, providerList, "providerlist") - .commit(); - } - else if(resultCode == ConfigHelper.CORRECTLY_DOWNLOADED_JSON_FILES) { - setResult(RESULT_OK); - finish(); - } - else if(resultCode == ConfigHelper.INCORRECTLY_DOWNLOADED_JSON_FILES) { - setResult(RESULT_CANCELED); - Toast.makeText(getApplicationContext(), "You have not entered a LEAP provider URL", Toast.LENGTH_LONG).show(); - } - else if(resultCode == ConfigHelper.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, new JSONObject().put(ConfigHelper.danger_on, danger_on)); - } catch (JSONException e) { - // TODO Auto-generated catch block - e.printStackTrace(); - } - } - else if(resultCode == ConfigHelper.INCORRECTLY_UPDATED_PROVIDER_DOT_JSON) { - Toast.makeText(getApplicationContext(), "Install a new version of this app.", Toast.LENGTH_LONG).show(); - } - - } } diff --git a/src/se/leap/leapclient/Dashboard.java b/src/se/leap/leapclient/Dashboard.java index c8cbc5a3..b937c949 100644 --- a/src/se/leap/leapclient/Dashboard.java +++ b/src/se/leap/leapclient/Dashboard.java @@ -6,6 +6,10 @@ import org.json.JSONException; import org.json.JSONObject; import se.leap.leapclient.ProviderAPIResultReceiver.Receiver; +import se.leap.leapclient.R; +import se.leap.leapclient.R.id; +import se.leap.leapclient.R.layout; +import se.leap.leapclient.R.menu; import se.leap.openvpn.AboutFragment; import se.leap.openvpn.MainActivity; import android.app.Activity; @@ -116,11 +120,11 @@ public class Dashboard extends Activity implements LogInDialog.LogInDialogInterf @Override public boolean onPrepareOptionsMenu(Menu menu) { - String provider_json_string = ConfigHelper.getStringFromSharedPref(ConfigHelper.provider_key); + String provider_json_string = ConfigHelper.getStringFromSharedPref(ConfigHelper.PROVIDER_KEY); try { JSONObject provider_json = new JSONObject(provider_json_string); - JSONObject service_description = provider_json.getJSONObject(ConfigHelper.service_key); - if(service_description.getBoolean(ConfigHelper.allow_registration_key)) { + JSONObject service_description = provider_json.getJSONObject(ConfigHelper.SERVICE_KEY); + if(service_description.getBoolean(ConfigHelper.ALLOW_REGISTRATION_KEY)) { menu.findItem(R.id.login_button).setVisible(true); menu.findItem(R.id.logout_button).setVisible(true); return true; @@ -187,19 +191,19 @@ 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); + method_and_parameters.putString(ConfigHelper.USERNAME_KEY, username); + method_and_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)); + 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)); } catch (JSONException e) { // TODO Auto-generated catch block e.printStackTrace(); } - provider_API_command.putExtra(ConfigHelper.srpAuth, method_and_parameters); + provider_API_command.putExtra(ConfigHelper.SRP_AUTH, method_and_parameters); provider_API_command.putExtra("receiver", providerAPI_result_receiver); startService(provider_API_command); @@ -214,14 +218,14 @@ public class Dashboard extends Activity implements LogInDialog.LogInDialogInterf 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)); + 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)); } catch (JSONException e) { // TODO Auto-generated catch block e.printStackTrace(); } - provider_API_command.putExtra(ConfigHelper.logOut, method_and_parameters); + provider_API_command.putExtra(ConfigHelper.LOG_OUT, method_and_parameters); provider_API_command.putExtra("receiver", providerAPI_result_receiver); startService(provider_API_command); @@ -229,14 +233,14 @@ public class Dashboard extends Activity implements LogInDialog.LogInDialogInterf public void logInDialog(View view) { FragmentTransaction fragment_transaction = getFragmentManager().beginTransaction(); - Fragment previous_log_in_dialog = getFragmentManager().findFragmentByTag(ConfigHelper.logInDialog); + Fragment previous_log_in_dialog = getFragmentManager().findFragmentByTag(ConfigHelper.LOG_IN_DIALOG); if (previous_log_in_dialog != null) { fragment_transaction.remove(previous_log_in_dialog); } fragment_transaction.addToBackStack(null); DialogFragment newFragment = LogInDialog.newInstance(); - newFragment.show(fragment_transaction, ConfigHelper.logInDialog); + newFragment.show(fragment_transaction, ConfigHelper.LOG_IN_DIALOG); } private void downloadAuthedUserCertificate(Cookie session_id) { @@ -246,10 +250,10 @@ 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.session_id_cookie_key, session_id.getName()); - method_and_parameters.putString(ConfigHelper.session_id_key, session_id.getValue()); + method_and_parameters.putString(ConfigHelper.SESSION_ID_COOKIE_KEY, session_id.getName()); + method_and_parameters.putString(ConfigHelper.SESSION_ID_KEY, session_id.getValue()); - provider_API_command.putExtra(ConfigHelper.downloadUserAuthedCertificate, method_and_parameters); + provider_API_command.putExtra(ConfigHelper.DOWNLOAD_USER_AUTHED_CERTIFICATE, method_and_parameters); provider_API_command.putExtra("receiver", providerAPI_result_receiver); startService(provider_API_command); @@ -258,8 +262,8 @@ public class Dashboard extends Activity implements LogInDialog.LogInDialogInterf @Override public void onReceiveResult(int resultCode, Bundle resultData) { if(resultCode == ConfigHelper.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(ConfigHelper.SESSION_ID_COOKIE_KEY); + String session_id_string = resultData.getString(ConfigHelper.SESSION_ID_KEY); setResult(RESULT_OK); Toast.makeText(getApplicationContext(), "Authentication succeeded", Toast.LENGTH_LONG).show(); diff --git a/src/se/leap/leapclient/LeapHttpClient.java b/src/se/leap/leapclient/LeapHttpClient.java index 4de7ae08..a2ee8ad6 100644 --- a/src/se/leap/leapclient/LeapHttpClient.java +++ b/src/se/leap/leapclient/LeapHttpClient.java @@ -16,57 +16,57 @@ import android.content.Context; public class LeapHttpClient extends DefaultHttpClient { final Context context; - + private static LeapHttpClient client; - public LeapHttpClient(Context context) { - this.context = context; - } + public static LeapHttpClient getInstance(Context context) { + if(client == null) { + client = new LeapHttpClient(context); + String cert_json_string = ConfigHelper.getStringFromSharedPref(ConfigHelper.MAIN_CERT_KEY); + String cert_string; + try { + cert_string = new JSONObject(cert_json_string).getString(ConfigHelper.MAIN_CERT_KEY); + if(!cert_string.isEmpty()) { + ConfigHelper.addTrustedCertificate("recovered_certificate", cert_string); + } + } catch (JSONException e) { + // TODO Auto-generated catch block + e.printStackTrace(); + } + } + return client; + } + + @Override + protected ClientConnectionManager createClientConnectionManager() { + SchemeRegistry registry = new SchemeRegistry(); + registry.register(new Scheme("http", PlainSocketFactory.getSocketFactory(), 80)); + // Register for port 443 our SSLSocketFactory with our keystore + // to the ConnectionManager + registry.register(new Scheme("https", newSslSocketFactory(), 443)); + return new SingleClientConnManager(getParams(), registry); + } + + private SSLSocketFactory newSslSocketFactory() { + try { + // Get an instance of the Bouncy Castle KeyStore format + KeyStore trusted = ConfigHelper.getKeystore(); + + // Pass the keystore to the SSLSocketFactory. The factory is responsible + // for the verification of the server certificate. + SSLSocketFactory sf = new SSLSocketFactory(trusted); - @Override - protected ClientConnectionManager createClientConnectionManager() { - SchemeRegistry registry = new SchemeRegistry(); - registry.register(new Scheme("http", PlainSocketFactory.getSocketFactory(), 80)); - // Register for port 443 our SSLSocketFactory with our keystore - // to the ConnectionManager - registry.register(new Scheme("https", newSslSocketFactory(), 443)); - return new SingleClientConnManager(getParams(), registry); - } + // Hostname verification from certificate + // http://hc.apache.org/httpcomponents-client-ga/tutorial/html/connmgmt.html#d4e506 + sf.setHostnameVerifier(SSLSocketFactory.ALLOW_ALL_HOSTNAME_VERIFIER); - private SSLSocketFactory newSslSocketFactory() { - try { - // Get an instance of the Bouncy Castle KeyStore format - KeyStore trusted = ConfigHelper.getKeystore(); - - // Pass the keystore to the SSLSocketFactory. The factory is responsible - // for the verification of the server certificate. - SSLSocketFactory sf = new SSLSocketFactory(trusted); - - // Hostname verification from certificate - // http://hc.apache.org/httpcomponents-client-ga/tutorial/html/connmgmt.html#d4e506 - sf.setHostnameVerifier(SSLSocketFactory.ALLOW_ALL_HOSTNAME_VERIFIER); - - return sf; - } catch (Exception e) { - throw new AssertionError(e); - } - } + return sf; + } catch (Exception e) { + throw new AssertionError(e); + } + } - public static LeapHttpClient getInstance(Context context) { - if(client == null) { - client = new LeapHttpClient(context); - String cert_json_string = ConfigHelper.getStringFromSharedPref(ConfigHelper.main_cert_key); - String cert_string; - try { - cert_string = new JSONObject(cert_json_string).getString(ConfigHelper.main_cert_key); - if(!cert_string.isEmpty()) { - ConfigHelper.addTrustedCertificate("recovered_certificate", cert_string); - } - } catch (JSONException e) { - // TODO Auto-generated catch block - e.printStackTrace(); - } - } - return client; - } + public LeapHttpClient(Context context) { + this.context = context; + } } diff --git a/src/se/leap/leapclient/LeapSRPSession.java b/src/se/leap/leapclient/LeapSRPSession.java index f9037de9..7b32e791 100644 --- a/src/se/leap/leapclient/LeapSRPSession.java +++ b/src/se/leap/leapclient/LeapSRPSession.java @@ -47,8 +47,7 @@ public class LeapSRPSession { @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. This must be - 8 bytes in length. + @param abytes, the random exponent used in the A public key */ public LeapSRPSession(String username, String password, SRPParameters params, byte[] abytes) { @@ -177,8 +176,9 @@ public class LeapSRPSession { /** * 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 - * @param bs * @return the parameter M1 * @throws NoSuchAlgorithmException */ @@ -190,8 +190,6 @@ public class LeapSRPSession { // Calculate v = kg^x mod N String k_string = "bf66c44a428916cad64aa7c679f3fd897ad4c375e9bbb4cbf2f5de241d618ef0"; this.v = calculateV(k_string); - //String v_string = v.toString(16); - // H(N) byte[] digest_of_n = newDigest().digest(N_bytes); @@ -201,54 +199,45 @@ public class LeapSRPSession { // clientHash = H(N) xor H(g) byte[] xor_digest = xor(digest_of_n, digest_of_g, digest_of_g.length); - //String hxg_string = new BigInteger(1, xor_digest).toString(16); clientHash.update(xor_digest); // clientHash = H(N) xor H(g) | H(U) byte[] username_digest = newDigest().digest(Util.trim(username.getBytes())); username_digest = Util.trim(username_digest); - //String username_digest_string = new BigInteger(1, username_digest).toString(16); clientHash.update(username_digest); // clientHash = H(N) xor H(g) | H(U) | s - //String salt_string = new BigInteger(1, salt_bytes).toString(16); clientHash.update(Util.trim(salt_bytes)); K = null; - - // clientHash = H(N) xor H(g) | H(U) | s | A | B - - byte[] Abytes = Util.trim(A.toByteArray()); - //String Abytes_string = new BigInteger(1, Abytes).toString(16); // clientHash = H(N) xor H(g) | H(U) | A + byte[] Abytes = Util.trim(A.toByteArray()); clientHash.update(Abytes); // clientHash = H(N) xor H(g) | H(U) | s | A | B Bbytes = Util.trim(Bbytes); - //String Bbytes_string = new BigInteger(1, Bbytes).toString(16); clientHash.update(Bbytes); // Calculate S = (B - kg^x) ^ (a + u * x) % N BigInteger S = calculateS(Bbytes); byte[] S_bytes = Util.trim(S.toByteArray()); - //String S_bytes_string = new BigInteger(1, S_bytes).toString(16); // K = SessionHash(S) String hash_algorithm = params.hashAlgorithm; MessageDigest sessionDigest = MessageDigest.getInstance(hash_algorithm); K = Util.trim(sessionDigest.digest(S_bytes)); - //K = Util.trim(K); - //String K_bytes_string = new BigInteger(1, K).toString(16); // clientHash = H(N) xor H(g) | H(U) | A | B | K clientHash.update(K); + byte[] M1 = Util.trim(clientHash.digest()); // serverHash = Astr + M + K serverHash.update(Abytes); serverHash.update(M1); serverHash.update(K); + return M1; } @@ -263,13 +252,10 @@ public class LeapSRPSession { byte[] u_bytes = getU(Abytes, Bbytes); BigInteger B = new BigInteger(1, Bbytes); - //String Bstring = B.toString(16); BigInteger u = new BigInteger(1, u_bytes); - //String u_string = u.toString(16); BigInteger B_minus_v = B.subtract(v); BigInteger a_ux = a.add(u.multiply(x)); - //String a_ux_string = a_ux.toString(16); BigInteger S = B_minus_v.modPow(a_ux, N); return S; @@ -285,7 +271,7 @@ public class LeapSRPSession { MessageDigest u_digest = newDigest(); u_digest.update(Util.trim(Abytes)); u_digest.update(Util.trim(Bbytes)); - byte[] u_digest_bytes = u_digest.digest();//Util.trim(u_digest.digest()); + byte[] u_digest_bytes = u_digest.digest(); return Util.trim(new BigInteger(1, u_digest_bytes).toByteArray()); } @@ -302,17 +288,6 @@ public class LeapSRPSession { return valid; } - /** Returns the negotiated session K, K = SHA_Interleave(S) - @return the private session K byte[] - @throws SecurityException - if the current thread does not have an - getSessionKey SRPPermission. - */ - public byte[] getSessionKey() throws SecurityException - { - return K; - } - - /** * @return a new SHA-256 digest. */ diff --git a/src/se/leap/leapclient/LogInDialog.java b/src/se/leap/leapclient/LogInDialog.java index 30984db6..370a138c 100644 --- a/src/se/leap/leapclient/LogInDialog.java +++ b/src/se/leap/leapclient/LogInDialog.java @@ -1,8 +1,11 @@ package se.leap.leapclient; +import se.leap.leapclient.R; +import se.leap.leapclient.R.id; +import se.leap.leapclient.R.layout; +import se.leap.leapclient.R.string; import android.app.Activity; import android.app.AlertDialog; -import android.app.Dialog; import android.app.DialogFragment; import android.content.DialogInterface; import android.os.Bundle; @@ -12,49 +15,25 @@ import android.widget.EditText; import android.widget.Toast; public class LogInDialog extends DialogFragment { - - public interface LogInDialogInterface { - public void authenticate(String username, String password); - } - - LogInDialogInterface interface_with_Dashboard; - - public static DialogFragment newInstance() { - LogInDialog dialog_fragment = new LogInDialog(); - return dialog_fragment; - } - - @Override - public void onAttach(Activity activity) { - super.onAttach(activity); - // Verify that the host activity implements the callback interface - try { - // Instantiate the NoticeDialogListener so we can send events to the host - interface_with_Dashboard = (LogInDialogInterface) activity; - } catch (ClassCastException e) { - // The activity doesn't implement the interface, throw exception - throw new ClassCastException(activity.toString() - + " must implement NoticeDialogListener"); - } - } - public Dialog onCreateDialog(Bundle savedInstanceState) { + 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 EditText username_field = (EditText)log_in_dialog_view.findViewById(R.id.username_entered); final EditText password_field = (EditText)log_in_dialog_view.findViewById(R.id.password_entered); + builder.setView(log_in_dialog_view) .setPositiveButton(R.string.log_in_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(); - if(validPassword(password)) { + if(wellFormedPassword(password)) { interface_with_Dashboard.authenticate(username, password); - Toast.makeText(getActivity().getApplicationContext(), "Your password is valid", Toast.LENGTH_LONG).show(); } else { password_field.setText(""); - Toast.makeText(getActivity().getApplicationContext(), "Your password is not valid: it should have at least 8 characters", Toast.LENGTH_LONG).show(); + Toast.makeText(getActivity().getApplicationContext(), "Your password is not well-formed: it should have at least 8 characters", Toast.LENGTH_LONG).show(); } } }) @@ -63,11 +42,33 @@ public class LogInDialog extends DialogFragment { dialog.cancel(); } }); - // Create the AlertDialog object and return it + return builder.create(); } - boolean validPassword(String entered_password) { - return entered_password.length() > 4; + boolean wellFormedPassword(String entered_password) { + return entered_password.length() > 8; } + + public interface LogInDialogInterface { + public void authenticate(String username, String password); + } + + LogInDialogInterface interface_with_Dashboard; + + 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 NoticeDialogListener"); + } + } } diff --git a/src/se/leap/leapclient/NewProviderDialog.java b/src/se/leap/leapclient/NewProviderDialog.java index 61018463..99788001 100644 --- a/src/se/leap/leapclient/NewProviderDialog.java +++ b/src/se/leap/leapclient/NewProviderDialog.java @@ -1,5 +1,9 @@ package se.leap.leapclient; +import se.leap.leapclient.R; +import se.leap.leapclient.R.id; +import se.leap.leapclient.R.layout; +import se.leap.leapclient.R.string; import android.app.Activity; import android.app.AlertDialog; import android.app.Dialog; @@ -28,12 +32,9 @@ public class NewProviderDialog extends DialogFragment { @Override public void onAttach(Activity activity) { super.onAttach(activity); - // Verify that the host activity implements the callback interface try { - // Instantiate the NoticeDialogListener so we can send events to the host interface_with_ConfigurationWizard = (NewProviderDialogInterface) activity; } catch (ClassCastException e) { - // The activity doesn't implement the interface, throw exception throw new ClassCastException(activity.toString() + " must implement NoticeDialogListener"); } diff --git a/src/se/leap/leapclient/Provider.java b/src/se/leap/leapclient/Provider.java index 4235acfd..f86bbf59 100644 --- a/src/se/leap/leapclient/Provider.java +++ b/src/se/leap/leapclient/Provider.java @@ -18,7 +18,7 @@ import android.content.SharedPreferences; * @author Sean Leonard * */ -final class Provider implements Serializable { +public final class Provider implements Serializable { private static final long serialVersionUID = 6003835972151761353L; diff --git a/src/se/leap/leapclient/ProviderAPI.java b/src/se/leap/leapclient/ProviderAPI.java index b44c9971..00033440 100644 --- a/src/se/leap/leapclient/ProviderAPI.java +++ b/src/se/leap/leapclient/ProviderAPI.java @@ -11,7 +11,6 @@ import java.security.NoSuchAlgorithmException; import java.security.cert.CertificateException; import java.security.cert.CertificateFactory; import java.security.cert.X509Certificate; -import java.util.List; import java.net.CookieHandler; import java.net.CookieManager; import java.net.HttpCookie; @@ -32,6 +31,7 @@ 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; @@ -63,89 +63,72 @@ public class ProviderAPI extends IntentService { final ResultReceiver receiver = task_for.getParcelableExtra("receiver"); Bundle task; - if((task = task_for.getBundleExtra(ConfigHelper.downloadJsonFilesBundleExtra)) != null) { - if(!downloadJsonFiles(task)) + if((task = task_for.getBundleExtra(ConfigHelper.DOWNLOAD_JSON_FILES_BUNDLE_EXTRA)) != null) { + if(!downloadJsonFiles(task)) { receiver.send(ConfigHelper.INCORRECTLY_DOWNLOADED_JSON_FILES, Bundle.EMPTY); - else + } else { receiver.send(ConfigHelper.CORRECTLY_DOWNLOADED_JSON_FILES, Bundle.EMPTY); + } } - else if ((task = task_for.getBundleExtra(ConfigHelper.updateProviderDotJSON)) != null) { - JSONObject result = updateProviderDotJSON(task); - boolean successful; - try { - successful = result.getBoolean(ConfigHelper.resultKey); - if(successful) { - Bundle provider_dot_json_and_danger_on = new Bundle(); - provider_dot_json_and_danger_on.putBoolean(ConfigHelper.danger_on, result.getBoolean(ConfigHelper.danger_on)); - provider_dot_json_and_danger_on.putString(ConfigHelper.provider_key, result.getJSONObject(ConfigHelper.provider_key).toString()); - receiver.send(ConfigHelper.CORRECTLY_UPDATED_PROVIDER_DOT_JSON, provider_dot_json_and_danger_on); - } else { - receiver.send(ConfigHelper.INCORRECTLY_UPDATED_PROVIDER_DOT_JSON, Bundle.EMPTY); - } - } catch (JSONException e) { - // TODO Auto-generated catch block - e.printStackTrace(); + else if ((task = task_for.getBundleExtra(ConfigHelper.UPDATE_PROVIDER_DOTJSON)) != null) { + Bundle result = updateProviderDotJSON(task); + if(result.getBoolean(ConfigHelper.RESULT_KEY)) { + receiver.send(ConfigHelper.CORRECTLY_UPDATED_PROVIDER_DOT_JSON, result); + } else { + receiver.send(ConfigHelper.INCORRECTLY_UPDATED_PROVIDER_DOT_JSON, Bundle.EMPTY); } } - else if ((task = task_for.getBundleExtra(ConfigHelper.downloadNewProviderDotJSON)) != null) { - if(downloadNewProviderDotJSON(task)) + else if ((task = task_for.getBundleExtra(ConfigHelper.DOWNLOAD_NEW_PROVIDER_DOTJSON)) != null) { + if(downloadNewProviderDotJSON(task)) { receiver.send(ConfigHelper.CUSTOM_PROVIDER_ADDED, Bundle.EMPTY); - else + } else { receiver.send(ConfigHelper.INCORRECTLY_DOWNLOADED_JSON_FILES, Bundle.EMPTY); + } } - else if ((task = task_for.getBundleExtra(ConfigHelper.srpAuth)) != null) { - try { - JSONObject session_idAndResult = authenticateBySRP(task); - if(session_idAndResult.getBoolean(ConfigHelper.resultKey)) { - Bundle session_id_bundle = new Bundle(); - session_id_bundle.putString(ConfigHelper.session_id_cookie_key, session_idAndResult.getString(ConfigHelper.session_id_cookie_key)); - session_id_bundle.putString(ConfigHelper.session_id_key, session_idAndResult.getString(ConfigHelper.session_id_key)); - receiver.send(ConfigHelper.SRP_AUTHENTICATION_SUCCESSFUL, session_id_bundle); - } else { - receiver.send(ConfigHelper.SRP_AUTHENTICATION_FAILED, Bundle.EMPTY); - } - } catch (JSONException e) { - // TODO Auto-generated catch block - e.printStackTrace(); + else if ((task = task_for.getBundleExtra(ConfigHelper.SRP_AUTH)) != null) { + Bundle session_id_bundle = authenticateBySRP(task); + if(session_id_bundle.getBoolean(ConfigHelper.RESULT_KEY)) { + receiver.send(ConfigHelper.SRP_AUTHENTICATION_SUCCESSFUL, session_id_bundle); + } else { + receiver.send(ConfigHelper.SRP_AUTHENTICATION_FAILED, Bundle.EMPTY); } } - else if ((task = task_for.getBundleExtra(ConfigHelper.logOut)) != null) { - if(logOut(task)) + else if ((task = task_for.getBundleExtra(ConfigHelper.LOG_OUT)) != null) { + if(logOut(task)) { receiver.send(ConfigHelper.LOGOUT_SUCCESSFUL, Bundle.EMPTY); - else + } else { receiver.send(ConfigHelper.LOGOUT_FAILED, Bundle.EMPTY); + } } - else if ((task = task_for.getBundleExtra(ConfigHelper.downloadUserAuthedCertificate)) != null) { - if(getNewCert(task)) + else if ((task = task_for.getBundleExtra(ConfigHelper.DOWNLOAD_USER_AUTHED_CERTIFICATE)) != null) { + if(getNewCert(task)) { receiver.send(ConfigHelper.CORRECTLY_DOWNLOADED_AUTHED_USER_CERTIFICATE, Bundle.EMPTY); - else + } else { receiver.send(ConfigHelper.INCORRECTLY_DOWNLOADED_AUTHED_USER_CERTIFICATE, Bundle.EMPTY); + } } } private boolean downloadJsonFiles(Bundle task) { - //String provider_name = task.getString(ConfigHelper.provider_key); - 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(ConfigHelper.MAIN_CERT_KEY); + 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); - //ConfigHelper.addTrustedCertificate(provider_name, cert_string); - JSONObject cert_json = new JSONObject().put(ConfigHelper.main_cert_key, cert_string); - ConfigHelper.saveSharedPref(ConfigHelper.main_cert_key, cert_json); + JSONObject cert_json = new JSONObject().put(ConfigHelper.MAIN_CERT_KEY, cert_string); + ConfigHelper.saveSharedPref(ConfigHelper.MAIN_CERT_KEY, cert_json); JSONObject eip_service_json = getJSONFromProvider(eip_service_json_url, danger_on); - ConfigHelper.saveSharedPref(ConfigHelper.eip_service_key, eip_service_json); + ConfigHelper.saveSharedPref(ConfigHelper.EIP_SERVICE_KEY, eip_service_json); return true; } catch (JSONException e) { - ConfigHelper.rescueJSONException(e); return false; } } private boolean registerWithSRP(Bundle task) { - String username = (String) task.get(ConfigHelper.username_key); - String password = (String) task.get(ConfigHelper.password_key); - String authentication_server = (String) task.get(ConfigHelper.api_url_key); + String username = (String) task.get(ConfigHelper.USERNAME_KEY); + String password = (String) task.get(ConfigHelper.PASSWORD_KEY); + String authentication_server = (String) task.get(ConfigHelper.API_URL_KEY); BigInteger ng_1024 = new BigInteger(ConfigHelper.NG_1024, 16); BigInteger salt = ng_1024.probablePrime(1024, null); @@ -154,173 +137,127 @@ public class ProviderAPI extends IntentService { return false; } - private JSONObject authenticateBySRP(Bundle task) { - JSONObject successfulAndsession_id = new JSONObject(); - - String username = (String) task.get(ConfigHelper.username_key); - String password = (String) task.get(ConfigHelper.password_key); - String authentication_server = (String) task.get(ConfigHelper.api_url_key); + private Bundle authenticateBySRP(Bundle task) { + Bundle session_id_bundle = new Bundle(); - String salt = "abcd"; + String username = (String) task.get(ConfigHelper.USERNAME_KEY); + String password = (String) task.get(ConfigHelper.PASSWORD_KEY); + String authentication_server = (String) task.get(ConfigHelper.API_URL_KEY); - SRPParameters params = new SRPParameters(new BigInteger(ConfigHelper.NG_1024, 16).toByteArray(), new BigInteger("2").toByteArray(), new BigInteger(salt, 16).toByteArray(), "SHA-256"); - //SRPClientSession client = new SRPClientSession(username, password.toCharArray(), params); + 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) { - salt = saltAndB.getString("salt"); + String salt = saltAndB.getString(ConfigHelper.SALT_KEY); byte[] Bbytes = new BigInteger(saltAndB.getString("B"), 16).toByteArray(); byte[] M1 = client.response(new BigInteger(salt, 16).toByteArray(), Bbytes); - //byte[] M2 = sendM1ToSRPServer(authentication_server, username, M1); JSONObject session_idAndM2 = sendM1ToSRPServer(authentication_server, username, M1); if( client.verify((byte[])session_idAndM2.get("M2")) == false ) { - //throw new SecurityException("Failed to validate server reply: M2 = " + new BigInteger(1, M2).toString(16)); - successfulAndsession_id.put(ConfigHelper.resultKey, false); - return successfulAndsession_id; + session_id_bundle.putBoolean(ConfigHelper.RESULT_KEY, false); } else { - successfulAndsession_id.put(ConfigHelper.resultKey, true); - successfulAndsession_id.put(ConfigHelper.session_id_key, session_idAndM2.getString(ConfigHelper.session_id_key)); - successfulAndsession_id.put(ConfigHelper.session_id_cookie_key, session_idAndM2.getString(ConfigHelper.session_id_cookie_key)); - return successfulAndsession_id; + 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)); } } else { - successfulAndsession_id.put(ConfigHelper.resultKey, false); - return successfulAndsession_id; + session_id_bundle.putBoolean(ConfigHelper.RESULT_KEY, false); } - } catch (ClientProtocolException e1) { - // TODO Auto-generated catch block - e1.printStackTrace(); - } catch (IOException e1) { - // TODO Auto-generated catch block - e1.printStackTrace(); - } catch (JSONException e1) { - // TODO Auto-generated catch block - e1.printStackTrace(); + } catch (ClientProtocolException e) { + session_id_bundle.putBoolean(ConfigHelper.RESULT_KEY, false); + } catch (IOException e) { + session_id_bundle.putBoolean(ConfigHelper.RESULT_KEY, false); + } catch (JSONException e) { + session_id_bundle.putBoolean(ConfigHelper.RESULT_KEY, false); } catch (NoSuchAlgorithmException e) { - // TODO Auto-generated catch block - e.printStackTrace(); + session_id_bundle.putBoolean(ConfigHelper.RESULT_KEY, false); } - return successfulAndsession_id; + + return session_id_bundle; } private JSONObject sendAToSRPServer(String server_url, String username, String clientA) throws ClientProtocolException, IOException, JSONException { - DefaultHttpClient client = LeapHttpClient.getInstance(getApplicationContext()); - String parameter_chain = "A" + "=" + clientA + "&" + "login" + "=" + username; - HttpPost post = new HttpPost(server_url + "/sessions.json" + "?" + parameter_chain); - - HttpResponse getResponse = client.execute(post); - 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("errors") || json_response.has("errors")) { - return new JSONObject(); - } - - String session_id = ""; - List cookies = client.getCookieStore().getCookies(); - if(!cookies.isEmpty()) { - session_id = cookies.get(0).getValue(); - } - return json_response; + HttpPost post = new HttpPost(server_url + "/sessions.json" + "?" + "login=" + username + "&&" + "A=" + clientA); + return sendToServer(post); } 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, Util.trim(m1)).toString(16)); + JSONObject json_response = sendToServer(put); + JSONObject session_idAndM2 = new JSONObject(); + if(json_response.length() > 0) { + byte[] M2_not_trimmed = new BigInteger(json_response.getString("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("M2", Util.trim(M2_not_trimmed)); + } + return session_idAndM2; + } + + private JSONObject sendToServer(HttpUriRequest request) throws ClientProtocolException, IOException, JSONException { DefaultHttpClient client = LeapHttpClient.getInstance(getApplicationContext()); - String parameter_chain = "client_auth" + "=" + new BigInteger(1, Util.trim(m1)).toString(16); - HttpPut put = new HttpPut(server_url + "/sessions/" + username +".json" + "?" + parameter_chain); HttpContext localContext = new BasicHttpContext(); localContext.setAttribute(ClientContext.COOKIE_STORE, client.getCookieStore()); - String session_id = client.getCookieStore().getCookies().get(0).getValue(); - int number_of_cookies = client.getCookieStore().getCookies().size(); - HttpResponse getResponse = client.execute(put, 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); if(!json_response.isNull("errors") || json_response.has("errors")) { - return session_idAndM2; + return new JSONObject(); } - number_of_cookies = client.getCookieStore().getCookies().size(); - byte[] M2_not_trimmed = new BigInteger(json_response.getString("M2"), 16).toByteArray(); - session_idAndM2.put(ConfigHelper.session_id_cookie_key, client.getCookieStore().getCookies().get(0).getName()); - session_idAndM2.put(ConfigHelper.session_id_key, client.getCookieStore().getCookies().get(0).getValue()); - session_idAndM2.put("M2", Util.trim(M2_not_trimmed)); - return session_idAndM2; + return json_response; } - private JSONObject updateProviderDotJSON(Bundle task) { - JSONObject result = new JSONObject(); - 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); + 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); - JSONObject provider_json = null; try { - provider_json = getJSONFromProvider(provider_json_url, danger_on); - } catch (JSONException e) { - // TODO Auto-generated catch block - e.printStackTrace(); - try { - return result.put(ConfigHelper.resultKey, false); - } catch (JSONException e1) { - // TODO Auto-generated catch block - e1.printStackTrace(); - } - } - - if(provider_json == null) { - try { - return result.put(ConfigHelper.resultKey, false); - } catch (JSONException e) { - // TODO Auto-generated catch block - e.printStackTrace(); - } - } else { - String filename = provider_name + "_provider.json".replaceFirst("__", "_"); - ConfigHelper.saveFile(filename, provider_json.toString()); - //ConfigHelper.saveSharedPref(ConfigHelper.provider_key, provider_json); + JSONObject provider_json = getJSONFromProvider(provider_json_url, danger_on); + if(provider_json == null) { + result.putBoolean(ConfigHelper.RESULT_KEY, false); + } else { + String filename = provider_name + "_provider.json".replaceFirst("__", "_"); + ConfigHelper.saveFile(filename, provider_json.toString()); - ProviderListContent.addItem(new ProviderItem(provider_name, provider_json_url, filename, custom, danger_on)); - try { - return result.put(ConfigHelper.resultKey, true).put(ConfigHelper.provider_key, provider_json).put(ConfigHelper.danger_on, danger_on); - } catch (JSONException e) { - // TODO Auto-generated catch block - e.printStackTrace(); + ProviderListContent.addItem(new ProviderItem(provider_name, provider_json_url, filename, custom, danger_on)); + result.putBoolean(ConfigHelper.RESULT_KEY, true); + result.putString(ConfigHelper.PROVIDER_KEY, provider_json.toString()); + result.putBoolean(ConfigHelper.DANGER_ON, danger_on); } + } catch (JSONException e) { + result.putBoolean(ConfigHelper.RESULT_KEY, false); } + return result; } private boolean downloadNewProviderDotJSON(Bundle task) { boolean custom = true; - boolean danger_on = task.getBoolean(ConfigHelper.danger_on); + boolean danger_on = task.getBoolean(ConfigHelper.DANGER_ON); - String provider_main_url = (String) task.get(ConfigHelper.provider_main_url); + String provider_main_url = (String) task.get(ConfigHelper.PROVIDER_MAIN_URL); String provider_name = provider_main_url.replaceFirst("http[s]?://", "").replaceFirst("\\/", "_"); String provider_json_url = guessURL(provider_main_url); JSONObject provider_json = null; try { provider_json = getJSONFromProvider(provider_json_url, danger_on); - } catch (JSONException e) { - // TODO Auto-generated catch block - e.printStackTrace(); - return false; - } - - if(provider_json == null) { - return false; - } else { + String filename = provider_name + "_provider.json".replaceFirst("__", "_"); ConfigHelper.saveFile(filename, provider_json.toString()); - //ConfigHelper.saveSharedPref(ConfigHelper.provider_key, provider_json); ProviderListContent.addItem(new ProviderItem(provider_name, provider_json_url, filename, custom, danger_on)); return true; + } catch (JSONException e) { + return false; } } @@ -385,8 +322,8 @@ public class ProviderAPI extends IntentService { try { cf = CertificateFactory.getInstance("X.509"); - String cert_json_string = ConfigHelper.getStringFromSharedPref(ConfigHelper.main_cert_key); - String cert_string = new JSONObject(cert_json_string).getString(ConfigHelper.main_cert_key); + String cert_json_string = ConfigHelper.getStringFromSharedPref(ConfigHelper.MAIN_CERT_KEY); + String cert_string = new JSONObject(cert_json_string).getString(ConfigHelper.MAIN_CERT_KEY); cert_string = cert_string.replaceFirst("-----BEGIN CERTIFICATE-----", "").replaceFirst("-----END CERTIFICATE-----", "").trim(); byte[] cert_bytes = Base64.decode(cert_string, Base64.DEFAULT); InputStream caInput = new ByteArrayInputStream(cert_bytes); @@ -454,7 +391,7 @@ public class ProviderAPI extends IntentService { 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" + "?authenticity_token=" + client.getCookieStore().getCookies().get(session_id_index).getValue(); HttpDelete delete = new HttpDelete(delete_url); HttpResponse getResponse = client.execute(delete); HttpEntity responseEntity = getResponse.getEntity(); @@ -476,24 +413,24 @@ public class ProviderAPI extends IntentService { } private boolean getNewCert(Bundle task) { - String provider_json_string = ConfigHelper.getStringFromSharedPref(ConfigHelper.provider_key); - HttpCookie session_id_cookie = new HttpCookie(task.getString(ConfigHelper.session_id_cookie_key), task.getString(ConfigHelper.session_id_key)); + String provider_json_string = ConfigHelper.getStringFromSharedPref(ConfigHelper.PROVIDER_KEY); + HttpCookie session_id_cookie = new HttpCookie(task.getString(ConfigHelper.SESSION_ID_COOKIE_KEY), task.getString(ConfigHelper.SESSION_ID_KEY)); try { JSONObject provider_json = new JSONObject(provider_json_string); - URL provider_main_url = new URL(provider_json.getString(ConfigHelper.api_url_key).replace("api.", "")); - String new_cert_string_url = provider_main_url.getProtocol() + "://" + provider_main_url.getHost() + "/" + provider_json.getString(ConfigHelper.api_version_key) + "/" + ConfigHelper.cert_key; + URL provider_main_url = new URL(provider_json.getString(ConfigHelper.API_URL_KEY).replace("api.", "")); + String new_cert_string_url = provider_main_url.getProtocol() + "://" + provider_main_url.getHost() + "/" + provider_json.getString(ConfigHelper.API_VERSION_KEY) + "/" + ConfigHelper.CERT_KEY; CookieManager cookieManager = new CookieManager(); cookieManager.getCookieStore().add(provider_main_url.toURI(), session_id_cookie); CookieHandler.setDefault(cookieManager); - String danger_on_json_string = ConfigHelper.getStringFromSharedPref(ConfigHelper.danger_on); - boolean danger_on = new JSONObject(danger_on_json_string).getBoolean(ConfigHelper.danger_on); + String danger_on_json_string = ConfigHelper.getStringFromSharedPref(ConfigHelper.DANGER_ON); + boolean danger_on = new JSONObject(danger_on_json_string).getBoolean(ConfigHelper.DANGER_ON); String cert_string = getStringFromProvider(new_cert_string_url, danger_on); if(!cert_string.isEmpty()) { - JSONObject cert_json = new JSONObject().put(ConfigHelper.cert_key, cert_string); - ConfigHelper.saveSharedPref(ConfigHelper.cert_key, cert_json); + JSONObject cert_json = new JSONObject().put(ConfigHelper.CERT_KEY, cert_string); + ConfigHelper.saveSharedPref(ConfigHelper.CERT_KEY, cert_json); return true; } else { return false; diff --git a/src/se/leap/leapclient/ProviderListContent.java b/src/se/leap/leapclient/ProviderListContent.java index d4bb6a9a..b83bbd8e 100644 --- a/src/se/leap/leapclient/ProviderListContent.java +++ b/src/se/leap/leapclient/ProviderListContent.java @@ -91,7 +91,7 @@ public class ProviderListContent { this.name = name; this.provider_json_url = provider_json_url; this.provider_json_filename = provider_json_filename; - eip_service_json_url = file_contents.getString("api_uri") + "/" + file_contents.getString("api_version") + "/" + ConfigHelper.eip_service_api_path; + eip_service_json_url = file_contents.getString("api_uri") + "/" + file_contents.getString("api_version") + "/" + ConfigHelper.EIP_SERVICE_API_PATH; cert_json_url = (String) file_contents.get("ca_cert_uri"); this.custom = custom; this.danger_on = danger_on; -- cgit v1.2.3 From 75edcdb601be69f4c1ee6783cf7f80390a9f094d Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Parm=C3=A9nides=20GV?= Date: Tue, 14 May 2013 21:03:07 +0200 Subject: Anon certificate is downloaded if possible. I download the anon certificate only if allow_anonymous is true, and before launching Dashboard. I store it in SharedPreferences, with "cert" key, as a JSON object. --- src/se/leap/leapclient/ConfigHelper.java | 14 ++++++--- src/se/leap/leapclient/ConfigurationWizard.java | 39 ++++++++++++++++++++++++- src/se/leap/leapclient/Dashboard.java | 7 +++-- src/se/leap/leapclient/ProviderAPI.java | 24 ++++++++------- 4 files changed, 66 insertions(+), 18 deletions(-) (limited to 'src/se/leap/leapclient') diff --git a/src/se/leap/leapclient/ConfigHelper.java b/src/se/leap/leapclient/ConfigHelper.java index 5d44f004..6a70378f 100644 --- a/src/se/leap/leapclient/ConfigHelper.java +++ b/src/se/leap/leapclient/ConfigHelper.java @@ -37,14 +37,18 @@ public class ConfigHelper { SRP_AUTH = "srpAuth", LOG_IN = "logIn", LOG_OUT = "logOut", - DOWNLOAD_USER_AUTHED_CERTIFICATE = "downloadUserAuthedCertificate", + DOWNLOAD_CERTIFICATE = "downloadUserAuthedCertificate", API_VERSION_KEY = "api_version", RESULT_KEY = "result", PROVIDER_KEY = "provider", SERVICE_KEY = "service", + ALLOWED_ANON = "allow_anonymous", MAIN_CERT_KEY = "main_cert", CERT_KEY = "cert", EIP_SERVICE_KEY = "eip", + TYPE_OF_CERTIFICATE = "type_of_certificate", + ANON_CERTIFICATE = "anon_certificate", + AUTHED_CERTIFICATE = "authed_certificate", SALT_KEY = "salt", SESSION_ID_COOKIE_KEY = "session_id_cookie_key", SESSION_ID_KEY = "session_id", @@ -76,10 +80,12 @@ public class ConfigHelper { SRP_REGISTRATION_FAILED = 6, LOGOUT_SUCCESSFUL = 7, LOGOUT_FAILED = 8, - CORRECTLY_DOWNLOADED_AUTHED_USER_CERTIFICATE = 9, - INCORRECTLY_DOWNLOADED_AUTHED_USER_CERTIFICATE = 10, + CORRECTLY_DOWNLOADED_CERTIFICATE = 9, + INCORRECTLY_DOWNLOADED_CERTIFICATE = 10, CORRECTLY_UPDATED_PROVIDER_DOT_JSON = 11, - INCORRECTLY_UPDATED_PROVIDER_DOT_JSON = 12 + INCORRECTLY_UPDATED_PROVIDER_DOT_JSON = 12, + CORRECTLY_DOWNLOADED_ANON_CERTIFICATE = 13, + INCORRECTLY_DOWNLOADED_ANON_CERTIFICATE = 14 ; public static void saveSharedPref(String shared_preferences_key, JSONObject content) { diff --git a/src/se/leap/leapclient/ConfigurationWizard.java b/src/se/leap/leapclient/ConfigurationWizard.java index 78ac0462..fff155a8 100644 --- a/src/se/leap/leapclient/ConfigurationWizard.java +++ b/src/se/leap/leapclient/ConfigurationWizard.java @@ -73,7 +73,6 @@ public class ConfigurationWizard extends Activity } else if(resultCode == ConfigHelper.CORRECTLY_DOWNLOADED_JSON_FILES) { setResult(RESULT_OK); - finish(); } else if(resultCode == ConfigHelper.INCORRECTLY_DOWNLOADED_JSON_FILES) { setResult(RESULT_CANCELED); @@ -86,6 +85,7 @@ public class ConfigurationWizard extends Activity boolean danger_on = resultData.getBoolean(ConfigHelper.DANGER_ON); ConfigHelper.saveSharedPref(ConfigHelper.PROVIDER_KEY, provider_json); ConfigHelper.saveSharedPref(ConfigHelper.DANGER_ON, new JSONObject().put(ConfigHelper.DANGER_ON, danger_on)); + downloadAnonCert(); } catch (JSONException e) { // TODO Auto-generated catch block e.printStackTrace(); @@ -94,6 +94,14 @@ public class ConfigurationWizard extends Activity else if(resultCode == ConfigHelper.INCORRECTLY_UPDATED_PROVIDER_DOT_JSON) { Toast.makeText(getApplicationContext(), "Install a new version of this app.", Toast.LENGTH_LONG).show(); } + else if(resultCode == ConfigHelper.CORRECTLY_DOWNLOADED_CERTIFICATE) { + setResult(RESULT_OK); + Toast.makeText(getApplicationContext(), "Your anon cert has been correctly downloaded", Toast.LENGTH_LONG).show(); + finish(); + } else if(resultCode == ConfigHelper.INCORRECTLY_DOWNLOADED_CERTIFICATE) { + setResult(RESULT_CANCELED); + Toast.makeText(getApplicationContext(), "Your anon cert was not downloaded", Toast.LENGTH_LONG).show(); + } } /** @@ -155,7 +163,9 @@ public class ConfigurationWizard extends Activity provider_contents = new Scanner(ConfigHelper.openFileInputStream(current_provider_item.provider_json_filename)).useDelimiter("\\A").next(); provider_json = new JSONObject(provider_contents); ConfigHelper.saveSharedPref(ConfigHelper.PROVIDER_KEY, provider_json); + ConfigHelper.saveSharedPref(ConfigHelper.ALLOWED_ANON, new JSONObject().put(ConfigHelper.ALLOWED_ANON, provider_json.getJSONObject(ConfigHelper.SERVICE_KEY).getBoolean(ConfigHelper.ALLOWED_ANON))); ConfigHelper.saveSharedPref(ConfigHelper.DANGER_ON, new JSONObject().put(ConfigHelper.DANGER_ON, current_provider_item.danger_on)); + downloadAnonCert(); return true; } } catch (JSONException e) { @@ -182,6 +192,33 @@ public class ConfigurationWizard extends Activity startService(provider_API_command); } + private boolean downloadAnonCert() { + + JSONObject allowed_anon; + try { + allowed_anon = new JSONObject(ConfigHelper.getStringFromSharedPref(ConfigHelper.ALLOWED_ANON)); + if(allowed_anon.getBoolean(ConfigHelper.ALLOWED_ANON)) { + providerAPI_result_receiver = new ProviderAPIResultReceiver(new Handler()); + providerAPI_result_receiver.setReceiver(this); + + Intent provider_API_command = new Intent(this, ProviderAPI.class); + + Bundle method_and_parameters = new Bundle(); + + method_and_parameters.putString(ConfigHelper.TYPE_OF_CERTIFICATE, ConfigHelper.ANON_CERTIFICATE); + + provider_API_command.putExtra(ConfigHelper.DOWNLOAD_CERTIFICATE, method_and_parameters); + provider_API_command.putExtra("receiver", providerAPI_result_receiver); + + startService(provider_API_command); + return true; + } else { + return false; + } + } catch (JSONException e) { + return false; + } + } public void addNewProvider(View view) { FragmentTransaction fragment_transaction = getFragmentManager().beginTransaction(); Fragment previous_new_provider_dialog = getFragmentManager().findFragmentByTag(ConfigHelper.NEW_PROVIDER_DIALOG); diff --git a/src/se/leap/leapclient/Dashboard.java b/src/se/leap/leapclient/Dashboard.java index b937c949..5ffbc19e 100644 --- a/src/se/leap/leapclient/Dashboard.java +++ b/src/se/leap/leapclient/Dashboard.java @@ -250,10 +250,11 @@ 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()); - provider_API_command.putExtra(ConfigHelper.DOWNLOAD_USER_AUTHED_CERTIFICATE, method_and_parameters); + provider_API_command.putExtra(ConfigHelper.DOWNLOAD_CERTIFICATE, method_and_parameters); provider_API_command.putExtra("receiver", providerAPI_result_receiver); startService(provider_API_command); @@ -278,10 +279,10 @@ public class Dashboard extends Activity implements LogInDialog.LogInDialogInterf } else if(resultCode == ConfigHelper.LOGOUT_FAILED) { setResult(RESULT_CANCELED); Toast.makeText(getApplicationContext(), "Didn't logged out", Toast.LENGTH_LONG).show(); - } else if(resultCode == ConfigHelper.CORRECTLY_DOWNLOADED_AUTHED_USER_CERTIFICATE) { + } else if(resultCode == ConfigHelper.CORRECTLY_DOWNLOADED_CERTIFICATE) { setResult(RESULT_CANCELED); Toast.makeText(getApplicationContext(), "Your own cert has been correctly downloaded", Toast.LENGTH_LONG).show(); - } else if(resultCode == ConfigHelper.INCORRECTLY_DOWNLOADED_AUTHED_USER_CERTIFICATE) { + } else if(resultCode == ConfigHelper.INCORRECTLY_DOWNLOADED_CERTIFICATE) { setResult(RESULT_CANCELED); Toast.makeText(getApplicationContext(), "Your own cert has incorrectly been downloaded", Toast.LENGTH_LONG).show(); } diff --git a/src/se/leap/leapclient/ProviderAPI.java b/src/se/leap/leapclient/ProviderAPI.java index 00033440..d5e164d6 100644 --- a/src/se/leap/leapclient/ProviderAPI.java +++ b/src/se/leap/leapclient/ProviderAPI.java @@ -100,11 +100,11 @@ public class ProviderAPI extends IntentService { receiver.send(ConfigHelper.LOGOUT_FAILED, Bundle.EMPTY); } } - else if ((task = task_for.getBundleExtra(ConfigHelper.DOWNLOAD_USER_AUTHED_CERTIFICATE)) != null) { + else if ((task = task_for.getBundleExtra(ConfigHelper.DOWNLOAD_CERTIFICATE)) != null) { if(getNewCert(task)) { - receiver.send(ConfigHelper.CORRECTLY_DOWNLOADED_AUTHED_USER_CERTIFICATE, Bundle.EMPTY); + receiver.send(ConfigHelper.CORRECTLY_DOWNLOADED_CERTIFICATE, Bundle.EMPTY); } else { - receiver.send(ConfigHelper.INCORRECTLY_DOWNLOADED_AUTHED_USER_CERTIFICATE, Bundle.EMPTY); + receiver.send(ConfigHelper.INCORRECTLY_DOWNLOADED_CERTIFICATE, Bundle.EMPTY); } } } @@ -224,7 +224,9 @@ public class ProviderAPI extends IntentService { JSONObject provider_json = getJSONFromProvider(provider_json_url, danger_on); if(provider_json == null) { result.putBoolean(ConfigHelper.RESULT_KEY, false); - } else { + } else { + ConfigHelper.saveSharedPref(ConfigHelper.ALLOWED_ANON, new JSONObject().put(ConfigHelper.ALLOWED_ANON, provider_json.getJSONObject(ConfigHelper.SERVICE_KEY).getBoolean(ConfigHelper.ALLOWED_ANON))); + String filename = provider_name + "_provider.json".replaceFirst("__", "_"); ConfigHelper.saveFile(filename, provider_json.toString()); @@ -414,17 +416,20 @@ public class ProviderAPI extends IntentService { private boolean getNewCert(Bundle task) { String provider_json_string = ConfigHelper.getStringFromSharedPref(ConfigHelper.PROVIDER_KEY); - HttpCookie session_id_cookie = new HttpCookie(task.getString(ConfigHelper.SESSION_ID_COOKIE_KEY), task.getString(ConfigHelper.SESSION_ID_KEY)); - + String type_of_certificate = task.getString(ConfigHelper.TYPE_OF_CERTIFICATE); try { JSONObject provider_json = new JSONObject(provider_json_string); URL provider_main_url = new URL(provider_json.getString(ConfigHelper.API_URL_KEY).replace("api.", "")); String new_cert_string_url = provider_main_url.getProtocol() + "://" + provider_main_url.getHost() + "/" + provider_json.getString(ConfigHelper.API_VERSION_KEY) + "/" + ConfigHelper.CERT_KEY; - CookieManager cookieManager = new CookieManager(); - cookieManager.getCookieStore().add(provider_main_url.toURI(), session_id_cookie); - CookieHandler.setDefault(cookieManager); + 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)); + CookieManager cookieManager = new CookieManager(); + cookieManager.getCookieStore().add(provider_main_url.toURI(), session_id_cookie); + CookieHandler.setDefault(cookieManager); + } + String danger_on_json_string = ConfigHelper.getStringFromSharedPref(ConfigHelper.DANGER_ON); boolean danger_on = new JSONObject(danger_on_json_string).getBoolean(ConfigHelper.DANGER_ON); String cert_string = getStringFromProvider(new_cert_string_url, danger_on); @@ -435,7 +440,6 @@ public class ProviderAPI extends IntentService { } else { return false; } - } catch (IOException e) { // TODO Auto-generated catch block e.printStackTrace(); -- cgit v1.2.3 From 7b75fbe9ca3b2d6175b124b26f5d8f527b15d1bd Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Parm=C3=A9nides=20GV?= Date: Wed, 29 May 2013 19:54:26 +0200 Subject: Fixed passwords with strange characters? Using two test with values from my localhost leap_web deployment, I've achieved to login with passwords containing ! and $ without problems. This should fix bug #2348. --- src/se/leap/leapclient/LeapSRPSession.java | 21 +++++---------------- 1 file changed, 5 insertions(+), 16 deletions(-) (limited to 'src/se/leap/leapclient') diff --git a/src/se/leap/leapclient/LeapSRPSession.java b/src/se/leap/leapclient/LeapSRPSession.java index 7b32e791..715e9de1 100644 --- a/src/se/leap/leapclient/LeapSRPSession.java +++ b/src/se/leap/leapclient/LeapSRPSession.java @@ -95,35 +95,24 @@ public class LeapSRPSession { MessageDigest x_digest = newDigest(); // Try to convert the username to a byte[] using UTF-8 byte[] user = null; + byte[] password_bytes = null; byte[] colon = {}; try { user = Util.trim(username.getBytes("UTF-8")); colon = Util.trim(":".getBytes("UTF-8")); + password_bytes = Util.trim(password.getBytes("UTF-8")); } catch(UnsupportedEncodingException e) { // Use the default platform encoding user = Util.trim(username.getBytes()); colon = Util.trim(":".getBytes()); + password_bytes = Util.trim(password.getBytes()); } - - byte[] passBytes = new byte[2*password.toCharArray().length]; - int passBytesLength = 0; - for(int p = 0; p < password.toCharArray().length; p++) { - int c = (password.toCharArray()[p] & 0x00FFFF); - // The low byte of the char - byte b0 = (byte) (c & 0x0000FF); - // The high byte of the char - byte b1 = (byte) ((c & 0x00FF00) >> 8); - passBytes[passBytesLength ++] = b0; - // Only encode the high byte if c is a multi-byte char - if( c > 255 ) - passBytes[passBytesLength ++] = b1; - } - + // Build the hash x_digest.update(user); x_digest.update(colon); - x_digest.update(passBytes, 0, passBytesLength); + x_digest.update(password_bytes); byte[] h = x_digest.digest(); //h = Util.trim(h); -- cgit v1.2.3 From ac47aab124d63add14189cb3d03e3a05361a7932 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Parm=C3=A9nides=20GV?= Date: Tue, 4 Jun 2013 16:31:39 +0200 Subject: Fixed 2 important bugs. LeapSRPSession was doing bad SRP calculations when salt byte array started with a 0. Now I trimmed that array before using it. ProviderAPI was not timing out when a server didn't respond. Now, I use a timeout of 1 second to stop waiting for a response. --- src/se/leap/leapclient/LeapSRPSession.java | 27 ++++++++++++++++++++++++--- src/se/leap/leapclient/ProviderAPI.java | 13 +++++++++++-- 2 files changed, 35 insertions(+), 5 deletions(-) (limited to 'src/se/leap/leapclient') diff --git a/src/se/leap/leapclient/LeapSRPSession.java b/src/se/leap/leapclient/LeapSRPSession.java index 715e9de1..8d6f77bf 100644 --- a/src/se/leap/leapclient/LeapSRPSession.java +++ b/src/se/leap/leapclient/LeapSRPSession.java @@ -109,13 +109,29 @@ public class LeapSRPSession { password_bytes = Util.trim(password.getBytes()); } + /*byte[] passBytes = new byte[2*password.toCharArray().length]; + int passBytesLength = 0; + for(int p = 0; p < password.toCharArray().length; p++) { + int c = (password.toCharArray()[p] & 0x00FFFF); + // The low byte of the char + byte b0 = (byte) (c & 0x0000FF); + // The high byte of the char + byte b1 = (byte) ((c & 0x00FF00) >> 8); + passBytes[passBytesLength ++] = b0; + // Only encode the high byte if c is a multi-byte char + if( c > 255 ) + passBytes[passBytesLength ++] = b1; + }*/ + // Build the hash x_digest.update(user); x_digest.update(colon); x_digest.update(password_bytes); + //x_digest.update(passBytes, 0, passBytesLength); byte[] h = x_digest.digest(); + String hstr = new BigInteger(1, h).toString(16); //h = Util.trim(h); - + //25c19c2b903ff36dd5acd6e1136b8f3af008ceee45103ef9771334f4246d6226 x_digest.reset(); x_digest.update(salt); x_digest.update(h); @@ -173,8 +189,9 @@ public class LeapSRPSession { */ public byte[] response(byte[] salt_bytes, byte[] Bbytes) throws NoSuchAlgorithmException { // Calculate x = H(s | H(U | ':' | password)) - byte[] xb = calculatePasswordHash(username, password, salt_bytes); + byte[] xb = calculatePasswordHash(username, password, Util.trim(salt_bytes)); this.x = new BigInteger(1, xb); + String xstr = x.toString(16); // Calculate v = kg^x mod N String k_string = "bf66c44a428916cad64aa7c679f3fd897ad4c375e9bbb4cbf2f5de241d618ef0"; @@ -211,6 +228,7 @@ public class LeapSRPSession { // Calculate S = (B - kg^x) ^ (a + u * x) % N BigInteger S = calculateS(Bbytes); byte[] S_bytes = Util.trim(S.toByteArray()); + String Sstr = S.toString(16); // K = SessionHash(S) String hash_algorithm = params.hashAlgorithm; @@ -219,8 +237,10 @@ public class LeapSRPSession { // clientHash = H(N) xor H(g) | H(U) | A | B | K clientHash.update(K); + String Kstr = new BigInteger(1, K).toString(16); byte[] M1 = Util.trim(clientHash.digest()); + String M1str = new BigInteger(1, M1).toString(16); // serverHash = Astr + M + K serverHash.update(Abytes); @@ -244,9 +264,10 @@ public class LeapSRPSession { BigInteger u = new BigInteger(1, u_bytes); BigInteger B_minus_v = B.subtract(v); + String vstr = v.toString(16); BigInteger a_ux = a.add(u.multiply(x)); + String xstr = x.toString(16); BigInteger S = B_minus_v.modPow(a_ux, N); - return S; } diff --git a/src/se/leap/leapclient/ProviderAPI.java b/src/se/leap/leapclient/ProviderAPI.java index d5e164d6..a6a2d6be 100644 --- a/src/se/leap/leapclient/ProviderAPI.java +++ b/src/se/leap/leapclient/ProviderAPI.java @@ -15,8 +15,10 @@ 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.util.Scanner; import javax.net.ssl.HostnameVerifier; @@ -296,12 +298,17 @@ public class ProviderAPI extends IntentService { String json_file_content = ""; URL provider_url = null; + int seconds_of_timeout = 1; try { provider_url = new URL(string_url); - json_file_content = new Scanner(provider_url.openStream()).useDelimiter("\\A").next(); + 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) { // TODO Auto-generated catch block e.printStackTrace(); + } catch(SocketTimeoutException e) { + return ""; } catch (IOException e) { // TODO SSLHandshakeException // This means that we have not added ca.crt to the trusted certificates. @@ -310,8 +317,10 @@ public class ProviderAPI extends IntentService { } //json_file_content = downloadStringFromProviderWithCACertAdded(string_url); e.printStackTrace(); + } catch (Exception e) { + e.printStackTrace(); } - + return json_file_content; } -- cgit v1.2.3 From 46bc4830705bc0a21f28d3e7b3899c2a978f4915 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Parm=C3=A9nides=20GV?= Date: Tue, 4 Jun 2013 17:09:28 +0200 Subject: Fix bug #2717. "https://" is automatically appended. --- src/se/leap/leapclient/NewProviderDialog.java | 3 +++ 1 file changed, 3 insertions(+) (limited to 'src/se/leap/leapclient') diff --git a/src/se/leap/leapclient/NewProviderDialog.java b/src/se/leap/leapclient/NewProviderDialog.java index 99788001..07185b47 100644 --- a/src/se/leap/leapclient/NewProviderDialog.java +++ b/src/se/leap/leapclient/NewProviderDialog.java @@ -52,6 +52,9 @@ public class NewProviderDialog extends DialogFragment { .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.saveProvider(entered_url, danger_on); -- cgit v1.2.3 From 611bb7869ea6a98fe656b6e86ef98118d232fd45 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Parm=C3=A9nides=20GV?= Date: Tue, 4 Jun 2013 20:42:05 +0200 Subject: Fixed SRP strange characters bugs. The problem was the encoding of the bytes when calculating the password hash. I supposed that it was UTF-8 (I already saw that encoding in the html code from leap_web), but not, it was ISO-8859-1 (trial/error). --- src/se/leap/leapclient/LeapSRPSession.java | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) (limited to 'src/se/leap/leapclient') diff --git a/src/se/leap/leapclient/LeapSRPSession.java b/src/se/leap/leapclient/LeapSRPSession.java index 8d6f77bf..77f43945 100644 --- a/src/se/leap/leapclient/LeapSRPSession.java +++ b/src/se/leap/leapclient/LeapSRPSession.java @@ -97,10 +97,11 @@ public class LeapSRPSession { byte[] user = null; byte[] password_bytes = null; byte[] colon = {}; + String encoding = "ISO-8859-1"; try { - user = Util.trim(username.getBytes("UTF-8")); - colon = Util.trim(":".getBytes("UTF-8")); - password_bytes = Util.trim(password.getBytes("UTF-8")); + user = Util.trim(username.getBytes(encoding)); + colon = Util.trim(":".getBytes(encoding)); + password_bytes = Util.trim(password.getBytes(encoding)); } catch(UnsupportedEncodingException e) { // Use the default platform encoding -- cgit v1.2.3 From d74a3ae14a27893572d170c138e18522b541866a Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Parm=C3=A9nides=20GV?= Date: Wed, 5 Jun 2013 18:57:55 +0200 Subject: Fixed passwords with \ character. The substitution I was doing let me to pass my tests localhost, but was not valid for real use in Android emulator. This was so because JSONObject getString method understood \/ simply as /, while what I wanted was plain \/. This commit makes #2368 --- src/se/leap/leapclient/LeapSRPSession.java | 23 +++-------------------- 1 file changed, 3 insertions(+), 20 deletions(-) (limited to 'src/se/leap/leapclient') diff --git a/src/se/leap/leapclient/LeapSRPSession.java b/src/se/leap/leapclient/LeapSRPSession.java index 77f43945..47dff276 100644 --- a/src/se/leap/leapclient/LeapSRPSession.java +++ b/src/se/leap/leapclient/LeapSRPSession.java @@ -90,10 +90,10 @@ public class LeapSRPSession { */ public byte[] calculatePasswordHash(String username, String password, byte[] salt) { - password = password.replaceAll("\\\\", "\\\\\\\\"); + //password = password.replaceAll("\\\\", "\\\\\\\\"); // Calculate x = H(s | H(U | ':' | password)) MessageDigest x_digest = newDigest(); - // Try to convert the username to a byte[] using UTF-8 + // Try to convert the username to a byte[] using ISO-8859-1 byte[] user = null; byte[] password_bytes = null; byte[] colon = {}; @@ -110,29 +110,12 @@ public class LeapSRPSession { password_bytes = Util.trim(password.getBytes()); } - /*byte[] passBytes = new byte[2*password.toCharArray().length]; - int passBytesLength = 0; - for(int p = 0; p < password.toCharArray().length; p++) { - int c = (password.toCharArray()[p] & 0x00FFFF); - // The low byte of the char - byte b0 = (byte) (c & 0x0000FF); - // The high byte of the char - byte b1 = (byte) ((c & 0x00FF00) >> 8); - passBytes[passBytesLength ++] = b0; - // Only encode the high byte if c is a multi-byte char - if( c > 255 ) - passBytes[passBytesLength ++] = b1; - }*/ - // Build the hash x_digest.update(user); x_digest.update(colon); x_digest.update(password_bytes); - //x_digest.update(passBytes, 0, passBytesLength); byte[] h = x_digest.digest(); - String hstr = new BigInteger(1, h).toString(16); - //h = Util.trim(h); - //25c19c2b903ff36dd5acd6e1136b8f3af008ceee45103ef9771334f4246d6226 + x_digest.reset(); x_digest.update(salt); x_digest.update(h); -- cgit v1.2.3 From 899583d474a0b04e168203ce06195403461b9215 Mon Sep 17 00:00:00 2001 From: Sean Leonard Date: Sat, 8 Jun 2013 20:55:48 -0600 Subject: Improve retrieving and saving SharedPreferences for different types (String, boolean, JSONObject) --- src/se/leap/leapclient/ConfigHelper.java | 63 +++++++++++++++++++++---- src/se/leap/leapclient/ConfigurationWizard.java | 46 +++++++++--------- src/se/leap/leapclient/Dashboard.java | 9 ++++ src/se/leap/leapclient/ProviderAPI.java | 21 +++------ 4 files changed, 91 insertions(+), 48 deletions(-) (limited to 'src/se/leap/leapclient') diff --git a/src/se/leap/leapclient/ConfigHelper.java b/src/se/leap/leapclient/ConfigHelper.java index 6a70378f..e8bc27c5 100644 --- a/src/se/leap/leapclient/ConfigHelper.java +++ b/src/se/leap/leapclient/ConfigHelper.java @@ -18,6 +18,7 @@ import java.security.cert.X509Certificate; import org.json.JSONException; import org.json.JSONObject; +import android.content.Context; import android.content.SharedPreferences; import android.os.Environment; import android.util.Log; @@ -88,6 +89,17 @@ public class ConfigHelper { INCORRECTLY_DOWNLOADED_ANON_CERTIFICATE = 14 ; + + private static boolean checkSharedPrefs() { + try { + shared_preferences = Dashboard.getAppContext().getSharedPreferences(PREFERENCES_KEY,Context.MODE_PRIVATE); + } catch (Exception e) { + return false; + } + + return true; + } + public static void saveSharedPref(String shared_preferences_key, JSONObject content) { SharedPreferences.Editor shared_preferences_editor = shared_preferences @@ -97,16 +109,49 @@ public class ConfigHelper { shared_preferences_editor.commit(); } + 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(); + } + + 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(); + } + public static String getStringFromSharedPref(String shared_preferences_key) { - String value = ""; - if(shared_preferences != null) { - String content = shared_preferences.getString(shared_preferences_key, ""); - try { - JSONObject json_object = new JSONObject(content); - value = json_object.toString(); - } catch (JSONException e) { - value = content; - } + String content = null; + if ( checkSharedPrefs() ) { + content = shared_preferences.getString(shared_preferences_key, ""); + } + return content; + } + + public static JSONObject getJsonFromSharedPref(String shared_preferences_key) throws JSONException { + JSONObject content = null; + if ( checkSharedPrefs() ) { + content = new JSONObject( shared_preferences.getString(shared_preferences_key, "") ); + } + + 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; } diff --git a/src/se/leap/leapclient/ConfigurationWizard.java b/src/se/leap/leapclient/ConfigurationWizard.java index fff155a8..3afbdacf 100644 --- a/src/se/leap/leapclient/ConfigurationWizard.java +++ b/src/se/leap/leapclient/ConfigurationWizard.java @@ -84,7 +84,7 @@ public class ConfigurationWizard extends Activity 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, new JSONObject().put(ConfigHelper.DANGER_ON, danger_on)); + ConfigHelper.saveSharedPref(ConfigHelper.DANGER_ON, danger_on); downloadAnonCert(); } catch (JSONException e) { // TODO Auto-generated catch block @@ -163,9 +163,8 @@ public class ConfigurationWizard extends Activity provider_contents = new Scanner(ConfigHelper.openFileInputStream(current_provider_item.provider_json_filename)).useDelimiter("\\A").next(); provider_json = new JSONObject(provider_contents); ConfigHelper.saveSharedPref(ConfigHelper.PROVIDER_KEY, provider_json); - ConfigHelper.saveSharedPref(ConfigHelper.ALLOWED_ANON, new JSONObject().put(ConfigHelper.ALLOWED_ANON, provider_json.getJSONObject(ConfigHelper.SERVICE_KEY).getBoolean(ConfigHelper.ALLOWED_ANON))); - ConfigHelper.saveSharedPref(ConfigHelper.DANGER_ON, new JSONObject().put(ConfigHelper.DANGER_ON, current_provider_item.danger_on)); - downloadAnonCert(); + ConfigHelper.saveSharedPref(ConfigHelper.ALLOWED_ANON, provider_json.getJSONObject(ConfigHelper.SERVICE_KEY).getBoolean(ConfigHelper.ALLOWED_ANON)); + ConfigHelper.saveSharedPref(ConfigHelper.DANGER_ON, current_provider_item.danger_on); return true; } } catch (JSONException e) { @@ -194,31 +193,28 @@ public class ConfigurationWizard extends Activity private boolean downloadAnonCert() { - JSONObject allowed_anon; - try { - allowed_anon = new JSONObject(ConfigHelper.getStringFromSharedPref(ConfigHelper.ALLOWED_ANON)); - if(allowed_anon.getBoolean(ConfigHelper.ALLOWED_ANON)) { - providerAPI_result_receiver = new ProviderAPIResultReceiver(new Handler()); - providerAPI_result_receiver.setReceiver(this); - - Intent provider_API_command = new Intent(this, ProviderAPI.class); - - Bundle method_and_parameters = new Bundle(); - - method_and_parameters.putString(ConfigHelper.TYPE_OF_CERTIFICATE, ConfigHelper.ANON_CERTIFICATE); - - provider_API_command.putExtra(ConfigHelper.DOWNLOAD_CERTIFICATE, method_and_parameters); - provider_API_command.putExtra("receiver", providerAPI_result_receiver); + boolean allowed_anon; + allowed_anon = ConfigHelper.getBoolFromSharedPref(ConfigHelper.ALLOWED_ANON); + if(allowed_anon) { + providerAPI_result_receiver = new ProviderAPIResultReceiver(new Handler()); + providerAPI_result_receiver.setReceiver(this); - startService(provider_API_command); - return true; - } else { - return false; - } - } catch (JSONException e) { + Intent provider_API_command = new Intent(this, ProviderAPI.class); + + Bundle method_and_parameters = new Bundle(); + + method_and_parameters.putString(ConfigHelper.TYPE_OF_CERTIFICATE, ConfigHelper.ANON_CERTIFICATE); + + provider_API_command.putExtra(ConfigHelper.DOWNLOAD_CERTIFICATE, method_and_parameters); + provider_API_command.putExtra("receiver", providerAPI_result_receiver); + + startService(provider_API_command); + return true; + } else { return false; } } + public void addNewProvider(View view) { FragmentTransaction fragment_transaction = getFragmentManager().beginTransaction(); Fragment previous_new_provider_dialog = getFragmentManager().findFragmentByTag(ConfigHelper.NEW_PROVIDER_DIALOG); diff --git a/src/se/leap/leapclient/Dashboard.java b/src/se/leap/leapclient/Dashboard.java index 5ffbc19e..de7946e9 100644 --- a/src/se/leap/leapclient/Dashboard.java +++ b/src/se/leap/leapclient/Dashboard.java @@ -16,6 +16,7 @@ import android.app.Activity; import android.app.DialogFragment; import android.app.Fragment; import android.app.FragmentTransaction; +import android.content.Context; import android.content.Intent; import android.content.SharedPreferences; import android.os.Bundle; @@ -34,6 +35,7 @@ public class Dashboard extends Activity implements LogInDialog.LogInDialogInterf protected static final int CONFIGURE_LEAP = 0; + private static Context app; private static SharedPreferences preferences; private static Provider provider; @@ -45,6 +47,9 @@ public class Dashboard extends Activity implements LogInDialog.LogInDialogInterf @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); + + app = this; + setContentView(R.layout.client_dashboard); preferences = getSharedPreferences(ConfigHelper.PREFERENCES_KEY,MODE_PRIVATE); @@ -288,4 +293,8 @@ public class Dashboard extends Activity implements LogInDialog.LogInDialogInterf } } + // Used for getting Context when outside of a class extending Context + public static Context getAppContext() { + return app; + } } diff --git a/src/se/leap/leapclient/ProviderAPI.java b/src/se/leap/leapclient/ProviderAPI.java index a6a2d6be..cd19da04 100644 --- a/src/se/leap/leapclient/ProviderAPI.java +++ b/src/se/leap/leapclient/ProviderAPI.java @@ -117,8 +117,7 @@ public class ProviderAPI extends IntentService { boolean danger_on = task.getBoolean(ConfigHelper.DANGER_ON); try { String cert_string = getStringFromProvider(cert_url, danger_on); - JSONObject cert_json = new JSONObject().put(ConfigHelper.MAIN_CERT_KEY, cert_string); - ConfigHelper.saveSharedPref(ConfigHelper.MAIN_CERT_KEY, cert_json); + ConfigHelper.saveSharedPref(ConfigHelper.MAIN_CERT_KEY, cert_string); JSONObject eip_service_json = getJSONFromProvider(eip_service_json_url, danger_on); ConfigHelper.saveSharedPref(ConfigHelper.EIP_SERVICE_KEY, eip_service_json); return true; @@ -227,7 +226,7 @@ public class ProviderAPI extends IntentService { if(provider_json == null) { result.putBoolean(ConfigHelper.RESULT_KEY, false); } else { - ConfigHelper.saveSharedPref(ConfigHelper.ALLOWED_ANON, new JSONObject().put(ConfigHelper.ALLOWED_ANON, provider_json.getJSONObject(ConfigHelper.SERVICE_KEY).getBoolean(ConfigHelper.ALLOWED_ANON))); + ConfigHelper.saveSharedPref(ConfigHelper.ALLOWED_ANON, provider_json.getJSONObject(ConfigHelper.SERVICE_KEY).getBoolean(ConfigHelper.ALLOWED_ANON)); String filename = provider_name + "_provider.json".replaceFirst("__", "_"); ConfigHelper.saveFile(filename, provider_json.toString()); @@ -333,8 +332,7 @@ public class ProviderAPI extends IntentService { try { cf = CertificateFactory.getInstance("X.509"); - String cert_json_string = ConfigHelper.getStringFromSharedPref(ConfigHelper.MAIN_CERT_KEY); - String cert_string = new JSONObject(cert_json_string).getString(ConfigHelper.MAIN_CERT_KEY); + String cert_string = ConfigHelper.getStringFromSharedPref(ConfigHelper.MAIN_CERT_KEY); cert_string = cert_string.replaceFirst("-----BEGIN CERTIFICATE-----", "").replaceFirst("-----END CERTIFICATE-----", "").trim(); byte[] cert_bytes = Base64.decode(cert_string, Base64.DEFAULT); InputStream caInput = new ByteArrayInputStream(cert_bytes); @@ -381,10 +379,8 @@ public class ProviderAPI extends IntentService { } catch (KeyManagementException e) { // TODO Auto-generated catch block e.printStackTrace(); - } catch (JSONException e) { - // TODO Auto-generated catch block - e.printStackTrace(); } + return json_file_content; } @@ -424,10 +420,9 @@ public class ProviderAPI extends IntentService { } private boolean getNewCert(Bundle task) { - String provider_json_string = ConfigHelper.getStringFromSharedPref(ConfigHelper.PROVIDER_KEY); String type_of_certificate = task.getString(ConfigHelper.TYPE_OF_CERTIFICATE); try { - JSONObject provider_json = new JSONObject(provider_json_string); + JSONObject provider_json = ConfigHelper.getJsonFromSharedPref(ConfigHelper.PROVIDER_KEY); URL provider_main_url = new URL(provider_json.getString(ConfigHelper.API_URL_KEY).replace("api.", "")); String new_cert_string_url = provider_main_url.getProtocol() + "://" + provider_main_url.getHost() + "/" + provider_json.getString(ConfigHelper.API_VERSION_KEY) + "/" + ConfigHelper.CERT_KEY; @@ -439,12 +434,10 @@ public class ProviderAPI extends IntentService { CookieHandler.setDefault(cookieManager); } - String danger_on_json_string = ConfigHelper.getStringFromSharedPref(ConfigHelper.DANGER_ON); - boolean danger_on = new JSONObject(danger_on_json_string).getBoolean(ConfigHelper.DANGER_ON); + boolean danger_on = ConfigHelper.getBoolFromSharedPref(ConfigHelper.DANGER_ON); String cert_string = getStringFromProvider(new_cert_string_url, danger_on); if(!cert_string.isEmpty()) { - JSONObject cert_json = new JSONObject().put(ConfigHelper.CERT_KEY, cert_string); - ConfigHelper.saveSharedPref(ConfigHelper.CERT_KEY, cert_json); + ConfigHelper.saveSharedPref(ConfigHelper.CERT_KEY, cert_string); return true; } else { return false; -- cgit v1.2.3 From 344a4596e38bb4a908f2791e2f710eb485a5e719 Mon Sep 17 00:00:00 2001 From: Sean Leonard Date: Sat, 8 Jun 2013 21:33:11 -0600 Subject: Make LogInDialog accept passwords >= 8 characters, instead of > 8 --- src/se/leap/leapclient/LogInDialog.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'src/se/leap/leapclient') diff --git a/src/se/leap/leapclient/LogInDialog.java b/src/se/leap/leapclient/LogInDialog.java index 370a138c..26889679 100644 --- a/src/se/leap/leapclient/LogInDialog.java +++ b/src/se/leap/leapclient/LogInDialog.java @@ -47,7 +47,7 @@ public class LogInDialog extends DialogFragment { } boolean wellFormedPassword(String entered_password) { - return entered_password.length() > 8; + return entered_password.length() >= 8; } public interface LogInDialogInterface { -- cgit v1.2.3 From d14ae81fe92494a67994d703e1175ef4264adddb Mon Sep 17 00:00:00 2001 From: Sean Leonard Date: Sat, 8 Jun 2013 21:58:00 -0600 Subject: Refactor ConfigurationWizard for better task handling, completion, and return information --- src/se/leap/leapclient/ConfigurationWizard.java | 99 ++++++++++++++----------- 1 file changed, 54 insertions(+), 45 deletions(-) (limited to 'src/se/leap/leapclient') diff --git a/src/se/leap/leapclient/ConfigurationWizard.java b/src/se/leap/leapclient/ConfigurationWizard.java index 3afbdacf..389c2911 100644 --- a/src/se/leap/leapclient/ConfigurationWizard.java +++ b/src/se/leap/leapclient/ConfigurationWizard.java @@ -33,7 +33,12 @@ public class ConfigurationWizard extends Activity * device. */ private boolean mTwoPane; + private ProviderItem mSelectedProvider; + private Intent mConfigState = new Intent(); + protected static final String PROVIDER_SET = "PROVIDER SET"; + protected static final String SERVICES_RETRIEVED = "SERVICES RETRIEVED"; + public ProviderAPIResultReceiver providerAPI_result_receiver; @Override @@ -41,6 +46,9 @@ public class ConfigurationWizard extends Activity super.onCreate(savedInstanceState); setContentView(R.layout.activity_configuration_wizard); + + providerAPI_result_receiver = new ProviderAPIResultReceiver(new Handler()); + providerAPI_result_receiver.setReceiver(this); ConfigHelper.setSharedPreferences(getSharedPreferences(ConfigHelper.PREFERENCES_KEY, MODE_PRIVATE)); @@ -72,11 +80,19 @@ public class ConfigurationWizard extends Activity .commit(); } else if(resultCode == ConfigHelper.CORRECTLY_DOWNLOADED_JSON_FILES) { - setResult(RESULT_OK); + if (ConfigHelper.getBoolFromSharedPref(ConfigHelper.ALLOWED_ANON)){ + mConfigState.putExtra(SERVICES_RETRIEVED, true); + downloadAnonCert(); + } else { + Toast.makeText(getApplicationContext(), R.string.success, Toast.LENGTH_LONG).show(); + setResult(RESULT_OK); + finish(); + } } else if(resultCode == ConfigHelper.INCORRECTLY_DOWNLOADED_JSON_FILES) { - setResult(RESULT_CANCELED); Toast.makeText(getApplicationContext(), "You have not entered a LEAP provider URL or it is unavailable", Toast.LENGTH_LONG).show(); + setResult(RESULT_CANCELED, mConfigState); + finish(); } else if(resultCode == ConfigHelper.CORRECTLY_UPDATED_PROVIDER_DOT_JSON) { JSONObject provider_json; @@ -85,22 +101,35 @@ public class ConfigurationWizard extends Activity boolean danger_on = resultData.getBoolean(ConfigHelper.DANGER_ON); ConfigHelper.saveSharedPref(ConfigHelper.PROVIDER_KEY, provider_json); ConfigHelper.saveSharedPref(ConfigHelper.DANGER_ON, danger_on); - downloadAnonCert(); + ConfigHelper.saveSharedPref(ConfigHelper.ALLOWED_ANON, provider_json.getBoolean(ConfigHelper.ALLOWED_ANON)); + + mConfigState.setAction(PROVIDER_SET); + + downloadJSONFiles(mSelectedProvider); } catch (JSONException e) { // TODO Auto-generated catch block e.printStackTrace(); + + Toast.makeText(this, getResources().getString(R.string.config_error_parsing), Toast.LENGTH_LONG); + setResult(RESULT_CANCELED, mConfigState); + finish(); } } else if(resultCode == ConfigHelper.INCORRECTLY_UPDATED_PROVIDER_DOT_JSON) { Toast.makeText(getApplicationContext(), "Install a new version of this app.", Toast.LENGTH_LONG).show(); + setResult(RESULT_CANCELED, mConfigState); + finish(); } else if(resultCode == ConfigHelper.CORRECTLY_DOWNLOADED_CERTIFICATE) { - setResult(RESULT_OK); Toast.makeText(getApplicationContext(), "Your anon cert has been correctly downloaded", Toast.LENGTH_LONG).show(); + Toast.makeText(getApplicationContext(), R.string.success, Toast.LENGTH_LONG).show(); + //mConfigState.putExtra(CERTIFICATE_RETRIEVED, true); // If this isn't the last step and finish() is moved... + setResult(RESULT_OK); finish(); } else if(resultCode == ConfigHelper.INCORRECTLY_DOWNLOADED_CERTIFICATE) { - setResult(RESULT_CANCELED); Toast.makeText(getApplicationContext(), "Your anon cert was not downloaded", Toast.LENGTH_LONG).show(); + setResult(RESULT_CANCELED, mConfigState); + finish(); } } @@ -114,16 +143,11 @@ public class ConfigurationWizard extends Activity Iterator preseeded_providers_iterator = ProviderListContent.ITEMS.iterator(); while(preseeded_providers_iterator.hasNext()) { - ProviderItem current_provider_item = preseeded_providers_iterator.next(); - if(current_provider_item.id.equalsIgnoreCase(id)) + ProviderItem provider = preseeded_providers_iterator.next(); + if(provider.id.equalsIgnoreCase(id)) { - try { - saveProviderJson(current_provider_item); - downloadJSONFiles(current_provider_item); - } catch (IOException e) { - // TODO Auto-generated catch block - e.printStackTrace(); - } + mSelectedProvider = provider; + saveProviderJson(mSelectedProvider); } } } @@ -152,30 +176,31 @@ public class ConfigurationWizard extends Activity return loaded_preseeded_providers; } - private boolean saveProviderJson(ProviderItem current_provider_item) { + private void saveProviderJson(ProviderItem current_provider_item) { JSONObject provider_json = new JSONObject(); try { String provider_contents = ""; if(!current_provider_item.custom) { updateProviderDotJson(current_provider_item.name, current_provider_item.provider_json_url, current_provider_item.danger_on); - return true; } 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_contents = new Scanner(ConfigHelper.openFileInputStream(current_provider_item.provider_json_filename)).useDelimiter("\\A").next(); provider_json = new JSONObject(provider_contents); 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, current_provider_item.danger_on); - return true; + + downloadJSONFiles(mSelectedProvider); } } catch (JSONException e) { - return false; + setResult(RESULT_CANCELED); + finish(); } } - private void downloadJSONFiles(ProviderItem current_provider_item) throws IOException { - providerAPI_result_receiver = new ProviderAPIResultReceiver(new Handler()); - providerAPI_result_receiver.setReceiver(this); - + private void downloadJSONFiles(ProviderItem current_provider_item) { Intent provider_API_command = new Intent(this, ProviderAPI.class); Bundle method_and_parameters = new Bundle(); @@ -192,27 +217,17 @@ public class ConfigurationWizard extends Activity } private boolean downloadAnonCert() { + Intent provider_API_command = new Intent(this, ProviderAPI.class); - boolean allowed_anon; - allowed_anon = ConfigHelper.getBoolFromSharedPref(ConfigHelper.ALLOWED_ANON); - if(allowed_anon) { - providerAPI_result_receiver = new ProviderAPIResultReceiver(new Handler()); - providerAPI_result_receiver.setReceiver(this); - - Intent provider_API_command = new Intent(this, ProviderAPI.class); - - Bundle method_and_parameters = new Bundle(); + Bundle method_and_parameters = new Bundle(); - method_and_parameters.putString(ConfigHelper.TYPE_OF_CERTIFICATE, ConfigHelper.ANON_CERTIFICATE); + method_and_parameters.putString(ConfigHelper.TYPE_OF_CERTIFICATE, ConfigHelper.ANON_CERTIFICATE); - provider_API_command.putExtra(ConfigHelper.DOWNLOAD_CERTIFICATE, method_and_parameters); - provider_API_command.putExtra("receiver", providerAPI_result_receiver); + provider_API_command.putExtra(ConfigHelper.DOWNLOAD_CERTIFICATE, method_and_parameters); + provider_API_command.putExtra("receiver", providerAPI_result_receiver); - startService(provider_API_command); - return true; - } else { - return false; - } + startService(provider_API_command); + return true; } public void addNewProvider(View view) { @@ -229,9 +244,6 @@ public class ConfigurationWizard extends Activity @Override public void saveProvider(String provider_main_url, boolean danger_on) { - providerAPI_result_receiver = new ProviderAPIResultReceiver(new Handler()); - providerAPI_result_receiver.setReceiver(this); - Intent provider_API_command = new Intent(this, ProviderAPI.class); Bundle method_and_parameters = new Bundle(); @@ -245,9 +257,6 @@ public class ConfigurationWizard extends Activity } public void updateProviderDotJson(String provider_name, String provider_json_url, boolean danger_on) { - providerAPI_result_receiver = new ProviderAPIResultReceiver(new Handler()); - providerAPI_result_receiver.setReceiver(this); - Intent provider_API_command = new Intent(this, ProviderAPI.class); Bundle method_and_parameters = new Bundle(); -- cgit v1.2.3 From 626b32fba7b6b45bead3b79fb7e7aa6cddc5c535 Mon Sep 17 00:00:00 2001 From: Sean Leonard Date: Sat, 8 Jun 2013 22:07:39 -0600 Subject: Add ProgressDialog to ConfigurationWizard while downloading from provider --- src/se/leap/leapclient/ConfigurationWizard.java | 11 +++++++++++ 1 file changed, 11 insertions(+) (limited to 'src/se/leap/leapclient') diff --git a/src/se/leap/leapclient/ConfigurationWizard.java b/src/se/leap/leapclient/ConfigurationWizard.java index 389c2911..164b1d43 100644 --- a/src/se/leap/leapclient/ConfigurationWizard.java +++ b/src/se/leap/leapclient/ConfigurationWizard.java @@ -17,6 +17,7 @@ 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; @@ -34,6 +35,7 @@ public class ConfigurationWizard extends Activity */ private boolean mTwoPane; private ProviderItem mSelectedProvider; + private ProgressDialog mProgressDialog; private Intent mConfigState = new Intent(); protected static final String PROVIDER_SET = "PROVIDER SET"; @@ -81,9 +83,11 @@ public class ConfigurationWizard extends Activity } else if(resultCode == ConfigHelper.CORRECTLY_DOWNLOADED_JSON_FILES) { if (ConfigHelper.getBoolFromSharedPref(ConfigHelper.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(); @@ -105,28 +109,33 @@ public class ConfigurationWizard extends Activity mConfigState.setAction(PROVIDER_SET); + mProgressDialog.setMessage(getResources().getString(R.string.config_downloading_services)); 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); finish(); } } else if(resultCode == ConfigHelper.INCORRECTLY_UPDATED_PROVIDER_DOT_JSON) { + mProgressDialog.dismiss(); Toast.makeText(getApplicationContext(), "Install a new version of this app.", Toast.LENGTH_LONG).show(); setResult(RESULT_CANCELED, mConfigState); finish(); } else if(resultCode == ConfigHelper.CORRECTLY_DOWNLOADED_CERTIFICATE) { + mProgressDialog.dismiss(); Toast.makeText(getApplicationContext(), "Your anon cert has been correctly downloaded", Toast.LENGTH_LONG).show(); Toast.makeText(getApplicationContext(), R.string.success, Toast.LENGTH_LONG).show(); //mConfigState.putExtra(CERTIFICATE_RETRIEVED, true); // If this isn't the last step and finish() is moved... setResult(RESULT_OK); finish(); } else if(resultCode == ConfigHelper.INCORRECTLY_DOWNLOADED_CERTIFICATE) { + mProgressDialog.dismiss(); Toast.makeText(getApplicationContext(), "Your anon cert was not downloaded", Toast.LENGTH_LONG).show(); setResult(RESULT_CANCELED, mConfigState); finish(); @@ -146,6 +155,7 @@ public class ConfigurationWizard extends Activity ProviderItem provider = preseeded_providers_iterator.next(); if(provider.id.equalsIgnoreCase(id)) { + mProgressDialog = ProgressDialog.show(this, getResources().getString(R.string.config_wait_title), getResources().getString(R.string.config_connecting_provider), true); mSelectedProvider = provider; saveProviderJson(mSelectedProvider); } @@ -192,6 +202,7 @@ public class ConfigurationWizard extends Activity ConfigHelper.saveSharedPref(ConfigHelper.ALLOWED_ANON, provider_json.getJSONObject(ConfigHelper.SERVICE_KEY).getBoolean(ConfigHelper.ALLOWED_ANON)); ConfigHelper.saveSharedPref(ConfigHelper.DANGER_ON, current_provider_item.danger_on); + mProgressDialog.setMessage(getResources().getString(R.string.config_downloading_services)); downloadJSONFiles(mSelectedProvider); } } catch (JSONException e) { -- cgit v1.2.3 From 769344327d5cb16adbdc04db224ff6902b4a4771 Mon Sep 17 00:00:00 2001 From: Sean Leonard Date: Sat, 8 Jun 2013 22:27:25 -0600 Subject: Better config/partial config handling in Dashboard --- src/se/leap/leapclient/Dashboard.java | 30 +++++++++++++++++++++++++----- 1 file changed, 25 insertions(+), 5 deletions(-) (limited to 'src/se/leap/leapclient') diff --git a/src/se/leap/leapclient/Dashboard.java b/src/se/leap/leapclient/Dashboard.java index de7946e9..6bdd74d2 100644 --- a/src/se/leap/leapclient/Dashboard.java +++ b/src/se/leap/leapclient/Dashboard.java @@ -13,10 +13,12 @@ import se.leap.leapclient.R.menu; import se.leap.openvpn.AboutFragment; import se.leap.openvpn.MainActivity; import android.app.Activity; +import android.app.AlertDialog; import android.app.DialogFragment; import android.app.Fragment; import android.app.FragmentTransaction; import android.content.Context; +import android.content.DialogInterface; import android.content.Intent; import android.content.SharedPreferences; import android.os.Bundle; @@ -58,10 +60,10 @@ public class Dashboard extends Activity implements LogInDialog.LogInDialogInterf // Check if we have preferences, run configuration wizard if not // TODO We should do a better check for config that this! - if (!preferences.contains("provider") ) - startActivityForResult(new Intent(this,ConfigurationWizard.class),CONFIGURE_LEAP); - else + if (preferences.contains("provider") && preferences.getString(ConfigHelper.PROVIDER_KEY, null) != null) buildDashboard(); + else + startActivityForResult(new Intent(this,ConfigurationWizard.class),CONFIGURE_LEAP); } @Override @@ -73,8 +75,26 @@ public class Dashboard extends Activity implements LogInDialog.LogInDialogInterf buildDashboard(); } else { - // Something went wrong... TODO figure out what - // TODO Error dialog + // Something went wrong in configuration + 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(ConfigHelper.PREFERENCES_KEY, MODE_PRIVATE).edit(); + prefsEdit.remove(ConfigHelper.PROVIDER_KEY).commit(); + finish(); + } + }); } } } -- cgit v1.2.3 From 8acc7febb78c5a6480aa0b326e9464592e792097 Mon Sep 17 00:00:00 2001 From: Sean Leonard Date: Sat, 8 Jun 2013 22:44:01 -0600 Subject: Fixed onPrepareOptionsMenu to not return prematurely. Also implements ConfigHelper.getJsonFromSharedPref(), now --- src/se/leap/leapclient/Dashboard.java | 14 ++++++-------- 1 file changed, 6 insertions(+), 8 deletions(-) (limited to 'src/se/leap/leapclient') diff --git a/src/se/leap/leapclient/Dashboard.java b/src/se/leap/leapclient/Dashboard.java index 6bdd74d2..f72af809 100644 --- a/src/se/leap/leapclient/Dashboard.java +++ b/src/se/leap/leapclient/Dashboard.java @@ -145,21 +145,19 @@ public class Dashboard extends Activity implements LogInDialog.LogInDialogInterf @Override public boolean onPrepareOptionsMenu(Menu menu) { - String provider_json_string = ConfigHelper.getStringFromSharedPref(ConfigHelper.PROVIDER_KEY); + JSONObject provider_json; try { - JSONObject provider_json = new JSONObject(provider_json_string); + provider_json = ConfigHelper.getJsonFromSharedPref(ConfigHelper.PROVIDER_KEY); JSONObject service_description = provider_json.getJSONObject(ConfigHelper.SERVICE_KEY); if(service_description.getBoolean(ConfigHelper.ALLOW_REGISTRATION_KEY)) { menu.findItem(R.id.login_button).setVisible(true); menu.findItem(R.id.logout_button).setVisible(true); - return true; } } catch (JSONException e) { - menu.findItem(R.id.login_button).setVisible(false); - menu.findItem(R.id.logout_button).setVisible(false); - return false; - } - return false; + // TODO Auto-generated catch block + e.printStackTrace(); + } + return true; } @Override -- cgit v1.2.3 From e581c6f2c1844d5dd96b12413df91dbb06102282 Mon Sep 17 00:00:00 2001 From: Sean Leonard Date: Sat, 8 Jun 2013 22:50:07 -0600 Subject: Clean up some unused and some formatting --- src/se/leap/leapclient/ConfigurationWizard.java | 10 +--------- src/se/leap/leapclient/Dashboard.java | 5 +---- src/se/leap/leapclient/LeapSRPSession.java | 2 -- src/se/leap/leapclient/LogInDialog.java | 3 --- src/se/leap/leapclient/NewProviderDialog.java | 3 --- src/se/leap/leapclient/Provider.java | 3 ++- src/se/leap/leapclient/ProviderListFragment.java | 3 --- 7 files changed, 4 insertions(+), 25 deletions(-) (limited to 'src/se/leap/leapclient') diff --git a/src/se/leap/leapclient/ConfigurationWizard.java b/src/se/leap/leapclient/ConfigurationWizard.java index 164b1d43..69f73561 100644 --- a/src/se/leap/leapclient/ConfigurationWizard.java +++ b/src/se/leap/leapclient/ConfigurationWizard.java @@ -10,8 +10,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.leapclient.R.id; -import se.leap.leapclient.R.layout; import android.app.Activity; import android.app.DialogFragment; import android.app.Fragment; @@ -26,14 +24,8 @@ import android.view.View; import android.widget.Toast; public class ConfigurationWizard extends Activity - implements ProviderListFragment.Callbacks, NewProviderDialog.NewProviderDialogInterface, Receiver { +implements ProviderListFragment.Callbacks, NewProviderDialog.NewProviderDialogInterface, Receiver { - - /** - * Whether or not the activity is in two-pane mode, i.e. running on a tablet - * device. - */ - private boolean mTwoPane; private ProviderItem mSelectedProvider; private ProgressDialog mProgressDialog; private Intent mConfigState = new Intent(); diff --git a/src/se/leap/leapclient/Dashboard.java b/src/se/leap/leapclient/Dashboard.java index f72af809..c1f4697d 100644 --- a/src/se/leap/leapclient/Dashboard.java +++ b/src/se/leap/leapclient/Dashboard.java @@ -7,9 +7,6 @@ import org.json.JSONObject; import se.leap.leapclient.ProviderAPIResultReceiver.Receiver; import se.leap.leapclient.R; -import se.leap.leapclient.R.id; -import se.leap.leapclient.R.layout; -import se.leap.leapclient.R.menu; import se.leap.openvpn.AboutFragment; import se.leap.openvpn.MainActivity; import android.app.Activity; @@ -116,7 +113,7 @@ public class Dashboard extends Activity implements LogInDialog.LogInDialogInterf private void serviceItemEIP() { // FIXME Provider service (eip/openvpn) - View eipOverview = ((ViewStub) findViewById(R.id.eipOverviewStub)).inflate(); + ((ViewStub) findViewById(R.id.eipOverviewStub)).inflate(); // Set our EIP type title eipTypeTV = (TextView) findViewById(R.id.eipType); diff --git a/src/se/leap/leapclient/LeapSRPSession.java b/src/se/leap/leapclient/LeapSRPSession.java index 47dff276..8eb28c4d 100644 --- a/src/se/leap/leapclient/LeapSRPSession.java +++ b/src/se/leap/leapclient/LeapSRPSession.java @@ -7,9 +7,7 @@ import java.security.NoSuchAlgorithmException; import java.util.Arrays; import org.jboss.security.Util; -import org.jboss.security.srp.SRPClientSession; import org.jboss.security.srp.SRPParameters; -import org.jboss.security.srp.SRPPermission; public class LeapSRPSession { diff --git a/src/se/leap/leapclient/LogInDialog.java b/src/se/leap/leapclient/LogInDialog.java index 26889679..c20413d7 100644 --- a/src/se/leap/leapclient/LogInDialog.java +++ b/src/se/leap/leapclient/LogInDialog.java @@ -1,9 +1,6 @@ package se.leap.leapclient; import se.leap.leapclient.R; -import se.leap.leapclient.R.id; -import se.leap.leapclient.R.layout; -import se.leap.leapclient.R.string; import android.app.Activity; import android.app.AlertDialog; import android.app.DialogFragment; diff --git a/src/se/leap/leapclient/NewProviderDialog.java b/src/se/leap/leapclient/NewProviderDialog.java index 07185b47..60ac8d2a 100644 --- a/src/se/leap/leapclient/NewProviderDialog.java +++ b/src/se/leap/leapclient/NewProviderDialog.java @@ -1,9 +1,6 @@ package se.leap.leapclient; import se.leap.leapclient.R; -import se.leap.leapclient.R.id; -import se.leap.leapclient.R.layout; -import se.leap.leapclient.R.string; import android.app.Activity; import android.app.AlertDialog; import android.app.Dialog; diff --git a/src/se/leap/leapclient/Provider.java b/src/se/leap/leapclient/Provider.java index f86bbf59..50bd2925 100644 --- a/src/se/leap/leapclient/Provider.java +++ b/src/se/leap/leapclient/Provider.java @@ -11,6 +11,7 @@ import org.json.JSONArray; import org.json.JSONException; import org.json.JSONObject; +import android.content.Context; import android.app.Activity; import android.content.SharedPreferences; @@ -67,7 +68,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,0); // We don't get MODE_PRIVATE by importing SharedPreferences; i guess it's in Activity? + preferences = activity.getSharedPreferences(ConfigHelper.PREFERENCES_KEY,Context.MODE_PRIVATE); // Inflate our provider.json data try { definition = new JSONObject( preferences.getString("provider", "") ); diff --git a/src/se/leap/leapclient/ProviderListFragment.java b/src/se/leap/leapclient/ProviderListFragment.java index 4316e9f3..ee3ee8ea 100644 --- a/src/se/leap/leapclient/ProviderListFragment.java +++ b/src/se/leap/leapclient/ProviderListFragment.java @@ -2,9 +2,6 @@ package se.leap.leapclient; import se.leap.leapclient.ProviderListContent.ProviderItem; import android.app.Activity; -import android.app.DialogFragment; -import android.app.Fragment; -import android.app.FragmentTransaction; import android.app.ListFragment; import android.os.Bundle; import android.view.LayoutInflater; -- cgit v1.2.3 From 1559bc45048fb877d45247f1aa9b51ee3632a3b8 Mon Sep 17 00:00:00 2001 From: Sean Leonard Date: Sat, 8 Jun 2013 23:07:36 -0600 Subject: Rearrange if/elseif statements in ConfigurationWizard for logical sequence readability --- src/se/leap/leapclient/ConfigurationWizard.java | 34 ++++++++++++------------- 1 file changed, 17 insertions(+), 17 deletions(-) (limited to 'src/se/leap/leapclient') diff --git a/src/se/leap/leapclient/ConfigurationWizard.java b/src/se/leap/leapclient/ConfigurationWizard.java index 69f73561..2a9b93b2 100644 --- a/src/se/leap/leapclient/ConfigurationWizard.java +++ b/src/se/leap/leapclient/ConfigurationWizard.java @@ -73,23 +73,6 @@ implements ProviderListFragment.Callbacks, NewProviderDialog.NewProviderDialogIn .replace(R.id.configuration_wizard_layout, providerList, "providerlist") .commit(); } - else if(resultCode == ConfigHelper.CORRECTLY_DOWNLOADED_JSON_FILES) { - if (ConfigHelper.getBoolFromSharedPref(ConfigHelper.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 == ConfigHelper.INCORRECTLY_DOWNLOADED_JSON_FILES) { - Toast.makeText(getApplicationContext(), "You have not entered a LEAP provider URL or it is unavailable", Toast.LENGTH_LONG).show(); - setResult(RESULT_CANCELED, mConfigState); - finish(); - } else if(resultCode == ConfigHelper.CORRECTLY_UPDATED_PROVIDER_DOT_JSON) { JSONObject provider_json; try { @@ -119,6 +102,23 @@ implements ProviderListFragment.Callbacks, NewProviderDialog.NewProviderDialogIn setResult(RESULT_CANCELED, mConfigState); finish(); } + else if(resultCode == ConfigHelper.CORRECTLY_DOWNLOADED_JSON_FILES) { + if (ConfigHelper.getBoolFromSharedPref(ConfigHelper.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 == ConfigHelper.INCORRECTLY_DOWNLOADED_JSON_FILES) { + Toast.makeText(getApplicationContext(), "You have not entered a LEAP provider URL or it is unavailable", Toast.LENGTH_LONG).show(); + setResult(RESULT_CANCELED, mConfigState); + finish(); + } else if(resultCode == ConfigHelper.CORRECTLY_DOWNLOADED_CERTIFICATE) { mProgressDialog.dismiss(); Toast.makeText(getApplicationContext(), "Your anon cert has been correctly downloaded", Toast.LENGTH_LONG).show(); -- cgit v1.2.3 From 57ac2c271561fe9f1255109733f5daae06e9234c Mon Sep 17 00:00:00 2001 From: Sean Leonard Date: Sat, 8 Jun 2013 23:12:49 -0600 Subject: More changes to calls for SharedPreferences via ConfigHelper methods --- src/se/leap/leapclient/LeapHttpClient.java | 16 +++------------- 1 file changed, 3 insertions(+), 13 deletions(-) (limited to 'src/se/leap/leapclient') diff --git a/src/se/leap/leapclient/LeapHttpClient.java b/src/se/leap/leapclient/LeapHttpClient.java index a2ee8ad6..646f80f5 100644 --- a/src/se/leap/leapclient/LeapHttpClient.java +++ b/src/se/leap/leapclient/LeapHttpClient.java @@ -9,9 +9,6 @@ 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 org.json.JSONException; -import org.json.JSONObject; - import android.content.Context; public class LeapHttpClient extends DefaultHttpClient { @@ -22,16 +19,9 @@ public class LeapHttpClient extends DefaultHttpClient { public static LeapHttpClient getInstance(Context context) { if(client == null) { client = new LeapHttpClient(context); - String cert_json_string = ConfigHelper.getStringFromSharedPref(ConfigHelper.MAIN_CERT_KEY); - String cert_string; - try { - cert_string = new JSONObject(cert_json_string).getString(ConfigHelper.MAIN_CERT_KEY); - if(!cert_string.isEmpty()) { - ConfigHelper.addTrustedCertificate("recovered_certificate", cert_string); - } - } catch (JSONException e) { - // TODO Auto-generated catch block - e.printStackTrace(); + String cert_string = ConfigHelper.getStringFromSharedPref(ConfigHelper.MAIN_CERT_KEY); + if(!cert_string.isEmpty()) { + ConfigHelper.addTrustedCertificate("recovered_certificate", cert_string); } } return client; -- cgit v1.2.3 From 5d14f128f8da5384e6834008326e435524c8fe33 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Parm=C3=A9nides=20GV?= Date: Mon, 10 Jun 2013 18:18:07 +0200 Subject: NullPointer solved. ConfigHelper refactored methods returning nulls instead of empty objects broke LeapHttpClient getInstance implementation, because it checked the emptiness of the object and not if it was null. --- src/se/leap/leapclient/LeapHttpClient.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'src/se/leap/leapclient') diff --git a/src/se/leap/leapclient/LeapHttpClient.java b/src/se/leap/leapclient/LeapHttpClient.java index 646f80f5..3eeebe95 100644 --- a/src/se/leap/leapclient/LeapHttpClient.java +++ b/src/se/leap/leapclient/LeapHttpClient.java @@ -20,7 +20,7 @@ public class LeapHttpClient extends DefaultHttpClient { if(client == null) { client = new LeapHttpClient(context); String cert_string = ConfigHelper.getStringFromSharedPref(ConfigHelper.MAIN_CERT_KEY); - if(!cert_string.isEmpty()) { + if(cert_string != null) { ConfigHelper.addTrustedCertificate("recovered_certificate", cert_string); } } -- cgit v1.2.3 From 265a66e66cffacbd2c99f99bebbcec3bf100a546 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Parm=C3=A9nides=20GV?= Date: Mon, 10 Jun 2013 18:43:50 +0200 Subject: OpenVPN certificate is downloaded from API_BASE, using api_uri field from provider.json. This fixes bug #2780 --- src/se/leap/leapclient/ProviderAPI.java | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) (limited to 'src/se/leap/leapclient') diff --git a/src/se/leap/leapclient/ProviderAPI.java b/src/se/leap/leapclient/ProviderAPI.java index cd19da04..a51c3a05 100644 --- a/src/se/leap/leapclient/ProviderAPI.java +++ b/src/se/leap/leapclient/ProviderAPI.java @@ -423,8 +423,8 @@ public class ProviderAPI extends IntentService { 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).replace("api.", "")); - String new_cert_string_url = provider_main_url.getProtocol() + "://" + provider_main_url.getHost() + "/" + provider_json.getString(ConfigHelper.API_VERSION_KEY) + "/" + ConfigHelper.CERT_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; 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)); -- cgit v1.2.3 From 1e2470b1e940877f6fe247a65bccd2b62b621eb6 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Parm=C3=A9nides=20GV?= Date: Mon, 10 Jun 2013 18:56:34 +0200 Subject: Removed unused methods and variables. Variables from LeapSRPSession were there because I used it while testing srp calculations, comparing that strings with the ones from javascript. Unused method from ProviderAPI was there because I foresee I'll have to implement it in the future, but I've removed it since it's already in the history. This fixes #2781. --- src/se/leap/leapclient/LeapSRPSession.java | 6 ------ src/se/leap/leapclient/ProviderAPI.java | 12 ------------ 2 files changed, 18 deletions(-) (limited to 'src/se/leap/leapclient') diff --git a/src/se/leap/leapclient/LeapSRPSession.java b/src/se/leap/leapclient/LeapSRPSession.java index 8eb28c4d..0a8e735f 100644 --- a/src/se/leap/leapclient/LeapSRPSession.java +++ b/src/se/leap/leapclient/LeapSRPSession.java @@ -173,7 +173,6 @@ public class LeapSRPSession { // Calculate x = H(s | H(U | ':' | password)) byte[] xb = calculatePasswordHash(username, password, Util.trim(salt_bytes)); this.x = new BigInteger(1, xb); - String xstr = x.toString(16); // Calculate v = kg^x mod N String k_string = "bf66c44a428916cad64aa7c679f3fd897ad4c375e9bbb4cbf2f5de241d618ef0"; @@ -210,7 +209,6 @@ public class LeapSRPSession { // Calculate S = (B - kg^x) ^ (a + u * x) % N BigInteger S = calculateS(Bbytes); byte[] S_bytes = Util.trim(S.toByteArray()); - String Sstr = S.toString(16); // K = SessionHash(S) String hash_algorithm = params.hashAlgorithm; @@ -219,10 +217,8 @@ public class LeapSRPSession { // clientHash = H(N) xor H(g) | H(U) | A | B | K clientHash.update(K); - String Kstr = new BigInteger(1, K).toString(16); byte[] M1 = Util.trim(clientHash.digest()); - String M1str = new BigInteger(1, M1).toString(16); // serverHash = Astr + M + K serverHash.update(Abytes); @@ -246,9 +242,7 @@ public class LeapSRPSession { BigInteger u = new BigInteger(1, u_bytes); BigInteger B_minus_v = B.subtract(v); - String vstr = v.toString(16); BigInteger a_ux = a.add(u.multiply(x)); - String xstr = x.toString(16); BigInteger S = B_minus_v.modPow(a_ux, N); return S; } diff --git a/src/se/leap/leapclient/ProviderAPI.java b/src/se/leap/leapclient/ProviderAPI.java index a51c3a05..0898ebb8 100644 --- a/src/se/leap/leapclient/ProviderAPI.java +++ b/src/se/leap/leapclient/ProviderAPI.java @@ -125,18 +125,6 @@ public class ProviderAPI extends IntentService { return false; } } - - private boolean registerWithSRP(Bundle task) { - String username = (String) task.get(ConfigHelper.USERNAME_KEY); - String password = (String) task.get(ConfigHelper.PASSWORD_KEY); - String authentication_server = (String) task.get(ConfigHelper.API_URL_KEY); - - BigInteger ng_1024 = new BigInteger(ConfigHelper.NG_1024, 16); - BigInteger salt = ng_1024.probablePrime(1024, null); - byte[] salt_in_bytes = salt.toByteArray(); - - return false; - } private Bundle authenticateBySRP(Bundle task) { Bundle session_id_bundle = new Bundle(); -- cgit v1.2.3 From 6c90e0043ec68254c15562fd12a707f5e45f47e7 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Parm=C3=A9nides=20GV?= Date: Tue, 11 Jun 2013 19:01:36 +0200 Subject: We are not using SD storage anymore. We were using it to save certificate and provider.json files from chosen provider, so that exporting them was easily done. We don't need that files, because if we wanted to export that files we would be able to recover them easily and updated. This fixes #2783 --- src/se/leap/leapclient/ConfigHelper.java | 20 -------------------- src/se/leap/leapclient/ProviderAPI.java | 2 -- 2 files changed, 22 deletions(-) (limited to 'src/se/leap/leapclient') diff --git a/src/se/leap/leapclient/ConfigHelper.java b/src/se/leap/leapclient/ConfigHelper.java index e8bc27c5..11f95041 100644 --- a/src/se/leap/leapclient/ConfigHelper.java +++ b/src/se/leap/leapclient/ConfigHelper.java @@ -156,26 +156,6 @@ public class ConfigHelper { return value; } - public static void saveFile(String filename, String content) { - File root = Environment.getExternalStorageDirectory(); - File leap_dir = new File(root.getAbsolutePath() + File.separator + USER_DIRECTORY); - if (!leap_dir.isDirectory()) { - leap_dir.mkdir(); - } - try { - if (!leap_dir.isDirectory()) { - throw new IOException( - "Unable to create directory " + USER_DIRECTORY + ". Maybe the SD card is mounted?"); - } - File outputFile = new File(leap_dir, filename); - BufferedWriter writer = new BufferedWriter(new FileWriter(outputFile)); - writer.write(content); - writer.close(); - } catch (IOException e) { - Log.w("leap_android", e.getMessage(), e); - } - } - public static FileInputStream openFileInputStream(String filename) { FileInputStream input_stream = null; File root = Environment.getExternalStorageDirectory(); diff --git a/src/se/leap/leapclient/ProviderAPI.java b/src/se/leap/leapclient/ProviderAPI.java index 0898ebb8..10f04c5d 100644 --- a/src/se/leap/leapclient/ProviderAPI.java +++ b/src/se/leap/leapclient/ProviderAPI.java @@ -217,7 +217,6 @@ public class ProviderAPI extends IntentService { ConfigHelper.saveSharedPref(ConfigHelper.ALLOWED_ANON, provider_json.getJSONObject(ConfigHelper.SERVICE_KEY).getBoolean(ConfigHelper.ALLOWED_ANON)); String filename = provider_name + "_provider.json".replaceFirst("__", "_"); - ConfigHelper.saveFile(filename, provider_json.toString()); ProviderListContent.addItem(new ProviderItem(provider_name, provider_json_url, filename, custom, danger_on)); result.putBoolean(ConfigHelper.RESULT_KEY, true); @@ -243,7 +242,6 @@ public class ProviderAPI extends IntentService { provider_json = getJSONFromProvider(provider_json_url, danger_on); String filename = provider_name + "_provider.json".replaceFirst("__", "_"); - ConfigHelper.saveFile(filename, provider_json.toString()); ProviderListContent.addItem(new ProviderItem(provider_name, provider_json_url, filename, custom, danger_on)); return true; -- cgit v1.2.3 From 2f69eb6eb9aa3993354e8de295df68558ab7b71e Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Parm=C3=A9nides=20GV?= Date: Wed, 12 Jun 2013 18:51:44 +0200 Subject: Removed some unnecessary libraries. I've also removed some unnecessary comments from LeapHttpClient. --- src/se/leap/leapclient/LeapHttpClient.java | 10 +--------- 1 file changed, 1 insertion(+), 9 deletions(-) (limited to 'src/se/leap/leapclient') diff --git a/src/se/leap/leapclient/LeapHttpClient.java b/src/se/leap/leapclient/LeapHttpClient.java index 3eeebe95..00ee15e9 100644 --- a/src/se/leap/leapclient/LeapHttpClient.java +++ b/src/se/leap/leapclient/LeapHttpClient.java @@ -31,23 +31,15 @@ public class LeapHttpClient extends DefaultHttpClient { protected ClientConnectionManager createClientConnectionManager() { SchemeRegistry registry = new SchemeRegistry(); registry.register(new Scheme("http", PlainSocketFactory.getSocketFactory(), 80)); - // Register for port 443 our SSLSocketFactory with our keystore - // to the ConnectionManager registry.register(new Scheme("https", newSslSocketFactory(), 443)); + return new SingleClientConnManager(getParams(), registry); } private SSLSocketFactory newSslSocketFactory() { try { - // Get an instance of the Bouncy Castle KeyStore format KeyStore trusted = ConfigHelper.getKeystore(); - - // Pass the keystore to the SSLSocketFactory. The factory is responsible - // for the verification of the server certificate. SSLSocketFactory sf = new SSLSocketFactory(trusted); - - // Hostname verification from certificate - // http://hc.apache.org/httpcomponents-client-ga/tutorial/html/connmgmt.html#d4e506 sf.setHostnameVerifier(SSLSocketFactory.ALLOW_ALL_HOSTNAME_VERIFIER); return sf; -- cgit v1.2.3 From 30c7bab5d8618df665e602fdd08bafa010a15497 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Parm=C3=A9nides=20GV?= Date: Thu, 13 Jun 2013 17:37:37 +0200 Subject: bitmask json files are downloaded. There was a problem on the assets file "bitmask.url". It had an error in the eip-service url. We should use this file only for main url, and proceed as if it were a new provider but with a preseeded main url. --- src/se/leap/leapclient/ConfigHelper.java | 1 - src/se/leap/leapclient/ConfigurationWizard.java | 4 ++-- src/se/leap/leapclient/ProviderAPI.java | 18 ++++++++---------- src/se/leap/leapclient/ProviderListContent.java | 17 +++-------------- 4 files changed, 13 insertions(+), 27 deletions(-) (limited to 'src/se/leap/leapclient') diff --git a/src/se/leap/leapclient/ConfigHelper.java b/src/se/leap/leapclient/ConfigHelper.java index 11f95041..0e50c7dd 100644 --- a/src/se/leap/leapclient/ConfigHelper.java +++ b/src/se/leap/leapclient/ConfigHelper.java @@ -192,7 +192,6 @@ public class ConfigHelper { public static void addTrustedCertificate(String provider, String certificate) { String filename_to_save = provider + "_certificate.cer"; - saveFile(filename_to_save, certificate); CertificateFactory cf; try { cf = CertificateFactory.getInstance("X.509"); diff --git a/src/se/leap/leapclient/ConfigurationWizard.java b/src/se/leap/leapclient/ConfigurationWizard.java index 2a9b93b2..1dc00938 100644 --- a/src/se/leap/leapclient/ConfigurationWizard.java +++ b/src/se/leap/leapclient/ConfigurationWizard.java @@ -80,8 +80,8 @@ implements ProviderListFragment.Callbacks, NewProviderDialog.NewProviderDialogIn 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.getBoolean(ConfigHelper.ALLOWED_ANON)); - + ConfigHelper.saveSharedPref(ConfigHelper.ALLOWED_ANON, provider_json.getJSONObject(ConfigHelper.SERVICE_KEY).getBoolean(ConfigHelper.ALLOWED_ANON)); + mConfigState.setAction(PROVIDER_SET); mProgressDialog.setMessage(getResources().getString(R.string.config_downloading_services)); diff --git a/src/se/leap/leapclient/ProviderAPI.java b/src/se/leap/leapclient/ProviderAPI.java index 10f04c5d..471eb6cf 100644 --- a/src/se/leap/leapclient/ProviderAPI.java +++ b/src/se/leap/leapclient/ProviderAPI.java @@ -216,9 +216,7 @@ public class ProviderAPI extends IntentService { } else { ConfigHelper.saveSharedPref(ConfigHelper.ALLOWED_ANON, provider_json.getJSONObject(ConfigHelper.SERVICE_KEY).getBoolean(ConfigHelper.ALLOWED_ANON)); - String filename = provider_name + "_provider.json".replaceFirst("__", "_"); - - ProviderListContent.addItem(new ProviderItem(provider_name, provider_json_url, filename, custom, danger_on)); + 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); @@ -237,17 +235,17 @@ public class ProviderAPI extends IntentService { String provider_main_url = (String) task.get(ConfigHelper.PROVIDER_MAIN_URL); String provider_name = provider_main_url.replaceFirst("http[s]?://", "").replaceFirst("\\/", "_"); String provider_json_url = guessURL(provider_main_url); - JSONObject provider_json = null; + + JSONObject provider_json; try { provider_json = getJSONFromProvider(provider_json_url, danger_on); - - String filename = provider_name + "_provider.json".replaceFirst("__", "_"); - - ProviderListContent.addItem(new ProviderItem(provider_name, provider_json_url, filename, custom, danger_on)); - return true; + ProviderListContent.addItem(new ProviderItem(provider_name, provider_json_url, provider_json, custom, danger_on)); } catch (JSONException e) { - return false; + // TODO Auto-generated catch block + e.printStackTrace(); } + + return true; } private String getStringFromProviderWithoutValidate( diff --git a/src/se/leap/leapclient/ProviderListContent.java b/src/se/leap/leapclient/ProviderListContent.java index b83bbd8e..10dce578 100644 --- a/src/se/leap/leapclient/ProviderListContent.java +++ b/src/se/leap/leapclient/ProviderListContent.java @@ -1,6 +1,5 @@ package se.leap.leapclient; -import java.io.FileInputStream; import java.io.IOException; import java.io.InputStream; import java.util.ArrayList; @@ -78,21 +77,14 @@ public class ProviderListContent { } } - public ProviderItem(String name, String provider_json_url, String provider_json_filename, boolean custom, boolean danger_on) { + public ProviderItem(String name, String provider_json_url, JSONObject provider_json, boolean custom, boolean danger_on) { - - FileInputStream provider_json = ConfigHelper.openFileInputStream(provider_json_filename); try { - byte[] urls_file_bytes = new byte[provider_json.available()]; - provider_json.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; this.provider_json_url = provider_json_url; - this.provider_json_filename = provider_json_filename; - eip_service_json_url = file_contents.getString("api_uri") + "/" + file_contents.getString("api_version") + "/" + ConfigHelper.EIP_SERVICE_API_PATH; - cert_json_url = (String) file_contents.get("ca_cert_uri"); + eip_service_json_url = provider_json.getString("api_uri") + "/" + provider_json.getString("api_version") + "/" + ConfigHelper.EIP_SERVICE_API_PATH; + cert_json_url = (String) provider_json.get("ca_cert_uri"); this.custom = custom; this.danger_on = danger_on; if(custom) @@ -100,9 +92,6 @@ public class ProviderListContent { } catch (JSONException e) { // TODO Auto-generated catch block e.printStackTrace(); - } catch (IOException e) { - // TODO Auto-generated catch block - e.printStackTrace(); } } -- cgit v1.2.3 From bffd21a326bcb86d814dd3fe2caf5295ea705f2d Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Parm=C3=A9nides=20GV?= Date: Thu, 13 Jun 2013 21:12:24 +0200 Subject: Bypasses self signed certificates. It's working against cdev.bitmask.net and bitmask.net. Look at #2840 for further explanation about self signed certificates. I've also removed some file dependant configuration (when a provider was custom, ConfigurationWizard still tried to read from file a provider.json that now I store in memory via ProviderItem class). --- src/se/leap/leapclient/ConfigurationWizard.java | 3 +- src/se/leap/leapclient/ProviderAPI.java | 126 +++++++++++++++++------- src/se/leap/leapclient/ProviderListContent.java | 2 + 3 files changed, 94 insertions(+), 37 deletions(-) (limited to 'src/se/leap/leapclient') diff --git a/src/se/leap/leapclient/ConfigurationWizard.java b/src/se/leap/leapclient/ConfigurationWizard.java index 1dc00938..6f26adcc 100644 --- a/src/se/leap/leapclient/ConfigurationWizard.java +++ b/src/se/leap/leapclient/ConfigurationWizard.java @@ -188,8 +188,7 @@ implements ProviderListFragment.Callbacks, NewProviderDialog.NewProviderDialogIn // 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_contents = new Scanner(ConfigHelper.openFileInputStream(current_provider_item.provider_json_filename)).useDelimiter("\\A").next(); - provider_json = new JSONObject(provider_contents); + provider_json = current_provider_item.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, current_provider_item.danger_on); diff --git a/src/se/leap/leapclient/ProviderAPI.java b/src/se/leap/leapclient/ProviderAPI.java index 471eb6cf..f98e4361 100644 --- a/src/se/leap/leapclient/ProviderAPI.java +++ b/src/se/leap/leapclient/ProviderAPI.java @@ -26,6 +26,8 @@ import javax.net.ssl.HttpsURLConnection; import javax.net.ssl.SSLContext; import javax.net.ssl.SSLSession; import javax.net.ssl.TrustManagerFactory; +import javax.net.ssl.TrustManager; +import javax.net.ssl.X509TrustManager; import org.apache.http.HttpEntity; import org.apache.http.HttpResponse; @@ -247,34 +249,6 @@ public class ProviderAPI extends IntentService { return true; } - - private String getStringFromProviderWithoutValidate( - URL provider_json_url) { - - String json_string = ""; - HostnameVerifier hostnameVerifier = new HostnameVerifier() { - @Override - public boolean verify(String hostname, SSLSession session) { - return true; - } - }; - - // Tell the URLConnection to use our HostnameVerifier - try { - HttpsURLConnection urlConnection = - (HttpsURLConnection)provider_json_url.openConnection(); - urlConnection.setHostnameVerifier(hostnameVerifier); - json_string = new Scanner(urlConnection.getInputStream()).useDelimiter("\\A").next(); - } catch (MalformedURLException e) { - // TODO Auto-generated catch block - e.printStackTrace(); - } catch (IOException e) { - // TODO Auto-generated catch block - json_string = getStringFromProviderWithCACertAdded(provider_json_url); - //e.printStackTrace(); - } - return json_string; - } private String getStringFromProvider(String string_url, boolean danger_on) { @@ -307,25 +281,56 @@ public class ProviderAPI extends IntentService { return json_file_content; } + private String getStringFromProviderWithoutValidate( + URL provider_json_url) { + + String json_string = ""; + HostnameVerifier hostnameVerifier = new HostnameVerifier() { + @Override + public boolean verify(String hostname, SSLSession session) { + return true; + } + }; + + try { + HttpsURLConnection urlConnection = + (HttpsURLConnection)provider_json_url.openConnection(); + urlConnection.setHostnameVerifier(hostnameVerifier); + json_string = new Scanner(urlConnection.getInputStream()).useDelimiter("\\A").next(); + } catch (MalformedURLException e) { + // TODO Auto-generated catch block + e.printStackTrace(); + } catch (IOException e) { + json_string = getStringFromProviderWithCACertAdded(provider_json_url); + //e.printStackTrace(); + } + + return json_string; + } + private String getStringFromProviderWithCACertAdded(URL url) { 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()) { + cert_string = downloadCertificateWithoutTrusting(url.getProtocol() + "://" + url.getHost() + "/" + "ca.crt"); + ConfigHelper.saveSharedPref(ConfigHelper.MAIN_CERT_KEY, cert_string); + } CertificateFactory cf; try { cf = CertificateFactory.getInstance("X.509"); - String cert_string = ConfigHelper.getStringFromSharedPref(ConfigHelper.MAIN_CERT_KEY); cert_string = cert_string.replaceFirst("-----BEGIN CERTIFICATE-----", "").replaceFirst("-----END CERTIFICATE-----", "").trim(); byte[] cert_bytes = Base64.decode(cert_string, Base64.DEFAULT); InputStream caInput = new ByteArrayInputStream(cert_bytes); java.security.cert.Certificate ca; try { - ca = cf.generateCertificate(caInput); - System.out.println("ca=" + ((X509Certificate) ca).getSubjectDN()); + ca = cf.generateCertificate(caInput); + System.out.println("ca=" + ((X509Certificate) ca).getSubjectDN()); } finally { - caInput.close(); + caInput.close(); } // Create a KeyStore containing our trusted CAs @@ -345,7 +350,7 @@ public class ProviderAPI extends IntentService { // Tell the URLConnection to use a SocketFactory from our SSLContext HttpsURLConnection urlConnection = - (HttpsURLConnection)url.openConnection(); + (HttpsURLConnection)url.openConnection(); urlConnection.setSSLSocketFactory(context.getSocketFactory()); json_file_content = new Scanner(urlConnection.getInputStream()).useDelimiter("\\A").next(); } catch (CertificateException e) { @@ -364,10 +369,61 @@ public class ProviderAPI extends IntentService { // TODO Auto-generated catch block e.printStackTrace(); } - return json_file_content; } + 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; + } + 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); diff --git a/src/se/leap/leapclient/ProviderListContent.java b/src/se/leap/leapclient/ProviderListContent.java index 10dce578..4cf0a5ff 100644 --- a/src/se/leap/leapclient/ProviderListContent.java +++ b/src/se/leap/leapclient/ProviderListContent.java @@ -40,6 +40,7 @@ public class ProviderListContent { public String id; public String name; 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; @@ -83,6 +84,7 @@ public class ProviderListContent { id = name; this.name = name; this.provider_json_url = provider_json_url; + this.provider_json = provider_json; eip_service_json_url = provider_json.getString("api_uri") + "/" + provider_json.getString("api_version") + "/" + ConfigHelper.EIP_SERVICE_API_PATH; cert_json_url = (String) provider_json.get("ca_cert_uri"); this.custom = custom; -- cgit v1.2.3 From d475ae617d8dc0994a1294be7c8cca338a68fd9e Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Parm=C3=A9nides=20GV?= Date: Wed, 19 Jun 2013 19:05:12 +0200 Subject: First round of comments. This resolves the first step from issue #2908. Next step: Put user message strings into an appropiate place. --- src/se/leap/leapclient/ConfigHelper.java | 59 +++++++++- src/se/leap/leapclient/ConfigurationWizard.java | 63 ++++++++--- src/se/leap/leapclient/Dashboard.java | 11 ++ src/se/leap/leapclient/LeapHttpClient.java | 17 +++ src/se/leap/leapclient/LeapSRPSession.java | 19 +++- src/se/leap/leapclient/LogInDialog.java | 31 +++++- src/se/leap/leapclient/NewProviderDialog.java | 15 +++ src/se/leap/leapclient/ProviderAPI.java | 121 ++++++++++++++++++++- .../leap/leapclient/ProviderAPIResultReceiver.java | 12 +- src/se/leap/leapclient/ProviderListContent.java | 44 ++++---- 10 files changed, 344 insertions(+), 48 deletions(-) (limited to 'src/se/leap/leapclient') diff --git a/src/se/leap/leapclient/ConfigHelper.java b/src/se/leap/leapclient/ConfigHelper.java index 0e50c7dd..5838f529 100644 --- a/src/se/leap/leapclient/ConfigHelper.java +++ b/src/se/leap/leapclient/ConfigHelper.java @@ -1,10 +1,8 @@ package se.leap.leapclient; -import java.io.BufferedWriter; import java.io.File; import java.io.FileInputStream; import java.io.FileNotFoundException; -import java.io.FileWriter; import java.io.IOException; import java.math.BigInteger; import java.io.InputStream; @@ -21,8 +19,14 @@ import org.json.JSONObject; import android.content.Context; import android.content.SharedPreferences; import android.os.Environment; -import android.util.Log; +/** + * Stores constants, and implements auxiliary methods used across all LEAP Android classes. + * + * @author parmegv + * @author MeanderingCode + * + */ public class ConfigHelper { public static SharedPreferences shared_preferences; @@ -100,6 +104,11 @@ public class ConfigHelper { 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 @@ -109,6 +118,11 @@ public class ConfigHelper { 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 @@ -117,7 +131,12 @@ public class ConfigHelper { 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 @@ -126,6 +145,11 @@ public class ConfigHelper { shared_preferences_editor.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; if ( checkSharedPrefs() ) { @@ -134,6 +158,11 @@ public class ConfigHelper { 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() ) { @@ -156,6 +185,11 @@ public class ConfigHelper { return value; } + /** + * 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(); @@ -169,11 +203,20 @@ public class ConfigHelper { return input_stream; } + /** + * Sets class scope Shared Preferences + * @param shared_preferences + */ public static void setSharedPreferences( SharedPreferences shared_preferences) { ConfigHelper.shared_preferences = shared_preferences; } + /** + * 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 { @@ -190,6 +233,11 @@ public class ConfigHelper { } } + /** + * 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) { String filename_to_save = provider + "_certificate.cer"; CertificateFactory cf; @@ -217,6 +265,9 @@ public class ConfigHelper { } } + /** + * @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 index 6f26adcc..91b92d65 100644 --- a/src/se/leap/leapclient/ConfigurationWizard.java +++ b/src/se/leap/leapclient/ConfigurationWizard.java @@ -2,7 +2,6 @@ package se.leap.leapclient; import java.io.IOException; import java.util.Iterator; -import java.util.Scanner; import org.json.JSONException; import org.json.JSONObject; @@ -23,6 +22,14 @@ import android.os.Handler; import android.view.View; import android.widget.Toast; +/** + * 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, Receiver { @@ -154,6 +161,10 @@ implements ProviderListFragment.Callbacks, NewProviderDialog.NewProviderDialogIn } } + /** + * 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(); @@ -178,20 +189,26 @@ implements ProviderListFragment.Callbacks, NewProviderDialog.NewProviderDialogIn return loaded_preseeded_providers; } - private void saveProviderJson(ProviderItem current_provider_item) { + /** + * 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 { - String provider_contents = ""; - if(!current_provider_item.custom) { - updateProviderDotJson(current_provider_item.name, current_provider_item.provider_json_url, current_provider_item.danger_on); + 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 = current_provider_item.provider_json; + 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, current_provider_item.danger_on); + ConfigHelper.saveSharedPref(ConfigHelper.DANGER_ON, provider.danger_on); mProgressDialog.setMessage(getResources().getString(R.string.config_downloading_services)); downloadJSONFiles(mSelectedProvider); @@ -202,15 +219,21 @@ implements ProviderListFragment.Callbacks, NewProviderDialog.NewProviderDialogIn } } - private void downloadJSONFiles(ProviderItem current_provider_item) { + /** + * 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 method_and_parameters = new Bundle(); - method_and_parameters.putString(ConfigHelper.PROVIDER_KEY, current_provider_item.name); - method_and_parameters.putString(ConfigHelper.MAIN_CERT_KEY, current_provider_item.cert_json_url); - method_and_parameters.putString(ConfigHelper.EIP_SERVICE_KEY, current_provider_item.eip_service_json_url); - method_and_parameters.putBoolean(ConfigHelper.DANGER_ON, current_provider_item.danger_on); + 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); provider_API_command.putExtra(ConfigHelper.DOWNLOAD_JSON_FILES_BUNDLE_EXTRA, method_and_parameters); provider_API_command.putExtra("receiver", providerAPI_result_receiver); @@ -218,7 +241,10 @@ implements ProviderListFragment.Callbacks, NewProviderDialog.NewProviderDialogIn startService(provider_API_command); } - private boolean downloadAnonCert() { + /** + * Asks ProviderAPI to download an anonymous (anon) VPN certificate. + */ + private void downloadAnonCert() { Intent provider_API_command = new Intent(this, ProviderAPI.class); Bundle method_and_parameters = new Bundle(); @@ -229,9 +255,12 @@ implements ProviderListFragment.Callbacks, NewProviderDialog.NewProviderDialogIn provider_API_command.putExtra("receiver", providerAPI_result_receiver); startService(provider_API_command); - return true; } + /** + * Open the new provider dialog + * @param view from which the dialog is showed + */ public void addNewProvider(View view) { FragmentTransaction fragment_transaction = getFragmentManager().beginTransaction(); Fragment previous_new_provider_dialog = getFragmentManager().findFragmentByTag(ConfigHelper.NEW_PROVIDER_DIALOG); @@ -258,6 +287,12 @@ implements ProviderListFragment.Callbacks, NewProviderDialog.NewProviderDialogIn 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); diff --git a/src/se/leap/leapclient/Dashboard.java b/src/se/leap/leapclient/Dashboard.java index c1f4697d..e8ea2705 100644 --- a/src/se/leap/leapclient/Dashboard.java +++ b/src/se/leap/leapclient/Dashboard.java @@ -229,6 +229,9 @@ public class Dashboard extends Activity implements LogInDialog.LogInDialogInterf startService(provider_API_command); } + /** + * Asks ProviderAPI to log out. + */ public void logOut() { providerAPI_result_receiver = new ProviderAPIResultReceiver(new Handler()); providerAPI_result_receiver.setReceiver(this); @@ -251,6 +254,10 @@ public class Dashboard extends Activity implements LogInDialog.LogInDialogInterf startService(provider_API_command); } + /** + * Shows the log in dialog. + * @param view from which the dialog is created. + */ public void logInDialog(View view) { FragmentTransaction fragment_transaction = getFragmentManager().beginTransaction(); Fragment previous_log_in_dialog = getFragmentManager().findFragmentByTag(ConfigHelper.LOG_IN_DIALOG); @@ -263,6 +270,10 @@ public class Dashboard extends Activity implements LogInDialog.LogInDialogInterf newFragment.show(fragment_transaction, ConfigHelper.LOG_IN_DIALOG); } + /** + * 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); diff --git a/src/se/leap/leapclient/LeapHttpClient.java b/src/se/leap/leapclient/LeapHttpClient.java index 00ee15e9..42f9a523 100644 --- a/src/se/leap/leapclient/LeapHttpClient.java +++ b/src/se/leap/leapclient/LeapHttpClient.java @@ -11,11 +11,22 @@ 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); @@ -36,6 +47,12 @@ public class LeapHttpClient extends DefaultHttpClient { return new SingleClientConnManager(getParams(), registry); } + /** + * Uses keystore from ConfigHelper for the SSLSocketFactory. + * + * Sets hostname verifier to allow all hostname verifier. + * @return + */ private SSLSocketFactory newSslSocketFactory() { try { KeyStore trusted = ConfigHelper.getKeystore(); diff --git a/src/se/leap/leapclient/LeapSRPSession.java b/src/se/leap/leapclient/LeapSRPSession.java index 0a8e735f..beb286da 100644 --- a/src/se/leap/leapclient/LeapSRPSession.java +++ b/src/se/leap/leapclient/LeapSRPSession.java @@ -9,6 +9,14 @@ import java.util.Arrays; import org.jboss.security.Util; 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 { private SRPParameters params; @@ -133,7 +141,14 @@ public class LeapSRPSession { return v; } - public byte[] xor(byte[] b1, byte[] b2, int length) + /** + * 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(); @@ -185,7 +200,7 @@ public class LeapSRPSession { byte[] digest_of_g = newDigest().digest(params.g); // clientHash = H(N) xor H(g) - byte[] xor_digest = xor(digest_of_n, digest_of_g, digest_of_g.length); + byte[] xor_digest = xor(digest_of_n, digest_of_g); clientHash.update(xor_digest); // clientHash = H(N) xor H(g) | H(U) diff --git a/src/se/leap/leapclient/LogInDialog.java b/src/se/leap/leapclient/LogInDialog.java index c20413d7..00429d10 100644 --- a/src/se/leap/leapclient/LogInDialog.java +++ b/src/se/leap/leapclient/LogInDialog.java @@ -11,6 +11,16 @@ import android.view.View; import android.widget.EditText; import android.widget.Toast; +/** + * 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 { public AlertDialog onCreateDialog(Bundle savedInstanceState) { @@ -43,16 +53,35 @@ public class LogInDialog extends DialogFragment { return builder.create(); } - boolean wellFormedPassword(String 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; } + /** + * 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; diff --git a/src/se/leap/leapclient/NewProviderDialog.java b/src/se/leap/leapclient/NewProviderDialog.java index 60ac8d2a..5b84ec03 100644 --- a/src/se/leap/leapclient/NewProviderDialog.java +++ b/src/se/leap/leapclient/NewProviderDialog.java @@ -13,6 +13,12 @@ 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 { public interface NewProviderDialogInterface { @@ -21,6 +27,9 @@ public class NewProviderDialog extends DialogFragment { NewProviderDialogInterface interface_with_ConfigurationWizard; + /** + * @return a new instance of this DialogFragment. + */ public static DialogFragment newInstance() { NewProviderDialog dialog_fragment = new NewProviderDialog(); return dialog_fragment; @@ -37,6 +46,7 @@ public class NewProviderDialog extends DialogFragment { } } + @Override public Dialog onCreateDialog(Bundle savedInstanceState) { AlertDialog.Builder builder = new AlertDialog.Builder(getActivity()); LayoutInflater inflater = getActivity().getLayoutInflater(); @@ -71,6 +81,11 @@ public class NewProviderDialog extends DialogFragment { 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/ProviderAPI.java b/src/se/leap/leapclient/ProviderAPI.java index f98e4361..f8d730e7 100644 --- a/src/se/leap/leapclient/ProviderAPI.java +++ b/src/se/leap/leapclient/ProviderAPI.java @@ -55,6 +55,15 @@ import android.os.ResultReceiver; import android.util.Base64; import android.util.Log; +/** + * Implements HTTP api methods used to manage communications with the provider server. + * + * It's an IntentService because it downloads data fromt he Internet, so it operates in the background. + * + * @author parmegv + * @author MeanderingCode + * + */ public class ProviderAPI extends IntentService { public ProviderAPI() { @@ -113,6 +122,11 @@ public class ProviderAPI extends IntentService { } } + /** + * 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(ConfigHelper.MAIN_CERT_KEY); String eip_service_json_url = task.getString(ConfigHelper.EIP_SERVICE_KEY); @@ -128,6 +142,12 @@ 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. + */ private Bundle authenticateBySRP(Bundle task) { Bundle session_id_bundle = new Bundle(); @@ -168,11 +188,31 @@ public class ProviderAPI extends IntentService { return session_id_bundle; } + /** + * 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 + */ 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); } + /** + * 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 + */ 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, Util.trim(m1)).toString(16)); JSONObject json_response = sendToServer(put); @@ -188,6 +228,14 @@ 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(); @@ -204,6 +252,11 @@ public class ProviderAPI extends IntentService { return json_response; } + /** + * 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. + */ private Bundle updateProviderDotJSON(Bundle task) { Bundle result = new Bundle(); boolean custom = task.getBoolean(ConfigHelper.CUSTOM); @@ -230,13 +283,18 @@ public class ProviderAPI extends IntentService { 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 boolean downloadNewProviderDotJSON(Bundle task) { boolean custom = true; boolean danger_on = task.getBoolean(ConfigHelper.DANGER_ON); String provider_main_url = (String) task.get(ConfigHelper.PROVIDER_MAIN_URL); String provider_name = provider_main_url.replaceFirst("http[s]?://", "").replaceFirst("\\/", "_"); - String provider_json_url = guessURL(provider_main_url); + String provider_json_url = guessProviderDotJsonURL(provider_main_url); JSONObject provider_json; try { @@ -245,11 +303,20 @@ public class ProviderAPI extends IntentService { } catch (JSONException e) { // TODO Auto-generated catch block e.printStackTrace(); + return false; } return true; } + /** + * Tries to download whatever is pointed by the string_url. + * + * 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) { String json_file_content = ""; @@ -281,8 +348,15 @@ public class ProviderAPI extends IntentService { return json_file_content; } + /** + * 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 provider_json_url) { + URL string_url) { String json_string = ""; HostnameVerifier hostnameVerifier = new HostnameVerifier() { @@ -294,20 +368,25 @@ public class ProviderAPI extends IntentService { try { HttpsURLConnection urlConnection = - (HttpsURLConnection)provider_json_url.openConnection(); + (HttpsURLConnection)string_url.openConnection(); urlConnection.setHostnameVerifier(hostnameVerifier); json_string = new Scanner(urlConnection.getInputStream()).useDelimiter("\\A").next(); } catch (MalformedURLException e) { // TODO Auto-generated catch block e.printStackTrace(); } catch (IOException e) { - json_string = getStringFromProviderWithCACertAdded(provider_json_url); + json_string = getStringFromProviderWithCACertAdded(string_url); //e.printStackTrace(); } return json_string; } + /** + * Tries to download the contents of the provided url using main certificate from choosen provider. + * @param url + * @return an empty string if it fails, the url content if not. + */ private String getStringFromProviderWithCACertAdded(URL url) { String json_file_content = ""; @@ -372,6 +451,11 @@ public class ProviderAPI extends IntentService { return json_file_content; } + /** + * 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 = ""; @@ -424,15 +508,34 @@ public class ProviderAPI extends IntentService { 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); } - private String guessURL(String provider_main_url) { + /** + * 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) { DefaultHttpClient client = LeapHttpClient.getInstance(getApplicationContext()); int session_id_index = 0; @@ -459,6 +562,12 @@ public class ProviderAPI extends IntentService { 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) { String type_of_certificate = task.getString(ConfigHelper.TYPE_OF_CERTIFICATE); try { @@ -493,7 +602,7 @@ public class ProviderAPI extends IntentService { } catch (URISyntaxException e) { // TODO Auto-generated catch block e.printStackTrace(); + return false; } - return true; } } diff --git a/src/se/leap/leapclient/ProviderAPIResultReceiver.java b/src/se/leap/leapclient/ProviderAPIResultReceiver.java index a6a8d9d8..e32f6ffd 100644 --- a/src/se/leap/leapclient/ProviderAPIResultReceiver.java +++ b/src/se/leap/leapclient/ProviderAPIResultReceiver.java @@ -4,6 +4,11 @@ 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; @@ -11,11 +16,16 @@ public class ProviderAPIResultReceiver extends ResultReceiver { 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); } diff --git a/src/se/leap/leapclient/ProviderListContent.java b/src/se/leap/leapclient/ProviderListContent.java index 4cf0a5ff..4ae46099 100644 --- a/src/se/leap/leapclient/ProviderListContent.java +++ b/src/se/leap/leapclient/ProviderListContent.java @@ -10,30 +10,29 @@ import java.util.Map; import org.json.JSONException; import org.json.JSONObject; - +/** + * Models the provider list shown in the ConfigurationWizard. + * + * @author parmegv + * + */ public class ProviderListContent { - /** - * An array of sample (dummy) items. - */ public static List ITEMS = new ArrayList(); - /** - * A map of sample (dummy) items, by ID. - */ public static Map ITEM_MAP = new HashMap(); - - static { - //addItem(new ProviderItem("1", "bitmask", "https://bitmask.net/provider.json", "https://api.bitmask.net:4430/1/config/eip-service.json")); - } + /** + * 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 dummy item representing a piece of content. + * A provider item. */ public static class ProviderItem { public boolean custom = false; @@ -45,15 +44,13 @@ public class ProviderListContent { public String eip_service_json_url; public String cert_json_url; public boolean danger_on = false; - - public ProviderItem(String id, String name, String provider_json_url, String eip_service_json_url, String cert_json_url) { - this.id = id; - this.name = name; - this.provider_json_url = provider_json_url; - this.eip_service_json_url = eip_service_json_url; - this.cert_json_url = cert_json_url; - } + /** + * @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 { @@ -78,6 +75,13 @@ public class ProviderListContent { } } + /** + * @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 { -- cgit v1.2.3 From f4956bb818fb9ed04760e6de3b53b876272da5cc Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Parm=C3=A9nides=20GV?= Date: Thu, 20 Jun 2013 16:52:43 +0200 Subject: User messages are now in string.xml Some more constants added to ConfigHelper. This solves #2908. --- src/se/leap/leapclient/ConfigHelper.java | 6 +++++- src/se/leap/leapclient/ConfigurationWizard.java | 16 ++++++++-------- src/se/leap/leapclient/Dashboard.java | 18 +++++++++--------- src/se/leap/leapclient/LogInDialog.java | 2 +- src/se/leap/leapclient/NewProviderDialog.java | 4 ++-- src/se/leap/leapclient/ProviderAPI.java | 6 +++--- src/se/leap/leapclient/ProviderListContent.java | 6 +++--- 7 files changed, 31 insertions(+), 27 deletions(-) (limited to 'src/se/leap/leapclient') diff --git a/src/se/leap/leapclient/ConfigHelper.java b/src/se/leap/leapclient/ConfigHelper.java index 5838f529..cb4a550f 100644 --- a/src/se/leap/leapclient/ConfigHelper.java +++ b/src/se/leap/leapclient/ConfigHelper.java @@ -40,11 +40,14 @@ public class ConfigHelper { 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", RESULT_KEY = "result", + RECEIVER_KEY = "receiver", PROVIDER_KEY = "provider", SERVICE_KEY = "service", ALLOWED_ANON = "allow_anonymous", @@ -68,7 +71,8 @@ public class ConfigHelper { USERNAME_KEY = "username", PASSWORD_KEY = "password", ALLOW_REGISTRATION_KEY = "allow_registration", - EIP_SERVICE_API_PATH = "config/eip-service.json" + EIP_SERVICE_API_PATH = "config/eip-service.json", + ERRORS_KEY = "errors" ; final public static String NG_1024 = diff --git a/src/se/leap/leapclient/ConfigurationWizard.java b/src/se/leap/leapclient/ConfigurationWizard.java index 91b92d65..ce279425 100644 --- a/src/se/leap/leapclient/ConfigurationWizard.java +++ b/src/se/leap/leapclient/ConfigurationWizard.java @@ -105,7 +105,7 @@ implements ProviderListFragment.Callbacks, NewProviderDialog.NewProviderDialogIn } else if(resultCode == ConfigHelper.INCORRECTLY_UPDATED_PROVIDER_DOT_JSON) { mProgressDialog.dismiss(); - Toast.makeText(getApplicationContext(), "Install a new version of this app.", Toast.LENGTH_LONG).show(); + Toast.makeText(getApplicationContext(), R.string.incorrectly_updated_provider_dot_json_message, Toast.LENGTH_LONG).show(); setResult(RESULT_CANCELED, mConfigState); finish(); } @@ -122,20 +122,20 @@ implements ProviderListFragment.Callbacks, NewProviderDialog.NewProviderDialogIn } } else if(resultCode == ConfigHelper.INCORRECTLY_DOWNLOADED_JSON_FILES) { - Toast.makeText(getApplicationContext(), "You have not entered a LEAP provider URL or it is unavailable", Toast.LENGTH_LONG).show(); + Toast.makeText(getApplicationContext(), R.string.incorrectly_downloaded_json_files_message, Toast.LENGTH_LONG).show(); setResult(RESULT_CANCELED, mConfigState); finish(); } else if(resultCode == ConfigHelper.CORRECTLY_DOWNLOADED_CERTIFICATE) { mProgressDialog.dismiss(); - Toast.makeText(getApplicationContext(), "Your anon cert has been correctly downloaded", Toast.LENGTH_LONG).show(); + Toast.makeText(getApplicationContext(), R.string.correctly_downloaded_json_files_message, Toast.LENGTH_LONG).show(); Toast.makeText(getApplicationContext(), R.string.success, Toast.LENGTH_LONG).show(); //mConfigState.putExtra(CERTIFICATE_RETRIEVED, true); // If this isn't the last step and finish() is moved... setResult(RESULT_OK); finish(); } else if(resultCode == ConfigHelper.INCORRECTLY_DOWNLOADED_CERTIFICATE) { mProgressDialog.dismiss(); - Toast.makeText(getApplicationContext(), "Your anon cert was not downloaded", Toast.LENGTH_LONG).show(); + Toast.makeText(getApplicationContext(), R.string.incorrectly_downloaded_certificate_message, Toast.LENGTH_LONG).show(); setResult(RESULT_CANCELED, mConfigState); finish(); } @@ -236,7 +236,7 @@ implements ProviderListFragment.Callbacks, NewProviderDialog.NewProviderDialogIn method_and_parameters.putBoolean(ConfigHelper.DANGER_ON, provider.danger_on); provider_API_command.putExtra(ConfigHelper.DOWNLOAD_JSON_FILES_BUNDLE_EXTRA, method_and_parameters); - provider_API_command.putExtra("receiver", providerAPI_result_receiver); + provider_API_command.putExtra(ConfigHelper.RECEIVER_KEY, providerAPI_result_receiver); startService(provider_API_command); } @@ -252,7 +252,7 @@ implements ProviderListFragment.Callbacks, NewProviderDialog.NewProviderDialogIn method_and_parameters.putString(ConfigHelper.TYPE_OF_CERTIFICATE, ConfigHelper.ANON_CERTIFICATE); provider_API_command.putExtra(ConfigHelper.DOWNLOAD_CERTIFICATE, method_and_parameters); - provider_API_command.putExtra("receiver", providerAPI_result_receiver); + provider_API_command.putExtra(ConfigHelper.RECEIVER_KEY, providerAPI_result_receiver); startService(provider_API_command); } @@ -282,7 +282,7 @@ implements ProviderListFragment.Callbacks, NewProviderDialog.NewProviderDialogIn method_and_parameters.putBoolean(ConfigHelper.DANGER_ON, danger_on); provider_API_command.putExtra(ConfigHelper.DOWNLOAD_NEW_PROVIDER_DOTJSON, method_and_parameters); - provider_API_command.putExtra("receiver", providerAPI_result_receiver); + provider_API_command.putExtra(ConfigHelper.RECEIVER_KEY, providerAPI_result_receiver); startService(provider_API_command); } @@ -302,7 +302,7 @@ implements ProviderListFragment.Callbacks, NewProviderDialog.NewProviderDialogIn method_and_parameters.putBoolean(ConfigHelper.DANGER_ON, danger_on); provider_API_command.putExtra(ConfigHelper.UPDATE_PROVIDER_DOTJSON, method_and_parameters); - provider_API_command.putExtra("receiver", providerAPI_result_receiver); + 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 e8ea2705..dd8ee335 100644 --- a/src/se/leap/leapclient/Dashboard.java +++ b/src/se/leap/leapclient/Dashboard.java @@ -224,7 +224,7 @@ public class Dashboard extends Activity implements LogInDialog.LogInDialogInterf } provider_API_command.putExtra(ConfigHelper.SRP_AUTH, method_and_parameters); - provider_API_command.putExtra("receiver", providerAPI_result_receiver); + provider_API_command.putExtra(ConfigHelper.RECEIVER_KEY, providerAPI_result_receiver); startService(provider_API_command); } @@ -249,7 +249,7 @@ public class Dashboard extends Activity implements LogInDialog.LogInDialogInterf } provider_API_command.putExtra(ConfigHelper.LOG_OUT, method_and_parameters); - provider_API_command.putExtra("receiver", providerAPI_result_receiver); + provider_API_command.putExtra(ConfigHelper.RECEIVER_KEY, providerAPI_result_receiver); startService(provider_API_command); } @@ -286,7 +286,7 @@ public class Dashboard extends Activity implements LogInDialog.LogInDialogInterf method_and_parameters.putString(ConfigHelper.SESSION_ID_KEY, session_id.getValue()); provider_API_command.putExtra(ConfigHelper.DOWNLOAD_CERTIFICATE, method_and_parameters); - provider_API_command.putExtra("receiver", providerAPI_result_receiver); + provider_API_command.putExtra(ConfigHelper.RECEIVER_KEY, providerAPI_result_receiver); startService(provider_API_command); } @@ -297,25 +297,25 @@ public class Dashboard extends Activity implements LogInDialog.LogInDialogInterf 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); - Toast.makeText(getApplicationContext(), "Authentication succeeded", Toast.LENGTH_LONG).show(); + Toast.makeText(getApplicationContext(), R.string.succesful_authentication_message, Toast.LENGTH_LONG).show(); Cookie session_id = new BasicClientCookie(session_id_cookie_key, session_id_string); downloadAuthedUserCertificate(session_id); } else if(resultCode == ConfigHelper.SRP_AUTHENTICATION_FAILED) { setResult(RESULT_CANCELED); - Toast.makeText(getApplicationContext(), "Authentication failed", Toast.LENGTH_LONG).show(); + Toast.makeText(getApplicationContext(), R.string.authentication_failed_message, Toast.LENGTH_LONG).show(); } else if(resultCode == ConfigHelper.LOGOUT_SUCCESSFUL) { setResult(RESULT_OK); - Toast.makeText(getApplicationContext(), "Logged out", Toast.LENGTH_LONG).show(); + Toast.makeText(getApplicationContext(), R.string.successful_log_out_message, Toast.LENGTH_LONG).show(); } else if(resultCode == ConfigHelper.LOGOUT_FAILED) { setResult(RESULT_CANCELED); - Toast.makeText(getApplicationContext(), "Didn't logged out", Toast.LENGTH_LONG).show(); + Toast.makeText(getApplicationContext(), R.string.log_out_failed_message, Toast.LENGTH_LONG).show(); } else if(resultCode == ConfigHelper.CORRECTLY_DOWNLOADED_CERTIFICATE) { setResult(RESULT_CANCELED); - Toast.makeText(getApplicationContext(), "Your own cert has been correctly downloaded", Toast.LENGTH_LONG).show(); + Toast.makeText(getApplicationContext(), R.string.successful_authed_cert_downloaded_message, Toast.LENGTH_LONG).show(); } else if(resultCode == ConfigHelper.INCORRECTLY_DOWNLOADED_CERTIFICATE) { setResult(RESULT_CANCELED); - Toast.makeText(getApplicationContext(), "Your own cert has incorrectly been downloaded", Toast.LENGTH_LONG).show(); + Toast.makeText(getApplicationContext(), R.string.authed_cert_download_failed_message, Toast.LENGTH_LONG).show(); } } diff --git a/src/se/leap/leapclient/LogInDialog.java b/src/se/leap/leapclient/LogInDialog.java index 00429d10..dcb92d89 100644 --- a/src/se/leap/leapclient/LogInDialog.java +++ b/src/se/leap/leapclient/LogInDialog.java @@ -40,7 +40,7 @@ public class LogInDialog extends DialogFragment { interface_with_Dashboard.authenticate(username, password); } else { password_field.setText(""); - Toast.makeText(getActivity().getApplicationContext(), "Your password is not well-formed: it should have at least 8 characters", Toast.LENGTH_LONG).show(); + Toast.makeText(getActivity().getApplicationContext(), R.string.not_valid_password_message, Toast.LENGTH_LONG).show(); } } }) diff --git a/src/se/leap/leapclient/NewProviderDialog.java b/src/se/leap/leapclient/NewProviderDialog.java index 5b84ec03..678e805f 100644 --- a/src/se/leap/leapclient/NewProviderDialog.java +++ b/src/se/leap/leapclient/NewProviderDialog.java @@ -65,10 +65,10 @@ public class NewProviderDialog extends DialogFragment { boolean danger_on = danger_checkbox.isChecked(); if(validURL(entered_url)) { interface_with_ConfigurationWizard.saveProvider(entered_url, danger_on); - Toast.makeText(getActivity().getApplicationContext(), "It seems your URL is well formed", Toast.LENGTH_LONG).show(); + Toast.makeText(getActivity().getApplicationContext(), R.string.valid_url_entered, Toast.LENGTH_LONG).show(); } else { url_input_field.setText(""); - Toast.makeText(getActivity().getApplicationContext(), "It seems your URL is not well formed", Toast.LENGTH_LONG).show(); + Toast.makeText(getActivity().getApplicationContext(), R.string.not_valid_password_message, Toast.LENGTH_LONG).show(); } } }) diff --git a/src/se/leap/leapclient/ProviderAPI.java b/src/se/leap/leapclient/ProviderAPI.java index f8d730e7..4dfe200a 100644 --- a/src/se/leap/leapclient/ProviderAPI.java +++ b/src/se/leap/leapclient/ProviderAPI.java @@ -219,11 +219,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("M2"), 16).toByteArray(); + 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); 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("M2", Util.trim(M2_not_trimmed)); + session_idAndM2.put(ConfigHelper.M2_KEY, Util.trim(M2_not_trimmed)); } return session_idAndM2; } @@ -245,7 +245,7 @@ public class ProviderAPI extends IntentService { 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("errors") || json_response.has("errors")) { + if(!json_response.isNull(ConfigHelper.ERRORS_KEY) || json_response.has(ConfigHelper.ERRORS_KEY)) { return new JSONObject(); } diff --git a/src/se/leap/leapclient/ProviderListContent.java b/src/se/leap/leapclient/ProviderListContent.java index 4ae46099..8727b16b 100644 --- a/src/se/leap/leapclient/ProviderListContent.java +++ b/src/se/leap/leapclient/ProviderListContent.java @@ -60,10 +60,10 @@ public class ProviderListContent { JSONObject file_contents = new JSONObject(urls_file_content); id = name; this.name = name; - provider_json_url = file_contents.getString("json_provider"); + provider_json_url = file_contents.getString(ConfigHelper.PROVIDER_JSON_URL); 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("cert"); + cert_json_url = file_contents.getString(ConfigHelper.CERT_KEY); this.custom = custom; this.danger_on = danger_on; } catch (JSONException e) { @@ -89,7 +89,7 @@ public class ProviderListContent { this.name = name; this.provider_json_url = provider_json_url; this.provider_json = provider_json; - eip_service_json_url = provider_json.getString("api_uri") + "/" + provider_json.getString("api_version") + "/" + ConfigHelper.EIP_SERVICE_API_PATH; + eip_service_json_url = provider_json.getString(ConfigHelper.API_URL_KEY) + "/" + provider_json.getString(ConfigHelper.API_VERSION_KEY) + "/" + ConfigHelper.EIP_SERVICE_API_PATH; cert_json_url = (String) provider_json.get("ca_cert_uri"); this.custom = custom; this.danger_on = danger_on; -- cgit v1.2.3 From 65e2f56a8a10877964fb9fc57963d1bf8104801a Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Parm=C3=A9nides=20GV?= Date: Thu, 20 Jun 2013 17:47:07 +0200 Subject: No binary library needed. I've decided not to include any lib, but to copy the SRPParameters class to our codebase and Util.trim method to ConfigHelper. --- src/se/leap/leapclient/ConfigHelper.java | 20 +++++++++ src/se/leap/leapclient/LeapSRPSession.java | 69 +++++++++++++++--------------- src/se/leap/leapclient/ProviderAPI.java | 5 +-- 3 files changed, 57 insertions(+), 37 deletions(-) (limited to 'src/se/leap/leapclient') diff --git a/src/se/leap/leapclient/ConfigHelper.java b/src/se/leap/leapclient/ConfigHelper.java index cb4a550f..dd20112c 100644 --- a/src/se/leap/leapclient/ConfigHelper.java +++ b/src/se/leap/leapclient/ConfigHelper.java @@ -207,6 +207,26 @@ public class ConfigHelper { return input_stream; } + /** + * 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 diff --git a/src/se/leap/leapclient/LeapSRPSession.java b/src/se/leap/leapclient/LeapSRPSession.java index beb286da..d21ccffe 100644 --- a/src/se/leap/leapclient/LeapSRPSession.java +++ b/src/se/leap/leapclient/LeapSRPSession.java @@ -4,9 +4,9 @@ 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.Util; import org.jboss.security.srp.SRPParameters; /** @@ -30,6 +30,7 @@ public class LeapSRPSession { 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 */ @@ -57,20 +58,20 @@ public class LeapSRPSession { */ public LeapSRPSession(String username, String password, SRPParameters params, byte[] abytes) { - try { - // Initialize the secure random number and message digests - Util.init(); - } - catch(NoSuchAlgorithmException e) { - } - this.params = params; this.g = new BigInteger(1, params.g); - N_bytes = Util.trim(params.N); + 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? @@ -105,15 +106,15 @@ public class LeapSRPSession { byte[] colon = {}; String encoding = "ISO-8859-1"; try { - user = Util.trim(username.getBytes(encoding)); - colon = Util.trim(":".getBytes(encoding)); - password_bytes = Util.trim(password.getBytes(encoding)); + 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 = Util.trim(username.getBytes()); - colon = Util.trim(":".getBytes()); - password_bytes = Util.trim(password.getBytes()); + user = ConfigHelper.trim(username.getBytes()); + colon = ConfigHelper.trim(":".getBytes()); + password_bytes = ConfigHelper.trim(password.getBytes()); } // Build the hash @@ -152,7 +153,7 @@ public class LeapSRPSession { { //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 Util.trim(xor_digest); + return ConfigHelper.trim(xor_digest); } /** @@ -166,11 +167,11 @@ public class LeapSRPSession { if( a == null ) { BigInteger one = BigInteger.ONE; do { - a = new BigInteger(A_LEN, Util.getPRNG()); + a = new BigInteger(A_LEN, pseudoRng); } while(a.compareTo(one) <= 0); } A = g.modPow(a, N); - Abytes = Util.trim(A.toByteArray()); + Abytes = ConfigHelper.trim(A.toByteArray()); } return Abytes; } @@ -186,7 +187,7 @@ public class LeapSRPSession { */ public byte[] response(byte[] salt_bytes, byte[] Bbytes) throws NoSuchAlgorithmException { // Calculate x = H(s | H(U | ':' | password)) - byte[] xb = calculatePasswordHash(username, password, Util.trim(salt_bytes)); + byte[] xb = calculatePasswordHash(username, password, ConfigHelper.trim(salt_bytes)); this.x = new BigInteger(1, xb); // Calculate v = kg^x mod N @@ -204,36 +205,36 @@ public class LeapSRPSession { clientHash.update(xor_digest); // clientHash = H(N) xor H(g) | H(U) - byte[] username_digest = newDigest().digest(Util.trim(username.getBytes())); - username_digest = Util.trim(username_digest); + 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(Util.trim(salt_bytes)); + clientHash.update(ConfigHelper.trim(salt_bytes)); K = null; // clientHash = H(N) xor H(g) | H(U) | A - byte[] Abytes = Util.trim(A.toByteArray()); + byte[] Abytes = ConfigHelper.trim(A.toByteArray()); clientHash.update(Abytes); // clientHash = H(N) xor H(g) | H(U) | s | A | B - Bbytes = Util.trim(Bbytes); + Bbytes = ConfigHelper.trim(Bbytes); clientHash.update(Bbytes); // Calculate S = (B - kg^x) ^ (a + u * x) % N BigInteger S = calculateS(Bbytes); - byte[] S_bytes = Util.trim(S.toByteArray()); + byte[] S_bytes = ConfigHelper.trim(S.toByteArray()); // K = SessionHash(S) String hash_algorithm = params.hashAlgorithm; MessageDigest sessionDigest = MessageDigest.getInstance(hash_algorithm); - K = Util.trim(sessionDigest.digest(S_bytes)); + K = ConfigHelper.trim(sessionDigest.digest(S_bytes)); // clientHash = H(N) xor H(g) | H(U) | A | B | K clientHash.update(K); - byte[] M1 = Util.trim(clientHash.digest()); + byte[] M1 = ConfigHelper.trim(clientHash.digest()); // serverHash = Astr + M + K serverHash.update(Abytes); @@ -249,8 +250,8 @@ public class LeapSRPSession { * @return the parameter S */ private BigInteger calculateS(byte[] Bbytes) { - byte[] Abytes = Util.trim(A.toByteArray()); - Bbytes = Util.trim(Bbytes); + byte[] Abytes = ConfigHelper.trim(A.toByteArray()); + Bbytes = ConfigHelper.trim(Bbytes); byte[] u_bytes = getU(Abytes, Bbytes); BigInteger B = new BigInteger(1, Bbytes); @@ -270,10 +271,10 @@ public class LeapSRPSession { */ public byte[] getU(byte[] Abytes, byte[] Bbytes) { MessageDigest u_digest = newDigest(); - u_digest.update(Util.trim(Abytes)); - u_digest.update(Util.trim(Bbytes)); + u_digest.update(ConfigHelper.trim(Abytes)); + u_digest.update(ConfigHelper.trim(Bbytes)); byte[] u_digest_bytes = u_digest.digest(); - return Util.trim(new BigInteger(1, u_digest_bytes).toByteArray()); + return ConfigHelper.trim(new BigInteger(1, u_digest_bytes).toByteArray()); } /** @@ -283,8 +284,8 @@ public class LeapSRPSession { public boolean verify(byte[] M2) { // M2 = H(A | M1 | K) - M2 = Util.trim(M2); - byte[] myM2 = Util.trim(serverHash.digest()); + M2 = ConfigHelper.trim(M2); + byte[] myM2 = ConfigHelper.trim(serverHash.digest()); boolean valid = Arrays.equals(M2, myM2); return valid; } diff --git a/src/se/leap/leapclient/ProviderAPI.java b/src/se/leap/leapclient/ProviderAPI.java index 4dfe200a..00d7d820 100644 --- a/src/se/leap/leapclient/ProviderAPI.java +++ b/src/se/leap/leapclient/ProviderAPI.java @@ -41,7 +41,6 @@ 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.Util; import org.jboss.security.srp.SRPParameters; import org.json.JSONException; import org.json.JSONObject; @@ -214,7 +213,7 @@ public class ProviderAPI extends IntentService { * @throws JSONException */ 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, Util.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(put); JSONObject session_idAndM2 = new JSONObject(); @@ -223,7 +222,7 @@ public class ProviderAPI extends IntentService { 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, Util.trim(M2_not_trimmed)); + session_idAndM2.put(ConfigHelper.M2_KEY, ConfigHelper.trim(M2_not_trimmed)); } return session_idAndM2; } -- cgit v1.2.3 From 9a9823f7e5bf0e46e360ba327ac6514ecd4bb320 Mon Sep 17 00:00:00 2001 From: Sean Leonard Date: Sun, 9 Jun 2013 02:08:52 -0600 Subject: Introducing the EIP class! Parses eip-service.json for OpenVPN gateways and builds VpnProfiles out of them --- src/se/leap/leapclient/Dashboard.java | 2 + src/se/leap/leapclient/EIP.java | 294 ++++++++++++++++++++++++++++++++++ 2 files changed, 296 insertions(+) create mode 100644 src/se/leap/leapclient/EIP.java (limited to 'src/se/leap/leapclient') diff --git a/src/se/leap/leapclient/Dashboard.java b/src/se/leap/leapclient/Dashboard.java index dd8ee335..19c635a3 100644 --- a/src/se/leap/leapclient/Dashboard.java +++ b/src/se/leap/leapclient/Dashboard.java @@ -69,6 +69,8 @@ public class Dashboard extends Activity implements LogInDialog.LogInDialogInterf if ( resultCode == RESULT_OK ){ // Configuration done, get our preferences again preferences = getSharedPreferences(ConfigHelper.PREFERENCES_KEY,MODE_PRIVATE); + // Update eip-service local parsing + startService( new Intent(EIP.ACTION_UPDATE_EIP_SERVICE) ); buildDashboard(); } else { diff --git a/src/se/leap/leapclient/EIP.java b/src/se/leap/leapclient/EIP.java new file mode 100644 index 00000000..f86dd083 --- /dev/null +++ b/src/se/leap/leapclient/EIP.java @@ -0,0 +1,294 @@ +package se.leap.leapclient; + +import java.util.Collection; +import java.util.HashMap; +import java.util.Iterator; +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.ProfileManager; +import se.leap.openvpn.VpnProfile; +import android.app.IntentService; +import android.content.Context; +import android.content.Intent; +import android.util.Log; + +/** + * @author Sean Leonard + * + */ +public final class EIP extends IntentService { + + public final static String ACTION_UPDATE_EIP_SERVICE = "se.leap.leapclient.UPDATE_EIP_SERVICE"; + + private static Context context; + + // Represents our Provider's eip-service.json + private static JSONObject eipDefinition = null; + + + public EIP(){ + super("LEAPEIP"); + } + + @Override + public void onCreate() { + super.onCreate(); + + context = getApplicationContext(); + + // Inflate our eip-service.json data + try { + eipDefinition = ConfigHelper.getJsonFromSharedPref(ConfigHelper.EIP_SERVICE_KEY); + } catch (JSONException e) { + // TODO Auto-generated catch block + e.printStackTrace(); + } + } + + @Override + protected void onHandleIntent(Intent intent) { + // Get our action from the Intent + String action = intent.getAction(); + + if ( action == ACTION_UPDATE_EIP_SERVICE ) + this.updateEIPService(); + } + + private void updateEIPService() { + // TODO this will also fetch new eip-service.json + try { + eipDefinition = ConfigHelper.getJsonFromSharedPref(ConfigHelper.EIP_SERVICE_KEY); + } catch (JSONException e) { + // TODO Auto-generated catch block + e.printStackTrace(); + } + updateGateways(); + } + + private void updateGateways(){ + JSONArray gatewaysDefined = null; + + // Get our list of gateways + try { + gatewaysDefined = eipDefinition.getJSONArray("gateways"); + } catch (JSONException e1) { + // TODO Auto-generated catch block + e1.printStackTrace(); + } + + // Walk the list of gateways and inflate them to VPNProfiles + 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") ){ + // We have an openvpn gateway! + // Now build VPNProfiles and save their UUIDs + // TODO create multiple profiles for each gateway to allow trying e.g. different ports when connections don't complete + new OVPNGateway(gw); + } + } catch (JSONException e) { + // TODO Auto-generated catch block + e.printStackTrace(); + } + } + } + + private class OVPNGateway { + + // Log tag + private String TAG = "OVPNGateway"; + + // The actual VPN Profile object + private VpnProfile mVpnProfile; + // Our gateway definition from eip-service.json + private JSONObject gateway; + // This holds our OpenVPN options for creating the VPNProfile + // Options get put here in the form that se.leap.openvpn.ConfigParser wants TODO will be gone w/ rewrite + private HashMap>> options = new HashMap>>(); + + + // Constructor to create a gateway by definition + protected OVPNGateway(JSONObject gw){ + // TODO We're going to build 1 profile per gateway, but eventually several + + gateway = gw; + + // Delete VpnProfile for host, if there already is one + // FIXME There is a better way to check settings and update them, instead of destroy/rebuild + // Also, this allows one gateway per hostname entry, so that had better be true from the server! + // TODO Will we define multiple gateways per host, for variable options? or change how .openvpn.VpnProfile works? + ProfileManager vpl = ProfileManager.getInstance(context); + Collection profiles = vpl.getProfiles(); + for (VpnProfile p : profiles){ + try { + if ( p.mName.contains( gateway.getString("host") ) ) + vpl.removeProfile(context, p); + } catch (JSONException e) { + // TODO Auto-generated catch block + e.printStackTrace(); + } + } + + // Create options HashMap for se.leap.openvpn.ConfigParser + this.parseOptions(); + // Now create the VPNProfile + this.createVPNProfile(); + // Now let's save it in the .openvpn package way + + setUniqueProfileName(vpl); + vpl.addProfile(mVpnProfile); + vpl.saveProfile(context, mVpnProfile); + vpl.saveProfileList(context); + } + + private void setUniqueProfileName(ProfileManager vpl) { + int i=0; + + String newname; + try { + newname = gateway.getString("host"); + while(vpl.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 whole thing will get rewritten when we modify ConfigParser + // in fact, don't even bother looking, except to debug + private void parseOptions(){ + // TODO we will want to rewrite se.leap.openvpn.ConfigParser soon to be targeted at our use + + // 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"; + + // FIXME Our gateway definition has keys that are not OpenVPN options... + // We need a hard spec for the eip-service.json and better handling in this class + // Then we can stop dumping all the "capabilities" key:values into our options for parsing + + // Put our common options in + // FIXME quite ugly. We don't need the nested vectors, as we're not byte-reading file input, but we haven't rewritten the parser, yet + + 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(); + } + + // Now our gateway-specific options + // to hold 'em the way they're wanted for parsing + + // remote:ip_address + try { + arg.add("remote"); + arg.add(gateway.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(); + + // proto:udp||tcp + JSONArray protocolsJSON = null; + arg.add("proto"); + try { + protocolsJSON = gateway.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(); + + + // Now ports...picking one 'cause i say so'... TODO we should have multiple profiles?... + String port = null; + arg.add("port"); + try { + port = gateway.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(); + } + + protected void createVPNProfile(){ + // TODO take data from eip-service.json for openvpn gateway definitions and create VPNProfile for each + try { + ConfigParser cp = new ConfigParser(); + cp.setDefinition(options); + VpnProfile vp = cp.convertProfile(); + mVpnProfile = vp; + Log.v(TAG,"Created VPNProfile"); + } catch (ConfigParseError e) { + // FIXME Being here is bad because we didn't get a VpnProfile! + Log.v(TAG,"Error createing VPNProfile"); + e.printStackTrace(); + } + } + } + +} -- cgit v1.2.3 From 33338d43e0e83329a7c46807e096b8148e19aff7 Mon Sep 17 00:00:00 2001 From: Sean Leonard Date: Sun, 9 Jun 2013 04:09:03 -0600 Subject: Quite basic staring and stopping of VPN --- src/se/leap/leapclient/ConfigHelper.java | 1 + src/se/leap/leapclient/Dashboard.java | 44 ++++++++++++++---------- src/se/leap/leapclient/EIP.java | 58 ++++++++++++++++++++++++++++++++ src/se/leap/leapclient/Provider.java | 1 + src/se/leap/leapclient/ProviderAPI.java | 14 ++++++-- 5 files changed, 98 insertions(+), 20 deletions(-) (limited to 'src/se/leap/leapclient') diff --git a/src/se/leap/leapclient/ConfigHelper.java b/src/se/leap/leapclient/ConfigHelper.java index dd20112c..1c2a482a 100644 --- a/src/se/leap/leapclient/ConfigHelper.java +++ b/src/se/leap/leapclient/ConfigHelper.java @@ -53,6 +53,7 @@ public class ConfigHelper { ALLOWED_ANON = "allow_anonymous", MAIN_CERT_KEY = "main_cert", CERT_KEY = "cert", + KEY_KEY = "key", EIP_SERVICE_KEY = "eip", TYPE_OF_CERTIFICATE = "type_of_certificate", ANON_CERTIFICATE = "anon_certificate", diff --git a/src/se/leap/leapclient/Dashboard.java b/src/se/leap/leapclient/Dashboard.java index 19c635a3..31719d90 100644 --- a/src/se/leap/leapclient/Dashboard.java +++ b/src/se/leap/leapclient/Dashboard.java @@ -6,7 +6,6 @@ import org.json.JSONException; import org.json.JSONObject; import se.leap.leapclient.ProviderAPIResultReceiver.Receiver; -import se.leap.leapclient.R; import se.leap.openvpn.AboutFragment; import se.leap.openvpn.MainActivity; import android.app.Activity; @@ -26,6 +25,7 @@ import android.view.View; import android.view.ViewGroup; import android.view.ViewStub; import android.widget.CompoundButton; +import android.widget.RelativeLayout; import android.widget.Switch; import android.widget.TextView; import android.widget.Toast; @@ -100,26 +100,32 @@ public class Dashboard extends Activity implements LogInDialog.LogInDialogInterf private void buildDashboard() { // Get our provider - provider = Provider.getInstance(); - provider.init( this ); - - // Set provider name in textview - providerNameTV = (TextView) findViewById(R.id.providerName); - providerNameTV.setText(provider.getName()); - providerNameTV.setTextSize(28); // TODO maybe to some calculating, or a marquee? - - // TODO Inflate layout fragments for provider's services - if ( provider.hasEIP() ) - serviceItemEIP(); + provider = Provider.getInstance(); + provider.init( this ); + + // Set provider name in textview + providerNameTV = (TextView) findViewById(R.id.providerName); + providerNameTV.setText(provider.getName()); + providerNameTV.setTextSize(28); // TODO maybe to some calculating, or a marquee? + + if ( provider.hasEIP() /*&& provider.getEIP() != null*/){ + // FIXME let's schedule this, so we're not doing it when we load the app + startService( new Intent(EIP.ACTION_UPDATE_EIP_SERVICE) ); + serviceItemEIP(); + } } private void serviceItemEIP() { - // FIXME Provider service (eip/openvpn) ((ViewStub) findViewById(R.id.eipOverviewStub)).inflate(); // Set our EIP type title eipTypeTV = (TextView) findViewById(R.id.eipType); eipTypeTV.setText(provider.getEIPType()); + // Show our EIP detail + View eipDetail = ((RelativeLayout) findViewById(R.id.eipDetail)); + View eipSettings = findViewById(R.id.eipSettings); + eipSettings.setVisibility(View.GONE); // FIXME too! + eipDetail.setVisibility(View.VISIBLE); // TODO Bind our switch to run our EIP // What happens when our VPN stops running? does it call the listener? @@ -127,12 +133,14 @@ public class Dashboard extends Activity implements LogInDialog.LogInDialogInterf eipSwitch.setOnCheckedChangeListener(new CompoundButton.OnCheckedChangeListener() { @Override public void onCheckedChanged(CompoundButton buttonView, boolean isChecked) { - if ( isChecked ){ - //TODO startVPN(); - } else { - //TODO stopVPN(); + Intent vpnIntent; + if (isChecked){ + vpnIntent = new Intent(EIP.ACTION_START_EIP); + } else { + vpnIntent = new Intent(EIP.ACTION_STOP_EIP); + } + startService(vpnIntent); } - } }); //TODO write our info into the view fragment that will expand with details and a settings button diff --git a/src/se/leap/leapclient/EIP.java b/src/se/leap/leapclient/EIP.java index f86dd083..21cbdfd5 100644 --- a/src/se/leap/leapclient/EIP.java +++ b/src/se/leap/leapclient/EIP.java @@ -3,6 +3,7 @@ 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; @@ -11,6 +12,8 @@ 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.ProfileManager; import se.leap.openvpn.VpnProfile; import android.app.IntentService; @@ -24,6 +27,8 @@ import android.util.Log; */ 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"; private static Context context; @@ -31,6 +36,8 @@ public final class EIP extends IntentService { // Represents our Provider's eip-service.json private static JSONObject eipDefinition = null; + // Our active gateway + private static OVPNGateway activeGateway = null; public EIP(){ super("LEAPEIP"); @@ -58,6 +65,26 @@ public final class EIP extends IntentService { if ( action == ACTION_UPDATE_EIP_SERVICE ) this.updateEIPService(); + else if ( action == ACTION_START_EIP ) + this.startEIP(); + else if ( action == ACTION_STOP_EIP ) + this.stopEIP(); + } + + 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() ); + startActivity(intent); + } + + private void stopEIP() { + OpenVpnManagementThread.stopOpenVPN(); } private void updateEIPService() { @@ -71,6 +98,11 @@ public final class EIP extends IntentService { updateGateways(); } + private OVPNGateway selectGateway() { + // TODO Logic, yay! + return new OVPNGateway("first"); + } + private void updateGateways(){ JSONArray gatewaysDefined = null; @@ -122,6 +154,32 @@ public final class EIP extends IntentService { private HashMap>> options = new HashMap>>(); + // Constructor to load a gateway by name + private OVPNGateway(String name){ + ProfileManager vpl = ProfileManager.getInstance(context); + + try { + + // FIXME ha, this got funny..it will get smart once i'm further... + if ( name == "first" ) { + name = vpl.getProfiles().iterator().next().mName; + } + + mVpnProfile = vpl.getProfileByName(name); + + } catch (NoSuchElementException e) { + + // The gateway we were looking for is not in ProfileList! + updateEIPService(); + + // TODO prompt user to fix config error + + } catch (Exception e) { + // TODO Auto-generated catch block + e.printStackTrace(); + } + } + // Constructor to create a gateway by definition protected OVPNGateway(JSONObject gw){ // TODO We're going to build 1 profile per gateway, but eventually several diff --git a/src/se/leap/leapclient/Provider.java b/src/se/leap/leapclient/Provider.java index 50bd2925..4a09bf7a 100644 --- a/src/se/leap/leapclient/Provider.java +++ b/src/se/leap/leapclient/Provider.java @@ -124,6 +124,7 @@ public final class Provider implements Serializable { } for (int i=0;i Date: Sun, 9 Jun 2013 04:31:27 -0600 Subject: Better control and UI feedback for VPN --- src/se/leap/leapclient/ConfigHelper.java | 4 +- src/se/leap/leapclient/Dashboard.java | 138 +++++++++++++++++++++++++++++- src/se/leap/leapclient/EIP.java | 140 ++++++++++++++++++++++++++++++- 3 files changed, 276 insertions(+), 6 deletions(-) (limited to 'src/se/leap/leapclient') diff --git a/src/se/leap/leapclient/ConfigHelper.java b/src/se/leap/leapclient/ConfigHelper.java index 1c2a482a..cab5fdee 100644 --- a/src/se/leap/leapclient/ConfigHelper.java +++ b/src/se/leap/leapclient/ConfigHelper.java @@ -73,7 +73,9 @@ public class ConfigHelper { PASSWORD_KEY = "password", ALLOW_REGISTRATION_KEY = "allow_registration", EIP_SERVICE_API_PATH = "config/eip-service.json", - ERRORS_KEY = "errors" + ERRORS_KEY = "errors", + RECEIVER_TAG = "receiverTag", + REQUEST_TAG = "requestTag"; ; final public static String NG_1024 = diff --git a/src/se/leap/leapclient/Dashboard.java b/src/se/leap/leapclient/Dashboard.java index 31719d90..f10966b2 100644 --- a/src/se/leap/leapclient/Dashboard.java +++ b/src/se/leap/leapclient/Dashboard.java @@ -8,6 +8,8 @@ import org.json.JSONObject; import se.leap.leapclient.ProviderAPIResultReceiver.Receiver; import se.leap.openvpn.AboutFragment; import se.leap.openvpn.MainActivity; +import se.leap.openvpn.OpenVPN; +import se.leap.openvpn.OpenVPN.StateListener; import android.app.Activity; import android.app.AlertDialog; import android.app.DialogFragment; @@ -19,6 +21,7 @@ import android.content.Intent; import android.content.SharedPreferences; import android.os.Bundle; import android.os.Handler; +import android.os.ResultReceiver; import android.view.Menu; import android.view.MenuItem; import android.view.View; @@ -30,7 +33,7 @@ import android.widget.Switch; import android.widget.TextView; import android.widget.Toast; -public class Dashboard extends Activity implements LogInDialog.LogInDialogInterface, Receiver { +public class Dashboard extends Activity implements LogInDialog.LogInDialogInterface,Receiver,StateListener { protected static final int CONFIGURE_LEAP = 0; @@ -40,8 +43,14 @@ public class Dashboard extends Activity implements LogInDialog.LogInDialogInterf private TextView providerNameTV; private TextView eipTypeTV; + private Switch eipSwitch; + private View eipDetail; + private TextView eipStatus; + + private boolean mEipWait = false; public ProviderAPIResultReceiver providerAPI_result_receiver; + private EIPReceiver mEIPReceiver; @Override protected void onCreate(Bundle savedInstanceState) { @@ -62,6 +71,24 @@ public class Dashboard extends Activity implements LogInDialog.LogInDialogInterf else startActivityForResult(new Intent(this,ConfigurationWizard.class),CONFIGURE_LEAP); } + + @Override + protected void onStop() { + super.onStop(); + // TODO null provider should only happen before ConfigurationWizard has run, once...better way? + if (provider != null) + if (provider.hasEIP() && provider.getEIPType() == "OpenVPN") + OpenVPN.removeStateListener(this); + } + + @Override + protected void onResume() { + super.onResume(); + // TODO null provider should only happen before ConfigurationWizard has run, once...better way? + if (provider != null) + if (provider.hasEIP() && provider.getEIPType() == "OpenVPN") + OpenVPN.addStateListener(this); + } @Override protected void onActivityResult(int requestCode, int resultCode, Intent data){ @@ -111,36 +138,55 @@ public class Dashboard extends Activity implements LogInDialog.LogInDialogInterf if ( provider.hasEIP() /*&& provider.getEIP() != null*/){ // FIXME let's schedule this, so we're not doing it when we load the app startService( new Intent(EIP.ACTION_UPDATE_EIP_SERVICE) ); + if (provider.getEIPType() == "OpenVPN") + OpenVPN.addStateListener(this); serviceItemEIP(); } } private void serviceItemEIP() { + mEIPReceiver = new EIPReceiver(new Handler()); + mEIPReceiver.setReceiver(this); + + Intent intent = new Intent(this,EIP.class); + intent.setAction(EIP.ACTION_IS_EIP_RUNNING); + intent.putExtra(ConfigHelper.RECEIVER_TAG, mEIPReceiver); + startService(intent); + ((ViewStub) findViewById(R.id.eipOverviewStub)).inflate(); // Set our EIP type title eipTypeTV = (TextView) findViewById(R.id.eipType); eipTypeTV.setText(provider.getEIPType()); + // Show our EIP detail - View eipDetail = ((RelativeLayout) findViewById(R.id.eipDetail)); + eipDetail = ((RelativeLayout) findViewById(R.id.eipDetail)); View eipSettings = findViewById(R.id.eipSettings); eipSettings.setVisibility(View.GONE); // FIXME too! eipDetail.setVisibility(View.VISIBLE); + eipStatus = (TextView) findViewById(R.id.eipStatus); // TODO Bind our switch to run our EIP // What happens when our VPN stops running? does it call the listener? - Switch eipSwitch = (Switch) findViewById(R.id.eipSwitch); + eipSwitch = (Switch) findViewById(R.id.eipSwitch); eipSwitch.setOnCheckedChangeListener(new CompoundButton.OnCheckedChangeListener() { @Override public void onCheckedChanged(CompoundButton buttonView, boolean isChecked) { + if (!mEipWait){ + // We're gonna have to have some patience! + buttonView.setClickable(false); + mEipWait = true; + Intent vpnIntent; if (isChecked){ vpnIntent = new Intent(EIP.ACTION_START_EIP); } else { vpnIntent = new Intent(EIP.ACTION_STOP_EIP); } + vpnIntent.putExtra(ConfigHelper.RECEIVER_TAG, mEIPReceiver); startService(vpnIntent); } + } }); //TODO write our info into the view fragment that will expand with details and a settings button @@ -333,4 +379,90 @@ public class Dashboard extends Activity implements LogInDialog.LogInDialogInterf public static Context getAppContext() { return app; } + + @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(?) ) + // TODO follow-back calls to updateState to find set variable values passed as first param & third param (find those strings...are they all R.string.STATE_* ?) + runOnUiThread(new Runnable() { + + @Override + public void run() { + if (eipStatus != null) { + String prefix = getString(localizedResId) + ":"; + if (state.equals("BYTECOUNT") || state.equals("NOPROCESS")) + prefix = ""; + eipStatus.setText(prefix + logmessage); + } + } + }); + } + + protected class EIPReceiver extends ResultReceiver { + + Dashboard mDashboard; + + protected EIPReceiver(Handler handler){ + super(handler); + } + + public void setReceiver(Dashboard receiver) { + mDashboard = receiver; + } + + @Override + protected void onReceiveResult(int resultCode, Bundle resultData) { + super.onReceiveResult(resultCode, resultData); + + // What were we asking for, again? + String request = resultData.getString(ConfigHelper.REQUEST_TAG); + // Should the EIP switch be on? + mEipWait = true; + boolean checked = false; + + if (request == EIP.ACTION_IS_EIP_RUNNING) { + switch (resultCode){ + case RESULT_OK: + checked = true; + break; + case RESULT_CANCELED: + checked = false; + break; + } + } else if (request == EIP.ACTION_START_EIP) { + switch (resultCode){ + case RESULT_OK: + checked = true; + break; + case RESULT_CANCELED: + checked = false; + break; + } + } else if (request == EIP.ACTION_STOP_EIP) { + switch (resultCode){ + case RESULT_OK: + checked = false; + break; + case RESULT_CANCELED: + checked = true; + break; + } + } else if (request == EIP.EIP_NOTIFICATION) { + switch (resultCode){ + case RESULT_OK: + checked = true; + break; + case RESULT_CANCELED: + checked = false; + break; + } + } + + Switch eipS = ((Switch) mDashboard.findViewById(R.id.eipSwitch)); + eipS.setChecked(checked); + eipS.setClickable(true); + mEipWait = false; + } + } } diff --git a/src/se/leap/leapclient/EIP.java b/src/se/leap/leapclient/EIP.java index 21cbdfd5..867805bd 100644 --- a/src/se/leap/leapclient/EIP.java +++ b/src/se/leap/leapclient/EIP.java @@ -13,12 +13,21 @@ 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.content.SharedPreferences; +import android.os.Bundle; +import android.os.IBinder; +import android.os.ResultReceiver; import android.util.Log; /** @@ -31,7 +40,17 @@ public final class EIP extends IntentService { 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"; + private static Context context; + private static ResultReceiver mReceiver; + // Binder to OpenVpnService for comm ops + private static OpenVpnService mVpnService; + private static boolean mBound = false; + // Used to store actions to "resume" onServiceConnection + private static String mPending = null; // Represents our Provider's eip-service.json private static JSONObject eipDefinition = null; @@ -56,13 +75,27 @@ public final class EIP extends IntentService { // 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) { // Get our action from the Intent String action = intent.getAction(); + // Get the ResultReceiver, if any + mReceiver = intent.getParcelableExtra(ConfigHelper.RECEIVER_TAG); + if ( action == ACTION_IS_EIP_RUNNING ) + this.isRunning(); if ( action == ACTION_UPDATE_EIP_SERVICE ) this.updateEIPService(); else if ( action == ACTION_START_EIP ) @@ -70,6 +103,70 @@ public final class EIP extends IntentService { else if ( action == ACTION_STOP_EIP ) this.stopEIP(); } + + 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(ConfigHelper.REQUEST_TAG, EIP_NOTIFICATION); + mReceiver.send(resultCode, resultData); + + mPending = null; + } + } + + @Override + public void onServiceDisconnected(ComponentName name) { + // XXX tell mReceiver!! + mBound = false; + + if (mReceiver != null){ + Bundle resultData = new Bundle(); + resultData.putString(ConfigHelper.REQUEST_TAG, EIP_NOTIFICATION); + mReceiver.send(Activity.RESULT_CANCELED, resultData); + } + } + + }; + + private void isRunning() { + // TODO I don't like that whatever requested this never receives a response + // if OpenVpnService has not been START_SERVICE, though the one place this is used that's okay + if (mBound) { + if (mReceiver != null){ + Bundle resultData = new Bundle(); + resultData.putString(ConfigHelper.REQUEST_TAG, ACTION_IS_EIP_RUNNING); + int resultCode = (mVpnService.isRunning()) ? Activity.RESULT_OK : Activity.RESULT_CANCELED; + mReceiver.send(resultCode, resultData); + } + } else { + mPending = ACTION_IS_EIP_RUNNING; + this.retreiveVpnService(); + } + } private void startEIP() { if (activeGateway==null) @@ -80,11 +177,50 @@ 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); startActivity(intent); + // Let's give it 2s to get rolling... TODO there really should be a better way to do this, or it's not needed. + // Read more code in .openvpn package + try { + Thread.sleep(1000); + } catch (InterruptedException e) { + // TODO Auto-generated catch block + e.printStackTrace(); + } + // Bind OpenVpnService for comm ops + if (!mBound){ + mPending = ACTION_START_EIP; + this.retreiveVpnService(); + } else { + if (mReceiver != null) { + Bundle resultData = new Bundle(); + resultData.putString(ConfigHelper.REQUEST_TAG, ACTION_START_EIP); + mReceiver.send(Activity.RESULT_OK, resultData); + } + } } private void stopEIP() { - OpenVpnManagementThread.stopOpenVPN(); + if (mBound){ + mVpnService.onRevoke(); + + /*if (mReceiver != null){ + Bundle resultData = new Bundle(); + resultData.putString(ConfigHelper.REQUEST_TAG, ACTION_STOP_EIP); + mReceiver.send(Activity.RESULT_OK, resultData); + }*/ + } else { + // TODO If OpenVpnService isn't bound, does that really always mean it's not running? + // If it's not running, bindService doesn't work w/o START_SERVICE action, so... + /*mPending = ACTION_STOP_EIP; + this.retreiveVpnService();*/ + } + // Remove this if above comes back + if (mReceiver != null){ + Bundle resultData = new Bundle(); + resultData.putString(ConfigHelper.REQUEST_TAG, ACTION_STOP_EIP); + mReceiver.send(Activity.RESULT_OK, resultData); + } } private void updateEIPService() { -- cgit v1.2.3 From 276b8f7dbc7763e284f246a1c538bd06dd8be756 Mon Sep 17 00:00:00 2001 From: Sean Leonard Date: Sun, 9 Jun 2013 04:36:08 -0600 Subject: Bring up VPN connection log on status line click. Also show it on click of "Configure" button on system notification popup. Also allow toggling of status line. --- src/se/leap/leapclient/Dashboard.java | 23 +++++++++++++++++------ 1 file changed, 17 insertions(+), 6 deletions(-) (limited to 'src/se/leap/leapclient') diff --git a/src/se/leap/leapclient/Dashboard.java b/src/se/leap/leapclient/Dashboard.java index f10966b2..965e8692 100644 --- a/src/se/leap/leapclient/Dashboard.java +++ b/src/se/leap/leapclient/Dashboard.java @@ -7,6 +7,7 @@ import org.json.JSONObject; import se.leap.leapclient.ProviderAPIResultReceiver.Receiver; import se.leap.openvpn.AboutFragment; +import se.leap.openvpn.LogWindow; import se.leap.openvpn.MainActivity; import se.leap.openvpn.OpenVPN; import se.leap.openvpn.OpenVPN.StateListener; @@ -188,13 +189,28 @@ public class Dashboard extends Activity implements LogInDialog.LogInDialogInterf } } }); - + //TODO write our info into the view fragment that will expand with details and a settings button // TODO set eip overview subview // TODO make eip type clickable, show subview // TODO attach vpn status feedback to eip overview view // TODO attach settings button to something } + + public void toggleEipOverview(View view) { + if (eipDetail.isShown()) + eipDetail.setVisibility(View.GONE); + else + eipDetail.setVisibility(View.VISIBLE); + } + + // FIXME!! I will move to EIPSettingsFragment and begone! + // Also means change onClick property for status line + public void showEIPLog(View view){ + Intent intent = new Intent(getBaseContext(),LogWindow.class); + intent.addFlags(Intent.FLAG_ACTIVITY_REORDER_TO_FRONT); + startActivity(intent); + } @Override public boolean onPrepareOptionsMenu(Menu menu) { @@ -253,11 +269,6 @@ public class Dashboard extends Activity implements LogInDialog.LogInDialogInterf } } - - @SuppressWarnings("unused") - private void toggleOverview() { - // TODO Expand the one line overview item to show some details - } @Override public void authenticate(String username, String password) { -- cgit v1.2.3 From 98b27656cdb2e76bf966baad0dd8766fd1ebbbdd Mon Sep 17 00:00:00 2001 From: Sean Leonard Date: Tue, 18 Jun 2013 20:22:40 -0600 Subject: Remove superfluous comments Unused import removal --- src/se/leap/leapclient/Dashboard.java | 22 +--------------- src/se/leap/leapclient/EIP.java | 47 +---------------------------------- 2 files changed, 2 insertions(+), 67 deletions(-) (limited to 'src/se/leap/leapclient') diff --git a/src/se/leap/leapclient/Dashboard.java b/src/se/leap/leapclient/Dashboard.java index 965e8692..d88d09e9 100644 --- a/src/se/leap/leapclient/Dashboard.java +++ b/src/se/leap/leapclient/Dashboard.java @@ -65,7 +65,6 @@ public class Dashboard extends Activity implements LogInDialog.LogInDialogInterf if(ConfigHelper.shared_preferences == null) ConfigHelper.setSharedPreferences(preferences); - // Check if we have preferences, run configuration wizard if not // TODO We should do a better check for config that this! if (preferences.contains("provider") && preferences.getString(ConfigHelper.PROVIDER_KEY, null) != null) buildDashboard(); @@ -95,14 +94,11 @@ public class Dashboard extends Activity implements LogInDialog.LogInDialogInterf protected void onActivityResult(int requestCode, int resultCode, Intent data){ if ( requestCode == CONFIGURE_LEAP ) { if ( resultCode == RESULT_OK ){ - // Configuration done, get our preferences again preferences = getSharedPreferences(ConfigHelper.PREFERENCES_KEY,MODE_PRIVATE); - // Update eip-service local parsing startService( new Intent(EIP.ACTION_UPDATE_EIP_SERVICE) ); buildDashboard(); } else { - // Something went wrong in configuration AlertDialog.Builder alertBuilder = new AlertDialog.Builder(getAppContext()); alertBuilder.setTitle(getResources().getString(R.string.setup_error_title)); alertBuilder @@ -127,16 +123,14 @@ public class Dashboard extends Activity implements LogInDialog.LogInDialogInterf } private void buildDashboard() { - // Get our provider provider = Provider.getInstance(); provider.init( this ); - // Set provider name in textview providerNameTV = (TextView) findViewById(R.id.providerName); providerNameTV.setText(provider.getName()); providerNameTV.setTextSize(28); // TODO maybe to some calculating, or a marquee? - if ( provider.hasEIP() /*&& provider.getEIP() != null*/){ + if ( provider.hasEIP() ){ // FIXME let's schedule this, so we're not doing it when we load the app startService( new Intent(EIP.ACTION_UPDATE_EIP_SERVICE) ); if (provider.getEIPType() == "OpenVPN") @@ -156,25 +150,20 @@ public class Dashboard extends Activity implements LogInDialog.LogInDialogInterf ((ViewStub) findViewById(R.id.eipOverviewStub)).inflate(); - // Set our EIP type title eipTypeTV = (TextView) findViewById(R.id.eipType); eipTypeTV.setText(provider.getEIPType()); - // Show our EIP detail eipDetail = ((RelativeLayout) findViewById(R.id.eipDetail)); View eipSettings = findViewById(R.id.eipSettings); eipSettings.setVisibility(View.GONE); // FIXME too! eipDetail.setVisibility(View.VISIBLE); eipStatus = (TextView) findViewById(R.id.eipStatus); - // TODO Bind our switch to run our EIP - // What happens when our VPN stops running? does it call the listener? eipSwitch = (Switch) findViewById(R.id.eipSwitch); eipSwitch.setOnCheckedChangeListener(new CompoundButton.OnCheckedChangeListener() { @Override public void onCheckedChanged(CompoundButton buttonView, boolean isChecked) { if (!mEipWait){ - // We're gonna have to have some patience! buttonView.setClickable(false); mEipWait = true; @@ -205,7 +194,6 @@ public class Dashboard extends Activity implements LogInDialog.LogInDialogInterf } // FIXME!! I will move to EIPSettingsFragment and begone! - // Also means change onClick property for status line public void showEIPLog(View view){ Intent intent = new Intent(getBaseContext(),LogWindow.class); intent.addFlags(Intent.FLAG_ACTIVITY_REORDER_TO_FRONT); @@ -231,7 +219,6 @@ public class Dashboard extends Activity implements LogInDialog.LogInDialogInterf @Override public boolean onCreateOptionsMenu(Menu menu) { - // Inflate the menu; this adds items to the action bar if it is present. getMenuInflater().inflate(R.menu.client_dashboard, menu); return true; } @@ -239,7 +226,6 @@ public class Dashboard extends Activity implements LogInDialog.LogInDialogInterf @Override public boolean onOptionsItemSelected(MenuItem item){ Intent intent; - // Handle item selection switch (item.getItemId()){ case R.id.about_leap: // TODO move se.leap.openvpn.AboutFragment into our package @@ -248,12 +234,8 @@ public class Dashboard extends Activity implements LogInDialog.LogInDialogInterf trans.replace(R.id.dashboardLayout, aboutFragment); trans.addToBackStack(null); trans.commit(); - - //intent = new Intent(this,AboutFragment.class); - //startActivity(intent); return true; case R.id.legacy_interface: - // TODO call se.leap.openvpn.MainActivity intent = new Intent(this,MainActivity.class); startActivity(intent); return true; @@ -426,9 +408,7 @@ public class Dashboard extends Activity implements LogInDialog.LogInDialogInterf protected void onReceiveResult(int resultCode, Bundle resultData) { super.onReceiveResult(resultCode, resultData); - // What were we asking for, again? String request = resultData.getString(ConfigHelper.REQUEST_TAG); - // Should the EIP switch be on? mEipWait = true; boolean checked = false; diff --git a/src/se/leap/leapclient/EIP.java b/src/se/leap/leapclient/EIP.java index 867805bd..4e23675a 100644 --- a/src/se/leap/leapclient/EIP.java +++ b/src/se/leap/leapclient/EIP.java @@ -24,7 +24,6 @@ import android.content.ComponentName; import android.content.Context; import android.content.Intent; import android.content.ServiceConnection; -import android.content.SharedPreferences; import android.os.Bundle; import android.os.IBinder; import android.os.ResultReceiver; @@ -39,23 +38,18 @@ 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"; private static Context context; private static ResultReceiver mReceiver; - // Binder to OpenVpnService for comm ops private static OpenVpnService mVpnService; private static boolean mBound = false; // Used to store actions to "resume" onServiceConnection private static String mPending = null; - // Represents our Provider's eip-service.json private static JSONObject eipDefinition = null; - // Our active gateway private static OVPNGateway activeGateway = null; public EIP(){ @@ -68,7 +62,6 @@ public final class EIP extends IntentService { context = getApplicationContext(); - // Inflate our eip-service.json data try { eipDefinition = ConfigHelper.getJsonFromSharedPref(ConfigHelper.EIP_SERVICE_KEY); } catch (JSONException e) { @@ -89,9 +82,7 @@ public final class EIP extends IntentService { @Override protected void onHandleIntent(Intent intent) { - // Get our action from the Intent String action = intent.getAction(); - // Get the ResultReceiver, if any mReceiver = intent.getParcelableExtra(ConfigHelper.RECEIVER_TAG); if ( action == ACTION_IS_EIP_RUNNING ) @@ -187,7 +178,6 @@ public final class EIP extends IntentService { // TODO Auto-generated catch block e.printStackTrace(); } - // Bind OpenVpnService for comm ops if (!mBound){ mPending = ACTION_START_EIP; this.retreiveVpnService(); @@ -201,21 +191,8 @@ public final class EIP extends IntentService { } private void stopEIP() { - if (mBound){ + if (mBound) mVpnService.onRevoke(); - - /*if (mReceiver != null){ - Bundle resultData = new Bundle(); - resultData.putString(ConfigHelper.REQUEST_TAG, ACTION_STOP_EIP); - mReceiver.send(Activity.RESULT_OK, resultData); - }*/ - } else { - // TODO If OpenVpnService isn't bound, does that really always mean it's not running? - // If it's not running, bindService doesn't work w/o START_SERVICE action, so... - /*mPending = ACTION_STOP_EIP; - this.retreiveVpnService();*/ - } - // Remove this if above comes back if (mReceiver != null){ Bundle resultData = new Bundle(); resultData.putString(ConfigHelper.REQUEST_TAG, ACTION_STOP_EIP); @@ -242,7 +219,6 @@ public final class EIP extends IntentService { private void updateGateways(){ JSONArray gatewaysDefined = null; - // Get our list of gateways try { gatewaysDefined = eipDefinition.getJSONArray("gateways"); } catch (JSONException e1) { @@ -250,7 +226,6 @@ public final class EIP extends IntentService { e1.printStackTrace(); } - // Walk the list of gateways and inflate them to VPNProfiles for ( int i=0 ; i < gatewaysDefined.length(); i++ ){ JSONObject gw = null; @@ -264,7 +239,6 @@ public final class EIP extends IntentService { try { if ( gw.getJSONObject("capabilities").getJSONArray("transport").toString().contains("openvpn") ){ - // We have an openvpn gateway! // Now build VPNProfiles and save their UUIDs // TODO create multiple profiles for each gateway to allow trying e.g. different ports when connections don't complete new OVPNGateway(gw); @@ -278,14 +252,10 @@ public final class EIP extends IntentService { private class OVPNGateway { - // Log tag private String TAG = "OVPNGateway"; - // The actual VPN Profile object private VpnProfile mVpnProfile; - // Our gateway definition from eip-service.json private JSONObject gateway; - // This holds our OpenVPN options for creating the VPNProfile // Options get put here in the form that se.leap.openvpn.ConfigParser wants TODO will be gone w/ rewrite private HashMap>> options = new HashMap>>(); @@ -304,12 +274,7 @@ public final class EIP extends IntentService { mVpnProfile = vpl.getProfileByName(name); } catch (NoSuchElementException e) { - - // The gateway we were looking for is not in ProfileList! updateEIPService(); - - // TODO prompt user to fix config error - } catch (Exception e) { // TODO Auto-generated catch block e.printStackTrace(); @@ -325,7 +290,6 @@ public final class EIP extends IntentService { // Delete VpnProfile for host, if there already is one // FIXME There is a better way to check settings and update them, instead of destroy/rebuild // Also, this allows one gateway per hostname entry, so that had better be true from the server! - // TODO Will we define multiple gateways per host, for variable options? or change how .openvpn.VpnProfile works? ProfileManager vpl = ProfileManager.getInstance(context); Collection profiles = vpl.getProfiles(); for (VpnProfile p : profiles){ @@ -338,11 +302,8 @@ public final class EIP extends IntentService { } } - // Create options HashMap for se.leap.openvpn.ConfigParser this.parseOptions(); - // Now create the VPNProfile this.createVPNProfile(); - // Now let's save it in the .openvpn package way setUniqueProfileName(vpl); vpl.addProfile(mVpnProfile); @@ -415,10 +376,6 @@ public final class EIP extends IntentService { e.printStackTrace(); } - // Now our gateway-specific options - // to hold 'em the way they're wanted for parsing - - // remote:ip_address try { arg.add("remote"); arg.add(gateway.getString(remote)); @@ -431,7 +388,6 @@ public final class EIP extends IntentService { arg.clear(); args.clear(); - // proto:udp||tcp JSONArray protocolsJSON = null; arg.add("proto"); try { @@ -453,7 +409,6 @@ public final class EIP extends IntentService { args.clear(); - // Now ports...picking one 'cause i say so'... TODO we should have multiple profiles?... String port = null; arg.add("port"); try { -- cgit v1.2.3 From a56ecf1b46a158485aa89d2a8f1f5b1b0d819b39 Mon Sep 17 00:00:00 2001 From: Sean Leonard Date: Tue, 18 Jun 2013 20:32:47 -0600 Subject: Forceful stopping of OpenVPN when trying without bound service --- src/se/leap/leapclient/EIP.java | 4 ++++ 1 file changed, 4 insertions(+) (limited to 'src/se/leap/leapclient') diff --git a/src/se/leap/leapclient/EIP.java b/src/se/leap/leapclient/EIP.java index 4e23675a..5afffd61 100644 --- a/src/se/leap/leapclient/EIP.java +++ b/src/se/leap/leapclient/EIP.java @@ -13,6 +13,7 @@ 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; @@ -193,6 +194,9 @@ public final class EIP extends IntentService { private void stopEIP() { if (mBound) mVpnService.onRevoke(); + else + OpenVpnManagementThread.stopOpenVPN(); + if (mReceiver != null){ Bundle resultData = new Bundle(); resultData.putString(ConfigHelper.REQUEST_TAG, ACTION_STOP_EIP); -- cgit v1.2.3 From 7e98a58eedd638113d447be9c7c2aff8ecfa444e Mon Sep 17 00:00:00 2001 From: Sean Leonard Date: Tue, 18 Jun 2013 20:38:24 -0600 Subject: Remove bad,duplicate code from EIP.startEIP() --- src/se/leap/leapclient/EIP.java | 19 +------------------ 1 file changed, 1 insertion(+), 18 deletions(-) (limited to 'src/se/leap/leapclient') diff --git a/src/se/leap/leapclient/EIP.java b/src/se/leap/leapclient/EIP.java index 5afffd61..3831aaf6 100644 --- a/src/se/leap/leapclient/EIP.java +++ b/src/se/leap/leapclient/EIP.java @@ -171,24 +171,7 @@ public final class EIP extends IntentService { intent.putExtra(LaunchVPN.EXTRA_NAME, activeGateway.mVpnProfile.getName() ); intent.putExtra(ConfigHelper.RECEIVER_TAG, mReceiver); startActivity(intent); - // Let's give it 2s to get rolling... TODO there really should be a better way to do this, or it's not needed. - // Read more code in .openvpn package - try { - Thread.sleep(1000); - } catch (InterruptedException e) { - // TODO Auto-generated catch block - e.printStackTrace(); - } - if (!mBound){ - mPending = ACTION_START_EIP; - this.retreiveVpnService(); - } else { - if (mReceiver != null) { - Bundle resultData = new Bundle(); - resultData.putString(ConfigHelper.REQUEST_TAG, ACTION_START_EIP); - mReceiver.send(Activity.RESULT_OK, resultData); - } - } + mPending = ACTION_START_EIP; } private void stopEIP() { -- cgit v1.2.3 From e8603d83248591a750d632a35dac125ea7749575 Mon Sep 17 00:00:00 2001 From: Sean Leonard Date: Tue, 18 Jun 2013 20:57:46 -0600 Subject: Remove superfluous loading of SharedPreferences --- src/se/leap/leapclient/Dashboard.java | 2 -- 1 file changed, 2 deletions(-) (limited to 'src/se/leap/leapclient') diff --git a/src/se/leap/leapclient/Dashboard.java b/src/se/leap/leapclient/Dashboard.java index d88d09e9..d417bb83 100644 --- a/src/se/leap/leapclient/Dashboard.java +++ b/src/se/leap/leapclient/Dashboard.java @@ -94,9 +94,7 @@ public class Dashboard extends Activity implements LogInDialog.LogInDialogInterf protected void onActivityResult(int requestCode, int resultCode, Intent data){ if ( requestCode == CONFIGURE_LEAP ) { if ( resultCode == RESULT_OK ){ - preferences = getSharedPreferences(ConfigHelper.PREFERENCES_KEY,MODE_PRIVATE); startService( new Intent(EIP.ACTION_UPDATE_EIP_SERVICE) ); - buildDashboard(); } else { AlertDialog.Builder alertBuilder = new AlertDialog.Builder(getAppContext()); -- cgit v1.2.3 From e2ef783caa56d9d0812c24693a69bcbc23edcbfc Mon Sep 17 00:00:00 2001 From: Sean Leonard Date: Tue, 18 Jun 2013 20:58:37 -0600 Subject: Move ConfigurationWizard error result logic to its own method --- src/se/leap/leapclient/Dashboard.java | 46 +++++++++++++++++++---------------- 1 file changed, 25 insertions(+), 21 deletions(-) (limited to 'src/se/leap/leapclient') diff --git a/src/se/leap/leapclient/Dashboard.java b/src/se/leap/leapclient/Dashboard.java index d417bb83..392aba54 100644 --- a/src/se/leap/leapclient/Dashboard.java +++ b/src/se/leap/leapclient/Dashboard.java @@ -96,30 +96,34 @@ public class Dashboard extends Activity implements LogInDialog.LogInDialogInterf if ( resultCode == RESULT_OK ){ startService( new Intent(EIP.ACTION_UPDATE_EIP_SERVICE) ); buildDashboard(); - } else { - 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(ConfigHelper.PREFERENCES_KEY, MODE_PRIVATE).edit(); - prefsEdit.remove(ConfigHelper.PROVIDER_KEY).commit(); - finish(); - } - }); - } + } else + // FIXME Doesn't take partial config into account + configErrorDialog(); } } + 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(ConfigHelper.PREFERENCES_KEY, MODE_PRIVATE).edit(); + prefsEdit.remove(ConfigHelper.PROVIDER_KEY).commit(); + finish(); + } + }); + } + private void buildDashboard() { provider = Provider.getInstance(); provider.init( this ); -- cgit v1.2.3 From 79bc86f999d72a9baa548e00deb7c32fcb47e9fe Mon Sep 17 00:00:00 2001 From: Sean Leonard Date: Tue, 18 Jun 2013 23:23:24 -0600 Subject: Removed TODO comments, moved to issue tracker --- src/se/leap/leapclient/Dashboard.java | 16 +--------------- src/se/leap/leapclient/EIP.java | 31 +++++-------------------------- 2 files changed, 6 insertions(+), 41 deletions(-) (limited to 'src/se/leap/leapclient') diff --git a/src/se/leap/leapclient/Dashboard.java b/src/se/leap/leapclient/Dashboard.java index 392aba54..d8b3a195 100644 --- a/src/se/leap/leapclient/Dashboard.java +++ b/src/se/leap/leapclient/Dashboard.java @@ -65,7 +65,6 @@ public class Dashboard extends Activity implements LogInDialog.LogInDialogInterf if(ConfigHelper.shared_preferences == null) ConfigHelper.setSharedPreferences(preferences); - // TODO We should do a better check for config that this! if (preferences.contains("provider") && preferences.getString(ConfigHelper.PROVIDER_KEY, null) != null) buildDashboard(); else @@ -75,7 +74,6 @@ public class Dashboard extends Activity implements LogInDialog.LogInDialogInterf @Override protected void onStop() { super.onStop(); - // TODO null provider should only happen before ConfigurationWizard has run, once...better way? if (provider != null) if (provider.hasEIP() && provider.getEIPType() == "OpenVPN") OpenVPN.removeStateListener(this); @@ -84,7 +82,6 @@ public class Dashboard extends Activity implements LogInDialog.LogInDialogInterf @Override protected void onResume() { super.onResume(); - // TODO null provider should only happen before ConfigurationWizard has run, once...better way? if (provider != null) if (provider.hasEIP() && provider.getEIPType() == "OpenVPN") OpenVPN.addStateListener(this); @@ -97,7 +94,6 @@ public class Dashboard extends Activity implements LogInDialog.LogInDialogInterf startService( new Intent(EIP.ACTION_UPDATE_EIP_SERVICE) ); buildDashboard(); } else - // FIXME Doesn't take partial config into account configErrorDialog(); } } @@ -130,10 +126,9 @@ public class Dashboard extends Activity implements LogInDialog.LogInDialogInterf providerNameTV = (TextView) findViewById(R.id.providerName); providerNameTV.setText(provider.getName()); - providerNameTV.setTextSize(28); // TODO maybe to some calculating, or a marquee? + providerNameTV.setTextSize(28); if ( provider.hasEIP() ){ - // FIXME let's schedule this, so we're not doing it when we load the app startService( new Intent(EIP.ACTION_UPDATE_EIP_SERVICE) ); if (provider.getEIPType() == "OpenVPN") OpenVPN.addStateListener(this); @@ -180,12 +175,6 @@ public class Dashboard extends Activity implements LogInDialog.LogInDialogInterf } } }); - - //TODO write our info into the view fragment that will expand with details and a settings button - // TODO set eip overview subview - // TODO make eip type clickable, show subview - // TODO attach vpn status feedback to eip overview view - // TODO attach settings button to something } public void toggleEipOverview(View view) { @@ -195,7 +184,6 @@ public class Dashboard extends Activity implements LogInDialog.LogInDialogInterf eipDetail.setVisibility(View.VISIBLE); } - // FIXME!! I will move to EIPSettingsFragment and begone! public void showEIPLog(View view){ Intent intent = new Intent(getBaseContext(),LogWindow.class); intent.addFlags(Intent.FLAG_ACTIVITY_REORDER_TO_FRONT); @@ -230,7 +218,6 @@ public class Dashboard extends Activity implements LogInDialog.LogInDialogInterf Intent intent; switch (item.getItemId()){ case R.id.about_leap: - // TODO move se.leap.openvpn.AboutFragment into our package Fragment aboutFragment = new AboutFragment(); FragmentTransaction trans = getFragmentManager().beginTransaction(); trans.replace(R.id.dashboardLayout, aboutFragment); @@ -379,7 +366,6 @@ public class Dashboard extends Activity implements LogInDialog.LogInDialogInterf 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(?) ) - // TODO follow-back calls to updateState to find set variable values passed as first param & third param (find those strings...are they all R.string.STATE_* ?) runOnUiThread(new Runnable() { @Override diff --git a/src/se/leap/leapclient/EIP.java b/src/se/leap/leapclient/EIP.java index 3831aaf6..d20921c7 100644 --- a/src/se/leap/leapclient/EIP.java +++ b/src/se/leap/leapclient/EIP.java @@ -132,7 +132,6 @@ public final class EIP extends IntentService { @Override public void onServiceDisconnected(ComponentName name) { - // XXX tell mReceiver!! mBound = false; if (mReceiver != null){ @@ -145,8 +144,6 @@ public final class EIP extends IntentService { }; private void isRunning() { - // TODO I don't like that whatever requested this never receives a response - // if OpenVpnService has not been START_SERVICE, though the one place this is used that's okay if (mBound) { if (mReceiver != null){ Bundle resultData = new Bundle(); @@ -188,7 +185,6 @@ public final class EIP extends IntentService { } private void updateEIPService() { - // TODO this will also fetch new eip-service.json try { eipDefinition = ConfigHelper.getJsonFromSharedPref(ConfigHelper.EIP_SERVICE_KEY); } catch (JSONException e) { @@ -199,7 +195,8 @@ public final class EIP extends IntentService { } private OVPNGateway selectGateway() { - // TODO Logic, yay! + // TODO Implement gateway selection logic based on TZ or preferences + // TODO will also remove "first" from OVPNGateway constructor return new OVPNGateway("first"); } @@ -226,8 +223,6 @@ public final class EIP extends IntentService { try { if ( gw.getJSONObject("capabilities").getJSONArray("transport").toString().contains("openvpn") ){ - // Now build VPNProfiles and save their UUIDs - // TODO create multiple profiles for each gateway to allow trying e.g. different ports when connections don't complete new OVPNGateway(gw); } } catch (JSONException e) { @@ -243,7 +238,6 @@ public final class EIP extends IntentService { private VpnProfile mVpnProfile; private JSONObject gateway; - // Options get put here in the form that se.leap.openvpn.ConfigParser wants TODO will be gone w/ rewrite private HashMap>> options = new HashMap>>(); @@ -253,7 +247,7 @@ public final class EIP extends IntentService { try { - // FIXME ha, this got funny..it will get smart once i'm further... + // TODO when implementing gateway selection logic if ( name == "first" ) { name = vpl.getProfiles().iterator().next().mName; } @@ -268,15 +262,11 @@ public final class EIP extends IntentService { } } - // Constructor to create a gateway by definition protected OVPNGateway(JSONObject gw){ - // TODO We're going to build 1 profile per gateway, but eventually several gateway = gw; - // Delete VpnProfile for host, if there already is one - // FIXME There is a better way to check settings and update them, instead of destroy/rebuild - // Also, this allows one gateway per hostname entry, so that had better be true from the server! + // Currently deletes VpnProfile for host, if there already is one, and builds new ProfileManager vpl = ProfileManager.getInstance(context); Collection profiles = vpl.getProfiles(); for (VpnProfile p : profiles){ @@ -320,10 +310,7 @@ public final class EIP extends IntentService { } } - // FIXME this whole thing will get rewritten when we modify ConfigParser - // in fact, don't even bother looking, except to debug private void parseOptions(){ - // TODO we will want to rewrite se.leap.openvpn.ConfigParser soon to be targeted at our use // FIXME move these to a common API (& version) definition place, like ProviderAPI or ConfigHelper String common_options = "openvpn_configuration"; @@ -332,13 +319,6 @@ public final class EIP extends IntentService { String protos = "protocols"; String capabilities = "capabilities"; - // FIXME Our gateway definition has keys that are not OpenVPN options... - // We need a hard spec for the eip-service.json and better handling in this class - // Then we can stop dumping all the "capabilities" key:values into our options for parsing - - // Put our common options in - // FIXME quite ugly. We don't need the nested vectors, as we're not byte-reading file input, but we haven't rewritten the parser, yet - Vector arg = new Vector(); Vector> args = new Vector>(); @@ -412,7 +392,6 @@ public final class EIP extends IntentService { } protected void createVPNProfile(){ - // TODO take data from eip-service.json for openvpn gateway definitions and create VPNProfile for each try { ConfigParser cp = new ConfigParser(); cp.setDefinition(options); @@ -420,7 +399,7 @@ public final class EIP extends IntentService { mVpnProfile = vp; Log.v(TAG,"Created VPNProfile"); } catch (ConfigParseError e) { - // FIXME Being here is bad because we didn't get a VpnProfile! + // FIXME We didn't get a VpnProfile! Error handling! Log.v(TAG,"Error createing VPNProfile"); e.printStackTrace(); } -- cgit v1.2.3 From f993d85bcb7e6236960570fef88a22d8d6bcc5e7 Mon Sep 17 00:00:00 2001 From: Sean Leonard Date: Tue, 18 Jun 2013 23:26:26 -0600 Subject: Refactor EIP.isRunning() --- src/se/leap/leapclient/EIP.java | 14 ++++++++------ 1 file changed, 8 insertions(+), 6 deletions(-) (limited to 'src/se/leap/leapclient') diff --git a/src/se/leap/leapclient/EIP.java b/src/se/leap/leapclient/EIP.java index d20921c7..5287173c 100644 --- a/src/se/leap/leapclient/EIP.java +++ b/src/se/leap/leapclient/EIP.java @@ -144,17 +144,19 @@ public final class EIP extends IntentService { }; private void isRunning() { + Bundle resultData = new Bundle(); + resultData.putString(ConfigHelper.REQUEST_TAG, ACTION_IS_EIP_RUNNING); + int resultCode = Activity.RESULT_CANCELED; if (mBound) { - if (mReceiver != null){ - Bundle resultData = new Bundle(); - resultData.putString(ConfigHelper.REQUEST_TAG, ACTION_IS_EIP_RUNNING); - int resultCode = (mVpnService.isRunning()) ? Activity.RESULT_OK : Activity.RESULT_CANCELED; - mReceiver.send(resultCode, resultData); - } + resultCode = (mVpnService.isRunning()) ? Activity.RESULT_OK : Activity.RESULT_CANCELED; } else { mPending = ACTION_IS_EIP_RUNNING; this.retreiveVpnService(); } + + if (mReceiver != null){ + mReceiver.send(resultCode, resultData); + } } private void startEIP() { -- cgit v1.2.3 From 13fd30cdc0740c60bfeed92c7012bef9a46d4485 Mon Sep 17 00:00:00 2001 From: Sean Leonard Date: Tue, 18 Jun 2013 23:27:28 -0600 Subject: Rename EIP.OVPNGateway argument and member variable for readability --- src/se/leap/leapclient/EIP.java | 14 +++++++------- 1 file changed, 7 insertions(+), 7 deletions(-) (limited to 'src/se/leap/leapclient') diff --git a/src/se/leap/leapclient/EIP.java b/src/se/leap/leapclient/EIP.java index 5287173c..cadb4494 100644 --- a/src/se/leap/leapclient/EIP.java +++ b/src/se/leap/leapclient/EIP.java @@ -239,7 +239,7 @@ public final class EIP extends IntentService { private String TAG = "OVPNGateway"; private VpnProfile mVpnProfile; - private JSONObject gateway; + private JSONObject mGateway; private HashMap>> options = new HashMap>>(); @@ -264,9 +264,9 @@ public final class EIP extends IntentService { } } - protected OVPNGateway(JSONObject gw){ + protected OVPNGateway(JSONObject gateway){ - gateway = gw; + mGateway = gateway; // Currently deletes VpnProfile for host, if there already is one, and builds new ProfileManager vpl = ProfileManager.getInstance(context); @@ -295,7 +295,7 @@ public final class EIP extends IntentService { String newname; try { - newname = gateway.getString("host"); + newname = mGateway.getString("host"); while(vpl.getProfileByName(newname)!=null) { i++; if(i==1) @@ -347,7 +347,7 @@ public final class EIP extends IntentService { try { arg.add("remote"); - arg.add(gateway.getString(remote)); + arg.add(mGateway.getString(remote)); } catch (JSONException e) { // TODO Auto-generated catch block e.printStackTrace(); @@ -360,7 +360,7 @@ public final class EIP extends IntentService { JSONArray protocolsJSON = null; arg.add("proto"); try { - protocolsJSON = gateway.getJSONObject(capabilities).getJSONArray(protos); + protocolsJSON = mGateway.getJSONObject(capabilities).getJSONArray(protos); } catch (JSONException e) { // TODO Auto-generated catch block e.printStackTrace(); @@ -381,7 +381,7 @@ public final class EIP extends IntentService { String port = null; arg.add("port"); try { - port = gateway.getJSONObject(capabilities).getJSONArray(ports).optString(0); + port = mGateway.getJSONObject(capabilities).getJSONArray(ports).optString(0); } catch (JSONException e) { // TODO Auto-generated catch block e.printStackTrace(); -- cgit v1.2.3 From 2249c44ff76949d9ccfabfcb21187eadabc62190 Mon Sep 17 00:00:00 2001 From: Sean Leonard Date: Wed, 19 Jun 2013 10:10:19 -0600 Subject: Class and method comments and some readability --- src/se/leap/leapclient/Dashboard.java | 40 ++++++++++++++++- src/se/leap/leapclient/EIP.java | 84 ++++++++++++++++++++++++++++++++--- 2 files changed, 116 insertions(+), 8 deletions(-) (limited to 'src/se/leap/leapclient') diff --git a/src/se/leap/leapclient/Dashboard.java b/src/se/leap/leapclient/Dashboard.java index d8b3a195..bf754bae 100644 --- a/src/se/leap/leapclient/Dashboard.java +++ b/src/se/leap/leapclient/Dashboard.java @@ -34,6 +34,12 @@ import android.widget.Switch; 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,StateListener { protected static final int CONFIGURE_LEAP = 0; @@ -98,6 +104,10 @@ public class Dashboard extends Activity implements LogInDialog.LogInDialogInterf } } + /** + * 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)); @@ -120,6 +130,10 @@ public class Dashboard extends Activity implements LogInDialog.LogInDialogInterf }); } + /** + * 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 ); @@ -136,6 +150,9 @@ public class Dashboard extends Activity implements LogInDialog.LogInDialogInterf } } + /** + * Builds the UI for the EIP service Dashboard component + */ private void serviceItemEIP() { mEIPReceiver = new EIPReceiver(new Handler()); mEIPReceiver.setReceiver(this); @@ -177,6 +194,12 @@ public class Dashboard extends Activity implements LogInDialog.LogInDialogInterf }); } + /** + * Expands the EIP Dashboard component for extra details view. + * Called by onClick property in client_dashboard.xml layout. + * + * @param view (Unused) The View calling this method by its onClick property + */ public void toggleEipOverview(View view) { if (eipDetail.isShown()) eipDetail.setVisibility(View.GONE); @@ -184,6 +207,11 @@ public class Dashboard extends Activity implements LogInDialog.LogInDialogInterf eipDetail.setVisibility(View.VISIBLE); } + /** + * Launches the se.leap.openvpn.LogWindow Activity showing detailed OpenVPN log + * + * @param view (Unused) The View calling this method by its onClick property + */ public void showEIPLog(View view){ Intent intent = new Intent(getBaseContext(),LogWindow.class); intent.addFlags(Intent.FLAG_ACTIVITY_REORDER_TO_FRONT); @@ -357,7 +385,12 @@ public class Dashboard extends Activity implements LogInDialog.LogInDialogInterf } } - // Used for getting Context when outside of a class extending Context + /** + * 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; } @@ -380,6 +413,11 @@ public class Dashboard extends Activity implements LogInDialog.LogInDialogInterf }); } + /** + * Inner class for handling messages related to EIP status and control requests + * + * @author Sean Leonard + */ protected class EIPReceiver extends ResultReceiver { Dashboard mDashboard; diff --git a/src/se/leap/leapclient/EIP.java b/src/se/leap/leapclient/EIP.java index cadb4494..426f4359 100644 --- a/src/se/leap/leapclient/EIP.java +++ b/src/se/leap/leapclient/EIP.java @@ -31,8 +31,13 @@ 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 { @@ -96,6 +101,10 @@ public final class EIP extends IntentService { 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); @@ -143,6 +152,15 @@ public final class EIP extends IntentService { }; + /** + * 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(ConfigHelper.REQUEST_TAG, ACTION_IS_EIP_RUNNING); @@ -159,6 +177,10 @@ public final class EIP extends IntentService { } } + /** + * 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(); @@ -173,6 +195,10 @@ public final class EIP extends IntentService { 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(); @@ -186,6 +212,11 @@ public final class EIP extends IntentService { } } + /** + * 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(ConfigHelper.EIP_SERVICE_KEY); @@ -196,12 +227,23 @@ public final class EIP extends IntentService { 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 will also remove "first" from OVPNGateway constructor + // 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; @@ -234,6 +276,13 @@ public final class EIP extends IntentService { } } + /** + * 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"; @@ -243,13 +292,17 @@ public final class EIP extends IntentService { private HashMap>> options = new HashMap>>(); - // Constructor to load a gateway by name + /** + * 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){ ProfileManager vpl = ProfileManager.getInstance(context); try { - // TODO when implementing gateway selection logic if ( name == "first" ) { name = vpl.getProfiles().iterator().next().mName; } @@ -264,6 +317,12 @@ public final class EIP extends IntentService { } } + /** + * 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; @@ -290,13 +349,18 @@ public final class EIP extends IntentService { vpl.saveProfileList(context); } - private void setUniqueProfileName(ProfileManager vpl) { + /** + * 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(vpl.getProfileByName(newname)!=null) { + while(profileManager.getProfileByName(newname)!=null) { i++; if(i==1) newname = getString(R.string.converted_profile); @@ -312,6 +376,9 @@ public final class EIP extends IntentService { } } + /** + * 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 @@ -393,6 +460,9 @@ public final class EIP extends IntentService { arg.clear(); } + /** + * Create and attach the VpnProfile to our gateway object + */ protected void createVPNProfile(){ try { ConfigParser cp = new ConfigParser(); @@ -401,7 +471,7 @@ public final class EIP extends IntentService { mVpnProfile = vp; Log.v(TAG,"Created VPNProfile"); } catch (ConfigParseError e) { - // FIXME We didn't get a VpnProfile! Error handling! + // FIXME We didn't get a VpnProfile! Error handling! and log level Log.v(TAG,"Error createing VPNProfile"); e.printStackTrace(); } -- cgit v1.2.3 From 1739e314e274b0c99b6dbb40ddda3b634affd680 Mon Sep 17 00:00:00 2001 From: Sean Leonard Date: Thu, 20 Jun 2013 20:41:53 -0600 Subject: Remove update eip definition call causing collision --- src/se/leap/leapclient/Dashboard.java | 1 - 1 file changed, 1 deletion(-) (limited to 'src/se/leap/leapclient') diff --git a/src/se/leap/leapclient/Dashboard.java b/src/se/leap/leapclient/Dashboard.java index bf754bae..3c9df56c 100644 --- a/src/se/leap/leapclient/Dashboard.java +++ b/src/se/leap/leapclient/Dashboard.java @@ -97,7 +97,6 @@ public class Dashboard extends Activity implements LogInDialog.LogInDialogInterf 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(); } else configErrorDialog(); -- cgit v1.2.3 From 304b29d6cb85d710756a56bc9c009429b8407d69 Mon Sep 17 00:00:00 2001 From: Sean Leonard Date: Thu, 20 Jun 2013 20:42:21 -0600 Subject: Fix bad for loop maths, rookie! --- src/se/leap/leapclient/Provider.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'src/se/leap/leapclient') diff --git a/src/se/leap/leapclient/Provider.java b/src/se/leap/leapclient/Provider.java index 4a09bf7a..189c3a84 100644 --- a/src/se/leap/leapclient/Provider.java +++ b/src/se/leap/leapclient/Provider.java @@ -122,7 +122,7 @@ public final class Provider implements Serializable { } catch (Exception e) { // TODO: handle exception } - for (int i=0;i Date: Tue, 25 Jun 2013 16:44:22 +0200 Subject: ConfigurationWizard shows domain and name. Items from the provider's list have 2 rows, first one with the domain and the other with the name. Names from preseeded providers are fetched from the assets file, because we don't download provider.json until they select it. --- src/se/leap/leapclient/ProviderListContent.java | 122 +++++++++++++---------- src/se/leap/leapclient/ProviderListFragment.java | 25 ++++- 2 files changed, 88 insertions(+), 59 deletions(-) (limited to 'src/se/leap/leapclient') diff --git a/src/se/leap/leapclient/ProviderListContent.java b/src/se/leap/leapclient/ProviderListContent.java index 8727b16b..991034b1 100644 --- a/src/se/leap/leapclient/ProviderListContent.java +++ b/src/se/leap/leapclient/ProviderListContent.java @@ -6,6 +6,8 @@ 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; @@ -18,54 +20,59 @@ import org.json.JSONObject; */ public class ProviderListContent { - public static List ITEMS = new ArrayList(); + 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); - } + public static Map ITEM_MAP = new HashMap(); - /** - * A provider item. - */ - public static class ProviderItem { - public boolean custom = false; - public String id; - public String name; - public String provider_json_url; + /** + * 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 { + 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; + 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) { - /** - * @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); + 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(ConfigHelper.PROVIDER_JSON_URL); - provider_json_filename = file_contents.getString("assets_json_provider"); + 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); 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(); @@ -73,37 +80,42 @@ public class ProviderListContent { // 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) { - /** - * @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 { + try { id = name; - this.name = 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(ConfigHelper.API_URL_KEY) + "/" + provider_json.getString(ConfigHelper.API_VERSION_KEY) + "/" + ConfigHelper.EIP_SERVICE_API_PATH; - cert_json_url = (String) provider_json.get("ca_cert_uri"); + 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; - } - } + @Override + public String toString() { + return name; + } + } } diff --git a/src/se/leap/leapclient/ProviderListFragment.java b/src/se/leap/leapclient/ProviderListFragment.java index ee3ee8ea..f4f5feb9 100644 --- a/src/se/leap/leapclient/ProviderListFragment.java +++ b/src/se/leap/leapclient/ProviderListFragment.java @@ -9,6 +9,8 @@ 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 @@ -74,10 +76,25 @@ public class ProviderListFragment extends ListFragment { super.onCreate(savedInstanceState); content_adapter = new ArrayAdapter( getActivity(), - android.R.layout.simple_list_item_activated_1, - android.R.id.text1, - ProviderListContent.ITEMS); - setListAdapter(content_adapter); + 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 -- cgit v1.2.3 From 6ada10858719786e489938b3124d1d6015a70421 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Parm=C3=A9nides=20GV?= Date: Tue, 25 Jun 2013 17:55:22 +0200 Subject: The added provider is selected automatically. I've also removed a lot of finishes when things go wrong (so that it should be returning to the previous activity/fragment). --- src/se/leap/leapclient/ConfigHelper.java | 1 + src/se/leap/leapclient/ConfigurationWizard.java | 82 ++++++++++++------------- src/se/leap/leapclient/NewProviderDialog.java | 4 +- src/se/leap/leapclient/ProviderAPI.java | 30 ++++++--- src/se/leap/leapclient/ProviderListContent.java | 10 ++- 5 files changed, 71 insertions(+), 56 deletions(-) (limited to 'src/se/leap/leapclient') diff --git a/src/se/leap/leapclient/ConfigHelper.java b/src/se/leap/leapclient/ConfigHelper.java index cab5fdee..9a3bd991 100644 --- a/src/se/leap/leapclient/ConfigHelper.java +++ b/src/se/leap/leapclient/ConfigHelper.java @@ -64,6 +64,7 @@ public class ConfigHelper { 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", diff --git a/src/se/leap/leapclient/ConfigurationWizard.java b/src/se/leap/leapclient/ConfigurationWizard.java index ce279425..6bf94ca6 100644 --- a/src/se/leap/leapclient/ConfigurationWizard.java +++ b/src/se/leap/leapclient/ConfigurationWizard.java @@ -50,9 +50,9 @@ 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)); - + loadPreseededProviders(); // Only create our fragments if we're not restoring a saved instance @@ -72,15 +72,7 @@ implements ProviderListFragment.Callbacks, NewProviderDialog.NewProviderDialogIn @Override public void onReceiveResult(int resultCode, Bundle resultData) { - if(resultCode == ConfigHelper.CUSTOM_PROVIDER_ADDED){ - ProviderListFragment providerList = new ProviderListFragment(); - - FragmentManager fragmentManager = getFragmentManager(); - fragmentManager.beginTransaction() - .replace(R.id.configuration_wizard_layout, providerList, "providerlist") - .commit(); - } - else if(resultCode == ConfigHelper.CORRECTLY_UPDATED_PROVIDER_DOT_JSON) { + if(resultCode == ConfigHelper.CORRECTLY_UPDATED_PROVIDER_DOT_JSON) { JSONObject provider_json; try { provider_json = new JSONObject(resultData.getString(ConfigHelper.PROVIDER_KEY)); @@ -88,10 +80,13 @@ implements ProviderListFragment.Callbacks, NewProviderDialog.NewProviderDialogIn 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)); - mConfigState.setAction(PROVIDER_SET); + if(mProgressDialog == null) + 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(mSelectedProvider == null) + mSelectedProvider = getProvider(resultData.getString(ConfigHelper.PROVIDER_ID)); downloadJSONFiles(mSelectedProvider); } catch (JSONException e) { // TODO Auto-generated catch block @@ -100,14 +95,12 @@ implements ProviderListFragment.Callbacks, NewProviderDialog.NewProviderDialogIn mProgressDialog.dismiss(); Toast.makeText(this, getResources().getString(R.string.config_error_parsing), Toast.LENGTH_LONG); setResult(RESULT_CANCELED, mConfigState); - finish(); } } else if(resultCode == ConfigHelper.INCORRECTLY_UPDATED_PROVIDER_DOT_JSON) { mProgressDialog.dismiss(); Toast.makeText(getApplicationContext(), R.string.incorrectly_updated_provider_dot_json_message, Toast.LENGTH_LONG).show(); setResult(RESULT_CANCELED, mConfigState); - finish(); } else if(resultCode == ConfigHelper.CORRECTLY_DOWNLOADED_JSON_FILES) { if (ConfigHelper.getBoolFromSharedPref(ConfigHelper.ALLOWED_ANON)){ @@ -122,22 +115,20 @@ implements ProviderListFragment.Callbacks, NewProviderDialog.NewProviderDialogIn } } else if(resultCode == ConfigHelper.INCORRECTLY_DOWNLOADED_JSON_FILES) { - Toast.makeText(getApplicationContext(), R.string.incorrectly_downloaded_json_files_message, Toast.LENGTH_LONG).show(); - setResult(RESULT_CANCELED, mConfigState); - finish(); + 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) { mProgressDialog.dismiss(); Toast.makeText(getApplicationContext(), R.string.correctly_downloaded_json_files_message, Toast.LENGTH_LONG).show(); Toast.makeText(getApplicationContext(), R.string.success, Toast.LENGTH_LONG).show(); //mConfigState.putExtra(CERTIFICATE_RETRIEVED, true); // If this isn't the last step and finish() is moved... - setResult(RESULT_OK); - finish(); + setResult(RESULT_OK); + finish(); } else if(resultCode == ConfigHelper.INCORRECTLY_DOWNLOADED_CERTIFICATE) { mProgressDialog.dismiss(); Toast.makeText(getApplicationContext(), R.string.incorrectly_downloaded_certificate_message, Toast.LENGTH_LONG).show(); setResult(RESULT_CANCELED, mConfigState); - finish(); } } @@ -147,18 +138,23 @@ implements ProviderListFragment.Callbacks, NewProviderDialog.NewProviderDialogIn */ @Override public void onItemSelected(String id) { - //TODO Code 2 pane view - Iterator preseeded_providers_iterator = ProviderListContent.ITEMS.iterator(); - while(preseeded_providers_iterator.hasNext()) - { - ProviderItem provider = preseeded_providers_iterator.next(); - if(provider.id.equalsIgnoreCase(id)) - { - mProgressDialog = ProgressDialog.show(this, getResources().getString(R.string.config_wait_title), getResources().getString(R.string.config_connecting_provider), true); - mSelectedProvider = provider; - saveProviderJson(mSelectedProvider); - } - } + //TODO Code 2 pane view + ProviderItem selected_provider = getProvider(id); + if(mProgressDialog == null) + mProgressDialog = ProgressDialog.show(this, getResources().getString(R.string.config_wait_title), getResources().getString(R.string.config_connecting_provider), true); + mSelectedProvider = selected_provider; + saveProviderJson(mSelectedProvider); + } + + 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; } /** @@ -237,7 +233,7 @@ implements ProviderListFragment.Callbacks, NewProviderDialog.NewProviderDialogIn provider_API_command.putExtra(ConfigHelper.DOWNLOAD_JSON_FILES_BUNDLE_EXTRA, method_and_parameters); provider_API_command.putExtra(ConfigHelper.RECEIVER_KEY, providerAPI_result_receiver); - + startService(provider_API_command); } @@ -261,20 +257,20 @@ implements ProviderListFragment.Callbacks, NewProviderDialog.NewProviderDialogIn * Open the new provider dialog * @param view from which the dialog is showed */ - public void addNewProvider(View view) { + public void addAndSelectNewProvider(View view) { FragmentTransaction fragment_transaction = getFragmentManager().beginTransaction(); - Fragment previous_new_provider_dialog = getFragmentManager().findFragmentByTag(ConfigHelper.NEW_PROVIDER_DIALOG); - 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); + Fragment previous_new_provider_dialog = getFragmentManager().findFragmentByTag(ConfigHelper.NEW_PROVIDER_DIALOG); + 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); } @Override - public void saveProvider(String provider_main_url, boolean danger_on) { + 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(); diff --git a/src/se/leap/leapclient/NewProviderDialog.java b/src/se/leap/leapclient/NewProviderDialog.java index 678e805f..cf361719 100644 --- a/src/se/leap/leapclient/NewProviderDialog.java +++ b/src/se/leap/leapclient/NewProviderDialog.java @@ -22,7 +22,7 @@ import android.widget.Toast; public class NewProviderDialog extends DialogFragment { public interface NewProviderDialogInterface { - public void saveProvider(String url_provider, boolean danger_on); + public void saveAndSelectProvider(String url_provider, boolean danger_on); } NewProviderDialogInterface interface_with_ConfigurationWizard; @@ -64,7 +64,7 @@ public class NewProviderDialog extends DialogFragment { } boolean danger_on = danger_checkbox.isChecked(); if(validURL(entered_url)) { - interface_with_ConfigurationWizard.saveProvider(entered_url, danger_on); + 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(""); diff --git a/src/se/leap/leapclient/ProviderAPI.java b/src/se/leap/leapclient/ProviderAPI.java index 72cc9b62..e7e3918c 100644 --- a/src/se/leap/leapclient/ProviderAPI.java +++ b/src/se/leap/leapclient/ProviderAPI.java @@ -91,8 +91,9 @@ public class ProviderAPI extends IntentService { } } else if ((task = task_for.getBundleExtra(ConfigHelper.DOWNLOAD_NEW_PROVIDER_DOTJSON)) != null) { - if(downloadNewProviderDotJSON(task)) { - receiver.send(ConfigHelper.CUSTOM_PROVIDER_ADDED, Bundle.EMPTY); + Bundle result = downloadNewProviderDotJSON(task); + 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); } @@ -287,7 +288,8 @@ public class ProviderAPI extends IntentService { * @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 boolean downloadNewProviderDotJSON(Bundle task) { + private Bundle downloadNewProviderDotJSON(Bundle task) { + Bundle result = new Bundle(); boolean custom = true; boolean danger_on = task.getBoolean(ConfigHelper.DANGER_ON); @@ -298,14 +300,26 @@ public class ProviderAPI extends IntentService { JSONObject provider_json; try { provider_json = getJSONFromProvider(provider_json_url, danger_on); - ProviderListContent.addItem(new ProviderItem(provider_name, provider_json_url, provider_json, custom, danger_on)); + if(provider_json == null) { + result.putBoolean(ConfigHelper.RESULT_KEY, false); + } else { + + 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)); + 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); + } } catch (JSONException e) { - // TODO Auto-generated catch block - e.printStackTrace(); - return false; + result.putBoolean(ConfigHelper.RESULT_KEY, false); } - return true; + return result; } /** diff --git a/src/se/leap/leapclient/ProviderListContent.java b/src/se/leap/leapclient/ProviderListContent.java index 991034b1..dc3d6ab3 100644 --- a/src/se/leap/leapclient/ProviderListContent.java +++ b/src/se/leap/leapclient/ProviderListContent.java @@ -114,8 +114,12 @@ public class ProviderListContent { } @Override - public String toString() { - return name; - } + public String toString() { + return name; + } + + public String getId() { + return id; + } } } -- cgit v1.2.3 From 2c6b2b47a48652d1e43a7f5383d6f91b7c5d06f1 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Parm=C3=A9nides=20GV?= Date: Mon, 24 Jun 2013 17:18:27 +0200 Subject: We can ignore any certificate. If ssl errors don't vanish using CA cert from provider, we go further and let the certificate not to be validated at all. --- src/se/leap/leapclient/ProviderAPI.java | 69 +++++++++++++++++++++++++++------ 1 file changed, 57 insertions(+), 12 deletions(-) (limited to 'src/se/leap/leapclient') diff --git a/src/se/leap/leapclient/ProviderAPI.java b/src/se/leap/leapclient/ProviderAPI.java index e7e3918c..11ad2e1d 100644 --- a/src/se/leap/leapclient/ProviderAPI.java +++ b/src/se/leap/leapclient/ProviderAPI.java @@ -11,6 +11,8 @@ 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; @@ -347,15 +349,13 @@ public class ProviderAPI extends IntentService { } catch(SocketTimeoutException e) { return ""; } catch (IOException e) { - // TODO SSLHandshakeException - // This means that we have not added ca.crt to the trusted certificates. if(provider_url != null && danger_on) { json_file_content = getStringFromProviderWithoutValidate(provider_url); } - //json_file_content = downloadStringFromProviderWithCACertAdded(string_url); - e.printStackTrace(); } catch (Exception e) { - e.printStackTrace(); + if(provider_url != null && danger_on) { + json_file_content = getStringFromProviderWithoutValidate(provider_url); + } } return json_file_content; @@ -389,7 +389,6 @@ public class ProviderAPI extends IntentService { e.printStackTrace(); } catch (IOException e) { json_string = getStringFromProviderWithCACertAdded(string_url); - //e.printStackTrace(); } return json_string; @@ -417,10 +416,10 @@ public class ProviderAPI extends IntentService { cert_string = cert_string.replaceFirst("-----BEGIN CERTIFICATE-----", "").replaceFirst("-----END CERTIFICATE-----", "").trim(); byte[] cert_bytes = Base64.decode(cert_string, Base64.DEFAULT); InputStream caInput = new ByteArrayInputStream(cert_bytes); - java.security.cert.Certificate ca; + java.security.cert.Certificate dangerous_certificate; try { - ca = cf.generateCertificate(caInput); - System.out.println("ca=" + ((X509Certificate) ca).getSubjectDN()); + dangerous_certificate = cf.generateCertificate(caInput); + System.out.println("dangerous certificate =" + ((X509Certificate) dangerous_certificate).getSubjectDN()); } finally { caInput.close(); } @@ -429,7 +428,7 @@ public class ProviderAPI extends IntentService { String keyStoreType = KeyStore.getDefaultType(); KeyStore keyStore = KeyStore.getInstance(keyStoreType); keyStore.load(null, null); - keyStore.setCertificateEntry("ca", ca); + keyStore.setCertificateEntry("dangerous_certificate", dangerous_certificate); // Create a TrustManager that trusts the CAs in our KeyStore String tmfAlgorithm = TrustManagerFactory.getDefaultAlgorithm(); @@ -449,8 +448,8 @@ public class ProviderAPI extends IntentService { // TODO Auto-generated catch block e.printStackTrace(); } catch (IOException e) { - // TODO Auto-generated catch block - e.printStackTrace(); + // The downloaded certificate doesn't validate our https connection. + json_file_content = getStringFromProviderIgnoringCertificate(url); } catch (KeyStoreException e) { // TODO Auto-generated catch block e.printStackTrace(); @@ -464,6 +463,52 @@ public class ProviderAPI extends IntentService { return json_file_content; } + /** + * Downloads the string that's in the url without regarding certificate validity + */ + private String getStringFromProviderIgnoringCertificate(URL url) { + String string = ""; + try { + 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(new HostnameVerifier() { + @Override + public boolean verify(String arg0, SSLSession arg1) { + return true; + } + }); + string = new Scanner(urlConnection.getInputStream()).useDelimiter("\\A").next(); + System.out.println("String ignoring certificate = " + string); + } catch (IOException e) { + // The downloaded certificate doesn't validate our https connection. + e.printStackTrace(); + } catch (NoSuchAlgorithmException e) { + // TODO Auto-generated catch block + e.printStackTrace(); + } catch (KeyManagementException e) { + // TODO Auto-generated catch block + e.printStackTrace(); + } + return string; + } + /** * Downloads the certificate from the parameter url bypassing self signed certificate SSL errors. * @param certificate_url_string -- cgit v1.2.3 From 7c2ec16d1ec98640dcc9e070f2b9361f68df6f02 Mon Sep 17 00:00:00 2001 From: Sean Leonard Date: Wed, 10 Jul 2013 11:24:15 -0600 Subject: Fix ConcurrentModificationException when removing VpnProfile from iterator backing Collection --- src/se/leap/leapclient/EIP.java | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) (limited to 'src/se/leap/leapclient') diff --git a/src/se/leap/leapclient/EIP.java b/src/se/leap/leapclient/EIP.java index 426f4359..b86a2a4a 100644 --- a/src/se/leap/leapclient/EIP.java +++ b/src/se/leap/leapclient/EIP.java @@ -302,7 +302,6 @@ public final class EIP extends IntentService { ProfileManager vpl = ProfileManager.getInstance(context); try { - if ( name == "first" ) { name = vpl.getProfiles().iterator().next().mName; } @@ -330,9 +329,11 @@ public final class EIP extends IntentService { // Currently deletes VpnProfile for host, if there already is one, and builds new ProfileManager vpl = ProfileManager.getInstance(context); Collection profiles = vpl.getProfiles(); - for (VpnProfile p : profiles){ + 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 -- cgit v1.2.3 From 9e7693c112a7c85cae998ae538643cda9660ff7c Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Parm=C3=A9nides=20GV?= Date: Thu, 27 Jun 2013 20:29:33 +0200 Subject: Coded new fragment appearance Domain, name and description come from provider.json Next step: code buttons to login or to use anonymously. --- src/se/leap/leapclient/ConfigHelper.java | 6 ++- src/se/leap/leapclient/ConfigurationWizard.java | 23 ++++++++- src/se/leap/leapclient/LogInDialog.java | 2 +- src/se/leap/leapclient/ProviderDetailFragment.java | 54 ++++++++++++++++++++++ 4 files changed, 81 insertions(+), 4 deletions(-) create mode 100644 src/se/leap/leapclient/ProviderDetailFragment.java (limited to 'src/se/leap/leapclient') diff --git a/src/se/leap/leapclient/ConfigHelper.java b/src/se/leap/leapclient/ConfigHelper.java index 9a3bd991..e0496422 100644 --- a/src/se/leap/leapclient/ConfigHelper.java +++ b/src/se/leap/leapclient/ConfigHelper.java @@ -76,7 +76,11 @@ public class ConfigHelper { EIP_SERVICE_API_PATH = "config/eip-service.json", ERRORS_KEY = "errors", RECEIVER_TAG = "receiverTag", - REQUEST_TAG = "requestTag"; + REQUEST_TAG = "requestTag", + PROVIDER_DETAILS_DIALOG = "providerDetailsFragment", + DOMAIN = "domain", + NAME = "name", + DESCRIPTION = "description" ; final public static String NG_1024 = diff --git a/src/se/leap/leapclient/ConfigurationWizard.java b/src/se/leap/leapclient/ConfigurationWizard.java index 6bf94ca6..6c016209 100644 --- a/src/se/leap/leapclient/ConfigurationWizard.java +++ b/src/se/leap/leapclient/ConfigurationWizard.java @@ -46,7 +46,7 @@ implements ProviderListFragment.Callbacks, NewProviderDialog.NewProviderDialogIn protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); - setContentView(R.layout.activity_configuration_wizard); + setContentView(R.layout.configuration_wizard_activity); providerAPI_result_receiver = new ProviderAPIResultReceiver(new Handler()); providerAPI_result_receiver.setReceiver(this); @@ -124,7 +124,8 @@ implements ProviderListFragment.Callbacks, NewProviderDialog.NewProviderDialogIn Toast.makeText(getApplicationContext(), R.string.success, Toast.LENGTH_LONG).show(); //mConfigState.putExtra(CERTIFICATE_RETRIEVED, true); // If this isn't the last step and finish() is moved... setResult(RESULT_OK); - finish(); + //finish(); + showProviderDetails(getCurrentFocus()); } else if(resultCode == ConfigHelper.INCORRECTLY_DOWNLOADED_CERTIFICATE) { mProgressDialog.dismiss(); Toast.makeText(getApplicationContext(), R.string.incorrectly_downloaded_certificate_message, Toast.LENGTH_LONG).show(); @@ -268,6 +269,24 @@ implements ProviderListFragment.Callbacks, NewProviderDialog.NewProviderDialogIn DialogFragment newFragment = NewProviderDialog.newInstance(); newFragment.show(fragment_transaction, ConfigHelper.NEW_PROVIDER_DIALOG); } + + /** + * 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(ConfigHelper.PROVIDER_DETAILS_DIALOG); + 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); + } @Override public void saveAndSelectProvider(String provider_main_url, boolean danger_on) { diff --git a/src/se/leap/leapclient/LogInDialog.java b/src/se/leap/leapclient/LogInDialog.java index dcb92d89..3b240ba1 100644 --- a/src/se/leap/leapclient/LogInDialog.java +++ b/src/se/leap/leapclient/LogInDialog.java @@ -32,7 +32,7 @@ public class LogInDialog extends DialogFragment { final EditText password_field = (EditText)log_in_dialog_view.findViewById(R.id.password_entered); builder.setView(log_in_dialog_view) - .setPositiveButton(R.string.log_in_button, new DialogInterface.OnClickListener() { + .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(); diff --git a/src/se/leap/leapclient/ProviderDetailFragment.java b/src/se/leap/leapclient/ProviderDetailFragment.java new file mode 100644 index 00000000..d061a708 --- /dev/null +++ b/src/se/leap/leapclient/ProviderDetailFragment.java @@ -0,0 +1,54 @@ +package se.leap.leapclient; + +import org.json.JSONException; +import org.json.JSONObject; + +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 { + @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(ConfigHelper.PROVIDER_KEY); + + final TextView domain = (TextView)provider_detail_view.findViewById(R.id.provider_detail_domain); + domain.setText(provider_json.getString(ConfigHelper.DOMAIN)); + final TextView name = (TextView)provider_detail_view.findViewById(R.id.provider_detail_name); + name.setText(provider_json.getJSONObject(ConfigHelper.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")); + + builder.setView(provider_detail_view); + builder.setTitle(R.string.provider_details_fragment_title); + builder.setPositiveButton(R.string.use_anonymously_button, new DialogInterface.OnClickListener() { + public void onClick(DialogInterface dialog, int id) { + } + }); + builder.setNegativeButton(R.string.login_button, new DialogInterface.OnClickListener() { + public void onClick(DialogInterface dialog, int id) { + } + }); + + return builder.create(); + } catch (JSONException e) { + return null; + } + } + + public static DialogFragment newInstance() { + ProviderDetailFragment provider_detail_fragment = new ProviderDetailFragment(); + return provider_detail_fragment; + } +} -- cgit v1.2.3 From 36b3b30960bb7c07d3ca4c3a748334627ecb8003 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Parm=C3=A9nides=20GV?= Date: Thu, 27 Jun 2013 21:23:49 +0200 Subject: Use anonymously from ProviderDetail works OK. Tested with dev.bitmask.net, I use the previously downloaded certificate (I should not do that, I'll file an issue because I should download it once the user has requested to do so). Next step: login button from ProviderDetailFragment. --- src/se/leap/leapclient/ConfigurationWizard.java | 23 ++++++++++++++++++++-- src/se/leap/leapclient/LogInDialog.java | 2 +- src/se/leap/leapclient/ProviderDetailFragment.java | 23 ++++++++++++++++++++++ 3 files changed, 45 insertions(+), 3 deletions(-) (limited to 'src/se/leap/leapclient') diff --git a/src/se/leap/leapclient/ConfigurationWizard.java b/src/se/leap/leapclient/ConfigurationWizard.java index 6c016209..7f29a408 100644 --- a/src/se/leap/leapclient/ConfigurationWizard.java +++ b/src/se/leap/leapclient/ConfigurationWizard.java @@ -31,7 +31,7 @@ import android.widget.Toast; * */ public class ConfigurationWizard extends Activity -implements ProviderListFragment.Callbacks, NewProviderDialog.NewProviderDialogInterface, Receiver { +implements ProviderListFragment.Callbacks, NewProviderDialog.NewProviderDialogInterface, ProviderDetailFragment.ProviderDetailFragmentInterface, Receiver { private ProviderItem mSelectedProvider; private ProgressDialog mProgressDialog; @@ -85,8 +85,16 @@ implements ProviderListFragment.Callbacks, NewProviderDialog.NewProviderDialogIn if(mProgressDialog == null) 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(mSelectedProvider == null) + if(mSelectedProvider == null) { mSelectedProvider = getProvider(resultData.getString(ConfigHelper.PROVIDER_ID)); + + 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 @@ -321,4 +329,15 @@ implements ProviderListFragment.Callbacks, NewProviderDialog.NewProviderDialogIn startService(provider_API_command); } + + @Override + public void login() { + //TODO Start dashboard and show login dialog + } + + @Override + public void use_anonymously() { + setResult(RESULT_OK); + finish(); + } } diff --git a/src/se/leap/leapclient/LogInDialog.java b/src/se/leap/leapclient/LogInDialog.java index 3b240ba1..99b19628 100644 --- a/src/se/leap/leapclient/LogInDialog.java +++ b/src/se/leap/leapclient/LogInDialog.java @@ -94,7 +94,7 @@ public class LogInDialog extends DialogFragment { interface_with_Dashboard = (LogInDialogInterface) activity; } catch (ClassCastException e) { throw new ClassCastException(activity.toString() - + " must implement NoticeDialogListener"); + + " must implement LogInDialogListener"); } } } diff --git a/src/se/leap/leapclient/ProviderDetailFragment.java b/src/se/leap/leapclient/ProviderDetailFragment.java index d061a708..6121ac7c 100644 --- a/src/se/leap/leapclient/ProviderDetailFragment.java +++ b/src/se/leap/leapclient/ProviderDetailFragment.java @@ -3,6 +3,9 @@ package se.leap.leapclient; import org.json.JSONException; import org.json.JSONObject; +import se.leap.leapclient.LogInDialog.LogInDialogInterface; + +import android.app.Activity; import android.app.AlertDialog; import android.app.Dialog; import android.app.DialogFragment; @@ -34,10 +37,12 @@ public class ProviderDetailFragment extends DialogFragment { builder.setTitle(R.string.provider_details_fragment_title); builder.setPositiveButton(R.string.use_anonymously_button, new DialogInterface.OnClickListener() { public void onClick(DialogInterface dialog, int id) { + interface_with_configuration_wizard.use_anonymously(); } }); builder.setNegativeButton(R.string.login_button, new DialogInterface.OnClickListener() { public void onClick(DialogInterface dialog, int id) { + interface_with_configuration_wizard.login(); } }); @@ -51,4 +56,22 @@ public class ProviderDetailFragment extends DialogFragment { 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; } -- cgit v1.2.3 From 73a18a778abdfd8010c8b7609c99b825cc1554d0 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Parm=C3=A9nides=20GV?= Date: Thu, 27 Jun 2013 21:52:54 +0200 Subject: Login button from ProviderDetailFragment works. I return an intent with ConfigHelper.LOG_IN extra present. Dashboard looks for it, and if found, starts LogInDialog. --- src/se/leap/leapclient/ConfigurationWizard.java | 5 ++++- src/se/leap/leapclient/Dashboard.java | 5 +++++ 2 files changed, 9 insertions(+), 1 deletion(-) (limited to 'src/se/leap/leapclient') diff --git a/src/se/leap/leapclient/ConfigurationWizard.java b/src/se/leap/leapclient/ConfigurationWizard.java index 7f29a408..7cf989a4 100644 --- a/src/se/leap/leapclient/ConfigurationWizard.java +++ b/src/se/leap/leapclient/ConfigurationWizard.java @@ -332,7 +332,10 @@ implements ProviderListFragment.Callbacks, NewProviderDialog.NewProviderDialogIn @Override public void login() { - //TODO Start dashboard and show login dialog + Intent ask_login = new Intent(); + ask_login.putExtra(ConfigHelper.LOG_IN, ConfigHelper.LOG_IN); + setResult(RESULT_OK, ask_login); + finish(); } @Override diff --git a/src/se/leap/leapclient/Dashboard.java b/src/se/leap/leapclient/Dashboard.java index 3c9df56c..96b982fc 100644 --- a/src/se/leap/leapclient/Dashboard.java +++ b/src/se/leap/leapclient/Dashboard.java @@ -88,6 +88,7 @@ public class Dashboard extends Activity implements LogInDialog.LogInDialogInterf @Override protected void onResume() { super.onResume(); + if (provider != null) if (provider.hasEIP() && provider.getEIPType() == "OpenVPN") OpenVPN.addStateListener(this); @@ -98,6 +99,10 @@ public class Dashboard extends Activity implements LogInDialog.LogInDialogInterf if ( requestCode == CONFIGURE_LEAP ) { if ( resultCode == RESULT_OK ){ buildDashboard(); + if(data != null && data.hasExtra(ConfigHelper.LOG_IN)) { + View view = ((ViewGroup)findViewById(android.R.id.content)).getChildAt(0); + logInDialog(view); + } } else configErrorDialog(); } -- cgit v1.2.3 From 74f95b56051c5c313febdc59f14e0e9077935817 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Parm=C3=A9nides=20GV?= Date: Thu, 27 Jun 2013 21:56:37 +0200 Subject: Removed unnecessary toasts. They are commented, just in case we decide to include any of them before releasing 0.2.0. --- src/se/leap/leapclient/ConfigurationWizard.java | 6 +++--- src/se/leap/leapclient/ProviderDetailFragment.java | 2 -- 2 files changed, 3 insertions(+), 5 deletions(-) (limited to 'src/se/leap/leapclient') diff --git a/src/se/leap/leapclient/ConfigurationWizard.java b/src/se/leap/leapclient/ConfigurationWizard.java index 7cf989a4..df7da8ff 100644 --- a/src/se/leap/leapclient/ConfigurationWizard.java +++ b/src/se/leap/leapclient/ConfigurationWizard.java @@ -117,7 +117,7 @@ implements ProviderListFragment.Callbacks, NewProviderDialog.NewProviderDialogIn downloadAnonCert(); } else { mProgressDialog.dismiss(); - Toast.makeText(getApplicationContext(), R.string.success, Toast.LENGTH_LONG).show(); + //Toast.makeText(getApplicationContext(), R.string.success, Toast.LENGTH_LONG).show(); setResult(RESULT_OK); finish(); } @@ -128,8 +128,8 @@ implements ProviderListFragment.Callbacks, NewProviderDialog.NewProviderDialogIn } else if(resultCode == ConfigHelper.CORRECTLY_DOWNLOADED_CERTIFICATE) { mProgressDialog.dismiss(); - Toast.makeText(getApplicationContext(), R.string.correctly_downloaded_json_files_message, Toast.LENGTH_LONG).show(); - Toast.makeText(getApplicationContext(), R.string.success, Toast.LENGTH_LONG).show(); + //Toast.makeText(getApplicationContext(), R.string.correctly_downloaded_json_files_message, Toast.LENGTH_LONG).show(); + //Toast.makeText(getApplicationContext(), R.string.success, Toast.LENGTH_LONG).show(); //mConfigState.putExtra(CERTIFICATE_RETRIEVED, true); // If this isn't the last step and finish() is moved... setResult(RESULT_OK); //finish(); diff --git a/src/se/leap/leapclient/ProviderDetailFragment.java b/src/se/leap/leapclient/ProviderDetailFragment.java index 6121ac7c..ebd11391 100644 --- a/src/se/leap/leapclient/ProviderDetailFragment.java +++ b/src/se/leap/leapclient/ProviderDetailFragment.java @@ -3,8 +3,6 @@ package se.leap.leapclient; import org.json.JSONException; import org.json.JSONObject; -import se.leap.leapclient.LogInDialog.LogInDialogInterface; - import android.app.Activity; import android.app.AlertDialog; import android.app.Dialog; -- cgit v1.2.3 From dd9f4b8f26debbbea034d00db85fe123cab5619d Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Parm=C3=A9nides=20GV?= Date: Sat, 29 Jun 2013 11:48:15 +0200 Subject: JSONExceptions from ProviderDetail returns false. Buttons from this fragment are shown if the key is present and contains a "true" value, but if an exception occurs the button it's not showed. --- src/se/leap/leapclient/ProviderDetailFragment.java | 45 +++++++++++++++++----- 1 file changed, 35 insertions(+), 10 deletions(-) (limited to 'src/se/leap/leapclient') diff --git a/src/se/leap/leapclient/ProviderDetailFragment.java b/src/se/leap/leapclient/ProviderDetailFragment.java index ebd11391..3b6cf83c 100644 --- a/src/se/leap/leapclient/ProviderDetailFragment.java +++ b/src/se/leap/leapclient/ProviderDetailFragment.java @@ -33,22 +33,47 @@ public class ProviderDetailFragment extends DialogFragment { builder.setView(provider_detail_view); builder.setTitle(R.string.provider_details_fragment_title); - builder.setPositiveButton(R.string.use_anonymously_button, new DialogInterface.OnClickListener() { - public void onClick(DialogInterface dialog, int id) { - interface_with_configuration_wizard.use_anonymously(); - } - }); - builder.setNegativeButton(R.string.login_button, new DialogInterface.OnClickListener() { - public void onClick(DialogInterface dialog, int id) { - interface_with_configuration_wizard.login(); - } - }); + + 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(ConfigHelper.SERVICE_KEY); + return service_description.has(ConfigHelper.ALLOWED_ANON) && service_description.getBoolean(ConfigHelper.ALLOWED_ANON); + } catch (JSONException e) { + return false; + } + } + + 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); + } catch (JSONException e) { + return false; + } + } public static DialogFragment newInstance() { ProviderDetailFragment provider_detail_fragment = new ProviderDetailFragment(); -- cgit v1.2.3 From 755633af514c8f425f936bc5185815175397937c Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Parm=C3=A9nides=20GV?= Date: Sat, 29 Jun 2013 12:54:15 +0200 Subject: Distinguish non LEAP provider and down provider. I've set ProviderAPI to show its own toast depending on the exception that getStringFromProvider issues. If the socket timeout reaches its end, a toast different from when an IOException or a MalformedException occur. --- src/se/leap/leapclient/ConfigurationWizard.java | 11 +++------ src/se/leap/leapclient/ProviderAPI.java | 32 ++++++++++++++++++++----- 2 files changed, 29 insertions(+), 14 deletions(-) (limited to 'src/se/leap/leapclient') diff --git a/src/se/leap/leapclient/ConfigurationWizard.java b/src/se/leap/leapclient/ConfigurationWizard.java index df7da8ff..840e4e6d 100644 --- a/src/se/leap/leapclient/ConfigurationWizard.java +++ b/src/se/leap/leapclient/ConfigurationWizard.java @@ -101,13 +101,12 @@ implements ProviderListFragment.Callbacks, NewProviderDialog.NewProviderDialogIn e.printStackTrace(); mProgressDialog.dismiss(); - Toast.makeText(this, getResources().getString(R.string.config_error_parsing), Toast.LENGTH_LONG); + //Toast.makeText(this, getResources().getString(R.string.config_error_parsing), Toast.LENGTH_LONG); setResult(RESULT_CANCELED, mConfigState); } } else if(resultCode == ConfigHelper.INCORRECTLY_UPDATED_PROVIDER_DOT_JSON) { mProgressDialog.dismiss(); - Toast.makeText(getApplicationContext(), R.string.incorrectly_updated_provider_dot_json_message, Toast.LENGTH_LONG).show(); setResult(RESULT_CANCELED, mConfigState); } else if(resultCode == ConfigHelper.CORRECTLY_DOWNLOADED_JSON_FILES) { @@ -123,20 +122,16 @@ implements ProviderListFragment.Callbacks, NewProviderDialog.NewProviderDialogIn } } else if(resultCode == ConfigHelper.INCORRECTLY_DOWNLOADED_JSON_FILES) { - Toast.makeText(getApplicationContext(), R.string.incorrectly_downloaded_json_files_message, Toast.LENGTH_LONG).show(); + //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) { mProgressDialog.dismiss(); - //Toast.makeText(getApplicationContext(), R.string.correctly_downloaded_json_files_message, Toast.LENGTH_LONG).show(); - //Toast.makeText(getApplicationContext(), R.string.success, Toast.LENGTH_LONG).show(); - //mConfigState.putExtra(CERTIFICATE_RETRIEVED, true); // If this isn't the last step and finish() is moved... setResult(RESULT_OK); - //finish(); showProviderDetails(getCurrentFocus()); } else if(resultCode == ConfigHelper.INCORRECTLY_DOWNLOADED_CERTIFICATE) { mProgressDialog.dismiss(); - Toast.makeText(getApplicationContext(), R.string.incorrectly_downloaded_certificate_message, Toast.LENGTH_LONG).show(); + //Toast.makeText(getApplicationContext(), R.string.incorrectly_downloaded_certificate_message, Toast.LENGTH_LONG).show(); setResult(RESULT_CANCELED, mConfigState); } } diff --git a/src/se/leap/leapclient/ProviderAPI.java b/src/se/leap/leapclient/ProviderAPI.java index 11ad2e1d..b9cbdf24 100644 --- a/src/se/leap/leapclient/ProviderAPI.java +++ b/src/se/leap/leapclient/ProviderAPI.java @@ -52,9 +52,11 @@ 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. @@ -67,10 +69,28 @@ import android.util.Log; */ public class ProviderAPI extends IntentService { + private Handler mHandler; + public ProviderAPI() { super("ProviderAPI"); Log.v("ClassName", "Provider API"); } + + @Override + public void onCreate() { + super.onCreate(); + mHandler = new Handler(); + } + + 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 task_for) { @@ -304,7 +324,7 @@ public class ProviderAPI extends IntentService { provider_json = getJSONFromProvider(provider_json_url, danger_on); if(provider_json == null) { result.putBoolean(ConfigHelper.RESULT_KEY, false); - } else { + } else { ConfigHelper.saveSharedPref(ConfigHelper.PROVIDER_KEY, provider_json); ConfigHelper.saveSharedPref(ConfigHelper.DANGER_ON, danger_on); @@ -344,14 +364,14 @@ public class ProviderAPI extends IntentService { url_connection.setConnectTimeout(seconds_of_timeout*1000); json_file_content = new Scanner(url_connection.getInputStream()).useDelimiter("\\A").next(); } catch (MalformedURLException e) { - // TODO Auto-generated catch block - e.printStackTrace(); + displayToast(R.string.malformed_url); } catch(SocketTimeoutException e) { - return ""; + displayToast(R.string.server_is_down_message); } catch (IOException e) { if(provider_url != null && danger_on) { json_file_content = getStringFromProviderWithoutValidate(provider_url); } + displayToast(R.string.malformed_url); } catch (Exception e) { if(provider_url != null && danger_on) { json_file_content = getStringFromProviderWithoutValidate(provider_url); @@ -385,8 +405,7 @@ public class ProviderAPI extends IntentService { urlConnection.setHostnameVerifier(hostnameVerifier); json_string = new Scanner(urlConnection.getInputStream()).useDelimiter("\\A").next(); } catch (MalformedURLException e) { - // TODO Auto-generated catch block - e.printStackTrace(); + Toast.makeText(getApplicationContext(), R.string.malformed_url, Toast.LENGTH_LONG).show(); } catch (IOException e) { json_string = getStringFromProviderWithCACertAdded(string_url); } @@ -450,6 +469,7 @@ public class ProviderAPI extends IntentService { } catch (IOException e) { // The downloaded certificate doesn't validate our https connection. json_file_content = getStringFromProviderIgnoringCertificate(url); + Toast.makeText(getApplicationContext(), R.string.malformed_url, Toast.LENGTH_LONG).show(); } catch (KeyStoreException e) { // TODO Auto-generated catch block e.printStackTrace(); -- cgit v1.2.3 From 713078d3348017dd8c229ee52701c2c1b69bd85d Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Parm=C3=A9nides=20GV?= Date: Sat, 29 Jun 2013 13:01:07 +0200 Subject: Shows certificate error message. If a download didn't occurr due to an IOException, we assume it was for an SSL error and notify the user telling him/her that LEAP provider is not trusted. --- src/se/leap/leapclient/ProviderAPI.java | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) (limited to 'src/se/leap/leapclient') diff --git a/src/se/leap/leapclient/ProviderAPI.java b/src/se/leap/leapclient/ProviderAPI.java index b9cbdf24..1bc11495 100644 --- a/src/se/leap/leapclient/ProviderAPI.java +++ b/src/se/leap/leapclient/ProviderAPI.java @@ -371,7 +371,7 @@ public class ProviderAPI extends IntentService { if(provider_url != null && danger_on) { json_file_content = getStringFromProviderWithoutValidate(provider_url); } - displayToast(R.string.malformed_url); + displayToast(R.string.certificate_error); } catch (Exception e) { if(provider_url != null && danger_on) { json_file_content = getStringFromProviderWithoutValidate(provider_url); @@ -405,7 +405,7 @@ public class ProviderAPI extends IntentService { urlConnection.setHostnameVerifier(hostnameVerifier); json_string = new Scanner(urlConnection.getInputStream()).useDelimiter("\\A").next(); } catch (MalformedURLException e) { - Toast.makeText(getApplicationContext(), R.string.malformed_url, Toast.LENGTH_LONG).show(); + displayToast(R.string.malformed_url); } catch (IOException e) { json_string = getStringFromProviderWithCACertAdded(string_url); } @@ -469,7 +469,7 @@ public class ProviderAPI extends IntentService { } catch (IOException e) { // The downloaded certificate doesn't validate our https connection. json_file_content = getStringFromProviderIgnoringCertificate(url); - Toast.makeText(getApplicationContext(), R.string.malformed_url, Toast.LENGTH_LONG).show(); + displayToast(R.string.certificate_error); } catch (KeyStoreException e) { // TODO Auto-generated catch block e.printStackTrace(); -- cgit v1.2.3 From 51a1059ed87afb40b639685901f822f6c90e1255 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Parm=C3=A9nides=20GV?= Date: Sat, 29 Jun 2013 13:04:45 +0200 Subject: Substituted IOException by SSLHandshakeException. In getStringFromProvider, there is no IOException but an SSLHandshakeException. Substituing this gives our code more semantics. --- src/se/leap/leapclient/ProviderAPI.java | 1 + 1 file changed, 1 insertion(+) (limited to 'src/se/leap/leapclient') diff --git a/src/se/leap/leapclient/ProviderAPI.java b/src/se/leap/leapclient/ProviderAPI.java index 1bc11495..ce9e974d 100644 --- a/src/se/leap/leapclient/ProviderAPI.java +++ b/src/se/leap/leapclient/ProviderAPI.java @@ -26,6 +26,7 @@ import java.util.Scanner; import javax.net.ssl.HostnameVerifier; import javax.net.ssl.HttpsURLConnection; import javax.net.ssl.SSLContext; +import javax.net.ssl.SSLHandshakeException; import javax.net.ssl.SSLSession; import javax.net.ssl.TrustManagerFactory; import javax.net.ssl.TrustManager; -- cgit v1.2.3 From 7aabefb6df93fd96a354efbbf42a2138e171b763 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Parm=C3=A9nides=20GV?= Date: Sat, 29 Jun 2013 13:18:40 +0200 Subject: Back to IOException instead of SSL exception. The previous commit broke functionality, and instead of discarding it I've decided to undo with a new commit for future references. It would seem that IOException can be substitued by SSLHandshakeException, but the previous commit proves it cannot. --- src/se/leap/leapclient/ProviderAPI.java | 1 - 1 file changed, 1 deletion(-) (limited to 'src/se/leap/leapclient') diff --git a/src/se/leap/leapclient/ProviderAPI.java b/src/se/leap/leapclient/ProviderAPI.java index ce9e974d..1bc11495 100644 --- a/src/se/leap/leapclient/ProviderAPI.java +++ b/src/se/leap/leapclient/ProviderAPI.java @@ -26,7 +26,6 @@ import java.util.Scanner; import javax.net.ssl.HostnameVerifier; import javax.net.ssl.HttpsURLConnection; import javax.net.ssl.SSLContext; -import javax.net.ssl.SSLHandshakeException; import javax.net.ssl.SSLSession; import javax.net.ssl.TrustManagerFactory; import javax.net.ssl.TrustManager; -- cgit v1.2.3 From c95194cffd8ca59298f1eed78b73c8d5a7f4c537 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Parm=C3=A9nides=20GV?= Date: Sat, 29 Jun 2013 13:31:40 +0200 Subject: Untrusted message is not shown if danger_on = true I forgot to add an else in the IOException from getStringFromProvider. This was causing that even if the user checked the trusted completely beckbox and everything was fine, the "not trusted provider" message was being shown. --- src/se/leap/leapclient/ProviderAPI.java | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) (limited to 'src/se/leap/leapclient') diff --git a/src/se/leap/leapclient/ProviderAPI.java b/src/se/leap/leapclient/ProviderAPI.java index 1bc11495..d0001b48 100644 --- a/src/se/leap/leapclient/ProviderAPI.java +++ b/src/se/leap/leapclient/ProviderAPI.java @@ -370,8 +370,9 @@ public class ProviderAPI extends IntentService { } catch (IOException e) { if(provider_url != null && danger_on) { json_file_content = getStringFromProviderWithoutValidate(provider_url); + } else { + displayToast(R.string.certificate_error); } - displayToast(R.string.certificate_error); } catch (Exception e) { if(provider_url != null && danger_on) { json_file_content = getStringFromProviderWithoutValidate(provider_url); -- cgit v1.2.3 From acdbbb68f2429986f96d94888c12a01883785170 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Parm=C3=A9nides=20GV?= Date: Wed, 10 Jul 2013 07:09:30 +0200 Subject: UnknownHostException separated from IOException. I was treating the former exception simply as a kind of the latter, but user messages are different. Now, each one shows its different error message. --- src/se/leap/leapclient/ProviderAPI.java | 3 +++ 1 file changed, 3 insertions(+) (limited to 'src/se/leap/leapclient') diff --git a/src/se/leap/leapclient/ProviderAPI.java b/src/se/leap/leapclient/ProviderAPI.java index d0001b48..4f98e420 100644 --- a/src/se/leap/leapclient/ProviderAPI.java +++ b/src/se/leap/leapclient/ProviderAPI.java @@ -21,6 +21,7 @@ import java.net.SocketTimeoutException; import java.net.URISyntaxException; import java.net.URL; import java.net.URLConnection; +import java.net.UnknownHostException; import java.util.Scanner; import javax.net.ssl.HostnameVerifier; @@ -467,6 +468,8 @@ public class ProviderAPI extends IntentService { } catch (CertificateException e) { // TODO Auto-generated catch block e.printStackTrace(); + } catch (UnknownHostException e) { + displayToast(R.string.server_is_down_message); } catch (IOException e) { // The downloaded certificate doesn't validate our https connection. json_file_content = getStringFromProviderIgnoringCertificate(url); -- cgit v1.2.3 From b684f2fdd35064210d7c5ae760c1a2e4939b1ec5 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Parm=C3=A9nides=20GV?= Date: Sat, 29 Jun 2013 14:03:15 +0200 Subject: Pressing back button, we don't choose any provider Once in the provider detail fragment, if the user presses the back button, provider.json is removed from sharedpreferences (so that Dashboard does not start as if the user had selected the canceled provider) and ConfigurationWizard gets the focus. --- src/se/leap/leapclient/ConfigHelper.java | 16 +++++++++++++--- src/se/leap/leapclient/ConfigurationWizard.java | 13 ++++++------- src/se/leap/leapclient/Dashboard.java | 8 ++++---- src/se/leap/leapclient/ProviderAPI.java | 2 +- src/se/leap/leapclient/ProviderDetailFragment.java | 6 ++++++ 5 files changed, 30 insertions(+), 15 deletions(-) (limited to 'src/se/leap/leapclient') diff --git a/src/se/leap/leapclient/ConfigHelper.java b/src/se/leap/leapclient/ConfigHelper.java index e0496422..559c8e03 100644 --- a/src/se/leap/leapclient/ConfigHelper.java +++ b/src/se/leap/leapclient/ConfigHelper.java @@ -164,9 +164,7 @@ public class ConfigHelper { */ public static String getStringFromSharedPref(String shared_preferences_key) { String content = null; - if ( checkSharedPrefs() ) { - content = shared_preferences.getString(shared_preferences_key, ""); - } + content = shared_preferences.getString(shared_preferences_key, ""); return content; } @@ -196,6 +194,18 @@ public class ConfigHelper { } return value; } + + /* + * 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(); + } /** * Opens a FileInputStream from the user directory of the external storage directory. diff --git a/src/se/leap/leapclient/ConfigurationWizard.java b/src/se/leap/leapclient/ConfigurationWizard.java index 840e4e6d..cd367bc4 100644 --- a/src/se/leap/leapclient/ConfigurationWizard.java +++ b/src/se/leap/leapclient/ConfigurationWizard.java @@ -85,16 +85,15 @@ implements ProviderListFragment.Callbacks, NewProviderDialog.NewProviderDialogIn if(mProgressDialog == null) 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(mSelectedProvider == null) { + if(resultData.containsKey(ConfigHelper.PROVIDER_ID)) mSelectedProvider = getProvider(resultData.getString(ConfigHelper.PROVIDER_ID)); - ProviderListFragment providerList = new ProviderListFragment(); + ProviderListFragment providerList = new ProviderListFragment(); - FragmentManager fragmentManager = getFragmentManager(); - fragmentManager.beginTransaction() - .replace(R.id.configuration_wizard_layout, providerList, "providerlist") - .commit(); - } + FragmentManager fragmentManager = getFragmentManager(); + fragmentManager.beginTransaction() + .replace(R.id.configuration_wizard_layout, providerList, "providerlist") + .commit(); downloadJSONFiles(mSelectedProvider); } catch (JSONException e) { // TODO Auto-generated catch block diff --git a/src/se/leap/leapclient/Dashboard.java b/src/se/leap/leapclient/Dashboard.java index 96b982fc..1e7fbf68 100644 --- a/src/se/leap/leapclient/Dashboard.java +++ b/src/se/leap/leapclient/Dashboard.java @@ -67,14 +67,14 @@ public class Dashboard extends Activity implements LogInDialog.LogInDialogInterf setContentView(R.layout.client_dashboard); - preferences = getSharedPreferences(ConfigHelper.PREFERENCES_KEY,MODE_PRIVATE); + ConfigHelper.setSharedPreferences(getSharedPreferences(ConfigHelper.PREFERENCES_KEY, MODE_PRIVATE)); if(ConfigHelper.shared_preferences == null) ConfigHelper.setSharedPreferences(preferences); - if (preferences.contains("provider") && preferences.getString(ConfigHelper.PROVIDER_KEY, null) != null) - buildDashboard(); - else + if (ConfigHelper.getStringFromSharedPref(ConfigHelper.PROVIDER_KEY).isEmpty()) startActivityForResult(new Intent(this,ConfigurationWizard.class),CONFIGURE_LEAP); + else + buildDashboard(); } @Override diff --git a/src/se/leap/leapclient/ProviderAPI.java b/src/se/leap/leapclient/ProviderAPI.java index 4f98e420..306ffa20 100644 --- a/src/se/leap/leapclient/ProviderAPI.java +++ b/src/se/leap/leapclient/ProviderAPI.java @@ -294,7 +294,7 @@ public class ProviderAPI extends IntentService { } else { 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)); + //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); diff --git a/src/se/leap/leapclient/ProviderDetailFragment.java b/src/se/leap/leapclient/ProviderDetailFragment.java index 3b6cf83c..0b707d3e 100644 --- a/src/se/leap/leapclient/ProviderDetailFragment.java +++ b/src/se/leap/leapclient/ProviderDetailFragment.java @@ -74,6 +74,12 @@ public class ProviderDetailFragment extends DialogFragment { return false; } } + + @Override + public void onCancel(DialogInterface dialog) { + super.onCancel(dialog); + ConfigHelper.removeFromSharedPref(ConfigHelper.PROVIDER_KEY); + } public static DialogFragment newInstance() { ProviderDetailFragment provider_detail_fragment = new ProviderDetailFragment(); -- cgit v1.2.3 From 6776f5eb7b384982ffab3cfd285c3180ecb14bc8 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Parm=C3=A9nides=20GV?= Date: Sat, 29 Jun 2013 16:01:14 +0200 Subject: Back button from ConfigurationWizard quits. If the user decides not to choose any provider, the app quits. I'll create another branch to handle this exit properly, warning the user with an AlertDialog as suggested in #3023. --- src/se/leap/leapclient/ConfigHelper.java | 3 ++- src/se/leap/leapclient/ConfigurationWizard.java | 8 ++++++++ src/se/leap/leapclient/Dashboard.java | 2 ++ 3 files changed, 12 insertions(+), 1 deletion(-) (limited to 'src/se/leap/leapclient') diff --git a/src/se/leap/leapclient/ConfigHelper.java b/src/se/leap/leapclient/ConfigHelper.java index 559c8e03..acc4888a 100644 --- a/src/se/leap/leapclient/ConfigHelper.java +++ b/src/se/leap/leapclient/ConfigHelper.java @@ -80,7 +80,8 @@ public class ConfigHelper { PROVIDER_DETAILS_DIALOG = "providerDetailsFragment", DOMAIN = "domain", NAME = "name", - DESCRIPTION = "description" + DESCRIPTION = "description", + QUIT = "quit" ; final public static String NG_1024 = diff --git a/src/se/leap/leapclient/ConfigurationWizard.java b/src/se/leap/leapclient/ConfigurationWizard.java index cd367bc4..a9fac096 100644 --- a/src/se/leap/leapclient/ConfigurationWizard.java +++ b/src/se/leap/leapclient/ConfigurationWizard.java @@ -148,6 +148,14 @@ implements ProviderListFragment.Callbacks, NewProviderDialog.NewProviderDialogIn mSelectedProvider = selected_provider; saveProviderJson(mSelectedProvider); } + + @Override + public void onBackPressed() { + Intent ask_quit = new Intent(); + ask_quit.putExtra(ConfigHelper.QUIT, ConfigHelper.QUIT); + setResult(RESULT_CANCELED, ask_quit); + super.onBackPressed(); + } private ProviderItem getProvider(String id) { Iterator providers_iterator = ProviderListContent.ITEMS.iterator(); diff --git a/src/se/leap/leapclient/Dashboard.java b/src/se/leap/leapclient/Dashboard.java index 1e7fbf68..93963b3b 100644 --- a/src/se/leap/leapclient/Dashboard.java +++ b/src/se/leap/leapclient/Dashboard.java @@ -103,6 +103,8 @@ public class Dashboard extends Activity implements LogInDialog.LogInDialogInterf View view = ((ViewGroup)findViewById(android.R.id.content)).getChildAt(0); logInDialog(view); } + } else if(resultCode == RESULT_CANCELED && data.hasExtra(ConfigHelper.QUIT)) { + finish(); } else configErrorDialog(); } -- cgit v1.2.3 From 6d532dd2d1a159d0053f5247db7d0c5480ce081e Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Parm=C3=A9nides=20GV?= Date: Sat, 29 Jun 2013 16:24:30 +0200 Subject: ProgressDialog works ok when discarding providers. If the user selects a provider, gets into provider detail, discards it, further trials of selecting a provider trigger the same ProgressDialogs than the initial trials. --- src/se/leap/leapclient/ConfigurationWizard.java | 8 +++----- 1 file changed, 3 insertions(+), 5 deletions(-) (limited to 'src/se/leap/leapclient') diff --git a/src/se/leap/leapclient/ConfigurationWizard.java b/src/se/leap/leapclient/ConfigurationWizard.java index a9fac096..5eab3053 100644 --- a/src/se/leap/leapclient/ConfigurationWizard.java +++ b/src/se/leap/leapclient/ConfigurationWizard.java @@ -20,7 +20,6 @@ import android.content.res.AssetManager; import android.os.Bundle; import android.os.Handler; import android.view.View; -import android.widget.Toast; /** * Activity that builds and shows the list of known available providers. @@ -82,8 +81,8 @@ implements ProviderListFragment.Callbacks, NewProviderDialog.NewProviderDialogIn ConfigHelper.saveSharedPref(ConfigHelper.ALLOWED_ANON, provider_json.getJSONObject(ConfigHelper.SERVICE_KEY).getBoolean(ConfigHelper.ALLOWED_ANON)); mConfigState.setAction(PROVIDER_SET); - if(mProgressDialog == null) - mProgressDialog = ProgressDialog.show(this, getResources().getString(R.string.config_wait_title), getResources().getString(R.string.config_connecting_provider), true); + 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)); @@ -143,8 +142,7 @@ implements ProviderListFragment.Callbacks, NewProviderDialog.NewProviderDialogIn public void onItemSelected(String id) { //TODO Code 2 pane view ProviderItem selected_provider = getProvider(id); - if(mProgressDialog == null) - mProgressDialog = ProgressDialog.show(this, getResources().getString(R.string.config_wait_title), getResources().getString(R.string.config_connecting_provider), true); + mProgressDialog = ProgressDialog.show(this, getResources().getString(R.string.config_wait_title), getResources().getString(R.string.config_connecting_provider), true); mSelectedProvider = selected_provider; saveProviderJson(mSelectedProvider); } -- cgit v1.2.3 From f6efff1a7ec06d68bad27cd65e66d33e72572c37 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Parm=C3=A9nides=20GV?= Date: Sat, 29 Jun 2013 17:07:44 +0200 Subject: Added menu to ConfigurationWizard. It only contains the "About LEAP" option. If the user clicks again that option while the About fragment is up, no new fragment is added and pressing 1 time the back button drives him/her to the ConfigurationWizard activity. --- src/se/leap/leapclient/ConfigHelper.java | 1 + src/se/leap/leapclient/ConfigurationWizard.java | 38 +++++++++++++++++++++++++ 2 files changed, 39 insertions(+) (limited to 'src/se/leap/leapclient') diff --git a/src/se/leap/leapclient/ConfigHelper.java b/src/se/leap/leapclient/ConfigHelper.java index acc4888a..10b3edf4 100644 --- a/src/se/leap/leapclient/ConfigHelper.java +++ b/src/se/leap/leapclient/ConfigHelper.java @@ -33,6 +33,7 @@ public class ConfigHelper { private static KeyStore keystore_trusted; final public static String + ABOUT_FRAGMENT = "aboutFragment", DOWNLOAD_JSON_FILES_BUNDLE_EXTRA = "downloadJSONFiles", UPDATE_PROVIDER_DOTJSON = "updateProviderDotJSON", DOWNLOAD_NEW_PROVIDER_DOTJSON = "downloadNewProviderDotJSON", diff --git a/src/se/leap/leapclient/ConfigurationWizard.java b/src/se/leap/leapclient/ConfigurationWizard.java index 5eab3053..23220e79 100644 --- a/src/se/leap/leapclient/ConfigurationWizard.java +++ b/src/se/leap/leapclient/ConfigurationWizard.java @@ -9,6 +9,8 @@ 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.AboutFragment; +import se.leap.openvpn.MainActivity; import android.app.Activity; import android.app.DialogFragment; import android.app.Fragment; @@ -19,7 +21,10 @@ 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; +import android.view.ViewGroup; /** * Activity that builds and shows the list of known available providers. @@ -329,6 +334,39 @@ implements ProviderListFragment.Callbacks, NewProviderDialog.NewProviderDialogIn 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(ConfigHelper.ABOUT_FRAGMENT); + 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(); + } + } @Override public void login() { -- cgit v1.2.3 From 7d8e1bded64fc6186eb2179ed566f5347e2f5f4e Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Parm=C3=A9nides=20GV?= Date: Sat, 29 Jun 2013 17:30:40 +0200 Subject: Login dialog appears after a failed login. If the user enters his/her password incorrectly, the dialog appears again. --- src/se/leap/leapclient/Dashboard.java | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) (limited to 'src/se/leap/leapclient') diff --git a/src/se/leap/leapclient/Dashboard.java b/src/se/leap/leapclient/Dashboard.java index 93963b3b..f63649dd 100644 --- a/src/se/leap/leapclient/Dashboard.java +++ b/src/se/leap/leapclient/Dashboard.java @@ -68,8 +68,7 @@ public class Dashboard extends Activity implements LogInDialog.LogInDialogInterf setContentView(R.layout.client_dashboard); ConfigHelper.setSharedPreferences(getSharedPreferences(ConfigHelper.PREFERENCES_KEY, MODE_PRIVATE)); - if(ConfigHelper.shared_preferences == null) - ConfigHelper.setSharedPreferences(preferences); + preferences = ConfigHelper.shared_preferences; if (ConfigHelper.getStringFromSharedPref(ConfigHelper.PROVIDER_KEY).isEmpty()) startActivityForResult(new Intent(this,ConfigurationWizard.class),CONFIGURE_LEAP); @@ -374,7 +373,7 @@ 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) { - setResult(RESULT_CANCELED); + logInDialog(getCurrentFocus()); Toast.makeText(getApplicationContext(), R.string.authentication_failed_message, Toast.LENGTH_LONG).show(); } else if(resultCode == ConfigHelper.LOGOUT_SUCCESSFUL) { setResult(RESULT_OK); -- cgit v1.2.3 From e3dd09bb37f6727a09a2d5da7c880997555b4d1f Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Parm=C3=A9nides=20GV?= Date: Sat, 29 Jun 2013 17:54:34 +0200 Subject: New menu option to go back to ConfigurationWizard. It works ok (it simply starts ConfigurationWizard activity for result), but when entering again to Dashboard a NullPointer happens in serviceItemEIP(((ViewStub) findViewById(R.id.eipOverviewStub)).inflate();). It also adds (I forgot to commit before leaving the retry-login branch) ProgressDialogs to login and logout operations. --- src/se/leap/leapclient/Dashboard.java | 18 ++++++++++++++---- 1 file changed, 14 insertions(+), 4 deletions(-) (limited to 'src/se/leap/leapclient') diff --git a/src/se/leap/leapclient/Dashboard.java b/src/se/leap/leapclient/Dashboard.java index f63649dd..5855b6ae 100644 --- a/src/se/leap/leapclient/Dashboard.java +++ b/src/se/leap/leapclient/Dashboard.java @@ -16,6 +16,7 @@ import android.app.AlertDialog; import android.app.DialogFragment; import android.app.Fragment; import android.app.FragmentTransaction; +import android.app.ProgressDialog; import android.content.Context; import android.content.DialogInterface; import android.content.Intent; @@ -43,7 +44,8 @@ import android.widget.Toast; public class Dashboard extends Activity implements LogInDialog.LogInDialogInterface,Receiver,StateListener { protected static final int CONFIGURE_LEAP = 0; - + + private ProgressDialog mProgressDialog; private static Context app; private static SharedPreferences preferences; private static Provider provider; @@ -261,6 +263,9 @@ public class Dashboard extends Activity implements LogInDialog.LogInDialogInterf 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); @@ -297,6 +302,8 @@ public class Dashboard extends Activity implements LogInDialog.LogInDialogInterf provider_API_command.putExtra(ConfigHelper.SRP_AUTH, method_and_parameters); provider_API_command.putExtra(ConfigHelper.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); } @@ -322,6 +329,8 @@ public class Dashboard extends Activity implements LogInDialog.LogInDialogInterf provider_API_command.putExtra(ConfigHelper.LOG_OUT, method_and_parameters); provider_API_command.putExtra(ConfigHelper.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); } @@ -368,18 +377,19 @@ public class Dashboard extends Activity implements LogInDialog.LogInDialogInterf 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); - Toast.makeText(getApplicationContext(), R.string.succesful_authentication_message, Toast.LENGTH_LONG).show(); + mProgressDialog.dismiss(); Cookie session_id = new BasicClientCookie(session_id_cookie_key, session_id_string); downloadAuthedUserCertificate(session_id); } else if(resultCode == ConfigHelper.SRP_AUTHENTICATION_FAILED) { logInDialog(getCurrentFocus()); - Toast.makeText(getApplicationContext(), R.string.authentication_failed_message, Toast.LENGTH_LONG).show(); + mProgressDialog.dismiss(); } else if(resultCode == ConfigHelper.LOGOUT_SUCCESSFUL) { setResult(RESULT_OK); - Toast.makeText(getApplicationContext(), R.string.successful_log_out_message, Toast.LENGTH_LONG).show(); + mProgressDialog.dismiss(); } else if(resultCode == ConfigHelper.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) { setResult(RESULT_CANCELED); -- cgit v1.2.3 From 478b8b50cabc6955314d147bdadadc6127f56e5f Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Parm=C3=A9nides=20GV?= Date: Mon, 1 Jul 2013 18:07:44 +0200 Subject: Check a nullpointer textview. --- src/se/leap/leapclient/Dashboard.java | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) (limited to 'src/se/leap/leapclient') diff --git a/src/se/leap/leapclient/Dashboard.java b/src/se/leap/leapclient/Dashboard.java index 5855b6ae..59c0f182 100644 --- a/src/se/leap/leapclient/Dashboard.java +++ b/src/se/leap/leapclient/Dashboard.java @@ -169,7 +169,9 @@ public class Dashboard extends Activity implements LogInDialog.LogInDialogInterf intent.putExtra(ConfigHelper.RECEIVER_TAG, mEIPReceiver); startService(intent); - ((ViewStub) findViewById(R.id.eipOverviewStub)).inflate(); + ViewStub eip_overview_stub = ((ViewStub) findViewById(R.id.eipOverviewStub)); + if(eip_overview_stub != null) + eip_overview_stub.inflate(); eipTypeTV = (TextView) findViewById(R.id.eipType); eipTypeTV.setText(provider.getEIPType()); -- cgit v1.2.3 From 99a4d94564635f0223d447bc9bcf081cadd8ff36 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Parm=C3=A9nides=20GV?= Date: Tue, 2 Jul 2013 19:20:58 +0200 Subject: User messages are added to the new recovery dialog When login is not successful, a new recovery dialog is prompted with a message about the previous error. --- src/se/leap/leapclient/Dashboard.java | 13 +++-- src/se/leap/leapclient/LogInDialog.java | 26 +++------ src/se/leap/leapclient/NewProviderDialog.java | 2 +- src/se/leap/leapclient/ProviderAPI.java | 76 +++++++++++++++++---------- 4 files changed, 67 insertions(+), 50 deletions(-) (limited to 'src/se/leap/leapclient') diff --git a/src/se/leap/leapclient/Dashboard.java b/src/se/leap/leapclient/Dashboard.java index 59c0f182..a330f9e0 100644 --- a/src/se/leap/leapclient/Dashboard.java +++ b/src/se/leap/leapclient/Dashboard.java @@ -102,7 +102,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, ""); } } else if(resultCode == RESULT_CANCELED && data.hasExtra(ConfigHelper.QUIT)) { finish(); @@ -270,7 +270,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, ""); return true; case R.id.logout_button: logOut(); @@ -340,7 +340,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) { + public void logInDialog(View view, String user_message) { FragmentTransaction fragment_transaction = getFragmentManager().beginTransaction(); Fragment previous_log_in_dialog = getFragmentManager().findFragmentByTag(ConfigHelper.LOG_IN_DIALOG); if (previous_log_in_dialog != null) { @@ -349,6 +349,11 @@ public class Dashboard extends Activity implements LogInDialog.LogInDialogInterf fragment_transaction.addToBackStack(null); DialogFragment newFragment = LogInDialog.newInstance(); + if(user_message != null && !user_message.isEmpty()) { + Bundle user_message_bundle = new Bundle(); + user_message_bundle.putString(getResources().getString(R.string.user_message), user_message); + newFragment.setArguments(user_message_bundle); + } newFragment.show(fragment_transaction, ConfigHelper.LOG_IN_DIALOG); } @@ -384,7 +389,7 @@ 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) { - logInDialog(getCurrentFocus()); + logInDialog(getCurrentFocus(), resultData.getString(getResources().getString(R.string.user_message))); mProgressDialog.dismiss(); } else if(resultCode == ConfigHelper.LOGOUT_SUCCESSFUL) { setResult(RESULT_OK); diff --git a/src/se/leap/leapclient/LogInDialog.java b/src/se/leap/leapclient/LogInDialog.java index 99b19628..0536c6df 100644 --- a/src/se/leap/leapclient/LogInDialog.java +++ b/src/se/leap/leapclient/LogInDialog.java @@ -9,7 +9,7 @@ import android.os.Bundle; import android.view.LayoutInflater; import android.view.View; import android.widget.EditText; -import android.widget.Toast; +import android.widget.TextView; /** * Implements the log in dialog, currently without progress dialog. @@ -22,12 +22,16 @@ import android.widget.Toast; * */ public class LogInDialog extends DialogFragment { - + 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); final EditText password_field = (EditText)log_in_dialog_view.findViewById(R.id.password_entered); @@ -36,12 +40,7 @@ public class LogInDialog extends DialogFragment { public void onClick(DialogInterface dialog, int id) { String username = username_field.getText().toString().trim(); String password = password_field.getText().toString().trim(); - if(wellFormedPassword(password)) { - interface_with_Dashboard.authenticate(username, password); - } else { - password_field.setText(""); - Toast.makeText(getActivity().getApplicationContext(), R.string.not_valid_password_message, Toast.LENGTH_LONG).show(); - } + interface_with_Dashboard.authenticate(username, password); } }) .setNegativeButton(R.string.cancel, new DialogInterface.OnClickListener() { @@ -52,15 +51,6 @@ public class LogInDialog extends DialogFragment { return builder.create(); } - - /** - * 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; - } /** * Interface used to communicate LogInDialog with Dashboard. diff --git a/src/se/leap/leapclient/NewProviderDialog.java b/src/se/leap/leapclient/NewProviderDialog.java index cf361719..3712e8f9 100644 --- a/src/se/leap/leapclient/NewProviderDialog.java +++ b/src/se/leap/leapclient/NewProviderDialog.java @@ -68,7 +68,7 @@ public class NewProviderDialog extends DialogFragment { 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_password_message, Toast.LENGTH_LONG).show(); + Toast.makeText(getActivity().getApplicationContext(), R.string.not_valid_url_entered, Toast.LENGTH_LONG).show(); } } }) diff --git a/src/se/leap/leapclient/ProviderAPI.java b/src/se/leap/leapclient/ProviderAPI.java index 306ffa20..5238224e 100644 --- a/src/se/leap/leapclient/ProviderAPI.java +++ b/src/se/leap/leapclient/ProviderAPI.java @@ -62,7 +62,7 @@ import android.widget.Toast; /** * Implements HTTP api methods used to manage communications with the provider server. * - * It's an IntentService because it downloads data fromt he Internet, so it operates in the background. + * It's an IntentService because it downloads data from the Internet, so it operates in the background. * * @author parmegv * @author MeanderingCode @@ -126,7 +126,10 @@ public class ProviderAPI extends IntentService { if(session_id_bundle.getBoolean(ConfigHelper.RESULT_KEY)) { receiver.send(ConfigHelper.SRP_AUTHENTICATION_SUCCESSFUL, session_id_bundle); } else { - receiver.send(ConfigHelper.SRP_AUTHENTICATION_FAILED, Bundle.EMPTY); + 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); } } else if ((task = task_for.getBundleExtra(ConfigHelper.LOG_OUT)) != null) { @@ -176,41 +179,60 @@ public class ProviderAPI extends IntentService { String username = (String) task.get(ConfigHelper.USERNAME_KEY); String password = (String) task.get(ConfigHelper.PASSWORD_KEY); - String authentication_server = (String) task.get(ConfigHelper.API_URL_KEY); + if(wellFormedPassword(password)) { + String authentication_server = (String) task.get(ConfigHelper.API_URL_KEY); - 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(ConfigHelper.SALT_KEY); - 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( client.verify((byte[])session_idAndM2.get("M2")) == false ) { - session_id_bundle.putBoolean(ConfigHelper.RESULT_KEY, false); + 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(ConfigHelper.SALT_KEY); + 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( client.verify((byte[])session_idAndM2.get("M2")) == false ) { + session_id_bundle.putBoolean(ConfigHelper.RESULT_KEY, false); + } else { + 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)); + } } else { - 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(getResources().getString(R.string.user_message), getResources().getString(R.string.error_bad_user_password_user_message)); + session_id_bundle.putBoolean(ConfigHelper.RESULT_KEY, false); } - } else { + } 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)); + } 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)); + } 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)); + } 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)); } - } catch (ClientProtocolException e) { - session_id_bundle.putBoolean(ConfigHelper.RESULT_KEY, false); - } catch (IOException e) { - session_id_bundle.putBoolean(ConfigHelper.RESULT_KEY, false); - } catch (JSONException e) { - session_id_bundle.putBoolean(ConfigHelper.RESULT_KEY, false); - } catch (NoSuchAlgorithmException e) { + } 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)); } - + return session_id_bundle; } + /** + * 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 -- cgit v1.2.3 From 84d3b5f6967c0bac2a740627386ff92b6e283b16 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Parm=C3=A9nides=20GV?= Date: Wed, 3 Jul 2013 18:02:36 +0200 Subject: ConfigurationWizard backstack and exit behavior. Feature #3023 first solution. I don't like to tell anything to the user when s/he wants to exit pressing the back button. I assume s/he is saying: "Wanna go out!!" I've implemented the behaviour written in UI Rev II. If a user selects a new provider when coming back from Switch Provider, the previous provider is forgotten and we assume s/he wants to change of provider but he is not sure to which. That means that previous provider configuration will be removed (that means there is no provider selected and Dashboard will not be launched before a new provider is selected). --- src/se/leap/leapclient/ConfigHelper.java | 3 ++- src/se/leap/leapclient/ConfigurationWizard.java | 14 +++++++++++++- src/se/leap/leapclient/ProviderDetailFragment.java | 3 +++ 3 files changed, 18 insertions(+), 2 deletions(-) (limited to 'src/se/leap/leapclient') diff --git a/src/se/leap/leapclient/ConfigHelper.java b/src/se/leap/leapclient/ConfigHelper.java index 10b3edf4..007db95c 100644 --- a/src/se/leap/leapclient/ConfigHelper.java +++ b/src/se/leap/leapclient/ConfigHelper.java @@ -178,7 +178,8 @@ public class ConfigHelper { public static JSONObject getJsonFromSharedPref(String shared_preferences_key) throws JSONException { JSONObject content = null; if ( checkSharedPrefs() ) { - content = new JSONObject( shared_preferences.getString(shared_preferences_key, "") ); + String json_string = shared_preferences.getString(shared_preferences_key, ""); + content = new JSONObject(json_string); } return content; diff --git a/src/se/leap/leapclient/ConfigurationWizard.java b/src/se/leap/leapclient/ConfigurationWizard.java index 23220e79..d12fdc77 100644 --- a/src/se/leap/leapclient/ConfigurationWizard.java +++ b/src/se/leap/leapclient/ConfigurationWizard.java @@ -154,10 +154,22 @@ implements ProviderListFragment.Callbacks, NewProviderDialog.NewProviderDialogIn @Override public void onBackPressed() { + try { + if(ConfigHelper.getJsonFromSharedPref(ConfigHelper.PROVIDER_KEY) == null || ConfigHelper.getJsonFromSharedPref(ConfigHelper.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(ConfigHelper.QUIT, ConfigHelper.QUIT); setResult(RESULT_CANCELED, ask_quit); - super.onBackPressed(); } private ProviderItem getProvider(String id) { diff --git a/src/se/leap/leapclient/ProviderDetailFragment.java b/src/se/leap/leapclient/ProviderDetailFragment.java index 0b707d3e..a788594f 100644 --- a/src/se/leap/leapclient/ProviderDetailFragment.java +++ b/src/se/leap/leapclient/ProviderDetailFragment.java @@ -79,6 +79,9 @@ public class ProviderDetailFragment extends DialogFragment { 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); } public static DialogFragment newInstance() { -- cgit v1.2.3 From 3e04f2ab44e5e5e33efcfe515088ec3f918ccef0 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Parm=C3=A9nides=20GV?= Date: Sat, 29 Jun 2013 12:54:15 +0200 Subject: Distinguish non LEAP provider and down provider. I've set ProviderAPI to show its own toast depending on the exception that getStringFromProvider issues. If the socket timeout reaches its end, a toast different from when an IOException or a MalformedException occur. --- src/se/leap/leapclient/ProviderAPI.java | 1 + 1 file changed, 1 insertion(+) (limited to 'src/se/leap/leapclient') diff --git a/src/se/leap/leapclient/ProviderAPI.java b/src/se/leap/leapclient/ProviderAPI.java index 5238224e..fba0ab01 100644 --- a/src/se/leap/leapclient/ProviderAPI.java +++ b/src/se/leap/leapclient/ProviderAPI.java @@ -396,6 +396,7 @@ public class ProviderAPI extends IntentService { } else { displayToast(R.string.certificate_error); } + displayToast(R.string.malformed_url); } catch (Exception e) { if(provider_url != null && danger_on) { json_file_content = getStringFromProviderWithoutValidate(provider_url); -- cgit v1.2.3 From 7202591b0a42cd91a10255720bd80c2218af2093 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Parm=C3=A9nides=20GV?= Date: Sat, 29 Jun 2013 13:01:07 +0200 Subject: Shows certificate error message. If a download didn't occurr due to an IOException, we assume it was for an SSL error and notify the user telling him/her that LEAP provider is not trusted. --- src/se/leap/leapclient/ProviderAPI.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'src/se/leap/leapclient') diff --git a/src/se/leap/leapclient/ProviderAPI.java b/src/se/leap/leapclient/ProviderAPI.java index fba0ab01..f3ea5f2e 100644 --- a/src/se/leap/leapclient/ProviderAPI.java +++ b/src/se/leap/leapclient/ProviderAPI.java @@ -396,7 +396,7 @@ public class ProviderAPI extends IntentService { } else { displayToast(R.string.certificate_error); } - displayToast(R.string.malformed_url); + displayToast(R.string.certificate_error); } catch (Exception e) { if(provider_url != null && danger_on) { json_file_content = getStringFromProviderWithoutValidate(provider_url); -- cgit v1.2.3 From dacf638f7dd15e291cdb23a6cf8317e1dd80ed29 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Parm=C3=A9nides=20GV?= Date: Tue, 2 Jul 2013 19:38:48 +0200 Subject: New certificates are added without creating files LeapHttpClient can fetch the main CA certificate downloaded from the provider and add it to its in-memory keystore, without saving the certificate in a file. This is a very important feature, I think it can be cherry picked (it has little modifications, and very localized). It's very important because authentication does not work without this bug fix in the latest branches, because I removed the code that saved the certificate in a file but didn't test the authentication part. --- src/se/leap/leapclient/ConfigHelper.java | 40 +++++++++++++++++++++++++------- src/se/leap/leapclient/ProviderAPI.java | 17 +++----------- 2 files changed, 35 insertions(+), 22 deletions(-) (limited to 'src/se/leap/leapclient') diff --git a/src/se/leap/leapclient/ConfigHelper.java b/src/se/leap/leapclient/ConfigHelper.java index 007db95c..c5a37be5 100644 --- a/src/se/leap/leapclient/ConfigHelper.java +++ b/src/se/leap/leapclient/ConfigHelper.java @@ -1,5 +1,6 @@ package se.leap.leapclient; +import java.io.ByteArrayInputStream; import java.io.File; import java.io.FileInputStream; import java.io.FileNotFoundException; @@ -19,6 +20,7 @@ import org.json.JSONObject; import android.content.Context; import android.content.SharedPreferences; import android.os.Environment; +import android.util.Base64; /** * Stores constants, and implements auxiliary methods used across all LEAP Android classes. @@ -256,6 +258,31 @@ public class ConfigHelper { 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; + } /** * Adds a new X509 certificate given its input stream and its provider name @@ -284,26 +311,23 @@ public class ConfigHelper { * @param certificate */ public static void addTrustedCertificate(String provider, String certificate) { - String filename_to_save = provider + "_certificate.cer"; - CertificateFactory cf; + try { - cf = CertificateFactory.getInstance("X.509"); - X509Certificate cert = - (X509Certificate)cf.generateCertificate(openFileInputStream(filename_to_save)); + X509Certificate cert = ConfigHelper.parseX509CertificateFromString(certificate); if(keystore_trusted == null) { keystore_trusted = KeyStore.getInstance("BKS"); keystore_trusted.load(null); } 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(); } 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(); diff --git a/src/se/leap/leapclient/ProviderAPI.java b/src/se/leap/leapclient/ProviderAPI.java index f3ea5f2e..25a14bb5 100644 --- a/src/se/leap/leapclient/ProviderAPI.java +++ b/src/se/leap/leapclient/ProviderAPI.java @@ -452,21 +452,10 @@ public class ProviderAPI extends IntentService { if(cert_string.isEmpty()) { cert_string = downloadCertificateWithoutTrusting(url.getProtocol() + "://" + url.getHost() + "/" + "ca.crt"); ConfigHelper.saveSharedPref(ConfigHelper.MAIN_CERT_KEY, cert_string); - } - CertificateFactory cf; + } + try { - cf = CertificateFactory.getInstance("X.509"); - - cert_string = cert_string.replaceFirst("-----BEGIN CERTIFICATE-----", "").replaceFirst("-----END CERTIFICATE-----", "").trim(); - byte[] cert_bytes = Base64.decode(cert_string, Base64.DEFAULT); - InputStream caInput = new ByteArrayInputStream(cert_bytes); - java.security.cert.Certificate dangerous_certificate; - try { - dangerous_certificate = cf.generateCertificate(caInput); - System.out.println("dangerous certificate =" + ((X509Certificate) dangerous_certificate).getSubjectDN()); - } finally { - caInput.close(); - } + java.security.cert.Certificate dangerous_certificate = ConfigHelper.parseX509CertificateFromString(cert_string); // Create a KeyStore containing our trusted CAs String keyStoreType = KeyStore.getDefaultType(); -- cgit v1.2.3 From 652d0e84785b89ac13c0fc03663ce0e2811aea6b Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Parm=C3=A9nides=20GV?= Date: Tue, 9 Jul 2013 18:41:47 +0200 Subject: Dashboard menu is updated when logged in or out. Login option is not shown if the user is already logged in, and logout option is not shown if the user is not logged in. I've also removed a debug line from ProviderDetailFragment, which returned true when it returned false because of an exception. --- src/se/leap/leapclient/Dashboard.java | 16 ++++++++++++---- src/se/leap/leapclient/ProviderDetailFragment.java | 1 - 2 files changed, 12 insertions(+), 5 deletions(-) (limited to 'src/se/leap/leapclient') diff --git a/src/se/leap/leapclient/Dashboard.java b/src/se/leap/leapclient/Dashboard.java index a330f9e0..a429d3b3 100644 --- a/src/se/leap/leapclient/Dashboard.java +++ b/src/se/leap/leapclient/Dashboard.java @@ -57,6 +57,7 @@ public class Dashboard extends Activity implements LogInDialog.LogInDialogInterf private TextView eipStatus; private boolean mEipWait = false; + private boolean authed = false; public ProviderAPIResultReceiver providerAPI_result_receiver; private EIPReceiver mEIPReceiver; @@ -234,8 +235,13 @@ public class Dashboard extends Activity implements LogInDialog.LogInDialogInterf provider_json = ConfigHelper.getJsonFromSharedPref(ConfigHelper.PROVIDER_KEY); JSONObject service_description = provider_json.getJSONObject(ConfigHelper.SERVICE_KEY); if(service_description.getBoolean(ConfigHelper.ALLOW_REGISTRATION_KEY)) { - menu.findItem(R.id.login_button).setVisible(true); - menu.findItem(R.id.logout_button).setVisible(true); + 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 @@ -384,14 +390,16 @@ public class Dashboard extends Activity implements LogInDialog.LogInDialogInterf 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); - mProgressDialog.dismiss(); + authed = true; + invalidateOptionsMenu(); Cookie session_id = new BasicClientCookie(session_id_cookie_key, session_id_string); downloadAuthedUserCertificate(session_id); } else if(resultCode == ConfigHelper.SRP_AUTHENTICATION_FAILED) { logInDialog(getCurrentFocus(), resultData.getString(getResources().getString(R.string.user_message))); - mProgressDialog.dismiss(); } else if(resultCode == ConfigHelper.LOGOUT_SUCCESSFUL) { + authed = false; + invalidateOptionsMenu(); setResult(RESULT_OK); mProgressDialog.dismiss(); } else if(resultCode == ConfigHelper.LOGOUT_FAILED) { diff --git a/src/se/leap/leapclient/ProviderDetailFragment.java b/src/se/leap/leapclient/ProviderDetailFragment.java index a788594f..600be58f 100644 --- a/src/se/leap/leapclient/ProviderDetailFragment.java +++ b/src/se/leap/leapclient/ProviderDetailFragment.java @@ -43,7 +43,6 @@ public class ProviderDetailFragment extends DialogFragment { } 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(); -- cgit v1.2.3 From a8d10d9800fcd58d8ee5e3b428b8ba402e83764f Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Parm=C3=A9nides=20GV?= Date: Wed, 10 Jul 2013 21:42:42 +0200 Subject: Shows bad user/password message when appropriate. If an empty json string is received after sending M1 (that means no M2 in return), bad user/password message is shown. This fixes bug 3153. --- src/se/leap/leapclient/ProviderAPI.java | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) (limited to 'src/se/leap/leapclient') diff --git a/src/se/leap/leapclient/ProviderAPI.java b/src/se/leap/leapclient/ProviderAPI.java index 25a14bb5..37856f60 100644 --- a/src/se/leap/leapclient/ProviderAPI.java +++ b/src/se/leap/leapclient/ProviderAPI.java @@ -192,12 +192,13 @@ 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( client.verify((byte[])session_idAndM2.get("M2")) == false ) { - session_id_bundle.putBoolean(ConfigHelper.RESULT_KEY, false); - } else { + 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)); + } 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)); } } else { session_id_bundle.putString(getResources().getString(R.string.user_message), getResources().getString(R.string.error_bad_user_password_user_message)); -- cgit v1.2.3 From 85cbeb46d371b96af0034f08e2e323d3bc202c49 Mon Sep 17 00:00:00 2001 From: Sean Leonard Date: Tue, 2 Jul 2013 22:54:28 -0600 Subject: Move AboutFragment into leapclient package --- src/se/leap/leapclient/AboutFragment.java | 65 +++++++++++++++++++++++++ src/se/leap/leapclient/ConfigurationWizard.java | 1 - src/se/leap/leapclient/Dashboard.java | 1 - 3 files changed, 65 insertions(+), 2 deletions(-) create mode 100644 src/se/leap/leapclient/AboutFragment.java (limited to 'src/se/leap/leapclient') diff --git a/src/se/leap/leapclient/AboutFragment.java b/src/se/leap/leapclient/AboutFragment.java new file mode 100644 index 00000000..9c7f31f0 --- /dev/null +++ b/src/se/leap/leapclient/AboutFragment.java @@ -0,0 +1,65 @@ +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 { + + 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 paypal = (TextView) v.findViewById(R.id.donatestring); + + String donatetext = getActivity().getString(R.string.donatewithpaypal); + Spanned htmltext = Html.fromHtml(donatetext); + paypal.setText(htmltext); + paypal.setMovementMethod(LinkMovementMethod.getInstance()); + + 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/ConfigurationWizard.java b/src/se/leap/leapclient/ConfigurationWizard.java index d12fdc77..2687b579 100644 --- a/src/se/leap/leapclient/ConfigurationWizard.java +++ b/src/se/leap/leapclient/ConfigurationWizard.java @@ -9,7 +9,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.AboutFragment; import se.leap.openvpn.MainActivity; import android.app.Activity; import android.app.DialogFragment; diff --git a/src/se/leap/leapclient/Dashboard.java b/src/se/leap/leapclient/Dashboard.java index a429d3b3..1b6b8e38 100644 --- a/src/se/leap/leapclient/Dashboard.java +++ b/src/se/leap/leapclient/Dashboard.java @@ -6,7 +6,6 @@ import org.json.JSONException; import org.json.JSONObject; import se.leap.leapclient.ProviderAPIResultReceiver.Receiver; -import se.leap.openvpn.AboutFragment; import se.leap.openvpn.LogWindow; import se.leap.openvpn.MainActivity; import se.leap.openvpn.OpenVPN; -- cgit v1.2.3 From b358f7883257fdf2c5ca391ce7dcc51ff28f6266 Mon Sep 17 00:00:00 2001 From: Sean Leonard Date: Thu, 4 Jul 2013 08:41:32 -0600 Subject: Clean up AboutFragment, remove donation text --- src/se/leap/leapclient/AboutFragment.java | 7 ------- 1 file changed, 7 deletions(-) (limited to 'src/se/leap/leapclient') diff --git a/src/se/leap/leapclient/AboutFragment.java b/src/se/leap/leapclient/AboutFragment.java index 9c7f31f0..a3fbbf93 100644 --- a/src/se/leap/leapclient/AboutFragment.java +++ b/src/se/leap/leapclient/AboutFragment.java @@ -45,13 +45,6 @@ public class AboutFragment extends Fragment { ver.setText(getString(R.string.version_info,name,version)); - TextView paypal = (TextView) v.findViewById(R.id.donatestring); - - String donatetext = getActivity().getString(R.string.donatewithpaypal); - Spanned htmltext = Html.fromHtml(donatetext); - paypal.setText(htmltext); - paypal.setMovementMethod(LinkMovementMethod.getInstance()); - TextView translation = (TextView) v.findViewById(R.id.translation); // Don't print a text for myself -- cgit v1.2.3 From 6614dface821c5f975dba47bc6150783c25ee468 Mon Sep 17 00:00:00 2001 From: Sean Leonard Date: Wed, 10 Jul 2013 11:17:03 -0600 Subject: Better VPN connection state messages --- src/se/leap/leapclient/Dashboard.java | 19 ++++++++++++++----- 1 file changed, 14 insertions(+), 5 deletions(-) (limited to 'src/se/leap/leapclient') diff --git a/src/se/leap/leapclient/Dashboard.java b/src/se/leap/leapclient/Dashboard.java index 1b6b8e38..b58f4952 100644 --- a/src/se/leap/leapclient/Dashboard.java +++ b/src/se/leap/leapclient/Dashboard.java @@ -427,16 +427,25 @@ public class Dashboard extends Activity implements LogInDialog.LogInDialogInterf @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(?) ) + // NOPROCESS,NONETWORK,BYTECOUNT,AUTH_FAILED + some parsing thing ( WAIT(?),AUTH,GET_CONFIG,ASSIGN_IP,CONNECTED,SIGINT ) runOnUiThread(new Runnable() { @Override public void run() { if (eipStatus != null) { - String prefix = getString(localizedResId) + ":"; - if (state.equals("BYTECOUNT") || state.equals("NOPROCESS")) - prefix = ""; - eipStatus.setText(prefix + logmessage); + String statusMessage = ""; + String prefix = getString(localizedResId); + if (state.equals("CONNECTED")){ + statusMessage = "Connection Secure"; + } else if (state.equals("BYTECOUNT")) { + statusMessage = logmessage; + } else if (state.equals("NOPROCESS") || state.equals("EXITING")) { + statusMessage = "Not running! Connection not secure!"; + } else { + statusMessage = prefix + logmessage; + } + + eipStatus.setText(statusMessage); } } }); -- cgit v1.2.3 From e85eb39a9cfa209eb5503657d9724d1eebd2be0b Mon Sep 17 00:00:00 2001 From: Sean Leonard Date: Wed, 10 Jul 2013 11:23:21 -0600 Subject: Only parse eip-services.json if the serial has incremented --- src/se/leap/leapclient/ConfigHelper.java | 23 +++++++++++++++++++++++ src/se/leap/leapclient/Dashboard.java | 1 + src/se/leap/leapclient/EIP.java | 21 +++++++++++++++++---- 3 files changed, 41 insertions(+), 4 deletions(-) (limited to 'src/se/leap/leapclient') diff --git a/src/se/leap/leapclient/ConfigHelper.java b/src/se/leap/leapclient/ConfigHelper.java index c5a37be5..0c589c41 100644 --- a/src/se/leap/leapclient/ConfigHelper.java +++ b/src/se/leap/leapclient/ConfigHelper.java @@ -49,6 +49,7 @@ public class ConfigHelper { LOG_OUT = "logOut", DOWNLOAD_CERTIFICATE = "downloadUserAuthedCertificate", API_VERSION_KEY = "api_version", + API_RETURN_SERIAL_KEY = "serial", RESULT_KEY = "result", RECEIVER_KEY = "receiver", PROVIDER_KEY = "provider", @@ -58,6 +59,7 @@ public class ConfigHelper { 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", @@ -161,6 +163,17 @@ public class ConfigHelper { 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 @@ -199,6 +212,16 @@ public class ConfigHelper { } 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. diff --git a/src/se/leap/leapclient/Dashboard.java b/src/se/leap/leapclient/Dashboard.java index b58f4952..6634479e 100644 --- a/src/se/leap/leapclient/Dashboard.java +++ b/src/se/leap/leapclient/Dashboard.java @@ -99,6 +99,7 @@ public class Dashboard extends Activity implements LogInDialog.LogInDialogInterf 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(ConfigHelper.LOG_IN)) { View view = ((ViewGroup)findViewById(android.R.id.content)).getChildAt(0); diff --git a/src/se/leap/leapclient/EIP.java b/src/se/leap/leapclient/EIP.java index b86a2a4a..5057732e 100644 --- a/src/se/leap/leapclient/EIP.java +++ b/src/se/leap/leapclient/EIP.java @@ -54,6 +54,7 @@ public final class EIP extends IntentService { // 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; @@ -70,6 +71,7 @@ public final class EIP extends IntentService { try { eipDefinition = ConfigHelper.getJsonFromSharedPref(ConfigHelper.EIP_SERVICE_KEY); + parsedEipSerial = ConfigHelper.getIntFromSharedPref(ConfigHelper.EIP_PARSED_SERIAL); } catch (JSONException e) { // TODO Auto-generated catch block e.printStackTrace(); @@ -224,7 +226,8 @@ public final class EIP extends IntentService { // TODO Auto-generated catch block e.printStackTrace(); } - updateGateways(); + if (eipDefinition.optInt("serial") > parsedEipSerial) + updateGateways(); } /** @@ -274,6 +277,8 @@ public final class EIP extends IntentService { e.printStackTrace(); } } + + ConfigHelper.saveSharedPref(ConfigHelper.EIP_PARSED_SERIAL, eipDefinition.optInt(ConfigHelper.API_RETURN_SERIAL_KEY)); } /** @@ -287,6 +292,7 @@ public final class EIP extends IntentService { private String TAG = "OVPNGateway"; + private String mName; private VpnProfile mVpnProfile; private JSONObject mGateway; private HashMap>> options = new HashMap>>(); @@ -299,17 +305,24 @@ public final class EIP extends IntentService { * @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 ( name == "first" ) { - name = vpl.getProfiles().iterator().next().mName; + if ( mName == "first" ) { + mName = vpl.getProfiles().iterator().next().mName; } - mVpnProfile = vpl.getProfileByName(name); + mVpnProfile = vpl.getProfileByName(mName); } catch (NoSuchElementException e) { updateEIPService(); + this.loadVpnProfile(); // FIXME catch infinite loops } catch (Exception e) { // TODO Auto-generated catch block e.printStackTrace(); -- cgit v1.2.3 From 437183f283e61da878aded001fb78e8e62aa9da6 Mon Sep 17 00:00:00 2001 From: Sean Leonard Date: Wed, 10 Jul 2013 13:15:52 -0600 Subject: Use non-blocking logic for EIP switch Includes AlertDialog if the user attempts to stop EIP while a connection is being established --- src/se/leap/leapclient/Dashboard.java | 59 +++++++++++++++++++++++++---------- 1 file changed, 43 insertions(+), 16 deletions(-) (limited to 'src/se/leap/leapclient') diff --git a/src/se/leap/leapclient/Dashboard.java b/src/se/leap/leapclient/Dashboard.java index 6634479e..ebce35ed 100644 --- a/src/se/leap/leapclient/Dashboard.java +++ b/src/se/leap/leapclient/Dashboard.java @@ -55,7 +55,7 @@ public class Dashboard extends Activity implements LogInDialog.LogInDialogInterf private View eipDetail; private TextView eipStatus; - private boolean mEipWait = false; + private boolean mEipStartPending = false; private boolean authed = false; public ProviderAPIResultReceiver providerAPI_result_receiver; @@ -187,23 +187,50 @@ public class Dashboard extends Activity implements LogInDialog.LogInDialogInterf eipSwitch.setOnCheckedChangeListener(new CompoundButton.OnCheckedChangeListener() { @Override public void onCheckedChanged(CompoundButton buttonView, boolean isChecked) { - if (!mEipWait){ - buttonView.setClickable(false); - mEipWait = true; - - Intent vpnIntent; - if (isChecked){ - vpnIntent = new Intent(EIP.ACTION_START_EIP); + + if (isChecked){ + mEipStartPending = true; + eipCommand(EIP.ACTION_START_EIP); + } else { + if (mEipStartPending){ + AlertDialog.Builder alertBuilder = new AlertDialog.Builder(getAppContext()); + 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) { + eipSwitch.setChecked(true); + } + }) + .show(); } else { - vpnIntent = new Intent(EIP.ACTION_STOP_EIP); + eipCommand(EIP.ACTION_STOP_EIP); } - vpnIntent.putExtra(ConfigHelper.RECEIVER_TAG, mEIPReceiver); - startService(vpnIntent); } } }); } + /** + * 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(ConfigHelper.RECEIVER_TAG, mEIPReceiver); + startService(vpnIntent); + } + /** * Expands the EIP Dashboard component for extra details view. * Called by onClick property in client_dashboard.xml layout. @@ -434,18 +461,22 @@ public class Dashboard extends Activity implements LogInDialog.LogInDialogInterf @Override public void run() { if (eipStatus != null) { + boolean switchState = true; String statusMessage = ""; String prefix = getString(localizedResId); if (state.equals("CONNECTED")){ statusMessage = "Connection Secure"; + mEipStartPending = false; } else if (state.equals("BYTECOUNT")) { statusMessage = logmessage; } else if (state.equals("NOPROCESS") || state.equals("EXITING")) { statusMessage = "Not running! Connection not secure!"; + switchState = false; } else { statusMessage = prefix + logmessage; } + eipSwitch.setChecked(switchState); eipStatus.setText(statusMessage); } } @@ -474,7 +505,6 @@ public class Dashboard extends Activity implements LogInDialog.LogInDialogInterf super.onReceiveResult(resultCode, resultData); String request = resultData.getString(ConfigHelper.REQUEST_TAG); - mEipWait = true; boolean checked = false; if (request == EIP.ACTION_IS_EIP_RUNNING) { @@ -515,10 +545,7 @@ public class Dashboard extends Activity implements LogInDialog.LogInDialogInterf } } - Switch eipS = ((Switch) mDashboard.findViewById(R.id.eipSwitch)); - eipS.setChecked(checked); - eipS.setClickable(true); - mEipWait = false; + eipSwitch.setChecked(checked); } } } -- cgit v1.2.3 From f9131ce775b180cee3fa8ec1ac52290a7f58d1ef Mon Sep 17 00:00:00 2001 From: Sean Leonard Date: Wed, 10 Jul 2013 18:26:31 -0600 Subject: Refactor EIP UI and control logic out of Dashboard into a Fragment --- src/se/leap/leapclient/Dashboard.java | 241 +------------------------ src/se/leap/leapclient/EipServiceFragment.java | 234 ++++++++++++++++++++++++ 2 files changed, 244 insertions(+), 231 deletions(-) create mode 100644 src/se/leap/leapclient/EipServiceFragment.java (limited to 'src/se/leap/leapclient') diff --git a/src/se/leap/leapclient/Dashboard.java b/src/se/leap/leapclient/Dashboard.java index ebce35ed..4cd517a9 100644 --- a/src/se/leap/leapclient/Dashboard.java +++ b/src/se/leap/leapclient/Dashboard.java @@ -6,14 +6,12 @@ import org.json.JSONException; import org.json.JSONObject; import se.leap.leapclient.ProviderAPIResultReceiver.Receiver; -import se.leap.openvpn.LogWindow; import se.leap.openvpn.MainActivity; -import se.leap.openvpn.OpenVPN; -import se.leap.openvpn.OpenVPN.StateListener; 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; @@ -22,15 +20,10 @@ import android.content.Intent; import android.content.SharedPreferences; import android.os.Bundle; import android.os.Handler; -import android.os.ResultReceiver; import android.view.Menu; import android.view.MenuItem; import android.view.View; import android.view.ViewGroup; -import android.view.ViewStub; -import android.widget.CompoundButton; -import android.widget.RelativeLayout; -import android.widget.Switch; import android.widget.TextView; import android.widget.Toast; @@ -40,26 +33,23 @@ import android.widget.Toast; * * @author Sean Leonard */ -public class Dashboard extends Activity implements LogInDialog.LogInDialogInterface,Receiver,StateListener { +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"; + private ProgressDialog mProgressDialog; + private static Context app; private static SharedPreferences preferences; private static Provider provider; private TextView providerNameTV; - private TextView eipTypeTV; - private Switch eipSwitch; - private View eipDetail; - private TextView eipStatus; - - private boolean mEipStartPending = false; + private boolean authed = false; public ProviderAPIResultReceiver providerAPI_result_receiver; - private EIPReceiver mEIPReceiver; @Override protected void onCreate(Bundle savedInstanceState) { @@ -77,23 +67,6 @@ public class Dashboard extends Activity implements LogInDialog.LogInDialogInterf else buildDashboard(); } - - @Override - protected void onStop() { - super.onStop(); - if (provider != null) - if (provider.hasEIP() && provider.getEIPType() == "OpenVPN") - OpenVPN.removeStateListener(this); - } - - @Override - protected void onResume() { - super.onResume(); - - if (provider != null) - if (provider.hasEIP() && provider.getEIPType() == "OpenVPN") - OpenVPN.addStateListener(this); - } @Override protected void onActivityResult(int requestCode, int resultCode, Intent data){ @@ -150,111 +123,13 @@ public class Dashboard extends Activity implements LogInDialog.LogInDialogInterf providerNameTV.setText(provider.getName()); providerNameTV.setTextSize(28); - if ( provider.hasEIP() ){ - startService( new Intent(EIP.ACTION_UPDATE_EIP_SERVICE) ); - if (provider.getEIPType() == "OpenVPN") - OpenVPN.addStateListener(this); - serviceItemEIP(); + FragmentManager fragMan = getFragmentManager(); + if ( provider.hasEIP() && fragMan.findFragmentByTag(TAG_EIP_FRAGMENT) == null){ + EipServiceFragment eipFragment = new EipServiceFragment(); + fragMan.beginTransaction().add(R.id.servicesCollection, eipFragment, TAG_EIP_FRAGMENT).commit(); } } - /** - * Builds the UI for the EIP service Dashboard component - */ - private void serviceItemEIP() { - mEIPReceiver = new EIPReceiver(new Handler()); - mEIPReceiver.setReceiver(this); - - Intent intent = new Intent(this,EIP.class); - intent.setAction(EIP.ACTION_IS_EIP_RUNNING); - intent.putExtra(ConfigHelper.RECEIVER_TAG, mEIPReceiver); - startService(intent); - - ViewStub eip_overview_stub = ((ViewStub) findViewById(R.id.eipOverviewStub)); - if(eip_overview_stub != null) - eip_overview_stub.inflate(); - - eipTypeTV = (TextView) findViewById(R.id.eipType); - eipTypeTV.setText(provider.getEIPType()); - - eipDetail = ((RelativeLayout) findViewById(R.id.eipDetail)); - View eipSettings = findViewById(R.id.eipSettings); - eipSettings.setVisibility(View.GONE); // FIXME too! - eipDetail.setVisibility(View.VISIBLE); - eipStatus = (TextView) findViewById(R.id.eipStatus); - - eipSwitch = (Switch) findViewById(R.id.eipSwitch); - eipSwitch.setOnCheckedChangeListener(new CompoundButton.OnCheckedChangeListener() { - @Override - public void onCheckedChanged(CompoundButton buttonView, boolean isChecked) { - - if (isChecked){ - mEipStartPending = true; - eipCommand(EIP.ACTION_START_EIP); - } else { - if (mEipStartPending){ - AlertDialog.Builder alertBuilder = new AlertDialog.Builder(getAppContext()); - 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) { - eipSwitch.setChecked(true); - } - }) - .show(); - } else { - eipCommand(EIP.ACTION_STOP_EIP); - } - } - } - }); - } - - /** - * 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(ConfigHelper.RECEIVER_TAG, mEIPReceiver); - startService(vpnIntent); - } - - /** - * Expands the EIP Dashboard component for extra details view. - * Called by onClick property in client_dashboard.xml layout. - * - * @param view (Unused) The View calling this method by its onClick property - */ - public void toggleEipOverview(View view) { - if (eipDetail.isShown()) - eipDetail.setVisibility(View.GONE); - else - eipDetail.setVisibility(View.VISIBLE); - } - - /** - * Launches the se.leap.openvpn.LogWindow Activity showing detailed OpenVPN log - * - * @param view (Unused) The View calling this method by its onClick property - */ - public void showEIPLog(View view){ - Intent intent = new Intent(getBaseContext(),LogWindow.class); - intent.addFlags(Intent.FLAG_ACTIVITY_REORDER_TO_FRONT); - startActivity(intent); - } - @Override public boolean onPrepareOptionsMenu(Menu menu) { JSONObject provider_json; @@ -452,100 +327,4 @@ public class Dashboard extends Activity implements LogInDialog.LogInDialogInterf return app; } - @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 ) - 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"; - mEipStartPending = false; - } else if (state.equals("BYTECOUNT")) { - statusMessage = logmessage; - } else if (state.equals("NOPROCESS") || state.equals("EXITING")) { - statusMessage = "Not running! Connection not secure!"; - switchState = false; - } else { - statusMessage = prefix + logmessage; - } - - eipSwitch.setChecked(switchState); - eipStatus.setText(statusMessage); - } - } - }); - } - - /** - * Inner class for handling messages related to EIP status and control requests - * - * @author Sean Leonard - */ - protected class EIPReceiver extends ResultReceiver { - - Dashboard mDashboard; - - protected EIPReceiver(Handler handler){ - super(handler); - } - - public void setReceiver(Dashboard receiver) { - mDashboard = receiver; - } - - @Override - protected void onReceiveResult(int resultCode, Bundle resultData) { - super.onReceiveResult(resultCode, resultData); - - String request = resultData.getString(ConfigHelper.REQUEST_TAG); - boolean checked = false; - - if (request == EIP.ACTION_IS_EIP_RUNNING) { - switch (resultCode){ - case RESULT_OK: - checked = true; - break; - case RESULT_CANCELED: - checked = false; - break; - } - } else if (request == EIP.ACTION_START_EIP) { - switch (resultCode){ - case RESULT_OK: - checked = true; - break; - case RESULT_CANCELED: - checked = false; - break; - } - } else if (request == EIP.ACTION_STOP_EIP) { - switch (resultCode){ - case RESULT_OK: - checked = false; - break; - case RESULT_CANCELED: - checked = true; - break; - } - } else if (request == EIP.EIP_NOTIFICATION) { - switch (resultCode){ - case RESULT_OK: - checked = true; - break; - case RESULT_CANCELED: - checked = false; - break; - } - } - - eipSwitch.setChecked(checked); - } - } } diff --git a/src/se/leap/leapclient/EipServiceFragment.java b/src/se/leap/leapclient/EipServiceFragment.java new file mode 100644 index 00000000..485a06af --- /dev/null +++ b/src/se/leap/leapclient/EipServiceFragment.java @@ -0,0 +1,234 @@ +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.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 View eipFragment; + private Switch eipSwitch; + private View eipDetail; + private TextView eipStatus; + + private boolean eipAutoSwitched = false; + + 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! + + eipStatus = (TextView) eipFragment.findViewById(R.id.eipStatus); + eipStatus.setOnClickListener(this); + + eipSwitch = (Switch) eipFragment.findViewById(R.id.eipSwitch); + eipSwitch.setOnCheckedChangeListener(this); + + return eipFragment; + } + + @Override + public void onCreate(Bundle savedInstanceState) { + super.onCreate(savedInstanceState); + + mEIPReceiver = new EIPReceiver(new Handler()); + } + + @Override + public void onResume() { + super.onResume(); + + OpenVPN.addStateListener(this); + } + + @Override + public void onPause() { + super.onPause(); + + OpenVPN.removeStateListener(this); + } + + @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; + 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); + } + } + } + } + + /** + * 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(ConfigHelper.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"; + mEipStartPending = false; + } else if (state.equals("BYTECOUNT")) { + statusMessage = logmessage; + } else if (state.equals("NOPROCESS") || state.equals("EXITING")) { + statusMessage = "Not running! Connection not secure!"; + 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(ConfigHelper.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; + 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; + } + } +} -- cgit v1.2.3 From b19dc954b381c1e266395fdc1f19a1246096d4ab Mon Sep 17 00:00:00 2001 From: Sean Leonard Date: Wed, 10 Jul 2013 21:57:43 -0600 Subject: Add a progress bar while VPN connection is being established --- src/se/leap/leapclient/EipServiceFragment.java | 23 ++++++++++++++++++++++- 1 file changed, 22 insertions(+), 1 deletion(-) (limited to 'src/se/leap/leapclient') diff --git a/src/se/leap/leapclient/EipServiceFragment.java b/src/se/leap/leapclient/EipServiceFragment.java index 485a06af..51284bc0 100644 --- a/src/se/leap/leapclient/EipServiceFragment.java +++ b/src/se/leap/leapclient/EipServiceFragment.java @@ -23,6 +23,8 @@ 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; @@ -37,6 +39,7 @@ public class EipServiceFragment extends Fragment implements StateListener, OnCli @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)); @@ -44,6 +47,9 @@ public class EipServiceFragment extends Fragment implements StateListener, OnCli 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); @@ -59,6 +65,9 @@ public class EipServiceFragment extends Fragment implements StateListener, OnCli super.onCreate(savedInstanceState); mEIPReceiver = new EIPReceiver(new Handler()); + + if (savedInstanceState != null) + mEipStartPending = savedInstanceState.getBoolean(IS_EIP_PENDING); } @Override @@ -75,6 +84,12 @@ public class EipServiceFragment extends Fragment implements StateListener, OnCli 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)) @@ -95,6 +110,8 @@ public class EipServiceFragment extends Fragment implements StateListener, OnCli 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){ @@ -151,11 +168,14 @@ public class EipServiceFragment extends Fragment implements StateListener, OnCli 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") || state.equals("EXITING")) { + } 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; @@ -204,6 +224,7 @@ public class EipServiceFragment extends Fragment implements StateListener, OnCli break; case Activity.RESULT_CANCELED: checked = false; + eipFragment.findViewById(R.id.eipProgress).setVisibility(View.GONE); break; } } else if (request == EIP.ACTION_STOP_EIP) { -- cgit v1.2.3 From f0c42391501aa646c5d65df5e19dbbd36b19b970 Mon Sep 17 00:00:00 2001 From: Sean Leonard Date: Fri, 19 Jul 2013 14:11:29 -0600 Subject: Add logic to only trigger EIP control events if switch changed by a touch event. Fixes VPN reconnection when framework rebuilds view, triggering onCheckedChangeListener --- src/se/leap/leapclient/EipServiceFragment.java | 11 ++++++++++- 1 file changed, 10 insertions(+), 1 deletion(-) (limited to 'src/se/leap/leapclient') diff --git a/src/se/leap/leapclient/EipServiceFragment.java b/src/se/leap/leapclient/EipServiceFragment.java index 51284bc0..c18f83da 100644 --- a/src/se/leap/leapclient/EipServiceFragment.java +++ b/src/se/leap/leapclient/EipServiceFragment.java @@ -12,6 +12,7 @@ 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; @@ -30,7 +31,7 @@ public class EipServiceFragment extends Fragment implements StateListener, OnCli private View eipDetail; private TextView eipStatus; - private boolean eipAutoSwitched = false; + private boolean eipAutoSwitched = true; private boolean mEipStartPending = false; @@ -55,6 +56,13 @@ public class EipServiceFragment extends Fragment implements StateListener, OnCli 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; @@ -139,6 +147,7 @@ public class EipServiceFragment extends Fragment implements StateListener, OnCli } } } + eipAutoSwitched = true; } /** -- cgit v1.2.3 From 99b65032fae646293a6e7ddeaa8553d9e0590f3d Mon Sep 17 00:00:00 2001 From: Sean Leonard Date: Tue, 2 Jul 2013 22:57:27 -0600 Subject: Display provider domain on Dashboard instead of name --- src/se/leap/leapclient/Dashboard.java | 2 +- src/se/leap/leapclient/Provider.java | 12 ++++++++++++ 2 files changed, 13 insertions(+), 1 deletion(-) (limited to 'src/se/leap/leapclient') diff --git a/src/se/leap/leapclient/Dashboard.java b/src/se/leap/leapclient/Dashboard.java index 4cd517a9..96f542bf 100644 --- a/src/se/leap/leapclient/Dashboard.java +++ b/src/se/leap/leapclient/Dashboard.java @@ -120,7 +120,7 @@ public class Dashboard extends Activity implements LogInDialog.LogInDialogInterf provider.init( this ); providerNameTV = (TextView) findViewById(R.id.providerName); - providerNameTV.setText(provider.getName()); + providerNameTV.setText(provider.getDomain()); providerNameTV.setTextSize(28); FragmentManager fragMan = getFragmentManager(); diff --git a/src/se/leap/leapclient/Provider.java b/src/se/leap/leapclient/Provider.java index 189c3a84..72184eb0 100644 --- a/src/se/leap/leapclient/Provider.java +++ b/src/se/leap/leapclient/Provider.java @@ -36,6 +36,7 @@ public final class Provider implements Serializable { // 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"}; @@ -79,6 +80,17 @@ public final class Provider implements Serializable { } } + 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(); -- cgit v1.2.3 From 6f9cb39e79ff97bcd5e0635cb67f9a8f23f2b486 Mon Sep 17 00:00:00 2001 From: Sean Leonard Date: Tue, 2 Jul 2013 22:58:16 -0600 Subject: Change EIP switch label to "Encrypted Internet" --- src/se/leap/leapclient/Dashboard.java | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) (limited to 'src/se/leap/leapclient') diff --git a/src/se/leap/leapclient/Dashboard.java b/src/se/leap/leapclient/Dashboard.java index 96f542bf..3a50ad1e 100644 --- a/src/se/leap/leapclient/Dashboard.java +++ b/src/se/leap/leapclient/Dashboard.java @@ -56,8 +56,6 @@ public class Dashboard extends Activity implements LogInDialog.LogInDialogInterf super.onCreate(savedInstanceState); app = this; - - setContentView(R.layout.client_dashboard); ConfigHelper.setSharedPreferences(getSharedPreferences(ConfigHelper.PREFERENCES_KEY, MODE_PRIVATE)); preferences = ConfigHelper.shared_preferences; @@ -119,6 +117,8 @@ public class Dashboard extends Activity implements LogInDialog.LogInDialogInterf provider = Provider.getInstance(); provider.init( this ); + setContentView(R.layout.client_dashboard); + providerNameTV = (TextView) findViewById(R.id.providerName); providerNameTV.setText(provider.getDomain()); providerNameTV.setTextSize(28); -- cgit v1.2.3 From 5edc2af535d177edaeda97523a04c6f73fad26a4 Mon Sep 17 00:00:00 2001 From: Sean Leonard Date: Wed, 10 Jul 2013 11:20:33 -0600 Subject: Fix config error dialog missing call to show() --- src/se/leap/leapclient/Dashboard.java | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) (limited to 'src/se/leap/leapclient') diff --git a/src/se/leap/leapclient/Dashboard.java b/src/se/leap/leapclient/Dashboard.java index 3a50ad1e..4c9c28dd 100644 --- a/src/se/leap/leapclient/Dashboard.java +++ b/src/se/leap/leapclient/Dashboard.java @@ -106,7 +106,8 @@ public class Dashboard extends Activity implements LogInDialog.LogInDialogInterf prefsEdit.remove(ConfigHelper.PROVIDER_KEY).commit(); finish(); } - }); + }) + .show(); } /** -- cgit v1.2.3 From 492f353e790875da560d8b29bac86e7db0db8922 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Parm=C3=A9nides=20GV?= Date: Tue, 16 Jul 2013 18:45:35 +0200 Subject: Erroneous untrusted provider toast with LEAP fixed I've also rearranged how we handle SSL errors. In first place, if the user checked the "Trust completely" checkbox, leap_android tries to use the CA cert pointed out by provider.json. If that does not succeed, it uses an always-returning-true hostname verifier (this was previously done before using CA cert). --- src/se/leap/leapclient/ProviderAPI.java | 7 +++---- 1 file changed, 3 insertions(+), 4 deletions(-) (limited to 'src/se/leap/leapclient') diff --git a/src/se/leap/leapclient/ProviderAPI.java b/src/se/leap/leapclient/ProviderAPI.java index 37856f60..72b134e5 100644 --- a/src/se/leap/leapclient/ProviderAPI.java +++ b/src/se/leap/leapclient/ProviderAPI.java @@ -397,10 +397,9 @@ public class ProviderAPI extends IntentService { } else { displayToast(R.string.certificate_error); } - displayToast(R.string.certificate_error); } catch (Exception e) { if(provider_url != null && danger_on) { - json_file_content = getStringFromProviderWithoutValidate(provider_url); + json_file_content = getStringFromProviderWithCACertAdded(provider_url); } } @@ -433,7 +432,7 @@ public class ProviderAPI extends IntentService { } catch (MalformedURLException e) { displayToast(R.string.malformed_url); } catch (IOException e) { - json_string = getStringFromProviderWithCACertAdded(string_url); + json_string = getStringFromProviderIgnoringCertificate(string_url); } return json_string; @@ -485,7 +484,7 @@ public class ProviderAPI extends IntentService { displayToast(R.string.server_is_down_message); } catch (IOException e) { // The downloaded certificate doesn't validate our https connection. - json_file_content = getStringFromProviderIgnoringCertificate(url); + json_file_content = getStringFromProviderWithoutValidate(url); displayToast(R.string.certificate_error); } catch (KeyStoreException e) { // TODO Auto-generated catch block -- cgit v1.2.3 From 5ed843dd7dfdddc9c64568a464ed550ba2185ac9 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Parm=C3=A9nides=20GV?= Date: Tue, 16 Jul 2013 19:52:34 +0200 Subject: Certificate message shown when appropiate. Only if all downloading methods fail and the last one throws an IOException, the certificate error message toast is shown. --- src/se/leap/leapclient/ProviderAPI.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'src/se/leap/leapclient') diff --git a/src/se/leap/leapclient/ProviderAPI.java b/src/se/leap/leapclient/ProviderAPI.java index 72b134e5..db53d6f9 100644 --- a/src/se/leap/leapclient/ProviderAPI.java +++ b/src/se/leap/leapclient/ProviderAPI.java @@ -485,7 +485,6 @@ public class ProviderAPI extends IntentService { } catch (IOException e) { // The downloaded certificate doesn't validate our https connection. json_file_content = getStringFromProviderWithoutValidate(url); - displayToast(R.string.certificate_error); } catch (KeyStoreException e) { // TODO Auto-generated catch block e.printStackTrace(); @@ -535,6 +534,7 @@ public class ProviderAPI extends IntentService { } 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(); -- cgit v1.2.3 From 6b740cdb44bd4f7181f93b6c15e772d14fb96796 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Parm=C3=A9nides=20GV?= Date: Sat, 20 Jul 2013 12:01:11 +0200 Subject: If IOException, use current provider CA cert. If the CA cert was correctly downloaded, we assume it can be used to validate the string download. If CA cert cannot validate that connection, then if the trust completely checkbox was checked it will try with the other methods. If it was not checked, a certificate error is shown (telling the user the provider is not trusted). --- src/se/leap/leapclient/ProviderAPI.java | 19 ++++++++++++------- 1 file changed, 12 insertions(+), 7 deletions(-) (limited to 'src/se/leap/leapclient') diff --git a/src/se/leap/leapclient/ProviderAPI.java b/src/se/leap/leapclient/ProviderAPI.java index db53d6f9..a5da4b42 100644 --- a/src/se/leap/leapclient/ProviderAPI.java +++ b/src/se/leap/leapclient/ProviderAPI.java @@ -392,14 +392,14 @@ public class ProviderAPI extends IntentService { } catch(SocketTimeoutException e) { displayToast(R.string.server_is_down_message); } catch (IOException e) { - if(provider_url != null && danger_on) { - json_file_content = getStringFromProviderWithoutValidate(provider_url); + if(provider_url != null) { + json_file_content = getStringFromProviderWithCACertAdded(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); + json_file_content = getStringFromProviderWithCACertAdded(provider_url, danger_on); } } @@ -441,15 +441,16 @@ public class ProviderAPI extends IntentService { /** * Tries to download the contents of the provided url using main certificate from choosen 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) { + private String getStringFromProviderWithCACertAdded(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()) { + if(cert_string.isEmpty() && danger_on) { cert_string = downloadCertificateWithoutTrusting(url.getProtocol() + "://" + url.getHost() + "/" + "ca.crt"); ConfigHelper.saveSharedPref(ConfigHelper.MAIN_CERT_KEY, cert_string); } @@ -461,7 +462,7 @@ public class ProviderAPI extends IntentService { String keyStoreType = KeyStore.getDefaultType(); KeyStore keyStore = KeyStore.getInstance(keyStoreType); keyStore.load(null, null); - keyStore.setCertificateEntry("dangerous_certificate", dangerous_certificate); + keyStore.setCertificateEntry("provider_ca_certificate", dangerous_certificate); // Create a TrustManager that trusts the CAs in our KeyStore String tmfAlgorithm = TrustManagerFactory.getDefaultAlgorithm(); @@ -484,7 +485,11 @@ public class ProviderAPI extends IntentService { displayToast(R.string.server_is_down_message); } catch (IOException e) { // The downloaded certificate doesn't validate our https connection. - json_file_content = getStringFromProviderWithoutValidate(url); + if(danger_on) { + json_file_content = getStringFromProviderWithoutValidate(url); + } else { + displayToast(R.string.certificate_error); + } } catch (KeyStoreException e) { // TODO Auto-generated catch block e.printStackTrace(); -- cgit v1.2.3 From 011906a4062c4169e343fbdf72ad75491caa1767 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Parm=C3=A9nides=20GV?= Date: Thu, 25 Jul 2013 18:38:21 +0200 Subject: Login progressdialog get dismissed when finished. If login is successful, dialog is dismissed and toast is showed. If login is not successful and the user cancels the new login dialog presented to him/her, then Dashboard is showed. --- src/se/leap/leapclient/Dashboard.java | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) (limited to 'src/se/leap/leapclient') diff --git a/src/se/leap/leapclient/Dashboard.java b/src/se/leap/leapclient/Dashboard.java index 4c9c28dd..67a73c44 100644 --- a/src/se/leap/leapclient/Dashboard.java +++ b/src/se/leap/leapclient/Dashboard.java @@ -299,6 +299,7 @@ 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) { + mProgressDialog.dismiss(); logInDialog(getCurrentFocus(), resultData.getString(getResources().getString(R.string.user_message))); } else if(resultCode == ConfigHelper.LOGOUT_SUCCESSFUL) { authed = false; @@ -310,10 +311,12 @@ public class Dashboard extends Activity implements LogInDialog.LogInDialogInterf mProgressDialog.dismiss(); Toast.makeText(getApplicationContext(), R.string.log_out_failed_message, Toast.LENGTH_LONG).show(); } else if(resultCode == ConfigHelper.CORRECTLY_DOWNLOADED_CERTIFICATE) { - setResult(RESULT_CANCELED); + 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) { setResult(RESULT_CANCELED); + mProgressDialog.dismiss(); Toast.makeText(getApplicationContext(), R.string.authed_cert_download_failed_message, Toast.LENGTH_LONG).show(); } } -- cgit v1.2.3 From 22e90c26036291de66f26ee148bb4c75b68c7764 Mon Sep 17 00:00:00 2001 From: Sean Leonard Date: Fri, 12 Jul 2013 21:53:57 -0600 Subject: Include GPLv3+ file and header for files in se.leap.leapclient package --- src/se/leap/leapclient/ConfigHelper.java | 16 ++++++++++++++++ src/se/leap/leapclient/ConfigurationWizard.java | 18 +++++++++++++++++- src/se/leap/leapclient/Dashboard.java | 18 +++++++++++++++++- src/se/leap/leapclient/EIP.java | 18 +++++++++++++++++- src/se/leap/leapclient/LeapHttpClient.java | 18 +++++++++++++++++- src/se/leap/leapclient/LeapSRPSession.java | 18 +++++++++++++++++- src/se/leap/leapclient/LogInDialog.java | 18 +++++++++++++++++- src/se/leap/leapclient/NewProviderDialog.java | 18 +++++++++++++++++- src/se/leap/leapclient/Provider.java | 13 +++++++++++++ src/se/leap/leapclient/ProviderAPI.java | 18 +++++++++++++++++- src/se/leap/leapclient/ProviderAPIResultReceiver.java | 18 +++++++++++++++++- src/se/leap/leapclient/ProviderListContent.java | 18 +++++++++++++++++- src/se/leap/leapclient/ProviderListFragment.java | 18 +++++++++++++++++- 13 files changed, 216 insertions(+), 11 deletions(-) (limited to 'src/se/leap/leapclient') diff --git a/src/se/leap/leapclient/ConfigHelper.java b/src/se/leap/leapclient/ConfigHelper.java index 0c589c41..62ebf8f1 100644 --- a/src/se/leap/leapclient/ConfigHelper.java +++ b/src/se/leap/leapclient/ConfigHelper.java @@ -1,3 +1,19 @@ +/** + * 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; diff --git a/src/se/leap/leapclient/ConfigurationWizard.java b/src/se/leap/leapclient/ConfigurationWizard.java index 2687b579..934e2ea0 100644 --- a/src/se/leap/leapclient/ConfigurationWizard.java +++ b/src/se/leap/leapclient/ConfigurationWizard.java @@ -1,4 +1,20 @@ -package se.leap.leapclient; +/** + * 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; diff --git a/src/se/leap/leapclient/Dashboard.java b/src/se/leap/leapclient/Dashboard.java index 67a73c44..063cd3cd 100644 --- a/src/se/leap/leapclient/Dashboard.java +++ b/src/se/leap/leapclient/Dashboard.java @@ -1,4 +1,20 @@ -package se.leap.leapclient; +/** + * 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; diff --git a/src/se/leap/leapclient/EIP.java b/src/se/leap/leapclient/EIP.java index 5057732e..e0685c15 100644 --- a/src/se/leap/leapclient/EIP.java +++ b/src/se/leap/leapclient/EIP.java @@ -1,4 +1,20 @@ -package se.leap.leapclient; +/** + * 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; diff --git a/src/se/leap/leapclient/LeapHttpClient.java b/src/se/leap/leapclient/LeapHttpClient.java index 42f9a523..686d3cc0 100644 --- a/src/se/leap/leapclient/LeapHttpClient.java +++ b/src/se/leap/leapclient/LeapHttpClient.java @@ -1,4 +1,20 @@ -package se.leap.leapclient; +/** + * 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; diff --git a/src/se/leap/leapclient/LeapSRPSession.java b/src/se/leap/leapclient/LeapSRPSession.java index d21ccffe..9451c1be 100644 --- a/src/se/leap/leapclient/LeapSRPSession.java +++ b/src/se/leap/leapclient/LeapSRPSession.java @@ -1,4 +1,20 @@ -package se.leap.leapclient; +/** + * 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; diff --git a/src/se/leap/leapclient/LogInDialog.java b/src/se/leap/leapclient/LogInDialog.java index 0536c6df..8b3f9e80 100644 --- a/src/se/leap/leapclient/LogInDialog.java +++ b/src/se/leap/leapclient/LogInDialog.java @@ -1,4 +1,20 @@ -package se.leap.leapclient; +/** + * 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; diff --git a/src/se/leap/leapclient/NewProviderDialog.java b/src/se/leap/leapclient/NewProviderDialog.java index 3712e8f9..0b9d8fd0 100644 --- a/src/se/leap/leapclient/NewProviderDialog.java +++ b/src/se/leap/leapclient/NewProviderDialog.java @@ -1,4 +1,20 @@ -package se.leap.leapclient; +/** + * 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; diff --git a/src/se/leap/leapclient/Provider.java b/src/se/leap/leapclient/Provider.java index 72184eb0..cdcd56c5 100644 --- a/src/se/leap/leapclient/Provider.java +++ b/src/se/leap/leapclient/Provider.java @@ -1,5 +1,18 @@ /** + * 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; diff --git a/src/se/leap/leapclient/ProviderAPI.java b/src/se/leap/leapclient/ProviderAPI.java index a5da4b42..944a0e7f 100644 --- a/src/se/leap/leapclient/ProviderAPI.java +++ b/src/se/leap/leapclient/ProviderAPI.java @@ -1,4 +1,20 @@ -package se.leap.leapclient; +/** + * 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; diff --git a/src/se/leap/leapclient/ProviderAPIResultReceiver.java b/src/se/leap/leapclient/ProviderAPIResultReceiver.java index e32f6ffd..d82484c8 100644 --- a/src/se/leap/leapclient/ProviderAPIResultReceiver.java +++ b/src/se/leap/leapclient/ProviderAPIResultReceiver.java @@ -1,4 +1,20 @@ -package se.leap.leapclient; +/** + * 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; diff --git a/src/se/leap/leapclient/ProviderListContent.java b/src/se/leap/leapclient/ProviderListContent.java index dc3d6ab3..714ed5f4 100644 --- a/src/se/leap/leapclient/ProviderListContent.java +++ b/src/se/leap/leapclient/ProviderListContent.java @@ -1,4 +1,20 @@ -package se.leap.leapclient; +/** + * 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; diff --git a/src/se/leap/leapclient/ProviderListFragment.java b/src/se/leap/leapclient/ProviderListFragment.java index f4f5feb9..2fca20e2 100644 --- a/src/se/leap/leapclient/ProviderListFragment.java +++ b/src/se/leap/leapclient/ProviderListFragment.java @@ -1,4 +1,20 @@ -package se.leap.leapclient; +/** + * 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; -- cgit v1.2.3